From 662c08272acd7be79531550919f56f846726eabb Mon Sep 17 00:00:00 2001 From: "only.lurking" Date: Mon, 23 Aug 2010 14:29:20 +0000 Subject: [PATCH] git-svn-id: http://tgstation13.googlecode.com/svn/trunk@2 316c924e-a436-60f5-8080-3fe189b3f50e --- code/ATMOSPHERICS/atmospherics.dm | 52 + .../binary_devices/binary_atmos_base.dm | 129 + .../components/binary_devices/circulator.dm | 64 + .../components/binary_devices/dp_vent_pump.dm | 198 + .../components/binary_devices/passive_gate.dm | 55 + .../components/binary_devices/pump.dm | 128 + .../components/binary_devices/volume_pump.dm | 113 + code/ATMOSPHERICS/components/filter.dm | 366 + code/ATMOSPHERICS/components/mixer.dm | 249 + .../components/portables_connector.dm | 129 + .../components/unary/cold_sink.dm | 40 + .../components/unary/generator_input.dm | 21 + .../components/unary/heat_exchanger.dm | 66 + .../components/unary/heat_source.dm | 42 + .../components/unary/outlet_injector.dm | 133 + .../components/unary/oxygen_generator.dm | 49 + .../components/unary/unary_base.dm | 87 + .../components/unary/vent_pump.dm | 212 + .../components/unary/vent_scrubber.dm | 88 + code/ATMOSPHERICS/components/valve.dm | 249 + code/ATMOSPHERICS/datum_pipe_network.dm | 203 + code/ATMOSPHERICS/datum_pipeline.dm | 231 + code/ATMOSPHERICS/pipes.dm | 681 ++ code/FEA/DEBUG_REMOVE_BEFORE_RELEASE.dm | 604 ++ code/FEA/FEA_airgroup.dm | 299 + code/FEA/FEA_fire.dm | 146 + code/FEA/FEA_gas_mixture.dm | 950 +++ code/FEA/FEA_group_helpers.dm | 114 + code/FEA/FEA_system.dm | 343 + code/FEA/FEA_turf_tile.dm | 539 ++ code/WorkInProgress/BrokenInhands.dm | 36 + code/WorkInProgress/Cameras.dm | 188 + code/WorkInProgress/Chemistry-Holder.dm | 235 + code/WorkInProgress/Chemistry-Machinery.dm | 231 + code/WorkInProgress/Chemistry-Readme.dm | 219 + code/WorkInProgress/Chemistry-Reagents.dm | 920 +++ code/WorkInProgress/Chemistry-Recipes.dm | 390 ++ code/WorkInProgress/Chemistry-Tools.dm | 1349 ++++ code/WorkInProgress/KeelinsStuff.dm | 490 ++ code/WorkInProgress/NewBan.dm | 194 + code/WorkInProgress/buildmode.dm | 263 + code/WorkInProgress/cloning.dm | 724 ++ .../computer2/airlock_control.dm | 60 + code/WorkInProgress/computer2/arcade.dm | 136 + code/WorkInProgress/computer2/base_program.dm | 263 + .../computer2/buildandrepair.dm | 153 + code/WorkInProgress/computer2/computerII.dm | 414 ++ code/WorkInProgress/computer2/filebrowse.dm | 164 + code/WorkInProgress/computer2/med_rec.dm | 463 ++ code/WorkInProgress/computer2/messenger.dm | 96 + code/WorkInProgress/computer2/peripherals.dm | 209 + code/WorkInProgress/explosion_particles.dm | 70 + code/WorkInProgress/optics/beam.dm | 179 + code/WorkInProgress/optics/laser-pointer.dm | 72 + code/WorkInProgress/optics/mirror.dm | 83 + code/WorkInProgress/pda2/base_os.dm | 445 ++ code/WorkInProgress/pda2/base_program.dm | 185 + code/WorkInProgress/pda2/pda2.dm | 297 + code/WorkInProgress/pda2/record_progs.dm | 181 + code/WorkInProgress/pda2/scanners.dm | 101 + code/WorkInProgress/pda2/smallprogs.dm | 204 + code/WorkInProgress/plants/plant.dm | 18 + code/WorkInProgress/recycling/conveyor.dm | 389 ++ .../recycling/disposal-construction.dm | 162 + code/WorkInProgress/recycling/disposal.dm | 936 +++ code/WorkInProgress/recycling/scrap.dm | 288 + code/_debug.dm | 611 ++ code/datums/ai_laws.dm | 81 + code/datums/chemical.dm | 0 code/datums/computerfiles.dm | 7 + code/datums/configuration.dm | 218 + code/datums/datumvars.dm | 141 + code/datums/disease.dm | 74 + code/datums/diseases/alien_embryo.dm | 78 + code/datums/diseases/cold.dm | 49 + code/datums/diseases/dna_spread.dm | 61 + code/datums/diseases/fake_gbs.dm | 27 + code/datums/diseases/flu.dm | 50 + code/datums/diseases/gbs.dm | 34 + code/datums/diseases/jungle_fever.dm | 6 + code/datums/diseases/plasmatoid.dm | 5 + .../datums/diseases/robotic_transformation.dm | 54 + code/datums/diseases/xeno_transformation.dm | 56 + code/datums/mind.dm | 36 + code/datums/mixed.dm | 49 + code/datums/modules.dm | 62 + code/datums/organs.dm | 121 + code/datums/shuttle_controller.dm | 132 + code/datums/sun.dm | 97 + code/datums/vote.dm | 7 + code/defines/area/Space Station 13 areas.dm | 735 ++ code/defines/atom.dm | 120 + code/defines/client.dm | 30 + code/defines/global.dm | 160 + code/defines/hub.dm | 5 + code/defines/mob/dead/observer.dm | 11 + code/defines/mob/living/carbon/alien.dm | 9 + .../mob/living/carbon/alien_humanoid.dm | 25 + code/defines/mob/living/carbon/alien_larva.dm | 9 + code/defines/mob/living/carbon/carbon.dm | 5 + code/defines/mob/living/carbon/changeling.dm | 0 code/defines/mob/living/carbon/human.dm | 54 + code/defines/mob/living/carbon/monkey.dm | 8 + code/defines/mob/living/living.dm | 8 + code/defines/mob/living/silicon/ai.dm | 22 + code/defines/mob/living/silicon/hivebot.dm | 47 + code/defines/mob/living/silicon/robot.dm | 47 + code/defines/mob/living/silicon/silicon.dm | 4 + code/defines/mob/mob.dm | 173 + code/defines/obj.dm | 741 ++ code/defines/obj/assemblies.dm | 153 + code/defines/obj/closet.dm | 324 + code/defines/obj/clothing.dm | 865 +++ code/defines/obj/clothing/gimmick.dm | 252 + code/defines/obj/computer.dm | 229 + code/defines/obj/decal.dm | 136 + code/defines/obj/door.dm | 115 + code/defines/obj/food.dm | 61 + code/defines/obj/injector.dm | 173 + code/defines/obj/machinery.dm | 652 ++ code/defines/obj/nutrient.dm | 31 + code/defines/obj/radio.dm | 88 + code/defines/obj/seeds.dm | 112 + code/defines/obj/spawner.dm | 3 + code/defines/obj/spawner/bomb.dm | 44 + code/defines/obj/storage.dm | 175 + code/defines/obj/weapon.dm | 1348 ++++ code/defines/obj/window.dm | 74 + code/defines/procs/AStar.dm | 184 + code/defines/procs/church_name.dm | 16 + code/defines/procs/command_alert.dm | 9 + code/defines/procs/command_name.dm | 26 + code/defines/procs/dbcore.dm | 179 + code/defines/procs/gamehelpers.dm | 83 + code/defines/procs/helpers.dm | 764 ++ code/defines/procs/logging.dm | 28 + code/defines/procs/religion_name.dm | 11 + code/defines/procs/station_name.dm | 39 + code/defines/procs/statistics.dm | 206 + code/defines/procs/syndicate_name.dm | 29 + code/defines/turf.dm | 175 + code/defines/world.dm | 17 + code/game/airtunnel.dm | 448 ++ code/game/algorithm.dm | 172 + code/game/area/ai_monitored.dm | 86 + code/game/area/areas.dm | 210 + code/game/atom_procs.dm | 342 + code/game/cellautomata.dm | 177 + code/game/chemistry.dm | 376 + code/game/communications.dm | 93 + code/game/dna.dm | 1239 ++++ code/game/gamemodes/blob/blob.dm | 183 + code/game/gamemodes/blob/theblob.dm | 220 + .../gamemodes/changeling/changeling_powers.dm | 366 + code/game/gamemodes/ctf/ctf.dm | 140 + code/game/gamemodes/ctf/ctf_items.dm | 139 + code/game/gamemodes/deathmatch/deathmatch.dm | 66 + code/game/gamemodes/events.dm | 265 + code/game/gamemodes/extended/extended.dm | 8 + code/game/gamemodes/game_mode.dm | 122 + code/game/gamemodes/gameticker.dm | 254 + code/game/gamemodes/intercept_report.dm | 126 + .../gamemodes/malfunction/Malf_Modules.dm | 202 + .../game/gamemodes/malfunction/malfunction.dm | 128 + code/game/gamemodes/meteor/meteor.dm | 39 + code/game/gamemodes/meteor/meteors.dm | 112 + code/game/gamemodes/monkey/monkey.dm | 69 + code/game/gamemodes/nuclear/nuclear.dm | 228 + code/game/gamemodes/nuclear/nuclearbomb.dm | 163 + code/game/gamemodes/nuclear/pinpointer.dm | 129 + code/game/gamemodes/objective.dm | 149 + .../gamemodes/restructuring/restructuring.dm | 76 + code/game/gamemodes/revolution/revolution.dm | 389 ++ code/game/gamemodes/ruby/ruby.dm | 285 + code/game/gamemodes/sandbox/h_sandbox.dm | 154 + code/game/gamemodes/sandbox/sandbox.dm | 17 + code/game/gamemodes/setupgame.dm | 48 + code/game/gamemodes/traitor/traitor.dm | 200 + code/game/gamemodes/wizard/spell10.dm | 28 + code/game/gamemodes/wizard/spell11.dm | 97 + code/game/gamemodes/wizard/spell12.dm | 89 + code/game/gamemodes/wizard/spell13.dm | 33 + code/game/gamemodes/wizard/spell14.dm | 197 + code/game/gamemodes/wizard/spell2.dm | 24 + code/game/gamemodes/wizard/spell3.dm | 23 + code/game/gamemodes/wizard/spell4.dm | 39 + code/game/gamemodes/wizard/spell6.dm | 36 + code/game/gamemodes/wizard/spell7.dm | 24 + code/game/gamemodes/wizard/spell8.dm | 50 + code/game/gamemodes/wizard/spell9.dm | 37 + code/game/gamemodes/wizard/wizard.dm | 572 ++ code/game/hud.dm | 110 + code/game/jobs/access.dm | 239 + code/game/jobs/jobprocs.dm | 535 ++ code/game/jobs/jobs.dm | 26 + code/game/landmarks.dm | 61 + code/game/machinery/Freezer.dm | 82 + code/game/machinery/OpTable.dm | 119 + code/game/machinery/Sleeper.dm | 287 + code/game/machinery/airlock_control.dm | 202 + code/game/machinery/alarm.dm | 407 ++ code/game/machinery/atmo_control.dm | 558 ++ code/game/machinery/atmoalter/canister.dm | 270 + code/game/machinery/atmoalter/meter.dm | 90 + .../atmoalter/portable_atmospherics.dm | 130 + code/game/machinery/atmoalter/pump.dm | 135 + code/game/machinery/atmoalter/scrubber.dm | 131 + code/game/machinery/autolathe.dm | 214 + code/game/machinery/bots/bots.dm | 75 + code/game/machinery/bots/cleanbot.dm | 223 + code/game/machinery/bots/floorbot.dm | 385 ++ code/game/machinery/bots/medbot.dm | 632 ++ code/game/machinery/bots/mulebot.dm | 914 +++ code/game/machinery/bots/secbot.dm | 789 +++ code/game/machinery/camera.dm | 309 + code/game/machinery/cell_charger.dm | 64 + code/game/machinery/computer/Operating.dm | 69 + code/game/machinery/computer/arcade.dm | 196 + code/game/machinery/computer/atmos.dm | 119 + .../game/machinery/computer/buildandrepair.dm | 191 + .../game/machinery/computer/communications.dm | 447 ++ code/game/machinery/computer/computer.dm | 586 ++ code/game/machinery/computer/crew.dm | 92 + code/game/machinery/computer/engine.dm | 0 code/game/machinery/computer/hologram.dm | 94 + code/game/machinery/computer/medical.dm | 504 ++ code/game/machinery/computer/power.dm | 92 + code/game/machinery/computer/robot.dm | 185 + code/game/machinery/computer/security.dm | 432 ++ code/game/machinery/computer/shuttle.dm | 181 + code/game/machinery/cryo.dm | 284 + code/game/machinery/dispenser.dm | 100 + code/game/machinery/door_control.dm | 88 + code/game/machinery/doors/airlock.dm | 924 +++ code/game/machinery/doors/brigdoors.dm | 203 + .../machinery/doors/checkForMultipleDoors.dm | 16 + code/game/machinery/doors/door.dm | 257 + code/game/machinery/doors/firedoor.dm | 111 + code/game/machinery/doors/poddoor.dm | 57 + code/game/machinery/doors/shuttledoor.dm | 0 code/game/machinery/doors/windowdoor.dm | 129 + .../embedded_controller/access_controller.dm | 205 + .../embedded_controller/airlock_controller.dm | 256 + .../embedded_controller_base.dm | 82 + code/game/machinery/flasher.dm | 103 + code/game/machinery/gibber.dm | 120 + code/game/machinery/hologram.dm | 79 + code/game/machinery/hydroponics.dm | 331 + code/game/machinery/igniter.dm | 142 + code/game/machinery/lightswitch.dm | 62 + code/game/machinery/main.dm | 30 + code/game/machinery/microwave.dm | 341 + code/game/machinery/morgue.dm | 345 + code/game/machinery/navbeacon.dm | 244 + code/game/machinery/overview.dm | 357 + code/game/machinery/pipe/construction.dm | 488 ++ code/game/machinery/pipe/filter_control.dm | 162 + code/game/machinery/pipe/pipe.dm | 1832 +++++ code/game/machinery/pipe/pipe_dispenser.dm | 104 + code/game/machinery/pipe/pipe_filter.dm | 243 + code/game/machinery/processor.dm | 72 + code/game/machinery/recharger.dm | 55 + code/game/machinery/rechargestation.dm | 144 + code/game/machinery/robot_fabricator.dm | 150 + code/game/machinery/seed_extractor.dm | 29 + code/game/machinery/singularity.dm | 1226 ++++ code/game/machinery/sink.dm | 37 + code/game/machinery/spaceheater.dm | 196 + code/game/machinery/status_display.dm | 306 + code/game/machinery/teleporter.dm | 288 + code/game/machinery/turrets.dm | 307 + code/game/machinery/vending.dm | 450 ++ code/game/magic/library.dm | 663 ++ code/game/magic/magicmonster.dm | 300 + code/game/magic/musician.dm | 117 + code/game/magic/ritual.dm | 181 + code/game/master_controller.dm | 92 + code/game/objects/alien/acid.dm | 11 + code/game/objects/alien/defines.dm | 63 + code/game/objects/alien/egg.dm | 45 + code/game/objects/alien/facehugger.dm | 388 ++ code/game/objects/alien/resin.dm | 21 + code/game/objects/alien/weeds.dm | 103 + code/game/objects/assemblies.dm | 207 + code/game/objects/blood.dm | 52 + code/game/objects/bomb.dm | 156 + code/game/objects/cleaner.dm | 34 + code/game/objects/closets.dm | 205 + code/game/objects/closets/emergency.dm | 27 + code/game/objects/closets/gmcloset.dm | 13 + code/game/objects/closets/janitor.dm | 17 + code/game/objects/closets/kitchen.dm | 54 + code/game/objects/closets/l3closet.dm | 7 + code/game/objects/closets/malfunction.dm | 10 + code/game/objects/closets/nuclear.dm | 18 + code/game/objects/closets/secure/animal.dm | 10 + code/game/objects/closets/secure/bar.dm | 14 + code/game/objects/closets/secure/brig.dm | 6 + code/game/objects/closets/secure/captain.dm | 11 + code/game/objects/closets/secure/courtroom.dm | 15 + .../objects/closets/secure/engineering.dm | 54 + code/game/objects/closets/secure/medical.dm | 33 + code/game/objects/closets/secure/personal.dm | 50 + code/game/objects/closets/secure/scientist.dm | 12 + code/game/objects/closets/secure/security.dm | 67 + code/game/objects/closets/syndicate.dm | 13 + code/game/objects/closets/thunderdome.dm | 47 + code/game/objects/closets/wardrobe.dm | 247 + code/game/objects/death_commando_gear.dm | 9 + code/game/objects/devices/PDA.dm | 1640 +++++ code/game/objects/devices/aicard.dm | 55 + code/game/objects/devices/chameleonproj.dm | 106 + code/game/objects/devices/device.dm | 0 code/game/objects/devices/flash.dm | 99 + code/game/objects/devices/flashlight.dm | 45 + code/game/objects/devices/igniter.dm | 148 + code/game/objects/devices/infra_sensor.dm | 211 + code/game/objects/devices/multitool.dm | 17 + code/game/objects/devices/powersink.dm | 108 + code/game/objects/devices/proxy_sensor.dm | 170 + code/game/objects/devices/scanners.dm | 230 + code/game/objects/devices/shields.dm | 22 + code/game/objects/devices/timer.dm | 155 + code/game/objects/displaycase.dm | 95 + code/game/objects/effect_system.dm | 873 +++ code/game/objects/explosion.dm | 53 + code/game/objects/gibs.dm | 78 + code/game/objects/grille.dm | 149 + code/game/objects/items.dm | 373 + code/game/objects/items/assemblies.dm | 45 + code/game/objects/items/clothing.dm | 298 + code/game/objects/items/food.dm | 166 + code/game/objects/items/helper_procs.dm | 73 + code/game/objects/items/item.dm | 333 + code/game/objects/items/robot_parts.dm | 196 + code/game/objects/items/weapons/AI_modules.dm | 273 + code/game/objects/items/weapons/RCD.dm | 133 + code/game/objects/items/weapons/cards_ids.dm | 249 + .../objects/items/weapons/cigs_lighters.dm | 86 + .../game/objects/items/weapons/clown_items.dm | 40 + .../objects/items/weapons/flamethrower.dm | 340 + code/game/objects/items/weapons/game_kit.dm | 136 + code/game/objects/items/weapons/glass.dm | 254 + code/game/objects/items/weapons/grenades.dm | 385 ++ code/game/objects/items/weapons/guns_ammo.dm | 867 +++ code/game/objects/items/weapons/implants.dm | 253 + code/game/objects/items/weapons/kitchen.dm | 114 + code/game/objects/items/weapons/medical.dm | 107 + .../game/objects/items/weapons/metals_rods.dm | 433 ++ code/game/objects/items/weapons/misc.dm | 83 + .../objects/items/weapons/mops_cleaners.dm | 81 + .../game/objects/items/weapons/papers_bins.dm | 610 ++ .../objects/items/weapons/surgery_tools.dm | 179 + .../objects/items/weapons/swords_axes_etc.dm | 211 + .../objects/items/weapons/table_rack_parts.dm | 82 + .../objects/items/weapons/teleportation.dm | 138 + .../game/objects/items/weapons/tiles_wires.dm | 111 + code/game/objects/items/weapons/toilets.dm | 94 + code/game/objects/items/weapons/tools.dm | 235 + code/game/objects/items/weapons/uplinks.dm | 167 + code/game/objects/kitchen.dm | 72 + code/game/objects/noticeboard.dm | 67 + code/game/objects/object_procs.dm | 23 + code/game/objects/portals.dm | 37 + code/game/objects/radio/beacon.dm | 15 + code/game/objects/radio/electropack.dm | 151 + code/game/objects/radio/intercom.dm | 17 + code/game/objects/radio/radio.dm | 289 + code/game/objects/radio/signaler.dm | 156 + code/game/objects/secstorage/sbriefcase.dm | 47 + code/game/objects/secstorage/secstorage.dm | 250 + code/game/objects/secstorage/ssafe.dm | 20 + code/game/objects/secure_area.dm | 18 + code/game/objects/secure_closets.dm | 257 + code/game/objects/shieldgen.dm | 236 + code/game/objects/spawners/bomb.dm | 80 + code/game/objects/stool.dm | 265 + code/game/objects/storage/backpack.dm | 62 + code/game/objects/storage/bible.dm | 90 + code/game/objects/storage/briefcase.dm | 40 + code/game/objects/storage/crates.dm | 199 + code/game/objects/storage/firstaid.dm | 88 + code/game/objects/storage/kit.dm | 151 + code/game/objects/storage/storage.dm | 239 + code/game/objects/storage/toolbox.dm | 31 + code/game/objects/structures.dm | 112 + code/game/objects/tables_racks.dm | 218 + code/game/objects/tank.dm | 539 ++ code/game/objects/weapons.dm | 1251 ++++ code/game/objects/window.dm | 249 + code/game/sound.dm | 88 + code/game/spacecraft/manufacturing.dm | 247 + code/game/spacecraft/shipcore.dm | 349 + code/game/spacecraft/syndicatebeacon.dm | 99 + code/game/status.dm | 61 + code/game/supplyshuttle.dm | 696 ++ code/game/throwing.dm | 183 + code/game/topic.dm | 33 + code/game/turf.dm | 835 +++ code/game/verbs/AI_status.dm | 13 + code/game/verbs/ai_lockdown.dm | 60 + code/game/verbs/authorize.dm | 164 + code/game/verbs/begin.dm | 0 code/game/verbs/checkkarma.dm | 22 + code/game/verbs/ooc.dm | 70 + code/game/verbs/suicide.dm | 112 + code/game/verbs/who.dm | 46 + code/game/vials.dm | 287 + code/game/vote.dm | 334 + code/modules/admin/admin.dm | 1928 ++++++ code/modules/admin/admin_verbs.dm | 778 +++ code/modules/admin/banjob.dm | 46 + code/modules/admin/create_mob.dm | 9 + code/modules/admin/create_object.dm | 9 + code/modules/admin/create_turf.dm | 9 + code/modules/admin/verbs/adminhelp.dm | 21 + code/modules/admin/verbs/adminjump.dm | 91 + code/modules/admin/verbs/adminsay.dm | 28 + code/modules/admin/verbs/changetemperature.dm | 16 + code/modules/admin/verbs/deadsay.dm | 24 + code/modules/admin/verbs/debug.dm | 194 + code/modules/admin/verbs/diagnostics.dm | 109 + code/modules/admin/verbs/grillify.dm | 23 + code/modules/admin/verbs/modifyvariables.dm | 371 + code/modules/admin/verbs/playsound.dm | 33 + code/modules/admin/verbs/pray.dm | 21 + code/modules/admin/verbs/randomverbs.dm | 471 ++ code/modules/admin/verbs/ticklag.dm | 20 + code/modules/mob/dead/dead.dm | 0 code/modules/mob/dead/observer/hud.dm | 2 + code/modules/mob/dead/observer/login.dm | 10 + code/modules/mob/dead/observer/login.dm.bak | 14 + code/modules/mob/dead/observer/observer.dm | 222 + .../modules/mob/dead/observer/observer.dm.bak | 170 + code/modules/mob/dead/observer/say.dm | 30 + code/modules/mob/dead/observer/say.dm.bak | 30 + code/modules/mob/living/carbon/alien/alien.dm | 0 .../carbon/alien/humanoid/alien_powers.dm | 291 + .../mob/living/carbon/alien/humanoid/death.dm | 57 + .../mob/living/carbon/alien/humanoid/emote.dm | 105 + .../mob/living/carbon/alien/humanoid/hud.dm | 302 + .../living/carbon/alien/humanoid/humanoid.dm | 780 +++ .../mob/living/carbon/alien/humanoid/life.dm | 351 + .../living/carbon/alien/humanoid/life_new.dm | 590 ++ .../mob/living/carbon/alien/humanoid/login.dm | 106 + .../mob/living/carbon/alien/humanoid/queen.dm | 189 + .../mob/living/carbon/alien/larva/death.dm | 51 + .../mob/living/carbon/alien/larva/emote.dm | 105 + .../mob/living/carbon/alien/larva/hud.dm | 228 + .../mob/living/carbon/alien/larva/larva.dm | 554 ++ .../mob/living/carbon/alien/larva/life.dm | 510 ++ .../mob/living/carbon/alien/larva/login.dm | 12 + .../mob/living/carbon/alien/larva/powers.dm | 30 + code/modules/mob/living/carbon/alien/say.dm | 11 + code/modules/mob/living/carbon/beast/beast.dm | 1 + .../mob/living/carbon/beast/bodypart.dm | 15 + code/modules/mob/living/carbon/beast/death.dm | 13 + .../mob/living/carbon/beast/examine.dm | 0 code/modules/mob/living/carbon/beast/life.dm | 0 code/modules/mob/living/carbon/beast/login.dm | 0 code/modules/mob/living/carbon/beast/say.dm | 0 code/modules/mob/living/carbon/carbon.dm | 44 + code/modules/mob/living/carbon/human/death.dm | 87 + code/modules/mob/living/carbon/human/emote.dm | 443 ++ .../mob/living/carbon/human/examine.dm | 108 + code/modules/mob/living/carbon/human/hud.dm | 556 ++ code/modules/mob/living/carbon/human/human.dm | 2329 +++++++ code/modules/mob/living/carbon/human/life.dm | 896 +++ code/modules/mob/living/carbon/human/login.dm | 12 + .../mob/living/carbon/human/savefile.dm | 92 + code/modules/mob/living/carbon/human/say.dm | 11 + .../mob/living/carbon/human/whisper.dm | 128 + .../modules/mob/living/carbon/monkey/death.dm | 38 + .../modules/mob/living/carbon/monkey/emote.dm | 105 + .../mob/living/carbon/monkey/examine.dm | 31 + code/modules/mob/living/carbon/monkey/hud.dm | 552 ++ code/modules/mob/living/carbon/monkey/life.dm | 585 ++ .../modules/mob/living/carbon/monkey/login.dm | 54 + .../mob/living/carbon/monkey/monkey.dm | 577 ++ code/modules/mob/living/carbon/monkey/say.dm | 2 + code/modules/mob/living/living.dm | 0 code/modules/mob/living/say.dm | 217 + code/modules/mob/living/silicon/ai/ai.dm | 298 + code/modules/mob/living/silicon/ai/death.dm | 43 + code/modules/mob/living/silicon/ai/examine.dm | 21 + code/modules/mob/living/silicon/ai/hud.dm | 2 + code/modules/mob/living/silicon/ai/life.dm | 208 + code/modules/mob/living/silicon/ai/login.dm | 27 + code/modules/mob/living/silicon/ai/logout.dm | 11 + code/modules/mob/living/silicon/ai/move.dm | 78 + code/modules/mob/living/silicon/ai/say.dm | 16 + .../mob/living/silicon/hivebot/death.dm | 24 + .../mob/living/silicon/hivebot/emote.dm | 137 + .../mob/living/silicon/hivebot/examine.dm | 20 + .../living/silicon/hivebot/hive_modules.dm | 57 + .../mob/living/silicon/hivebot/hivebot.dm | 508 ++ .../modules/mob/living/silicon/hivebot/hud.dm | 250 + .../mob/living/silicon/hivebot/life.dm | 229 + .../mob/living/silicon/hivebot/login.dm | 15 + .../mob/living/silicon/hivebot/mainframe.dm | 178 + .../modules/mob/living/silicon/hivebot/say.dm | 18 + .../modules/mob/living/silicon/robot/death.dm | 39 + .../modules/mob/living/silicon/robot/emote.dm | 137 + .../mob/living/silicon/robot/examine.dm | 24 + code/modules/mob/living/silicon/robot/hud.dm | 250 + code/modules/mob/living/silicon/robot/life.dm | 286 + .../modules/mob/living/silicon/robot/login.dm | 20 + .../modules/mob/living/silicon/robot/robot.dm | 796 +++ .../mob/living/silicon/robot/robot_modules.dm | 101 + code/modules/mob/living/silicon/robot/say.dm | 18 + code/modules/mob/living/silicon/say.dm | 74 + code/modules/mob/living/silicon/silicon.dm | 11 + code/modules/mob/login.dm | 40 + code/modules/mob/logout.dm | 7 + code/modules/mob/mob.dm | 2014 ++++++ code/modules/mob/new_player/new_player.dm | 470 ++ code/modules/mob/new_player/preferences.dm | 639 ++ code/modules/mob/organs.dm | 83 + code/modules/mob/say.dm | 59 + code/modules/mob/transform_procs.dm | 234 + code/modules/power/antimatter/computer.dm | 93 + code/modules/power/antimatter/engine.dm | 207 + code/modules/power/antimatter/fuel.dm | 99 + code/modules/power/apc.dm | 892 +++ code/modules/power/cable.dm | 435 ++ code/modules/power/cell.dm | 88 + code/modules/power/engine.dm | 40 + code/modules/power/generator.dm | 132 + code/modules/power/generator_type2.dm | 128 + code/modules/power/lighting.dm | 493 ++ code/modules/power/port_gen.dm | 36 + code/modules/power/portable.dm | 0 code/modules/power/power.dm | 364 + code/modules/power/sd_DynamicAreaLighting.dm | 772 +++ code/modules/power/smes.dm | 292 + code/modules/power/solar.dm | 293 + code/modules/power/terminal.dm | 23 + code/modules/power/tracker.dm | 49 + code/modules/power/turbine.dm | 328 + code/names.dm | 8 + code/notes.dm | 59 + code/setup.dm | 138 + code/stylesheet.dm | 103 + code/unused/dna.dm | 952 +++ code/unused/heater.dm | 201 + code/unused/modules/admin/ban.dm | 0 code/unused/musicplayer.dm | 15 + code/unused/siphs.dm | 515 ++ code/unused/vehicle.dm | 145 + config/access levels.txt | 50 + config/admins.txt | 3 + config/config.txt | 65 + config/motd help.txt | 1 + config/motd-auth.txt | 1 + config/motd-noauth.txt | 1 + config/motd.txt | 3 + config/names/ai.txt | 148 + config/names/death_commando.txt | 70 + config/names/first.txt | 1502 ++++ config/names/first_female.txt | 814 +++ config/names/first_male.txt | 755 ++ config/names/last.txt | 644 ++ config/names/loggedsay.txt | 48 + config/rules.html | 31 + config/testers.txt | 1 + data/mode.txt | 1 + goonstation.dme | 668 ++ icons/80x15.png | Bin 0 -> 697 bytes icons/88x31.png | Bin 0 -> 5460 bytes icons/PSD files/door.psd | Bin 0 -> 47999 bytes icons/Testing/air_meter.dmi | Bin 0 -> 463 bytes icons/Testing/atmos_testing.dmi | Bin 0 -> 390 bytes icons/Testing/turf_analysis.dmi | Bin 0 -> 1144 bytes icons/Thumbs.db | Bin 0 -> 27648 bytes icons/admin_pm.html | 53 + icons/changelog.html | 896 +++ icons/create_object.html | 105 + icons/dice.png | Bin 0 -> 1838 bytes icons/dice20.png | Bin 0 -> 810 bytes icons/effects/160x160.dmi | Bin 0 -> 219 bytes icons/effects/96x96.dmi | Bin 0 -> 187360 bytes icons/effects/alert.dmi | Bin 0 -> 944 bytes icons/effects/alphacolors.dmi | Bin 0 -> 395 bytes icons/effects/beam.dmi | Bin 0 -> 2769 bytes icons/effects/blood.dmi | Bin 0 -> 38360 bytes icons/effects/effects.dmi | Bin 0 -> 186834 bytes icons/effects/fire.dmi | Bin 0 -> 233985 bytes icons/effects/genetics.dmi | Bin 0 -> 14115 bytes icons/effects/lighting.dmi | Bin 0 -> 404 bytes icons/effects/oil.dmi | Bin 0 -> 2214 bytes icons/effects/plasma.dmi | Bin 0 -> 712 bytes icons/effects/ss13_dark_alpha7.dmi | Bin 0 -> 320 bytes icons/effects/station_explosion.dmi | Bin 0 -> 3673168 bytes icons/effects/tile_effects.dmi | Bin 0 -> 739 bytes icons/effects/water.dmi | Bin 0 -> 2729 bytes icons/help.html | 392 ++ icons/map.png | Bin 0 -> 5629 bytes icons/misc/beach.dmi | Bin 0 -> 7280 bytes icons/misc/beach2.dmi | Bin 0 -> 3760 bytes icons/misc/buildmode.dmi | Bin 0 -> 788 bytes icons/misc/flags.dmi | Bin 0 -> 2663 bytes icons/misc/fullscreen.dmi | Bin 0 -> 409601 bytes icons/misc/imap.dmi | Bin 0 -> 208 bytes icons/misc/inpipe.dmi | Bin 0 -> 1408 bytes icons/misc/largeui.dmi | Bin 0 -> 271 bytes icons/misc/mark.dmi | Bin 0 -> 2406 bytes icons/misc/mouse.dmi | Bin 0 -> 263 bytes icons/misc/old_or_unused.dmi | Bin 0 -> 15582 bytes icons/mob/alien.dmi | Bin 0 -> 22156 bytes icons/mob/back.dmi | Bin 0 -> 4189 bytes icons/mob/belt.dmi | Bin 0 -> 1617 bytes icons/mob/blob.dmi | Bin 0 -> 49409 bytes icons/mob/dam_human.dmi | Bin 0 -> 9103 bytes icons/mob/dam_mask.dmi | Bin 0 -> 1503 bytes icons/mob/ears.dmi | Bin 0 -> 455 bytes icons/mob/eyes.dmi | Bin 0 -> 1589 bytes icons/mob/feet.dmi | Bin 0 -> 2560 bytes icons/mob/golems.dmi | Bin 0 -> 1824 bytes icons/mob/hands.dmi | Bin 0 -> 741 bytes icons/mob/head.dmi | Bin 0 -> 17112 bytes icons/mob/hivebot.dmi | 0 icons/mob/human.dmi | Bin 0 -> 14825 bytes icons/mob/human_face.dmi | Bin 0 -> 4481 bytes icons/mob/items_lefthand.dmi | Bin 0 -> 61431 bytes icons/mob/items_righthand.dmi | Bin 0 -> 63716 bytes icons/mob/mask.dmi | Bin 0 -> 7321 bytes icons/mob/mob.dmi | Bin 0 -> 60104 bytes icons/mob/monkey.dmi | Bin 0 -> 1934 bytes icons/mob/robots.dmi | Bin 0 -> 19915 bytes icons/mob/screen1.dmi | Bin 0 -> 68784 bytes icons/mob/screen1_alien.dmi | Bin 0 -> 84046 bytes icons/mob/screen1_robot.dmi | Bin 0 -> 28399 bytes icons/mob/sectoid.dmi | Bin 0 -> 423 bytes icons/mob/suit.dmi | Bin 0 -> 56006 bytes icons/mob/techpriest.dmi | Bin 0 -> 4772 bytes icons/mob/uniform.dmi | Bin 0 -> 111601 bytes icons/mob/uniform_fat.dmi | Bin 0 -> 32068 bytes icons/mob/zone_sel.dmi | Bin 0 -> 1469 bytes icons/obj/AM_Engine.dmi | Bin 0 -> 3332 bytes icons/obj/Cryogenic2.dmi | Bin 0 -> 39909 bytes icons/obj/aibots.dmi | Bin 0 -> 11493 bytes icons/obj/airlock_machines.dmi | Bin 0 -> 1212 bytes icons/obj/airtunnel.dmi | Bin 0 -> 2706 bytes icons/obj/ammo.dmi | Bin 0 -> 1198 bytes icons/obj/assemblies.dmi | Bin 0 -> 10445 bytes icons/obj/atmos.dmi | Bin 0 -> 16147 bytes icons/obj/atmospherics/blue_pipe_tank.dmi | Bin 0 -> 593 bytes icons/obj/atmospherics/cold_sink.dmi | Bin 0 -> 595 bytes icons/obj/atmospherics/digital_valve.dmi | Bin 0 -> 4770 bytes icons/obj/atmospherics/dp_vent_pump.dmi | Bin 0 -> 10462 bytes icons/obj/atmospherics/filter.dmi | Bin 0 -> 14688 bytes icons/obj/atmospherics/heat_exchanger.dmi | Bin 0 -> 639 bytes icons/obj/atmospherics/mixer.dmi | Bin 0 -> 2698 bytes icons/obj/atmospherics/orange_pipe_tank.dmi | Bin 0 -> 630 bytes icons/obj/atmospherics/outlet_injector.dmi | Bin 0 -> 1079 bytes icons/obj/atmospherics/oxygen_generator.dmi | Bin 0 -> 1447 bytes icons/obj/atmospherics/passive_gate.dmi | Bin 0 -> 1913 bytes icons/obj/atmospherics/pipe_manifold.dmi | Bin 0 -> 3753 bytes icons/obj/atmospherics/pipe_tank.dmi | Bin 0 -> 613 bytes icons/obj/atmospherics/pipe_vent.dmi | Bin 0 -> 3725 bytes .../obj/atmospherics/portables_connector.dmi | Bin 0 -> 2501 bytes icons/obj/atmospherics/pump.dmi | Bin 0 -> 7363 bytes .../obj/atmospherics/red_orange_pipe_tank.dmi | Bin 0 -> 688 bytes icons/obj/atmospherics/red_pipe.dmi | Bin 0 -> 1042 bytes icons/obj/atmospherics/red_pipe_tank.dmi | Bin 0 -> 603 bytes icons/obj/atmospherics/valve.dmi | Bin 0 -> 4763 bytes icons/obj/atmospherics/vent_pump.dmi | Bin 0 -> 10359 bytes icons/obj/atmospherics/vent_scrubber.dmi | Bin 0 -> 5780 bytes icons/obj/atmospherics/volume_pump.dmi | Bin 0 -> 2879 bytes icons/obj/card.dmi | Bin 0 -> 1609 bytes icons/obj/chemical.dmi | Bin 0 -> 10806 bytes icons/obj/cigarettes.dmi | Bin 0 -> 804 bytes icons/obj/cloning.dmi | Bin 0 -> 8298 bytes icons/obj/closet.dmi | Bin 0 -> 11128 bytes icons/obj/clothing/glasses.dmi | Bin 0 -> 1414 bytes icons/obj/clothing/gloves.dmi | Bin 0 -> 660 bytes icons/obj/clothing/hats.dmi | Bin 0 -> 5699 bytes icons/obj/clothing/masks.dmi | Bin 0 -> 3325 bytes icons/obj/clothing/shoes.dmi | Bin 0 -> 2864 bytes icons/obj/clothing/suits.dmi | Bin 0 -> 12056 bytes icons/obj/clothing/uniforms.dmi | Bin 0 -> 20452 bytes icons/obj/computer.dmi | Bin 0 -> 28368 bytes icons/obj/computer_frame.dmi | Bin 0 -> 625 bytes icons/obj/craft.dmi | Bin 0 -> 1856 bytes icons/obj/decals.dmi | Bin 0 -> 7971 bytes icons/obj/device.dmi | Bin 0 -> 17198 bytes icons/obj/doors/Door1.dmi | Bin 0 -> 75085 bytes icons/obj/doors/Doorcom.dmi | Bin 0 -> 11547 bytes icons/obj/doors/Dooreng.dmi | Bin 0 -> 3277 bytes icons/obj/doors/Doorext.dmi | Bin 0 -> 9729 bytes icons/obj/doors/Doorf.dmi | Bin 0 -> 43423 bytes icons/obj/doors/Doorfire.dmi | Bin 0 -> 3066 bytes icons/obj/doors/Doorglass.dmi | Bin 0 -> 11797 bytes icons/obj/doors/Doormaint.dmi | Bin 0 -> 10634 bytes icons/obj/doors/Doorsec.dmi | Bin 0 -> 3125 bytes icons/obj/doors/door_fire2.dmi | Bin 0 -> 8117 bytes icons/obj/doors/doorint.dmi | Bin 0 -> 10228 bytes icons/obj/doors/doormed.dmi | Bin 0 -> 10805 bytes icons/obj/doors/doormorgue.dmi | Bin 0 -> 2344 bytes icons/obj/doors/rapid_pdoor.dmi | Bin 0 -> 3121 bytes icons/obj/doors/windoor.dmi | Bin 0 -> 30082 bytes icons/obj/dropper.dmi | Bin 0 -> 486 bytes icons/obj/engine.dmi | Bin 0 -> 46054 bytes icons/obj/escapepod.dmi | Bin 0 -> 4381 bytes icons/obj/food.dmi | Bin 0 -> 13726 bytes icons/obj/grenade.dmi | Bin 0 -> 454 bytes icons/obj/gun.dmi | Bin 0 -> 6479 bytes icons/obj/hydroponics.dmi | Bin 0 -> 17603 bytes icons/obj/items.dmi | Bin 0 -> 20422 bytes icons/obj/janitor.dmi | Bin 0 -> 1107 bytes icons/obj/junk.dmi | Bin 0 -> 447 bytes icons/obj/kitchen.dmi | Bin 0 -> 8408 bytes icons/obj/library.dmi | Bin 0 -> 6729 bytes icons/obj/lighting.dmi | Bin 0 -> 7250 bytes icons/obj/machines/fiber.dmi | Bin 0 -> 244 bytes icons/obj/machines/heavy_fiber.dmi | Bin 0 -> 283 bytes icons/obj/machines/lasers.dmi | Bin 0 -> 1406 bytes icons/obj/machines/reactor.dmi | Bin 0 -> 283 bytes icons/obj/magic.dmi | Bin 0 -> 4396 bytes icons/obj/magic_pillar.dmi | Bin 0 -> 6006 bytes icons/obj/magic_terror.dmi | Bin 0 -> 436043 bytes icons/obj/meteor.dmi | Bin 0 -> 2432 bytes icons/obj/meter.dmi | Bin 0 -> 693 bytes icons/obj/mining.dmi | Bin 0 -> 5797 bytes icons/obj/module.dmi | Bin 0 -> 725 bytes icons/obj/monitors.dmi | Bin 0 -> 5414 bytes icons/obj/musician.dmi | Bin 0 -> 1909 bytes icons/obj/objects.dmi | Bin 0 -> 64477 bytes icons/obj/optics.dmi | Bin 0 -> 1964 bytes icons/obj/otherthing.dmi | Bin 0 -> 1838 bytes icons/obj/pda.dmi | Bin 0 -> 3213 bytes icons/obj/pipe-item.dmi | Bin 0 -> 9379 bytes icons/obj/pipes.dmi | Bin 0 -> 38157 bytes icons/obj/pipes/disposal.dmi | Bin 0 -> 57948 bytes icons/obj/pipes/heat.dmi | Bin 0 -> 1749 bytes icons/obj/pipes/junction.dmi | Bin 0 -> 619 bytes icons/obj/pipes/large.dmi | Bin 0 -> 8198 bytes icons/obj/pipes/regular.dmi | Bin 0 -> 2758 bytes icons/obj/pipes2.dmi | Bin 0 -> 5375 bytes icons/obj/power.dmi | Bin 0 -> 15323 bytes icons/obj/power_cond.dmi | Bin 0 -> 4298 bytes icons/obj/power_local.dmi | Bin 0 -> 1829 bytes icons/obj/projectiles.dmi | Bin 0 -> 2349 bytes icons/obj/recycling.dmi | Bin 0 -> 24374 bytes icons/obj/robot_parts.dmi | Bin 0 -> 867 bytes icons/obj/scrap.dmi | Bin 0 -> 11048 bytes icons/obj/shards.dmi | Bin 0 -> 1385 bytes icons/obj/singularity.dmi | Bin 0 -> 6658 bytes icons/obj/stationobjs.dmi | Bin 0 -> 56550 bytes icons/obj/status_display.dmi | Bin 0 -> 7338 bytes icons/obj/storage.dmi | Bin 0 -> 17771 bytes icons/obj/structures.dmi | Bin 0 -> 23674 bytes icons/obj/surgery.dmi | Bin 0 -> 8137 bytes icons/obj/syringe.dmi | Bin 0 -> 644 bytes icons/obj/tank.dmi | Bin 0 -> 1071 bytes icons/obj/tubing.dmi | Bin 0 -> 1730 bytes icons/obj/turrets.dmi | Bin 0 -> 4976 bytes icons/obj/vending.dmi | Bin 0 -> 22620 bytes icons/obj/weapons.dmi | Bin 0 -> 10257 bytes icons/obj/wizard.dmi | Bin 0 -> 5855 bytes icons/postcardsmall.jpg | Bin 0 -> 17836 bytes icons/somerights20.png | Bin 0 -> 958 bytes icons/sprites_todo.txt | 8 + icons/ss13_32.png | Bin 0 -> 5762 bytes icons/ss13_64.png | Bin 0 -> 10413 bytes icons/turf/areas.dmi | Bin 0 -> 10118 bytes icons/turf/floors.dmi | Bin 0 -> 215914 bytes icons/turf/shuttle.dmi | Bin 0 -> 66885 bytes icons/turf/space.dmi | Bin 0 -> 3896 bytes icons/turf/walls.dmi | Bin 0 -> 52080 bytes interface/skin.dmf | 753 ++ maps/backup/trunkmap.dmm | 6137 +++++++++++++++++ maps/backup/trunkmap07132010.dmm | 5583 +++++++++++++++ maps/trunkmap.dmm | 6134 ++++++++++++++++ maps/trunkmap.rar | Bin 0 -> 69416 bytes music/music help.txt | 1 + sound/ambience/ambiatm1.ogg | Bin 0 -> 74840 bytes sound/ambience/ambicha1.ogg | Bin 0 -> 102387 bytes sound/ambience/ambicha2.ogg | Bin 0 -> 44743 bytes sound/ambience/ambicha3.ogg | Bin 0 -> 43212 bytes sound/ambience/ambicha4.ogg | Bin 0 -> 62500 bytes sound/ambience/ambience_outdoors.ogg | Bin 0 -> 280161 bytes sound/ambience/ambieng1.ogg | Bin 0 -> 255630 bytes sound/ambience/ambigen1.ogg | Bin 0 -> 83412 bytes sound/ambience/ambigen10.ogg | Bin 0 -> 38533 bytes sound/ambience/ambigen11.ogg | Bin 0 -> 152721 bytes sound/ambience/ambigen12.ogg | Bin 0 -> 194041 bytes sound/ambience/ambigen13.ogg | Bin 0 -> 84154 bytes sound/ambience/ambigen14.ogg | Bin 0 -> 35707 bytes sound/ambience/ambigen2.ogg | Bin 0 -> 83412 bytes sound/ambience/ambigen3.ogg | Bin 0 -> 41042 bytes sound/ambience/ambigen4.ogg | Bin 0 -> 30299 bytes sound/ambience/ambigen5.ogg | Bin 0 -> 28856 bytes sound/ambience/ambigen6.ogg | Bin 0 -> 101163 bytes sound/ambience/ambigen7.ogg | Bin 0 -> 51340 bytes sound/ambience/ambigen8.ogg | Bin 0 -> 41360 bytes sound/ambience/ambigen9.ogg | Bin 0 -> 30800 bytes sound/ambience/ambimal1.ogg | Bin 0 -> 325665 bytes sound/ambience/ambimal2.ogg | Bin 0 -> 261830 bytes sound/ambience/ambimal3.ogg | Bin 0 -> 8997 bytes sound/ambience/ambimo1.ogg | Bin 0 -> 226606 bytes sound/ambience/ambimo2.ogg | Bin 0 -> 50936 bytes sound/ambience/seag1.ogg | Bin 0 -> 9577 bytes sound/ambience/seag2.ogg | Bin 0 -> 7130 bytes sound/ambience/seag3.ogg | Bin 0 -> 8199 bytes sound/ambience/shipambience.ogg | Bin 0 -> 91744 bytes sound/ambience/shore.ogg | Bin 0 -> 237212 bytes sound/effects/Explosion1.ogg | Bin 0 -> 20834 bytes sound/effects/Explosion2.ogg | Bin 0 -> 21899 bytes sound/effects/Glassbr1.ogg | Bin 0 -> 12948 bytes sound/effects/Glassbr2.ogg | Bin 0 -> 11173 bytes sound/effects/Glassbr3.ogg | Bin 0 -> 48690 bytes sound/effects/Glasshit.ogg | Bin 0 -> 9668 bytes sound/effects/Heart Beat.ogg | Bin 0 -> 134640 bytes sound/effects/attackblob.ogg | Bin 0 -> 9345 bytes sound/effects/bamf.ogg | Bin 0 -> 15223 bytes sound/effects/bang.ogg | Bin 0 -> 5133 bytes sound/effects/blobattack.ogg | Bin 0 -> 10401 bytes sound/effects/bubbles.ogg | Bin 0 -> 14273 bytes sound/effects/bubbles2.ogg | Bin 0 -> 102623 bytes sound/effects/clang.ogg | Bin 0 -> 19932 bytes sound/effects/explosionfar.ogg | Bin 0 -> 12252 bytes sound/effects/ghost.ogg | Bin 0 -> 36048 bytes sound/effects/ghost2.ogg | Bin 0 -> 13249 bytes sound/effects/grillehit.ogg | Bin 0 -> 7247 bytes sound/effects/pop.ogg | Bin 0 -> 4525 bytes sound/effects/screech.ogg | Bin 0 -> 18256 bytes sound/effects/slosh.ogg | Bin 0 -> 18306 bytes sound/effects/smoke.ogg | Bin 0 -> 24160 bytes sound/effects/snap.ogg | Bin 0 -> 7827 bytes sound/effects/sparks1.ogg | Bin 0 -> 7272 bytes sound/effects/sparks2.ogg | Bin 0 -> 8202 bytes sound/effects/sparks3.ogg | Bin 0 -> 8757 bytes sound/effects/sparks4.ogg | Bin 0 -> 9858 bytes sound/effects/splat.ogg | Bin 0 -> 11605 bytes sound/effects/spray.ogg | Bin 0 -> 12875 bytes sound/effects/syringeproj.ogg | Bin 0 -> 6957 bytes sound/effects/zzzt.ogg | Bin 0 -> 4995 bytes sound/items/Crowbar.ogg | Bin 0 -> 5596 bytes sound/items/Deconstruct.ogg | Bin 0 -> 8219 bytes sound/items/Ratchet.ogg | Bin 0 -> 7533 bytes sound/items/Screwdriver.ogg | Bin 0 -> 12529 bytes sound/items/Screwdriver2.ogg | Bin 0 -> 4733 bytes sound/items/Welder.ogg | Bin 0 -> 15662 bytes sound/items/Welder2.ogg | Bin 0 -> 11513 bytes sound/items/Wirecutter.ogg | Bin 0 -> 5628 bytes sound/items/bikehorn.ogg | Bin 0 -> 10434 bytes sound/items/drink.ogg | Bin 0 -> 21414 bytes sound/items/eatfood.ogg | Bin 0 -> 33186 bytes sound/items/polaroid1.ogg | Bin 0 -> 13055 bytes sound/items/polaroid2.ogg | Bin 0 -> 13280 bytes sound/machines/airlock.ogg | Bin 0 -> 11695 bytes sound/machines/blender.ogg | Bin 0 -> 64478 bytes sound/machines/buzz-sigh.ogg | Bin 0 -> 8972 bytes sound/machines/buzz-two.ogg | Bin 0 -> 12724 bytes sound/machines/chime.ogg | Bin 0 -> 9549 bytes sound/machines/click.ogg | Bin 0 -> 6325 bytes sound/machines/ding.ogg | Bin 0 -> 15045 bytes sound/machines/disposalflush.ogg | Bin 0 -> 37814 bytes sound/machines/door_close.ogg | Bin 0 -> 12783 bytes sound/machines/door_locked.ogg | Bin 0 -> 9569 bytes sound/machines/door_open.ogg | Bin 0 -> 14249 bytes sound/machines/genetics.ogg | Bin 0 -> 182558 bytes sound/machines/hiss.ogg | Bin 0 -> 30286 bytes sound/machines/ping.ogg | Bin 0 -> 9308 bytes sound/machines/signal.ogg | Bin 0 -> 155288 bytes sound/machines/twobeep.ogg | Bin 0 -> 5853 bytes sound/machines/warning-buzzer.ogg | Bin 0 -> 31756 bytes sound/machines/windowdoor.ogg | Bin 0 -> 12359 bytes sound/misc/NewRound.ogg | Bin 0 -> 32026 bytes sound/misc/NewRound2.ogg | Bin 0 -> 26564 bytes sound/misc/clownstep1.ogg | Bin 0 -> 6116 bytes sound/misc/clownstep2.ogg | Bin 0 -> 6176 bytes sound/misc/glass_step.ogg | Bin 0 -> 11279 bytes sound/misc/main.ogg | Bin 0 -> 904912 bytes sound/misc/meteorimpact.ogg | Bin 0 -> 8977 bytes sound/misc/null.ogg | Bin 0 -> 4072 bytes sound/misc/rustle1.ogg | Bin 0 -> 16338 bytes sound/misc/rustle2.ogg | Bin 0 -> 10467 bytes sound/misc/rustle3.ogg | Bin 0 -> 10451 bytes sound/misc/rustle4.ogg | Bin 0 -> 10883 bytes sound/misc/rustle5.ogg | Bin 0 -> 10483 bytes sound/misc/slip.ogg | Bin 0 -> 4813 bytes sound/misc/traitor.ogg | Bin 0 -> 1367039 bytes sound/piano/pianoA.ogg | Bin 0 -> 11320 bytes sound/piano/pianoB.ogg | Bin 0 -> 11283 bytes sound/piano/pianoC.ogg | Bin 0 -> 11341 bytes sound/piano/pianoD.ogg | Bin 0 -> 11865 bytes sound/piano/pianoE.ogg | Bin 0 -> 11743 bytes sound/piano/pianoF.ogg | Bin 0 -> 11803 bytes sound/piano/pianoG.ogg | Bin 0 -> 11825 bytes sound/voice/bcreep.ogg | Bin 0 -> 4632 bytes sound/voice/bcriminal.ogg | Bin 0 -> 4577 bytes sound/voice/bfreeze.ogg | Bin 0 -> 4465 bytes sound/voice/bgod.ogg | Bin 0 -> 7490 bytes sound/voice/biamthelaw.ogg | Bin 0 -> 6035 bytes sound/voice/binsult.ogg | Bin 0 -> 24608 bytes sound/voice/bjustice.ogg | Bin 0 -> 4422 bytes sound/voice/bradio.ogg | Bin 0 -> 5611 bytes sound/voice/bsecureday.ogg | Bin 0 -> 4780 bytes sound/weapons/Egloves.ogg | Bin 0 -> 7045 bytes sound/weapons/Genhit.ogg | Bin 0 -> 12678 bytes sound/weapons/Gunshot.ogg | Bin 0 -> 7321 bytes sound/weapons/Laser.ogg | Bin 0 -> 7679 bytes sound/weapons/Taser.ogg | Bin 0 -> 6558 bytes sound/weapons/armbomb.ogg | Bin 0 -> 10665 bytes sound/weapons/flash.ogg | Bin 0 -> 9891 bytes sound/weapons/genhit1.ogg | Bin 0 -> 9432 bytes sound/weapons/genhit2.ogg | Bin 0 -> 8498 bytes sound/weapons/genhit3.ogg | Bin 0 -> 9033 bytes sound/weapons/handcuffs.ogg | Bin 0 -> 8896 bytes sound/weapons/punch1.ogg | Bin 0 -> 8817 bytes sound/weapons/punch2.ogg | Bin 0 -> 8751 bytes sound/weapons/punch3.ogg | Bin 0 -> 8620 bytes sound/weapons/punch4.ogg | Bin 0 -> 7884 bytes sound/weapons/punchmiss.ogg | Bin 0 -> 6528 bytes sound/weapons/shotgunpump.ogg | Bin 0 -> 13017 bytes sound/weapons/smash.ogg | Bin 0 -> 9660 bytes sound/weapons/thudswoosh.ogg | Bin 0 -> 8834 bytes 919 files changed, 136852 insertions(+) create mode 100644 code/ATMOSPHERICS/atmospherics.dm create mode 100644 code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm create mode 100644 code/ATMOSPHERICS/components/binary_devices/circulator.dm create mode 100644 code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm create mode 100644 code/ATMOSPHERICS/components/binary_devices/passive_gate.dm create mode 100644 code/ATMOSPHERICS/components/binary_devices/pump.dm create mode 100644 code/ATMOSPHERICS/components/binary_devices/volume_pump.dm create mode 100644 code/ATMOSPHERICS/components/filter.dm create mode 100644 code/ATMOSPHERICS/components/mixer.dm create mode 100644 code/ATMOSPHERICS/components/portables_connector.dm create mode 100644 code/ATMOSPHERICS/components/unary/cold_sink.dm create mode 100644 code/ATMOSPHERICS/components/unary/generator_input.dm create mode 100644 code/ATMOSPHERICS/components/unary/heat_exchanger.dm create mode 100644 code/ATMOSPHERICS/components/unary/heat_source.dm create mode 100644 code/ATMOSPHERICS/components/unary/outlet_injector.dm create mode 100644 code/ATMOSPHERICS/components/unary/oxygen_generator.dm create mode 100644 code/ATMOSPHERICS/components/unary/unary_base.dm create mode 100644 code/ATMOSPHERICS/components/unary/vent_pump.dm create mode 100644 code/ATMOSPHERICS/components/unary/vent_scrubber.dm create mode 100644 code/ATMOSPHERICS/components/valve.dm create mode 100644 code/ATMOSPHERICS/datum_pipe_network.dm create mode 100644 code/ATMOSPHERICS/datum_pipeline.dm create mode 100644 code/ATMOSPHERICS/pipes.dm create mode 100644 code/FEA/DEBUG_REMOVE_BEFORE_RELEASE.dm create mode 100644 code/FEA/FEA_airgroup.dm create mode 100644 code/FEA/FEA_fire.dm create mode 100644 code/FEA/FEA_gas_mixture.dm create mode 100644 code/FEA/FEA_group_helpers.dm create mode 100644 code/FEA/FEA_system.dm create mode 100644 code/FEA/FEA_turf_tile.dm create mode 100644 code/WorkInProgress/BrokenInhands.dm create mode 100644 code/WorkInProgress/Cameras.dm create mode 100644 code/WorkInProgress/Chemistry-Holder.dm create mode 100644 code/WorkInProgress/Chemistry-Machinery.dm create mode 100644 code/WorkInProgress/Chemistry-Readme.dm create mode 100644 code/WorkInProgress/Chemistry-Reagents.dm create mode 100644 code/WorkInProgress/Chemistry-Recipes.dm create mode 100644 code/WorkInProgress/Chemistry-Tools.dm create mode 100644 code/WorkInProgress/KeelinsStuff.dm create mode 100644 code/WorkInProgress/NewBan.dm create mode 100644 code/WorkInProgress/buildmode.dm create mode 100644 code/WorkInProgress/cloning.dm create mode 100644 code/WorkInProgress/computer2/airlock_control.dm create mode 100644 code/WorkInProgress/computer2/arcade.dm create mode 100644 code/WorkInProgress/computer2/base_program.dm create mode 100644 code/WorkInProgress/computer2/buildandrepair.dm create mode 100644 code/WorkInProgress/computer2/computerII.dm create mode 100644 code/WorkInProgress/computer2/filebrowse.dm create mode 100644 code/WorkInProgress/computer2/med_rec.dm create mode 100644 code/WorkInProgress/computer2/messenger.dm create mode 100644 code/WorkInProgress/computer2/peripherals.dm create mode 100644 code/WorkInProgress/explosion_particles.dm create mode 100644 code/WorkInProgress/optics/beam.dm create mode 100644 code/WorkInProgress/optics/laser-pointer.dm create mode 100644 code/WorkInProgress/optics/mirror.dm create mode 100644 code/WorkInProgress/pda2/base_os.dm create mode 100644 code/WorkInProgress/pda2/base_program.dm create mode 100644 code/WorkInProgress/pda2/pda2.dm create mode 100644 code/WorkInProgress/pda2/record_progs.dm create mode 100644 code/WorkInProgress/pda2/scanners.dm create mode 100644 code/WorkInProgress/pda2/smallprogs.dm create mode 100644 code/WorkInProgress/plants/plant.dm create mode 100644 code/WorkInProgress/recycling/conveyor.dm create mode 100644 code/WorkInProgress/recycling/disposal-construction.dm create mode 100644 code/WorkInProgress/recycling/disposal.dm create mode 100644 code/WorkInProgress/recycling/scrap.dm create mode 100644 code/_debug.dm create mode 100644 code/datums/ai_laws.dm create mode 100644 code/datums/chemical.dm create mode 100644 code/datums/computerfiles.dm create mode 100644 code/datums/configuration.dm create mode 100644 code/datums/datumvars.dm create mode 100644 code/datums/disease.dm create mode 100644 code/datums/diseases/alien_embryo.dm create mode 100644 code/datums/diseases/cold.dm create mode 100644 code/datums/diseases/dna_spread.dm create mode 100644 code/datums/diseases/fake_gbs.dm create mode 100644 code/datums/diseases/flu.dm create mode 100644 code/datums/diseases/gbs.dm create mode 100644 code/datums/diseases/jungle_fever.dm create mode 100644 code/datums/diseases/plasmatoid.dm create mode 100644 code/datums/diseases/robotic_transformation.dm create mode 100644 code/datums/diseases/xeno_transformation.dm create mode 100644 code/datums/mind.dm create mode 100644 code/datums/mixed.dm create mode 100644 code/datums/modules.dm create mode 100644 code/datums/organs.dm create mode 100644 code/datums/shuttle_controller.dm create mode 100644 code/datums/sun.dm create mode 100644 code/datums/vote.dm create mode 100644 code/defines/area/Space Station 13 areas.dm create mode 100644 code/defines/atom.dm create mode 100644 code/defines/client.dm create mode 100644 code/defines/global.dm create mode 100644 code/defines/hub.dm create mode 100644 code/defines/mob/dead/observer.dm create mode 100644 code/defines/mob/living/carbon/alien.dm create mode 100644 code/defines/mob/living/carbon/alien_humanoid.dm create mode 100644 code/defines/mob/living/carbon/alien_larva.dm create mode 100644 code/defines/mob/living/carbon/carbon.dm create mode 100644 code/defines/mob/living/carbon/changeling.dm create mode 100644 code/defines/mob/living/carbon/human.dm create mode 100644 code/defines/mob/living/carbon/monkey.dm create mode 100644 code/defines/mob/living/living.dm create mode 100644 code/defines/mob/living/silicon/ai.dm create mode 100644 code/defines/mob/living/silicon/hivebot.dm create mode 100644 code/defines/mob/living/silicon/robot.dm create mode 100644 code/defines/mob/living/silicon/silicon.dm create mode 100644 code/defines/mob/mob.dm create mode 100644 code/defines/obj.dm create mode 100644 code/defines/obj/assemblies.dm create mode 100644 code/defines/obj/closet.dm create mode 100644 code/defines/obj/clothing.dm create mode 100644 code/defines/obj/clothing/gimmick.dm create mode 100644 code/defines/obj/computer.dm create mode 100644 code/defines/obj/decal.dm create mode 100644 code/defines/obj/door.dm create mode 100644 code/defines/obj/food.dm create mode 100644 code/defines/obj/injector.dm create mode 100644 code/defines/obj/machinery.dm create mode 100644 code/defines/obj/nutrient.dm create mode 100644 code/defines/obj/radio.dm create mode 100644 code/defines/obj/seeds.dm create mode 100644 code/defines/obj/spawner.dm create mode 100644 code/defines/obj/spawner/bomb.dm create mode 100644 code/defines/obj/storage.dm create mode 100644 code/defines/obj/weapon.dm create mode 100644 code/defines/obj/window.dm create mode 100644 code/defines/procs/AStar.dm create mode 100644 code/defines/procs/church_name.dm create mode 100644 code/defines/procs/command_alert.dm create mode 100644 code/defines/procs/command_name.dm create mode 100644 code/defines/procs/dbcore.dm create mode 100644 code/defines/procs/gamehelpers.dm create mode 100644 code/defines/procs/helpers.dm create mode 100644 code/defines/procs/logging.dm create mode 100644 code/defines/procs/religion_name.dm create mode 100644 code/defines/procs/station_name.dm create mode 100644 code/defines/procs/statistics.dm create mode 100644 code/defines/procs/syndicate_name.dm create mode 100644 code/defines/turf.dm create mode 100644 code/defines/world.dm create mode 100644 code/game/airtunnel.dm create mode 100644 code/game/algorithm.dm create mode 100644 code/game/area/ai_monitored.dm create mode 100644 code/game/area/areas.dm create mode 100644 code/game/atom_procs.dm create mode 100644 code/game/cellautomata.dm create mode 100644 code/game/chemistry.dm create mode 100644 code/game/communications.dm create mode 100644 code/game/dna.dm create mode 100644 code/game/gamemodes/blob/blob.dm create mode 100644 code/game/gamemodes/blob/theblob.dm create mode 100644 code/game/gamemodes/changeling/changeling_powers.dm create mode 100644 code/game/gamemodes/ctf/ctf.dm create mode 100644 code/game/gamemodes/ctf/ctf_items.dm create mode 100644 code/game/gamemodes/deathmatch/deathmatch.dm create mode 100644 code/game/gamemodes/events.dm create mode 100644 code/game/gamemodes/extended/extended.dm create mode 100644 code/game/gamemodes/game_mode.dm create mode 100644 code/game/gamemodes/gameticker.dm create mode 100644 code/game/gamemodes/intercept_report.dm create mode 100644 code/game/gamemodes/malfunction/Malf_Modules.dm create mode 100644 code/game/gamemodes/malfunction/malfunction.dm create mode 100644 code/game/gamemodes/meteor/meteor.dm create mode 100644 code/game/gamemodes/meteor/meteors.dm create mode 100644 code/game/gamemodes/monkey/monkey.dm create mode 100644 code/game/gamemodes/nuclear/nuclear.dm create mode 100644 code/game/gamemodes/nuclear/nuclearbomb.dm create mode 100644 code/game/gamemodes/nuclear/pinpointer.dm create mode 100644 code/game/gamemodes/objective.dm create mode 100644 code/game/gamemodes/restructuring/restructuring.dm create mode 100644 code/game/gamemodes/revolution/revolution.dm create mode 100644 code/game/gamemodes/ruby/ruby.dm create mode 100644 code/game/gamemodes/sandbox/h_sandbox.dm create mode 100644 code/game/gamemodes/sandbox/sandbox.dm create mode 100644 code/game/gamemodes/setupgame.dm create mode 100644 code/game/gamemodes/traitor/traitor.dm create mode 100644 code/game/gamemodes/wizard/spell10.dm create mode 100644 code/game/gamemodes/wizard/spell11.dm create mode 100644 code/game/gamemodes/wizard/spell12.dm create mode 100644 code/game/gamemodes/wizard/spell13.dm create mode 100644 code/game/gamemodes/wizard/spell14.dm create mode 100644 code/game/gamemodes/wizard/spell2.dm create mode 100644 code/game/gamemodes/wizard/spell3.dm create mode 100644 code/game/gamemodes/wizard/spell4.dm create mode 100644 code/game/gamemodes/wizard/spell6.dm create mode 100644 code/game/gamemodes/wizard/spell7.dm create mode 100644 code/game/gamemodes/wizard/spell8.dm create mode 100644 code/game/gamemodes/wizard/spell9.dm create mode 100644 code/game/gamemodes/wizard/wizard.dm create mode 100644 code/game/hud.dm create mode 100644 code/game/jobs/access.dm create mode 100644 code/game/jobs/jobprocs.dm create mode 100644 code/game/jobs/jobs.dm create mode 100644 code/game/landmarks.dm create mode 100644 code/game/machinery/Freezer.dm create mode 100644 code/game/machinery/OpTable.dm create mode 100644 code/game/machinery/Sleeper.dm create mode 100644 code/game/machinery/airlock_control.dm create mode 100644 code/game/machinery/alarm.dm create mode 100644 code/game/machinery/atmo_control.dm create mode 100644 code/game/machinery/atmoalter/canister.dm create mode 100644 code/game/machinery/atmoalter/meter.dm create mode 100644 code/game/machinery/atmoalter/portable_atmospherics.dm create mode 100644 code/game/machinery/atmoalter/pump.dm create mode 100644 code/game/machinery/atmoalter/scrubber.dm create mode 100644 code/game/machinery/autolathe.dm create mode 100644 code/game/machinery/bots/bots.dm create mode 100644 code/game/machinery/bots/cleanbot.dm create mode 100644 code/game/machinery/bots/floorbot.dm create mode 100644 code/game/machinery/bots/medbot.dm create mode 100644 code/game/machinery/bots/mulebot.dm create mode 100644 code/game/machinery/bots/secbot.dm create mode 100644 code/game/machinery/camera.dm create mode 100644 code/game/machinery/cell_charger.dm create mode 100644 code/game/machinery/computer/Operating.dm create mode 100644 code/game/machinery/computer/arcade.dm create mode 100644 code/game/machinery/computer/atmos.dm create mode 100644 code/game/machinery/computer/buildandrepair.dm create mode 100644 code/game/machinery/computer/communications.dm create mode 100644 code/game/machinery/computer/computer.dm create mode 100644 code/game/machinery/computer/crew.dm create mode 100644 code/game/machinery/computer/engine.dm create mode 100644 code/game/machinery/computer/hologram.dm create mode 100644 code/game/machinery/computer/medical.dm create mode 100644 code/game/machinery/computer/power.dm create mode 100644 code/game/machinery/computer/robot.dm create mode 100644 code/game/machinery/computer/security.dm create mode 100644 code/game/machinery/computer/shuttle.dm create mode 100644 code/game/machinery/cryo.dm create mode 100644 code/game/machinery/dispenser.dm create mode 100644 code/game/machinery/door_control.dm create mode 100644 code/game/machinery/doors/airlock.dm create mode 100644 code/game/machinery/doors/brigdoors.dm create mode 100644 code/game/machinery/doors/checkForMultipleDoors.dm create mode 100644 code/game/machinery/doors/door.dm create mode 100644 code/game/machinery/doors/firedoor.dm create mode 100644 code/game/machinery/doors/poddoor.dm create mode 100644 code/game/machinery/doors/shuttledoor.dm create mode 100644 code/game/machinery/doors/windowdoor.dm create mode 100644 code/game/machinery/embedded_controller/access_controller.dm create mode 100644 code/game/machinery/embedded_controller/airlock_controller.dm create mode 100644 code/game/machinery/embedded_controller/embedded_controller_base.dm create mode 100644 code/game/machinery/flasher.dm create mode 100644 code/game/machinery/gibber.dm create mode 100644 code/game/machinery/hologram.dm create mode 100644 code/game/machinery/hydroponics.dm create mode 100644 code/game/machinery/igniter.dm create mode 100644 code/game/machinery/lightswitch.dm create mode 100644 code/game/machinery/main.dm create mode 100644 code/game/machinery/microwave.dm create mode 100644 code/game/machinery/morgue.dm create mode 100644 code/game/machinery/navbeacon.dm create mode 100644 code/game/machinery/overview.dm create mode 100644 code/game/machinery/pipe/construction.dm create mode 100644 code/game/machinery/pipe/filter_control.dm create mode 100644 code/game/machinery/pipe/pipe.dm create mode 100644 code/game/machinery/pipe/pipe_dispenser.dm create mode 100644 code/game/machinery/pipe/pipe_filter.dm create mode 100644 code/game/machinery/processor.dm create mode 100644 code/game/machinery/recharger.dm create mode 100644 code/game/machinery/rechargestation.dm create mode 100644 code/game/machinery/robot_fabricator.dm create mode 100644 code/game/machinery/seed_extractor.dm create mode 100644 code/game/machinery/singularity.dm create mode 100644 code/game/machinery/sink.dm create mode 100644 code/game/machinery/spaceheater.dm create mode 100644 code/game/machinery/status_display.dm create mode 100644 code/game/machinery/teleporter.dm create mode 100644 code/game/machinery/turrets.dm create mode 100644 code/game/machinery/vending.dm create mode 100644 code/game/magic/library.dm create mode 100644 code/game/magic/magicmonster.dm create mode 100644 code/game/magic/musician.dm create mode 100644 code/game/magic/ritual.dm create mode 100644 code/game/master_controller.dm create mode 100644 code/game/objects/alien/acid.dm create mode 100644 code/game/objects/alien/defines.dm create mode 100644 code/game/objects/alien/egg.dm create mode 100644 code/game/objects/alien/facehugger.dm create mode 100644 code/game/objects/alien/resin.dm create mode 100644 code/game/objects/alien/weeds.dm create mode 100644 code/game/objects/assemblies.dm create mode 100644 code/game/objects/blood.dm create mode 100644 code/game/objects/bomb.dm create mode 100644 code/game/objects/cleaner.dm create mode 100644 code/game/objects/closets.dm create mode 100644 code/game/objects/closets/emergency.dm create mode 100644 code/game/objects/closets/gmcloset.dm create mode 100644 code/game/objects/closets/janitor.dm create mode 100644 code/game/objects/closets/kitchen.dm create mode 100644 code/game/objects/closets/l3closet.dm create mode 100644 code/game/objects/closets/malfunction.dm create mode 100644 code/game/objects/closets/nuclear.dm create mode 100644 code/game/objects/closets/secure/animal.dm create mode 100644 code/game/objects/closets/secure/bar.dm create mode 100644 code/game/objects/closets/secure/brig.dm create mode 100644 code/game/objects/closets/secure/captain.dm create mode 100644 code/game/objects/closets/secure/courtroom.dm create mode 100644 code/game/objects/closets/secure/engineering.dm create mode 100644 code/game/objects/closets/secure/medical.dm create mode 100644 code/game/objects/closets/secure/personal.dm create mode 100644 code/game/objects/closets/secure/scientist.dm create mode 100644 code/game/objects/closets/secure/security.dm create mode 100644 code/game/objects/closets/syndicate.dm create mode 100644 code/game/objects/closets/thunderdome.dm create mode 100644 code/game/objects/closets/wardrobe.dm create mode 100644 code/game/objects/death_commando_gear.dm create mode 100644 code/game/objects/devices/PDA.dm create mode 100644 code/game/objects/devices/aicard.dm create mode 100644 code/game/objects/devices/chameleonproj.dm create mode 100644 code/game/objects/devices/device.dm create mode 100644 code/game/objects/devices/flash.dm create mode 100644 code/game/objects/devices/flashlight.dm create mode 100644 code/game/objects/devices/igniter.dm create mode 100644 code/game/objects/devices/infra_sensor.dm create mode 100644 code/game/objects/devices/multitool.dm create mode 100644 code/game/objects/devices/powersink.dm create mode 100644 code/game/objects/devices/proxy_sensor.dm create mode 100644 code/game/objects/devices/scanners.dm create mode 100644 code/game/objects/devices/shields.dm create mode 100644 code/game/objects/devices/timer.dm create mode 100644 code/game/objects/displaycase.dm create mode 100644 code/game/objects/effect_system.dm create mode 100644 code/game/objects/explosion.dm create mode 100644 code/game/objects/gibs.dm create mode 100644 code/game/objects/grille.dm create mode 100644 code/game/objects/items.dm create mode 100644 code/game/objects/items/assemblies.dm create mode 100644 code/game/objects/items/clothing.dm create mode 100644 code/game/objects/items/food.dm create mode 100644 code/game/objects/items/helper_procs.dm create mode 100644 code/game/objects/items/item.dm create mode 100644 code/game/objects/items/robot_parts.dm create mode 100644 code/game/objects/items/weapons/AI_modules.dm create mode 100644 code/game/objects/items/weapons/RCD.dm create mode 100644 code/game/objects/items/weapons/cards_ids.dm create mode 100644 code/game/objects/items/weapons/cigs_lighters.dm create mode 100644 code/game/objects/items/weapons/clown_items.dm create mode 100644 code/game/objects/items/weapons/flamethrower.dm create mode 100644 code/game/objects/items/weapons/game_kit.dm create mode 100644 code/game/objects/items/weapons/glass.dm create mode 100644 code/game/objects/items/weapons/grenades.dm create mode 100644 code/game/objects/items/weapons/guns_ammo.dm create mode 100644 code/game/objects/items/weapons/implants.dm create mode 100644 code/game/objects/items/weapons/kitchen.dm create mode 100644 code/game/objects/items/weapons/medical.dm create mode 100644 code/game/objects/items/weapons/metals_rods.dm create mode 100644 code/game/objects/items/weapons/misc.dm create mode 100644 code/game/objects/items/weapons/mops_cleaners.dm create mode 100644 code/game/objects/items/weapons/papers_bins.dm create mode 100644 code/game/objects/items/weapons/surgery_tools.dm create mode 100644 code/game/objects/items/weapons/swords_axes_etc.dm create mode 100644 code/game/objects/items/weapons/table_rack_parts.dm create mode 100644 code/game/objects/items/weapons/teleportation.dm create mode 100644 code/game/objects/items/weapons/tiles_wires.dm create mode 100644 code/game/objects/items/weapons/toilets.dm create mode 100644 code/game/objects/items/weapons/tools.dm create mode 100644 code/game/objects/items/weapons/uplinks.dm create mode 100644 code/game/objects/kitchen.dm create mode 100644 code/game/objects/noticeboard.dm create mode 100644 code/game/objects/object_procs.dm create mode 100644 code/game/objects/portals.dm create mode 100644 code/game/objects/radio/beacon.dm create mode 100644 code/game/objects/radio/electropack.dm create mode 100644 code/game/objects/radio/intercom.dm create mode 100644 code/game/objects/radio/radio.dm create mode 100644 code/game/objects/radio/signaler.dm create mode 100644 code/game/objects/secstorage/sbriefcase.dm create mode 100644 code/game/objects/secstorage/secstorage.dm create mode 100644 code/game/objects/secstorage/ssafe.dm create mode 100644 code/game/objects/secure_area.dm create mode 100644 code/game/objects/secure_closets.dm create mode 100644 code/game/objects/shieldgen.dm create mode 100644 code/game/objects/spawners/bomb.dm create mode 100644 code/game/objects/stool.dm create mode 100644 code/game/objects/storage/backpack.dm create mode 100644 code/game/objects/storage/bible.dm create mode 100644 code/game/objects/storage/briefcase.dm create mode 100644 code/game/objects/storage/crates.dm create mode 100644 code/game/objects/storage/firstaid.dm create mode 100644 code/game/objects/storage/kit.dm create mode 100644 code/game/objects/storage/storage.dm create mode 100644 code/game/objects/storage/toolbox.dm create mode 100644 code/game/objects/structures.dm create mode 100644 code/game/objects/tables_racks.dm create mode 100644 code/game/objects/tank.dm create mode 100644 code/game/objects/weapons.dm create mode 100644 code/game/objects/window.dm create mode 100644 code/game/sound.dm create mode 100644 code/game/spacecraft/manufacturing.dm create mode 100644 code/game/spacecraft/shipcore.dm create mode 100644 code/game/spacecraft/syndicatebeacon.dm create mode 100644 code/game/status.dm create mode 100644 code/game/supplyshuttle.dm create mode 100644 code/game/throwing.dm create mode 100644 code/game/topic.dm create mode 100644 code/game/turf.dm create mode 100644 code/game/verbs/AI_status.dm create mode 100644 code/game/verbs/ai_lockdown.dm create mode 100644 code/game/verbs/authorize.dm create mode 100644 code/game/verbs/begin.dm create mode 100644 code/game/verbs/checkkarma.dm create mode 100644 code/game/verbs/ooc.dm create mode 100644 code/game/verbs/suicide.dm create mode 100644 code/game/verbs/who.dm create mode 100644 code/game/vials.dm create mode 100644 code/game/vote.dm create mode 100644 code/modules/admin/admin.dm create mode 100644 code/modules/admin/admin_verbs.dm create mode 100644 code/modules/admin/banjob.dm create mode 100644 code/modules/admin/create_mob.dm create mode 100644 code/modules/admin/create_object.dm create mode 100644 code/modules/admin/create_turf.dm create mode 100644 code/modules/admin/verbs/adminhelp.dm create mode 100644 code/modules/admin/verbs/adminjump.dm create mode 100644 code/modules/admin/verbs/adminsay.dm create mode 100644 code/modules/admin/verbs/changetemperature.dm create mode 100644 code/modules/admin/verbs/deadsay.dm create mode 100644 code/modules/admin/verbs/debug.dm create mode 100644 code/modules/admin/verbs/diagnostics.dm create mode 100644 code/modules/admin/verbs/grillify.dm create mode 100644 code/modules/admin/verbs/modifyvariables.dm create mode 100644 code/modules/admin/verbs/playsound.dm create mode 100644 code/modules/admin/verbs/pray.dm create mode 100644 code/modules/admin/verbs/randomverbs.dm create mode 100644 code/modules/admin/verbs/ticklag.dm create mode 100644 code/modules/mob/dead/dead.dm create mode 100644 code/modules/mob/dead/observer/hud.dm create mode 100644 code/modules/mob/dead/observer/login.dm create mode 100644 code/modules/mob/dead/observer/login.dm.bak create mode 100644 code/modules/mob/dead/observer/observer.dm create mode 100644 code/modules/mob/dead/observer/observer.dm.bak create mode 100644 code/modules/mob/dead/observer/say.dm create mode 100644 code/modules/mob/dead/observer/say.dm.bak create mode 100644 code/modules/mob/living/carbon/alien/alien.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/death.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/emote.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/hud.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/humanoid.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/life.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/life_new.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/login.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/queen.dm create mode 100644 code/modules/mob/living/carbon/alien/larva/death.dm create mode 100644 code/modules/mob/living/carbon/alien/larva/emote.dm create mode 100644 code/modules/mob/living/carbon/alien/larva/hud.dm create mode 100644 code/modules/mob/living/carbon/alien/larva/larva.dm create mode 100644 code/modules/mob/living/carbon/alien/larva/life.dm create mode 100644 code/modules/mob/living/carbon/alien/larva/login.dm create mode 100644 code/modules/mob/living/carbon/alien/larva/powers.dm create mode 100644 code/modules/mob/living/carbon/alien/say.dm create mode 100644 code/modules/mob/living/carbon/beast/beast.dm create mode 100644 code/modules/mob/living/carbon/beast/bodypart.dm create mode 100644 code/modules/mob/living/carbon/beast/death.dm create mode 100644 code/modules/mob/living/carbon/beast/examine.dm create mode 100644 code/modules/mob/living/carbon/beast/life.dm create mode 100644 code/modules/mob/living/carbon/beast/login.dm create mode 100644 code/modules/mob/living/carbon/beast/say.dm create mode 100644 code/modules/mob/living/carbon/carbon.dm create mode 100644 code/modules/mob/living/carbon/human/death.dm create mode 100644 code/modules/mob/living/carbon/human/emote.dm create mode 100644 code/modules/mob/living/carbon/human/examine.dm create mode 100644 code/modules/mob/living/carbon/human/hud.dm create mode 100644 code/modules/mob/living/carbon/human/human.dm create mode 100644 code/modules/mob/living/carbon/human/life.dm create mode 100644 code/modules/mob/living/carbon/human/login.dm create mode 100644 code/modules/mob/living/carbon/human/savefile.dm create mode 100644 code/modules/mob/living/carbon/human/say.dm create mode 100644 code/modules/mob/living/carbon/human/whisper.dm create mode 100644 code/modules/mob/living/carbon/monkey/death.dm create mode 100644 code/modules/mob/living/carbon/monkey/emote.dm create mode 100644 code/modules/mob/living/carbon/monkey/examine.dm create mode 100644 code/modules/mob/living/carbon/monkey/hud.dm create mode 100644 code/modules/mob/living/carbon/monkey/life.dm create mode 100644 code/modules/mob/living/carbon/monkey/login.dm create mode 100644 code/modules/mob/living/carbon/monkey/monkey.dm create mode 100644 code/modules/mob/living/carbon/monkey/say.dm create mode 100644 code/modules/mob/living/living.dm create mode 100644 code/modules/mob/living/say.dm create mode 100644 code/modules/mob/living/silicon/ai/ai.dm create mode 100644 code/modules/mob/living/silicon/ai/death.dm create mode 100644 code/modules/mob/living/silicon/ai/examine.dm create mode 100644 code/modules/mob/living/silicon/ai/hud.dm create mode 100644 code/modules/mob/living/silicon/ai/life.dm create mode 100644 code/modules/mob/living/silicon/ai/login.dm create mode 100644 code/modules/mob/living/silicon/ai/logout.dm create mode 100644 code/modules/mob/living/silicon/ai/move.dm create mode 100644 code/modules/mob/living/silicon/ai/say.dm create mode 100644 code/modules/mob/living/silicon/hivebot/death.dm create mode 100644 code/modules/mob/living/silicon/hivebot/emote.dm create mode 100644 code/modules/mob/living/silicon/hivebot/examine.dm create mode 100644 code/modules/mob/living/silicon/hivebot/hive_modules.dm create mode 100644 code/modules/mob/living/silicon/hivebot/hivebot.dm create mode 100644 code/modules/mob/living/silicon/hivebot/hud.dm create mode 100644 code/modules/mob/living/silicon/hivebot/life.dm create mode 100644 code/modules/mob/living/silicon/hivebot/login.dm create mode 100644 code/modules/mob/living/silicon/hivebot/mainframe.dm create mode 100644 code/modules/mob/living/silicon/hivebot/say.dm create mode 100644 code/modules/mob/living/silicon/robot/death.dm create mode 100644 code/modules/mob/living/silicon/robot/emote.dm create mode 100644 code/modules/mob/living/silicon/robot/examine.dm create mode 100644 code/modules/mob/living/silicon/robot/hud.dm create mode 100644 code/modules/mob/living/silicon/robot/life.dm create mode 100644 code/modules/mob/living/silicon/robot/login.dm create mode 100644 code/modules/mob/living/silicon/robot/robot.dm create mode 100644 code/modules/mob/living/silicon/robot/robot_modules.dm create mode 100644 code/modules/mob/living/silicon/robot/say.dm create mode 100644 code/modules/mob/living/silicon/say.dm create mode 100644 code/modules/mob/living/silicon/silicon.dm create mode 100644 code/modules/mob/login.dm create mode 100644 code/modules/mob/logout.dm create mode 100644 code/modules/mob/mob.dm create mode 100644 code/modules/mob/new_player/new_player.dm create mode 100644 code/modules/mob/new_player/preferences.dm create mode 100644 code/modules/mob/organs.dm create mode 100644 code/modules/mob/say.dm create mode 100644 code/modules/mob/transform_procs.dm create mode 100644 code/modules/power/antimatter/computer.dm create mode 100644 code/modules/power/antimatter/engine.dm create mode 100644 code/modules/power/antimatter/fuel.dm create mode 100644 code/modules/power/apc.dm create mode 100644 code/modules/power/cable.dm create mode 100644 code/modules/power/cell.dm create mode 100644 code/modules/power/engine.dm create mode 100644 code/modules/power/generator.dm create mode 100644 code/modules/power/generator_type2.dm create mode 100644 code/modules/power/lighting.dm create mode 100644 code/modules/power/port_gen.dm create mode 100644 code/modules/power/portable.dm create mode 100644 code/modules/power/power.dm create mode 100644 code/modules/power/sd_DynamicAreaLighting.dm create mode 100644 code/modules/power/smes.dm create mode 100644 code/modules/power/solar.dm create mode 100644 code/modules/power/terminal.dm create mode 100644 code/modules/power/tracker.dm create mode 100644 code/modules/power/turbine.dm create mode 100644 code/names.dm create mode 100644 code/notes.dm create mode 100644 code/setup.dm create mode 100644 code/stylesheet.dm create mode 100644 code/unused/dna.dm create mode 100644 code/unused/heater.dm create mode 100644 code/unused/modules/admin/ban.dm create mode 100644 code/unused/musicplayer.dm create mode 100644 code/unused/siphs.dm create mode 100644 code/unused/vehicle.dm create mode 100644 config/access levels.txt create mode 100644 config/admins.txt create mode 100644 config/config.txt create mode 100644 config/motd help.txt create mode 100644 config/motd-auth.txt create mode 100644 config/motd-noauth.txt create mode 100644 config/motd.txt create mode 100644 config/names/ai.txt create mode 100644 config/names/death_commando.txt create mode 100644 config/names/first.txt create mode 100644 config/names/first_female.txt create mode 100644 config/names/first_male.txt create mode 100644 config/names/last.txt create mode 100644 config/names/loggedsay.txt create mode 100644 config/rules.html create mode 100644 config/testers.txt create mode 100644 data/mode.txt create mode 100644 goonstation.dme create mode 100644 icons/80x15.png create mode 100644 icons/88x31.png create mode 100644 icons/PSD files/door.psd create mode 100644 icons/Testing/air_meter.dmi create mode 100644 icons/Testing/atmos_testing.dmi create mode 100644 icons/Testing/turf_analysis.dmi create mode 100644 icons/Thumbs.db create mode 100644 icons/admin_pm.html create mode 100644 icons/changelog.html create mode 100644 icons/create_object.html create mode 100644 icons/dice.png create mode 100644 icons/dice20.png create mode 100644 icons/effects/160x160.dmi create mode 100644 icons/effects/96x96.dmi create mode 100644 icons/effects/alert.dmi create mode 100644 icons/effects/alphacolors.dmi create mode 100644 icons/effects/beam.dmi create mode 100644 icons/effects/blood.dmi create mode 100644 icons/effects/effects.dmi create mode 100644 icons/effects/fire.dmi create mode 100644 icons/effects/genetics.dmi create mode 100644 icons/effects/lighting.dmi create mode 100644 icons/effects/oil.dmi create mode 100644 icons/effects/plasma.dmi create mode 100644 icons/effects/ss13_dark_alpha7.dmi create mode 100644 icons/effects/station_explosion.dmi create mode 100644 icons/effects/tile_effects.dmi create mode 100644 icons/effects/water.dmi create mode 100644 icons/help.html create mode 100644 icons/map.png create mode 100644 icons/misc/beach.dmi create mode 100644 icons/misc/beach2.dmi create mode 100644 icons/misc/buildmode.dmi create mode 100644 icons/misc/flags.dmi create mode 100644 icons/misc/fullscreen.dmi create mode 100644 icons/misc/imap.dmi create mode 100644 icons/misc/inpipe.dmi create mode 100644 icons/misc/largeui.dmi create mode 100644 icons/misc/mark.dmi create mode 100644 icons/misc/mouse.dmi create mode 100644 icons/misc/old_or_unused.dmi create mode 100644 icons/mob/alien.dmi create mode 100644 icons/mob/back.dmi create mode 100644 icons/mob/belt.dmi create mode 100644 icons/mob/blob.dmi create mode 100644 icons/mob/dam_human.dmi create mode 100644 icons/mob/dam_mask.dmi create mode 100644 icons/mob/ears.dmi create mode 100644 icons/mob/eyes.dmi create mode 100644 icons/mob/feet.dmi create mode 100644 icons/mob/golems.dmi create mode 100644 icons/mob/hands.dmi create mode 100644 icons/mob/head.dmi create mode 100644 icons/mob/hivebot.dmi create mode 100644 icons/mob/human.dmi create mode 100644 icons/mob/human_face.dmi create mode 100644 icons/mob/items_lefthand.dmi create mode 100644 icons/mob/items_righthand.dmi create mode 100644 icons/mob/mask.dmi create mode 100644 icons/mob/mob.dmi create mode 100644 icons/mob/monkey.dmi create mode 100644 icons/mob/robots.dmi create mode 100644 icons/mob/screen1.dmi create mode 100644 icons/mob/screen1_alien.dmi create mode 100644 icons/mob/screen1_robot.dmi create mode 100644 icons/mob/sectoid.dmi create mode 100644 icons/mob/suit.dmi create mode 100644 icons/mob/techpriest.dmi create mode 100644 icons/mob/uniform.dmi create mode 100644 icons/mob/uniform_fat.dmi create mode 100644 icons/mob/zone_sel.dmi create mode 100644 icons/obj/AM_Engine.dmi create mode 100644 icons/obj/Cryogenic2.dmi create mode 100644 icons/obj/aibots.dmi create mode 100644 icons/obj/airlock_machines.dmi create mode 100644 icons/obj/airtunnel.dmi create mode 100644 icons/obj/ammo.dmi create mode 100644 icons/obj/assemblies.dmi create mode 100644 icons/obj/atmos.dmi create mode 100644 icons/obj/atmospherics/blue_pipe_tank.dmi create mode 100644 icons/obj/atmospherics/cold_sink.dmi create mode 100644 icons/obj/atmospherics/digital_valve.dmi create mode 100644 icons/obj/atmospherics/dp_vent_pump.dmi create mode 100644 icons/obj/atmospherics/filter.dmi create mode 100644 icons/obj/atmospherics/heat_exchanger.dmi create mode 100644 icons/obj/atmospherics/mixer.dmi create mode 100644 icons/obj/atmospherics/orange_pipe_tank.dmi create mode 100644 icons/obj/atmospherics/outlet_injector.dmi create mode 100644 icons/obj/atmospherics/oxygen_generator.dmi create mode 100644 icons/obj/atmospherics/passive_gate.dmi create mode 100644 icons/obj/atmospherics/pipe_manifold.dmi create mode 100644 icons/obj/atmospherics/pipe_tank.dmi create mode 100644 icons/obj/atmospherics/pipe_vent.dmi create mode 100644 icons/obj/atmospherics/portables_connector.dmi create mode 100644 icons/obj/atmospherics/pump.dmi create mode 100644 icons/obj/atmospherics/red_orange_pipe_tank.dmi create mode 100644 icons/obj/atmospherics/red_pipe.dmi create mode 100644 icons/obj/atmospherics/red_pipe_tank.dmi create mode 100644 icons/obj/atmospherics/valve.dmi create mode 100644 icons/obj/atmospherics/vent_pump.dmi create mode 100644 icons/obj/atmospherics/vent_scrubber.dmi create mode 100644 icons/obj/atmospherics/volume_pump.dmi create mode 100644 icons/obj/card.dmi create mode 100644 icons/obj/chemical.dmi create mode 100644 icons/obj/cigarettes.dmi create mode 100644 icons/obj/cloning.dmi create mode 100644 icons/obj/closet.dmi create mode 100644 icons/obj/clothing/glasses.dmi create mode 100644 icons/obj/clothing/gloves.dmi create mode 100644 icons/obj/clothing/hats.dmi create mode 100644 icons/obj/clothing/masks.dmi create mode 100644 icons/obj/clothing/shoes.dmi create mode 100644 icons/obj/clothing/suits.dmi create mode 100644 icons/obj/clothing/uniforms.dmi create mode 100644 icons/obj/computer.dmi create mode 100644 icons/obj/computer_frame.dmi create mode 100644 icons/obj/craft.dmi create mode 100644 icons/obj/decals.dmi create mode 100644 icons/obj/device.dmi create mode 100644 icons/obj/doors/Door1.dmi create mode 100644 icons/obj/doors/Doorcom.dmi create mode 100644 icons/obj/doors/Dooreng.dmi create mode 100644 icons/obj/doors/Doorext.dmi create mode 100644 icons/obj/doors/Doorf.dmi create mode 100644 icons/obj/doors/Doorfire.dmi create mode 100644 icons/obj/doors/Doorglass.dmi create mode 100644 icons/obj/doors/Doormaint.dmi create mode 100644 icons/obj/doors/Doorsec.dmi create mode 100644 icons/obj/doors/door_fire2.dmi create mode 100644 icons/obj/doors/doorint.dmi create mode 100644 icons/obj/doors/doormed.dmi create mode 100644 icons/obj/doors/doormorgue.dmi create mode 100644 icons/obj/doors/rapid_pdoor.dmi create mode 100644 icons/obj/doors/windoor.dmi create mode 100644 icons/obj/dropper.dmi create mode 100644 icons/obj/engine.dmi create mode 100644 icons/obj/escapepod.dmi create mode 100644 icons/obj/food.dmi create mode 100644 icons/obj/grenade.dmi create mode 100644 icons/obj/gun.dmi create mode 100644 icons/obj/hydroponics.dmi create mode 100644 icons/obj/items.dmi create mode 100644 icons/obj/janitor.dmi create mode 100644 icons/obj/junk.dmi create mode 100644 icons/obj/kitchen.dmi create mode 100644 icons/obj/library.dmi create mode 100644 icons/obj/lighting.dmi create mode 100644 icons/obj/machines/fiber.dmi create mode 100644 icons/obj/machines/heavy_fiber.dmi create mode 100644 icons/obj/machines/lasers.dmi create mode 100644 icons/obj/machines/reactor.dmi create mode 100644 icons/obj/magic.dmi create mode 100644 icons/obj/magic_pillar.dmi create mode 100644 icons/obj/magic_terror.dmi create mode 100644 icons/obj/meteor.dmi create mode 100644 icons/obj/meter.dmi create mode 100644 icons/obj/mining.dmi create mode 100644 icons/obj/module.dmi create mode 100644 icons/obj/monitors.dmi create mode 100644 icons/obj/musician.dmi create mode 100644 icons/obj/objects.dmi create mode 100644 icons/obj/optics.dmi create mode 100644 icons/obj/otherthing.dmi create mode 100644 icons/obj/pda.dmi create mode 100644 icons/obj/pipe-item.dmi create mode 100644 icons/obj/pipes.dmi create mode 100644 icons/obj/pipes/disposal.dmi create mode 100644 icons/obj/pipes/heat.dmi create mode 100644 icons/obj/pipes/junction.dmi create mode 100644 icons/obj/pipes/large.dmi create mode 100644 icons/obj/pipes/regular.dmi create mode 100644 icons/obj/pipes2.dmi create mode 100644 icons/obj/power.dmi create mode 100644 icons/obj/power_cond.dmi create mode 100644 icons/obj/power_local.dmi create mode 100644 icons/obj/projectiles.dmi create mode 100644 icons/obj/recycling.dmi create mode 100644 icons/obj/robot_parts.dmi create mode 100644 icons/obj/scrap.dmi create mode 100644 icons/obj/shards.dmi create mode 100644 icons/obj/singularity.dmi create mode 100644 icons/obj/stationobjs.dmi create mode 100644 icons/obj/status_display.dmi create mode 100644 icons/obj/storage.dmi create mode 100644 icons/obj/structures.dmi create mode 100644 icons/obj/surgery.dmi create mode 100644 icons/obj/syringe.dmi create mode 100644 icons/obj/tank.dmi create mode 100644 icons/obj/tubing.dmi create mode 100644 icons/obj/turrets.dmi create mode 100644 icons/obj/vending.dmi create mode 100644 icons/obj/weapons.dmi create mode 100644 icons/obj/wizard.dmi create mode 100644 icons/postcardsmall.jpg create mode 100644 icons/somerights20.png create mode 100644 icons/sprites_todo.txt create mode 100644 icons/ss13_32.png create mode 100644 icons/ss13_64.png create mode 100644 icons/turf/areas.dmi create mode 100644 icons/turf/floors.dmi create mode 100644 icons/turf/shuttle.dmi create mode 100644 icons/turf/space.dmi create mode 100644 icons/turf/walls.dmi create mode 100644 interface/skin.dmf create mode 100644 maps/backup/trunkmap.dmm create mode 100644 maps/backup/trunkmap07132010.dmm create mode 100644 maps/trunkmap.dmm create mode 100644 maps/trunkmap.rar create mode 100644 music/music help.txt create mode 100644 sound/ambience/ambiatm1.ogg create mode 100644 sound/ambience/ambicha1.ogg create mode 100644 sound/ambience/ambicha2.ogg create mode 100644 sound/ambience/ambicha3.ogg create mode 100644 sound/ambience/ambicha4.ogg create mode 100644 sound/ambience/ambience_outdoors.ogg create mode 100644 sound/ambience/ambieng1.ogg create mode 100644 sound/ambience/ambigen1.ogg create mode 100644 sound/ambience/ambigen10.ogg create mode 100644 sound/ambience/ambigen11.ogg create mode 100644 sound/ambience/ambigen12.ogg create mode 100644 sound/ambience/ambigen13.ogg create mode 100644 sound/ambience/ambigen14.ogg create mode 100644 sound/ambience/ambigen2.ogg create mode 100644 sound/ambience/ambigen3.ogg create mode 100644 sound/ambience/ambigen4.ogg create mode 100644 sound/ambience/ambigen5.ogg create mode 100644 sound/ambience/ambigen6.ogg create mode 100644 sound/ambience/ambigen7.ogg create mode 100644 sound/ambience/ambigen8.ogg create mode 100644 sound/ambience/ambigen9.ogg create mode 100644 sound/ambience/ambimal1.ogg create mode 100644 sound/ambience/ambimal2.ogg create mode 100644 sound/ambience/ambimal3.ogg create mode 100644 sound/ambience/ambimo1.ogg create mode 100644 sound/ambience/ambimo2.ogg create mode 100644 sound/ambience/seag1.ogg create mode 100644 sound/ambience/seag2.ogg create mode 100644 sound/ambience/seag3.ogg create mode 100644 sound/ambience/shipambience.ogg create mode 100644 sound/ambience/shore.ogg create mode 100644 sound/effects/Explosion1.ogg create mode 100644 sound/effects/Explosion2.ogg create mode 100644 sound/effects/Glassbr1.ogg create mode 100644 sound/effects/Glassbr2.ogg create mode 100644 sound/effects/Glassbr3.ogg create mode 100644 sound/effects/Glasshit.ogg create mode 100644 sound/effects/Heart Beat.ogg create mode 100644 sound/effects/attackblob.ogg create mode 100644 sound/effects/bamf.ogg create mode 100644 sound/effects/bang.ogg create mode 100644 sound/effects/blobattack.ogg create mode 100644 sound/effects/bubbles.ogg create mode 100644 sound/effects/bubbles2.ogg create mode 100644 sound/effects/clang.ogg create mode 100644 sound/effects/explosionfar.ogg create mode 100644 sound/effects/ghost.ogg create mode 100644 sound/effects/ghost2.ogg create mode 100644 sound/effects/grillehit.ogg create mode 100644 sound/effects/pop.ogg create mode 100644 sound/effects/screech.ogg create mode 100644 sound/effects/slosh.ogg create mode 100644 sound/effects/smoke.ogg create mode 100644 sound/effects/snap.ogg create mode 100644 sound/effects/sparks1.ogg create mode 100644 sound/effects/sparks2.ogg create mode 100644 sound/effects/sparks3.ogg create mode 100644 sound/effects/sparks4.ogg create mode 100644 sound/effects/splat.ogg create mode 100644 sound/effects/spray.ogg create mode 100644 sound/effects/syringeproj.ogg create mode 100644 sound/effects/zzzt.ogg create mode 100644 sound/items/Crowbar.ogg create mode 100644 sound/items/Deconstruct.ogg create mode 100644 sound/items/Ratchet.ogg create mode 100644 sound/items/Screwdriver.ogg create mode 100644 sound/items/Screwdriver2.ogg create mode 100644 sound/items/Welder.ogg create mode 100644 sound/items/Welder2.ogg create mode 100644 sound/items/Wirecutter.ogg create mode 100644 sound/items/bikehorn.ogg create mode 100644 sound/items/drink.ogg create mode 100644 sound/items/eatfood.ogg create mode 100644 sound/items/polaroid1.ogg create mode 100644 sound/items/polaroid2.ogg create mode 100644 sound/machines/airlock.ogg create mode 100644 sound/machines/blender.ogg create mode 100644 sound/machines/buzz-sigh.ogg create mode 100644 sound/machines/buzz-two.ogg create mode 100644 sound/machines/chime.ogg create mode 100644 sound/machines/click.ogg create mode 100644 sound/machines/ding.ogg create mode 100644 sound/machines/disposalflush.ogg create mode 100644 sound/machines/door_close.ogg create mode 100644 sound/machines/door_locked.ogg create mode 100644 sound/machines/door_open.ogg create mode 100644 sound/machines/genetics.ogg create mode 100644 sound/machines/hiss.ogg create mode 100644 sound/machines/ping.ogg create mode 100644 sound/machines/signal.ogg create mode 100644 sound/machines/twobeep.ogg create mode 100644 sound/machines/warning-buzzer.ogg create mode 100644 sound/machines/windowdoor.ogg create mode 100644 sound/misc/NewRound.ogg create mode 100644 sound/misc/NewRound2.ogg create mode 100644 sound/misc/clownstep1.ogg create mode 100644 sound/misc/clownstep2.ogg create mode 100644 sound/misc/glass_step.ogg create mode 100644 sound/misc/main.ogg create mode 100644 sound/misc/meteorimpact.ogg create mode 100644 sound/misc/null.ogg create mode 100644 sound/misc/rustle1.ogg create mode 100644 sound/misc/rustle2.ogg create mode 100644 sound/misc/rustle3.ogg create mode 100644 sound/misc/rustle4.ogg create mode 100644 sound/misc/rustle5.ogg create mode 100644 sound/misc/slip.ogg create mode 100644 sound/misc/traitor.ogg create mode 100644 sound/piano/pianoA.ogg create mode 100644 sound/piano/pianoB.ogg create mode 100644 sound/piano/pianoC.ogg create mode 100644 sound/piano/pianoD.ogg create mode 100644 sound/piano/pianoE.ogg create mode 100644 sound/piano/pianoF.ogg create mode 100644 sound/piano/pianoG.ogg create mode 100644 sound/voice/bcreep.ogg create mode 100644 sound/voice/bcriminal.ogg create mode 100644 sound/voice/bfreeze.ogg create mode 100644 sound/voice/bgod.ogg create mode 100644 sound/voice/biamthelaw.ogg create mode 100644 sound/voice/binsult.ogg create mode 100644 sound/voice/bjustice.ogg create mode 100644 sound/voice/bradio.ogg create mode 100644 sound/voice/bsecureday.ogg create mode 100644 sound/weapons/Egloves.ogg create mode 100644 sound/weapons/Genhit.ogg create mode 100644 sound/weapons/Gunshot.ogg create mode 100644 sound/weapons/Laser.ogg create mode 100644 sound/weapons/Taser.ogg create mode 100644 sound/weapons/armbomb.ogg create mode 100644 sound/weapons/flash.ogg create mode 100644 sound/weapons/genhit1.ogg create mode 100644 sound/weapons/genhit2.ogg create mode 100644 sound/weapons/genhit3.ogg create mode 100644 sound/weapons/handcuffs.ogg create mode 100644 sound/weapons/punch1.ogg create mode 100644 sound/weapons/punch2.ogg create mode 100644 sound/weapons/punch3.ogg create mode 100644 sound/weapons/punch4.ogg create mode 100644 sound/weapons/punchmiss.ogg create mode 100644 sound/weapons/shotgunpump.ogg create mode 100644 sound/weapons/smash.ogg create mode 100644 sound/weapons/thudswoosh.ogg diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm new file mode 100644 index 0000000000000..9f807c2970979 --- /dev/null +++ b/code/ATMOSPHERICS/atmospherics.dm @@ -0,0 +1,52 @@ +/* +Quick overview: + +Pipes combine to form pipelines +Pipelines and other atmospheric objects combine to form pipe_networks + Note: A single pipe_network represents a completely open space + +Pipes -> Pipelines +Pipelines + Other Objects -> Pipe network + +*/ + +obj/machinery/atmospherics + anchored = 1 + + var/initialize_directions = 0 + + process() + build_network() + ..() + + proc + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + // Check to see if should be added to network. Add self if so and adjust variables appropriately. + // Note don't forget to have neighbors look as well! + + return null + + build_network() + // Called to build a network from this node + + return null + + return_network(obj/machinery/atmospherics/reference) + // Returns pipe_network associated with connection to reference + // Notes: should create network if necessary + // Should never return null + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + // Used when two pipe_networks are combining + + return_network_air(datum/network/reference) + // Return a list of gas_mixture(s) in the object + // associated with reference pipe_network for use in rebuilding the networks gases list + // Is permitted to return null + + disconnect(obj/machinery/atmospherics/reference) + + update_icon() + return null \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm b/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm new file mode 100644 index 0000000000000..44446589cbf48 --- /dev/null +++ b/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm @@ -0,0 +1,129 @@ +obj/machinery/atmospherics/binary + dir = SOUTH + initialize_directions = SOUTH|NORTH + + var/datum/gas_mixture/air1 + var/datum/gas_mixture/air2 + + var/obj/machinery/atmospherics/node1 + var/obj/machinery/atmospherics/node2 + + var/datum/pipe_network/network1 + var/datum/pipe_network/network2 + + New() + ..() + switch(dir) + if(NORTH) + initialize_directions = NORTH|SOUTH + if(SOUTH) + initialize_directions = NORTH|SOUTH + if(EAST) + initialize_directions = EAST|WEST + if(WEST) + initialize_directions = EAST|WEST + air1 = new + air2 = new + + air1.volume = 200 + air2.volume = 200 + +// Housekeeping and pipe network stuff below + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node1) + network1 = new_network + + else if(reference == node2) + network2 = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + + Del() + loc = null + + if(node1) + node1.disconnect(src) + del(network1) + if(node2) + node2.disconnect(src) + del(network2) + + node1 = null + node2 = null + + ..() + + initialize() + if(node1 && node2) return + + var/node2_connect = dir + var/node1_connect = turn(dir, 180) + + 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 + + update_icon() + + build_network() + if(!network1 && node1) + network1 = new /datum/pipe_network() + network1.normal_members += src + network1.build_network(node1, src) + + if(!network2 && node2) + network2 = new /datum/pipe_network() + network2.normal_members += src + network2.build_network(node2, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node1) + return network1 + + if(reference==node2) + return network2 + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network1 == old_network) + network1 = new_network + if(network2 == old_network) + network2 = new_network + + return 1 + + return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(network1 == reference) + results += air1 + if(network2 == reference) + results += air2 + + return results + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node1) + del(network1) + node1 = null + + else if(reference==node2) + del(network2) + node2 = null + + return null \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/circulator.dm b/code/ATMOSPHERICS/components/binary_devices/circulator.dm new file mode 100644 index 0000000000000..3624742d047a1 --- /dev/null +++ b/code/ATMOSPHERICS/components/binary_devices/circulator.dm @@ -0,0 +1,64 @@ +//node1, air1, network1 correspond to input +//node2, air2, network2 correspond to output + +/obj/machinery/atmospherics/binary/circulator + name = "circulator/heat exchanger" + desc = "A gas circulator pump and heat exchanger." + icon = 'pipes.dmi' + icon_state = "circ1-off" + + var/side = 1 // 1=left 2=right + var/status = 0 + + var/last_pressure_delta = 0 + + anchored = 1.0 + density = 1 + + proc/return_transfer_air() + var/output_starting_pressure = air2.return_pressure() + var/input_starting_pressure = air1.return_pressure() + + if(output_starting_pressure >= input_starting_pressure-10) + //Need at least 10 KPa difference to overcome friction in the mechanism + last_pressure_delta = 0 + return null + + //Calculate necessary moles to transfer using PV = nRT + if((air1.total_moles() > 0) && (air1.temperature>0)) + var/pressure_delta = (input_starting_pressure - output_starting_pressure)/2 + + var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) + + last_pressure_delta = pressure_delta + + //Actually transfer the gas + var/datum/gas_mixture/removed = air1.remove(transfer_moles) + + if(network1) + network1.update = 1 + + if(network2) + network2.update = 1 + + return removed + + else + last_pressure_delta = 0 + + process() + ..() + update_icon() + + update_icon() + if(stat & (BROKEN|NOPOWER)) + icon_state = "circ[side]-p" + else if(last_pressure_delta > 0) + if(last_pressure_delta > ONE_ATMOSPHERE) + icon_state = "circ[side]-run" + else + icon_state = "circ[side]-slow" + else + icon_state = "circ[side]-off" + + return 1 \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm new file mode 100644 index 0000000000000..790189675b4d9 --- /dev/null +++ b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm @@ -0,0 +1,198 @@ +/obj/machinery/atmospherics/binary/dp_vent_pump + icon = 'dp_vent_pump.dmi' + icon_state = "off" + + //node2 is output port + //node1 is input port + + name = "Dual Port Air Vent" + desc = "Has a valve and pump attached to it. There are two ports." + + level = 1 + + high_volume + name = "Large Dual Port Air Vent" + + New() + ..() + + air1.volume = 1000 + air2.volume = 1000 + + var/on = 0 + var/pump_direction = 1 //0 = siphoning, 1 = releasing + + var/external_pressure_bound = ONE_ATMOSPHERE + var/input_pressure_min = 0 + var/output_pressure_max = 0 + + var/pressure_checks = 1 + //1: Do not pass external_pressure_bound + //2: Do not pass input_pressure_min + //4: Do not pass output_pressure_max + + update_icon() + if(on) + if(pump_direction) + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out" + else + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" + else + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" + on = 0 + + return + + hide(var/i) //to make the little pipe section invisible, the icon changes. + if(on) + if(pump_direction) + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out" + else + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" + else + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" + on = 0 + return + + process() + ..() + + if(!on) + return 0 + + var/datum/gas_mixture/environment = loc.return_air() + var/environment_pressure = environment.return_pressure() + + if(pump_direction) //input -> external + var/pressure_delta = 10000 + + if(pressure_checks&1) + pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure)) + if(pressure_checks&2) + pressure_delta = min(pressure_delta, (air1.return_pressure() - input_pressure_min)) + + if(pressure_delta > 0) + if(air1.temperature > 0) + var/transfer_moles = pressure_delta*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = air1.remove(transfer_moles) + + loc.assume_air(removed) + + if(network1) + network1.update = 1 + + else //external -> output + var/pressure_delta = 10000 + + if(pressure_checks&1) + pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound)) + if(pressure_checks&4) + pressure_delta = min(pressure_delta, (output_pressure_max - air2.return_pressure())) + + if(pressure_delta > 0) + if(environment.temperature > 0) + var/transfer_moles = pressure_delta*air2.volume/(environment.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) + + air2.merge(removed) + + if(network2) + network2.update = 1 + + return 1 + + //Radio remote control + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, "[frequency]") + + broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = id + signal.data["device"] = "ADVP" + signal.data["power"] = on?("on"):("off") + signal.data["direction"] = pump_direction?("release"):("siphon") + signal.data["checks"] = pressure_checks + signal.data["input"] = input_pressure_min + signal.data["output"] = output_pressure_max + signal.data["external"] = external_pressure_bound + + radio_connection.post_signal(src, signal) + + return 1 + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + + initialize() + ..() + if(frequency) + set_frequency(frequency) + + receive_signal(datum/signal/signal) + if(signal.data["tag"] && (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("power_on") + on = 1 + + if("power_off") + on = 0 + + if("power_toggle") + on = !on + + if("set_direction") + var/number = text2num(signal.data["parameter"]) + if(number > 0.5) + pump_direction = 1 + else + pump_direction = 0 + + if("set_checks") + var/number = round(text2num(signal.data["parameter"]),1) + pressure_checks = number + + if("purge") + pressure_checks &= ~1 + pump_direction = 0 + + if("stabalize") + pressure_checks |= 1 + pump_direction = 1 + + if("set_input_pressure") + var/number = text2num(signal.data["parameter"]) + number = min(max(number, 0), ONE_ATMOSPHERE*50) + + input_pressure_min = number + + if("set_output_pressure") + var/number = text2num(signal.data["parameter"]) + number = min(max(number, 0), ONE_ATMOSPHERE*50) + + output_pressure_max = number + + if("set_external_pressure") + var/number = text2num(signal.data["parameter"]) + number = min(max(number, 0), ONE_ATMOSPHERE*50) + + external_pressure_bound = number + + if(signal.data["tag"]) + spawn(5) broadcast_status() + update_icon() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm new file mode 100644 index 0000000000000..aee6b2fa37a78 --- /dev/null +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -0,0 +1,55 @@ +obj/machinery/atmospherics/binary/passive_gate + //Tries to achieve target pressure at output (like a normal pump) except + // Uses no power but can not transfer gases from a low pressure area to a high pressure area + icon = 'passive_gate.dmi' + icon_state = "intact_off" + + name = "Passive gate" + desc = "A one-way air valve that does not require power" + + var/on = 0 + var/target_pressure = ONE_ATMOSPHERE + + update_icon() + if(node1&&node2) + icon_state = "intact_[on?("on"):("off")]" + else + if(node1) + icon_state = "exposed_1_off" + else if(node2) + icon_state = "exposed_2_off" + else + icon_state = "exposed_3_off" + on = 0 + + return + + process() + ..() + if(!on) + return 0 + + var/output_starting_pressure = air2.return_pressure() + var/input_starting_pressure = air1.return_pressure() + + if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10)) + //No need to pump gas if target is already reached or input pressure is too low + //Need at least 10 KPa difference to overcome friction in the mechanism + return 1 + + //Calculate necessary moles to transfer using PV = nRT + if((air1.total_moles() > 0) && (air1.temperature>0)) + var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2) + //Can not have a pressure delta that would cause output_pressure > input_pressure + + var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + var/datum/gas_mixture/removed = air1.remove(transfer_moles) + air2.merge(removed) + + if(network1) + network1.update = 1 + + if(network2) + network2.update = 1 \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm new file mode 100644 index 0000000000000..682e619df96ca --- /dev/null +++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm @@ -0,0 +1,128 @@ +/* +Every cycle, the pump uses the air in air_in to try and make air_out the perfect pressure. + +node1, air1, network1 correspond to input +node2, air2, network2 correspond to output + +Thus, the two variables affect pump operation are set in New(): + air1.volume + This is the volume of gas available to the pump that may be transfered to the output + air2.volume + Higher quantities of this cause more air to be perfected later + but overall network volume is also increased as this increases... +*/ + +obj/machinery/atmospherics/binary/pump + icon = 'pump.dmi' + icon_state = "intact_off" + + name = "Gas pump" + desc = "A pump" + + var/on = 0 + var/target_pressure = ONE_ATMOSPHERE + + attack_hand(mob/user) + on = !on + update_icon() + + update_icon() + if(node1&&node2) + icon_state = "intact_[on?("on"):("off")]" + else + if(node1) + icon_state = "exposed_1_off" + else if(node2) + icon_state = "exposed_2_off" + else + icon_state = "exposed_3_off" + on = 0 + + return + + process() + ..() + if(!on) + return 0 + + var/output_starting_pressure = air2.return_pressure() + + if(output_starting_pressure >= target_pressure) + //No need to pump gas if target is already reached! + return 1 + + //Calculate necessary moles to transfer using PV=nRT + if((air1.total_moles() > 0) && (air1.temperature>0)) + var/pressure_delta = target_pressure - output_starting_pressure + var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + var/datum/gas_mixture/removed = air1.remove(transfer_moles) + air2.merge(removed) + + if(network1) + network1.update = 1 + + if(network2) + network2.update = 1 + + return 1 + + //Radio remote control + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, "[frequency]") + + broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = id + signal.data["device"] = "AGP" + signal.data["power"] = on + signal.data["target_output"] = target_pressure + + radio_connection.post_signal(src, signal) + + return 1 + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + + initialize() + ..() + if(frequency) + set_frequency(frequency) + + receive_signal(datum/signal/signal) + if(signal.data["tag"] && (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("power_on") + on = 1 + + if("power_off") + on = 0 + + if("power_toggle") + on = !on + + if("set_output_pressure") + var/number = text2num(signal.data["parameter"]) + number = min(max(number, 0), ONE_ATMOSPHERE*50) + + target_pressure = number + + if(signal.data["tag"]) + spawn(5) broadcast_status() + update_icon() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm new file mode 100644 index 0000000000000..ae3ff008d8e51 --- /dev/null +++ b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm @@ -0,0 +1,113 @@ +/* +Every cycle, the pump uses the air in air_in to try and make air_out the perfect pressure. + +node1, air1, network1 correspond to input +node2, air2, network2 correspond to output + +Thus, the two variables affect pump operation are set in New(): + air1.volume + This is the volume of gas available to the pump that may be transfered to the output + air2.volume + Higher quantities of this cause more air to be perfected later + but overall network volume is also increased as this increases... +*/ + +obj/machinery/atmospherics/binary/volume_pump + icon = 'volume_pump.dmi' + icon_state = "intact_off" + + name = "Gas pump" + desc = "A pump" + + var/on = 0 + var/transfer_rate = 200 + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + + update_icon() + if(node1&&node2) + icon_state = "intact_[on?("on"):("off")]" + else + if(node1) + icon_state = "exposed_1_off" + else if(node2) + icon_state = "exposed_2_off" + else + icon_state = "exposed_3_off" + on = 0 + + return + + process() + ..() + if(!on) + return 0 + + var/transfer_ratio = max(1, transfer_rate/air1.volume) + + var/datum/gas_mixture/removed = air1.remove_ratio(transfer_ratio) + + air2.merge(removed) + + if(network1) + network1.update = 1 + + if(network2) + network2.update = 1 + + return 1 + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, "[frequency]") + + broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = id + signal.data["device"] = "APV" + signal.data["power"] = on + signal.data["transfer_rate"] = transfer_rate + + radio_connection.post_signal(src, signal) + + return 1 + + initialize() + ..() + + set_frequency(frequency) + + receive_signal(datum/signal/signal) + if(signal.data["tag"] && (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("power_on") + on = 1 + + if("power_off") + on = 0 + + if("power_toggle") + on = !on + + if("set_transfer_rate") + var/number = text2num(signal.data["parameter"]) + number = min(max(number, 0), air1.volume) + + transfer_rate = number + + if(signal.data["tag"]) + spawn(5) broadcast_status() + update_icon() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/filter.dm b/code/ATMOSPHERICS/components/filter.dm new file mode 100644 index 0000000000000..3c31313cb5f10 --- /dev/null +++ b/code/ATMOSPHERICS/components/filter.dm @@ -0,0 +1,366 @@ +obj/machinery/atmospherics/filter + icon = 'filter.dmi' + icon_state = "intact_off" + density = 1 + + name = "Gas filter" + + dir = SOUTH + initialize_directions = SOUTH|NORTH|WEST + + var/on = 0 + var/temp = null // -- TLE + + var/datum/gas_mixture/air_in + var/datum/gas_mixture/air_out1 + var/datum/gas_mixture/air_out2 + + var/obj/machinery/atmospherics/node_in + var/obj/machinery/atmospherics/node_out1 + var/obj/machinery/atmospherics/node_out2 + + var/datum/pipe_network/network_in + var/datum/pipe_network/network_out1 + var/datum/pipe_network/network_out2 + + var/target_pressure = ONE_ATMOSPHERE + + var/filter_type = 0 +/* +Filter types: +0: Carbon Molecules: Plasma Toxin, Carbon Dioxide, Oxygen Agent B +1: Oxygen: Oxygen ONLY +2: Nitrogen: Nitrogen and Sleeping Agent +3: Carbon Dioxide: Carbon Dioxide ONLY +*/ + + var/frequency = 0 + var/datum/radio_frequency/radio_connection + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, "[frequency]") + + New() + ..() + switch(dir) + if(NORTH) + initialize_directions = NORTH|EAST|SOUTH + if(SOUTH) + initialize_directions = NORTH|SOUTH|WEST + if(EAST) + initialize_directions = EAST|WEST|SOUTH + if(WEST) + initialize_directions = NORTH|EAST|WEST + if(radio_controller) + initialize() + + update_icon() + if(node_out1&&node_out2&&node_in) + icon_state = "intact_[on?("on"):("off")]" + else + var/node_out1_direction = get_dir(src, node_out1) + var/node_out2_direction = get_dir(src, node_out2) + + var/node_in_bit = (node_in)?(1):(0) + + icon_state = "exposed_[node_out1_direction|node_out2_direction]_[node_in_bit]_off" + + on = 0 + + return + + New() + ..() + + air_in = new + air_out1 = new + air_out2 = new + + air_in.volume = 200 + air_out1.volume = 200 + air_out2.volume = 200 + + process() + ..() + if(!on) + return 0 + + var/output_starting_pressure = air_out2.return_pressure() + + if(output_starting_pressure >= target_pressure) + //No need to mix if target is already full! + return 1 + + //Calculate necessary moles to transfer using PV=nRT + + var/pressure_delta = target_pressure - output_starting_pressure + var/transfer_moles + + if(air_in.temperature > 0) + transfer_moles = pressure_delta*air_out2.volume/(air_in.temperature * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + + if(transfer_moles > 0) + var/datum/gas_mixture/removed = air_in.remove(transfer_moles) + + var/datum/gas_mixture/filtered_out = new + filtered_out.temperature = removed.temperature + + switch(filter_type) + if(0) //removing hydrocarbons + filtered_out.toxins = removed.toxins + removed.toxins = 0 + + filtered_out.carbon_dioxide = removed.carbon_dioxide + removed.carbon_dioxide = 0 + + if(removed.trace_gases.len>0) + for(var/datum/gas/trace_gas in removed.trace_gases) + if(istype(trace_gas, /datum/gas/oxygen_agent_b)) + removed.trace_gases -= trace_gas + filtered_out.trace_gases += trace_gas + + if(1) //removing O2 + filtered_out.oxygen = removed.oxygen + removed.oxygen = 0 + + if(2) //removing N2 + filtered_out.nitrogen = removed.nitrogen + removed.nitrogen = 0 + + if(removed.trace_gases.len>0) + for(var/datum/gas/trace_gas in removed.trace_gases) + if(istype(trace_gas, /datum/gas/sleeping_agent)) + removed.trace_gases -= trace_gas + filtered_out.trace_gases += trace_gas + + if(3) //removing CO2 + filtered_out.carbon_dioxide = removed.carbon_dioxide + removed.carbon_dioxide = 0 + + + air_out1.merge(filtered_out) + air_out2.merge(removed) + + if(network_out1) + network_out1.update = 1 + + if(network_out2) + network_out2.update = 1 + + if(network_in) + network_in.update = 1 + + return 1 + +// Housekeeping and pipe network stuff below + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node_out1) + network_out1 = new_network + + else if(reference == node_out2) + network_out2 = new_network + + else if(reference == node_in) + network_in = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + + Del() + loc = null + + if(node_out1) + node_out1.disconnect(src) + del(network_out1) + + if(node_out2) + node_out2.disconnect(src) + del(network_out2) + + if(node_in) + node_in.disconnect(src) + del(network_in) + + node_out1 = null + node_out2 = null + node_in = null + + ..() + + initialize() + if(node_out1 && node_in) return + + var/node_in_connect = turn(dir, -180) + var/node_out1_connect = turn(dir, -90) + var/node_out2_connect = dir + + + for(var/obj/machinery/atmospherics/target in get_step(src,node_out1_connect)) + if(target.initialize_directions & get_dir(target,src)) + node_out1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node_out2_connect)) + if(target.initialize_directions & get_dir(target,src)) + node_out2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node_in_connect)) + if(target.initialize_directions & get_dir(target,src)) + node_in = target + break + + update_icon() + + set_frequency(frequency) + + build_network() + if(!network_out1 && node_out1) + network_out1 = new /datum/pipe_network() + network_out1.normal_members += src + network_out1.build_network(node_out1, src) + + if(!network_out2 && node_out2) + network_out2 = new /datum/pipe_network() + network_out2.normal_members += src + network_out2.build_network(node_out2, src) + + if(!network_in && node_in) + network_in = new /datum/pipe_network() + network_in.normal_members += src + network_in.build_network(node_in, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node_out1) + return network_out1 + + if(reference==node_out2) + return network_out2 + + if(reference==node_in) + return network_in + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network_out1 == old_network) + network_out1 = new_network + + if(network_out2 == old_network) + network_out2 = new_network + + if(network_in == old_network) + network_in = new_network + + return 1 + + return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(network_out1 == reference) + results += air_out1 + + if(network_out2 == reference) + results += air_out2 + + if(network_in == reference) + results += air_in + + return results + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node_out1) + del(network_out1) + node_out1 = null + + else if(reference==node_out2) + del(network_out2) + node_out2 = null + + else if(reference==node_in) + del(network_in) + node_in = null + + return null + + +obj/machinery/atmospherics/filter/attack_hand(user as mob) // -- TLE + var/dat + if(..()) + return + if (1 == 1) +/* + dat += "Autolathe Wires:
" + var/wire + for(wire in src.wires) + dat += text("[wire] Wire: [src.wires[wire] ? "Mend" : "Cut"] Pulse
") + + dat += text("The red light is [src.disabled ? "off" : "on"].
") + dat += text("The green light is [src.shocked ? "off" : "on"].
") + dat += text("The blue light is [src.hacked ? "off" : "on"].
") +*/ + var/current_filter_type + switch(filter_type) + if(0) + current_filter_type = "Carbon Molecules" + if(1) + current_filter_type = "Oxygen" + if(2) + current_filter_type = "Nitrogen" + if(3) + current_filter_type = "Carbon Dioxide" + else + current_filter_type = "ERROR - Report this bug to the admin, please!" + + dat += "Filtering: [current_filter_type]

" + dat += "

Set Filter Type:


" + dat += "Carbon Molecules
" + dat += "Oxygen
" + dat += "Nitrogen
" + dat += "Carbon Dioxide
" + + user << browse("Atmospherics Filter[dat]","window=atmo_filter") + onclose(user, "atmo_filter") + return + if (src.temp) + dat = text("[]

Clear Screen", src.temp, src) + //else + // src.on != src.on + user << browse("Autolathe Control Panel[dat]", "window=atmo_filter") + onclose(user, "atmo_filter") + return + +obj/machinery/atmospherics/filter/Topic(href, href_list) // -- TLE + if(..()) + return + usr.machine = src + src.add_fingerprint(usr) + if(href_list["filterset"]) + if(href_list["filterset"] == "0") + src.filter_type = 0 + if(href_list["filterset"] == "1") + src.filter_type = 1 + if(href_list["filterset"] == "2") + src.filter_type = 2 + if(href_list["filterset"] == "3") + src.filter_type = 3 + if (href_list["temp"]) + src.temp = null + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + return \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/mixer.dm b/code/ATMOSPHERICS/components/mixer.dm new file mode 100644 index 0000000000000..19fe7a056404a --- /dev/null +++ b/code/ATMOSPHERICS/components/mixer.dm @@ -0,0 +1,249 @@ +obj/machinery/atmospherics/mixer + icon = 'mixer.dmi' + icon_state = "intact_off" + density = 1 + + name = "Gas mixer" + + dir = SOUTH + initialize_directions = SOUTH|NORTH|WEST + + var/on = 0 + + var/datum/gas_mixture/air_in1 + var/datum/gas_mixture/air_in2 + var/datum/gas_mixture/air_out + + var/obj/machinery/atmospherics/node_in1 + var/obj/machinery/atmospherics/node_in2 + var/obj/machinery/atmospherics/node_out + + var/datum/pipe_network/network_in1 + var/datum/pipe_network/network_in2 + var/datum/pipe_network/network_out + + var/target_pressure = ONE_ATMOSPHERE + var/node1_concentration = 0.5 + var/node2_concentration = 0.5 + + update_icon() + if(node_in1&&node_in2&&node_out) + icon_state = "intact_[on?("on"):("off")]" + else + var/node_in1_direction = get_dir(src, node_in1) + var/node_in2_direction = get_dir(src, node_in2) + + var/node_out_bit = (node_out)?(1):(0) + + icon_state = "exposed_[node_in1_direction|node_in2_direction]_[node_out_bit]_off" + + on = 0 + + return + + New() + ..() + switch(dir) + if(NORTH) + initialize_directions = NORTH|EAST|SOUTH + if(EAST) + initialize_directions = EAST|SOUTH|WEST + if(SOUTH) + initialize_directions = SOUTH|WEST|NORTH + if(WEST) + initialize_directions = WEST|NORTH|EAST + air_in1 = new + air_in2 = new + air_out = new + + air_in1.volume = 200 + air_in2.volume = 200 + air_out.volume = 300 + + process() + ..() + if(!on) + return 0 + + var/output_starting_pressure = air_out.return_pressure() + + if(output_starting_pressure >= target_pressure) + //No need to mix if target is already full! + return 1 + + //Calculate necessary moles to transfer using PV=nRT + + var/pressure_delta = target_pressure - output_starting_pressure + var/transfer_moles1 = 0 + var/transfer_moles2 = 0 + + if(air_in1.temperature > 0) + transfer_moles1 = (node1_concentration*pressure_delta)*air_out.volume/(air_in1.temperature * R_IDEAL_GAS_EQUATION) + + if(air_in2.temperature > 0) + transfer_moles2 = (node2_concentration*pressure_delta)*air_out.volume/(air_in2.temperature * R_IDEAL_GAS_EQUATION) + + var/air_in1_moles = air_in1.total_moles() + var/air_in2_moles = air_in2.total_moles() + + if((air_in1_moles < transfer_moles1) || (air_in2_moles < transfer_moles2)) + var/ratio = min(air_in1_moles/transfer_moles1, air_in2_moles/transfer_moles2) + + transfer_moles1 *= ratio + transfer_moles2 *= ratio + + //Actually transfer the gas + + if(transfer_moles1 > 0) + var/datum/gas_mixture/removed1 = air_in1.remove(transfer_moles1) + air_out.merge(removed1) + + if(transfer_moles2 > 0) + var/datum/gas_mixture/removed2 = air_in2.remove(transfer_moles2) + air_out.merge(removed2) + + if(network_in1 && transfer_moles1) + network_in1.update = 1 + + if(network_in2 && transfer_moles2) + network_in2.update = 1 + + if(network_out) + network_out.update = 1 + + return 1 + +// Housekeeping and pipe network stuff below + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node_in1) + network_in1 = new_network + + else if(reference == node_in2) + network_in2 = new_network + + else if(reference == node_out) + network_out = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + + Del() + loc = null + + if(node_in1) + node_in1.disconnect(src) + del(network_in1) + + if(node_in2) + node_in2.disconnect(src) + del(network_in2) + + if(node_out) + node_out.disconnect(src) + del(network_out) + + node_in1 = null + node_in2 = null + node_out = null + + ..() + + initialize() + if(node_in1 && node_out) return + + var/node_out_connect = dir + var/node_in1_connect = turn(dir, -90) + var/node_in2_connect = turn(dir, -180) + + for(var/obj/machinery/atmospherics/target in get_step(src,node_in1_connect)) + if(target.initialize_directions & get_dir(target,src)) + node_in1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node_in2_connect)) + if(target.initialize_directions & get_dir(target,src)) + node_in2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node_out_connect)) + if(target.initialize_directions & get_dir(target,src)) + node_out = target + break + + update_icon() + + build_network() + if(!network_in1 && node_in1) + network_in1 = new /datum/pipe_network() + network_in1.normal_members += src + network_in1.build_network(node_in1, src) + + if(!network_in2 && node_in2) + network_in2 = new /datum/pipe_network() + network_in2.normal_members += src + network_in2.build_network(node_in2, src) + + if(!network_out && node_out) + network_out = new /datum/pipe_network() + network_out.normal_members += src + network_out.build_network(node_out, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node_in1) + return network_in1 + + if(reference==node_in2) + return network_in2 + + if(reference==node_out) + return network_out + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network_in1 == old_network) + network_in1 = new_network + + if(network_in2 == old_network) + network_in2 = new_network + + if(network_out == old_network) + network_out = new_network + + return 1 + + return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(network_in1 == reference) + results += air_in1 + + if(network_in2 == reference) + results += air_in2 + + if(network_out == reference) + results += air_out + + return results + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node_in1) + del(network_in1) + node_in1 = null + + else if(reference==node_in2) + del(network_in2) + node_in2 = null + + else if(reference==node_out) + del(network_out) + node_out = null + + return null \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/portables_connector.dm b/code/ATMOSPHERICS/components/portables_connector.dm new file mode 100644 index 0000000000000..e35368ad69abf --- /dev/null +++ b/code/ATMOSPHERICS/components/portables_connector.dm @@ -0,0 +1,129 @@ +/obj/machinery/atmospherics/portables_connector + icon = 'portables_connector.dmi' + icon_state = "intact" + + name = "Connector Port" + desc = "For connecting portables devices related to atmospherics control." + + dir = SOUTH + initialize_directions = SOUTH + + var/obj/machinery/portable_atmospherics/connected_device + + var/obj/machinery/atmospherics/node + + var/datum/pipe_network/network + + var/on = 0 + + level = 0 + + + New() + initialize_directions = dir + ..() + + update_icon() + if(node) + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact" + dir = get_dir(src, node) + else + icon_state = "exposed" + + return + + hide(var/i) //to make the little pipe section invisible, the icon changes. + if(node) + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact" + dir = get_dir(src, node) + else + icon_state = "exposed" + + process() + ..() + if(!on) + return + if(!connected_device) + on = 0 + return + if(network) + network.update = 1 + return 1 + +// Housekeeping and pipe network stuff below + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node) + network = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + + Del() + loc = null + + if(connected_device) + connected_device.disconnect() + + if(node) + node.disconnect(src) + del(network) + + node = null + + ..() + + initialize() + if(node) return + + var/node_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) + if(target.initialize_directions & get_dir(target,src)) + node = target + break + + update_icon() + + build_network() + if(!network && node) + network = new /datum/pipe_network() + network.normal_members += src + network.build_network(node, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node) + return network + + if(reference==connected_device) + return network + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network == old_network) + network = new_network + + return 1 + + return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(connected_device) + results += connected_device.air_contents + + return results + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node) + del(network) + node = null + + return null + diff --git a/code/ATMOSPHERICS/components/unary/cold_sink.dm b/code/ATMOSPHERICS/components/unary/cold_sink.dm new file mode 100644 index 0000000000000..121fc4bbbb56b --- /dev/null +++ b/code/ATMOSPHERICS/components/unary/cold_sink.dm @@ -0,0 +1,40 @@ +/obj/machinery/atmospherics/unary/cold_sink + icon = 'cold_sink.dmi' + icon_state = "intact_off" + density = 1 + + name = "Cold Sink" + desc = "Cools gas when connected to pipe network" + + var/on = 0 + + var/current_temperature = T20C + var/current_heat_capacity = 50000 //totally random + + update_icon() + if(node) + icon_state = "intact_[on?("on"):("off")]" + else + icon_state = "exposed" + + on = 0 + + return + + process() + ..() + if(!on) + return 0 + var/air_heat_capacity = air_contents.heat_capacity() + var/combined_heat_capacity = current_heat_capacity + air_heat_capacity + var/old_temperature = air_contents.temperature + + if(combined_heat_capacity > 0) + var/combined_energy = current_temperature*current_heat_capacity + air_heat_capacity*air_contents.temperature + air_contents.temperature = combined_energy/combined_heat_capacity + + //todo: have current temperature affected. require power to bring down current temperature again + + if(abs(old_temperature-air_contents.temperature) > 1) + network.update = 1 + return 1 \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/generator_input.dm b/code/ATMOSPHERICS/components/unary/generator_input.dm new file mode 100644 index 0000000000000..8ee20073497c9 --- /dev/null +++ b/code/ATMOSPHERICS/components/unary/generator_input.dm @@ -0,0 +1,21 @@ +/obj/machinery/atmospherics/unary/generator_input + icon = 'heat_exchanger.dmi' + icon_state = "intact" + density = 1 + + name = "Generator Input" + desc = "Placeholder" + + var/update_cycle + + update_icon() + if(node) + icon_state = "intact" + else + icon_state = "exposed" + + return + + proc + return_exchange_air() + return air_contents \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/heat_exchanger.dm b/code/ATMOSPHERICS/components/unary/heat_exchanger.dm new file mode 100644 index 0000000000000..e9f7d6b2cd3b0 --- /dev/null +++ b/code/ATMOSPHERICS/components/unary/heat_exchanger.dm @@ -0,0 +1,66 @@ +/obj/machinery/atmospherics/unary/heat_exchanger + + icon = 'heat_exchanger.dmi' + icon_state = "intact" + density = 1 + + name = "Heat Exchanger" + desc = "Exchanges heat between two input gases. Setup for fast heat transfer" + + var/obj/machinery/atmospherics/unary/heat_exchanger/partner = null + var/update_cycle + + update_icon() + if(node) + icon_state = "intact" + else + icon_state = "exposed" + + return + + initialize() + if(!partner) + var/partner_connect = turn(dir,180) + + for(var/obj/machinery/atmospherics/unary/heat_exchanger/target in get_step(src,partner_connect)) + if(target.dir & get_dir(src,target)) + partner = target + partner.partner = src + break + + ..() + + process() + ..() + if(!partner) + return 0 + + if(!air_master || air_master.current_cycle <= update_cycle) + return 0 + + update_cycle = air_master.current_cycle + partner.update_cycle = air_master.current_cycle + + var/air_heat_capacity = air_contents.heat_capacity() + var/other_air_heat_capacity = partner.air_contents.heat_capacity() + var/combined_heat_capacity = other_air_heat_capacity + air_heat_capacity + + var/old_temperature = air_contents.temperature + var/other_old_temperature = partner.air_contents.temperature + + if(combined_heat_capacity > 0) + var/combined_energy = partner.air_contents.temperature*other_air_heat_capacity + air_heat_capacity*air_contents.temperature + + var/new_temperature = combined_energy/combined_heat_capacity + air_contents.temperature = new_temperature + partner.air_contents.temperature = new_temperature + + if(network) + if(abs(old_temperature-air_contents.temperature) > 1) + network.update = 1 + + if(partner.network) + if(abs(other_old_temperature-partner.air_contents.temperature) > 1) + partner.network.update = 1 + + return 1 \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/heat_source.dm b/code/ATMOSPHERICS/components/unary/heat_source.dm new file mode 100644 index 0000000000000..ec65c9409b3c4 --- /dev/null +++ b/code/ATMOSPHERICS/components/unary/heat_source.dm @@ -0,0 +1,42 @@ +/obj/machinery/atmospherics/unary/heat_reservoir +//currently the same code as cold_sink but anticipating process() changes + + icon = 'cold_sink.dmi' + icon_state = "intact_off" + density = 1 + + name = "Heat Reservoir" + desc = "Heats gas when connected to pipe network" + + var/on = 0 + + var/current_temperature = T20C + var/current_heat_capacity = 50000 //totally random + + update_icon() + if(node) + icon_state = "intact_[on?("on"):("off")]" + else + icon_state = "exposed" + + on = 0 + + return + + process() + ..() + if(!on) + return 0 + var/air_heat_capacity = air_contents.heat_capacity() + var/combined_heat_capacity = current_heat_capacity + air_heat_capacity + var/old_temperature = air_contents.temperature + + if(combined_heat_capacity > 0) + var/combined_energy = current_temperature*current_heat_capacity + air_heat_capacity*air_contents.temperature + air_contents.temperature = combined_energy/combined_heat_capacity + + //todo: have current temperature affected. require power to bring up current temperature again + + if(abs(old_temperature-air_contents.temperature) > 1) + network.update = 1 + return 1 \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/outlet_injector.dm b/code/ATMOSPHERICS/components/unary/outlet_injector.dm new file mode 100644 index 0000000000000..98472faca0e71 --- /dev/null +++ b/code/ATMOSPHERICS/components/unary/outlet_injector.dm @@ -0,0 +1,133 @@ +/obj/machinery/atmospherics/unary/outlet_injector + icon = 'outlet_injector.dmi' + icon_state = "off" + + name = "Air Injector" + desc = "Has a valve and pump attached to it" + + var/on = 0 + var/injecting = 0 + + var/volume_rate = 50 + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + + level = 1 + + update_icon() + if(node) + if(on) + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on" + else + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" + else + icon_state = "exposed" + on = 0 + + return + + process() + ..() + injecting = 0 + + if(!on) + return 0 + + if(air_contents.temperature > 0) + var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) + + loc.assume_air(removed) + + if(network) + network.update = 1 + + return 1 + + proc/inject() + if(on || injecting) + return 0 + + injecting = 1 + + if(air_contents.temperature > 0) + var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) + + loc.assume_air(removed) + + if(network) + network.update = 1 + + flick("inject", src) + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, "[frequency]") + + broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = id + signal.data["device"] = "AO" + signal.data["power"] = on + signal.data["volume_rate"] = volume_rate + + radio_connection.post_signal(src, signal) + + return 1 + + initialize() + ..() + + set_frequency(frequency) + + receive_signal(datum/signal/signal) + if(signal.data["tag"] && (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("power_on") + on = 1 + + if("power_off") + on = 0 + + if("power_toggle") + on = !on + + if("inject") + spawn inject() + + if("set_volume_rate") + var/number = text2num(signal.data["parameter"]) + number = min(max(number, 0), air_contents.volume) + + volume_rate = number + + if(signal.data["tag"]) + spawn(5) broadcast_status() + update_icon() + + hide(var/i) //to make the little pipe section invisible, the icon changes. + if(node) + if(on) + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on" + else + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" + else + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]exposed" + on = 0 + return \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/oxygen_generator.dm b/code/ATMOSPHERICS/components/unary/oxygen_generator.dm new file mode 100644 index 0000000000000..38447efa0e05b --- /dev/null +++ b/code/ATMOSPHERICS/components/unary/oxygen_generator.dm @@ -0,0 +1,49 @@ +obj/machinery/atmospherics/unary/oxygen_generator + icon = 'oxygen_generator.dmi' + icon_state = "intact_off" + density = 1 + + name = "Oxygen Generator" + desc = "" + + dir = SOUTH + initialize_directions = SOUTH + + var/on = 0 + + var/oxygen_content = 10 + + update_icon() + if(node) + icon_state = "intact_[on?("on"):("off")]" + else + icon_state = "exposed_off" + + on = 0 + + return + + New() + ..() + + air_contents.volume = 50 + + process() + ..() + if(!on) + return 0 + + var/total_moles = air_contents.total_moles() + + if(total_moles < oxygen_content) + var/current_heat_capacity = air_contents.heat_capacity() + + var/added_oxygen = oxygen_content - total_moles + + air_contents.temperature = (current_heat_capacity*air_contents.temperature + 20*added_oxygen*T0C)/(current_heat_capacity+20*added_oxygen) + air_contents.oxygen += added_oxygen + + if(network) + network.update = 1 + + return 1 \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/unary_base.dm b/code/ATMOSPHERICS/components/unary/unary_base.dm new file mode 100644 index 0000000000000..230296a9f4830 --- /dev/null +++ b/code/ATMOSPHERICS/components/unary/unary_base.dm @@ -0,0 +1,87 @@ +/obj/machinery/atmospherics/unary + dir = SOUTH + initialize_directions = SOUTH + + var/datum/gas_mixture/air_contents + + var/obj/machinery/atmospherics/node + + var/datum/pipe_network/network + + New() + ..() + initialize_directions = dir + air_contents = new + + air_contents.volume = 200 + +// Housekeeping and pipe network stuff below + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(reference == node) + network = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + return null + + Del() + loc = null + + if(node) + node.disconnect(src) + del(network) + + node = null + + ..() + + initialize() + if(node) return + + var/node_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) + if(target.initialize_directions & get_dir(target,src)) + node = target + break + + update_icon() + + build_network() + if(!network && node) + network = new /datum/pipe_network() + network.normal_members += src + network.build_network(node, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node) + return network + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network == old_network) + network = new_network + + return 1 + + return_network_air(datum/pipe_network/reference) + var/list/results = list() + + if(network == reference) + results += air_contents + + return results + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node) + del(network) + node = null + + return null \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm new file mode 100644 index 0000000000000..20bf82c05ce11 --- /dev/null +++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm @@ -0,0 +1,212 @@ +/obj/machinery/atmospherics/unary/vent_pump + icon = 'vent_pump.dmi' + icon_state = "off" + + name = "Air Vent" + desc = "Has a valve and pump attached to it" + + level = 1 + + high_volume + name = "Large Air Vent" + + New() + ..() + + air_contents.volume = 1000 + + var/on = 0 + var/pump_direction = 1 //0 = siphoning, 1 = releasing + + var/external_pressure_bound = ONE_ATMOSPHERE + var/internal_pressure_bound = 0 + + var/pressure_checks = 1 + //1: Do not pass external_pressure_bound + //2: Do not pass internal_pressure_bound + //3: Do not pass either + + var/welded = 0 // Added for aliens -- TLE + + update_icon() + if(on&&node) + if(pump_direction) + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out" + else + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" + else + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" + on = 0 + + return + + process() + ..() + if(!on) + return 0 + if(welded) + return 0 + + var/datum/gas_mixture/environment = loc.return_air() + var/environment_pressure = environment.return_pressure() + + if(pump_direction) //internal -> external + var/pressure_delta = 10000 + + if(pressure_checks&1) + pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure)) + if(pressure_checks&2) + pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound)) + + if(pressure_delta > 0) + if(air_contents.temperature > 0) + var/transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) + + loc.assume_air(removed) + + if(network) + network.update = 1 + + else //external -> internal + var/pressure_delta = 10000 + + if(pressure_checks&1) + pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound)) + if(pressure_checks&2) + pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure())) + + if(pressure_delta > 0) + if(environment.temperature > 0) + var/transfer_moles = pressure_delta*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) + + air_contents.merge(removed) + + if(network) + network.update = 1 + + return 1 + + //Radio remote control + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, "[frequency]") + + broadcast_status() + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = id + signal.data["device"] = "AVP" + signal.data["power"] = on?("on"):("off") + signal.data["direction"] = pump_direction?("release"):("siphon") + signal.data["checks"] = pressure_checks + signal.data["internal"] = internal_pressure_bound + signal.data["external"] = external_pressure_bound + + radio_connection.post_signal(src, signal) + + return 1 + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + + initialize() + ..() + if(frequency) + set_frequency(frequency) + update_icon() + + receive_signal(datum/signal/signal) + if(signal.data["tag"] && (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("power_on") + on = 1 + + if("power_off") + on = 0 + + if("power_toggle") + on = !on + + if("set_direction") + var/number = text2num(signal.data["parameter"]) + if(number > 0.5) + pump_direction = 1 + else + pump_direction = 0 + + if("purge") + pressure_checks &= ~1 + pump_direction = 0 + + if("stabalize") + pressure_checks |= 1 + pump_direction = 1 + + if("set_checks") + var/number = round(text2num(signal.data["parameter"]),1) + pressure_checks = number + + if("set_internal_pressure") + var/number = text2num(signal.data["parameter"]) + number = min(max(number, 0), ONE_ATMOSPHERE*50) + + internal_pressure_bound = number + + if("set_external_pressure") + var/number = text2num(signal.data["parameter"]) + number = min(max(number, 0), ONE_ATMOSPHERE*50) + + external_pressure_bound = number + + if(signal.data["tag"]) + spawn(5) broadcast_status() + + hide(var/i) //to make the little pipe section invisible, the icon changes. + if(on&&node) + if(pump_direction) + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out" + else + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" + else + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" + on = 0 + return + + attackby(obj/item/W, mob/user) // Added for aliens -- TLE + // Stolen from the Emitter welding code of the Singularity + if(istype(W, /obj/item/weapon/weldingtool) && W:welding) + if (W:get_fuel() < 1) + user << "\blue You need more welding fuel to complete this task." + return + W:use_fuel(1) + + if(!welded) + user.visible_message("[user] welds the vent shut.", "You weld the vent shut.") + playsound(src.loc, 'Welder2.ogg', 50, 1) + welded = 1 + else + user.visible_message("[user] unwelds the vent.", "You unweld the vent.") + playsound(src.loc, 'Welder2.ogg', 50, 1) + welded = 0 + + examine() + set src in oview(1) + ..() + if(welded) + usr << "It seems welded shut." \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm new file mode 100644 index 0000000000000..7c66541e7f2ce --- /dev/null +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -0,0 +1,88 @@ +/obj/machinery/atmospherics/unary/vent_scrubber + icon = 'vent_scrubber.dmi' + icon_state = "off" + + name = "Air Scrubber" + desc = "Has a valve and pump attached to it" + + level = 1 + + var/on = 0 + var/scrubbing = 1 //0 = siphoning, 1 = scrubbing + var/scrub_CO2 = 1 + var/scrub_Toxins = 0 + + var/volume_rate = 120 + + update_icon() + if(on&&node) + if(scrubbing) + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on" + else + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" + else + icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" + on = 0 + + return + + process() + ..() + if(!on) + return 0 + + var/datum/gas_mixture/environment = loc.return_air() + + if(scrubbing) + if((environment.toxins>0) || (environment.carbon_dioxide>0) || (environment.trace_gases.len>0)) + var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles() + + //Take a gas sample + var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) + + //Filter it + var/datum/gas_mixture/filtered_out = new + filtered_out.temperature = removed.temperature + if(scrub_Toxins) + filtered_out.toxins = removed.toxins + removed.toxins = 0 + if(scrub_CO2) + filtered_out.carbon_dioxide = removed.carbon_dioxide + removed.carbon_dioxide = 0 + + if(removed.trace_gases.len>0) + for(var/datum/gas/trace_gas in removed.trace_gases) + if(istype(trace_gas, /datum/gas/oxygen_agent_b)) + removed.trace_gases -= trace_gas + filtered_out.trace_gases += trace_gas + + //Remix the resulting gases + air_contents.merge(filtered_out) + + loc.assume_air(removed) + + if(network) + network.update = 1 + + else //Just siphoning all air + var/transfer_moles = environment.total_moles()*(volume_rate/environment.volume) + + var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) + + air_contents.merge(removed) + + if(network) + network.update = 1 + + return 1 + + hide(var/i) //to make the little pipe section invisible, the icon changes. + if(on&&node) + if(scrubbing) + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on" + else + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" + else + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" + on = 0 + return \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/valve.dm b/code/ATMOSPHERICS/components/valve.dm new file mode 100644 index 0000000000000..0e3c2def31ad2 --- /dev/null +++ b/code/ATMOSPHERICS/components/valve.dm @@ -0,0 +1,249 @@ +obj/machinery/atmospherics/valve + icon = 'valve.dmi' + icon_state = "valve0" + + name = "manual valve" + desc = "A pipe valve" + + dir = SOUTH + initialize_directions = SOUTH|NORTH + + var/open = 0 + + var/obj/machinery/atmospherics/node1 + var/obj/machinery/atmospherics/node2 + + var/datum/pipe_network/network_node1 + var/datum/pipe_network/network_node2 + + update_icon(animation) + if(animation) + flick("valve[src.open][!src.open]",src) + else + icon_state = "valve[open]" + + New() + switch(dir) + if(NORTH || SOUTH) + initialize_directions = NORTH|SOUTH + if(EAST || WEST) + initialize_directions = EAST|WEST + + network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + + + if(reference == node1) + network_node1 = new_network + if(open) + network_node2 = new_network + else if(reference == node2) + network_node2 = new_network + if(open) + network_node1 = new_network + + if(new_network.normal_members.Find(src)) + return 0 + + new_network.normal_members += src + + if(open) + if(reference == node1) + return node2.network_expand(new_network, src) + else if(reference == node2) + return node1.network_expand(new_network, src) + + return null + + Del() + loc = null + + if(node1) + node1.disconnect(src) + del(network_node1) + if(node2) + node2.disconnect(src) + del(network_node2) + + node1 = null + node2 = null + + ..() + + proc/open() + + if(open) return 0 + + open = 1 + update_icon() + + if(network_node1&&network_node2) + network_node1.merge(network_node2) + network_node2 = network_node1 + + if(network_node1) + network_node1.update = 1 + else if(network_node2) + network_node2.update = 1 + + return 1 + + proc/close() + + if(!open) + return 0 + + open = 0 + update_icon() + + if(network_node1) + del(network_node1) + if(network_node2) + del(network_node2) + + build_network() + + return 1 + + attack_paw(mob/user as mob) + return attack_hand(user) + + attack_hand(mob/user as mob) + update_icon(1) + sleep(10) + if (src.open) + src.close() + else + src.open() + + process() + ..() + if(open && (!node1 || !node2)) + close() + + return + + initialize() + if(node1 && node2) return + + var/connect_directions + + switch(dir) + if(NORTH) + connect_directions = NORTH|SOUTH + if(SOUTH) + connect_directions = NORTH|SOUTH + if(EAST) + connect_directions = EAST|WEST + if(WEST) + connect_directions = EAST|WEST + else + connect_directions = 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)) + connect_directions &= ~direction + + node1 = target + break + 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 + break + break + + build_network() + if(!network_node1 && node1) + network_node1 = new /datum/pipe_network() + network_node1.normal_members += src + network_node1.build_network(node1, src) + + if(!network_node2 && node2) + network_node2 = new /datum/pipe_network() + network_node2.normal_members += src + network_node2.build_network(node2, src) + + + return_network(obj/machinery/atmospherics/reference) + build_network() + + if(reference==node1) + return network_node1 + + if(reference==node2) + return network_node2 + + return null + + reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) + if(network_node1 == old_network) + network_node1 = new_network + if(network_node2 == old_network) + network_node2 = new_network + + return 1 + + return_network_air(datum/network/reference) + return null + + disconnect(obj/machinery/atmospherics/reference) + if(reference==node1) + del(network_node1) + node1 = null + + else if(reference==node2) + del(network_node2) + node2 = null + + return null + + digital // can be controlled by AI + name = "digital valve" + desc = "A digitally controlled valve." + icon = 'digital_valve.dmi' + + attack_ai(mob/user as mob) + return src.attack_hand(user) + + //Radio remote control + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + if(frequency) + radio_connection = radio_controller.add_object(src, "[frequency]") + + var/frequency = 0 + var/id = null + var/datum/radio_frequency/radio_connection + + initialize() + ..() + if(frequency) + set_frequency(frequency) + + receive_signal(datum/signal/signal) + if(signal.data["tag"] && (signal.data["tag"] != id)) + return 0 + + switch(signal.data["command"]) + if("valve_open") + if(!open) + open() + + if("valve_close") + if(open) + close() + + if("valve_toggle") + if(open) + close() + else + open() \ No newline at end of file diff --git a/code/ATMOSPHERICS/datum_pipe_network.dm b/code/ATMOSPHERICS/datum_pipe_network.dm new file mode 100644 index 0000000000000..47ef15f924057 --- /dev/null +++ b/code/ATMOSPHERICS/datum_pipe_network.dm @@ -0,0 +1,203 @@ +var/global/list/datum/pipe_network/pipe_networks = list() + +datum/pipe_network + var/list/datum/gas_mixture/gases = list() //All of the gas_mixtures continuously connected in this network + + var/list/obj/machinery/atmospherics/normal_members = list() + var/list/datum/pipeline/line_members = list() + //membership roster to go through for updates and what not + + var/update = 1 + var/datum/gas_mixture/air_transient = null + + New() + air_transient = new() + + ..() + + proc/process() + //Equalize gases amongst pipe if called for + if(update) + update = 0 + reconcile_air() //equalize_gases(gases) + + //Give pipelines their process call for pressure checking and what not + for(var/datum/pipeline/line_member in line_members) + line_member.process() + + proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference) + //Purpose: Generate membership roster + //Notes: Assuming that members will add themselves to appropriate roster in network_expand() + + if(!start_normal) + del(src) + + start_normal.network_expand(src, reference) + + update_network_gases() + + if((normal_members.len>0)||(line_members.len>0)) + pipe_networks += src + else + del(src) + + proc/merge(datum/pipe_network/giver) + if(giver==src) return 0 + + normal_members -= giver.normal_members + normal_members += giver.normal_members + + line_members -= giver.line_members + line_members += giver.line_members + + for(var/obj/machinery/atmospherics/normal_member in giver.normal_members) + normal_member.reassign_network(giver, src) + + for(var/datum/pipeline/line_member in giver.line_members) + line_member.network = src + + del(giver) + + update_network_gases() + return 1 + + proc/update_network_gases() + //Go through membership roster and make sure gases is up to date + + gases = list() + + for(var/obj/machinery/atmospherics/normal_member in normal_members) + var/result = normal_member.return_network_air(src) + if(result) gases += result + + for(var/datum/pipeline/line_member in line_members) + gases += line_member.air + + proc/reconcile_air() + //Perfectly equalize all gases members instantly + + //Calculate totals from individual components + var/total_thermal_energy = 0 + var/total_heat_capacity = 0 + + air_transient.volume = 0 + + air_transient.oxygen = 0 + air_transient.nitrogen = 0 + air_transient.toxins = 0 + air_transient.carbon_dioxide = 0 + + + air_transient.trace_gases = list() + + for(var/datum/gas_mixture/gas in gases) + air_transient.volume += gas.volume + total_thermal_energy += gas.thermal_energy() + total_heat_capacity += gas.heat_capacity() + + air_transient.oxygen += gas.oxygen + air_transient.nitrogen += gas.nitrogen + air_transient.toxins += gas.toxins + air_transient.carbon_dioxide += gas.carbon_dioxide + + if(gas.trace_gases.len) + for(var/datum/gas/trace_gas in gas.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in air_transient.trace_gases + if(!corresponding) + corresponding = new trace_gas.type() + air_transient.trace_gases += corresponding + + corresponding.moles += trace_gas.moles + + if(air_transient.volume > 0) + + if(total_heat_capacity > 0) + air_transient.temperature = total_thermal_energy/total_heat_capacity + + //Allow air mixture to react + if(air_transient.react()) + update = 1 + + else + air_transient.temperature = 0 + + //Update individual gas_mixtures by volume ratio + 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.carbon_dioxide = air_transient.carbon_dioxide*gas.volume/air_transient.volume + + gas.temperature = air_transient.temperature + + if(air_transient.trace_gases.len) + for(var/datum/gas/trace_gas in air_transient.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in gas.trace_gases + if(!corresponding) + corresponding = new trace_gas.type() + gas.trace_gases += corresponding + + corresponding.moles = trace_gas.moles*gas.volume/air_transient.volume + return 1 + +proc/equalize_gases(datum/gas_mixture/list/gases) + //Perfectly equalize all gases members instantly + + //Calculate totals from individual components + var/total_volume = 0 + var/total_thermal_energy = 0 + var/total_heat_capacity = 0 + + var/total_oxygen = 0 + var/total_nitrogen = 0 + var/total_toxins = 0 + var/total_carbon_dioxide = 0 + + var/list/total_trace_gases = list() + + for(var/datum/gas_mixture/gas in gases) + total_volume += gas.volume + total_thermal_energy += gas.thermal_energy() + total_heat_capacity += gas.heat_capacity() + + total_oxygen += gas.oxygen + total_nitrogen += gas.nitrogen + total_toxins += gas.toxins + total_carbon_dioxide += gas.carbon_dioxide + + if(gas.trace_gases.len) + for(var/datum/gas/trace_gas in gas.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in total_trace_gases + if(!corresponding) + corresponding = new trace_gas.type() + total_trace_gases += corresponding + + corresponding.moles += trace_gas.moles + + if(total_volume > 0) + + //Calculate temperature + var/temperature = 0 + + if(total_heat_capacity > 0) + temperature = total_thermal_energy/total_heat_capacity + + //Update individual gas_mixtures by volume ratio + 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.carbon_dioxide = total_carbon_dioxide*gas.volume/total_volume + + gas.temperature = temperature + + if(total_trace_gases.len) + for(var/datum/gas/trace_gas in total_trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in gas.trace_gases + if(!corresponding) + corresponding = new trace_gas.type() + gas.trace_gases += corresponding + + corresponding.moles = trace_gas.moles*gas.volume/total_volume + + return 1 \ No newline at end of file diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm new file mode 100644 index 0000000000000..488ba84a29bc0 --- /dev/null +++ b/code/ATMOSPHERICS/datum_pipeline.dm @@ -0,0 +1,231 @@ +datum/pipeline + var/datum/gas_mixture/air + + var/list/obj/machinery/atmospherics/pipe/members + var/list/obj/machinery/atmospherics/pipe/edges //Used for building networks + + var/datum/pipe_network/network + + var/alert_pressure = 0 + + Del() + if(network) + del(network) + + if(air && air.volume) + temporarily_store_air() + del(air) + + ..() + + proc/process() + + //Check to see if pressure is within acceptable limits + var/pressure = air.return_pressure() + if(pressure > alert_pressure) + for(var/obj/machinery/atmospherics/pipe/member in members) + if(!member.check_pressure(pressure)) + break //Only delete 1 pipe per process + + //Allow for reactions + //air.react() //Should be handled by pipe_network now + + proc/temporarily_store_air() + //Update individual gas_mixtures by volume ratio + + for(var/obj/machinery/atmospherics/pipe/member in members) + member.air_temporary = new + member.air_temporary.volume = member.volume + + 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.carbon_dioxide = air.carbon_dioxide*member.volume/air.volume + + member.air_temporary.temperature = air.temperature + + if(air.trace_gases.len) + for(var/datum/gas/trace_gas in air.trace_gases) + var/datum/gas/corresponding = new trace_gas.type() + member.air_temporary.trace_gases += corresponding + + corresponding.moles = trace_gas.moles*member.volume/air.volume + + proc/build_pipeline(obj/machinery/atmospherics/pipe/base) + air = new + + var/list/possible_expansions = list(base) + members = list(base) + edges = list() + + var/volume = base.volume + base.parent = src + alert_pressure = base.alert_pressure + + if(base.air_temporary) + air = base.air_temporary + base.air_temporary = null + else + air = new + + while(possible_expansions.len>0) + for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions) + + var/list/result = borderline.pipeline_expansion() + var/edge_check = result.len + + if(result.len>0) + for(var/obj/machinery/atmospherics/pipe/item in result) + if(!members.Find(item)) + members += item + possible_expansions += item + + volume += item.volume + item.parent = src + + alert_pressure = min(alert_pressure, item.alert_pressure) + + if(item.air_temporary) + air.merge(item.air_temporary) + + edge_check-- + + if(edge_check>0) + edges += borderline + + possible_expansions -= borderline + + air.volume = volume + + proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + + if(new_network.line_members.Find(src)) + return 0 + + new_network.line_members += src + + network = new_network + + for(var/obj/machinery/atmospherics/pipe/edge in edges) + for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion()) + if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference)) + result.network_expand(new_network, edge) + + return 1 + + proc/return_network(obj/machinery/atmospherics/reference) + if(!network) + network = new /datum/pipe_network() + network.build_network(src, null) + //technically passing these parameters should not be allowed + //however pipe_network.build_network(..) and pipeline.network_extend(...) + // were setup to properly handle this case + + return network + + proc/mingle_with_turf(turf/simulated/target, mingle_volume) + var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume) + air_sample.volume = mingle_volume + + if(istype(target) && target.parent && target.parent.group_processing) + //Have to consider preservation of group statuses + var/datum/gas_mixture/turf_copy = new + + turf_copy.copy_from(target.parent.air) + turf_copy.volume = target.parent.air.volume //Copy a good representation of the turf from parent group + + equalize_gases(list(air_sample, turf_copy)) + air.merge(air_sample) + + if(target.parent.air.compare(turf_copy)) + //The new turf would be an acceptable group member so permit the integration + + turf_copy.subtract(target.parent.air) + + target.parent.air.merge(turf_copy) + + else + //Comparison failure so dissemble group and copy turf + + target.parent.suspend_group_processing() + target.air.copy_from(turf_copy) + + else + var/datum/gas_mixture/turf_air = target.return_air() + + equalize_gases(list(air_sample, turf_air)) + 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) + + network.update = 1 + + proc/temperature_interact(turf/target, share_volume, thermal_conductivity) + var/total_heat_capacity = air.heat_capacity() + var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume) + + if(istype(target, /turf/simulated)) + var/turf/simulated/modeled_location = target + + if(modeled_location.blocks_air) + + if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0)) + var/delta_temperature = air.temperature - modeled_location.temperature + + var/heat = thermal_conductivity*delta_temperature* \ + (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity)) + + air.temperature -= heat/total_heat_capacity + modeled_location.temperature += heat/modeled_location.heat_capacity + + else + var/delta_temperature = 0 + var/sharer_heat_capacity = 0 + + if(modeled_location.parent && modeled_location.parent.group_processing) + delta_temperature = (air.temperature - modeled_location.parent.air.temperature) + sharer_heat_capacity = modeled_location.parent.air.heat_capacity() + else + delta_temperature = (air.temperature - modeled_location.air.temperature) + sharer_heat_capacity = modeled_location.air.heat_capacity() + + var/self_temperature_delta = 0 + var/sharer_temperature_delta = 0 + + if((sharer_heat_capacity>0) && (partial_heat_capacity>0)) + var/heat = thermal_conductivity*delta_temperature* \ + (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity)) + + self_temperature_delta = -heat/total_heat_capacity + sharer_temperature_delta = heat/sharer_heat_capacity + else + return 1 + + air.temperature += self_temperature_delta + + if(modeled_location.parent && modeled_location.parent.group_processing) + if((abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && (abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*modeled_location.parent.air.temperature)) + modeled_location.parent.suspend_group_processing() + + modeled_location.air.temperature += sharer_temperature_delta + + else + modeled_location.parent.air.temperature += sharer_temperature_delta/modeled_location.parent.air.group_multiplier + else + modeled_location.air.temperature += sharer_temperature_delta + + + else + if((target.heat_capacity>0) && (partial_heat_capacity>0)) + var/delta_temperature = air.temperature - target.temperature + + var/heat = thermal_conductivity*delta_temperature* \ + (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity)) + + air.temperature -= heat/total_heat_capacity + + network.update = 1 \ No newline at end of file diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm new file mode 100644 index 0000000000000..bf5a7b9bbd46e --- /dev/null +++ b/code/ATMOSPHERICS/pipes.dm @@ -0,0 +1,681 @@ +obj/machinery/atmospherics/pipe + + var/datum/gas_mixture/air_temporary //used when reconstructing a pipeline that broke + var/datum/pipeline/parent + + var/volume = 0 + var/nodealert = 0 + + var/alert_pressure = 80*ONE_ATMOSPHERE + //minimum pressure before check_pressure(...) should be called + + 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 + + return 1 + + return_air() + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) + + return parent.air + + build_network() + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) + + 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) + + return parent.network_expand(new_network, reference) + + return_network(obj/machinery/atmospherics/reference) + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) + + return parent.return_network(reference) + + Del() + del(parent) + if(air_temporary) + loc.assume_air(air_temporary) + + ..() + + simple + icon = '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 = WALL_HEAT_TRANSFER_COEFFICIENT + + 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 + ..() + + 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(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) + + check_pressure(pressure) + var/datum/gas_mixture/environment = loc.return_air() + + var/pressure_difference = pressure - environment.return_pressure() + + if(pressure_difference > maximum_pressure) + del(src) + + else if(pressure_difference > fatigue_pressure) + if(prob(5)) + del(src) + + else return 1 + + Del() + if(node1) + node1.disconnect(src) + if(node2) + node2.disconnect(src) + + ..() + + pipeline_expansion() + return list(node1, node2) + + update_icon() + if(node1&&node2) + icon_state = "intact[invisibility ? "-f" : "" ]" + + var/node1_direction = get_dir(src, node1) + var/node2_direction = get_dir(src, node2) + + dir = node1_direction|node2_direction + if(dir==3) dir = 1 + else if(dir==12) dir = 4 + + else + icon_state = "exposed[invisibility ? "-f" : "" ]" + + if(node1) + dir = get_dir(src,node1) + + else if(node2) + dir = get_dir(src,node2) + + else + del(src) + + initialize() + var/connect_directions + + switch(dir) + if(NORTH) + connect_directions = NORTH|SOUTH + if(SOUTH) + connect_directions = NORTH|SOUTH + if(EAST) + connect_directions = EAST|WEST + if(WEST) + connect_directions = EAST|WEST + else + connect_directions = 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 + break + + connect_directions &= ~direction + 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 + break + + connect_directions &= ~direction + break + + var/turf/T = src.loc // hide if turf is not intact + hide(T.intact) + //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/insulated + icon = '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 + + + simple/junction + icon = 'junction.dmi' + icon_state = "intact" + level = 2 + + update_icon() + if(istype(node1, /obj/machinery/atmospherics/pipe/simple/heat_exchanging)) + dir = get_dir(src, node1) + + if(node2) + icon_state = "intact" + else + icon_state = "exposed" + + else if(istype(node2, /obj/machinery/atmospherics/pipe/simple/heat_exchanging)) + dir = get_dir(src, node2) + + if(node1) + icon_state = "intact" + else + icon_state = "exposed" + + else + icon_state = "exposed" + + simple/heat_exchanging + icon = 'heat.dmi' + icon_state = "3" + level = 2 + + minimum_temperature_difference = 20 + thermal_conductivity = WINDOW_HEAT_TRANSFER_COEFFICIENT + + update_icon() + if(node1&&node2) + icon_state = "intact" + + var/node1_direction = get_dir(src, node1) + var/node2_direction = get_dir(src, node2) + + icon_state = "[node1_direction|node2_direction]" + + tank + icon = 'pipe_tank.dmi' + icon_state = "intact" + + name = "Pressure Tank" + desc = "A large vessel containing pressurized gas." + + volume = 1620 //in liters, 0.9 meters by 0.9 meters by 2 meters + + dir = SOUTH + initialize_directions = SOUTH + density = 1 + + var/obj/machinery/atmospherics/node1 + + New() + initialize_directions = dir + ..() + + process() + ..() + if(!node1) + parent.mingle_with_turf(loc, 200) + + 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 = '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 = '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 = '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 = '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 = '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 = 'pipe_vent.dmi' + icon_state = "intact" + + name = "Vent" + desc = "A large air vent" + + level = 1 + + volume = 250 + + dir = SOUTH + initialize_directions = SOUTH + + var/obj/machinery/atmospherics/node1 + New() + initialize_directions = dir + ..() + + process() + ..() + if(parent) + parent.mingle_with_turf(loc, 250) + + 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 = '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 + + 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(!node1) + parent.mingle_with_turf(loc, 70) + + else if(!node2) + parent.mingle_with_turf(loc, 70) + + else if(!node3) + parent.mingle_with_turf(loc, 70) + + 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) + 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 + + 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 + break + + connect_directions &= ~direction + 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 + break + + connect_directions &= ~direction + 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 + break + + connect_directions &= ~direction + break + + var/turf/T = src.loc // hide if turf is not intact + hide(T.intact) + //update_icon() diff --git a/code/FEA/DEBUG_REMOVE_BEFORE_RELEASE.dm b/code/FEA/DEBUG_REMOVE_BEFORE_RELEASE.dm new file mode 100644 index 0000000000000..daee6247330e6 --- /dev/null +++ b/code/FEA/DEBUG_REMOVE_BEFORE_RELEASE.dm @@ -0,0 +1,604 @@ +#define DEBUG + +datum/air_group/var/marker +datum/air_group/var/debugging = 0 +datum/pipe_network/var/marker + +datum/gas_mixture + var/turf/parent + +/* +turf/simulated + New() + ..() + + if(air) + air.parent = src +*/ +obj/machinery/door + verb + toggle_door() + set src in world + if(density) + open() + else + close() + +turf/space + verb + create_floor() + set src in world + new /turf/simulated/floor(src) + + create_meteor(direction as num) + set src in world + + var/obj/meteor/M = new( src ) + walk(M, direction,10) + + +turf/simulated/wall + verb + create_floor() + set src in world + new /turf/simulated/floor(src) + +obj/item/weapon/tank + verb + adjust_mixture(temperature as num, target_toxin_pressure as num, target_oxygen_pressure as num) + set src in world + if(!air_contents) + usr << "\red ERROR: no gas_mixture associated with this tank" + return null + + air_contents.temperature = temperature + air_contents.oxygen = target_oxygen_pressure*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature) + air_contents.toxins = target_toxin_pressure*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature) + +turf/simulated/floor + verb + parent_info() + set src in world + if(parent) + usr << "[x],[y] parent: Processing: [parent.group_processing]" + if(parent.members) + usr << "Members: [parent.members.len]" + else + usr << "Members: None?" + if(parent.borders) + usr << "Borders: [parent.borders.len]" + else + usr << "Borders: None" + if(parent.length_space_border) + usr << "Space Borders: [parent.space_borders.len], Space Length: [parent.length_space_border]" + else + usr << "Space Borders: None" + else + usr << "\blue [x],[y] has no parent air group." + + verb + create_wall() + set src in world + new /turf/simulated/wall(src) + verb + adjust_mixture(temp as num, tox as num, oxy as num) + set src in world + var/datum/gas_mixture/stuff = return_air() + stuff.temperature = temp + stuff.toxins = tox + stuff.oxygen = oxy + + verb + boom(inner_range as num, middle_range as num, outer_range as num) + set src in world + explosion(src,inner_range,middle_range,outer_range,outer_range) + + verb + flag_parent() + set src in world + if(parent) + parent.debugging = !parent.debugging + usr << "[parent.members.len] set to [parent.debugging]" + verb + small_explosion() + set src in world + explosion(src, 1, 2, 3, 3) + + verb + large_explosion() + set src in world + explosion(src, 3, 5, 7, 5) + +obj/machinery/portable_atmospherics/canister + verb/test_release() + set src in world + set category = "Minor" + + valve_open = 1 + release_pressure = 1000 + +obj/machinery/atmospherics + unary + heat_reservoir + verb + toggle_power() + set src in world + set category = "Minor" + + on = !on + + update_icon() + adjust_temp(temp as num) + set src in world + set category = "Minor" + + current_temperature = temp + cold_sink + verb + toggle_power() + set src in world + set category = "Minor" + + on = !on + + update_icon() + adjust_temp(temp as num) + set src in world + set category = "Minor" + + current_temperature = temp + vent_pump + verb + toggle_power() + set src in world + set category = "Minor" + + on = !on + + update_icon() + + toggle_direction() + set src in world + set category = "Minor" + + pump_direction = !pump_direction + + update_icon() + + change_pressure_parameters() + set src in world + set category = "Minor" + + usr << "current settings: PC=[pressure_checks], EB=[external_pressure_bound], IB=[internal_pressure_bound]" + + var/mode = input(usr, "Select an option:") in list("Bound External", "Bound Internal", "Bound Both") + + switch(mode) + if("Bound External") + pressure_checks = 1 + external_pressure_bound = input(usr, "External Pressure Bound?") as num + if("Bound Internal") + pressure_checks = 2 + internal_pressure_bound = input(usr, "Internal Pressure Bound?") as num + else + pressure_checks = 3 + external_pressure_bound = input(usr, "External Pressure Bound?") as num + internal_pressure_bound = input(usr, "Internal Pressure Bound?") as num + + outlet_injector + verb + toggle_power() + set src in world + set category = "Minor" + + on = !on + + update_icon() + verb + trigger_inject() + set src in world + set category = "Minor" + + inject() + + vent_scrubber + verb + toggle_power() + set src in world + set category = "Minor" + + on = !on + + update_icon() + + toggle_scrubbing() + set src in world + set category = "Minor" + + scrubbing = !scrubbing + + update_icon() + + change_rate(amount as num) + set src in world + set category = "Minor" + + volume_rate = amount + + mixer + verb + toggle() + set src in world + set category = "Minor" + + on = !on + + update_icon() + + change_pressure(amount as num) + set src in world + set category = "Minor" + + target_pressure = amount + + change_ratios() + set src in world + set category = "Minor" + + if(node_in1) + var/node_ratio = input(usr, "Node 1 Ratio? ([dir2text(get_dir(src, node_in1))])") as num + node_ratio = min(max(0,node_ratio),1) + + node1_concentration = node_ratio + node2_concentration = 1-node_ratio + else + node2_concentration = 1 + node1_concentration = 0 + + usr << "Node 1: [node1_concentration], Node 2: [node2_concentration]" + + + filter + verb + toggle() + set src in world + set category = "Minor" + + on = !on + + update_icon() + + change_pressure(amount as num) + set src in world + set category = "Minor" + + target_pressure = amount + + unary/oxygen_generator + verb + toggle() + set src in world + set category = "Minor" + + on = !on + + update_icon() + + change_rate(amount as num) + set src in world + set category = "Minor" + + oxygen_content = amount + binary/pump + verb + debug() + set src in world + set category = "Minor" + + world << "Debugging: [x],[y]" + + if(node1) + world << "Input node: [node1.x],[node1.y] [network1]" + if(node2) + world << "Output node: [node2.x],[node2.y] [network2]" + + toggle() + set src in world + set category = "Minor" + + on = !on + + update_icon() + change_pressure(amount as num) + set src in world + set category = "Minor" + + target_pressure = amount + + valve + verb + toggle() + set src in world + set category = "Minor" + + if(open) + close() + else + open() + network_data() + set src in world + set category = "Minor" + + world << "\blue [x],[y]" + world << "network 1: [network_node1.normal_members.len], [network_node1.line_members.len]" + for(var/obj/O in network_node1.normal_members) + world << "member: [O.x], [O.y]" + world << "network 2: [network_node2.normal_members.len], [network_node2.line_members.len]" + for(var/obj/O in network_node2.normal_members) + world << "member: [O.x], [O.y]" + pipe + verb + destroy() + set src in world + set category = "Minor" + + del(src) + + pipeline_data() + set src in world + set category = "Minor" + + if(parent) + usr << "[x],[y] is in a pipeline with [parent.members.len] members ([parent.edges.len] edges)! Volume: [parent.air.volume]" + usr << "Pressure: [parent.air.return_pressure()], Temperature: [parent.air.temperature]" + usr << "[parent.air.oxygen], [parent.air.toxins], [parent.air.nitrogen], [parent.air.carbon_dioxide] .. [parent.alert_pressure]" +mob + verb + flag_all_pipe_networks() + set category = "Debug" + + for(var/datum/pipe_network/network in pipe_networks) + network.update = 1 + + mark_pipe_networks() + set category = "Debug" + + for(var/datum/pipe_network/network in pipe_networks) + network.marker = rand(1,4) + + for(var/obj/machinery/atmospherics/pipe/P in world) + P.overlays = null + + var/datum/pipe_network/master = P.return_network() + if(master) + P.overlays += icon('atmos_testing.dmi',"marker[master.marker]") + else + world << "error" + P.overlays += icon('atmos_testing.dmi',"marker0") + + for(var/obj/machinery/atmospherics/valve/V in world) + V.overlays = null + + if(V.network_node1) + V.overlays += icon('atmos_testing.dmi',"marker[V.network_node1.marker]") + else + V.overlays += icon('atmos_testing.dmi',"marker0") + + if(V.network_node2) + V.overlays += icon('atmos_testing.dmi',"marker[V.network_node2.marker]") + else + V.overlays += icon('atmos_testing.dmi',"marker0") + +turf/simulated + var/fire_verbose = 0 + + verb + mark_direction() + set src in world + overlays = null + for(var/direction in list(NORTH,SOUTH,EAST,WEST)) + if(group_border&direction) + overlays += icon('turf_analysis.dmi',"red_arrow",direction) + else if(air_check_directions&direction) + overlays += icon('turf_analysis.dmi',"arrow",direction) + air_status() + set src in world + set category = "Minor" + var/datum/gas_mixture/GM = return_air() + usr << "\blue @[x],[y] ([GM.group_multiplier]): O:[GM.oxygen] T:[GM.toxins] N:[GM.nitrogen] C:[GM.carbon_dioxide] w [GM.temperature] Kelvin, [GM.return_pressure()] kPa [(active_hotspot)?("\red BURNING"):(null)]" + for(var/datum/gas/trace_gas in GM.trace_gases) + usr << "[trace_gas.type]: [trace_gas.moles]" + + force_temperature(temp as num) + set src in world + set category = "Minor" + if(parent&&parent.group_processing) + parent.suspend_group_processing() + + air.temperature = temp + + spark_temperature(temp as num, volume as num) + set src in world + set category = "Minor" + + hotspot_expose(temp, volume) + + fire_verbose() + set src in world + set category = "Minor" + + fire_verbose = !fire_verbose + usr << "[x],[y] now [fire_verbose]" + + add_sleeping_agent(amount as num) + set src in world + set category = "Minor" + + if(amount>1) + var/datum/gas_mixture/adding = new + var/datum/gas/sleeping_agent/trace_gas = new + + trace_gas.moles = amount + adding.trace_gases += trace_gas + adding.temperature = T20C + + assume_air(adding) + +obj/indicator + icon = 'air_meter.dmi' + var/measure = "temperature" + anchored = 1 + + proc/process() + icon_state = measurement() + + proc/measurement() + var/turf/T = loc + if(!isturf(T)) return + var/datum/gas_mixture/GM = T.return_air() + switch(measure) + if("temperature") + if(GM.temperature < 0) + return "error" + return "[round(GM.temperature/100+0.5)]" + if("oxygen") + if(GM.oxygen < 0) + return "error" + return "[round(GM.oxygen/MOLES_CELLSTANDARD*10+0.5)]" + if("plasma") + if(GM.toxins < 0) + return "error" + return "[round(GM.toxins/MOLES_CELLSTANDARD*10+0.5)]" + if("nitrogen") + if(GM.nitrogen < 0) + return "error" + return "[round(GM.nitrogen/MOLES_CELLSTANDARD*10+0.5)]" + else + return "[round((GM.total_moles())/MOLES_CELLSTANDARD*10+0.5)]" + + + Click() + process() + +obj/window + verb + destroy() + set category = "Minor" + set src in world + del(src) + +mob + sight = SEE_OBJS|SEE_TURFS + + verb + update_indicators() + set category = "Debug" + if(!air_master) + usr << "Cannot find air_system" + return + + for(var/obj/indicator/T in world) + T.process() + change_indicators() + set category = "Debug" + if(!air_master) + usr << "Cannot find air_system" + return + + var/str = input("Select") in list("oxygen", "nitrogen","plasma","all","temperature") + + for(var/obj/indicator/T in world) + T.measure = str + T.process() + + fire_report() + set category = "Debug" + usr << "\b \red Fire Report" + for(var/obj/hotspot/flame in world) + usr << "[flame.x],[flame.y]: [flame.temperature]K, [flame.volume] L - [flame.loc:air:temperature]" + + process_cycle() + set category = "Debug" + if(!master_controller) + usr << "Cannot find master_controller" + return + + master_controller.process() + update_indicators() + + process_cycles(amount as num) + set category = "Debug" + if(!master_controller) + usr << "Cannot find master_controller" + return + + var/start_time = world.timeofday + + for(var/i=1; i<=amount; i++) + master_controller.process() + + world << "Ended [amount] cycles in [(world.timeofday-start_time)/10] seconds. [(world.timeofday-start_time)/10-amount] calculation lag" + + update_indicators() + + process_updates_early() + set category = "Debug" + if(!air_master) + usr << "Cannot find air_system" + return + + air_master.process_update_tiles() + air_master.process_rebuild_select_groups() + + mark_groups() + set category = "Debug" + if(!air_master) + usr << "Cannot find air_system" + return + + for(var/datum/air_group/group in air_master.air_groups) + group.marker = 0 + + for(var/turf/simulated/floor/S in world) + S.icon = 'turf_analysis.dmi' + if(S.parent) + if(S.parent.group_processing) + if(S.parent.marker == 0) + S.parent.marker = rand(1,5) + if(S.parent.borders && S.parent.borders.Find(S)) + S.icon_state = "on[S.parent.marker]_border" + else + S.icon_state = "on[S.parent.marker]" + + else + S.icon_state = "suspended" + else + if(S.processing) + S.icon_state = "individual_on" + else + S.icon_state = "individual_off" + + get_broken_icons() + set category = "Debug" + getbrokeninhands() + +/* + for(var/obj/movable/floor/S in world) + S.icon = 'turf_analysis.dmi' + if(S.parent) + if(S.parent.group_processing) + if(S.parent.marker == 0) + S.parent.marker = rand(1,5) + if(S.parent.borders && S.parent.borders.Find(S)) + S.icon_state = "on[S.parent.marker]_border" + else + S.icon_state = "on[S.parent.marker]" + + else + S.icon_state = "suspended" + else + if(S.processing) + S.icon_state = "individual_on" + else + S.icon_state = "individual_off" +*/ \ No newline at end of file diff --git a/code/FEA/FEA_airgroup.dm b/code/FEA/FEA_airgroup.dm new file mode 100644 index 0000000000000..50f7f571df751 --- /dev/null +++ b/code/FEA/FEA_airgroup.dm @@ -0,0 +1,299 @@ +datum + air_group + var/tmp/group_processing = 1 //Processing all tiles as one large tile if 1 + + var/tmp/datum/gas_mixture/air = new + + var/tmp/current_cycle = 0 //cycle that oxygen value represents + var/tmp/archived_cycle = 0 //cycle that oxygen_archived value represents + //The use of archived cycle saves processing power by permitting the archiving step of FET + // to be rolled into the updating step + + proc + archive() + + members() + //Returns the members of the group + + check_regroup() + //If individually processing tiles, checks all member tiles to see if they are close enough + // that the group may resume group processing + //Warning: Do not call, called by air_master.process() + + process_group() + suspend_group_processing() + update_group_from_tiles() + //Copy group air information to individual tile air + //Used right before turning on group processing + + update_tiles_from_group() + //Copy group air information to individual tile air + //Used right before turning off group processing + + var/list/borders //Tiles that connect this group to other groups/individual tiles + var/list/members //All tiles in this group + + var/list/space_borders + var/length_space_border = 0 + + suspend_group_processing() + update_tiles_from_group() + group_processing = 0 + + update_group_from_tiles() + var/sample_member = pick(members) + var/datum/gas_mixture/sample_air = sample_member:air + + air.copy_from(sample_air) + air.group_multiplier = members.len + + return 1 + + update_tiles_from_group() + for(var/member in members) + member:air.copy_from(air) + + archive() + air.archive() + archived_cycle = air_master.current_cycle + + check_regroup() + //Purpose: Checks to see if group processing should be turned back on + //Returns: group_processing + if(group_processing) return 1 + + + var/turf/simulated/sample = pick(members) + for(var/member in members) + if(member:active_hotspot) + return 0 + if(member:air.compare(sample.air)) continue + else + return 0 + + update_group_from_tiles() + group_processing = 1 + + return 1 + + turf/process_group() + current_cycle = air_master.current_cycle + if(group_processing) //See if processing this group as a group + var/turf/simulated/list/border_individual = list() + var/datum/air_group/list/border_group = list() + + var/turf/simulated/list/enemies = list() //used to send the appropriate border tile of a group to the group proc + var/turf/simulated/list/self_group_borders = list() + var/turf/simulated/list/self_tile_borders = list() + + if(archived_cycle < air_master.current_cycle) + archive() + //Archive air data for use in calculations + //But only if another group didn't store it for us + + for(var/turf/simulated/border_tile in src.borders) + //var/obj/movable/floor/movable_on_me = locate(/obj/movable/floor) in border_tile + for(var/direction in cardinal) //Go through all border tiles and get bordering groups and individuals + if(border_tile.group_border&direction) + var/turf/simulated/enemy_tile = get_step(border_tile, direction) //Add found tile to appropriate category + //var/obj/movable/floor/movable_on_enemy + //if(!movable_on_me) + // movable_on_enemy = locate(/obj/movable/floor) in enemy_tile + /*if(movable_on_enemy) //guaranteed !movable_on_me if this is set + if(movable_on_enemy.parent && movable_on_enemy.parent.group_processing) + border_group += movable_on_enemy.parent + enemies += movable_on_enemy + self_group_borders += border_tile + else + border_individual += movable_on_enemy + self_tile_borders += border_tile + else*/ + if(istype(enemy_tile) && enemy_tile.parent && enemy_tile.parent.group_processing) + border_group += enemy_tile.parent + enemies += enemy_tile + self_group_borders += border_tile + else + border_individual += enemy_tile + self_tile_borders += border_tile + + var/abort_group = 0 + + // Process connections to adjacent groups + var/border_index = 1 + for(var/datum/air_group/AG in border_group) + if(AG.archived_cycle < archived_cycle) //archive other groups information if it has not been archived yet this cycle + AG.archive() + if(AG.current_cycle < current_cycle) + //This if statement makes sure two groups only process their individual connections once! + //Without it, each connection would be processed a second time as the second group is evaluated + + var/connection_difference = 0 + var/turf/simulated/floor/self_border = self_group_borders[border_index] + var/turf/simulated/floor/enemy_border = enemies[border_index] + + var/result = air.check_gas_mixture(AG.air) + if(result == 1) + connection_difference = air.share(AG.air) + else if(result == -1) + AG.suspend_group_processing() + connection_difference = air.share(enemy_border.air) + else + abort_group = 1 + break + + if(connection_difference) + if(connection_difference > 0) + self_border.consider_pressure_difference(connection_difference, get_dir(self_border,enemy_border)) + else + var/turf/enemy_turf = enemy_border + if(!isturf(enemy_turf)) + enemy_turf = enemy_border.loc + enemy_turf.consider_pressure_difference(-connection_difference, get_dir(enemy_turf,self_border)) + + border_index++ + + // Process connections to adjacent tiles + border_index = 1 + if(!abort_group) + for(var/atom/enemy_tile in border_individual) + var/connection_difference = 0 + var/turf/simulated/floor/self_border = self_tile_borders[border_index] + + if(istype(enemy_tile, /turf/simulated)) + if(enemy_tile:archived_cycle < archived_cycle) //archive tile information if not already done + enemy_tile:archive() + if(enemy_tile:current_cycle < current_cycle) + if(air.check_gas_mixture(enemy_tile:air)) + connection_difference = air.share(enemy_tile:air) + else + abort_group = 1 + break + else if(isturf(enemy_tile)) + if(air.check_turf(enemy_tile)) + connection_difference = air.mimic(enemy_tile) + else + abort_group = 1 + break + + if(connection_difference) + if(connection_difference > 0) + self_border.consider_pressure_difference(connection_difference, get_dir(self_border,enemy_tile)) + else + var/turf/enemy_turf = enemy_tile + if(!isturf(enemy_turf)) + enemy_turf = enemy_tile.loc + enemy_turf.consider_pressure_difference(-connection_difference, get_dir(enemy_tile,enemy_turf)) + + // Process connections to space + border_index = 1 + if(!abort_group) + if(length_space_border > 0) + var/turf/space/sample = locate() + var/connection_difference = 0 + + if(air.check_turf(sample)) + connection_difference = air.mimic(sample, length_space_border) + else + abort_group = 1 + + if(connection_difference) + for(var/turf/simulated/self_border in space_borders) + self_border.consider_pressure_difference_space(connection_difference) + + if(abort_group) + suspend_group_processing() + else + if(air.check_tile_graphic()) + for(var/turf/simulated/member in members) + member.update_visuals(air) + + + if(!group_processing) //Revert to individual processing + for(var/turf/simulated/member in members) + member.process_cell() + else + if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST) + for(var/turf/simulated/member in members) + member.hotspot_expose(air.temperature, CELL_VOLUME) + member.consider_superconductivity(starting=1) + + air.react() + + object/process_group() + current_cycle = air_master.current_cycle + + if(group_processing) //See if processing this group as a group + + var/turf/simulated/list/border_individual = list() + var/datum/air_group/list/border_group = list() + + var/turf/simulated/list/enemies = list() //used to send the appropriate border tile of a group to the group proc + var/enemy_index = 1 + + if(archived_cycle < air_master.current_cycle) + archive() + //Archive air data for use in calculations + //But only if another group didn't store it for us +/* + for(var/obj/movable/floor/border_tile in src.borders) + for(var/direction in list(NORTH,SOUTH,EAST,WEST)) //Go through all border tiles and get bordering groups and individuals + if(border_tile.group_border&direction) + var/turf/simulated/enemy_tile = get_step(border_tile, direction) //Add found tile to appropriate category + var/obj/movable/floor/movable_on_enemy = locate(/obj/movable/floor) in enemy_tile + if(movable_on_enemy) + if(movable_on_enemy.parent && movable_on_enemy.parent.group_processing) + border_group += movable_on_enemy.parent + enemies += movable_on_enemy + enemy_index++ + else + border_individual += movable_on_enemy + + else + if(istype(enemy_tile) && enemy_tile.parent && enemy_tile.parent.group_processing) + border_group += enemy_tile.parent + enemies += enemy_tile + enemy_index++ + else + border_individual += enemy_tile +*/ + enemy_index = 1 + var/abort_group = 0 + for(var/datum/air_group/AG in border_group) + if(AG.archived_cycle < archived_cycle) //archive other groups information if it has not been archived yet this cycle + AG.archive() + if(AG.current_cycle < current_cycle) + //This if statement makes sure two groups only process their individual connections once! + //Without it, each connection would be processed a second time as the second group is evaluated + + var/result = air.check_gas_mixture(AG.air) + if(result == 1) + air.share(AG.air) + else if(result == -1) + AG.suspend_group_processing() + var/turf/simulated/floor/enemy_border = enemies[enemy_index] + air.share(enemy_border.air) + else + abort_group = 0 + break + enemy_index++ + + if(!abort_group) + for(var/enemy_tile in border_individual) + if(istype(enemy_tile, /turf/simulated)) + if(enemy_tile:archived_cycle < archived_cycle) //archive tile information if not already done + enemy_tile:archive() + if(enemy_tile:current_cycle < current_cycle) + if(air.check_gas_mixture(enemy_tile:air)) + air.share(enemy_tile:air) + else + abort_group = 1 + break + else + if(air.check_turf(enemy_tile)) + air.mimic(enemy_tile) + else + abort_group = 1 + break + + if(abort_group) + suspend_group_processing() \ No newline at end of file diff --git a/code/FEA/FEA_fire.dm b/code/FEA/FEA_fire.dm new file mode 100644 index 0000000000000..6eec1fc82713a --- /dev/null +++ b/code/FEA/FEA_fire.dm @@ -0,0 +1,146 @@ +atom + proc + temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return null + +turf + proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) + + simulated + hotspot_expose(exposed_temperature, exposed_volume, soh) + var/datum/gas_mixture/air_contents = return_air() + if(!air_contents) + return 0 + if(active_hotspot) + if(soh) + if(air_contents.toxins > 0.5 && air_contents.oxygen > 0.5) + if(active_hotspot.temperature < exposed_temperature) + active_hotspot.temperature = exposed_temperature + if(active_hotspot.volume < exposed_volume) + active_hotspot.volume = exposed_volume + return 1 + + var/igniting = 0 + + if((exposed_temperature > PLASMA_MINIMUM_BURN_TEMPERATURE) && air_contents.toxins > 0.5) + igniting = 1 + + if(igniting) + if(air_contents.oxygen < 0.5 || air_contents.toxins < 0.5) + return 0 + + if(parent&&parent.group_processing) + parent.suspend_group_processing() + + active_hotspot = new(src) + active_hotspot.temperature = exposed_temperature + active_hotspot.volume = exposed_volume + + active_hotspot.just_spawned = (current_cycle < air_master.current_cycle) + //remove just_spawned protection if no longer processing this cell + + return igniting + +obj + hotspot + //Icon for fire on turfs, also helps for nurturing small fires until they are full tile + + anchored = 1 + + mouse_opacity = 0 + + //luminosity = 3 + + icon = 'fire.dmi' + icon_state = "1" + + layer = TURF_LAYER + + var + volume = 125 + temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST + + just_spawned = 1 + + bypassing = 0 + + proc/perform_exposure() + var/turf/simulated/floor/location = loc + if(!istype(location)) + return 0 + + if(volume > CELL_VOLUME*0.95) + bypassing = 1 + else bypassing = 0 + + if(bypassing) + if(!just_spawned) + volume = location.air.fuel_burnt*FIRE_GROWTH_RATE + temperature = location.air.temperature + else + var/datum/gas_mixture/affected = location.air.remove_ratio(volume/location.air.volume) + + affected.temperature = temperature + + affected.react() + + temperature = affected.temperature + volume = affected.fuel_burnt*FIRE_GROWTH_RATE + + location.assume_air(affected) + + for(var/atom/item in loc) + item.temperature_expose(null, temperature, volume) + + proc/process(turf/simulated/list/possible_spread) + if(just_spawned) + just_spawned = 0 + return 0 + + var/turf/simulated/floor/location = loc + if(!istype(location)) + del(src) + + if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1)) + del(src) + + if(location.air.toxins < 0.5 || location.air.oxygen < 0.5) + del(src) + + + perform_exposure() + + if(location.wet) location.wet = 0 + + if(bypassing) + icon_state = "3" + location.burn_tile() + + //Possible spread due to radiated heat + if(location.air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_SPREAD) + var/radiated_temperature = location.air.temperature*FIRE_SPREAD_RADIOSITY_SCALE + + for(var/turf/simulated/possible_target in possible_spread) + if(!possible_target.active_hotspot) + possible_target.hotspot_expose(radiated_temperature, CELL_VOLUME/4) + + else + if(volume > CELL_VOLUME*0.4) + icon_state = "2" + else + icon_state = "1" + + return 1 + + New() + ..() + dir = pick(cardinal) + sd_SetLuminosity(3) + + Del() + loc:active_hotspot = null + src.sd_SetLuminosity(0) + loc = null + + + ..() \ No newline at end of file diff --git a/code/FEA/FEA_gas_mixture.dm b/code/FEA/FEA_gas_mixture.dm new file mode 100644 index 0000000000000..42743840d14c4 --- /dev/null +++ b/code/FEA/FEA_gas_mixture.dm @@ -0,0 +1,950 @@ +/* +What are the archived variables for? + Calculations are done using the archived variables with the results merged into the regular variables. + This prevents race conditions that arise based on the order of tile processing. +*/ + +#define SPECIFIC_HEAT_TOXIN 200 +#define SPECIFIC_HEAT_AIR 20 +#define SPECIFIC_HEAT_CDO 30 +#define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) \ + (carbon_dioxide*SPECIFIC_HEAT_CDO + (oxygen+nitrogen)*SPECIFIC_HEAT_AIR + toxins*SPECIFIC_HEAT_TOXIN) + +#define MINIMUM_HEAT_CAPACITY 0.0003 +#define QUANTIZE(variable) (round(variable,0.0001)) + +datum + gas + sleeping_agent + specific_heat = 40 + + oxygen_agent_b + specific_heat = 300 + + volatile_fuel + specific_heat = 30 + + var + moles = 0 + specific_heat = 0 + + moles_archived = 0 + + gas_mixture + var + oxygen = 0 + carbon_dioxide = 0 + nitrogen = 0 + toxins = 0 + + volume = CELL_VOLUME + + temperature = 0 //in Kelvin, use calculate_temperature() to modify + + var/group_multiplier = 1 + //Size of the group this gas_mixture is representing. + //=1 for singletons + + graphic + + var/list/datum/gas/trace_gases = list() + + tmp + oxygen_archived + carbon_dioxide_archived + nitrogen_archived + toxins_archived + + temperature_archived + + graphic_archived + fuel_burnt = 0 + + proc //PV=nRT - related procedures + heat_capacity() + var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + heat_capacity += trace_gas.moles*trace_gas.specific_heat + + return heat_capacity + + heat_capacity_archived() + var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,toxins_archived) + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + heat_capacity_archived += trace_gas.moles_archived*trace_gas.specific_heat + + return heat_capacity_archived + + total_moles() + var/moles = oxygen + carbon_dioxide + nitrogen + toxins + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + moles += trace_gas.moles + + return moles + + return_pressure() + return total_moles()*R_IDEAL_GAS_EQUATION*temperature/volume + + thermal_energy() + return temperature*heat_capacity() + + proc //Procedures used for very specific events + check_tile_graphic() + //returns 1 if graphic changed + graphic = null + if(toxins > MOLES_PLASMA_VISIBLE) + graphic = "plasma" + else + var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in trace_gases + if(sleeping_agent && (sleeping_agent.moles > 1)) + graphic = "sleeping_agent" + else + graphic = null + + return graphic != graphic_archived + + react(atom/dump_location) + var/reacting = 0 //set to 1 if a notable reaction occured (used by pipe_network) + + if(trace_gases.len > 0) + if(temperature > 900) + if(toxins > MINIMUM_HEAT_CAPACITY && carbon_dioxide > MINIMUM_HEAT_CAPACITY) + var/datum/gas/oxygen_agent_b/trace_gas = locate(/datum/gas/oxygen_agent_b/) in trace_gases + if(trace_gas) + var/reaction_rate = min(carbon_dioxide*0.75, toxins*0.25, trace_gas.moles*0.05) + + carbon_dioxide -= reaction_rate + oxygen += reaction_rate + + trace_gas.moles -= reaction_rate*0.05 + + temperature -= (reaction_rate*20000)/heat_capacity() + + reacting = 1 + + fuel_burnt = 0 + if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST) + //world << "pre [temperature], [oxygen], [toxins]" + if(fire() > 0) + reacting = 1 + //world << "post [temperature], [oxygen], [toxins]" + + return reacting + + fire() + var/energy_released = 0 + var/old_heat_capacity = heat_capacity() + + var/datum/gas/volatile_fuel/fuel_store = locate(/datum/gas/volatile_fuel/) in trace_gases + if(fuel_store) //General volatile gas burn + var/burned_fuel = 0 + + if(oxygen < fuel_store.moles) + burned_fuel = oxygen + fuel_store.moles -= burned_fuel + oxygen = 0 + else + burned_fuel = fuel_store.moles + oxygen -= fuel_store.moles + del(fuel_store) + + energy_released += FIRE_CARBON_ENERGY_RELEASED * burned_fuel + carbon_dioxide += burned_fuel + fuel_burnt += burned_fuel + + //Handle plasma burning + if(toxins > MINIMUM_HEAT_CAPACITY) + var/plasma_burn_rate = 0 + var/oxygen_burn_rate = 0 + //more plasma released at higher temperatures + var/temperature_scale + if(temperature > PLASMA_UPPER_TEMPERATURE) + temperature_scale = 1 + else + temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE) + if(temperature_scale > 0) + oxygen_burn_rate = 1.4 - temperature_scale + if(oxygen > toxins*PLASMA_OXYGEN_FULLBURN) + plasma_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 + + energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate) + + fuel_burnt += (plasma_burn_rate)*(1+oxygen_burn_rate) + + if(energy_released > 0) + var/new_heat_capacity = heat_capacity() + if(new_heat_capacity > MINIMUM_HEAT_CAPACITY) + temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity + + return fuel_burnt + + proc + archive() + //Update archived versions of variables + //Returns: 1 in all cases + + merge(datum/gas_mixture/giver) + //Merges all air from giver into self. Deletes giver. + //Returns: 1 on success (no failure cases yet) + + check_then_merge(datum/gas_mixture/giver) + //Similar to merge(...) but first checks to see if the amount of air assumed is small enough + // that group processing is still accurate for source (aborts if not) + //Returns: 1 on successful merge, 0 if the check failed + + remove(amount) + //Proportionally removes amount of gas from the gas_mixture + //Returns: gas_mixture with the gases removed + + remove_ratio(ratio) + //Proportionally removes amount of gas from the gas_mixture + //Returns: gas_mixture with the gases removed + + subtract(datum/gas_mixture/right_side) + //Subtracts right_side from air_mixture. Used to help turfs mingle + + check_then_remove(amount) + //Similar to remove(...) but first checks to see if the amount of air removed is small enough + // that group processing is still accurate for source (aborts if not) + //Returns: gas_mixture with the gases removed or null + + copy_from(datum/gas_mixture/sample) + //Copies variables from sample + + share(datum/gas_mixture/sharer) + //Performs air sharing calculations between two gas_mixtures assuming only 1 boundary length + //Return: amount of gas exchanged (+ if sharer received) + + mimic(turf/model) + //Similar to share(...), except the model is not modified + //Return: amount of gas exchanged + + check_gas_mixture(datum/gas_mixture/sharer) + //Returns: 0 if the self-check failed then -1 if sharer-check failed then 1 if both checks pass + + check_turf(turf/model) + //Returns: 0 if self-check failed or 1 if check passes + + // check_me_then_share(datum/gas_mixture/sharer) + //Similar to share(...) but first checks to see if amount of air moved is small enough + // that group processing is still accurate for source (aborts if not) + //Returns: 1 on successful share, 0 if the check failed + + // check_me_then_mimic(turf/model) + //Similar to mimic(...) but first checks to see if amount of air moved is small enough + // that group processing is still accurate (aborts if not) + //Returns: 1 on successful mimic, 0 if the check failed + + // check_both_then_share(datum/gas_mixture/sharer) + //Similar to check_me_then_share(...) but also checks to see if amount of air moved is small enough + // that group processing is still accurate for the sharer (aborts if not) + //Returns: 0 if the self-check failed then -1 if sharer-check failed then 1 if successful share + + + temperature_mimic(turf/model, conduction_coefficient) + + temperature_share(datum/gas_mixture/sharer, conduction_coefficient) + + temperature_turf_share(turf/simulated/sharer, conduction_coefficient) + + + check_me_then_temperature_mimic(turf/model, conduction_coefficient) + + check_me_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient) + + check_both_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient) + + check_me_then_temperature_turf_share(turf/simulated/sharer, conduction_coefficient) + + compare(datum/gas_mixture/sample) + //Compares sample to self to see if within acceptable ranges that group processing may be enabled + + archive() + oxygen_archived = oxygen + carbon_dioxide_archived = carbon_dioxide + nitrogen_archived = nitrogen + toxins_archived = toxins + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + trace_gas.moles_archived = trace_gas.moles + + temperature_archived = temperature + + graphic_archived = graphic + + return 1 + + check_then_merge(datum/gas_mixture/giver) + if(!giver) + return 0 + 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))) + return 0 + if(abs(giver.temperature - temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) + return 0 + + if(giver.trace_gases.len) + for(var/datum/gas/trace_gas in giver.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if((trace_gas.moles > MINIMUM_AIR_TO_SUSPEND) && (!corresponding || (trace_gas.moles >= corresponding.moles*MINIMUM_AIR_RATIO_TO_SUSPEND))) + return 0 + + return merge(giver) + + merge(datum/gas_mixture/giver) + if(!giver) + return 0 + + if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity()*group_multiplier + var/giver_heat_capacity = giver.heat_capacity()*giver.group_multiplier + var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity + if(combined_heat_capacity != 0) + temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity + + if((group_multiplier>1)||(giver.group_multiplier>1)) + 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 + else + oxygen += giver.oxygen + carbon_dioxide += giver.carbon_dioxide + nitrogen += giver.nitrogen + toxins += giver.toxins + + if(giver.trace_gases.len) + for(var/datum/gas/trace_gas in giver.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(!corresponding) + corresponding = new trace_gas.type() + trace_gases += corresponding + corresponding.moles += trace_gas.moles*giver.group_multiplier/group_multiplier + + del(giver) + return 1 + + remove(amount) + + var/sum = total_moles() + amount = min(amount,sum) //Can not take more air than tile has! + if(amount <= 0) + return null + + var/datum/gas_mixture/removed = new + + + 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) + + oxygen -= removed.oxygen/group_multiplier + nitrogen -= removed.nitrogen/group_multiplier + carbon_dioxide -= removed.carbon_dioxide/group_multiplier + toxins -= removed.toxins/group_multiplier + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + var/datum/gas/corresponding = new trace_gas.type() + removed.trace_gases += corresponding + + corresponding.moles = (trace_gas.moles/sum)*amount + trace_gas.moles -= corresponding.moles/group_multiplier + + removed.temperature = temperature + + return removed + + remove_ratio(ratio) + + if(ratio <= 0) + return null + + ratio = min(ratio, 1) + + var/datum/gas_mixture/removed = new + + removed.oxygen = QUANTIZE(oxygen*ratio) + removed.nitrogen = QUANTIZE(nitrogen*ratio) + removed.carbon_dioxide = QUANTIZE(carbon_dioxide*ratio) + removed.toxins = QUANTIZE(toxins*ratio) + + oxygen -= removed.oxygen/group_multiplier + nitrogen -= removed.nitrogen/group_multiplier + carbon_dioxide -= removed.carbon_dioxide/group_multiplier + toxins -= removed.toxins/group_multiplier + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + var/datum/gas/corresponding = new trace_gas.type() + removed.trace_gases += corresponding + + corresponding.moles = trace_gas.moles*ratio + trace_gas.moles -= corresponding.moles/group_multiplier + + removed.temperature = temperature + + return removed + + check_then_remove(amount) + + //Since it is all proportional, the check may be done on the gas as a whole + var/sum = total_moles() + amount = min(amount,sum) //Can not take more air than tile has! + + if((amount > MINIMUM_AIR_RATIO_TO_SUSPEND) && (amount > sum*MINIMUM_AIR_RATIO_TO_SUSPEND)) + return 0 + + return remove(amount) + + copy_from(datum/gas_mixture/sample) + oxygen = sample.oxygen + carbon_dioxide = sample.carbon_dioxide + nitrogen = sample.nitrogen + toxins = sample.toxins + + trace_gases.len=null + if(sample.trace_gases.len > 0) + for(var/datum/gas/trace_gas in sample.trace_gases) + var/datum/gas/corresponding = new trace_gas.type() + trace_gases += corresponding + + corresponding.moles = trace_gas.moles + + temperature = sample.temperature + + return 1 + + subtract(datum/gas_mixture/right_side) + oxygen -= right_side.oxygen + carbon_dioxide -= right_side.carbon_dioxide + nitrogen -= right_side.nitrogen + toxins -= right_side.toxins + + if((trace_gases.len > 0)||(right_side.trace_gases.len > 0)) + for(var/datum/gas/trace_gas in right_side.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(!corresponding) + corresponding = new trace_gas.type() + trace_gases += corresponding + + corresponding.moles -= trace_gas.moles + + return 1 + + /* check_me_then_share(datum/gas_mixture/sharer) + var/delta_oxygen = (oxygen_archived - sharer.oxygen_archived)/5 + var/delta_carbon_dioxide = (carbon_dioxide_archived - sharer.carbon_dioxide_archived)/5 + var/delta_nitrogen = (nitrogen_archived - sharer.nitrogen_archived)/5 + var/delta_toxins = (toxins_archived - sharer.toxins_archived)/5 + + 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))) + return 0 + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) + return 0 + + return share(sharer)*/ + + check_gas_mixture(datum/gas_mixture/sharer) + var/delta_oxygen = (oxygen_archived - sharer.oxygen_archived)/5 + var/delta_carbon_dioxide = (carbon_dioxide_archived - sharer.carbon_dioxide_archived)/5 + var/delta_nitrogen = (nitrogen_archived - sharer.nitrogen_archived)/5 + var/delta_toxins = (toxins_archived - sharer.toxins_archived)/5 + + 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))) + return 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) + return 0 + + if(sharer.trace_gases.len) + for(var/datum/gas/trace_gas in sharer.trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(corresponding) + if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4) + return 0 + else + return 0 + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) + if(!locate(trace_gas.type) in sharer.trace_gases) + return 0 + + 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))) + return -1 + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) + var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases + if(corresponding) + if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4) + return -1 + else + return -1 + + return 1 + + check_turf(turf/model) + var/delta_oxygen = (oxygen_archived - model.oxygen)/5 + var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide)/5 + var/delta_nitrogen = (nitrogen_archived - model.nitrogen)/5 + var/delta_toxins = (toxins_archived - model.toxins)/5 + + 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))) + return 0 + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) + return 0 + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) + return 0 + + return 1 + + share(datum/gas_mixture/sharer) + var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/5 + var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/5 + var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/5 + var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/5 + + var/delta_temperature = (temperature_archived - sharer.temperature_archived) + + var/old_self_heat_capacity = 0 + var/old_sharer_heat_capacity = 0 + + var/heat_self_to_sharer = 0 + var/heat_capacity_self_to_sharer = 0 + var/heat_sharer_to_self = 0 + var/heat_capacity_sharer_to_self = 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + + var/delta_air = delta_oxygen+delta_nitrogen + if(delta_air) + var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air + if(delta_air > 0) + heat_self_to_sharer += air_heat_capacity*temperature_archived + heat_capacity_self_to_sharer += air_heat_capacity + else + heat_sharer_to_self -= air_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self -= air_heat_capacity + + if(delta_carbon_dioxide) + var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide + if(delta_carbon_dioxide > 0) + heat_self_to_sharer += carbon_dioxide_heat_capacity*temperature_archived + heat_capacity_self_to_sharer += carbon_dioxide_heat_capacity + else + 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 + else + heat_sharer_to_self -= toxins_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self -= toxins_heat_capacity + + old_self_heat_capacity = heat_capacity()*group_multiplier + old_sharer_heat_capacity = sharer.heat_capacity()*sharer.group_multiplier + + oxygen -= delta_oxygen/group_multiplier + sharer.oxygen += delta_oxygen/sharer.group_multiplier + + carbon_dioxide -= delta_carbon_dioxide/group_multiplier + sharer.carbon_dioxide += delta_carbon_dioxide/sharer.group_multiplier + + nitrogen -= delta_nitrogen/group_multiplier + sharer.nitrogen += delta_nitrogen/sharer.group_multiplier + + toxins -= delta_toxins/group_multiplier + sharer.toxins += delta_toxins/sharer.group_multiplier + + var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins) + + var/list/trace_types_considered = list() + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + + var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases + var/delta = 0 + + if(corresponding) + delta = QUANTIZE(trace_gas.moles_archived - corresponding.moles_archived)/5 + else + corresponding = new trace_gas.type() + sharer.trace_gases += corresponding + + delta = trace_gas.moles_archived/5 + + trace_gas.moles -= delta/group_multiplier + corresponding.moles += delta/sharer.group_multiplier + + if(delta) + var/individual_heat_capacity = trace_gas.specific_heat*delta + if(delta > 0) + heat_self_to_sharer += individual_heat_capacity*temperature_archived + heat_capacity_self_to_sharer += individual_heat_capacity + else + heat_sharer_to_self -= individual_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self -= individual_heat_capacity + + moved_moles += delta + + trace_types_considered += trace_gas.type + + + if(sharer.trace_gases.len) + for(var/datum/gas/trace_gas in sharer.trace_gases) + if(trace_gas.type in trace_types_considered) continue + else + var/datum/gas/corresponding + var/delta = 0 + + corresponding = new trace_gas.type() + trace_gases += corresponding + + delta = trace_gas.moles_archived/5 + + trace_gas.moles -= delta/sharer.group_multiplier + corresponding.moles += delta/group_multiplier + + //Guaranteed transfer from sharer to self + var/individual_heat_capacity = trace_gas.specific_heat*delta + heat_sharer_to_self += individual_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self += individual_heat_capacity + + moved_moles += -delta + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/new_self_heat_capacity = old_self_heat_capacity + heat_capacity_sharer_to_self - heat_capacity_self_to_sharer + var/new_sharer_heat_capacity = old_sharer_heat_capacity + heat_capacity_self_to_sharer - heat_capacity_sharer_to_self + + if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY) + temperature = (old_self_heat_capacity*temperature - heat_capacity_self_to_sharer*temperature_archived + heat_capacity_sharer_to_self*sharer.temperature_archived)/new_self_heat_capacity + + if(new_sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) + sharer.temperature = (old_sharer_heat_capacity*sharer.temperature-heat_capacity_sharer_to_self*sharer.temperature_archived + heat_capacity_self_to_sharer*temperature_archived)/new_sharer_heat_capacity + + if(abs(old_sharer_heat_capacity) > MINIMUM_HEAT_CAPACITY) + if(abs(new_sharer_heat_capacity/old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity + temperature_share(sharer, OPEN_HEAT_TRANSFER_COEFFICIENT) + + if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE) + var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - sharer.temperature_archived*(sharer.total_moles() - moved_moles) + return delta_pressure*R_IDEAL_GAS_EQUATION/volume + + else + return 0 + + mimic(turf/model, border_multiplier) + var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen)/5 + var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide)/5 + var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen)/5 + var/delta_toxins = QUANTIZE(toxins_archived - model.toxins)/5 + + var/delta_temperature = (temperature_archived - model.temperature) + + var/heat_transferred = 0 + var/old_self_heat_capacity = 0 + var/heat_capacity_transferred = 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + + var/delta_air = delta_oxygen+delta_nitrogen + if(delta_air) + var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air + heat_transferred -= air_heat_capacity*model.temperature + heat_capacity_transferred -= air_heat_capacity + + if(delta_carbon_dioxide) + var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide + 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 + + old_self_heat_capacity = heat_capacity()*group_multiplier + + if(border_multiplier) + 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 + else + oxygen -= delta_oxygen/group_multiplier + carbon_dioxide -= delta_carbon_dioxide/group_multiplier + nitrogen -= delta_nitrogen/group_multiplier + toxins -= delta_toxins/group_multiplier + + var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins) + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + var/delta = 0 + + delta = trace_gas.moles_archived/5 + + if(border_multiplier) + trace_gas.moles -= delta*border_multiplier/group_multiplier + else + trace_gas.moles -= delta/group_multiplier + + var/heat_cap_transferred = delta*trace_gas.specific_heat + heat_transferred += heat_cap_transferred*temperature_archived + heat_capacity_transferred += heat_cap_transferred + moved_moles += delta + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/new_self_heat_capacity = old_self_heat_capacity - heat_capacity_transferred + if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY) + if(border_multiplier) + temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity + else + temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity + + 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) + return delta_pressure*R_IDEAL_GAS_EQUATION/volume + else + return 0 + + check_both_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature_archived) + + var/self_heat_capacity = heat_capacity_archived() + var/sharer_heat_capacity = sharer.heat_capacity_archived() + + var/self_temperature_delta = 0 + var/sharer_temperature_delta = 0 + + if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity)) + + self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) + sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier) + else + return 1 + + if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) + return 0 + + if((abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*sharer.temperature_archived)) + return -1 + + temperature += self_temperature_delta + sharer.temperature += sharer_temperature_delta + + return 1 + //Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency + + check_me_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature_archived) + + var/self_heat_capacity = heat_capacity_archived() + var/sharer_heat_capacity = sharer.heat_capacity_archived() + + var/self_temperature_delta = 0 + var/sharer_temperature_delta = 0 + + if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity)) + + self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) + sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier) + else + return 1 + + if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) + return 0 + + temperature += self_temperature_delta + sharer.temperature += sharer_temperature_delta + + return 1 + //Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency + + check_me_then_temperature_turf_share(turf/simulated/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature) + + var/self_temperature_delta = 0 + var/sharer_temperature_delta = 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity_archived() + + if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity)) + + self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) + sharer_temperature_delta = heat/sharer.heat_capacity + else + return 1 + + if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) + return 0 + + temperature += self_temperature_delta + sharer.temperature += sharer_temperature_delta + + return 1 + //Logic integrated from: temperature_turf_share(sharer, conduction_coefficient) for efficiency + + check_me_then_temperature_mimic(turf/model, conduction_coefficient) + var/delta_temperature = (temperature_archived - model.temperature) + var/self_temperature_delta = 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity_archived() + + if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity)) + + self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) + + if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) + return 0 + + temperature += self_temperature_delta + + return 1 + //Logic integrated from: temperature_mimic(model, conduction_coefficient) for efficiency + + temperature_share(datum/gas_mixture/sharer, conduction_coefficient) + + var/delta_temperature = (temperature_archived - sharer.temperature_archived) + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity_archived() + var/sharer_heat_capacity = sharer.heat_capacity_archived() + + if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity)) + + temperature -= heat/(self_heat_capacity*group_multiplier) + sharer.temperature += heat/(sharer_heat_capacity*sharer.group_multiplier) + + temperature_mimic(turf/model, conduction_coefficient, border_multiplier) + var/delta_temperature = (temperature - model.temperature) + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity()//_archived() + + if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity)) + + if(border_multiplier) + temperature -= heat*border_multiplier/(self_heat_capacity*group_multiplier) + else + temperature -= heat/(self_heat_capacity*group_multiplier) + + temperature_turf_share(turf/simulated/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature) + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity() + + if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity)) + + temperature -= heat/(self_heat_capacity*group_multiplier) + sharer.temperature += heat/sharer.heat_capacity + + compare(datum/gas_mixture/sample) + if((abs(oxygen-sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \ + ((oxygen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen))) + return 0 + if((abs(nitrogen-sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \ + ((nitrogen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen) || (nitrogen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen))) + return 0 + if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \ + ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (oxygen > (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))) + return 0 + + if(total_moles() > MINIMUM_AIR_TO_SUSPEND) + if((abs(temperature-sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \ + ((temperature < (1-MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || (temperature > (1+MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature))) + //world << "temp fail [temperature] & [sample.temperature]" + return 0 + + if(sample.trace_gases.len) + for(var/datum/gas/trace_gas in sample.trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(corresponding) + if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \ + ((corresponding.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles) || (corresponding.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles))) + return 0 + else + return 0 + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND) + var/datum/gas/corresponding = locate(trace_gas.type) in sample.trace_gases + if(corresponding) + if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \ + ((trace_gas.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles) || (trace_gas.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles))) + return 0 + else + return 0 + return 1 \ No newline at end of file diff --git a/code/FEA/FEA_group_helpers.dm b/code/FEA/FEA_group_helpers.dm new file mode 100644 index 0000000000000..3a4835e0c6bf8 --- /dev/null +++ b/code/FEA/FEA_group_helpers.dm @@ -0,0 +1,114 @@ +/turf/simulated/proc/find_group() + //Basically, join any nearby valid groups + // If more than one, pick one with most members at my borders + // If can not find any but there was an ungrouped at border with me, call for group assembly + + var/turf/simulated/floor/north = get_step(src,NORTH) + var/turf/simulated/floor/south = get_step(src,SOUTH) + var/turf/simulated/floor/east = get_step(src,EAST) + var/turf/simulated/floor/west = get_step(src,WEST) + + //Clear those we do not have access to + if(!CanPass(null, north, null, 1) || !istype(north)) + north = null + if(!CanPass(null, south, null, 1) || !istype(south)) + south = null + if(!CanPass(null, east, null, 1) || !istype(east)) + east = null + if(!CanPass(null, west, null, 1) || !istype(west)) + west = null + + var/new_group_possible = 0 + + var/north_votes = 0 + var/south_votes = 0 + var/east_votes = 0 + + if(north) + if(north.parent) + north_votes = 1 + + if(south && (south.parent == north.parent)) + north_votes++ + south = null + + if(east && (east.parent == north.parent)) + north_votes++ + east = null + + if(west && (west.parent == north.parent)) + north_votes++ + west = null + else + new_group_possible = 1 + + if(south) + if(south.parent) + south_votes = 1 + + if(east && (east.parent == south.parent)) + south_votes++ + east = null + + if(west && (west.parent == south.parent)) + south_votes++ + west = null + else + new_group_possible = 1 + + if(east) + if(east.parent) + east_votes = 1 + + if(west && (west.parent == east.parent)) + east_votes++ + west = null + else + new_group_possible = 1 + +// world << "[north_votes], [south_votes], [east_votes]" + + if(west) + if(west.parent) + west.parent.suspend_group_processing() + west.parent.members += src + parent = west.parent + + air_master.tiles_to_update += west.parent.members + return 1 + + else + new_group_possible = 1 + + if(north_votes && (north_votes >= south_votes) && (north_votes >= east_votes)) + north.parent.suspend_group_processing() + north.parent.members += src + parent = north.parent + + air_master.tiles_to_update += north.parent.members + return 1 + + + if(south_votes && (south_votes >= east_votes)) + south.parent.suspend_group_processing() + south.parent.members += src + parent = south.parent + + air_master.tiles_to_update += south.parent.members + return 1 + + if(east_votes) + east.parent.suspend_group_processing() + east.parent.members += src + parent = east.parent + + air_master.tiles_to_update += east.parent.members + return 1 + + if(new_group_possible) + air_master.assemble_group_turf(src) + return 1 + + else + air_master.active_singletons += src + return 1 \ No newline at end of file diff --git a/code/FEA/FEA_system.dm b/code/FEA/FEA_system.dm new file mode 100644 index 0000000000000..87c409ec305a5 --- /dev/null +++ b/code/FEA/FEA_system.dm @@ -0,0 +1,343 @@ +/* +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/kill_air = 0 + +atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) + 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 + for(var/obj/obstacle in target) + if(!obstacle.CanPass(mover, src, height, air_group)) + return 0 + + return 1 + + +var/global/datum/controller/air_system/air_master + +datum + controller + air_system + //Geoemetry lists + var/list/datum/air_group/air_groups = list() + var/list/turf/simulated/active_singletons = list() + + //Special functions lists + var/list/turf/simulated/active_super_conductivity = list() + var/list/turf/simulated/high_pressure_delta = list() + + //Geometry updates lists + var/list/turf/simulated/tiles_to_update = list() + var/list/turf/simulated/groups_to_rebuild = list() + + var/current_cycle = 0 + + proc + setup() + //Call this at the start to setup air groups geometry + //Warning: Very processor intensive but only must be done once per round + + assemble_group_turf(turf/simulated/base) + //Call this to try to construct a group starting from base and merging with neighboring unparented tiles + //Expands the group until all valid borders explored + +// assemble_group_object(obj/movable/floor/base) + + process() + //Call this to process air movements for a cycle + + process_groups() + //Used by process() + //Warning: Do not call this + + process_singletons() + //Used by process() + //Warning: Do not call this + + process_high_pressure_delta() + //Used by process() + //Warning: Do not call this + + process_super_conductivity() + //Used by process() + //Warning: Do not call this + + process_update_tiles() + //Used by process() + //Warning: Do not call this + + process_rebuild_select_groups() + //Used by process() + //Warning: Do not call this + + rebuild_group(datum/air_group) + //Used by process_rebuild_select_groups() + //Warning: Do not call this, add the group to air_master.groups_to_rebuild instead + + add_singleton(turf/simulated/T) + if(!active_singletons.Find(T)) + active_singletons += T + + setup() + + world << "\red \b Processing Geometry..." + sleep(1) + + var/start_time = world.timeofday + + for(var/turf/simulated/S in world) + if(!S.blocks_air && !S.parent && S.z < 5) // Added last check to force skipping asteroid z-levels -- TLE + assemble_group_turf(S) + for(var/turf/simulated/S in world) //Update all pathing and border information as well + if(S.z > 4) // Skipping asteroids -- TLE + continue + S.update_air_properties() +/* + for(var/obj/movable/floor/S in world) + if(!S.parent) + assemble_group_object(S) + for(var/obj/movable/floor/S in world) //Update all pathing and border information as well + S.update_air_properties() +*/ + world << "\red \b Geometry processed in [(world.timeofday-start_time)/10] seconds!" + + assemble_group_turf(turf/simulated/base) + + var/list/turf/simulated/members = list(base) //Confirmed group members + var/list/turf/simulated/possible_members = list(base) //Possible places for group expansion + var/list/turf/simulated/possible_borders = list() + var/list/turf/simulated/possible_space_borders = list() + var/possible_space_length = 0 + + while(possible_members.len>0) //Keep expanding, looking for new members + for(var/turf/simulated/test in possible_members) + test.length_space_border = 0 + for(var/direction in cardinal) + var/turf/T = get_step(test,direction) + if(T && !members.Find(T) && test.CanPass(null, T, null,1)) + if(istype(T,/turf/simulated) && !T:parent) + possible_members += T + members += T + else if(istype(T,/turf/space)) + possible_space_borders -= test + possible_space_borders += test + test.length_space_border++ + else + possible_borders -= test + possible_borders += test + if(test.length_space_border > 0) + possible_space_length += test.length_space_border + possible_members -= test + + if(members.len > 1) + var/datum/air_group/turf/group = new + if(possible_borders.len>0) + group.borders = possible_borders + if(possible_space_borders.len>0) + group.space_borders = possible_space_borders + group.length_space_border = possible_space_length + + for(var/turf/simulated/test in members) + test.parent = group + test.processing = 0 + active_singletons -= test + + group.members = members + air_groups += group + + group.update_group_from_tiles() //Initialize air group variables + return group + else + base.processing = 0 //singletons at startup are technically unconnected anyway + base.parent = null + + if(base.air.check_tile_graphic()) + base.update_visuals(base.air) + + return null +/* + assemble_group_object(obj/movable/floor/base) + + var/list/obj/movable/floor/members = list(base) //Confirmed group members + var/list/obj/movable/floor/possible_members = list(base) //Possible places for group expansion + var/list/obj/movable/floor/possible_borders = list() + + while(possible_members.len>0) //Keep expanding, looking for new members + for(var/obj/movable/floor/test in possible_members) + for(var/direction in list(NORTH, SOUTH, EAST, WEST)) + var/turf/T = get_step(test.loc,direction) + if(T && test.loc.CanPass(null, T, null, 1)) + var/obj/movable/floor/O = locate(/obj/movable/floor) in T + if(istype(O) && !O.parent) + if(!members.Find(O)) + possible_members += O + members += O + else + possible_borders -= test + possible_borders += test + possible_members -= test + + if(members.len > 1) + var/datum/air_group/object/group = new + if(possible_borders.len>0) + group.borders = possible_borders + + for(var/obj/movable/floor/test in members) + test.parent = group + test.processing = 0 + active_singletons -= test + + group.members = members + air_groups += group + + group.update_group_from_tiles() //Initialize air group variables + return group + else + base.processing = 0 //singletons at startup are technically unconnected anyway + base.parent = null + + return null +*/ + process() + if(kill_air) + return 1 + current_cycle++ + if(groups_to_rebuild.len > 0) process_rebuild_select_groups() + if(tiles_to_update.len > 0) process_update_tiles() + + process_groups() + process_singletons() + + process_super_conductivity() + process_high_pressure_delta() + + if(current_cycle%10==5) //Check for groups of tiles to resume group processing every 10 cycles + for(var/datum/air_group/AG in air_groups) + AG.check_regroup() + + return 1 + + process_update_tiles() + for(var/turf/simulated/T in tiles_to_update) + T.update_air_properties() +/* + for(var/obj/movable/floor/O in tiles_to_update) + O.update_air_properties() +*/ + tiles_to_update.len = 0 + + process_rebuild_select_groups() + var/turf/list/turfs = list() + + for(var/datum/air_group/turf/turf_AG in groups_to_rebuild) //Deconstruct groups, gathering their old members + for(var/turf/simulated/T in turf_AG.members) + T.parent = null + turfs += T + del(turf_AG) + + for(var/turf/simulated/S in turfs) //Have old members try to form new groups + if(!S.parent) + assemble_group_turf(S) + for(var/turf/simulated/S in turfs) + S.update_air_properties() + +// var/obj/movable/list/movable_objects = list() + + for(var/datum/air_group/object/object_AG in groups_to_rebuild) //Deconstruct groups, gathering their old members +/* + for(var/obj/movable/floor/OM in object_AG.members) + OM.parent = null + movable_objects += OM + del(object_AG) + + for(var/obj/movable/floor/OM in movable_objects) //Have old members try to form new groups + if(!OM.parent) + assemble_group_object(OM) + for(var/obj/movable/floor/OM in movable_objects) + OM.update_air_properties() +*/ + groups_to_rebuild.len = 0 + + process_groups() + for(var/datum/air_group/AG in air_groups) + AG.process_group() + + process_singletons() + for(var/item in active_singletons) + item:process_cell() + + process_super_conductivity() + for(var/turf/simulated/hot_potato in active_super_conductivity) + hot_potato.super_conduct() + + process_high_pressure_delta() + for(var/turf/pressurized in high_pressure_delta) + pressurized.high_pressure_movements() + + high_pressure_delta.len = 0 diff --git a/code/FEA/FEA_turf_tile.dm b/code/FEA/FEA_turf_tile.dm new file mode 100644 index 0000000000000..7fcf1bc211398 --- /dev/null +++ b/code/FEA/FEA_turf_tile.dm @@ -0,0 +1,539 @@ +atom/movable/var/pressure_resistance = 20 +atom/movable/var/last_forced_movement = 0 + +atom/movable/proc/experience_pressure_difference(pressure_difference, direction) + if(last_forced_movement >= air_master.current_cycle) + return 0 + else if(!anchored) + if(pressure_difference > pressure_resistance) + last_forced_movement = air_master.current_cycle + spawn step(src, direction) + return 1 + +turf + assume_air(datum/gas_mixture/giver) //use this for machines to adjust air + //First, ensure there is no movable shuttle or what not on tile that is taking over +// var/obj/movable/floor/movable_on_me = locate(/obj/movable/floor) in src +// if(istype(movable_on_me)) +// return movable_on_me.assume_air(giver) + + del(giver) + return 0 + + return_air() + //First, ensure there is no movable shuttle or what not on tile that is taking over +// var/obj/movable/floor/movable_on_me = locate(/obj/movable/floor) in src +// if(istype(movable_on_me)) +// return movable_on_me.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 + + return GM + + remove_air(amount as num) + //First, ensure there is no movable shuttle or what not on tile that is taking over +// var/obj/movable/floor/movable_on_me = locate(/obj/movable/floor) in src +// if(istype(movable_on_me)) +// return movable_on_me.remove_air(amount) + + 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 + + return GM + +turf + var/pressure_difference = 0 + var/pressure_direction = 0 + + proc + high_pressure_movements() + + for(var/atom/movable/in_tile in src) + in_tile.experience_pressure_difference(pressure_difference, pressure_direction) + + pressure_difference = 0 + + consider_pressure_difference(connection_difference, connection_direction) + if(connection_difference < 0) + connection_difference = -connection_difference + connection_direction = turn(connection_direction,180) + + if(connection_difference > pressure_difference) + if(!pressure_difference) + air_master.high_pressure_delta += src + pressure_difference = connection_difference + pressure_direction = connection_direction + + simulated + proc + consider_pressure_difference_space(connection_difference) + for(var/direction in cardinal) + if(direction&group_border) + if(istype(get_step(src,direction),/turf/space)) + if(!pressure_difference) + air_master.high_pressure_delta += src + pressure_direction = direction + pressure_difference = connection_difference + return 1 + +turf + simulated + + var/current_graphic = null + + var/tmp + datum/gas_mixture/air + + processing = 1 + datum/air_group/turf/parent + group_border = 0 + length_space_border = 0 + + air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update + + archived_cycle = 0 + current_cycle = 0 + + obj/hotspot/active_hotspot + + temperature_archived //USED ONLY FOR SOLIDS + being_superconductive = 0 + + + proc + process_cell() + update_air_properties() + archive() + + mimic_air_with_tile(turf/model) + share_air_with_tile(turf/simulated/sharer) + + mimic_temperature_with_tile(turf/model) + share_temperature_with_tile(turf/simulated/sharer) + + super_conduct() + + update_visuals(datum/gas_mixture/model) + overlays = null + + switch(model.graphic) + if("plasma") + overlays.Add(plmaster) + if("sleeping_agent") + overlays.Add(slmaster) + else + overlays = null + + New() + ..() + + if(!blocks_air) + air = new + + air.oxygen = oxygen + air.carbon_dioxide = carbon_dioxide + air.nitrogen = nitrogen + air.toxins = toxins + + air.temperature = temperature + + if(air_master) + air_master.tiles_to_update.Add(src) + + find_group() + +// air.parent = src //TODO DEBUG REMOVE + + 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.Add(target) + + Del() + if(air_master) + if(parent) + air_master.groups_to_rebuild.Add(parent) + parent.members.Remove(src) + else + air_master.active_singletons.Remove(src) + 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) + ..() + + assume_air(datum/gas_mixture/giver) + if(air) + if(parent&&parent.group_processing) + if(!parent.air.check_then_merge(giver)) + parent.suspend_group_processing() + air.merge(giver) + else + air.merge(giver) + + if(!processing) + if(air.check_tile_graphic()) + update_visuals(air) + + return 1 + + else return ..() + + archive() + if(air) //For open space like floors + air.archive() + + temperature_archived = temperature + archived_cycle = air_master.current_cycle + + share_air_with_tile(turf/simulated/T) + return air.share(T.air) + + mimic_air_with_tile(turf/T) + return air.mimic(T) + + return_air() + if(air) + if(parent&&parent.group_processing) + return parent.air + else return air + + else + return ..() + + remove_air(amount as num) + if(air) + var/datum/gas_mixture/removed = null + + if(parent&&parent.group_processing) + removed = parent.air.check_then_remove(amount) + if(!removed) + parent.suspend_group_processing() + removed = air.remove(amount) + else + removed = air.remove(amount) + + if(!processing) + if(air.check_tile_graphic()) + update_visuals(air) + + return removed + + else + return ..() + + update_air_properties()//OPTIMIZE + air_check_directions = 0 + + for(var/direction in cardinal) + if(CanPass(null, get_step(src,direction), 0, 0)) + air_check_directions |= direction + + if(parent) + if(parent.borders) + parent.borders -= src + if(length_space_border > 0) + parent.length_space_border -= length_space_border + length_space_border = 0 + + group_border = 0 + for(var/direction in cardinal) + if(air_check_directions&direction) + var/turf/simulated/T = get_step(src,direction) + + //See if actually a border + if(!istype(T) || (T.parent!=parent)) + + //See what kind of border it is + if(istype(T,/turf/space)) + if(parent.space_borders) + parent.space_borders -= src + parent.space_borders += src + else + parent.space_borders = list(src) + length_space_border++ + + else + if(parent.borders) + parent.borders -= src + parent.borders += src + else + parent.borders = list(src) + + group_border |= direction + + parent.length_space_border += length_space_border + + if(air_check_directions) + processing = 1 + if(!parent) + air_master.add_singleton(src) + else + processing = 0 + + process_cell() + var/turf/simulated/list/possible_fire_spreads = list() + if(processing) + if(archived_cycle < air_master.current_cycle) //archive self if not already done + archive() + current_cycle = air_master.current_cycle + + for(var/direction in cardinal) + if(air_check_directions&direction) //Grab all valid bordering tiles + var/turf/simulated/enemy_tile = get_step(src, direction) + var/connection_difference = 0 + + if(istype(enemy_tile)) + if(enemy_tile.archived_cycle < archived_cycle) //archive bordering tile information if not already done + enemy_tile.archive() + if(enemy_tile.parent && enemy_tile.parent.group_processing) //apply tile to group sharing + if(enemy_tile.parent.current_cycle < current_cycle) + if(enemy_tile.parent.air.check_gas_mixture(air)) + connection_difference = air.share(enemy_tile.parent.air) + else + enemy_tile.parent.suspend_group_processing() + connection_difference = air.share(enemy_tile.air) + //group processing failed so interact with individual tile + else + if(enemy_tile.current_cycle < current_cycle) + connection_difference = air.share(enemy_tile.air) + if(active_hotspot) + possible_fire_spreads += enemy_tile + else +/* var/obj/movable/floor/movable_on_enemy = locate(/obj/movable/floor) in enemy_tile + + if(movable_on_enemy) + if(movable_on_enemy.parent && movable_on_enemy.parent.group_processing) //apply tile to group sharing + if(movable_on_enemy.parent.current_cycle < current_cycle) + if(movable_on_enemy.parent.air.check_gas_mixture(air)) + connection_difference = air.share(movable_on_enemy.parent.air) + + else + movable_on_enemy.parent.suspend_group_processing() + + if(movable_on_enemy.archived_cycle < archived_cycle) //archive bordering tile information if not already done + movable_on_enemy.archive() + connection_difference = air.share(movable_on_enemy.air) + //group processing failed so interact with individual tile + else + if(movable_on_enemy.archived_cycle < archived_cycle) //archive bordering tile information if not already done + movable_on_enemy.archive() + + if(movable_on_enemy.current_cycle < current_cycle) + connection_difference = share_air_with_tile(movable_on_enemy) + + else*/ + connection_difference = mimic_air_with_tile(enemy_tile) + //bordering a tile with fixed air properties + + if(connection_difference) + if(connection_difference > 0) + consider_pressure_difference(connection_difference, direction) + else + enemy_tile.consider_pressure_difference(connection_difference, direction) + else + air_master.active_singletons -= src //not active if not processing! + + air.react() + + if(active_hotspot) + active_hotspot.process(possible_fire_spreads) + + if(air.temperature > MINIMUM_TEMPERATURE_START_SUPERCONDUCTION) + consider_superconductivity(starting = 1) + + if(air.check_tile_graphic()) + update_visuals(air) + + if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST) + hotspot_expose(air.temperature, CELL_VOLUME) + for(var/atom/movable/item in src) + item.temperature_expose(air, air.temperature, CELL_VOLUME) + temperature_expose(air, air.temperature, CELL_VOLUME) + + return 1 + + super_conduct() + var/conductivity_directions = 0 + if(blocks_air) + //Does not participate in air exchange, so will conduct heat across all four borders at this time + conductivity_directions = NORTH|SOUTH|EAST|WEST + + if(archived_cycle < air_master.current_cycle) + archive() + + else + //Does particate in air exchange so only consider directions not considered during process_cell() + conductivity_directions = ~air_check_directions & (NORTH|SOUTH|EAST|WEST) + + if(conductivity_directions>0) + //Conduct with tiles around me + for(var/direction in cardinal) + if(conductivity_directions&direction) + var/turf/neighbor = get_step(src,direction) + + if(istype(neighbor, /turf/simulated)) //anything under this subtype will share in the exchange + var/turf/simulated/modeled_neighbor = neighbor + + if(modeled_neighbor.archived_cycle < air_master.current_cycle) + modeled_neighbor.archive() + + if(modeled_neighbor.air) + if(air) //Both tiles are open + + if(modeled_neighbor.parent && modeled_neighbor.parent.group_processing) + if(parent && parent.group_processing) + //both are acting as a group + //modified using construct developed in datum/air_group/share_air_with_group(...) + + var/result = parent.air.check_both_then_temperature_share(modeled_neighbor.parent.air, WINDOW_HEAT_TRANSFER_COEFFICIENT) + if(result==0) + //have to deconstruct parent air group + + parent.suspend_group_processing() + if(!modeled_neighbor.parent.air.check_me_then_temperature_share(air, WINDOW_HEAT_TRANSFER_COEFFICIENT)) + //may have to deconstruct neighbors air group + + modeled_neighbor.parent.suspend_group_processing() + air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT) + else if(result==-1) + // have to deconstruct neightbors air group but not mine + + modeled_neighbor.parent.suspend_group_processing() + parent.air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT) + else + air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT) + else + if(parent && parent.group_processing) + if(!parent.air.check_me_then_temperature_share(air, WINDOW_HEAT_TRANSFER_COEFFICIENT)) + //may have to deconstruct neighbors air group + + parent.suspend_group_processing() + air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT) + + else + air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT) + // world << "OPEN, OPEN" + + else //Solid but neighbor is open + if(modeled_neighbor.parent && modeled_neighbor.parent.group_processing) + if(!modeled_neighbor.parent.air.check_me_then_temperature_turf_share(src, modeled_neighbor.thermal_conductivity)) + + modeled_neighbor.parent.suspend_group_processing() + modeled_neighbor.air.temperature_turf_share(src, modeled_neighbor.thermal_conductivity) + else + modeled_neighbor.air.temperature_turf_share(src, modeled_neighbor.thermal_conductivity) + // world << "SOLID, OPEN" + + else + if(air) //Open but neighbor is solid + if(parent && parent.group_processing) + if(!parent.air.check_me_then_temperature_turf_share(modeled_neighbor, modeled_neighbor.thermal_conductivity)) + parent.suspend_group_processing() + air.temperature_turf_share(modeled_neighbor, modeled_neighbor.thermal_conductivity) + else + air.temperature_turf_share(modeled_neighbor, modeled_neighbor.thermal_conductivity) + // world << "OPEN, SOLID" + + else //Both tiles are solid + share_temperature_mutual_solid(modeled_neighbor, modeled_neighbor.thermal_conductivity) + // world << "SOLID, SOLID" + + modeled_neighbor.consider_superconductivity() + + else + if(air) //Open + if(parent && parent.group_processing) + if(!parent.air.check_me_then_temperature_mimic(neighbor, neighbor.thermal_conductivity)) + parent.suspend_group_processing() + air.temperature_mimic(neighbor, neighbor.thermal_conductivity) + else + air.temperature_mimic(neighbor, neighbor.thermal_conductivity) + else + mimic_temperature_solid(neighbor, neighbor.thermal_conductivity) + + //Radiate excess tile heat to space + var/turf/space/sample_space = locate(/turf/space) + if(sample_space && (temperature > T0C)) + //Considering 0 degC as te break even point for radiation in and out + mimic_temperature_solid(sample_space, FLOOR_HEAT_TRANSFER_COEFFICIENT) + + //Conduct with air on my tile if I have it + if(air) + if(parent && parent.group_processing) + if(!parent.air.check_me_then_temperature_turf_share(src, thermal_conductivity)) + parent.suspend_group_processing() + air.temperature_turf_share(src, thermal_conductivity) + else + air.temperature_turf_share(src, thermal_conductivity) + + + //Make sure still hot enough to continue conducting heat + if(air) + if(air.temperature < MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION) + being_superconductive = 0 + air_master.active_super_conductivity -= src + return 0 + + else + if(temperature < MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION) + being_superconductive = 0 + air_master.active_super_conductivity -= src + return 0 + + proc/mimic_temperature_solid(turf/model, conduction_coefficient) + var/delta_temperature = (temperature_archived - model.temperature) + if((heat_capacity > 0) && (abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)) + + var/heat = conduction_coefficient*delta_temperature* \ + (heat_capacity*model.heat_capacity/(heat_capacity+model.heat_capacity)) + temperature -= heat/heat_capacity + + proc/share_temperature_mutual_solid(turf/simulated/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature_archived) + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + + var/heat = conduction_coefficient*delta_temperature* \ + (heat_capacity*sharer.heat_capacity/(heat_capacity+sharer.heat_capacity)) + + temperature -= heat/heat_capacity + sharer.temperature += heat/sharer.heat_capacity + + proc/consider_superconductivity(starting) + + if(being_superconductive || !thermal_conductivity) + return 0 + + if(air) + if(air.temperature < (starting?MINIMUM_TEMPERATURE_START_SUPERCONDUCTION:MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION)) + return 0 + if(air.heat_capacity() < MOLES_CELLSTANDARD*0.1*0.05) + return 0 + else + if(temperature < (starting?MINIMUM_TEMPERATURE_START_SUPERCONDUCTION:MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION)) + return 0 + + being_superconductive = 1 + + air_master.active_super_conductivity += src diff --git a/code/WorkInProgress/BrokenInhands.dm b/code/WorkInProgress/BrokenInhands.dm new file mode 100644 index 0000000000000..b84c225765424 --- /dev/null +++ b/code/WorkInProgress/BrokenInhands.dm @@ -0,0 +1,36 @@ +/proc/getbrokeninhands() + var/icon/IL = new('items_lefthand.dmi') + var/list/Lstates = IL.IconStates() + var/icon/IR = new('items_righthand.dmi') + var/list/Rstates = IR.IconStates() + + + var/text + for(var/A in typesof(/obj/item)) + var/obj/item/O = new A( locate(1,1,1) ) + if(!O) continue + var/icon/J = new(O.icon) + var/list/istates = J.IconStates() + if(!Lstates.Find(O.icon_state) && !Lstates.Find(O.item_state)) + if(O.icon_state) + text += "[O.type] WANTS IN LEFT HAND CALLED\n\"[O.icon_state]\".\n" + if(!Rstates.Find(O.icon_state) && !Rstates.Find(O.item_state)) + if(O.icon_state) + text += "[O.type] WANTS IN RIGHT HAND CALLED\n\"[O.icon_state]\".\n" + + + if(O.icon_state) + if(!istates.Find(O.icon_state)) + text += "[O.type] MISSING NORMAL ICON CALLED\n\"[O.icon_state]\" IN \"[O.icon]\"\n" + if(O.item_state) + if(!istates.Find(O.item_state)) + text += "[O.type] MISSING NORMAL ICON CALLED\n\"[O.item_state]\" IN \"[O.icon]\"\n" + text+="\n" + del(O) + if(text) + var/F = file("broken_icons.txt") + fdel(F) + F << text + world << "Completely successfully and written to [F]" + + diff --git a/code/WorkInProgress/Cameras.dm b/code/WorkInProgress/Cameras.dm new file mode 100644 index 0000000000000..5349ed3703320 --- /dev/null +++ b/code/WorkInProgress/Cameras.dm @@ -0,0 +1,188 @@ +/obj/item/weapon/storage/photo_album + name = "Photo album" + icon = 'old_or_unused.dmi' + icon_state = "album" + item_state = "briefcase" + +/obj/item/weapon/storage/photo_album/MouseDrop(obj/over_object as obj) + + if ((istype(usr, /mob/living/carbon/human) || (ticker && ticker.mode.name == "monkey"))) + var/mob/M = usr + if (!( istype(over_object, /obj/screen) )) + return ..() + playsound(src.loc, "rustle", 50, 1, -5) + if ((!( M.restrained() ) && !( M.stat ) && M.back == src)) + if (over_object.name == "r_hand") + if (!( M.r_hand )) + M.u_equip(src) + M.r_hand = src + else + if (over_object.name == "l_hand") + if (!( M.l_hand )) + M.u_equip(src) + M.l_hand = src + M.update_clothing() + src.add_fingerprint(usr) + return + if(over_object == usr && in_range(src, usr) || usr.contents.Find(src)) + if (usr.s_active) + usr.s_active.close(usr) + src.show_to(usr) + return + return + +/obj/item/weapon/storage/photo_album/attackby(obj/item/weapon/W as obj, mob/user as mob) + + if (src.contents.len >= 7) + return + + if (!istype(W,/obj/item/weapon/photo)) + user << "\red You can only put photos in a photo album." + return + + var/t + for(var/obj/item/weapon/O in src) + t += O.w_class + + playsound(src.loc, "rustle", 50, 1, -5) + user.u_equip(W) + W.loc = src + if ((user.client && user.s_active != src)) + user.client.screen -= W + src.orient2hud(user) + W.dropped(user) + add_fingerprint(user) + for(var/mob/O in viewers(user, null)) + O.show_message(text("\blue [] has added [] to []!", user, W, src), 1) + + return + +/obj/item/weapon/camera_test + name = "camera" + icon = 'old_or_unused.dmi' + desc = "A one use - polaroid camera. 10 photos left." + icon_state = "camera" + item_state = "electropack" + w_class = 2.0 + flags = 466.0 + m_amt = 2000 + throwforce = 5 + throw_speed = 4 + throw_range = 10 + var/pictures_left = 10 + var/can_use = 1 + +/obj/item/weapon/photo + name = "photo" + icon = 'old_or_unused.dmi' + icon_state = "photo" + item_state = "clipboard" + w_class = 1.0 + +////////////////////////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/camera_test/proc/build_composite_icon(var/atom/C) + var/icon/composite = icon(C.icon, C.icon_state, C.dir, 1) + for(var/O in C.overlays) + var/image/I = O + composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY) + return composite +////////////////////////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/camera_test/attack(mob/living/carbon/human/M as mob, mob/user as mob) + return + +/obj/item/weapon/camera_test/afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag) + if (!can_use || !pictures_left || ismob(target.loc)) return + + var/turf/the_turf = get_turf(target) + + var/icon/photo = icon('old_or_unused.dmi',"photo") + + var/icon/turficon = build_composite_icon(the_turf) + turficon.Scale(22,20) + + photo.Blend(turficon,ICON_OVERLAY,6,8) + + var/mob_title = null + var/mob_detail = null + + var/item_title = null + var/item_detail = null + + var/itemnumber = 0 + for(var/atom/A in the_turf) + if(A.invisibility) continue + if(ismob(A)) + var/icon/X = build_composite_icon(A) + X.Scale(22,20) + photo.Blend(X,ICON_OVERLAY,6,8) + del(X) + + if(!mob_title) + mob_title = "[A]" + else + mob_title += " and [A]" + + if(!mob_detail) + + var/holding = null + if(istype(A, /mob/living/carbon)) + var/mob/living/carbon/temp = A + if(temp.l_hand || temp.r_hand) + if(temp.l_hand) holding = "They are holding \a [temp.l_hand]" + if(temp.r_hand) + if(holding) + holding += " and \a [temp.r_hand]." + else + holding = "They are holding \a [temp.r_hand]." + + if(!mob_detail) + mob_detail = "You can see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]" + else + mob_detail += "You can also see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]" + + else + if(itemnumber < 5) + var/icon/X = build_composite_icon(A) + X.Scale(22,20) + photo.Blend(X,ICON_OVERLAY,6,8) + del(X) + itemnumber++ + + if(!item_title) + item_title = " \a [A]" + else + item_title = " some objects" + + if(!item_detail) + item_detail = "\a [A]" + else + item_detail += " and \a [A]" + + var/finished_title = null + var/finished_detail = null + + if(!item_title && !mob_title) + finished_title = "boring photo" + finished_detail = "This is a pretty boring photo of \a [the_turf]." + else + if(mob_title) + finished_title = "photo of [mob_title][item_title ? " and[item_title]":""]" + finished_detail = "[mob_detail][item_detail ? " Theres also [item_detail].":"."]" + else if(item_title) + finished_title = "photo of[item_title]" + finished_detail = "You can see [item_detail]." + + var/obj/item/weapon/photo/P = new/obj/item/weapon/photo( get_turf(src) ) + + P.icon = photo + P.name = finished_title + P.desc = finished_detail + + playsound(src.loc, pick('polaroid1.ogg','polaroid2.ogg'), 75, 1, -3) + + pictures_left-- + src.desc = "A one use - polaroid camera. [pictures_left] photos left." + user << "\blue [pictures_left] photos left." + can_use = 0 + spawn(50) can_use = 1 + diff --git a/code/WorkInProgress/Chemistry-Holder.dm b/code/WorkInProgress/Chemistry-Holder.dm new file mode 100644 index 0000000000000..f17c1b1e9b7c2 --- /dev/null +++ b/code/WorkInProgress/Chemistry-Holder.dm @@ -0,0 +1,235 @@ +#define TOUCH 1 +#define INGEST 2 + +/////////////////////////////////////////////////////////////////////////////////// + +datum + reagents + var/list/reagent_list = new/list() + var/total_volume = 0 + var/maximum_volume = 100 + var/atom/my_atom = null + + New(maximum=100) + maximum_volume = maximum + + proc + + remove_any(var/amount=1) + var/total_transfered = 0 + var/current_list_element = 1 + + current_list_element = rand(1,reagent_list.len) + + while(total_transfered != amount) + if(total_transfered >= amount) break + if(total_volume <= 0 || !reagent_list.len) break + + if(current_list_element > reagent_list.len) current_list_element = 1 + var/datum/reagent/current_reagent = reagent_list[current_list_element] + + src.remove_reagent(current_reagent.id, 1) + + current_list_element++ + total_transfered++ + src.update_total() + + handle_reactions() + return total_transfered + + get_master_reagent_name() + var/the_name = null + var/the_volume = 0 + for(var/datum/reagent/A in reagent_list) + if(A.volume > the_volume) + the_volume = A.volume + the_name = A.name + + return the_name + + trans_to(var/obj/target, var/amount=1, var/multiplier=1) + var/total_transfered = 0 + var/current_list_element = 1 + var/datum/reagents/R = target.reagents + //if(R.total_volume + amount > R.maximum_volume) return 0 + + current_list_element = rand(1,reagent_list.len) //Eh, bandaid fix. + + while(total_transfered != amount) + if(total_transfered >= amount) break //Better safe than sorry. + if(total_volume <= 0 || !reagent_list.len) break + if(R.total_volume >= R.maximum_volume) break + + if(current_list_element > reagent_list.len) current_list_element = 1 + var/datum/reagent/current_reagent = reagent_list[current_list_element] + + R.add_reagent(current_reagent.id, (1 * multiplier) ) + src.remove_reagent(current_reagent.id, 1) + + current_list_element++ + total_transfered++ + src.update_total() + R.update_total() + + R.handle_reactions() + handle_reactions() + + return total_transfered + + metabolize(var/mob/M) + for(var/A in reagent_list) + var/datum/reagent/R = A + R.on_mob_life(M) + update_total() + + handle_reactions() + + if(ismob(my_atom)) return //No reactions inside mobs :I + + for(var/A in typesof(/datum/chemical_reaction) - /datum/chemical_reaction) + var/datum/chemical_reaction/C = new A() + var/total_required_reagents = C.required_reagents.len + var/total_matching_reagents = 0 + var/list/multipliers = new/list() + + for(var/B in C.required_reagents) + if(has_reagent(B, C.required_reagents[B])) + total_matching_reagents++ + multipliers += round(get_reagent_amount(B) / C.required_reagents[B]) + + if(total_matching_reagents == total_required_reagents) + var/multiplier = min(multipliers) + for(var/B in C.required_reagents) + del_reagent(B) + + var/created_volume = C.result_amount*multiplier + if(C.result) + multiplier = max(multiplier, 1) //this shouldnt happen ... + add_reagent(C.result, C.result_amount*multiplier) + + for(var/mob/M in viewers(4, get_turf(my_atom)) ) + M << "\blue \icon[my_atom] The solution begins to bubble." + playsound(get_turf(my_atom), 'bubbles.ogg', 80, 1) + + C.on_reaction(src, created_volume) + + update_total() + return 0 + + isolate_reagent(var/reagent) + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id != reagent) + del_reagent(R.id) + update_total() + + del_reagent(var/reagent) + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id == reagent) + reagent_list -= A + del(A) + update_total() + my_atom.on_reagent_change() + return 0 + + + return 1 + + update_total() + total_volume = 0 + for(var/datum/reagent/R in reagent_list) + if(R.volume < 1) + del_reagent(R.id) + else + total_volume += R.volume + + return 0 + + clear_reagents() + for(var/datum/reagent/R in reagent_list) + del_reagent(R.id) + return 0 + + reaction(var/atom/A, var/method=TOUCH, var/volume_modifier=0) + switch(method) + if(TOUCH) + for(var/datum/reagent/R in reagent_list) + if(ismob(A)) spawn(0) R.reaction_mob(A, TOUCH, R.volume+volume_modifier) + if(isturf(A)) spawn(0) R.reaction_turf(A, R.volume+volume_modifier) + if(isobj(A)) spawn(0) R.reaction_obj(A, R.volume+volume_modifier) + if(INGEST) + for(var/datum/reagent/R in reagent_list) + if(ismob(A)) spawn(0) R.reaction_mob(A, INGEST, R.volume+volume_modifier) + if(isturf(A)) spawn(0) R.reaction_turf(A, R.volume+volume_modifier) + if(isobj(A)) spawn(0) R.reaction_obj(A, R.volume+volume_modifier) + return + + add_reagent(var/reagent, var/amount) + if(!isnum(amount)) return 1 + update_total() + if(total_volume + amount > maximum_volume) amount = (maximum_volume - total_volume) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen. + + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id == reagent) + R.volume += amount + update_total() + my_atom.on_reagent_change() + return 0 + + for(var/A in typesof(/datum/reagent) - /datum/reagent) + var/datum/reagent/R = new A() + if (R.id == reagent) + reagent_list += R + R.holder = src + R.volume = amount + update_total() + my_atom.on_reagent_change() + return 0 + + return 1 + + remove_reagent(var/reagent, var/amount) + + if(!isnum(amount)) return 1 + + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id == reagent) + R.volume -= amount + update_total() + handle_reactions() + my_atom.on_reagent_change() + return 0 + + return 1 + + has_reagent(var/reagent, var/amount = -1) + + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id == reagent) + if(!amount) return 1 + else + if(R.volume >= amount) return 1 + else return 0 + + return 0 + + get_reagent_amount(var/reagent) + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id == reagent) + return R.volume + + return 0 + +/////////////////////////////////////////////////////////////////////////////////// + + +// Convenience proc to create a reagents holder for an atom +// Max vol is maximum volume of holder +atom/proc/create_reagents(var/max_vol) + reagents = new/datum/reagents(max_vol) + reagents.my_atom = src diff --git a/code/WorkInProgress/Chemistry-Machinery.dm b/code/WorkInProgress/Chemistry-Machinery.dm new file mode 100644 index 0000000000000..75c810ef01147 --- /dev/null +++ b/code/WorkInProgress/Chemistry-Machinery.dm @@ -0,0 +1,231 @@ +#define SOLID 1 +#define LIQUID 2 +#define GAS 3 + +/obj/machinery/chem_dispenser/ + name = "chem dispenser" + density = 1 + anchored = 1 + icon = 'chemical.dmi' + icon_state = "dispenser" + var/energy = 25 + var/max_energy = 25 + var/list/dispensable_reagents = list("water","oxygen","nitrogen","hydrogen","potassium","mercury","sulfur","carbon","chlorine","fluorine","phosphorus","lithium","acid","radium","iron","aluminium","silicon","plasma","sugar","ethanol") + + proc + recharge() + if(stat & BROKEN) return + if(energy != max_energy) + energy++ + use_power(50) + spawn(600) recharge() + + New() + recharge() + + ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(50)) + del(src) + return + + blob_act() + if (prob(25)) + del(src) + + meteorhit() + del(src) + return + + Topic(href, href_list) + if(stat & BROKEN) return + if(usr.stat || usr.restrained()) return + if(!in_range(src, usr)) return + + usr.machine = src + + if (href_list["dispense"]) + if(!energy) + var/dat = "Not enough energy.
OK" + usr << browse("Chemical DispenserChemical dispenser:
Energy = [energy]/[max_energy]

[dat]", "window=chem_dispenser") + return + var/id = href_list["dispense"] + var/obj/item/weapon/reagent_containers/glass/dispenser/G = new/obj/item/weapon/reagent_containers/glass/dispenser(src.loc) + switch(text2num(href_list["state"])) + if(LIQUID) + G.icon_state = "liquid" + if(GAS) + G.icon_state = "vapour" + if(SOLID) + G.icon_state = "solid" + G.name += " ([lowertext(href_list["name"])])" + G.reagents.add_reagent(id,30) + energy-- + src.updateUsrDialog() + return + else + usr << browse(null, "window=chem_dispenser") + return + + src.add_fingerprint(usr) + return + + attack_ai(mob/user as mob) + return src.attack_hand(user) + + attack_paw(mob/user as mob) + return src.attack_hand(user) + + attack_hand(mob/user as mob) + if(stat & BROKEN) + return + user.machine = src + var/dat = "" + for(var/re in dispensable_reagents) + for(var/da in typesof(/datum/reagent) - /datum/reagent) + var/datum/reagent/temp = new da() + if(temp.id == re) + dat += "[temp.name]
" + dat += "[temp.description]

" + user << browse("Chemical DispenserChemical dispenser:
Energy = [energy]/[max_energy]

[dat]", "window=chem_dispenser") + + onclose(user, "chem_dispenser") + return + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/obj/machinery/chem_master/ + name = "CheMaster 3000" + density = 1 + anchored = 1 + icon = 'chemical.dmi' + icon_state = "mixer0" + var/beaker = null + + ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(50)) + del(src) + return + + blob_act() + if (prob(25)) + del(src) + + meteorhit() + del(src) + return + + attackby(var/obj/item/weapon/reagent_containers/glass/B as obj, var/mob/user as mob) + if(!istype(B, /obj/item/weapon/reagent_containers/glass)) + return + + if(src.beaker) + user << "A beaker is already loaded into the machine." + return + + src.beaker = B + user.drop_item() + B.loc = src + user << "You add the beaker to the machine!" + src.updateUsrDialog() + icon_state = "mixer1" + + Topic(href, href_list) + if(stat & BROKEN) return + if(usr.stat || usr.restrained()) return + if(!in_range(src, usr)) return + + usr.machine = src + if(!beaker) return + var/datum/reagents/R = beaker:reagents + + if (href_list["isolate"]) + R.isolate_reagent(href_list["isolate"]) + src.updateUsrDialog() + return + else if (href_list["remove"]) + R.del_reagent(href_list["remove"]) + src.updateUsrDialog() + return + else if (href_list["remove5"]) + R.remove_reagent(href_list["remove5"], 5) + src.updateUsrDialog() + return + else if (href_list["remove1"]) + R.remove_reagent(href_list["remove1"], 1) + src.updateUsrDialog() + return + else if (href_list["analyze"]) + var/dat = "Chemmaster 3000Chemical infos:

Name:
[href_list["name"]]

Description:
[href_list["desc"]]


(Back)" + usr << browse(dat, "window=chem_master;size=575x400") + return + else if (href_list["main"]) + attack_hand(usr) + return + else if (href_list["eject"]) + beaker:loc = src.loc + beaker = null + icon_state = "mixer0" + src.updateUsrDialog() + return + else if (href_list["createpill"]) + var/obj/item/weapon/reagent_containers/pill/P = new/obj/item/weapon/reagent_containers/pill(src.loc) + var/name = input(usr,"Name:","Name your pill!",R.get_master_reagent_name()) + if(!name || name == " ") name = R.get_master_reagent_name() + P.name = "[name] pill" + R.trans_to(P,R.total_volume) + src.updateUsrDialog() + return + else if (href_list["createbottle"]) + var/obj/item/weapon/reagent_containers/glass/bottle/P = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) + var/name = input(usr,"Name:","Name your bottle!",R.get_master_reagent_name()) + if(!name || name == " ") name = R.get_master_reagent_name() + P.name = "[name] bottle" + R.trans_to(P,30) + src.updateUsrDialog() + return + else + usr << browse(null, "window=chem_master") + return + + src.add_fingerprint(usr) + return + + attack_ai(mob/user as mob) + return src.attack_hand(user) + + attack_paw(mob/user as mob) + return src.attack_hand(user) + + attack_hand(mob/user as mob) + if(stat & BROKEN) + return + user.machine = src + var/dat = "" + if(!beaker) + dat = "Please insert beaker.
" + dat += "Close" + else + var/datum/reagents/R = beaker:reagents + dat += "Eject beaker

" + if(!R.total_volume) + dat += "Beaker is empty." + else + dat += "Contained reagents:
" + for(var/datum/reagent/G in R.reagent_list) + dat += "[G.name] , [G.volume] Units - (Isolate) (Remove all) (Remove 5) (Remove 1) (Analyze)
" + dat += "
Create pill
" + dat += "Create bottle (30 units max)" + user << browse("Chemmaster 3000Chemmaster menu:

[dat]", "window=chem_master;size=575x400") + onclose(user, "chem_master") + return \ No newline at end of file diff --git a/code/WorkInProgress/Chemistry-Readme.dm b/code/WorkInProgress/Chemistry-Readme.dm new file mode 100644 index 0000000000000..6124d5c704b5a --- /dev/null +++ b/code/WorkInProgress/Chemistry-Readme.dm @@ -0,0 +1,219 @@ +/* +NOTE: IF YOU UPDATE THE REAGENT-SYSTEM, ALSO UPDATE THIS README. + +Structure: /////////////////// ////////////////////////// + // Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents. + /////////////////// ////////////////////////// + | | + The object that holds everything. V + reagent_list var (list) A List of datums, each datum is a reagent. + + | | | + V V V + + reagents (datums) Reagents. I.e. Water , antitoxins or mercury. + + +Random important notes: + + An objects on_reagent_change will be called every time the objects reagents change. + Useful if you want to update the objects icon etc. + +About the Holder: + + The holder (reagents datum) is the datum that holds a list of all reagents + currently in the object.It also has all the procs needed to manipulate reagents + + remove_any(var/amount) + This proc removes reagents from the holder until the passed amount + is matched. It'll try to remove some of ALL reagents contained. + + trans_to(var/obj/target, var/amount) + This proc equally transfers the contents of the holder to another + objects holder. You need to pass it the object (not the holder) you want + to transfer to and the amount you want to transfer. Its return value is the + actual amount transfered (if one of the objects is full/empty) + + metabolize(var/mob/M) + This proc is called by the mobs life proc. It simply calls on_mob_life for + all contained reagents. You shouldnt have to use this one directly. + + handle_reactions() + This proc check all recipes and, on a match, uses them. + It will also call the recipe's on_reaction proc (for explosions or w/e). + Currently, this proc is automatically called by trans_to. + + isolate_reagent(var/reagent) + Pass it a reagent id and it will remove all reagents but that one. + It's that simple. + + del_reagent(var/reagent) + Completely remove the reagent with the matching id. + + reaction_fire(exposed_temp) + Simply calls the reaction_fire procs of all contained reagents. + + update_total() + This one simply updates the total volume of the holder. + (the volume of all reagents added together) + + clear_reagents() + This proc removes ALL reagents from the holder. + + reaction(var/atom/A, var/method=TOUCH, var/volume_modifier=0) + This proc calls the appropriate reaction procs of the reagents. + I.e. if A is an object, it will call the reagents reaction_obj + proc. The method var is used for reaction on mobs. It simply tells + us if the mob TOUCHed the reagent or if it INGESTed the reagent. + Since the volume can be checked in a reagents proc, you might want to + use the volume_modifier var to modifiy the passed value without actually + changing the volume of the reagents. + If you're not sure if you need to use this the answer is very most likely 'No'. + You'll want to use this proc whenever an atom first comes in + contact with the reagents of a holder. (in the 'splash' part of a beaker i.e.) + More on the reaction in the reagent part of this readme. + + add_reagent(var/reagent, var/amount) + Attempts to add X of the matching reagent to the holder. + You wont use this much. Mostly in new procs for pre-filled + objects. + + remove_reagent(var/reagent, var/amount) + The exact opposite of the add_reagent proc. + + has_reagent(var/reagent, var/amount) + Returns 1 if the holder contains this reagent. + Or 0 if not. + If you pass it an amount it will additionally check + if the amount is matched. This is optional. + + get_reagent_amount(var/reagent) + Returns the amount of the matching reagent inside the + holder. Returns 0 if the reagent is missing. + + Important variables: + + total_volume + This variable contains the total volume of all reagents in this holder. + + reagent_list + This is a list of all contained reagents. More specifically, references + to the reagent datums. + + maximum_volume + This is the maximum volume of the holder. + + my_atom + This is the atom the holder is 'in'. Useful if you need to find the location. + (i.e. for explosions) + + +About Reagents: + + Reagents are all the things you can mix and fille in bottles etc. This can be anything from + rejuvs over water to ... iron. Each reagent also has a few procs - i'll explain those below. + + reaction_mob(var/mob/M, var/method=TOUCH) + This is called by the holder's reation proc. + This version is only called when the reagent + reacts with a mob. The method var can be either + TOUCH or INGEST. You'll want to put stuff like + acid-facemelting in here. + + reaction_obj(var/obj/O) + This is called by the holder's reation proc. + This version is called when the reagents reacts + with an object. You'll want to put stuff like + object melting in here ... or something. i dunno. + + reaction_turf(var/turf/T) + This is called by the holder's reation proc. + This version is called when the reagents reacts + with a turf. You'll want to put stuff like extra + slippery floors for lube or something in here. + + on_mob_life(var/mob/M) + This proc is called everytime the mobs life proc executes. + This is the place where you put damage for toxins , + drowsyness for sleep toxins etc etc. + You'll want to call the parents proc by using ..() . + If you dont, the chemical will stay in the mob forever - + unless you write your own piece of code to slowly remove it. + (Should be pretty easy, 1 line of code) + + Important variables: + + holder + This variable contains a reference to the holder the chemical is 'in' + + volume + This is the volume of the reagent. + + id + The id of the reagent + + name + The name of the reagent. + + data + This var can be used for whatever the fuck you want. I used it for the sleep + toxins to make them work slowly instead of instantly. You could also use this + for DNA in a blood reagent or ... well whatever you want. + + +About Recipes: + + Recipes are simple datums that contain a list of required reagents and a result. + They also have a proc that is called when the recipe is matched. + + on_reaction(var/datum/reagents/holder, var/created_volume) + This proc is called when the recipe is matched. + You'll want to add explosions etc here. + To find the location you'll have to do something + like get_turf(holder.my_atom) + + name & id + Should be pretty obvious. + + result + This var contains the id of the resulting reagent. + + required_reagents + This is a list of ids of the required reagents. + Each id also needs an associated value that gives us the minimum required amount + of that reagent. The handle_reaction proc can detect mutiples of the same recipes + so for most cases you want to set the required amount to 1. + + result_amount + This is the amount of the resulting reagent this recipe will produce. + I recommend you set this to the total volume of all required reagent. + + +About the Tools: + + By default, all atom have a reagents var - but its empty. if you want to use an object for the chem. + system you'll need to add something like this in its new proc: + + var/datum/reagents/R = new/datum/reagents(100) <<<<< create a new datum , 100 is the maximum_volume of the new holder datum. + reagents = R <<<<< assign the new datum to the objects reagents var + R.my_atom = src <<<<< set the holders my_atom to src so that we know where we are. + + This can also be done by calling a convenience proc: + atom/proc/create_reagents(var/max_volume) + + Other important stuff: + + amount_per_transfer_from_this var + This var is mostly used by beakers and bottles. + It simply tells us how much to transfer when + 'pouring' our reagents into something else. + + atom/proc/is_open_container() + Checks atom/var/flags & OPENCONTAINER. + If this returns 1 , you can use syringes, beakers etc + to manipulate the contents of this object. + If it's 0, you'll need to write your own custom reagent + transfer code since you will not be able to use the standard + tools to manipulate it. + +*/ \ No newline at end of file diff --git a/code/WorkInProgress/Chemistry-Reagents.dm b/code/WorkInProgress/Chemistry-Reagents.dm new file mode 100644 index 0000000000000..4dd52795e0c1a --- /dev/null +++ b/code/WorkInProgress/Chemistry-Reagents.dm @@ -0,0 +1,920 @@ +#define SOLID 1 +#define LIQUID 2 +#define GAS 3 + +//The reaction procs must ALWAYS set src = null, this detaches the proc from the object (the reagent) +//so that it can continue working when the reagent is deleted while the proc is still active. + +datum + reagent + var/name = "Reagent" + var/id = "reagent" + var/description = "" + var/datum/reagents/holder = null + var/reagent_state = SOLID + var/data = null + var/volume = 0 + + proc + reaction_mob(var/mob/M, var/method=TOUCH, var/volume) //By default we have a chance to transfer some + var/datum/reagent/self = src + src = null //of the reagent to the mob on TOUCHING it. + if(method == TOUCH) + + var/chance = 1 + for(var/obj/item/clothing/C in M.get_equipped_items()) + if(C.permeability_coefficient < chance) chance = C.permeability_coefficient + chance = chance * 100 + + if(prob(chance)) + if(M.reagents) + M.reagents.add_reagent(self.id,self.volume/2) + return + + reaction_obj(var/obj/O, var/volume) //By default we transfer a small part of the reagent to the object + src = null //if it can hold reagents. nope! + //if(O.reagents) + // O.reagents.add_reagent(id,volume/3) + return + + reaction_turf(var/turf/T, var/volume) + src = null + return + + on_mob_life(var/mob/M) + holder.remove_reagent(src.id, 0.4) //By default it slowly disappears. + return + + milk + name = "Milk" + id = "milk" + description = "An opaque white liquid produced by the mammary glands of mammals." + reagent_state = LIQUID + + beer + name = "Beer" + id = "beer" + description = "An alcoholic beverage made from malted grains, hops, yeast, and water." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!data) data = 1 + data++ + M.make_dizzy(3) + M:jitteriness = max(M:jitteriness-3,0) + if(data >= 25) + if (!M:stuttering) M:stuttering = 1 + M:stuttering += 3 + if(data >= 40 && prob(33)) + if (!M:confused) M:confused = 1 + M:confused += 2 + ..() + + water + name = "Water" + id = "water" + description = "A ubiquitous chemical substance that is composed of hydrogen and oxygen." + reagent_state = LIQUID + + reaction_turf(var/turf/T, var/volume) + src = null + if(volume >= 3) + if(T:wet >= 1) return + T:wet = 1 + if(T:wet_overlay) + T:overlays -= T:wet_overlay + T:wet_overlay = null + T:wet_overlay = image('water.dmi',T,"wet_floor") + T:overlays += T:wet_overlay + + spawn(800) + if(T:wet >= 2) return + T:wet = 0 + if(T:wet_overlay) + T:overlays -= T:wet_overlay + T:wet_overlay = null + + var/hotspot = (locate(/obj/hotspot) in T) + if(hotspot) + var/datum/gas_mixture/lowertemp = T.remove_air( T:air:total_moles() ) + lowertemp.temperature = max( min(lowertemp.temperature-2000,lowertemp.temperature / 2) ,0) + lowertemp.react() + T.assume_air(lowertemp) + del(hotspot) + return + reaction_obj(var/obj/O, var/volume) + src = null + var/turf/T = get_turf(O) + var/hotspot = (locate(/obj/hotspot) in T) + if(hotspot) + var/datum/gas_mixture/lowertemp = T.remove_air( T:air:total_moles() ) + lowertemp.temperature = max( min(lowertemp.temperature-2000,lowertemp.temperature / 2) ,0) + lowertemp.react() + T.assume_air(lowertemp) + del(hotspot) + return + + lube + name = "Space Lube" + id = "lube" + description = "Lubricant is a substance introduced between two moving surfaces to reduce the friction and wear between them. giggity." + reagent_state = LIQUID + + reaction_turf(var/turf/T, var/volume) + src = null + if(T:wet >= 2) return + T:wet = 2 + spawn(800) + T:wet = 0 + if(T:wet_overlay) + T:overlays -= T:wet_overlay + T:wet_overlay = null + + return + + bilk + name = "Bilk" + id = "bilk" + description = "This appears to be beer mixed with milk. Disgusting." + reagent_state = LIQUID + + anti_toxin + name = "Anti-Toxin (Dylovene)" + id = "anti_toxin" + description = "Dylovene is a broad-spectrum antitoxin." + reagent_state = LIQUID + + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:drowsyness = max(M:drowsyness-2, 0) + if(holder.has_reagent("toxin")) + holder.remove_reagent("toxin", 2) + if(holder.has_reagent("stoxin")) + holder.remove_reagent("stoxin", 2) + if(holder.has_reagent("plasma")) + holder.remove_reagent("plasma", 1) + if(holder.has_reagent("acid")) + holder.remove_reagent("acid", 1) + if(holder.has_reagent("cyanide")) + holder.remove_reagent("cyanide", 1) + M:toxloss = max(M:toxloss-2,0) + ..() + return + + toxin + name = "Toxin" + id = "toxin" + description = "A Toxic chemical." + reagent_state = LIQUID + + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:toxloss += 1.5 + ..() + return + + cyanide + name = "Cyanide" + id = "cyanide" + description = "A highly toxic chemical." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:toxloss += 3 + M:oxyloss += 3 + ..() + return + + stoxin + name = "Sleep Toxin" + id = "stoxin" + description = "An effective hypnotic used to treat insomnia." + reagent_state = LIQUID + + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(!data) data = 1 + switch(data) + if(1 to 15) + M.eye_blurry = max(M.eye_blurry, 10) + if(15 to 25) + M:drowsyness = max(M:drowsyness, 20) + if(25 to INFINITY) + M:paralysis = max(M:paralysis, 20) + M:drowsyness = max(M:drowsyness, 30) + data++ + ..() + return + + inaprovaline + name = "Inaprovaline" + id = "inaprovaline" + description = "Inaprovaline is a synaptic stimulant and cardiostimulant. Commonly used to stabilize patients." + reagent_state = LIQUID + + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(M.losebreath >= 10) + M.losebreath = max(10, M.losebreath-5) + holder.remove_reagent(src.id, 0.2) + return + + space_drugs + name = "Space drugs" + id = "space_drugs" + description = "An illegal chemical compound used as drug." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M.druggy = max(M.druggy, 15) + if(M.canmove) step(M, pick(cardinal)) + if(prob(7)) M:emote(pick("twitch","drool","moan","giggle")) + holder.remove_reagent(src.id, 0.2) + return + + silicate + name = "Silicate" + id = "silicate" + description = "A compound that can be used to reinforce glass." + reagent_state = LIQUID + reaction_obj(var/obj/O, var/volume) + src = null + if(istype(O,/obj/window)) + O:health = O:health * 2 + var/icon/I = icon(O.icon,O.icon_state,O.dir) + I.SetIntensity(1.15,1.50,1.75) + O.icon = I + return + + oxygen + name = "Oxygen" + id = "oxygen" + description = "A colorless, odorless gas." + reagent_state = GAS + + nitrogen + name = "Nitrogen" + id = "nitrogen" + description = "A colorless, odorless, tasteless gas." + reagent_state = GAS + + hydrogen + name = "Hydrogen" + id = "hydrogen" + description = "A colorless, odorless, nonmetallic, tasteless, highly combustible diatomic gas." + reagent_state = GAS + + potassium + name = "Potassium" + id = "potassium" + description = "A soft, low-melting solid that can easily be cut with a knife. Reacts violently with water." + reagent_state = SOLID + + mercury + name = "Mercury" + id = "mercury" + description = "A chemical element." + reagent_state = LIQUID + + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(M.canmove) step(M, pick(cardinal)) + if(prob(5)) M:emote(pick("twitch","drool","moan")) + ..() + return + + sulfur + name = "Sulfur" + id = "sulfur" + description = "A chemical element." + reagent_state = SOLID + + carbon + name = "Carbon" + id = "carbon" + description = "A chemical element." + reagent_state = SOLID + + reaction_turf(var/turf/T, var/volume) + src = null + if(!istype(T, /turf/space)) + new /obj/decal/cleanable/dirt(T) + + chlorine + name = "Chlorine" + id = "chlorine" + description = "A chemical element." + reagent_state = GAS + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:bruteloss++ + ..() + return + + fluorine + name = "Fluorine" + id = "fluorine" + description = "A highly-reactive chemical element." + reagent_state = GAS + on_mob_life(var/mob.M) + if(!M) M = holder.my_atom + M:toxloss++ + ..() + return + + phosphorus + name = "Phosphorus" + id = "phosphorus" + description = "A chemical element." + reagent_state = SOLID + + lithium + name = "Lithium" + id = "lithium" + description = "A chemical element." + reagent_state = SOLID + + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(M.canmove) step(M, pick(cardinal)) + if(prob(5)) M:emote(pick("twitch","drool","moan")) + ..() + return + + sugar + name = "Sugar" + id = "sugar" + description = "The organic compound commonly known as table sugar and sometimes called saccharose. This white, odorless, crystalline powder has a pleasing, sweet taste." + reagent_state = SOLID + + acid + name = "Sulphuric acid" + id = "acid" + description = "A strong mineral acid with the molecular formula H2SO4." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:toxloss++ + M:fireloss++ + ..() + return + reaction_mob(var/mob/M, var/method=TOUCH, var/volume) + if(method == TOUCH) + if(istype(M, /mob/living/carbon/human)) + if(M:wear_mask) + del (M:wear_mask) + M << "\red Your mask melts away but protects you from the acid!" + return + if(M:head) + del (M:head) + M << "\red Your helmet melts into uselessness but protects you from the acid!" + return + + if(prob(75)) + var/datum/organ/external/affecting = M:organs["head"] + affecting.take_damage(25, 0) + M:UpdateDamage() + M:UpdateDamageIcon() + M:emote("scream") + M << "\red Your face has become disfigured!" + M.real_name = "Unknown" + else + M:bruteloss += 15 + else + M:bruteloss += 15 + + reaction_obj(var/obj/O, var/volume) + if(istype(O,/obj/item) && prob(40)) + var/obj/decal/cleanable/molten_item/I = new/obj/decal/cleanable/molten_item(O.loc) + I.desc = "Looks like this was \an [O] some time ago." + for(var/mob/M in viewers(5, O)) + M << "\red \the [O] melts." + del(O) + + pacid + name = "Polytrinic acid" + id = "pacid" + description = "Polytrinic acid is a an extremely corrosive chemical substance." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:toxloss++ + M:fireloss++ + ..() + return + reaction_mob(var/mob/M, var/method=TOUCH, var/volume) + if(method == TOUCH) + if(istype(M, /mob/living/carbon/human)) + if(M:wear_mask) + del (M:wear_mask) + M << "\red Your mask melts away!" + return + if(M:head) + del (M:head) + M << "\red Your helmet melts into uselessness!" + return + var/datum/organ/external/affecting = M:organs["head"] + affecting.take_damage(75, 0) + M:UpdateDamage() + M:UpdateDamageIcon() + M:emote("scream") + M << "\red Your face has become disfigured!" + M.real_name = "Unknown" + else + M:bruteloss += 15 + else + if(istype(M, /mob/living/carbon/human)) + var/datum/organ/external/affecting = M:organs["head"] + affecting.take_damage(75, 0) + M:UpdateDamage() + M:UpdateDamageIcon() + M:emote("scream") + M << "\red Your face has become disfigured!" + M.real_name = "Unknown" + else + M:bruteloss += 15 + + reaction_obj(var/obj/O, var/volume) + if(istype(O,/obj/item)) + var/obj/decal/cleanable/molten_item/I = new/obj/decal/cleanable/molten_item(O.loc) + I.desc = "Looks like this was \an [O] some time ago." + for(var/mob/M in viewers(5, O)) + M << "\red \the [O] melts." + del(O) + + radium + name = "Radium" + id = "radium" + description = "Radium is an alkaline earth metal. It is extremely radioactive." + reagent_state = SOLID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M.radiation += 3 + ..() + return + + + reaction_turf(var/turf/T, var/volume) + src = null + if(!istype(T, /turf/space)) + new /obj/decal/cleanable/greenglow(T) + + + ryetalyn + name = "Ryetalyn" + id = "ryetalyn" + description = "Ryetalyn can cure all genetic abnomalities." + reagent_state = SOLID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M.mutations = 0 + M.disabilities = 0 + M.sdisabilities = 0 + ..() + return + + thermite + name = "Thermite" + id = "thermite" + description = "Thermite produces an aluminothermic reaction known as a thermite reaction. Can be used to melt walls." + reagent_state = SOLID + reaction_turf(var/turf/T, var/volume) + src = null + if(istype(T, /turf/simulated/wall)) + T:thermite = 1 + T.overlays = null + T.overlays = image('effects.dmi',icon_state = "thermite") + return + + mutagen + name = "Unstable mutagen" + id = "mutagen" + description = "Might cause unpredictable mutations. Keep away from children." + reagent_state = LIQUID + reaction_mob(var/mob/M, var/method=TOUCH, var/volume) + src = null + if ( (method==TOUCH && prob(33)) || method==INGEST) + randmuti(M) + if(prob(98)) + randmutb(M) + else + randmutg(M) + domutcheck(M, null, 1) + updateappearance(M,M.dna.uni_identity) + return + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M.radiation += 3 + ..() + return + + iron + name = "Iron" + id = "iron" + description = "Pure iron is a metal." + reagent_state = SOLID + + aluminium + name = "Aluminium" + id = "aluminium" + description = "A silvery white and ductile member of the boron group of chemical elements." + reagent_state = SOLID + + silicon + name = "Silicon" + id = "silicon" + description = "A tetravalent metalloid, silicon is less reactive than its chemical analog carbon." + reagent_state = SOLID + + fuel + name = "Welding fuel" + id = "fuel" + description = "Required for welders. Flamable." + reagent_state = LIQUID + reaction_obj(var/obj/O, var/volume) + src = null + var/turf/the_turf = get_turf(O) + var/datum/gas_mixture/napalm = new + var/datum/gas/volatile_fuel/fuel = new + fuel.moles = 15 + napalm.trace_gases += fuel + the_turf.assume_air(napalm) + reaction_turf(var/turf/T, var/volume) + src = null + var/datum/gas_mixture/napalm = new + var/datum/gas/volatile_fuel/fuel = new + fuel.moles = 15 + napalm.trace_gases += fuel + T.assume_air(napalm) + return + + coffee + name = "Coffee" + id = "coffee" + description = "Coffee is a brewed drink prepared from roasted seeds, commonly called coffee beans, of the coffee plant." + reagent_state = LIQUID + on_mob_life(var/mob/M) + ..() + M.dizziness = max(0,M.dizziness-5) + M:drowsyness = max(0,M:drowsyness-3) + M:sleeping = 0 + M.bodytemperature = min(310, M.bodytemperature+5) //310 is the normal bodytemp. 310.055 + M.make_jittery(5) + + space_cleaner + name = "Space cleaner" + id = "cleaner" + description = "A compound used to clean things. Now with 50% more sodium hypochlorite!" + reagent_state = LIQUID + reaction_obj(var/obj/O, var/volume) + if(istype(O,/obj/decal/cleanable)) + del(O) + else + O.clean_blood() + reaction_turf(var/turf/T, var/volume) + T.overlays = null + T.clean_blood() + for(var/obj/decal/cleanable/C in src) + del(C) + reaction_mob(var/mob/M, var/method=TOUCH, var/volume) + M.clean_blood() + if(istype(M, /mob/living/carbon)) + var/mob/living/carbon/C = M + if(C.r_hand) + C.r_hand.clean_blood() + if(C.l_hand) + C.l_hand.clean_blood() + if(C.wear_mask) + C.wear_mask.clean_blood() + if(istype(M, /mob/living/carbon/human)) + if(C:w_uniform) + C:w_uniform.clean_blood() + if(C:wear_suit) + C:wear_suit.clean_blood() + if(C:shoes) + C:shoes.clean_blood() + if(C:gloves) + C:gloves.clean_blood() + if(C:head) + C:head.clean_blood() + + + space_cola + name = "Cola" + id = "cola" + description = "A refreshing beverage." + reagent_state = LIQUID + on_mob_life(var/mob/M) + M:drowsyness = max(0,M:drowsyness-5) + M.bodytemperature = max(310, M.bodytemperature-5) //310 is the normal bodytemp. 310.055 + + plasma + name = "Plasma" + id = "plasma" + description = "Plasma in its liquid form." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(holder.has_reagent("inaprovaline")) + holder.remove_reagent("inaprovaline", 2) + M:toxloss++ + ..() + return + reaction_obj(var/obj/O, var/volume) + src = null + var/turf/the_turf = get_turf(O) + var/datum/gas_mixture/napalm = new + var/datum/gas/volatile_fuel/fuel = new + fuel.moles = 5 + napalm.trace_gases += fuel + the_turf.assume_air(napalm) + reaction_turf(var/turf/T, var/volume) + src = null + var/datum/gas_mixture/napalm = new + var/datum/gas/volatile_fuel/fuel = new + fuel.moles = 5 + napalm.trace_gases += fuel + T.assume_air(napalm) + return + + leporazine + name = "Leporazine" + id = "leporazine" + description = "Leporazine can be use to stabilize an individuals body temperature." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(M.bodytemperature < 310) + M.bodytemperature = max(310, M.bodytemperature-10) + else if(M.bodytemperature > 311) + M.bodytemperature = min(310, M.bodytemperature+10) + ..() + return + + cryptobiolin + name = "Cryptobiolin" + id = "cryptobiolin" + description = "Cryptobiolin causes confusion and dizzyness." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M.make_dizzy(1) + if(!M.confused) M.confused = 1 + M.confused = max(M.confused, 20) + holder.remove_reagent(src.id, 0.2) + return + + lexorin + name = "Lexorin" + id = "lexorin" + description = "Lexorin temporarily stops respiration. Causes tissue damage." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(prob(33)) M.bruteloss++ + holder.remove_reagent(src.id, 0.3) + return + + kelotane + name = "Kelotane" + id = "kelotane" + description = "Kelotane is a drug used to treat burns." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:fireloss = max(M:fireloss-2,0) + ..() + return + + dexalin + name = "Dexalin" + id = "dexalin" + description = "Dexalin is used in the treatment of oxygen deprivation." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:oxyloss = max(M:oxyloss-2, 0) + ..() + return + + dexalinp + name = "Dexalin Plus" + id = "dexalinp" + description = "Dexalin Plus is used in the treatment of oxygen deprivation. Its highly effective." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:oxyloss = 0 + ..() + return + + tricordrazine + name = "Tricordrazine" + id = "tricordrazine" + description = "Tricordrazine is a highly potent stimulant, originally derived from cordrazine. Can be used to treat a wide range of injuries." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(M:oxyloss && prob(40)) M:oxyloss-- + if(M:bruteloss && prob(40)) M:bruteloss-- + if(M:fireloss && prob(40)) M:fireloss-- + if(M:toxloss && prob(40)) M:toxloss-- + ..() + return + + synaptizine + name = "Synaptizine" + id = "synaptizine" + description = "Synaptizine is used to treat neuroleptic shock. Can be used to help remove disabling symptoms such as paralysis." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:drowsyness = max(M:drowsyness-5, 0) + if(M:paralysis) M:paralysis-- + if(M:stunned) M:stunned-- + if(M:weakened) M:weakened-- + ..() + return + + impedrezene + name = "Impedrezene" + id = "impedrezene" + description = "Impedrezene is a narcotic that impedes one's ability by slowing down the higher brain cell functions." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:jitteriness = max(M:jitteriness-5,0) + if(prob(80)) M:brainloss++ + if(prob(50)) M:drowsyness = max(M:drowsyness, 3) + if(prob(10)) M:emote("drool") + ..() + return + + hyronalin + name = "Hyronalin" + id = "hyronalin" + description = "Hyronalin is a medicinal drug used to counter the effects of radiation poisoning." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(M:radiation && prob(80)) M:radiation-- + ..() + return + + alkysine + name = "Alkysine" + id = "alkysine" + description = "Alkysine is a drug used to lessen the damage to neurological tissue after a catastrophic injury. Can heal brain tissue." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:brainloss = max(M:brainloss-3 , 0) + ..() + return + + arithrazine + name = "Arithrazine" + id = "arithrazine" + description = "Arithrazine is an unstable medication used for the most extreme cases of radiation poisoning." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + M:radiation = max(M:radiation-3,0) + if(M:toxloss && prob(50)) M:toxloss-- + if(prob(15)) M:bruteloss++ + ..() + return + + bicaridine + name = "Bicaridine" + id = "bicaridine" + description = "Bicaridine is an analgesic medication and can be used to treat blunt trauma." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(M:bruteloss && prob(40)) M:bruteloss-- + ..() + return + + hyperzine + name = "Hyperzine" + id = "hyperzine" + description = "Hyperzine is a highly effective, long lasting, muscle stimulant." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(prob(5)) M:emote(pick("twitch","blink_r","shiver")) + holder.remove_reagent(src.id, 0.2) + return + + cryoxadone + name = "Cryoxadone" + id = "cryoxadone" + description = "A chemical mixture with almost magical healing powers. Its main limitation is that the targets body temperature must be under 170K for it to metabolise correctly." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if(M.bodytemperature < 170) + if(M:oxyloss) M:oxyloss = max(0, M:oxyloss-3) + if(M:bruteloss) M:bruteloss = max(0, M:bruteloss-3) + if(M:fireloss) M:fireloss = max(0, M:fireloss-3) + if(M:toxloss) M:toxloss = max(0, M:toxloss-3) + + return + + spaceacillin + name = "Spaceacillin" + id = "spaceacillin" + description = "An all-purpose antiviral agent." + reagent_state = LIQUID + + on_mob_life(var/mob/M) + if(!M) M = holder.my_atom + if((M.virus) && (prob(8))) + if(M.virus.spread == "Airborne") + M.virus.spread = "Remissive" + M.virus.stage-- + if(M.virus.stage <= 0) + M.resistances += M.virus.type + M.virus = null + holder.remove_reagent(src.id, 0.2) + return + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + nanites + name = "Nanomachines" + id = "nanites" + description = "Microscopic construction robots." + reagent_state = LIQUID + reaction_mob(var/mob/M, var/method=TOUCH, var/volume) + src = null + if( (prob(10) && method==TOUCH) || method==INGEST) + if(!M.virus) + M.virus = new /datum/disease/robotic_transformation + M.virus.affected_mob = M + + xenomicrobes + name = "Xenomicrobes" + id = "xenomicrobes" + description = "Microbes with an entirely alien cellular structure." + reagent_state = LIQUID + reaction_mob(var/mob/M, var/method=TOUCH, var/volume) + src = null + if( (prob(10) && method==TOUCH) || method==INGEST) + if(!M.virus) + M.virus = new /datum/disease/xeno_transformation + M.virus.affected_mob = M + +//foam precursor + + fluorosurfactant + name = "Fluorosurfactant" + id = "fluorosurfactant" + description = "A perfluoronated sulfonic acid that forms a foam when mixed with water." + reagent_state = LIQUID + + +// metal foaming agent +// this is lithium hydride. Add other recipies (e.g. LiH + H2O -> LiOH + H2) eventually + + foaming_agent + name = "Foaming agent" + id = "foaming_agent" + description = "A agent that yields metallic foam when mixed with light metal and a strong acid." + reagent_state = SOLID + + nicotine + name = "Nicotine" + id = "nicotine" + description = "A highly addictive stimulant extracted from the tobacco plant." + reagent_state = LIQUID + + ethanol + name = "Ethanol" + id = "ethanol" + description = "A well-known alcohol with a variety of applications." + reagent_state = LIQUID + on_mob_life(var/mob/M) + if(!data) data = 1 + data++ + M.make_dizzy(5) + M:jitteriness = max(M:jitteriness-5,0) + if(data >= 25) + if (!M:stuttering) M:stuttering = 1 + M:stuttering += 4 + if(data >= 40 && prob(33)) + if (!M:confused) M:confused = 1 + M:confused += 3 + ..() + + ammonia + name = "Ammonia" + id = "ammonia" + description = "A caustic substance commonly used in fertilizer or household cleaners." + reagent_state = GAS + + diethylamine + name = "Diethylamine" + id = "diethylamine" + description = "A secondary amine, mildly corrosive." + reagent_state = LIQUID \ No newline at end of file diff --git a/code/WorkInProgress/Chemistry-Recipes.dm b/code/WorkInProgress/Chemistry-Recipes.dm new file mode 100644 index 0000000000000..554e24cbf311f --- /dev/null +++ b/code/WorkInProgress/Chemistry-Recipes.dm @@ -0,0 +1,390 @@ +/////////////////////////////////////////////////////////////////////////////////// +datum + chemical_reaction + var/name = null + var/id = null + var/result = null + var/list/required_reagents = new/list() + var/result_amount = 0 + + proc + on_reaction(var/datum/reagents/holder, var/created_volume) + return + + //I recommend you set the result amount to the total volume of all components. + + bilk + name = "Bilk" + id = "bilk" + result = "bilk" + required_reagents = list("milk" = 1, "beer" = 1) + result_amount = 2 + + explosion_potassium + name = "Explosion" + id = "explosion_potassium" + result = null + required_reagents = list("water" = 1, "potassium" = 1) + result_amount = null + on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread + s.set_up(2, 1, location) + s.start() + for(var/mob/M in viewers(5, location)) + M << "\red The solution violently explodes." + for(var/mob/M in viewers(1, location)) + M << "\red The explosion knocks you down." + M:weakened += 3 + return + + silicate + name = "Silicate" + id = "silicate" + result = "silicate" + required_reagents = list("aluminium" = 1, "silicon" = 1, "oxygen" = 1) + result_amount = 3 + + mutagen + name = "Unstable mutagen" + id = "mutagen" + result = "mutagen" + required_reagents = list("radium" = 1, "phosphorus" = 1, "chlorine" = 1) + result_amount = 3 + + //cyanide + // name = "Cyanide" + // id = "cyanide" + // result = "cyanide" + // required_reagents = list("hydrogen" = 1, "carbon" = 1, "nitrogen" = 1) + // result_amount = 3 + + thermite + name = "Thermite" + id = "thermite" + result = "thermite" + required_reagents = list("aluminium" = 1, "iron" = 1, "oxygen" = 1) + result_amount = 3 + + lexorin + name = "Lexorin" + id = "lexorin" + result = "lexorin" + required_reagents = list("plasma" = 1, "hydrogen" = 1, "nitrogen" = 1) + result_amount = 3 + + space_drugs + name = "Space Drugs" + id = "space_drugs" + result = "space_drugs" + required_reagents = list("mercury" = 1, "sugar" = 1, "lithium" = 1) + result_amount = 3 + + lube + name = "Space Lube" + id = "lube" + result = "lube" + required_reagents = list("water" = 1, "silicon" = 1, "oxygen" = 1) + result_amount = 4 + + pacid + name = "Polytrinic acid" + id = "pacid" + result = "pacid" + required_reagents = list("acid" = 1, "chlorine" = 1, "potassium" = 1) + result_amount = 3 + + synaptizine + name = "Synaptizine" + id = "synaptizine" + result = "synaptizine" + required_reagents = list("sugar" = 1, "lithium" = 1, "water" = 1) + result_amount = 3 + + hyronalin + name = "Hyronalin" + id = "hyronalin" + result = "hyronalin" + required_reagents = list("radium" = 1, "anti_toxin" = 1) + result_amount = 2 + + arithrazine + name = "Arithrazine" + id = "arithrazine" + result = "arithrazine" + required_reagents = list("hyronalin" = 1, "hydrogen" = 1) + result_amount = 2 + + impedrezene + name = "Impedrezene" + id = "impedrezene" + result = "impedrezene" + required_reagents = list("mercury" = 1, "oxygen" = 1, "sugar" = 1) + result_amount = 2 + + kelotane + name = "Kelotane" + id = "kelotane" + result = "kelotane" + required_reagents = list("silicon" = 1, "carbon" = 1) + result_amount = 2 + + leporazine + name = "Leporazine" + id = "leporazine" + result = "leporazine" + required_reagents = list("silicon" = 1, "plasma" = 1, ) + result_amount = 2 + + cryptobiolin + name = "Cryptobiolin" + id = "cryptobiolin" + result = "cryptobiolin" + required_reagents = list("potassium" = 1, "oxygen" = 1, "sugar" = 1) + result_amount = 3 + + tricordrazine + name = "Tricordrazine" + id = "tricordrazine" + result = "tricordrazine" + required_reagents = list("inaprovaline" = 1, "anti_toxin" = 1) + result_amount = 2 + + alkysine + name = "Alkysine" + id = "alkysine" + result = "alkysine" + required_reagents = list("chlorine" = 1, "nitrogen" = 1, "anti_toxin" = 1) + result_amount = 2 + + dexalin + name = "Dexalin" + id = "dexalin" + result = "dexalin" + required_reagents = list("plasma" = 1, "oxygen" = 1) + result_amount = 2 + + dexalinp + name = "Dexalin Plus" + id = "dexalinp" + result = "dexalinp" + required_reagents = list("dexalin" = 1, "carbon" = 1, "iron" = 1) + result_amount = 3 + + bicaridine + name = "Bicaridine" + id = "bicaridine" + result = "bicaridine" + required_reagents = list("inaprovaline" = 1, "carbon" = 1) + result_amount = 2 + + hyperzine + name = "Hyperzine" + id = "hyperzine" + result = "hyperzine" + required_reagents = list("sugar" = 1, "phosphorus" = 1, "sulfur" = 1,) + result_amount = 3 + + ryetalyn + name = "Ryetalyn" + id = "ryetalyn" + result = "ryetalyn" + required_reagents = list("arithrazine" = 1, "carbon" = 1) + result_amount = 2 + + cryoxadone + name = "Cryoxadone" + id = "cryoxadone" + result = "cryoxadone" + required_reagents = list("dexalin" = 1, "water" = 1, "oxygen" = 1) + result_amount = 10 + + spaceacillin + name = "spaceacillin" + id = "spaceacillin" + result = "spaceacillin" + required_reagents = list("cryptobiolin" = 1, "inaprovaline" = 1) + result_amount = 2 + + flash_powder + name = "Flash powder" + id = "flash_powder" + result = null + required_reagents = list("aluminium" = 1, "potassium" = 1, "sulfur" = 1 ) + result_amount = null + on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread + s.set_up(2, 1, location) + s.start() + for(var/mob/living/carbon/M in viewers(world.view, location)) + switch(get_dist(M, location)) + if(0 to 3) + if(hasvar(M, "glasses")) + if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses)) + continue + + flick("e_flash", M.flash) + M.weakened = 15 + + if(4 to 5) + if(hasvar(M, "glasses")) + if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses)) + continue + + flick("e_flash", M.flash) + M.stunned = 5 + + napalm + name = "Napalm" + id = "napalm" + result = null + required_reagents = list("aluminium" = 1, "plasma" = 1, "acid" = 1 ) + result_amount = null + on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + for(var/turf/simulated/floor/target_tile in range(1,location)) + if(target_tile.parent && target_tile.parent.group_processing) + target_tile.parent.suspend_group_processing() + + var/datum/gas_mixture/napalm = new + var/datum/gas/volatile_fuel/fuel = new + + fuel.moles = 15 + napalm.trace_gases += fuel + + target_tile.assume_air(napalm) + + spawn (0) target_tile.hotspot_expose(700, 400) + + return + + smoke + name = "Smoke" + id = "smoke" + result = null + required_reagents = list("potassium" = 1, "sugar" = 1, "phosphorus" = 1 ) + result_amount = null + on_reaction(var/datum/reagents/holder, var/created_volume) + var/location = get_turf(holder.my_atom) + var/datum/effects/system/bad_smoke_spread/S = new /datum/effects/system/bad_smoke_spread + S.attach(location) + S.set_up(10, 0, location) + playsound(location, 'smoke.ogg', 50, 1, -3) + spawn(0) + S.start() + sleep(10) + S.start() + sleep(10) + S.start() + sleep(10) + S.start() + sleep(10) + S.start() + return + +/////////////////////////////////////////////////////////////////////////////////// + +// foam and foam precursor + + surfactant + name = "Foam surfactant" + id = "foam surfactant" + result = "fluorosurfactant" + required_reagents = list("fluorine" = 2, "carbon" = 2, "acid" = 1) + result_amount = 5 + + + foam + name = "Foam" + id = "foam" + result = null + required_reagents = list("fluorosurfactant" = 1, "water" = 1) + result_amount = 2 + + on_reaction(var/datum/reagents/holder, var/created_volume) + + + var/location = get_turf(holder.my_atom) + for(var/mob/M in viewers(5, location)) + M << "\red The solution violently bubbles!" + + location = get_turf(holder.my_atom) + + for(var/mob/M in viewers(5, location)) + M << "\red The solution spews out foam!" + + //world << "Holder volume is [holder.total_volume]" + //for(var/datum/reagent/R in holder.reagent_list) + // world << "[R.name] = [R.volume]" + + var/datum/effects/system/foam_spread/s = new() + s.set_up(created_volume, location, holder, 0) + s.start() + holder.clear_reagents() + return + + + metalfoam + name = "Metal Foam" + id = "metalfoam" + result = null + required_reagents = list("aluminium" = 3, "foaming_agent" = 1, "pacid" = 1) + result_amount = 5 + + on_reaction(var/datum/reagents/holder, var/created_volume) + + + var/location = get_turf(holder.my_atom) + + for(var/mob/M in viewers(5, location)) + M << "\red The solution spews out a metalic foam!" + + var/datum/effects/system/foam_spread/s = new() + s.set_up(created_volume/2, location, holder, 1) + s.start() + return + + ironfoam + name = "Iron Foam" + id = "ironlfoam" + result = null + required_reagents = list("iron" = 3, "foaming_agent" = 1, "pacid" = 1) + result_amount = 5 + + on_reaction(var/datum/reagents/holder, var/created_volume) + + + var/location = get_turf(holder.my_atom) + + for(var/mob/M in viewers(5, location)) + M << "\red The solution spews out a metalic foam!" + + var/datum/effects/system/foam_spread/s = new() + s.set_up(created_volume/2, location, holder, 2) + s.start() + return + + + + foaming_agent + name = "Foaming Agent" + id = "foaming_agent" + result = "foaming_agent" + required_reagents = list("lithium" = 1, "hydrogen" = 1) + result_amount = 1 + + // Synthesizing these three chemicals is pretty complex in real life, but fuck it, it's just a game! + ammonia + name = "Ammonia" + id = "ammonia" + result = "ammonia" + required_reagents = list("hydrogen" = 3, "nitrogen" = 1) + result_amount = 3 + + space_cleaner + name = "Space cleaner" + id = "cleaner" + result = "cleaner" + required_reagents = list("ammonia" = 1, "water" = 1) + result_amount = 1 \ No newline at end of file diff --git a/code/WorkInProgress/Chemistry-Tools.dm b/code/WorkInProgress/Chemistry-Tools.dm new file mode 100644 index 0000000000000..ecb178394e684 --- /dev/null +++ b/code/WorkInProgress/Chemistry-Tools.dm @@ -0,0 +1,1349 @@ +// Bottles transfer 50 units +// Beakers transfer 30 units +// Syringes transfer 15 units +// Droppers transfer 5 units + +//BUG!!!: reactions on splashing etc cause errors because stuff gets deleted before it executes. +// Bandaid fix using spawn - very ugly, need to fix this. + +///////////////////////////////Grenades +/obj/item/weapon/chem_grenade + name = "metal casing" + icon_state = "chemg1" + icon = 'chemical.dmi' + item_state = "flashbang" + w_class = 2.0 + force = 2.0 + var/stage = 0 + var/state = 0 + var/list/beakers = new/list() + throw_speed = 4 + throw_range = 20 + flags = FPRINT | TABLEPASS | CONDUCT | ONBELT | USEDELAY + + New() + var/datum/reagents/R = new/datum/reagents(1000) + reagents = R + R.my_atom = src + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/assembly/time_ignite) && !stage) + user << "\blue You add [W] to the metal casing." + playsound(src.loc, 'Screwdriver2.ogg', 25, -3) + del(W) //Okay so we're not really adding anything here. cheating. + icon_state = "chemg2" + name = "unsecured grenade" + stage = 1 + else if(istype(W,/obj/item/weapon/screwdriver) && stage == 1) + if(beakers.len) + user << "\blue You lock the assembly." + playsound(src.loc, 'Screwdriver.ogg', 25, -3) + name = "grenade" + icon_state = "chemg3" + stage = 2 + else + user << "\red You need to add at least one beaker before locking the assembly." + else if (istype(W,/obj/item/weapon/reagent_containers/glass) && stage == 1) + if(beakers.len == 2) + user << "\red The grenade can not hold more containers." + return + else + if(W.reagents.total_volume) + user << "\blue You add \the [W] to the assembly." + user.drop_item() + W.loc = src + beakers += W + else + user << "\red \the [W] is empty." + + afterattack(atom/target as mob|obj|turf|area, mob/user as mob) + if (istype(target, /obj/item/weapon/storage)) return ..() + if (!src.state && stage == 2) + user << "\red You prime the grenade! 3 seconds!" + src.state = 1 + src.icon_state = "chemg4" + playsound(src.loc, 'armbomb.ogg', 75, 1, -3) + spawn(30) + explode() + user.drop_item() + var/t = (isturf(target) ? target : target.loc) + walk_towards(src, t, 3) + + attack_self(mob/user as mob) + if (!src.state && stage == 2) + user << "\red You prime the grenade! 3 seconds!" + src.state = 1 + src.icon_state = "chemg4" + playsound(src.loc, 'armbomb.ogg', 75, 1, -3) + spawn(30) + explode() + + attack_hand() + walk(src,0) + return ..() + attack_paw() + return attack_hand() + + proc + explode() + var/has_reagents = 0 + for(var/obj/item/weapon/reagent_containers/glass/G in beakers) + if(G.reagents.total_volume) has_reagents = 1 + + if(!has_reagents) + playsound(src.loc, 'Screwdriver2.ogg', 50, 1) + state = 0 + return + + playsound(src.loc, 'bamf.ogg', 50, 1) + + for(var/obj/item/weapon/reagent_containers/glass/G in beakers) + G.reagents.trans_to(src, G.reagents.total_volume) + + if(src.reagents.total_volume) //The possible reactions didnt use up all reagents. + var/datum/effects/system/steam_spread/steam = new /datum/effects/system/steam_spread() + steam.set_up(10, 0, get_turf(src)) + steam.attach(src) + steam.start() + + for(var/atom/A in view(3, src.loc)) + if( A == src ) continue + src.reagents.reaction(A, 1, 10) + + + invisibility = 100 //Why am i doing this? + spawn(50) //To make sure all reagents can work + del(src) //correctly before deleting the grenade. + + +/obj/item/weapon/chem_grenade/metalfoam + name = "metal foam grenade" + desc = "Used for emergency sealing of air breaches." + icon_state = "chemg3" + stage = 2 + + New() + ..() + var/obj/item/weapon/reagent_containers/glass/B1 = new(src) + var/obj/item/weapon/reagent_containers/glass/B2 = new(src) + + B1.reagents.add_reagent("aluminium", 30) + B2.reagents.add_reagent("foaming_agent", 10) + B2.reagents.add_reagent("pacid", 10) + + beakers += B1 + beakers += B2 + +/obj/item/weapon/chem_grenade/cleaner + name = "cleaner grenade" + desc = "BLAM!-brand foaming space cleaner. In a special applicator for rapid cleaning of wide areas." + icon_state = "chemg3" + stage = 2 + + New() + ..() + var/obj/item/weapon/reagent_containers/glass/B1 = new(src) + var/obj/item/weapon/reagent_containers/glass/B2 = new(src) + + B1.reagents.add_reagent("fluorosurfactant", 30) + B2.reagents.add_reagent("water", 10) + B2.reagents.add_reagent("cleaner", 10) + + beakers += B1 + beakers += B2 +/* +/obj/item/weapon/chem_grenade/poo + name = "poo grenade" + desc = "A ShiTastic! brand biological warfare charge. Not very effective unless the target is squeamish." + icon_state = "chemg3" + stage = 2 + + New() + ..() + var/obj/item/weapon/reagent_containers/glass/B1 = new(src) + var/obj/item/weapon/reagent_containers/glass/B2 = new(src) + + B1.reagents.add_reagent("poo", 30) + B2.reagents.add_reagent("poo", 30) + + beakers += B1 + beakers += B2 +*/ +///////////////////////////////Grenades + +/obj/syringe_gun_dummy + name = "" + desc = "" + icon = 'chemical.dmi' + icon_state = "null" + anchored = 1 + density = 0 + + New() + var/datum/reagents/R = new/datum/reagents(15) + reagents = R + R.my_atom = src + +/obj/item/weapon/gun/syringe + name = "syringe gun" + icon = 'gun.dmi' + icon_state = "syringegun" + item_state = "syringegun" + w_class = 3.0 + throw_speed = 2 + throw_range = 10 + force = 4.0 + var/list/syringes = new/list() + var/max_syringes = 1 + m_amt = 2000 + + examine() + set src in view(2) + ..() + usr << "\icon [src] Syringe gun:" + usr << "\blue [syringes] / [max_syringes] Syringes." + + attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/weapon/reagent_containers/syringe)) + if(syringes.len < max_syringes) + user.drop_item() + I.loc = src + syringes += I + user << "\blue You put the syringe in the syringe gun." + user << "\blue [syringes.len] / [max_syringes] Syringes." + else + usr << "\red The syringe gun cannot hold more syringes." + + afterattack(obj/target, mob/user , flag) + if(!isturf(target.loc) || target == user) return + + if(syringes.len) + spawn(0) fire_syringe(target,user) + else + usr << "\red The syringe gun is empty." + + proc + fire_syringe(atom/target, mob/user) + var/turf/trg = get_turf(target) + var/obj/syringe_gun_dummy/D = new/obj/syringe_gun_dummy(get_turf(src)) + var/obj/item/weapon/reagent_containers/syringe/S = syringes[1] + S.reagents.trans_to(D, S.reagents.total_volume) + syringes -= S + del(S) + D.icon_state = "syringeproj" + D.name = "syringe" + playsound(user.loc, 'syringeproj.ogg', 50, 1) + + for(var/i=0, i<6, i++) + if(D.loc == trg) break + step_towards(D,trg) + + for(var/mob/living/carbon/M in D.loc) + if(!istype(M,/mob/living/carbon)) continue + if(M == user) continue + D.reagents.trans_to(M, 15) + M.bruteloss += 5 + for(var/mob/O in viewers(world.view, D)) + O.show_message(text("\red [] was hit by the syringe!", M), 1) + + del(D) + + for(var/atom/A in D.loc) + if(A == user) continue + if(A.density) del(D) + + sleep(1) + + spawn(10) del(D) + + return + + + +/obj/reagent_dispensers + name = "Dispenser" + desc = "..." + icon = 'objects.dmi' + icon_state = "watertank" + density = 1 + anchored = 0 + flags = FPRINT + pressure_resistance = 2*ONE_ATMOSPHERE + + var/amount_per_transfer_from_this = 10 + + attackby(obj/item/weapon/W as obj, mob/user as mob) + return + + New() + var/datum/reagents/R = new/datum/reagents(1000) + reagents = R + R.my_atom = src + + examine() + set src in view(2) + ..() + usr << "\blue It contains:" + if(!reagents) return + if(reagents.reagent_list.len) + for(var/datum/reagent/R in reagents.reagent_list) + usr << "\blue [R.volume] units of [R.name]" + else + usr << "\blue Nothing." + + ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(50)) + new /obj/effects/water(src.loc) + del(src) + return + if(3.0) + if (prob(5)) + new /obj/effects/water(src.loc) + del(src) + return + else + return + + blob_act() + if(prob(25)) + new /obj/effects/water(src.loc) + del(src) + + + +/obj/item/weapon/reagent_containers + name = "Container" + desc = "..." + icon = 'chemical.dmi' + icon_state = null + w_class = 1 + var/amount_per_transfer_from_this = 5 + + New() + var/datum/reagents/R = new/datum/reagents(50) + reagents = R + R.my_atom = src + + attackby(obj/item/weapon/W as obj, mob/user as mob) + return + attack_self(mob/user as mob) + return + attack(mob/M as mob, mob/user as mob, def_zone) + return + attackby(obj/item/I as obj, mob/user as mob) + return + afterattack(obj/target, mob/user , flag) + return + +//////////////////////////////////////////////////////////////////////////////// +/// (Mixing)Glass. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/glass/ + name = " " + desc = " " + icon = 'chemical.dmi' + icon_state = "null" + item_state = "null" + amount_per_transfer_from_this = 10 + flags = FPRINT | TABLEPASS | OPENCONTAINER + + examine() + set src in view(2) + ..() + usr << "\blue It contains:" + if(!reagents) return + if(reagents.reagent_list.len) + for(var/datum/reagent/R in reagents.reagent_list) + usr << "\blue [R.volume] units of [R.name]" + else + usr << "\blue Nothing." + + New() + var/datum/reagents/R = new/datum/reagents(50) + reagents = R + R.my_atom = src + + afterattack(obj/target, mob/user , flag) + + if(ismob(target) && target.reagents && reagents.total_volume) + user << "\blue You splash the solution onto [target]." + for(var/mob/O in viewers(world.view, user)) + O.show_message(text("\red [] has been splashed with something by []!", target, user), 1) + src.reagents.reaction(target, TOUCH) + spawn(5) src.reagents.clear_reagents() + return + else if(istype(target, /obj/reagent_dispensers)) //A dispenser. Transfer FROM it TO us. + + if(!target.reagents.total_volume && target.reagents) + user << "\red [target] is empty." + return + + if(reagents.total_volume >= reagents.maximum_volume) + user << "\red [src] is full." + return + + var/trans = target.reagents.trans_to(src, 10) + user << "\blue You fill [src] with [trans] units of the contents of [target]." + + else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it. + if(!reagents.total_volume) + user << "\red [src] is empty." + return + + if(target.reagents.total_volume >= target.reagents.maximum_volume) + user << "\red [target] is full." + return + + var/trans = src.reagents.trans_to(target, 10) + user << "\blue You transfer [trans] units of the solution to [target]." + + else if(reagents.total_volume && !istype(target,/obj/machinery/chem_master/) && !istype(target,/obj/table) && !istype(target,/obj/secure_closet) && !istype(target,/obj/closet) && !istype(target,/obj/item/weapon/storage) && !istype(target, /obj/machinery/atmospherics/unary/cryo_cell) && !istype(target, /obj/item/weapon/chem_grenade) && !istype(target, /obj/machinery/bot/medbot)) + user << "\blue You splash the solution onto [target]." + src.reagents.reaction(target, TOUCH) + spawn(5) src.reagents.clear_reagents() + return + +//////////////////////////////////////////////////////////////////////////////// +/// (Mixing)Glass. END +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// Droppers. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/dropper + name = "Dropper" + desc = "A dropper. Transfers 5 units." + icon = 'chemical.dmi' + icon_state = "dropper0" + amount_per_transfer_from_this = 5 + var/filled = 0 + + New() + var/datum/reagents/R = new/datum/reagents(5) + reagents = R + R.my_atom = src + + afterattack(obj/target, mob/user , flag) + if(!target.reagents) return + + if(filled) + + if(target.reagents.total_volume >= target.reagents.maximum_volume) + user << "\red [target] is full." + return + + if(!target.is_open_container() && !ismob(target) && !istype(target,/obj/item/weapon/reagent_containers/food)) //You can inject humans and food but you cant remove the shit. + user << "\red You cannot directly fill this object." + return + + if(ismob(target)) + for(var/mob/O in viewers(world.view, user)) + O.show_message(text("\red [] drips something onto []!", user, target), 1) + src.reagents.reaction(target, TOUCH) + + spawn(5) src.reagents.trans_to(target, 5) + user << "\blue You transfer 5 units of the solution." + filled = 0 + icon_state = "dropper[filled]" + + else + + if(!target.is_open_container() && !istype(target,/obj/reagent_dispensers)) + user << "\red You cannot directly remove reagents from [target]." + return + + if(!target.reagents.total_volume) + user << "\red [target] is empty." + return + + target.reagents.trans_to(src, 5) + + user << "\blue You fill the dropper with 5 units of the solution." + + filled = 1 + icon_state = "dropper[filled]" + + return +//////////////////////////////////////////////////////////////////////////////// +/// Droppers. END +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// Syringes. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/syringe + name = "Syringe" + desc = "A syringe." + icon = 'syringe.dmi' + item_state = "syringe_0" + icon_state = "0" + amount_per_transfer_from_this = 5 + var/mode = "d" + + New() + var/datum/reagents/R = new/datum/reagents(15) + reagents = R + R.maximum_volume = 15 + R.my_atom = src + + on_reagent_change() + update_icon() + + pickup(mob/user) + ..() + update_icon() + + dropped(mob/user) + ..() + update_icon() + + attack_self(mob/user as mob) + switch(mode) + if("d") + mode = "i" + if("i") + mode = "d" + update_icon() + + attack_hand() + ..() + update_icon() + + attack_paw() + return attack_hand() + + attackby(obj/item/I as obj, mob/user as mob) + return + + afterattack(obj/target, mob/user , flag) + if(!target.reagents) return + + switch(mode) + if("d") + if(ismob(target)) return //Blood? + + if(!target.reagents.total_volume) + user << "\red [target] is empty." + return + + if(reagents.total_volume >= reagents.maximum_volume) + user << "\red The syringe is full." + return + + if(!target.is_open_container() && !istype(target,/obj/reagent_dispensers)) + user << "\red You cannot directly remove reagents from this object." + return + + target.reagents.trans_to(src, 5) + + user << "\blue You fill the syringe with 5 units of the solution." + + if("i") + if(!reagents.total_volume) + user << "\red The Syringe is empty." + return + + if(target.reagents.total_volume >= target.reagents.maximum_volume) + user << "\red [target] is full." + return + + if(!target.is_open_container() && !ismob(target) && !istype(target,/obj/item/weapon/reagent_containers/food)) + user << "\red You cannot directly fill this object." + return + + if(ismob(target) && target != user) + for(var/mob/O in viewers(world.view, user)) + O.show_message(text("\red [] is trying to inject []!", user, target), 1) + if(!do_mob(user, target)) return + for(var/mob/O in viewers(world.view, user)) + O.show_message(text("\red [] injects [] with the syringe!", user, target), 1) + src.reagents.reaction(target, INGEST) + if(ismob(target) && target == user) + src.reagents.reaction(target, INGEST) + + spawn(5) + src.reagents.trans_to(target, 5) + user << "\blue You inject 5 units of the solution. The syringe now contains [src.reagents.total_volume] units." + return + + proc + update_icon() + var/rounded_vol = round(reagents.total_volume,5) + if(ismob(loc)) + icon_state = "[mode][rounded_vol]" + else + icon_state = "[rounded_vol]" + item_state = "syringe_[rounded_vol]" + +//////////////////////////////////////////////////////////////////////////////// +/// Syringes. END +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// Snacks. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/food + var/heal_amt = 0 + proc + heal(var/mob/M) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + for(var/A in H.organs) + var/datum/organ/external/affecting = null + if(!H.organs[A]) continue + affecting = H.organs[A] + if(!istype(affecting, /datum/organ/external)) continue + if(affecting.heal_damage(src.heal_amt, src.heal_amt)) + H.UpdateDamageIcon() + else + H.UpdateDamage() + else + M.bruteloss = max(0, M.bruteloss - src.heal_amt) + M.fireloss = max(0, M.fireloss - src.heal_amt) + M.updatehealth() + +/obj/item/weapon/reagent_containers/food/snacks + name = "snack" + desc = "yummy" + icon = 'food.dmi' + icon_state = null + var/amount = 3 + heal_amt = 1 + + New() + var/datum/reagents/R = new/datum/reagents(10) + reagents = R + R.my_atom = src + + attackby(obj/item/weapon/W as obj, mob/user as mob) + return + attack_self(mob/user as mob) + return + attack(mob/M as mob, mob/user as mob, def_zone) + if(!src.amount) + user << "\red None of [src] left, oh no!" + del(src) + return 0 + if(istype(M, /mob/living/carbon/human)) + if(M == user) + M << "\blue You take a bite of [src]." + if(reagents.total_volume) + reagents.reaction(M, INGEST) + spawn(5) + reagents.trans_to(M, reagents.total_volume) + src.amount-- + M.nutrition += src.heal_amt * 10 + M.poo += 0.1 + src.heal(M) + playsound(M.loc,'eatfood.ogg', rand(10,50), 1) + if(!src.amount) + user << "\red You finish eating [src]." + del(src) + return 1 + else + for(var/mob/O in viewers(world.view, user)) + O.show_message("\red [user] attempts to feed [M] [src].", 1) + if(!do_mob(user, M)) return + for(var/mob/O in viewers(world.view, user)) + O.show_message("\red [user] feeds [M] [src].", 1) + + if(reagents.total_volume) + reagents.reaction(M, INGEST) + spawn(5) + reagents.trans_to(M, reagents.total_volume) + src.amount-- + M.nutrition += src.heal_amt * 10 + M.poo += 0.1 + src.heal(M) + playsound(M.loc, 'eatfood.ogg', rand(10,50), 1) + if(!src.amount) + user << "\red [M] finishes eating [src]." + del(src) + return 1 + + + return 0 + + attackby(obj/item/I as obj, mob/user as mob) + return + afterattack(obj/target, mob/user , flag) + return + +//////////////////////////////////////////////////////////////////////////////// +/// Snacks. END +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// Drinks. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/food/drinks + name = "drink" + desc = "yummy" + icon = 'food.dmi' + icon_state = null + flags = FPRINT | TABLEPASS | OPENCONTAINER + var/gulp_size = 5 //This is now officially broken ... need to think of a nice way to fix it. + + New() + var/datum/reagents/R = new/datum/reagents(50) + reagents = R + R.my_atom = src + update_gulp_size() + + proc + update_gulp_size() + gulp_size = round(reagents.total_volume / 5) + if (gulp_size < 5) gulp_size = 5 + + on_reagent_change() + update_gulp_size() + + attackby(obj/item/weapon/W as obj, mob/user as mob) + return + attack_self(mob/user as mob) + return + attack(mob/M as mob, mob/user as mob, def_zone) + var/datum/reagents/R = src.reagents + + if(!R.total_volume || !R) + user << "\red None of [src] left, oh no!" + return 0 + + if(M == user) + M << "\blue You swallow a gulp of [src]." + if(reagents.total_volume) + reagents.reaction(M, INGEST) + spawn(5) + reagents.trans_to(M, gulp_size) + + playsound(M.loc,'drink.ogg', rand(10,50), 1) + M.urine += 0.1 + return 1 + + else if( istype(M, /mob/living/carbon/human) ) + + for(var/mob/O in viewers(world.view, user)) + O.show_message("\red [user] attempts to feed [M] [src].", 1) + if(!do_mob(user, M)) return + for(var/mob/O in viewers(world.view, user)) + O.show_message("\red [user] feeds [M] [src].", 1) + + if(reagents.total_volume) + reagents.reaction(M, INGEST) + spawn(5) + reagents.trans_to(M, gulp_size) + + playsound(M.loc,'drink.ogg', rand(10,50), 1) + M.urine += 0.1 + return 1 + + return 0 + + attackby(obj/item/I as obj, mob/user as mob) + return + + afterattack(obj/target, mob/user , flag) + + if(istype(target, /obj/reagent_dispensers)) //A dispenser. Transfer FROM it TO us. + + if(!target.reagents.total_volume) + user << "\red [target] is empty." + return + + if(reagents.total_volume >= reagents.maximum_volume) + user << "\red [src] is full." + return + + var/trans = target.reagents.trans_to(src, 10) + user << "\blue You fill [src] with [trans] units of the contents of [target]." + + else if(target.is_open_container()) //Something like a glass. Player probably wants to transfer TO it. + if(!reagents.total_volume) + user << "\red [src] is empty." + return + + if(target.reagents.total_volume >= target.reagents.maximum_volume) + user << "\red [target] is full." + return + + var/trans = src.reagents.trans_to(target, 10) + user << "\blue You transfer [trans] units of the solution to [target]." + + return +//////////////////////////////////////////////////////////////////////////////// +/// Drinks. END +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// Pills. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/pill + name = "pill" + desc = "a pill." + icon = 'chemical.dmi' + icon_state = null + item_state = "pill" + + New() + var/datum/reagents/R = new/datum/reagents(100) + reagents = R + R.my_atom = src + icon_state = "pill[rand(1,20)]" + + attackby(obj/item/weapon/W as obj, mob/user as mob) + return + attack_self(mob/user as mob) + return + attack(mob/M as mob, mob/user as mob, def_zone) + if(M == user) + M << "\blue You swallow [src]." + if(reagents.total_volume) + reagents.reaction(M, INGEST) + spawn(5) + reagents.trans_to(M, reagents.total_volume) + del(src) + else + del(src) + return 1 + + else if(istype(M, /mob/living/carbon/human) ) + + for(var/mob/O in viewers(world.view, user)) + O.show_message("\red [user] attempts to force [M] to swallow [src].", 1) + + if(!do_mob(user, M)) return + + for(var/mob/O in viewers(world.view, user)) + O.show_message("\red [user] forces [M] to swallow [src].", 1) + + if(reagents.total_volume) + reagents.reaction(M, INGEST) + spawn(5) + reagents.trans_to(M, reagents.total_volume) + del(src) + else + del(src) + + return 1 + + return 0 + + attackby(obj/item/I as obj, mob/user as mob) + return + + afterattack(obj/target, mob/user , flag) + + if(target.is_open_container() == 1 && target.reagents) + if(!target.reagents.total_volume) + user << "\red [target] is empty. Cant dissolve pill." + return + user << "\blue You dissolve the pill in [target]" + reagents.trans_to(target, reagents.total_volume) + for(var/mob/O in viewers(2, user)) + O.show_message("\red [user] puts something in [target].", 1) + spawn(5) + del(src) + + return + +//////////////////////////////////////////////////////////////////////////////// +/// Pills. END +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// Subtypes. +//////////////////////////////////////////////////////////////////////////////// + +//Glasses +/obj/item/weapon/reagent_containers/glass/bucket + desc = "It's a bucket." + name = "bucket" + icon = 'janitor.dmi' + icon_state = "bucket" + item_state = "bucket" + amount_per_transfer_from_this = 10 + flags = FPRINT | OPENCONTAINER + New() + var/datum/reagents/R = new/datum/reagents(30) + reagents = R + R.my_atom = src + + attackby(var/obj/D, mob/user as mob) + if(istype(D, /obj/item/device/prox_sensor)) + var/obj/item/weapon/bucket_sensor/B = new /obj/item/weapon/bucket_sensor + B.loc = user + if (user.r_hand == D) + user.u_equip(D) + user.r_hand = B + else + user.u_equip(D) + user.l_hand = B + B.layer = 20 + user << "You add the sensor to the bucket" + del(D) + del(src) + +/obj/item/weapon/reagent_containers/glass/dispenser + name = "reagent glass" + desc = "A reagent glass." + icon = 'chemical.dmi' + icon_state = "beaker" + amount_per_transfer_from_this = 10 + flags = FPRINT | TABLEPASS | OPENCONTAINER + + +/obj/item/weapon/reagent_containers/glass/dispenser/surfactant + name = "reagent glass (surfactant)" + icon_state = "liquid" + + New() + ..() + reagents.add_reagent("fluorosurfactant", 20) + + +/obj/item/weapon/reagent_containers/glass/large + name = "large reagent glass" + desc = "A large reagent glass." + icon = 'chemical.dmi' + icon_state = "beakerlarge" + item_state = "beaker" + amount_per_transfer_from_this = 10 + flags = FPRINT | TABLEPASS | OPENCONTAINER + + New() + var/datum/reagents/R = new/datum/reagents(50) + reagents = R + R.my_atom = src + +/obj/item/weapon/reagent_containers/glass/bottle/ + name = "bottle" + desc = "A small bottle." + icon = 'chemical.dmi' + icon_state = "bottle16" + item_state = "atoxinbottle" + amount_per_transfer_from_this = 10 + flags = FPRINT | TABLEPASS | OPENCONTAINER + + New() + var/datum/reagents/R = new/datum/reagents(30) + reagents = R + R.my_atom = src + icon_state = "bottle[rand(1,20)]" + +/obj/item/weapon/reagent_containers/glass/bottle/inaprovaline + name = "inaprovaline bottle" + desc = "A small bottle. Contains inaprovaline - used to stabilize patients." + icon = 'chemical.dmi' + icon_state = "bottle16" + amount_per_transfer_from_this = 10 + + New() + var/datum/reagents/R = new/datum/reagents(30) + reagents = R + R.my_atom = src + R.add_reagent("inaprovaline", 30) + +/obj/item/weapon/reagent_containers/glass/bottle/toxin + name = "toxin bottle" + desc = "A small bottle." + icon = 'chemical.dmi' + icon_state = "bottle12" + amount_per_transfer_from_this = 5 + + New() + var/datum/reagents/R = new/datum/reagents(30) + reagents = R + R.my_atom = src + R.add_reagent("toxin", 30) + +/obj/item/weapon/reagent_containers/glass/bottle/stoxin + name = "sleep-toxin bottle" + desc = "A small bottle." + icon = 'chemical.dmi' + icon_state = "bottle20" + amount_per_transfer_from_this = 5 + + New() + var/datum/reagents/R = new/datum/reagents(30) + reagents = R + R.my_atom = src + R.add_reagent("stoxin", 30) + +/obj/item/weapon/reagent_containers/glass/bottle/antitoxin + name = "anti-toxin bottle" + desc = "A small bottle." + icon = 'chemical.dmi' + icon_state = "bottle17" + amount_per_transfer_from_this = 5 + + New() + var/datum/reagents/R = new/datum/reagents(30) + reagents = R + R.my_atom = src + R.add_reagent("anti_toxin", 30) + + + +/obj/item/weapon/reagent_containers/glass/beaker + name = "beaker" + desc = "A beaker. Can hold up to 30 units." + icon = 'chemical.dmi' + icon_state = "beaker0" + item_state = "beaker" + + on_reagent_change() + if(reagents.total_volume) + icon_state = "beaker1" + else + icon_state = "beaker0" + +/obj/item/weapon/reagent_containers/glass/beaker/cryoxadone + name = "beaker" + desc = "A beaker. Can hold up to 30 units." + icon = 'chemical.dmi' + icon_state = "beaker0" + item_state = "beaker" + + New() + var/datum/reagents/R = new/datum/reagents(30) + reagents = R + R.my_atom = src + R.add_reagent("cryoxadone", 30) + + +//Syringes +/obj/item/weapon/reagent_containers/syringe/robot + name = "Syringe (mixed)" + desc = "Contains inaprovaline & anti-toxins." + New() + var/datum/reagents/R = new/datum/reagents(15) + reagents = R + R.maximum_volume = 15 + R.my_atom = src + R.add_reagent("inaprovaline", 7) + R.add_reagent("anti_toxin", 8) + mode = "i" + update_icon() + +/obj/item/weapon/reagent_containers/syringe/inaprovaline + name = "Syringe (inaprovaline)" + desc = "Contains inaprovaline - used to stabilize patients." + New() + var/datum/reagents/R = new/datum/reagents(15) + reagents = R + R.maximum_volume = 15 + R.my_atom = src + R.add_reagent("inaprovaline", 15) + update_icon() + +/obj/item/weapon/reagent_containers/syringe/antitoxin + name = "Syringe (anti-toxin)" + desc = "Contains anti-toxins." + New() + var/datum/reagents/R = new/datum/reagents(15) + reagents = R + R.maximum_volume = 15 + R.my_atom = src + R.add_reagent("anti_toxin", 15) + update_icon() + +/obj/item/weapon/reagent_containers/syringe/antiviral + name = "Syringe (spaceacillin)" + desc = "Contains antiviral agents." + New() + var/datum/reagents/R = new/datum/reagents(15) + reagents = R + R.maximum_volume = 15 + R.my_atom = src + R.add_reagent("spaceacillin", 15) + update_icon() + +//Snacks +/obj/item/weapon/reagent_containers/food/snacks/candy + name = "candy" + desc = "Man, that shit looks good. I bet it's got nougat. Fuck." + icon_state = "candy" + heal_amt = 1 + +/obj/item/weapon/reagent_containers/food/snacks/chips + name = "chips" + desc = "Commander Riker's What-The-Crisps" + icon_state = "chips" + heal_amt = 1 + +/obj/item/weapon/reagent_containers/food/snacks/donut + name = "donut" + desc = "Goes great with Robust Coffee." + icon_state = "donut1" + heal_amt = 1 + New() + ..() + if(rand(1,3) == 1) + src.icon_state = "donut2" + src.name = "frosted donut" + src.heal_amt = 2 + heal(var/mob/M) + if(istype(M, /mob/living/carbon/human) && M.job in list("Security Officer", "Head of Security", "Detective")) + src.heal_amt *= 2 + ..() + src.heal_amt /= 2 + +/obj/item/weapon/reagent_containers/food/snacks/egg + name = "egg" + desc = "An egg!" + icon_state = "egg" + amount = 1 + heal_amt = 1 + +/obj/item/weapon/reagent_containers/food/snacks/flour + name = "flour" + desc = "Some flour" + icon_state = "flour" + amount = 1 + +/obj/item/weapon/reagent_containers/food/snacks/humanmeat + name = "-meat" + desc = "A slab of meat" + icon_state = "meat" + var/subjectname = "" + var/subjectjob = null + amount = 1 + + +/obj/item/weapon/reagent_containers/food/snacks/assburger + name = "assburger" + desc = "This burger gives off an air of awkwardness." + icon_state = "assburger" + amount = 5 + heal_amt = 2 + +/obj/item/weapon/reagent_containers/food/snacks/brainburger + name = "brainburger" + desc = "A strange looking burger. It looks almost sentient." + icon_state = "brainburger" + amount = 5 + heal_amt = 2 + +/obj/item/weapon/reagent_containers/food/snacks/faggot + name = "faggot" + desc = "A great meal all round." + icon_state = "faggot" + amount = 1 + heal_amt = 2 + heal(var/mob/M) + ..() + +/obj/item/weapon/reagent_containers/food/snacks/donkpocket + name = "donk-pocket" + desc = "The food of choice for the seasoned traitor." + icon_state = "donkpocket" + heal_amt = 1 + amount = 1 + var/warm = 0 + heal(var/mob/M) + if(src.warm && M.reagents) + M.reagents.add_reagent("tricordrazine",15) + else + M << "\red It's just not good enough cold.." + ..() + + proc/cooltime() + if (src.warm) + spawn( 4200 ) + src.warm = 0 + src.name = "donk-pocket" + return + +/obj/item/weapon/reagent_containers/food/snacks/humanburger + name = "-burger" + var/hname = "" + var/job = null + desc = "A bloody burger." + icon_state = "hburger" + amount = 5 + heal_amt = 2 + heal(var/mob/M) + ..() + +/obj/item/weapon/reagent_containers/food/snacks/monkeyburger + name = "monkeyburger" + desc = "The cornerstone of every nutritious breakfast." + icon_state = "mburger" + amount = 5 + heal_amt = 2 + +/obj/item/weapon/reagent_containers/food/snacks/roburger + name = "roburger" + desc = "The lettuce is the only organic component. Beep." + icon_state = "roburger" + New() + var/datum/reagents/R = new/datum/reagents(5) + reagents = R + R.my_atom = src + R.add_reagent("nanites", 5) + +/obj/item/weapon/reagent_containers/food/snacks/xenoburger + name = "xenoburger" + desc = "Smells caustic. Tastes like heresy." + icon_state = "xburger" + New() + var/datum/reagents/R = new/datum/reagents(5) + reagents = R + R.my_atom = src + R.add_reagent("xenomicrobes", 5) + +/obj/item/weapon/reagent_containers/food/snacks/monkeymeat + name = "meat" + desc = "A slab of meat" + icon_state = "meat" + amount = 1 + +/obj/item/weapon/reagent_containers/food/snacks/xenomeat + name = "meat" + desc = "A slab of meat" + icon_state = "xenomeat" + amount = 1 + +/obj/item/weapon/reagent_containers/food/snacks/pie + name = "custard pie" + desc = "It smells delicious. You just want to plant your face in it." + icon_state = "pie" + amount = 3 + +/obj/item/weapon/reagent_containers/food/snacks/waffles + name = "waffles" + desc = "Mmm, waffles" + icon_state = "waffles" + amount = 5 + heal_amt = 2 + +//Drinks +/obj/item/weapon/reagent_containers/food/drinks/coffee + name = "Robust Coffee" + desc = "Careful, the beverage you're about to enjoy is extremely hot." + icon_state = "coffee" + heal_amt = 1 + New() + var/datum/reagents/R = new/datum/reagents(50) + reagents = R + R.my_atom = src + R.add_reagent("coffee", 30) + +/obj/item/weapon/reagent_containers/food/drinks/cola + name = "space cola" + desc = "Cola. in space." + icon_state = "cola" + heal_amt = 1 + New() + var/datum/reagents/R = new/datum/reagents(50) + reagents = R + R.my_atom = src + R.add_reagent("cola", 30) + +/obj/item/weapon/reagent_containers/food/drinks/beer + name = "Space Beer" + desc = "Beer. in space." + icon_state = "beer" + heal_amt = 1 + New() + var/datum/reagents/R = new/datum/reagents(50) + reagents = R + R.my_atom = src + R.add_reagent("beer", 30) + +//Pills +/obj/item/weapon/reagent_containers/pill/antitox + name = "Anti-toxins pill" + desc = "Neutralizes many common toxins." + icon_state = "pill17" + + New() + var/datum/reagents/R = new/datum/reagents(100) + reagents = R + R.my_atom = src + R.add_reagent("anti_toxin", 50) + +/obj/item/weapon/reagent_containers/pill/tox + name = "Toxins pill" + desc = "Highly toxic." + icon_state = "pill5" + + New() + var/datum/reagents/R = new/datum/reagents(100) + reagents = R + R.my_atom = src + R.add_reagent("toxin", 50) + +/obj/item/weapon/reagent_containers/pill/stox + name = "Sleeping pill" + desc = "Commonly used to treat insomnia." + icon_state = "pill8" + + New() + var/datum/reagents/R = new/datum/reagents(100) + reagents = R + R.my_atom = src + R.add_reagent("stoxin", 30) + +/obj/item/weapon/reagent_containers/pill/kelotane + name = "Kelotane pill" + desc = "Used to treat burns." + icon_state = "pill11" + + New() + var/datum/reagents/R = new/datum/reagents(100) + reagents = R + R.my_atom = src + R.add_reagent("kelotane", 30) + +/obj/item/weapon/reagent_containers/pill/inaprovaline + name = "Inaprovaline pill" + desc = "Used to stabilize patients." + icon_state = "pill20" + + New() + var/datum/reagents/R = new/datum/reagents(100) + reagents = R + R.my_atom = src + R.add_reagent("inaprovaline", 30) + +//Dispensers +/obj/reagent_dispensers/watertank + name = "watertank" + desc = "A watertank" + icon = 'objects.dmi' + icon_state = "watertank" + amount_per_transfer_from_this = 10 + + New() + ..() + reagents.add_reagent("water",1000) + +/obj/reagent_dispensers/fueltank + name = "fueltank" + desc = "A fueltank" + icon = 'objects.dmi' + icon_state = "weldtank" + amount_per_transfer_from_this = 10 + + New() + ..() + reagents.add_reagent("fuel",1000) + +/obj/reagent_dispensers/beerkeg + name = "beer keg" + desc = "A beer keg" + icon = 'objects.dmi' + icon_state = "beertankTEMP" + amount_per_transfer_from_this = 10 + + New() + ..() + reagents.add_reagent("beer",1000) + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/code/WorkInProgress/KeelinsStuff.dm b/code/WorkInProgress/KeelinsStuff.dm new file mode 100644 index 0000000000000..6aedd627083ea --- /dev/null +++ b/code/WorkInProgress/KeelinsStuff.dm @@ -0,0 +1,490 @@ +/obj/signpost + icon = 'old_or_unused.dmi' + icon_state = "signpost" + anchored = 1 + density = 1 + + attackby(obj/item/weapon/W as obj, mob/user as mob) + return attack_hand(user) + + attack_hand(mob/user as mob) + switch(alert("Travel back to ss13?",,"Yes","No")) + if("Yes") + user.loc.loc.Exited(user) + user.loc = pick(latejoin) + if("No") + return + +/area/beach + name = "Keelin's private beach" + icon_state = "null" + luminosity = 1 + sd_lighting = 0 + requires_power = 0 + var/sound/mysound = null + + New() + ..() + var/sound/S = new/sound() + mysound = S + S.file = 'shore.ogg' + S.repeat = 1 + S.wait = 0 + S.channel = 123 + S.volume = 100 + S.priority = 255 + S.status = SOUND_UPDATE + process() + + Entered(atom/movable/Obj,atom/OldLoc) + if(ismob(Obj)) + if(Obj:client) + mysound.status = SOUND_UPDATE + Obj << mysound + return + + Exited(atom/movable/Obj) + if(ismob(Obj)) + if(Obj:client) + mysound.status = SOUND_PAUSED | SOUND_UPDATE + Obj << mysound + + proc/process() + set background = 1 + + var/sound/S = null + var/sound_delay = 0 + if(prob(25)) + S = sound(file=pick('seag1.ogg','seag2.ogg','seag3.ogg'), volume=100) + sound_delay = rand(0, 50) + + for(var/mob/living/carbon/human/H in src) + if(H.s_tone > -55) + H.s_tone-- + H.update_body() + if(H.client) + mysound.status = SOUND_UPDATE + H << mysound + if(S) + spawn(sound_delay) + H << S + + spawn(60) .() + +/obj/item/weapon/beach_ball + icon = 'beach.dmi' + icon_state = "ball" + name = "beach ball" + item_state = "clown" + density = 0 + anchored = 0 + w_class = 1.0 + force = 0.0 + throwforce = 0.0 + throw_speed = 1 + throw_range = 20 + flags = FPRINT | USEDELAY | TABLEPASS | CONDUCT + afterattack(atom/target as mob|obj|turf|area, mob/user as mob) + user.drop_item() + src.throw_at(target, throw_range, throw_speed) + +/obj/item/weapon/hand_labeler + icon = 'old_or_unused.dmi' + icon_state = "labeler" + item_state = "flight" + name = "Hand labeler" + var/label = null + var/labels_left = 10 + +/obj/item/weapon/hand_labeler/afterattack(atom/A, mob/user as mob) + if(A==loc) // if placing the labeller into something (e.g. backpack) + return // don't set a label + + if(!labels_left) + user << "\red No labels left." + return + if(!label || !length(label)) + user << "\red No text set." + return + if(length(A.name) + length(label) > 64) + user << "\red Label too big." + return + + for(var/mob/M in viewers()) + M << "\blue [user] puts a label on [A]." + A.name = "[A.name] ([label])" + +/obj/item/weapon/hand_labeler/attack_self() + var/str = input(usr,"Label text?","Set label","") + if(!str || !length(str)) + usr << "\red Invalid text." + return + if(length(str) > 10) + usr << "\red Text too long." + return + label = str + usr << "\blue You set the text to '[str]'." + +/proc/testa() + fake_attack(usr) + +/proc/testb() + fake_attack(input(usr) as mob in world) + +/obj/fake_attacker + icon = null + icon_state = null + name = "" + desc = "" + density = 0 + anchored = 1 + opacity = 0 + var/mob/living/carbon/human/my_target = null + var/weapon_name = null + +/obj/fake_attacker/attackby() + step_away(src,my_target,2) + for(var/mob/M in oviewers(world.view,my_target)) + M << "\red [my_target] flails around wildly." + my_target.show_message("\red [src] has been attacked by [my_target] ", 1) //Lazy. + return + +/obj/fake_attacker/HasEntered(var/mob/M, somenumber) + if(M == my_target) + step_away(src,my_target,2) + if(prob(30)) + for(var/mob/O in oviewers(world.view , my_target)) + O << "\red [my_target] stumbles around." + +/obj/fake_attacker/New() + spawn(300) del(src) + step_away(src,my_target,2) + proccess() + +/obj/fake_attacker/proc/proccess() + if(!my_target) spawn(5) .() + if(get_dist(src,my_target) > 1) + step_towards(src,my_target) + else + if(prob(15)) + if(weapon_name) + my_target << sound(pick('genhit1.ogg', 'genhit2.ogg', 'genhit3.ogg')) + my_target.show_message("\red [my_target] has been attacked with [weapon_name] by [src.name] ", 1) + if(prob(20)) my_target.eye_blurry += 3 + if(prob(33)) + if(!locate(/obj/overlay) in my_target.loc) + fake_blood(my_target) + else + my_target << sound(pick('punch1.ogg','punch2.ogg','punch3.ogg','punch4.ogg')) + my_target.show_message("\red [src.name] has punched [my_target]!", 1) + if(prob(33)) + if(!locate(/obj/overlay) in my_target.loc) + fake_blood(my_target) + + if(prob(15)) step_away(src,my_target,2) + spawn(5) .() + +/proc/fake_blood(var/mob/target) + var/obj/overlay/O = new/obj/overlay(target.loc) + O.name = "blood" + var/image/I = image('blood.dmi',O,"floor[rand(1,7)]",O.dir,1) + target << I + spawn(300) + del(O) + return + +/proc/fake_attack(var/mob/target) + var/list/possible_clones = new/list() + var/mob/living/carbon/human/clone = null + var/clone_weapon = null + + for(var/mob/living/carbon/human/H in world) + if(H.stat || H.lying || H.dir == NORTH) continue + possible_clones += H + + if(!possible_clones.len) return + clone = pick(possible_clones) + + if(clone.l_hand) + clone_weapon = clone.l_hand.name + else if (clone.r_hand) + clone_weapon = clone.r_hand.name + + var/obj/fake_attacker/F = new/obj/fake_attacker(target.loc) + + F.name = clone.name + F.my_target = target + F.weapon_name = clone_weapon + + var/image/O = image(clone,F) + target << O + + +/proc/can_see(var/atom/source, var/atom/target, var/length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate. + var/turf/current = get_turf(source) + var/turf/target_turf = get_turf(target) + var/steps = 0 + + while(current != target_turf) + if(steps > length) return 0 + if(current.opacity) return 0 + for(var/atom/A in current) + if(A.opacity) return 0 + current = get_step_towards(current, target_turf) + steps++ + + return 1 + + +/mob/proc/get_equipped_items() + var/list/items = new/list() + + if(hasvar(src,"back")) if(src:back) items += src:back + if(hasvar(src,"belt")) if(src:belt) items += src:belt + if(hasvar(src,"ears")) if(src:ears) items += src:ears + if(hasvar(src,"glasses")) if(src:glasses) items += src:glasses + if(hasvar(src,"gloves")) if(src:gloves) items += src:gloves + if(hasvar(src,"head")) if(src:head) items += src:head + if(hasvar(src,"shoes")) if(src:shoes) items += src:shoes + if(hasvar(src,"wear_id")) if(src:wear_id) items += src:wear_id + if(hasvar(src,"wear_mask")) if(src:wear_mask) items += src:wear_mask + if(hasvar(src,"wear_suit")) if(src:wear_suit) items += src:wear_suit +// if(hasvar(src,"w_radio")) if(src:w_radio) items += src:w_radio commenting this out since headsets go on your ears now PLEASE DON'T BE MAD KEELIN + if(hasvar(src,"w_uniform")) if(src:w_uniform) items += src:w_uniform + + //if(hasvar(src,"l_hand")) if(src:l_hand) items += src:l_hand + //if(hasvar(src,"r_hand")) if(src:r_hand) items += src:r_hand + + return items + +/proc/is_blocked_turf(var/turf/T) + var/cant_pass = 0 + if(T.density) cant_pass = 1 + for(var/atom/A in T) + if(A.density)//&&A.anchored + cant_pass = 1 + return cant_pass + +/proc/get_step_towards2(var/atom/ref , var/atom/trg) + var/base_dir = get_dir(ref, get_step_towards(ref,trg)) + var/turf/temp = get_step_towards(ref,trg) + + if(is_blocked_turf(temp)) + var/dir_alt1 = turn(base_dir, 90) + var/dir_alt2 = turn(base_dir, -90) + var/turf/turf_last1 = temp + var/turf/turf_last2 = temp + var/free_tile = null + var/breakpoint = 0 + + while(!free_tile && breakpoint < 10) + if(!is_blocked_turf(turf_last1)) + free_tile = turf_last1 + break + if(!is_blocked_turf(turf_last2)) + free_tile = turf_last2 + break + turf_last1 = get_step(turf_last1,dir_alt1) + turf_last2 = get_step(turf_last2,dir_alt2) + breakpoint++ + + if(!free_tile) return get_step(ref, base_dir) + else return get_step_towards(ref,free_tile) + + else return get_step(ref, base_dir) + +/proc/do_mob(var/mob/user , var/mob/target, var/time = 30) //This is quite an ugly solution but i refuse to use the old request system. + if(!user || !target) return 0 + var/user_loc = user.loc + var/target_loc = target.loc + var/holding = user.equipped() + sleep(time) + if ( user.loc == user_loc && target.loc == target_loc && user.equipped() == holding && !( user.stat ) && ( !user.stunned && !user.weakened && !user.paralysis && !user.lying ) ) + return 1 + else + return 0 + +/proc/do_after(mob/M as mob, time as num) + var/turf/T = M.loc + var/holding = M.equipped() + sleep(time) + if ((M.loc == T && M.equipped() == holding && !( M.stat ))) + return 1 + else + return 0 + +/proc/hasvar(var/datum/A, var/varname) + //Takes: Anything that could possibly have variables and a varname to check. + //Returns: 1 if found, 0 if not. + //Notes: Do i really need to explain this? + if(A.vars.Find(lowertext(varname))) return 1 + else return 0 + +/proc/get_areas(var/areatype) + //Takes: Area type as text string or as typepath OR an instance of the area. + //Returns: A list of all areas of that type in the world. + //Notes: Simple! + if(!areatype) return null + if(istext(areatype)) areatype = text2path(areatype) + if(isarea(areatype)) + var/area/areatemp = areatype + areatype = areatemp.type + + var/list/areas = new/list() + for(var/area/N in world) + if(istype(N, areatype)) areas += N + return areas + +/proc/get_area_turfs(var/areatype) + //Takes: Area type as text string or as typepath OR an instance of the area. + //Returns: A list of all turfs in areas of that type of that type in the world. + //Notes: Simple! + + if(!areatype) return null + if(istext(areatype)) areatype = text2path(areatype) + if(isarea(areatype)) + var/area/areatemp = areatype + areatype = areatemp.type + + var/list/turfs = new/list() + for(var/area/N in world) + if(istype(N, areatype)) + for(var/turf/T in N) turfs += T + return turfs + +/proc/get_area_all_atoms(var/areatype) + //Takes: Area type as text string or as typepath OR an instance of the area. + //Returns: A list of all atoms (objs, turfs, mobs) in areas of that type of that type in the world. + //Notes: Simple! + + if(!areatype) return null + if(istext(areatype)) areatype = text2path(areatype) + if(isarea(areatype)) + var/area/areatemp = areatype + areatype = areatemp.type + + var/list/atoms = new/list() + for(var/area/N in world) + if(istype(N, areatype)) + for(var/atom/A in N) + atoms += A + return atoms + +/datum/coords //Simple datum for storing coordinates. + var/x_pos = null + var/y_pos = null + var/z_pos = null + +/area/proc/move_contents_to(var/area/A, var/turftoleave=null) + //Takes: Area. Optional: turf type to leave behind. + //Returns: Nothing. + //Notes: Attempts to move the contents of one area to another area. + // Movement based on lower left corner. Tiles that do not fit + // into the new area will not be moved. + + if(!A || !src) return 0 + + var/list/turfs_src = get_area_turfs(src.type) + var/list/turfs_trg = get_area_turfs(A.type) + + var/src_min_x = 0 + var/src_min_y = 0 + for (var/turf/T in turfs_src) + if(T.x < src_min_x || !src_min_x) src_min_x = T.x + if(T.y < src_min_y || !src_min_y) src_min_y = T.y + + var/trg_min_x = 0 + var/trg_min_y = 0 + for (var/turf/T in turfs_trg) + if(T.x < trg_min_x || !trg_min_x) trg_min_x = T.x + if(T.y < trg_min_y || !trg_min_y) trg_min_y = T.y + + var/list/refined_src = new/list() + for(var/turf/T in turfs_src) + refined_src += T + refined_src[T] = new/datum/coords + var/datum/coords/C = refined_src[T] + C.x_pos = (T.x - src_min_x) + C.y_pos = (T.y - src_min_y) + + var/list/refined_trg = new/list() + for(var/turf/T in turfs_trg) + refined_trg += T + refined_trg[T] = new/datum/coords + var/datum/coords/C = refined_trg[T] + C.x_pos = (T.x - trg_min_x) + C.y_pos = (T.y - trg_min_y) + + var/list/fromupdate = new/list() + var/list/toupdate = new/list() + + moving: + for (var/turf/T in refined_src) + var/datum/coords/C_src = refined_src[T] + for (var/turf/B in refined_trg) + var/datum/coords/C_trg = refined_trg[B] + if(C_src.x_pos == C_trg.x_pos && C_src.y_pos == C_trg.y_pos) + + var/old_dir1 = T.dir + var/old_icon_state1 = T.icon_state + + var/turf/X = new T.type(B) + X.dir = old_dir1 + X.icon_state = old_icon_state1 + + for(var/obj/O in T) + if(!istype(O,/obj)) continue + O.loc = X + for(var/mob/M in T) + if(!istype(M,/mob)) continue + M.loc = X + + var/area/AR = X.loc + + if(AR.sd_lighting) + X.opacity = !X.opacity + X.sd_SetOpacity(!X.opacity) + + toupdate += X + + if(turftoleave) + var/turf/ttl = new turftoleave(T) + + var/area/AR2 = ttl.loc + + if(AR2.sd_lighting) + ttl.opacity = !ttl.opacity + ttl.sd_SetOpacity(!ttl.opacity) + + fromupdate += ttl + + else + T.ReplaceWithSpace() + + refined_src -= T + refined_trg -= B + continue moving + + var/list/doors = new/list() + + if(toupdate.len) + for(var/turf/simulated/T1 in toupdate) + for(var/obj/machinery/door/D2 in T1) + doors += D2 + if(T1.parent) + air_master.groups_to_rebuild += T1.parent + else + air_master.tiles_to_update += T1 + + if(fromupdate.len) + for(var/turf/simulated/T2 in fromupdate) + for(var/obj/machinery/door/D2 in T2) + doors += D2 + if(T2.parent) + air_master.groups_to_rebuild += T2.parent + else + air_master.tiles_to_update += T2 + + for(var/obj/O in doors) + O:update_nearby_tiles(1) + diff --git a/code/WorkInProgress/NewBan.dm b/code/WorkInProgress/NewBan.dm new file mode 100644 index 0000000000000..6982f98e2e2eb --- /dev/null +++ b/code/WorkInProgress/NewBan.dm @@ -0,0 +1,194 @@ +var/CMinutes = null +var/savefile/Banlist + + +/proc/CheckBan(var/client/clientvar) + + var/id = clientvar.computer_id + var/key = clientvar.ckey + + Banlist.cd = "/base" + if (Banlist.dir.Find("[key][id]")) + Banlist.cd = "[key][id]" + if (Banlist["temp"]) + if (!GetExp(Banlist["minutes"])) + ClearTempbans() + return 0 + else + return "[Banlist["reason"]]\n(This ban will be automatically removed in [GetExp(Banlist["minutes"])].)" + else + Banlist.cd = "/base/[key][id]" + return "[Banlist["reason"]]\n(This is a permanent ban)" + + Banlist.cd = "/base" + for (var/A in Banlist.dir) + Banlist.cd = "/base/[A]" + if (id == Banlist["id"] || key == Banlist["key"]) + if(Banlist["temp"]) + if (!GetExp(Banlist["minutes"])) + ClearTempbans() + return 0 + else + return "[Banlist["reason"]]\n(This ban will be automatically removed in [GetExp(Banlist["minutes"])].)" + else + return "[Banlist["reason"]]\n(This is a permanent ban)" + + return 0 + + +/proc/UpdateTime() //No idea why i made this a proc. + CMinutes = (world.realtime / 10) / 60 + return 1 + +/proc/LoadBans() + + Banlist = new("data/banlist.bdb") + log_admin("Loading Banlist") + + if (!length(Banlist.dir)) log_admin("Banlist is empty.") + + if (!Banlist.dir.Find("base")) + log_admin("Banlist missing base dir.") + Banlist.dir.Add("base") + Banlist.cd = "/base" + else if (Banlist.dir.Find("base")) + Banlist.cd = "/base" + + ClearTempbans() + return 1 + +/proc/ClearTempbans() + UpdateTime() + + Banlist.cd = "/base" + for (var/A in Banlist.dir) + Banlist.cd = "/base/[A]" + if (!Banlist["key"] || !Banlist["id"]) + RemoveBan(A) + log_admin("Invalid Ban.") + message_admins("Invalid Ban.") + continue + + if (!Banlist["temp"]) continue + if (CMinutes >= Banlist["minutes"]) RemoveBan(A) + + return 1 + + +/proc/AddBan(ckey, computerid, reason, bannedby, temp, minutes) + + var/bantimestamp + + if (temp) + UpdateTime() + bantimestamp = CMinutes + minutes + + Banlist.cd = "/base" + if ( Banlist.dir.Find("[ckey][computerid]") ) + usr << text("\red Ban already exists.") + return 0 + else + Banlist.dir.Add("[ckey][computerid]") + Banlist.cd = "/base/[ckey][computerid]" + Banlist["key"] << ckey + Banlist["id"] << computerid + Banlist["reason"] << reason + Banlist["bannedby"] << bannedby + Banlist["temp"] << temp + if (temp) + Banlist["minutes"] << bantimestamp + + return 1 + +/proc/RemoveBan(foldername) + var/key + var/id + + Banlist.cd = "/base/[foldername]" + Banlist["key"] >> key + Banlist["id"] >> id + Banlist.cd = "/base" + + if (!Banlist.dir.Remove(foldername)) return 0 + + if(!usr) + log_admin("Ban Expired: [key]") + message_admins("Ban Expired: [key]") + else + log_admin("[key_name_admin(usr)] unbanned [key]") + message_admins("[key_name_admin(usr)] unbanned: [key]") + + for (var/A in Banlist.dir) + Banlist.cd = "/base/[A]" + if (key == Banlist["key"] || id == Banlist["id"]) + Banlist.cd = "/base" + Banlist.dir.Remove(A) + continue + + return 1 + +/proc/GetExp(minutes as num) + UpdateTime() + var/exp = minutes - CMinutes + if (exp <= 0) + return 0 + else + var/timeleftstring + if (exp >= 1440) //1440 = 1 day in minutes + timeleftstring = "[round(exp / 1440, 0.1)] Days" + else if (exp >= 60) //60 = 1 hour in minutes + timeleftstring = "[round(exp / 60, 0.1)] Hours" + else + timeleftstring = "[exp] Minutes" + return timeleftstring + +/obj/admins/proc/unbanpanel() + var/count = 0 + var/dat + //var/dat = "
Unban Player: \blue(U) = Unban , (E) = Edit Ban\green (Total
" + Banlist.cd = "/base" + for (var/A in Banlist.dir) + count++ + Banlist.cd = "/base/[A]" + dat += text("") + + dat += "
(U)(E) Key: [Banlist["key"]] ([Banlist["temp"] ? "[GetExp(Banlist["minutes"]) ? GetExp(Banlist["minutes"]) : "Removal pending" ]" : "Permaban"])(By: [Banlist["bannedby"]])(Reason: [Banlist["reason"]])
" + dat = "
Bans: (U) = Unban , (E) = Edit Ban - ([count] Bans)
[dat]" + usr << browse(dat, "window=unbanp;size=875x400") + +//////////////////////////////////// DEBUG //////////////////////////////////// + +/proc/CreateBans() + + UpdateTime() + + var/i + var/last + + for(i=0, i<1001, i++) + var/a = pick(1,0) + var/b = pick(1,0) + if(b) + Banlist.cd = "/base" + Banlist.dir.Add("trash[i]trashid[i]") + Banlist.cd = "/base/trash[i]trashid[i]" + Banlist["key"] << "trash[i]" + else + Banlist.cd = "/base" + Banlist.dir.Add("[last]trashid[i]") + Banlist.cd = "/base/[last]trashid[i]" + Banlist["key"] << last + Banlist["id"] << "trashid[i]" + Banlist["reason"] << "Trashban[i]." + Banlist["temp"] << a + Banlist["minutes"] << CMinutes + rand(1,2000) + Banlist["bannedby"] << "trashmin" + last = "trash[i]" + + Banlist.cd = "/base" + +/proc/ClearAllBans() + Banlist.cd = "/base" + for (var/A in Banlist.dir) + RemoveBan(A) + diff --git a/code/WorkInProgress/buildmode.dm b/code/WorkInProgress/buildmode.dm new file mode 100644 index 0000000000000..7c89b5533f153 --- /dev/null +++ b/code/WorkInProgress/buildmode.dm @@ -0,0 +1,263 @@ +/proc/togglebuildmode(mob/M as mob in world) + if(M.client) + if(M.client.buildmode) + M.client.buildmode = 0 + M.client.show_popup_menus = 1 + for(var/obj/buildholder/H) + if(H.cl == M.client) + del(H) + else + M.client.buildmode = 1 + M.client.show_popup_menus = 0 + + var/obj/buildholder/H = new/obj/buildholder() + var/obj/builddir/A = new/obj/builddir(H) + A.master = H + var/obj/buildhelp/B = new/obj/buildhelp(H) + B.master = H + var/obj/buildmode/C = new/obj/buildmode(H) + C.master = H + var/obj/buildquit/D = new/obj/buildquit(H) + D.master = H + + H.builddir = A + H.buildhelp = B + H.buildmode = C + H.buildquit = D + M.client.screen += A + M.client.screen += B + M.client.screen += C + M.client.screen += D + H.cl = M.client + +/obj/builddir + density = 1 + anchored = 1 + layer = 20 + dir = NORTH + icon = 'buildmode.dmi' + icon_state = "build" + screen_loc = "NORTH,WEST" + var/obj/buildholder/master = null +/obj/buildhelp + density = 1 + anchored = 1 + layer = 20 + dir = NORTH + icon = 'buildmode.dmi' + icon_state = "buildhelp" + screen_loc = "NORTH,WEST+1" + var/obj/buildholder/master = null +/obj/buildmode + density = 1 + anchored = 1 + layer = 20 + dir = NORTH + icon = 'buildmode.dmi' + icon_state = "buildmode1" + screen_loc = "NORTH,WEST+2" + var/obj/buildholder/master = null + var/varholder = "name" + var/valueholder = "derp" + var/objholder = "/obj/closet" +/obj/buildquit + density = 1 + anchored = 1 + layer = 20 + dir = NORTH + icon = 'buildmode.dmi' + icon_state = "buildquit" + screen_loc = "NORTH,WEST+3" + var/obj/buildholder/master = null + +/obj/buildquit/Click() + togglebuildmode(master.cl.mob) + +/obj/buildholder + density = 0 + anchored = 1 + var/client/cl = null + var/obj/builddir/builddir = null + var/obj/buildhelp/buildhelp = null + var/obj/buildmode/buildmode = null + var/obj/buildquit/buildquit = null + +/obj/builddir/Click() + switch(dir) + if(NORTH) + dir = EAST + if(EAST) + dir = SOUTH + if(SOUTH) + dir = WEST + if(WEST) + dir = NORTHWEST + if(NORTHWEST) + dir = NORTH + +/obj/buildhelp/Click() + switch(master.cl.buildmode) + if(1) + usr << "\blue ***********************************************************" + usr << "\blue Left Mouse Button = Construct / Upgrade" + usr << "\blue Right Mouse Button = Deconstruct / Delete / Downgrade" + usr << "\blue Left Mouse Button + ctrl = R-Window" + usr << "\blue Left Mouse Button + alt = Airlock" + usr << "" + usr << "\blue Use the button in the upper left corner to" + usr << "\blue change the direction of built objects." + usr << "\blue ***********************************************************" + if(2) + usr << "\blue ***********************************************************" + usr << "\blue Right Mouse Button on buildmode button = Set object type" + usr << "\blue Left Mouse Button on turf/obj = Place objects" + usr << "\blue Right Mouse Button = Delete objects" + usr << "" + usr << "\blue Use the button in the upper left corner to" + usr << "\blue change the direction of built objects." + usr << "\blue ***********************************************************" + if(3) + usr << "\blue ***********************************************************" + usr << "\blue Right Mouse Button on buildmode button = Select var(type) & value" + usr << "\blue Left Mouse Button on turf/obj/mob = Set var(type) & value" + usr << "\blue Right Mouse Button on turf/obj/mob = Reset var's value" + usr << "\blue ***********************************************************" + +/obj/buildmode/Click(location, control, params) + var/list/pa = params2list(params) + + if(pa.Find("left")) + switch(master.cl.buildmode) + if(1) + master.cl.buildmode = 2 + src.icon_state = "buildmode2" + if(2) + master.cl.buildmode = 3 + src.icon_state = "buildmode3" + if(3) + master.cl.buildmode = 1 + src.icon_state = "buildmode1" + else if(pa.Find("right")) + switch(master.cl.buildmode) + if(1) + return + if(2) + objholder = input(usr,"Enter typepath:" ,"Typepath","/obj/closet") + var/list/removed_paths = list("/obj/bhole") + if(objholder in removed_paths) + alert("That path is not allowed.") + objholder = "/obj/closet" + else if (dd_hasprefix(objholder, "/mob") && !(usr.client.holder.rank in list("Host", "Coder", "Shit Guy"))) + objholder = "/obj/closet" + if(3) + var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "cuffed", "ka", "last_eaten", "urine") + + master.buildmode.varholder = input(usr,"Enter variable name:" ,"Name", "name") + if(master.buildmode.varholder in locked && !(usr.client.holder.rank in list("Host", "Coder"))) + return + var/thetype = input(usr,"Select variable type:" ,"Type") in list("text","number","mob-reference","obj-reference","turf-reference") + if(!thetype) return + switch(thetype) + if("text") + master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value", "value") as text + if("number") + master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value", 123) as num + if("mob-reference") + master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as mob in world + if("obj-reference") + master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as obj in world + if("turf-reference") + master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as turf in world + + +/proc/build_click(var/mob/user, buildmode, location, control, params, var/obj/object) + + var/obj/buildholder/holder = null + + for(var/obj/buildholder/H) + if(H.cl == user.client) + holder = H + break + + if(!holder) return + var/list/pa = params2list(params) + + + switch(buildmode) + + if(1) + if(istype(object,/turf) && pa.Find("left") && !pa.Find("alt") && !pa.Find("ctrl") ) + if(istype(object,/turf/space)) + var/turf/T = object + T.ReplaceWithFloor() + return + else if(istype(object,/turf/simulated/floor)) + var/turf/T = object + T.ReplaceWithWall() + return + else if(istype(object,/turf/simulated/wall)) + var/turf/T = object + T.ReplaceWithRWall() + return + + else if(pa.Find("right")) + if(istype(object,/turf/simulated/wall)) + var/turf/T = object + T.ReplaceWithFloor() + return + else if(istype(object,/turf/simulated/floor)) + var/turf/T = object + T.ReplaceWithSpace() + return + else if(istype(object,/turf/simulated/wall/r_wall)) + var/turf/T = object + T.ReplaceWithWall() + return + else if(istype(object,/obj)) + del(object) + return + + else if(istype(object,/turf) && pa.Find("alt") && pa.Find("left")) + new/obj/machinery/door/airlock(get_turf(object)) + + else if(istype(object,/turf) && pa.Find("ctrl") && pa.Find("left")) + switch(holder.builddir.dir) + if(NORTH) + new/obj/window/reinforced/north(get_turf(object)) + if(EAST) + new/obj/window/reinforced/east(get_turf(object)) + if(SOUTH) + new/obj/window/reinforced/south(get_turf(object)) + if(WEST) + new/obj/window/reinforced/west(get_turf(object)) + if(NORTHWEST) + new/obj/window/reinforced/northwest(get_turf(object)) + if(2) + if(pa.Find("left")) + var/obj/A = new holder.buildmode.objholder (get_turf(object)) + A.dir = holder.builddir.dir + blink(A) + else if(pa.Find("right")) + if(isobj(object)) del(object) + + if(3) + if(pa.Find("left")) //I cant believe this shit actually compiles. + if(object.vars.Find(holder.buildmode.varholder)) + log_admin("[key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]") +// message_admins("[key_name_admin(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]", 1) + object.vars[holder.buildmode.varholder] = holder.buildmode.valueholder + blink(object) + else + usr << "\red [initial(object.name)] does not have a var called '[holder.buildmode.varholder]'" + if(pa.Find("right")) + if(object.vars.Find(holder.buildmode.varholder)) + log_admin("[key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]") +// message_admins("[key_name_admin(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]", 1) + object.vars[holder.buildmode.varholder] = initial(object.vars[holder.buildmode.varholder]) + blink(object) + else + usr << "\red [initial(object.name)] does not have a var called '[holder.buildmode.varholder]'" + +/proc/blink(atom/A) + A.icon += rgb(0,75,75) + spawn(10) A.icon = initial(A.icon) diff --git a/code/WorkInProgress/cloning.dm b/code/WorkInProgress/cloning.dm new file mode 100644 index 0000000000000..5773944178f30 --- /dev/null +++ b/code/WorkInProgress/cloning.dm @@ -0,0 +1,724 @@ +//Cloning revival method. +//The pod handles the actual cloning while the computer manages the clone profiles + +//Potential replacement for genetics revives or something I dunno (?) + +/obj/machinery/clonepod + anchored = 1 + name = "cloning pod" + desc = "An electronically-lockable pod for growing organic tissue." + density = 1 + icon = 'cloning.dmi' + icon_state = "pod_0" + req_access = list(access_medlab) //For premature unlocking. + var/mob/living/occupant + var/heal_level = 90 //The clone is released once its health reaches this level. + var/locked = 0 + var/obj/machinery/computer/cloning/connected = null //So we remember the connected clone machine. + var/mess = 0 //Need to clean out it if it's full of exploded clone. + var/attempting = 0 //One clone attempt at a time thanks + var/eject_wait = 0 //Don't eject them as soon as they are created fuckkk + +/obj/machinery/computer/cloning + name = "Cloning console" + icon = 'computer.dmi' + icon_state = "dna" + req_access = list(access_heads) //Only used for record deletion right now. + var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning. + var/obj/machinery/clonepod/pod1 = null //Linked cloning pod. + var/temp = "Initializing System..." + var/menu = 1 //Which menu screen to display + var/list/records = list() + var/datum/data/record/active_record = null + var/obj/item/weapon/disk/data/diskette = null //Mostly so the geneticist can steal everything. + +//The return of data disks?? Just for transferring between genetics machine/cloning machine. +//TO-DO: Make the genetics machine accept them. +/obj/item/weapon/disk/data + name = "data disk" + icon = 'cloning.dmi' + icon_state = "datadisk0" //Gosh I hope syndies don't mistake them for the nuke disk. + item_state = "card-id" + w_class = 1.0 + var/data = "" + var/ue = 0 + var/data_type = "ui" //ui|se + var/owner = "God Emperor of Mankind" + var/read_only = 0 //Well,it's still a floppy disk + +/obj/item/weapon/disk/data/demo + name = "data disk - 'God Emperor of Mankind'" + data = "066000033000000000AF00330660FF4DB002690" + //data = "0C80C80C80C80C80C8000000000000161FBDDEF" - Farmer Jeff + ue = 1 + read_only = 1 + +/obj/item/weapon/disk/data/monkey + name = "data disk - 'Mr. Muggles'" + data_type = "se" + data = "0983E840344C39F4B059D5145FC5785DC6406A4FFF" + read_only = 1 + +/obj/machinery/computer/cloning/New() + ..() + spawn(5) + src.scanner = locate(/obj/machinery/dna_scannernew, get_step(src, WEST)) + src.pod1 = locate(/obj/machinery/clonepod, get_step(src, EAST)) + + src.temp = "" + if (isnull(src.scanner)) + src.temp += " SCNR-ERROR" + if (isnull(src.pod1)) + src.temp += " POD1-ERROR" + else + src.pod1.connected = src + + if (src.temp == "") + src.temp = "System ready." + return + return + +/obj/machinery/computer/cloning/attackby(obj/item/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/disk/data)) //INSERT SOME DISKETTES + if (!src.diskette) + user.drop_item() + W.loc = src + src.diskette = W + user << "You insert [W]." + src.updateUsrDialog() + return + else if((istype(W, /obj/item/weapon/screwdriver)) && (src.stat & BROKEN)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/cloning/M = new /obj/item/weapon/circuitboard/cloning( A ) + for (var/obj/C in src) + C.loc = src.loc + M.records = src.records + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + +/obj/machinery/computer/cloning/attack_paw(mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/cloning/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/cloning/attack_hand(mob/user as mob) + user.machine = src + add_fingerprint(user) + + if(stat & (BROKEN|NOPOWER)) + return + + var/dat = "

Cloning System Control

" + dat += "Refresh" + + dat += "
[temp]
" + + switch(src.menu) + if(1) + dat += "

Scanner Functions

" + + if (isnull(src.scanner)) + dat += "No scanner connected!" + else + if (src.scanner.occupant) + dat += "Scan - [src.scanner.occupant]" + else + dat += "Scanner unoccupied" + + dat += "
Lock status: [src.scanner.locked ? "Locked" : "Unlocked"]" + + dat += "

Database Functions

" + dat += "View Records
" + if (src.diskette) + dat += "Eject Disk" + + + if(2) + dat += "

Current records

" + dat += "Back

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

Selected Record

" + dat += "Back
" + + if (!src.active_record) + dat += "ERROR: Record not found." + else + dat += "
Delete Record
" + dat += "Name: [src.active_record.fields["name"]]
" + + var/obj/item/weapon/implant/health/H = locate(src.active_record.fields["imp"]) + + if ((H) && (istype(H))) + dat += "Health: [H.sensehealth()] | OXY-BURN-TOX-BRUTE
" + else + dat += "Unable to locate implant.
" + + if (!isnull(src.diskette)) + dat += "Load from disk." + + dat += " | Save: UI + UE" + dat += " | Save: UI" + dat += " | Save: SE" + dat += "
" + else + dat += "
" //Keeping a line empty for appearances I guess. + + dat += {"UI: [src.active_record.fields["UI"]]
+ SE: [src.active_record.fields["SE"]]

+ Clone
"} + + if(4) + if (!src.active_record) + src.menu = 2 + dat = "[src.temp]
" + dat += "

Confirm Record Deletion

" + + dat += "Scan card to confirm.
" + dat += "No" + + + user << browse(dat, "window=cloning") + onclose(user, "cloning") + return + +/obj/machinery/computer/cloning/Topic(href, href_list) + if(..()) + return + + if ((href_list["scan"]) && (!isnull(src.scanner))) + src.scan_mob(src.scanner.occupant) + + //No locking an open scanner. + else if ((href_list["lock"]) && (!isnull(src.scanner))) + if ((!src.scanner.locked) && (src.scanner.occupant)) + src.scanner.locked = 1 + else + src.scanner.locked = 0 + + else if (href_list["view_rec"]) + src.active_record = locate(href_list["view_rec"]) + if ((isnull(src.active_record.fields["ckey"])) || (src.active_record.fields["ckey"] == "")) + del(src.active_record) + src.temp = "ERROR: Record Corrupt" + else + src.menu = 3 + + else if (href_list["del_rec"]) + if ((!src.active_record) || (src.menu < 3)) + return + if (src.menu == 3) //If we are viewing a record, confirm deletion + src.temp = "Delete record?" + src.menu = 4 + + else if (src.menu == 4) + var/obj/item/weapon/card/id/C = usr.equipped() + if (istype(C)) + if(src.check_access(C)) + src.records.Remove(src.active_record) + del(src.active_record) + src.temp = "Record deleted." + src.menu = 2 + else + src.temp = "Access Denied." + + else if (href_list["disk"]) //Load or eject. + switch(href_list["disk"]) + if("load") + if ((isnull(src.diskette)) || (src.diskette.data == "")) + src.temp = "Load error." + src.updateUsrDialog() + return + if (isnull(src.active_record)) + src.temp = "Record error." + src.menu = 1 + src.updateUsrDialog() + return + + if (src.diskette.data_type == "ui") + src.active_record.fields["UI"] = src.diskette.data + if (src.diskette.ue) + src.active_record.fields["name"] = src.diskette.owner + else if (src.diskette.data_type == "se") + src.active_record.fields["SE"] = src.diskette.data + + src.temp = "Load successful." + if("eject") + if (!isnull(src.diskette)) + src.diskette.loc = src.loc + src.diskette = null + + else if (href_list["save_disk"]) //Save to disk! + if ((isnull(src.diskette)) || (src.diskette.read_only) || (isnull(src.active_record))) + src.temp = "Save error." + src.updateUsrDialog() + return + + switch(href_list["save_disk"]) //Save as Ui/Ui+Ue/Se + if("ui") + src.diskette.data = src.active_record.fields["UI"] + src.diskette.ue = 0 + src.diskette.data_type = "ui" + if("ue") + src.diskette.data = src.active_record.fields["UI"] + src.diskette.ue = 1 + src.diskette.data_type = "ui" + if("se") + src.diskette.data = src.active_record.fields["SE"] + src.diskette.ue = 0 + src.diskette.data_type = "se" + src.diskette.owner = src.active_record.fields["name"] + src.diskette.name = "data disk - '[src.diskette.owner]'" + src.temp = "Save \[[href_list["save_disk"]]\] successful." + + else if (href_list["refresh"]) + src.updateUsrDialog() + + else if (href_list["clone"]) + var/datum/data/record/C = locate(href_list["clone"]) + //Look for that player! They better be dead! + var/mob/selected = find_dead_player("[C.fields["ckey"]]") + +//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs. + if ((!selected) || (!src.pod1) || (src.pod1.occupant) || (src.pod1.mess)) + src.temp = "Unable to initiate cloning cycle." // most helpful error message in THE HISTORY OF THE WORLD + else if (src.pod1.growclone(selected, C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"])) + src.temp = "Cloning cycle activated." + src.records.Remove(C) + del(C) + src.menu = 1 + + else if (href_list["menu"]) + src.menu = text2num(href_list["menu"]) + + src.add_fingerprint(usr) + src.updateUsrDialog() + return + +/obj/machinery/computer/cloning/proc/scan_mob(mob/living/carbon/human/subject as mob) + if ((isnull(subject)) || (!istype(subject, /mob/living/carbon/human)) || (!subject.dna)) + src.temp = "Error: Unable to locate valid genetic data." + return + if ((!subject.ckey) || (!subject.client)) + src.temp = "Error: Mental interface failure." + return + if (!isnull(find_record(subject.ckey))) + src.temp = "Subject already in database." + return + + subject.dna.check_integrity() + + var/datum/data/record/R = new /datum/data/record( ) + R.fields["ckey"] = subject.ckey + R.fields["name"] = subject.real_name + R.fields["id"] = copytext(md5(subject.real_name), 2, 6) + R.fields["UI"] = subject.dna.uni_identity + R.fields["SE"] = subject.dna.struc_enzymes + + //Add an implant if needed + var/obj/item/weapon/implant/health/imp =locate(/obj/item/weapon/implant/health, subject) + if (isnull(imp)) + imp = new /obj/item/weapon/implant/health(subject) + imp.implanted = subject + R.fields["imp"] = "\ref[imp]" + //Update it if needed + else + R.fields["imp"] = "\ref[imp]" + + if (!isnull(subject.mind)) //Save that mind so traitors can continue traitoring after cloning. + R.fields["mind"] = "\ref[subject.mind]" + + src.records += R + src.temp = "Subject successfully scanned." + +//Find a specific record by key. +/obj/machinery/computer/cloning/proc/find_record(var/find_key) + var/selected_record = null + for(var/datum/data/record/R in src.records) + if (R.fields["ckey"] == find_key) + selected_record = R + break + return selected_record + +/obj/machinery/computer/cloning/power_change() + + if(stat & BROKEN) + icon_state = "commb" + else + if( powered() ) + icon_state = initial(icon_state) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + src.icon_state = "c_unpowered" + stat |= NOPOWER + + +//Find a dead mob with a brain and client. +/proc/find_dead_player(var/find_key) + if (isnull(find_key)) + return + + var/mob/selected = null + for(var/mob/M in world) + //Dead people only thanks! + if ((M.stat != 2) || (!M.client)) + continue + //They need a brain! + if ((istype(M, /mob/living/carbon/human)) && (M:brain_op_stage >= 4.0)) + continue + + if (M.ckey == find_key) + selected = M + break + return selected + +//Disk stuff. +/obj/item/weapon/disk/data/New() + ..() + var/diskcolor = pick(0,1,2) + src.icon_state = "datadisk[diskcolor]" + +/obj/item/weapon/disk/data/attack_self(mob/user as mob) + src.read_only = !src.read_only + user << "You flip the write-protect tab to [src.read_only ? "protected" : "unprotected"]." + +/obj/item/weapon/disk/data/examine() + set src in oview(5) + ..() + usr << text("The write-protect tab is set to [src.read_only ? "protected" : "unprotected"].") + return + +//Health Tracker Implant + +/obj/item/weapon/implant/health + name = "health implant" + var/healthstring = "" + +/obj/item/weapon/implant/health/proc/sensehealth() + if (!src.implanted) + return "ERROR" + else + src.healthstring = "[round(src.implanted:oxyloss)] - [round(src.implanted:fireloss)] - [round(src.implanted:toxloss)] - [round(src.implanted:bruteloss)]" + if (!src.healthstring) + src.healthstring = "ERROR" + return src.healthstring + +/obj/machinery/clonepod/attack_ai(mob/user as mob) + return attack_hand(user) +/obj/machinery/clonepod/attack_paw(mob/user as mob) + return attack_hand(user) +/obj/machinery/clonepod/attack_hand(mob/user as mob) + if ((isnull(src.occupant)) || (stat & NOPOWER)) + return + if ((!isnull(src.occupant)) && (src.occupant.stat != 2)) + var/completion = (100 * ((src.occupant.health + 100) / (src.heal_level + 100))) + user << "Current clone cycle is [round(completion)]% complete." + return + +//Clonepod + +//Start growing a human clone in the pod! +/obj/machinery/clonepod/proc/growclone(mob/ghost as mob, var/clonename, var/ui, var/se, var/mindref) + if (((!ghost) || (!ghost.client)) || src.mess || src.attempting) + return 0 + + src.attempting = 1 //One at a time!! + src.locked = 1 + + src.eject_wait = 1 + spawn(30) + src.eject_wait = 0 + + src.occupant = new /mob/living/carbon/human(src) + ghost.client.mob = src.occupant + + src.icon_state = "pod_1" + //Get the clone body ready + src.occupant.rejuv = 10 + src.occupant.bruteloss += 90 + src.occupant.toxloss += 50 + src.occupant.oxyloss += 40 + src.occupant.brainloss += 90 + src.occupant.paralysis += 4 + + //Here let's calculate their health so the pod doesn't immediately eject them!!! + src.occupant.health = (src.occupant.bruteloss + src.occupant.toxloss + src.occupant.oxyloss) + + src.occupant << "\blue Clone generation process initiated." + src.occupant << "\blue This will take a moment, please hold." + + if (clonename) + src.occupant.real_name = clonename + else + src.occupant.real_name = "clone" //No null names!! + + var/datum/mind/clonemind = (locate(mindref) in ticker.minds) + + if ((clonemind) && (istype(clonemind))) //Move that mind over!! + clonemind.transfer_to(src.occupant) + else //welp + src.occupant.mind = new /datum/mind( ) + src.occupant.mind.key = src.occupant.key + src.occupant.mind.current = src.occupant + src.occupant.mind.transfer_to(src.occupant) + ticker.minds += src.occupant.mind + + // -- Mode/mind specific stuff goes here + switch(ticker.mode.name) + if ("revolution") + if ((src.occupant.mind in ticker.mode:revolutionaries) || (src.occupant.mind in ticker.mode:head_revolutionaries)) + ticker.mode:add_revolutionary(src.occupant.mind) + ticker.mode:update_all_rev_icons() //So the icon actually appears + + // -- End mode specific stuff + + if (istype(ghost, /mob/dead/observer)) + del(ghost) //Don't leave ghosts everywhere!! + + if (!src.occupant.dna) + src.occupant.dna = new /datum/dna( ) + if (ui) + src.occupant.dna.uni_identity = ui + updateappearance(src.occupant, ui) + if (se) + src.occupant.dna.struc_enzymes = se + randmutb(src.occupant) //Sometimes the clones come out wrong. + + src.attempting = 0 + return 1 + +//Grow clones to maturity then kick them out. FREELOADERS +/obj/machinery/clonepod/process() + + if (stat & NOPOWER) //Autoeject if power is lost + if (src.occupant) + src.locked = 0 + src.go_out() + return + + if ((src.occupant) && (src.occupant.loc == src)) + if((src.occupant.stat == 2) || (src.occupant.suiciding)) //Autoeject corpses and suiciding dudes. + src.locked = 0 + src.go_out() + src.connected_message("Clone Rejected: Deceased.") + return + + else if(src.occupant.health < src.heal_level) + src.occupant.paralysis = 4 + + //Slowly get that clone healed and finished. + src.occupant.bruteloss = max(src.occupant.bruteloss-1, 0) + + //At this rate one clone takes about 95 seconds to produce.(with heal_level 90) + src.occupant.toxloss = max(src.occupant.toxloss-0.5, 0) + + //Premature clones may have brain damage. + src.occupant.brainloss = max(src.occupant.brainloss-1, 0) + + //So clones don't die of oxyloss in a running pod. + if (src.occupant.reagents.get_reagent_amount("inaprovaline") < 30) + src.occupant.reagents.add_reagent("inaprovaline", 60) + + //Also heal some oxyloss ourselves because inaprovaline is so bad at preventing it!! + src.occupant.oxyloss = max(src.occupant.oxyloss-2, 0) + + //Stop baking in the tubes you jerks. + src.occupant.fireloss = max(src.occupant.fireloss-2, 0) + + use_power(7500) //This might need tweaking. + return + + else if((src.occupant.health >= src.heal_level) && (!src.eject_wait)) + src.connected_message("Cloning Process Complete.") + src.locked = 0 + src.go_out() + return + + else if ((!src.occupant) || (src.occupant.loc != src)) + src.occupant = null + if (src.locked) + src.locked = 0 + if (!src.mess) + icon_state = "pod_0" + use_power(200) + return + + return + +//Let's unlock this early I guess. Might be too early, needs tweaking. +/obj/machinery/clonepod/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/card/id)) + if (!src.check_access(W)) + user << "\red Access Denied." + return + if ((!src.locked) || (isnull(src.occupant))) + return + if ((src.occupant.health < -20) && (src.occupant.stat != 2)) + user << "\red Access Refused." + return + else + src.locked = 0 + user << "System unlocked." + else if (istype(W, /obj/item/weapon/card/emag)) + if (isnull(src.occupant)) + return + user << "You force an emergency ejection." + src.locked = 0 + src.go_out() + return + else + ..() + +//Put messages in the connected computer's temp var for display. +/obj/machinery/clonepod/proc/connected_message(var/message) + if ((isnull(src.connected)) || (!istype(src.connected, /obj/machinery/computer/cloning))) + return 0 + if (!message) + return 0 + + src.connected.temp = message + src.connected.updateUsrDialog() + return 1 + +/obj/machinery/clonepod/verb/eject() + set src in oview(1) + + if (usr.stat != 0) + return + src.go_out() + add_fingerprint(usr) + return + +/obj/machinery/clonepod/proc/go_out() + if (src.locked) + return + + if (src.mess) //Clean that mess and dump those gibs! + src.mess = 0 + gibs(src.loc) + src.icon_state = "pod_0" + for(var/obj/O in src) + O.loc = src.loc + return + + if (!(src.occupant)) + return + for(var/obj/O in src) + O.loc = src.loc + + if (src.occupant.client) + src.occupant.client.eye = src.occupant.client.mob + src.occupant.client.perspective = MOB_PERSPECTIVE + src.occupant.loc = src.loc + src.icon_state = "pod_0" + src.eject_wait = 0 //If it's still set somehow. + domutcheck(src.occupant) //Waiting until they're out before possible monkeyizing. + src.occupant = null + return + +/obj/machinery/clonepod/proc/malfunction() + if (src.occupant) + src.connected_message("Critical Error!") + src.mess = 1 + src.icon_state = "pod_g" + src.occupant.ghostize() + spawn(5) + del(src.occupant) + return + +/obj/machinery/clonepod/relaymove(mob/user as mob) + if (user.stat) + return + src.go_out() + return + +/obj/machinery/clonepod/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + if(3.0) + if (prob(25)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + else + return + +/* + * Diskette Box + */ +/obj/item/weapon/storage/diskbox + name = "Diskette Box" + icon_state = "disk_kit" + item_state = "syringe_kit" + +/obj/item/weapon/storage/diskbox/New() + ..() + new /obj/item/weapon/disk/data(src) + new /obj/item/weapon/disk/data(src) + new /obj/item/weapon/disk/data(src) + new /obj/item/weapon/disk/data(src) + new /obj/item/weapon/disk/data(src) + new /obj/item/weapon/disk/data(src) + new /obj/item/weapon/disk/data(src) + +/* + * Manual -- A big ol' manual. + */ + +/obj/item/weapon/paper/Cloning + name = "paper - 'H-87 Cloning Apparatus Manual" + info = {"

Getting Started

+ Congratulations, your station has purchased the H-87 industrial cloning device!
+ Using the H-87 is almost as simple as brain surgery! Simply insert the target humanoid into the scanning chamber and select the scan option to create a new profile!
+ That's all there is to it!
+ Notice, cloning system cannot scan inorganic life or small primates. Scan may fail if subject has suffered extreme brain damage.
+

Clone profiles may be viewed through the profiles menu. Scanning implants a complementary HEALTH MONITOR IMPLANT into the subject, which may be viewed from each profile. + Profile Deletion has been restricted to \[Station Head\] level access.

+

Cloning from a profile

+ Cloning is as simple as pressing the CLONE option at the bottom of the desired profile.
+ Per your company's EMPLOYEE PRIVACY RIGHTS agreement, the H-87 has been blocked from cloning crewmembers while they are still alive.
+
+

The provided CLONEPOD SYSTEM will produce the desired clone. Standard clone maturation times (With SPEEDCLONE technology) are roughly 90 seconds. + The cloning pod may be unlocked early with any \[Medical Researcher\] ID after initial maturation is complete.


+ Please note that resulting clones may have a small DEVELOPMENTAL DEFECT as a result of genetic drift.
+

Profile Management

+

The H-87 (as well as your station's standard genetics machine) can accept STANDARD DATA DISKETTES. + These diskettes are used to transfer genetic information between machines and profiles. + A load/save dialog will become available in each profile if a disk is inserted.


+ A good diskette is a great way to counter aforementioned genetic drift!
+
+ This technology produced under license from Thinktronic Systems, LTD."} + +//SOME SCRAPS I GUESS +/* EMP grenade/spell effect + if(istype(A, /obj/machinery/clonepod)) + A:malfunction() +*/ \ No newline at end of file diff --git a/code/WorkInProgress/computer2/airlock_control.dm b/code/WorkInProgress/computer2/airlock_control.dm new file mode 100644 index 0000000000000..e14dca1e63017 --- /dev/null +++ b/code/WorkInProgress/computer2/airlock_control.dm @@ -0,0 +1,60 @@ +/datum/computer/file/computer_program/airlock_control + name = "Airlock Master" + size = 16.0 + id_tag = "TAG" + + + return_text() + if(..()) + return + + var/dat = "Close | " + dat += "Quit" + + /* + dat += "
Frequency: " + dat += "-- " + dat += "- " + dat += "[format_frequency(src.master.frequency)] " + dat += "+ " + dat += "++" + dat += "
" + */ + + + dat += "
ID:[src.id_tag]
" + + dat += "Cycle" + + + dat += "" + + return dat + + Topic(href, href_list) + if(..()) + return + + if(href_list["set_tag"]) + var/t = input(usr, "Please enter new tag", src.id_tag, null) as text + t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN) + if (!t) + return + if (!in_range(src.master, usr)) + return + + src.id_tag = t + +// if(href_list["adj_freq"]) +// var/new_frequency = (src.master.frequency + text2num(href_list["adj_freq"])) +// src.master.set_frequency(new_frequency) + + if(href_list["send_command"]) + var/datum/signal/signal = new + signal.data["tag"] = id_tag + signal.data["command"] = href_list["send_command"] + peripheral_command("send signal", signal) + + src.master.add_fingerprint(usr) + src.master.updateUsrDialog() + return \ No newline at end of file diff --git a/code/WorkInProgress/computer2/arcade.dm b/code/WorkInProgress/computer2/arcade.dm new file mode 100644 index 0000000000000..591402c04fabc --- /dev/null +++ b/code/WorkInProgress/computer2/arcade.dm @@ -0,0 +1,136 @@ +/datum/computer/file/computer_program/arcade + name = "Arcade 500" + size = 8.0 + var/enemy_name = "Space Villian" + var/temp = "Winners Don't Use Spacedrugs" //Temporary message, for attack messages, etc + var/player_hp = 30 //Player health/attack points + var/player_mp = 10 + var/enemy_hp = 45 //Enemy health/attack points + var/enemy_mp = 20 + var/gameover = 0 + var/blocked = 0 //Player cannot attack/heal while set + + New(obj/holding as obj) + if(holding) + src.holder = holding + + if(istype(src.holder.loc,/obj/machinery/computer2)) + src.master = src.holder.loc + +// var/name_action = pick("Defeat ", "Annihilate ", "Save ", "Strike ", "Stop ", "Destroy ", "Robust ", "Romance ") + + var/name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Evil ", "the Dread King ", "the Space ", "Lord ") + var/name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon") + + src.enemy_name = dd_replacetext((name_part1 + name_part2), "the ", "") +// src.name = (name_action + name_part1 + name_part2) + + + +/datum/computer/file/computer_program/arcade/return_text() + if(..()) + return + + var/dat = "Close | " + dat += "Quit" + + dat += "

[src.enemy_name]

" + + dat += "

[src.temp]

" + dat += "
Health: [src.player_hp] | Magic: [src.player_mp] | Enemy Health: [src.enemy_hp]
" + + if (src.gameover) + dat += "
New Game" + else + dat += "
Attack | " + dat += "Heal | " + dat += "Recharge Power" + + dat += "
" + + return dat + +/datum/computer/file/computer_program/arcade/Topic(href, href_list) + if(..()) + return + + if (!src.blocked) + if (href_list["attack"]) + src.blocked = 1 + var/attackamt = rand(2,6) + src.temp = "You attack for [attackamt] damage!" + src.master.updateUsrDialog() + + sleep(10) + src.enemy_hp -= attackamt + src.arcade_action() + + else if (href_list["heal"]) + src.blocked = 1 + var/pointamt = rand(1,3) + var/healamt = rand(6,8) + src.temp = "You use [pointamt] magic to heal for [healamt] damage!" + src.master.updateUsrDialog() + + sleep(10) + src.player_mp -= pointamt + src.player_hp += healamt + src.blocked = 1 + src.master.updateUsrDialog() + src.arcade_action() + + else if (href_list["charge"]) + src.blocked = 1 + var/chargeamt = rand(4,7) + src.temp = "You regain [chargeamt] points" + src.player_mp += chargeamt + + src.master.updateUsrDialog() + sleep(10) + src.arcade_action() + + if (href_list["newgame"]) //Reset everything + temp = "New Round" + player_hp = 30 + player_mp = 10 + enemy_hp = 45 + enemy_mp = 20 + gameover = 0 + + src.master.add_fingerprint(usr) + src.master.updateUsrDialog() + return + +/datum/computer/file/computer_program/arcade/proc/arcade_action() + if ((src.enemy_mp <= 0) || (src.enemy_hp <= 0)) + src.gameover = 1 + src.temp = "[src.enemy_name] has fallen! Rejoice!" + src.peripheral_command("vend prize") + + else if ((src.enemy_mp <= 5) && (prob(70))) + var/stealamt = rand(2,3) + src.temp = "[src.enemy_name] steals [stealamt] of your power!" + src.player_mp -= stealamt + src.master.updateUsrDialog() + + if (src.player_mp <= 0) + src.gameover = 1 + sleep(10) + src.temp = "You have been drained! GAME OVER" + + else if ((src.enemy_hp <= 10) && (src.enemy_mp > 4)) + src.temp = "[src.enemy_name] heals for 4 health!" + src.enemy_hp += 4 + src.enemy_mp -= 4 + + else + var/attackamt = rand(3,6) + src.temp = "[src.enemy_name] attacks for [attackamt] damage!" + src.player_hp -= attackamt + + if ((src.player_mp <= 0) || (src.player_hp <= 0)) + src.gameover = 1 + src.temp = "You have been crushed! GAME OVER" + + src.blocked = 0 + return \ No newline at end of file diff --git a/code/WorkInProgress/computer2/base_program.dm b/code/WorkInProgress/computer2/base_program.dm new file mode 100644 index 0000000000000..b85923be77fa5 --- /dev/null +++ b/code/WorkInProgress/computer2/base_program.dm @@ -0,0 +1,263 @@ +/datum/computer + var/size = 4.0 + var/obj/item/weapon/disk/data/holder = null + var/datum/computer/folder/holding_folder = null + folder + name = "Folder" + size = 0.0 + var/gen = 0 + Del() + for(var/datum/computer/F in src.contents) + del(F) + ..() + proc + add_file(datum/computer/R) + if(!holder || holder.read_only || !R) + return 0 + if(istype(R,/datum/computer/folder) && (src.gen>=10)) + return 0 + if((holder.file_used + R.size) <= holder.file_amount) + src.contents.Add(R) + R.holder = holder + R.holding_folder = src + src.holder.file_used -= src.size + src.size += R.size + src.holder.file_used += src.size + if(istype(R,/datum/computer/folder)) + R:gen = (src.gen+1) + return 1 + return 0 + + remove_file(datum/computer/R) + if(holder && !holder.read_only || !R) +// world << "Removing file [R]. File_used: [src.holder.file_used]" + src.contents.Remove(R) + src.holder.file_used -= src.size + src.size -= R.size + src.holder.file_used += src.size + src.holder.file_used = max(src.holder.file_used, 0) +// world << "Removed file [R]. File_used: [src.holder.file_used]" + return 1 + return 0 + file + name = "File" + var/extension = "FILE" //Differentiate between types of files, why not + proc + copy_file_to_folder(datum/computer/folder/newfolder) + if(!newfolder || (!istype(newfolder)) || (!newfolder.holder) || (newfolder.holder.read_only)) + return 0 + + if((newfolder.holder.file_used + src.size) <= newfolder.holder.file_amount) + var/datum/computer/file/newfile = new src.type + + for(var/V in src.vars) + if (issaved(src.vars[V]) && V != "holder") + newfile.vars[V] = src.vars[V] + + if(!newfolder.add_file(newfile)) + del(newfile) + + return 1 + + return 0 + + + Del() + if(holder && holding_folder) + holding_folder.remove_file(src) + ..() + + +/datum/computer/file/computer_program + name = "blank program" + extension = "PROG" + //var/size = 4.0 + //var/obj/item/weapon/disk/data/holder = null + var/obj/machinery/computer2/master = null + var/active_icon = null + var/id_tag = null + var/list/req_access = list() + + New(obj/holding as obj) + if(holding) + src.holder = holding + + if(istype(src.holder.loc,/obj/machinery/computer2)) + src.master = src.holder.loc + + Del() + if(master) + master.processing_programs.Remove(src) + ..() + + proc + return_text() + if((!src.holder) || (!src.master)) + return 1 + + if((!istype(holder)) || (!istype(master))) + return 1 + + if(master.stat & (NOPOWER|BROKEN)) + return 1 + + if(!(holder in src.master.contents)) + //world << "Holder [holder] not in [master] of prg:[src]" + if(master.active_program == src) + master.active_program = null + return 1 + + if(!src.holder.root) + src.holder.root = new /datum/computer/folder + src.holder.root.holder = src + src.holder.root.name = "root" + + return 0 + + process() + if((!src.holder) || (!src.master)) + return 1 + + if((!istype(holder)) || (!istype(master))) + return 1 + + if(!(holder in src.master.contents)) + if(master.active_program == src) + master.active_program = null + master.processing_programs.Remove(src) + return 1 + + if(!src.holder.root) + src.holder.root = new /datum/computer/folder + src.holder.root.holder = src + src.holder.root.name = "root" + + return 0 + + receive_command(obj/source, command, datum/signal/signal) + if((!src.holder) || (!src.master) || (!source) || (source != src.master)) + return 1 + + if((!istype(holder)) || (!istype(master))) + return 1 + + if(master.stat & (NOPOWER|BROKEN)) + return 1 + + if(!(holder in src.master.contents)) + if(master.active_program == src) + master.active_program = null + return 1 + + return 0 + + peripheral_command(command, datum/signal/signal) + if(master) + master.send_command(command, signal) + else + del(signal) + + transfer_holder(obj/item/weapon/disk/data/newholder,datum/computer/folder/newfolder) + + if((newholder.file_used + src.size) > newholder.file_amount) + return 0 + + if(!newholder.root) + newholder.root = new /datum/computer/folder + newholder.root.holder = newholder + newholder.root.name = "root" + + if(!newfolder) + newfolder = newholder.root + + if((src.holder && src.holder.read_only) || newholder.read_only) + return 0 + + if((src.holder) && (src.holder.root)) + src.holder.root.remove_file(src) + + newfolder.add_file(src) + + if(istype(newholder.loc,/obj/machinery/computer2)) + src.master = newholder.loc + + //world << "Setting [src.holder] to [newholder]" + src.holder = newholder + return 1 + + //Check access per program. + allowed(mob/M) + //check if it doesn't require any access at all + if(src.check_access(null)) + return 1 + if(istype(M, /mob/living/silicon)) + //AI can do whatever he wants + return 1 + else if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + //if they are holding or wearing a card that has access, that works + if(src.check_access(H.equipped()) || src.check_access(H.wear_id)) + return 1 + else if(istype(M, /mob/living/carbon/monkey)) + var/mob/living/carbon/monkey/george = M + //they can only hold things :( + if(george.equipped() && istype(george.equipped(), /obj/item/weapon/card/id) && src.check_access(george.equipped())) + return 1 + return 0 + + check_access(obj/item/weapon/card/id/I) + if(!src.req_access) //no requirements + return 1 + if(!istype(src.req_access, /list)) //something's very wrong + return 1 + + var/list/L = src.req_access + if(!L.len) //no requirements + return 1 + if(!I || !istype(I, /obj/item/weapon/card/id) || !I.access) //not ID or no access + return 0 + for(var/req in src.req_access) + if(!(req in I.access)) //doesn't have this access + return 0 + return 1 + + Topic(href, href_list) + if((!src.holder) || (!src.master)) + return 1 + + if((!istype(holder)) || (!istype(master))) + return 1 + + if(master.stat & (NOPOWER|BROKEN)) + return 1 + + if(src.master.active_program != src) + return 1 + + if ((!usr.contents.Find(src.master) && (!in_range(src.master, usr) || !istype(src.master.loc, /turf))) && (!istype(usr, /mob/living/silicon))) + return 1 + + if(!(holder in src.master.contents)) + if(master.active_program == src) + master.active_program = null + return 1 + + usr.machine = src.master + + if (href_list["close"]) + usr.machine = null + usr << browse(null, "window=comp2") + return 0 + + if (href_list["quit"]) +// src.master.processing_programs.Remove(src) + if(src.master.host_program && src.master.host_program.holder && (src.master.host_program.holder in src.master.contents)) + src.master.run_program(src.master.host_program) + src.master.updateUsrDialog() + return 1 + else + src.master.active_program = null + src.master.updateUsrDialog() + return 1 + + return 0 \ No newline at end of file diff --git a/code/WorkInProgress/computer2/buildandrepair.dm b/code/WorkInProgress/computer2/buildandrepair.dm new file mode 100644 index 0000000000000..c722bb5c61c65 --- /dev/null +++ b/code/WorkInProgress/computer2/buildandrepair.dm @@ -0,0 +1,153 @@ +//Motherboard is just used in assembly/disassembly, doesn't exist in the actual computer object. +/obj/item/weapon/motherboard + name = "Computer mainboard" + desc = "A computer motherboard." + icon = 'module.dmi' + icon_state = "mainboard" + item_state = "electronic" + w_class = 3 + var/created_name = null //If defined, result computer will have this name. + +/obj/computer2frame + density = 1 + anchored = 0 + name = "Computer-frame" + icon = 'computer_frame.dmi' + icon_state = "0" + var/state = 0 + var/obj/item/weapon/motherboard/mainboard = null + var/obj/item/weapon/disk/data/fixed_disk/hd = null + var/list/peripherals = list() + var/created_icon_state = "aiupload" + +/obj/computer2frame/attackby(obj/item/weapon/P as obj, mob/user as mob) + switch(state) + if(0) + if(istype(P, /obj/item/weapon/wrench)) + playsound(src.loc, 'Ratchet.ogg', 50, 1) + if(do_after(user, 20)) + user << "\blue You wrench the frame into place." + src.anchored = 1 + src.state = 1 + if(istype(P, /obj/item/weapon/weldingtool)) + playsound(src.loc, 'Welder.ogg', 50, 1) + if(do_after(user, 20)) + user << "\blue You deconstruct the frame." + var/obj/item/weapon/sheet/metal/A = new /obj/item/weapon/sheet/metal( src.loc ) + A.amount = 5 + del(src) + if(1) + if(istype(P, /obj/item/weapon/wrench)) + playsound(src.loc, 'Ratchet.ogg', 50, 1) + if(do_after(user, 20)) + user << "\blue You unfasten the frame." + src.anchored = 0 + src.state = 0 + if(istype(P, /obj/item/weapon/motherboard) && !mainboard) + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + user << "\blue You place the mainboard inside the frame." + src.icon_state = "1" + src.mainboard = P + user.drop_item() + P.loc = src + if(istype(P, /obj/item/weapon/screwdriver) && mainboard) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + user << "\blue You screw the mainboard into place." + src.state = 2 + src.icon_state = "2" + if(istype(P, /obj/item/weapon/crowbar) && mainboard) + playsound(src.loc, 'Crowbar.ogg', 50, 1) + user << "\blue You remove the mainboard." + src.state = 1 + src.icon_state = "0" + mainboard.loc = src.loc + src.mainboard = null + if(2) + if(istype(P, /obj/item/weapon/screwdriver) && mainboard && (!peripherals.len)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + user << "\blue You unfasten the mainboard." + src.state = 1 + src.icon_state = "1" + + if(istype(P, /obj/item/weapon/peripheral)) + if(src.peripherals.len < 3) + user.drop_item() + src.peripherals.Add(P) + P.loc = src + user << "\blue You add [P] to the frame." + else + user << "\red There is no more room for peripheral cards." + + if(istype(P, /obj/item/weapon/crowbar) && src.peripherals.len) + playsound(src.loc, 'Crowbar.ogg', 50, 1) + user << "\blue You remove the peripheral boards." + for(var/obj/item/weapon/peripheral/W in src.peripherals) + W.loc = src.loc + src.peripherals.Remove(W) + + if(istype(P, /obj/item/weapon/cable_coil)) + if(P:amount >= 5) + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + if(do_after(user, 20)) + P:amount -= 5 + if(!P:amount) del(P) + user << "\blue You add cables to the frame." + src.state = 3 + src.icon_state = "3" + if(3) + if(istype(P, /obj/item/weapon/wirecutters)) + playsound(src.loc, 'wirecutter.ogg', 50, 1) + user << "\blue You remove the cables." + src.state = 2 + src.icon_state = "2" + var/obj/item/weapon/cable_coil/A = new /obj/item/weapon/cable_coil( src.loc ) + A.amount = 5 + if(src.hd) + src.hd.loc = src.loc + src.hd = null + + if(istype(P, /obj/item/weapon/disk/data/fixed_disk) && !src.hd) + user.drop_item() + src.hd = P + P.loc = src + user << "\blue You connect the drive to the cabling." + + if(istype(P, /obj/item/weapon/crowbar) && src.hd) + playsound(src.loc, 'Crowbar.ogg', 50, 1) + user << "\blue You remove the hard drive." + src.hd.loc = src.loc + src.hd = null + + if(istype(P, /obj/item/weapon/sheet/glass)) + if(P:amount >= 2) + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + if(do_after(user, 20)) + P:amount -= 2 + if(!P:amount) del(P) + user << "\blue You put in the glass panel." + src.state = 4 + src.icon_state = "4" + if(4) + if(istype(P, /obj/item/weapon/crowbar)) + playsound(src.loc, 'Crowbar.ogg', 50, 1) + user << "\blue You remove the glass panel." + src.state = 3 + src.icon_state = "3" + var/obj/item/weapon/sheet/glass/A = new /obj/item/weapon/sheet/glass( src.loc ) + A.amount = 2 + if(istype(P, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + user << "\blue You connect the monitor." + var/obj/machinery/computer2/C= new /obj/machinery/computer2( src.loc ) + C.setup_drive_size = 0 + C.icon_state = src.created_icon_state + if(mainboard.created_name) C.name = mainboard.created_name + del(mainboard) + if(hd) + C.hd = hd + hd.loc = C + for(var/obj/item/weapon/peripheral/W in src.peripherals) + W.loc = C + W.host = C + C.peripherals.Add(W) + del(src) \ No newline at end of file diff --git a/code/WorkInProgress/computer2/computerII.dm b/code/WorkInProgress/computer2/computerII.dm new file mode 100644 index 0000000000000..ed1c4eb355464 --- /dev/null +++ b/code/WorkInProgress/computer2/computerII.dm @@ -0,0 +1,414 @@ + +/obj/machinery/computer2 + name = "computer" + desc = "A computer workstation." + icon = 'computer.dmi' + icon_state = "aiupload" + density = 1 + anchored = 1.0 + req_access = list() //This doesn't determine PROGRAM req access, just the access needed to install/delete programs. + var/base_icon_state = "aiupload" //Assembly creates a new computer2 and not a child typepath, so initial doesn't work!! + var/datum/radio_frequency/radio_connection + var/obj/item/weapon/disk/data/fixed_disk/hd = null + var/datum/computer/file/computer_program/active_program + var/datum/computer/file/computer_program/host_program //active is set to this when the normal active quits, if available + var/list/processing_programs = list() + var/obj/item/weapon/card/id/authid = null //For records computers etc + var/obj/item/weapon/card/id/auxid = null //For computers that need two ids for some reason. + var/obj/item/weapon/disk/data/diskette = null + var/list/peripherals = list() + //Setup for Starting program & peripherals + var/setup_starting_program = null //If set to a program path it will start with this one active. + var/setup_starting_peripheral = null //Spawn with radio card and whatever path is here. + var/setup_drive_size = 64.0 //How big is the drive (set to 0 for no drive) + var/setup_id_tag + var/setup_has_radio = 0 //Does it spawn with a radio peripheral? + var/setup_radio_tag + var/setup_frequency = 1411 + +/obj/item/weapon/disk/data + var/datum/computer/folder/root = null + var/file_amount = 32.0 + var/file_used = 0.0 + var/portable = 1 + var/title = "Data Disk" + New() + src.root = new /datum/computer/folder + src.root.holder = src + src.root.name = "root" + +/obj/item/weapon/disk/data/fixed_disk + name = "Storage Drive" + icon_state = "harddisk" + title = "Storage Drive" + file_amount = 80.0 + portable = 0 + + attack_self(mob/user as mob) + return + +/obj/item/weapon/disk/data/computer2test + name = "Programme Diskette" + file_amount = 128.0 + New() + ..() + src.root.add_file( new /datum/computer/file/computer_program/arcade(src)) + src.root.add_file( new /datum/computer/file/computer_program/med_data(src)) + src.root.add_file( new /datum/computer/file/computer_program/airlock_control(src)) + src.root.add_file( new /datum/computer/file/computer_program/messenger(src)) + src.root.add_file( new /datum/computer/file/computer_program/progman(src)) + +/obj/machinery/computer2/medical + name = "Medical computer" + icon_state = "dna" + setup_has_radio = 1 + setup_starting_program = /datum/computer/file/computer_program/med_data + setup_starting_peripheral = /obj/item/weapon/peripheral/printer + +/obj/machinery/computer2/arcade + name = "arcade machine" + icon_state = "arcade" + desc = "An arcade machine." + setup_drive_size = 16.0 + setup_starting_program = /datum/computer/file/computer_program/arcade + setup_starting_peripheral = /obj/item/weapon/peripheral/prize_vendor + + +/obj/machinery/computer2/New() + ..() + + spawn(4) + if(setup_has_radio) + var/obj/item/weapon/peripheral/radio/radio = new /obj/item/weapon/peripheral/radio(src) + radio.frequency = setup_frequency + radio.code = setup_radio_tag + + if(!hd && (setup_drive_size > 0)) + src.hd = new /obj/item/weapon/disk/data/fixed_disk(src) + src.hd.file_amount = src.setup_drive_size + + if(ispath(src.setup_starting_program)) + src.active_program = new src.setup_starting_program + src.active_program.id_tag = setup_id_tag + + src.hd.file_amount = max(src.hd.file_amount, src.active_program.size) + + src.active_program.transfer_holder(src.hd) + + if(ispath(src.setup_starting_peripheral)) + new src.setup_starting_peripheral(src) + + src.base_icon_state = src.icon_state + + return + +/obj/machinery/computer2/attack_hand(mob/user as mob) + if(..()) + return + + user.machine = src + + var/dat + if((src.active_program) && (src.active_program.master == src) && (src.active_program.holder in src)) + dat = src.active_program.return_text() + else + dat = "Thinktronic BIOS V1.4

" + + dat += "Current ID: [src.authid ? "[src.authid.name]" : "----------"]
" + dat += "Auxiliary ID: [src.auxid ? "[src.auxid.name]" : "----------"]

" + + var/progdat + if((src.hd) && (src.hd.root)) + for(var/datum/computer/file/computer_program/P in src.hd.root.contents) + progdat += "
" + + progdat += "" + + if(P in src.processing_programs) + progdat += "" + else + progdat += "" + + progdat += "" + + continue + + dat += "Disk Space: \[[src.hd.file_used]/[src.hd.file_amount]\]
" + dat += "Programs on Fixed Disk:
" + + if(!progdat) + progdat = "No programs found.
" + dat += "
[P.name]Size: [P.size]RunHaltLoadDel
[progdat]
" + + else + + dat += "Programs on Fixed Disk:
" + dat += "
No fixed disk detected.

" + + dat += "
" + + progdat = null + if((src.diskette) && (src.diskette.root)) + + dat += "Eject
" + + for(var/datum/computer/file/computer_program/P in src.diskette.root.contents) + progdat += "[P.name]Size: [P.size]" + progdat += "Run" + + if(P in src.processing_programs) + progdat += "Halt" + else + progdat += "Load" + + progdat += "Install" + + continue + + dat += "Disk Space: \[[src.diskette.file_used]/[src.diskette.file_amount]\]
" + dat += "Programs on Disk:
" + + if(!progdat) + progdat = "No data found.
" + dat += "
[progdat]
" + + else + + dat += "Programs on Disk:
" + dat += "
No diskette loaded.

" + + dat += "
" + + user << browse(dat,"window=comp2") + onclose(user,"comp2") + return + +/obj/machinery/computer2/Topic(href, href_list) + if(..()) + return + + if(!src.active_program) + if((href_list["prog"]) && (href_list["function"])) + var/datum/computer/file/computer_program/newprog = locate(href_list["prog"]) + if(newprog && istype(newprog)) + switch(href_list["function"]) + if("run") + src.run_program(newprog) + if("load") + src.load_program(newprog) + if("unload") + src.unload_program(newprog) + if((href_list["file"]) && (href_list["function"])) + var/datum/computer/file/newfile = locate(href_list["file"]) + if(!newfile) + return + switch(href_list["function"]) + if("install") + if((src.hd) && (src.hd.root) && (src.allowed(usr))) + newfile.copy_file_to_folder(src.hd.root) + + if("delete") + if(src.allowed(usr)) + src.delete_file(newfile) + + //If there is already one loaded eject, or if not and they have one insert it. + if (href_list["id"]) + switch(href_list["id"]) + if("auth") + if(!isnull(src.authid)) + src.authid.loc = get_turf(src) + src.authid = null + else + var/obj/item/I = usr.equipped() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + src.authid = I + if("aux") + if(!isnull(src.auxid)) + src.auxid.loc = get_turf(src) + src.auxid = null + else + var/obj/item/I = usr.equipped() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + src.auxid = I + + //Same but for a data disk + else if (href_list["disk"]) + if(!isnull(src.diskette)) + src.diskette.loc = get_turf(src) + src.diskette = null +/* else + var/obj/item/I = usr.equipped() + if (istype(I, /obj/item/weapon/disk/data)) + usr.drop_item() + I.loc = src + src.diskette = I +*/ + src.add_fingerprint(usr) + src.updateUsrDialog() + return + +/obj/machinery/computer2/process() + if(stat & (NOPOWER|BROKEN)) + return + use_power(250) + + for(var/datum/computer/file/computer_program/P in src.processing_programs) + P.process() + + return + +/obj/machinery/computer2/power_change() + if(stat & BROKEN) + icon_state = src.base_icon_state + src.icon_state += "b" + + else if(powered()) + icon_state = src.base_icon_state + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + icon_state = src.base_icon_state + src.icon_state += "0" + stat |= NOPOWER + + +/obj/machinery/computer2/attackby(obj/item/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/disk/data)) //INSERT SOME DISKETTES + if ((!src.diskette) && W:portable) + user.machine = src + user.drop_item() + W.loc = src + src.diskette = W + user << "You insert [W]." + src.updateUsrDialog() + return + + else if (istype(W, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + var/obj/computer2frame/A = new /obj/computer2frame( src.loc ) + A.created_icon_state = src.base_icon_state + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + new /obj/item/weapon/shard( src.loc ) + A.state = 3 + A.icon_state = "3" + else + user << "\blue You disconnect the monitor." + A.state = 4 + A.icon_state = "4" + + for (var/obj/item/weapon/peripheral/C in src.peripherals) + C.loc = A + A.peripherals.Add(C) + + if(src.diskette) + src.diskette.loc = src.loc + + //TO-DO: move card reading to peripheral cards instead + if(src.authid) + src.authid.loc = src.loc + + if(src.auxid) + src.auxid.loc = src.loc + + if(src.hd) + src.hd.loc = A + A.hd = src.hd + + A.mainboard = new /obj/item/weapon/motherboard(A) + A.mainboard.created_name = src.name + + + A.anchored = 1 + del(src) + + else + src.attack_hand(user) + return + +/obj/machinery/computer2/proc/send_command(command, datum/signal/signal) + for(var/obj/item/weapon/peripheral/P in src.peripherals) + P.receive_command(src, command, signal) + + del(signal) + +/obj/machinery/computer2/proc/receive_command(obj/source, command, datum/signal/signal) + if(source in src.contents) + + for(var/datum/computer/file/computer_program/P in src.processing_programs) + P.receive_command(src, command, signal) + + del(signal) + + return + + +/obj/machinery/computer2/proc/run_program(datum/computer/file/computer_program/program,datum/computer/file/computer_program/host) + if(!program) + return 0 + +// src.unload_program(src.active_program) + + if(src.load_program(program)) + if(host && istype(host)) + src.host_program = host + else + src.host_program = null + + src.active_program = program + return 1 + + return 0 + +/obj/machinery/computer2/proc/load_program(datum/computer/file/computer_program/program) + if((!program) || (!program.holder)) + return 0 + + if(!(program.holder in src)) +// world << "Not in src" + program = new program.type + program.transfer_holder(src.hd) + + if(program.master != src) + program.master = src + + if(program in src.processing_programs) + return 1 + else + src.processing_programs.Add(program) + return 1 + + return 0 + +/obj/machinery/computer2/proc/unload_program(datum/computer/file/computer_program/program) + if((!program) || (!src.hd)) + return 0 + + if(program in src.processing_programs) + src.processing_programs.Remove(program) + return 1 + + return 0 + +/obj/machinery/computer2/proc/delete_file(datum/computer/file/file) + //world << "Deleting [file]..." + if((!file) || (!file.holder) || (file.holder.read_only)) + //world << "Cannot delete :(" + return 0 + + if(file in src.processing_programs) + src.processing_programs.Remove(file) + + if(src.active_program == file) + src.active_program = null + +// file.holder.root.remove_file(file) + + //world << "Now calling del on [file]..." + del(file) + return 1 \ No newline at end of file diff --git a/code/WorkInProgress/computer2/filebrowse.dm b/code/WorkInProgress/computer2/filebrowse.dm new file mode 100644 index 0000000000000..38c88f0616101 --- /dev/null +++ b/code/WorkInProgress/computer2/filebrowse.dm @@ -0,0 +1,164 @@ +/datum/computer/file/computer_program/progman + name = "ProgManager" + size = 16.0 + var/datum/computer/folder/current_folder + var/mode = 0 + var/datum/computer/file/clipboard + + + return_text() + if(..()) + return + + if((!src.current_folder) || !(src.current_folder.holder in src.master)) + src.current_folder = src.holder.root + + var/dat = "Close | " + dat += "Quit" + + switch(mode) + if(0) + dat += " |Create Folder" + //dat += " | Create File" + dat += " | Paste" + dat += " | Root" + dat += " | Drive
" + + dat += "Contents of [current_folder] | Drive:\[[src.current_folder.holder.title]]
" + dat += "Used: \[[src.current_folder.holder.file_used]/[src.current_folder.holder.file_amount]\]
" + + dat += "" + for(var/datum/computer/P in current_folder.contents) + if(P == src) + dat += "" + continue + dat += "" + dat += "" + + dat += "" + + dat += "" + dat += "" + + + if(istype(P,/datum/computer/file)) + dat += "" + + dat += "" + + dat += "
SystemSize: [src.size]SYSTEM
[P.name]Size: [P.size][(istype(P,/datum/computer/folder)) ? "FOLDER" : "[P:extension]"]DelRenameCopy
" + + if(1) + dat += " | Main" + dat += " | Eject
" + + for(var/obj/item/weapon/disk/data/D in src.master) + if(D == current_folder.holder) + dat += "[D.name]
" + else + dat += "[D.title]
" + + + return dat + + Topic(href, href_list) + if(..()) + return + + if(href_list["create"]) + if(current_folder) + var/datum/computer/F = null + switch(href_list["create"]) + if("folder") + F = new /datum/computer/folder + if(!current_folder.add_file(F)) + //world << "Couldn't add folder :(" + del(F) + if("file") + F = new /datum/computer/file + if(!current_folder.add_file(F)) + //world << "Couldn't add file :(" + del(F) + + if(href_list["file"] && href_list["function"]) + var/datum/computer/F = locate(href_list["file"]) + if(!F || !istype(F)) + return + switch(href_list["function"]) + if("open") + if(istype(F,/datum/computer/folder)) + src.current_folder = F + else if(istype(F,/datum/computer/file/computer_program)) + src.master.run_program(F,src) + src.master.updateUsrDialog() + return + + if("delete") + src.master.delete_file(F) + + if("copy") + if(istype(F,/datum/computer/file) && (!F.holder || (F.holder in src.master.contents))) + src.clipboard = F + + if("paste") + if(istype(F,/datum/computer/folder)) + if(!src.clipboard || !src.clipboard.holder || !(src.clipboard.holder in src.master.contents)) + return + + if(!istype(src.clipboard)) + return + + src.clipboard.copy_file_to_folder(F) + + if("rename") + spawn(0) + var/t = input(usr, "Please enter new name", F.name, null) as text + t = copytext(sanitize(t), 1, 16) + if (!t) + return + if (!in_range(src.master, usr) || !(F.holder in src.master)) + return + if(F.holder.read_only) + return + F.name = capitalize(lowertext(t)) + src.master.updateUsrDialog() + return + + +/* + if(href_list["open"]) + var/datum/computer/F = locate(href_list["open"]) + if(!F || !istype(F)) + return + + if(istype(F,/datum/computer/folder)) + src.current_folder = F + else if(istype(F,/datum/computer/file/computer_program)) + src.master.run_program(F) + src.master.updateUsrDialog() + return + + if(href_list["delete"]) + var/datum/computer/F = locate(href_list["delete"]) + if(!F || !istype(F)) + return + + src.master.delete_file(F) +*/ + if(href_list["top_folder"]) + src.current_folder = src.current_folder.holder.root + + if(href_list["mode"]) + var/newmode = text2num(href_list["mode"]) + newmode = max(newmode,0) + src.mode = newmode + + if(href_list["drive"]) + var/obj/item/weapon/disk/data/D = locate(href_list["drive"]) + if(D && istype(D) && D.root) + current_folder = D.root + src.mode = 0 + + src.master.add_fingerprint(usr) + src.master.updateUsrDialog() + return \ No newline at end of file diff --git a/code/WorkInProgress/computer2/med_rec.dm b/code/WorkInProgress/computer2/med_rec.dm new file mode 100644 index 0000000000000..a017366f6aba5 --- /dev/null +++ b/code/WorkInProgress/computer2/med_rec.dm @@ -0,0 +1,463 @@ +/datum/computer/file/computer_program/med_data + name = "Medical Records" + size = 32.0 + active_icon = "dna" + req_access = list(access_medical) + var/authenticated = null + var/rank = null + var/screen = null + var/datum/data/record/active1 = null + var/datum/data/record/active2 = null + var/a_id = null + var/temp = null + +/datum/computer/file/computer_program/med_data/return_text() + if(..()) + return + var/dat + if (src.temp) + dat = text("[src.temp]

Clear Screen") + else + dat = text("Confirm Identity: []
", master, (src.master.authid ? text("[]", src.master.authid.name) : "----------")) + if (src.authenticated) + switch(src.screen) + if(1.0) + dat += {" +Search Records +
List Records +
+
Virus Database +
Medbot Tracking +
+
Record Maintenance +
{Log Out}
+"} + if(2.0) + dat += "Record List:
" + for(var/datum/data/record/R in data_core.general) + dat += text("[]: []
", src, R, R.fields["id"], R.fields["name"]) + //Foreach goto(132) + dat += text("
Back", src) + if(3.0) + dat += text("Records Maintenance
\nBackup To Disk
\nUpload From disk
\nDelete All Records
\n
\nBack", src, src, src, src) + if(4.0) + dat += "
Medical Record

" + if ((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))) + dat += text("Name: [] ID: []
\nSex: []
\nAge: []
\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", src.active1.fields["name"], src.active1.fields["id"], src, src.active1.fields["sex"], src, src.active1.fields["age"], src, src.active1.fields["fingerprint"], src, src.active1.fields["p_stat"], src, src.active1.fields["m_stat"]) + else + dat += "General Record Lost!
" + if ((istype(src.active2, /datum/data/record) && data_core.medical.Find(src.active2))) + dat += text("
\n
Medical Data

\nBlood Type: []
\n
\nMinor Disabilities: []
\nDetails: []
\n
\nMajor Disabilities: []
\nDetails: []
\n
\nAllergies: []
\nDetails: []
\n
\nCurrent Diseases: [] (per disease info placed in log/comment section)
\nDetails: []
\n
\nImportant Notes:
\n\t[]
\n
\n
Comments/Log

", src, src.active2.fields["b_type"], src, src.active2.fields["mi_dis"], src, src.active2.fields["mi_dis_d"], src, src.active2.fields["ma_dis"], src, src.active2.fields["ma_dis_d"], src, src.active2.fields["alg"], src, src.active2.fields["alg_d"], src, src.active2.fields["cdi"], src, src.active2.fields["cdi_d"], src, src.active2.fields["notes"]) + var/counter = 1 + while(src.active2.fields[text("com_[]", counter)]) + dat += text("[]
Delete Entry

", src.active2.fields[text("com_[]", counter)], src, counter) + counter++ + dat += text("Add Entry

", src) + dat += text("Delete Record (Medical Only)

", src) + else + dat += "Medical Record Lost!
" + dat += text("New Record

") + dat += text("\nPrint Record
\nBack
", src, src) + if(5.0) + dat += {"
Virus Database
+
GBS +
Common Cold +
Flu +
Jungle Fever +
Clowning Around +
Plasmatoid +
Space Rhinovirus +
Robot Transformation +
Back"} + if(6.0) + dat += "
Medical Robot Monitor
" + dat += "Back" + dat += "
Medical Robots:" + var/bdat = null + for(var/obj/machinery/bot/medbot/M in world) + var/turf/bl = get_turf(M) + bdat += "[M.name] - \[[bl.x],[bl.y]\] - [M.on ? "Online" : "Offline"]
" + if(!isnull(M.reagent_glass)) + bdat += "Reservoir: \[[M.reagent_glass.reagents.total_volume]/[M.reagent_glass.reagents.maximum_volume]\]" + else + bdat += "Using Internal Synthesizer." + + if(!bdat) + dat += "
None detected
" + else + dat += "[bdat]" + + else + else + dat += text("{Log In}", src) + dat += "
{Quit}" + + return dat + +/datum/computer/file/computer_program/med_data/Topic(href, href_list) + if(..()) + return + if (!( data_core.general.Find(src.active1) )) + src.active1 = null + if (!( data_core.medical.Find(src.active2) )) + src.active2 = null + if (href_list["temp"]) + src.temp = null + else if (href_list["logout"]) + src.authenticated = null + src.screen = null + src.active1 = null + src.active2 = null + else if (href_list["login"]) + if (istype(usr, /mob/living/silicon)) + src.active1 = null + src.active2 = null + src.authenticated = 1 + src.rank = "AI" + src.screen = 1 + else if (istype(src.master.authid, /obj/item/weapon/card/id)) + src.active1 = null + src.active2 = null + if (src.check_access(src.master.authid)) + src.authenticated = src.master.authid.registered + src.rank = src.master.authid.assignment + src.screen = 1 + if (src.authenticated) + + if(href_list["screen"]) + src.screen = text2num(href_list["screen"]) + if(src.screen < 1) + src.screen = 1 + + src.active1 = null + src.active2 = null + + if(href_list["vir"]) + switch(href_list["vir"]) + if("gbs") + src.temp = {"Name: GBS +
Number of stages: 5 +
Spread: Airborne Transmission +
Possible Cure: Spaceacillin +
Affected Species: Human +
+
Notes: If left untreated death will occur. +
+
Severity: Major"} + if("cc") + src.temp = {"Name: Common Cold +
Number of stages: 3 +
Spread: Airborne Transmission +
Possible Cure: Rest +
Affected Species: Human +
+
Notes: If left untreated the subject will contract the flu. +
+
Severity: Minor"} + if("f") + src.temp = {"Name: The Flu +
Number of stages: 3 +
Spread: Airborne Transmission +
Possible Cure: Rest +
Affected Species: Human +
+
Notes: If left untreated the subject will feel quite unwell. +
+
Severity: Medium"} + if("jf") + src.temp = {"Name: Jungle Fever +
Number of stages: 1 +
Spread: Airborne Transmission +
Possible Cure: None +
Affected Species: Monkey +
+
Notes: Monkies with this disease will bite humans, causing humans to spontaneously to mutate into a monkey. +
+
Severity: Medium"} + if("ca") + src.temp = {"Name: Clowning Around +
Number of stages: 4 +
Spread: Airborne Transmission +
Possible Cure: Spaceacillin +
Affected Species: Human +
+
Notes: Subjects are affected by rampant honking and a fondness for shenanigans. They may also spontaneously phase through closed airlocks. +
+
Severity: Laughable"} + if("p") + src.temp = {"Name: Plasmatoid +
Number of stages: 3 +
Spread: Airborne Transmission +
Possible Cure: Inaprovaline +
Affected Species: Human and Monkey +
+
Notes: With this disease the victim will need plasma to breathe. +
+
Severity: Major"} + if("dna") + src.temp = {"Name: Space Rhinovirus +
Number of stages: 4 +
Spread: Airborne Transmission +
Possible Cure: Spaceacillin +
Affected Species: Human +
+
Notes: This disease transplants the genetic code of the intial vector into new hosts. +
+
Severity: Medium"} + if("bot") + src.temp = {"Name: Robot Transformation +
Number of stages: 5 +
Spread: Infected food +
Possible Cure: None +
Affected Species: Human +
+
Notes: This disease, actually acute nanomachine infection, converts the victim into a cyborg. +
+
Severity: Major"} + + if (href_list["del_all"]) + src.temp = text("Are you sure you wish to delete all records?
\n\tYes
\n\tNo
", src, src) + + if (href_list["del_all2"]) + for(var/datum/data/record/R in data_core.medical) + del(R) + src.temp = "All records deleted." + + if (href_list["field"]) + var/a1 = src.active1 + var/a2 = src.active2 + switch(href_list["field"]) + if("fingerprint") + if (istype(src.active1, /datum/data/record)) + var/t1 = input("Please input fingerprint hash:", "Med. records", src.active1.fields["id"], null) as text + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) + return + src.active1.fields["fingerprint"] = t1 + if("sex") + if (istype(src.active1, /datum/data/record)) + if (src.active1.fields["sex"] == "Male") + src.active1.fields["sex"] = "Female" + else + src.active1.fields["sex"] = "Male" + if("age") + if (istype(src.active1, /datum/data/record)) + var/t1 = input("Please input age:", "Med. records", src.active1.fields["age"], null) as text + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) + return + src.active1.fields["age"] = t1 + if("mi_dis") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please input minor disabilities list:", "Med. records", src.active2.fields["mi_dis"], null) as text + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["mi_dis"] = t1 + if("mi_dis_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize minor dis.:", "Med. records", src.active2.fields["mi_dis_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["mi_dis_d"] = t1 + if("ma_dis") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please input major diabilities list:", "Med. records", src.active2.fields["ma_dis"], null) as text + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["ma_dis"] = t1 + if("ma_dis_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize major dis.:", "Med. records", src.active2.fields["ma_dis_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["ma_dis_d"] = t1 + if("alg") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please state allergies:", "Med. records", src.active2.fields["alg"], null) as text + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["alg"] = t1 + if("alg_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize allergies:", "Med. records", src.active2.fields["alg_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["alg_d"] = t1 + if("cdi") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please state diseases:", "Med. records", src.active2.fields["cdi"], null) as text + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["cdi"] = t1 + if("cdi_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize diseases:", "Med. records", src.active2.fields["cdi_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["cdi_d"] = t1 + if("notes") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize notes:", "Med. records", src.active2.fields["notes"], null) as message + if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["notes"] = t1 + if("p_stat") + if (istype(src.active1, /datum/data/record)) + src.temp = text("Physical Condition:
\n\t*Deceased*
\n\t*Unconscious*
\n\tActive
\n\tPhysically Unfit
", src, src, src, src) + if("m_stat") + if (istype(src.active1, /datum/data/record)) + src.temp = text("Mental Condition:
\n\t*Insane*
\n\t*Unstable*
\n\t*Watch*
\n\tStable
", src, src, src, src) + if("b_type") + if (istype(src.active2, /datum/data/record)) + src.temp = text("Blood Type:
\n\tA- A+
\n\tB- B+
\n\tAB- AB+
\n\tO- O+
", src, src, src, src, src, src, src, src) + else + + if (href_list["p_stat"]) + if (src.active1) + switch(href_list["p_stat"]) + if("deceased") + src.active1.fields["p_stat"] = "*Deceased*" + if("unconscious") + src.active1.fields["p_stat"] = "*Unconscious*" + if("active") + src.active1.fields["p_stat"] = "Active" + if("unfit") + src.active1.fields["p_stat"] = "Physically Unfit" + + if (href_list["m_stat"]) + if (src.active1) + switch(href_list["m_stat"]) + if("insane") + src.active1.fields["m_stat"] = "*Insane*" + if("unstable") + src.active1.fields["m_stat"] = "*Unstable*" + if("watch") + src.active1.fields["m_stat"] = "*Watch*" + if("stable") + src.active2.fields["m_stat"] = "Stable" + + + if (href_list["b_type"]) + if (src.active2) + switch(href_list["b_type"]) + if("an") + src.active2.fields["b_type"] = "A-" + if("bn") + src.active2.fields["b_type"] = "B-" + if("abn") + src.active2.fields["b_type"] = "AB-" + if("on") + src.active2.fields["b_type"] = "O-" + if("ap") + src.active2.fields["b_type"] = "A+" + if("bp") + src.active2.fields["b_type"] = "B+" + if("abp") + src.active2.fields["b_type"] = "AB+" + if("op") + src.active2.fields["b_type"] = "O+" + + + if (href_list["del_r"]) + if (src.active2) + src.temp = "Are you sure you wish to delete the record (Medical Portion Only)?
\n\tYes
\n\tNo
" + + if (href_list["del_r2"]) + if (src.active2) + del(src.active2) + + if (href_list["d_rec"]) + var/datum/data/record/R = locate(href_list["d_rec"]) + var/datum/data/record/M = locate(href_list["d_rec"]) + if (!( data_core.general.Find(R) )) + src.temp = "Record Not Found!" + return + for(var/datum/data/record/E in data_core.medical) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + M = E + else + //Foreach continue //goto(2540) + src.active1 = R + src.active2 = M + src.screen = 4 + + if (href_list["new"]) + if ((istype(src.active1, /datum/data/record) && !( istype(src.active2, /datum/data/record) ))) + var/datum/data/record/R = new /datum/data/record( ) + R.fields["name"] = src.active1.fields["name"] + R.fields["id"] = src.active1.fields["id"] + R.name = text("Medical Record #[]", R.fields["id"]) + R.fields["b_type"] = "Unknown" + R.fields["mi_dis"] = "None" + R.fields["mi_dis_d"] = "No minor disabilities have been declared." + R.fields["ma_dis"] = "None" + R.fields["ma_dis_d"] = "No major disabilities have been diagnosed." + R.fields["alg"] = "None" + R.fields["alg_d"] = "No allergies have been detected in this patient." + R.fields["cdi"] = "None" + R.fields["cdi_d"] = "No diseases have been diagnosed at the moment." + R.fields["notes"] = "No notes." + data_core.medical += R + src.active2 = R + src.screen = 4 + + if (href_list["add_c"]) + if (!( istype(src.active2, /datum/data/record) )) + return + var/a2 = src.active2 + var/t1 = input("Add Comment:", "Med. records", null, null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + var/counter = 1 + while(src.active2.fields[text("com_[]", counter)]) + counter++ + src.active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [], 2053
[]", src.authenticated, src.rank, time2text(world.realtime, "DDD MMM DD hh:mm:ss"), t1) + + if (href_list["del_c"]) + if ((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])])) + src.active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" + + if (href_list["search"]) + var/t1 = input("Search String: (Name or ID)", "Med. records", null, null) as text + if ((!( t1 ) || usr.stat || (!src.master) || !( src.authenticated ) || usr.restrained() || ((!in_range(src.master, usr)) && (!istype(usr, /mob/living/silicon))))) + return + src.active1 = null + src.active2 = null + t1 = lowertext(t1) + for(var/datum/data/record/R in data_core.general) + if ((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"]))) + src.active1 = R + else + + if (!( src.active1 )) + src.temp = text("Could not locate record [].", t1) + else + for(var/datum/data/record/E in data_core.medical) + if ((E.fields["name"] == src.active1.fields["name"] || E.fields["id"] == src.active1.fields["id"])) + src.active2 = E + else + + src.screen = 4 + + if (href_list["print_p"]) + var/info = "
Medical Record

" + if ((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))) + info += text("Name: [] ID: []
\nSex: []
\nAge: []
\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"], src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"]) + else + info += "General Record Lost!
" + if ((istype(src.active2, /datum/data/record) && data_core.medical.Find(src.active2))) + info += text("
\n
Medical Data

\nBlood Type: []
\n
\nMinor Disabilities: []
\nDetails: []
\n
\nMajor Disabilities: []
\nDetails: []
\n
\nAllergies: []
\nDetails: []
\n
\nCurrent Diseases: [] (per disease info placed in log/comment section)
\nDetails: []
\n
\nImportant Notes:
\n\t[]
\n
\n
Comments/Log

", src.active2.fields["b_type"], src.active2.fields["mi_dis"], src.active2.fields["mi_dis_d"], src.active2.fields["ma_dis"], src.active2.fields["ma_dis_d"], src.active2.fields["alg"], src.active2.fields["alg_d"], src.active2.fields["cdi"], src.active2.fields["cdi_d"], src.active2.fields["notes"]) + var/counter = 1 + while(src.active2.fields[text("com_[]", counter)]) + info += text("[]
", src.active2.fields[text("com_[]", counter)]) + counter++ + else + info += "Medical Record Lost!
" + info += "" + + var/datum/signal/signal = new + signal.data["data"] = info + signal.data["title"] = "Medical Record" + src.peripheral_command("print",signal) + + src.master.add_fingerprint(usr) + src.master.updateUsrDialog() + return \ No newline at end of file diff --git a/code/WorkInProgress/computer2/messenger.dm b/code/WorkInProgress/computer2/messenger.dm new file mode 100644 index 0000000000000..58c3037329ad2 --- /dev/null +++ b/code/WorkInProgress/computer2/messenger.dm @@ -0,0 +1,96 @@ +/datum/computer/file/computer_program/messenger + name = "Messenger" + size = 8.0 + var/messages = null + var/screen_name = "User" + +//To-do: take screen_name from inserted id card?? +//Saving log to file datum + + return_text() + if(..()) + return + + var/dat = "Close | " + dat += "Quit
" + + dat += "SpaceMessenger V4.1.2
" + + dat += "Send Message" + + dat += " | Clear" + dat += " | Print" + + dat += " | Name:[src.screen_name]
" + + dat += messages + + dat += "" + + return dat + + Topic(href, href_list) + if(..()) + return + + if(href_list["send_msg"]) + var/t = input(usr, "Please enter messenger", src.id_tag, null) as text + t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN) + if (!t) + return + if (!in_range(src.master, usr)) + return + + var/datum/signal/signal = new + signal.data["type"] = "message" + signal.data["data"] = t + signal.data["sender"] = src.screen_name + src.messages += "→ You:
[t]
" + peripheral_command("send signal", signal) + + if(href_list["func_msg"]) + switch(href_list["func_msg"]) + if("clear") + src.messages = null + + if("print") + var/datum/signal/signal = new + signal.data["data"] = src.messages + signal.data["title"] = "Chatlog" + peripheral_command("print", signal) + + //if("save") + //TO-DO + + + if(href_list["set_name"]) + var/t = input(usr, "Please enter screen name", src.id_tag, null) as text + t = copytext(sanitize(t), 1, 20) + if (!t) + return + if (!in_range(src.master, usr)) + return + + src.screen_name = t + + src.master.add_fingerprint(usr) + src.master.updateUsrDialog() + return + + receive_command(obj/source, command, datum/signal/signal) + if(..() || !signal) + return + + if(command == "radio signal") + switch(signal.data["type"]) + if("message") + var/sender = signal.data["sender"] + if(!sender) + sender = "Unknown" + + src.messages += "← From [sender]:
[signal.data["data"]]
" + if(src.master.active_program == src) + playsound(src.master.loc, 'twobeep.ogg', 50, 1) + src.master.updateUsrDialog() + + return \ No newline at end of file diff --git a/code/WorkInProgress/computer2/peripherals.dm b/code/WorkInProgress/computer2/peripherals.dm new file mode 100644 index 0000000000000..2f22a2d32552e --- /dev/null +++ b/code/WorkInProgress/computer2/peripherals.dm @@ -0,0 +1,209 @@ +/obj/item/weapon/peripheral + name = "Peripheral card" + desc = "A computer circuit board." + icon = 'module.dmi' + icon_state = "id_mod" + item_state = "electronic" + w_class = 2 + var/obj/machinery/computer2/host + var/id = null + + New() + ..() + spawn(2) + if(istype(src.loc,/obj/machinery/computer2)) + host = src.loc + host.peripherals.Add(src) +// var/setup_id = "\ref[src]" +// src.id = copytext(setup_id,4,(length(setup_id)-1) ) + + Del() + if(host) + host.peripherals.Remove(src) + ..() + + + proc + receive_command(obj/source, command, datum/signal/signal) + if((source != host) || !(src in host)) + return 1 + + if(!command) + return 1 + + return 0 + + send_command(command, datum/signal/signal) + if(!command || !host) + return + + src.host.receive_command(src, command, signal) + + return + +/obj/item/weapon/peripheral/radio + name = "Wireless card" + var/frequency = 1419 + var/code = null + var/datum/radio_frequency/radio_connection + New() + ..() + if(radio_controller) + initialize() + + initialize() + set_frequency(frequency) + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + radio_connection = radio_controller.add_object(src, "[frequency]") + + receive_command(obj/source, command, datum/signal/signal) + if(..()) + return + + if(!signal || !radio_connection) + return + + switch(command) + if("send signal") + src.radio_connection.post_signal(src, signal) + + return + + receive_signal(datum/signal/signal) + if(!signal || (signal.encryption && signal.encryption != code)) + return + + var/datum/signal/newsignal = new + newsignal.data = signal.data + if(src.code) + newsignal.encryption = src.code + + send_command("radio signal",newsignal) + return + +/obj/item/weapon/peripheral/printer + name = "Printer module" + desc = "A small printer designed to fit into a computer casing." + icon_state = "card_mod" + var/printing = 0 + + receive_command(obj/source,command, datum/signal/signal) + if(..()) + return + + if(!signal) + return + + if((command == "print") && !src.printing) + src.printing = 1 + + var/print_data = signal.data["data"] + var/print_title = signal.data["title"] + if(!print_data) + src.printing = 0 + return + spawn(50) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( src.host.loc ) + P.info = print_data + if(print_title) + P.name = "paper- '[print_title]'" + + src.printing = 0 + return + + return + +/obj/item/weapon/peripheral/prize_vendor + name = "Prize vending module" + desc = "An arcade prize dispenser designed to fit inside a computer casing." + icon_state = "power_mod" + var/last_vend = 0 //Delay between vends if manually activated(ie a dude is holding it and shaking stuff out) + + receive_command(obj/source,command, datum/signal/signal) + if(..()) + return + + if(command == "vend prize") + src.vend_prize() + + return + + attack_self(mob/user as mob) + if( (last_vend + 400) < world.time) + user << "You shake something out of [src]!" + src.vend_prize() + src.last_vend = world.time + else + user << "\red [src] isn't ready to dispense a prize yet." + + return + + proc/vend_prize() + var/obj/item/prize + var/prizeselect = rand(1,4) + var/turf/prize_location = null + + if(src.host) + prize_location = src.host.loc + else + prize_location = get_turf(src) + + switch(prizeselect) + if(1) + prize = new /obj/item/weapon/spacecash( prize_location ) + prize.name = "space ticket" + prize.desc = "It's almost like actual currency!" + if(2) + prize = new /obj/item/device/radio/beacon( prize_location ) + prize.name = "electronic blink toy game" + prize.desc = "Blink. Blink. Blink." + if(3) + prize = new /obj/item/weapon/zippo( prize_location ) + prize.name = "Burno Lighter" + prize.desc = "Almost like a decent lighter!" + if(4) + prize = new /obj/item/weapon/c_tube( prize_location ) + prize.name = "toy sword" + prize.icon = 'weapons.dmi' + prize.icon_state = "sword1" + prize.desc = "A sword made of cheap plastic." + +/* +/obj/item/weapon/peripheral/card_scanner + name = "ID scanner module" + icon_state = "card_mod" + var/obj/item/weapon/card/id/authid = null + + attack_self(mob/user as mob) + if(authid) + user << "The card falls out." + src.authid.loc = get_turf(user) + src.authid = null + + return + + receive_command(obj/source,command, datum/signal/signal) + if(..()) + return + + if(!signal || (signal.data["ref_id"] != "\ref[src]") ) + return + + switch(command) + if("eject card") + if(src.authid) + src.authid.loc = src.host.loc + src.authid = null + if("add card access") + var/new_access = signal.data["access"] + if(!new_access) + return + + + + return +*/ \ No newline at end of file diff --git a/code/WorkInProgress/explosion_particles.dm b/code/WorkInProgress/explosion_particles.dm new file mode 100644 index 0000000000000..174b346c508ff --- /dev/null +++ b/code/WorkInProgress/explosion_particles.dm @@ -0,0 +1,70 @@ +/obj/effects/expl_particles + name = "fire" + icon = 'effects.dmi' + icon_state = "explosion_particle" + opacity = 1 + anchored = 1 + mouse_opacity = 0 + +/obj/effects/expl_particles/New() + ..() + spawn (15) + del(src) + return + +/obj/effects/expl_particles/Move() + ..() + return + +/datum/effects/system/expl_particles + var/number = 10 + var/turf/location + var/total_particles = 0 + +/datum/effects/system/expl_particles/proc/set_up(n = 10, loca) + number = n + if(istype(loca, /turf/)) location = loca + else location = get_turf(loca) + +/datum/effects/system/expl_particles/proc/start() + var/i = 0 + for(i=0, i[src.master.scan_program.name]" : "None loaded"]" + dat += "
  • [src.master.fon ? "Disable" : "Enable"] Flashlight
  • " + + dat += "" + + if(1) + //Note Program. Can save/load note files. + dat += "

    Notekeeper V2.5

    " + + if(!src.note_mode) + dat += "Edit" + dat += " | New File" + dat += " | Save" + dat += " | Load
    " + + dat += src.note + else + dat += " Back" + dat += " | \[[src.holding_folder.holder.file_amount - src.holding_folder.holder.file_used]\] Free
    " + dat += "" + + for(var/datum/computer/file/text/T in src.holding_folder.contents) + dat += "" + dat += "" + dat += "" + + dat += "
    [T.name][T.extension]Length: [T.data ? (length(T.data)) : "0"]
    " + + if(2) + //Messenger. Uses Radio. Is a messenger. + //TO-DO: ~file sharing~ + src.master.overlays = null //Remove existing alerts + dat += "

    SpaceMessenger V4.0.5

    " + + if (!src.message_mode) + + dat += "Ringer: [src.message_silent == 1 ? "Off" : "On"] | " + dat += "Send / Receive: [src.message_on == 1 ? "On" : "Off"] | " + dat += "Set Ringtone | " + dat += "Messages
    " + + dat += "Scan
    " + dat += "Detected PDAs
    " + + dat += "
      " + + var/count = 0 + + if (src.message_on) + for (var/obj/item/device/pda2/P in src.detected_pdas) + if (!P.owner) + src.detected_pdas -= P + continue + else if (P == src) //I guess this can happen if somebody copies the system file. + src.detected_pdas -= P + continue + + dat += "
    • [P]" + + dat += "
    • " + count++ + + dat += "
    " + + if (count == 0) + dat += "None detected.
    " + + else + dat += "Clear | " + dat += "Back
    " + + dat += "

    Messages

    " + + dat += src.message_note + dat += "
    " + + if(3) + //File Browser. + //To-do(?): Setting "favorite" programs to access straight from main menu + //Not sure how needed it is, not like they have to go through 500 subfolders or whatever + if((!src.browse_folder) || !(src.browse_folder.holder in src.master)) + src.browse_folder = src.holding_folder + + dat += " | Paste" + dat += " | Drive: " + dat += "\[[src.browse_folder.holder == src.master.hd ? "MAIN" : "CART"]\]
    " + + dat += "Contents of [browse_folder] | Drive ID:\[[src.browse_folder.holder.title]]
    " + dat += "Used: \[[src.browse_folder.holder.file_used]/[src.browse_folder.holder.file_amount]\]
    " + + dat += "" + for(var/datum/computer/file/F in browse_folder.contents) + if(F == src) + dat += "" + continue + dat += "" + dat += "" + + dat += "" + + dat += "" + dat += "" + + dat += "" + + dat += "" + + dat += "
    SystemSize: [src.size]SYSTEM
    [F.name]Size: [F.size][F.extension]DelRenameCopy
    " + + if(4) + //Atmos Scanner + dat += "

    Atmospheric Readings

    " + + var/turf/T = get_turf_or_move(get_turf(src.master)) + if (isnull(T)) + dat += "Unable to obtain a reading.
    " + else + var/datum/gas_mixture/environment = T.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles() + + dat += "Air Pressure: [round(pressure,0.1)] kPa
    " + + if (total_moles) + var/o2_level = environment.oxygen/total_moles + var/n2_level = environment.nitrogen/total_moles + var/co2_level = environment.carbon_dioxide/total_moles + var/plasma_level = environment.toxins/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) + + dat += "Nitrogen: [round(n2_level*100)]%
    " + + dat += "Oxygen: [round(o2_level*100)]%
    " + + dat += "Carbon Dioxide: [round(co2_level*100)]%
    " + + dat += "Plasma: [round(plasma_level*100)]%
    " + + if(unknown_level > 0.01) + dat += "OTHER: [round(unknown_level)]%
    " + + dat += "Temperature: [round(environment.temperature-T0C)]°C
    " + + dat += "
    " + + return dat + + Topic(href, href_list) + if(..()) + return + + if(href_list["mode"]) + var/newmode = text2num(href_list["mode"]) + src.mode = max(newmode, 0) + + else if(href_list["flight"]) + src.master.toggle_light() + + else if(href_list["scanner"]) + if(src.master.scan_program) + src.master.scan_program = null + + else if(href_list["input"]) + switch(href_list["input"]) + if("tone") + var/t = input(usr, "Please enter new ringtone", src.name, src.message_tone) as text + if (!t) + return + + if (!src.master || !in_range(src.master, usr) && src.master.loc != usr) + return + + if(!(src.holder in src.master)) + return + + t = copytext(sanitize(t), 1, 20) + src.message_tone = t + + if("note") + var/t = input(usr, "Please enter note", src.name, src.note) as message + if (!t) + return + + if (!src.master || !in_range(src.master, usr) && src.master.loc != usr) + return + + if(!(src.holder in src.master)) + return + + t = copytext(adminscrub(t), 1, MAX_MESSAGE_LEN) + src.note = t + + + if("message") + var/obj/item/device/pda2/P = locate(href_list["target"]) + if(!P || !istype(P)) + return + + var/t = input(usr, "Please enter message", P.name, null) as text + if (!t) + return + + if (!src.master || !in_range(src.master, usr) && src.master.loc != usr) + return + + if(!(src.holder in src.master)) + return + + + var/datum/signal/signal = new + signal.data["command"] = "text message" + signal.data["message"] = t + signal.data["sender"] = src.master.owner + signal.data["tag"] = "\ref[P]" + src.post_signal(signal) + src.message_note += "→ To [P.owner]:
    [t]
    " + + if("rename") + var/datum/computer/file/F = locate(href_list["target"]) + if(!F || !istype(F)) + return + + var/t = input(usr, "Please enter new name", src.name, F.name) as text + t = copytext(sanitize(t), 1, 16) + if (!t) + return + if (!in_range(src.master, usr) || !(F.holder in src.master)) + return + if(F.holder.read_only) + return + F.name = capitalize(lowertext(t)) + + + else if(href_list["message_func"]) //Messenger specific topic junk + switch(href_list["message_func"]) + if("ringer") + src.message_silent = !src.message_silent + if("on") + src.message_on = !src.message_on + if("clear") + src.message_note = null + if("scan") + if(src.message_on) + src.detected_pdas = list() + var/datum/signal/signal = new + signal.data["command"] = "report pda" + src.post_signal(signal) + + else if(href_list["note_func"]) //Note program specific topic junk + switch(href_list["note_func"]) + if("new") + src.note_file = null + src.note = null + if("save") + if(src.note_file && src.note_file.holder in src.master) + src.note_file.data = src.note + else + var/datum/computer/file/text/F = new /datum/computer/file/text + if(!src.holding_folder.add_file(F)) + del(F) + else + src.note_file = F + F.data = src.note + + if("load") + var/datum/computer/file/text/T = locate(href_list["target"]) + if(!T || !istype(T)) + return + + src.note_file = T + src.note = note_file.data + src.note_mode = 0 + + if("switchmenu") + src.note_mode = !src.note_mode + + else if(href_list["browse_func"]) //File browser specific topic junk + var/datum/computer/target = locate(href_list["target"]) + switch(href_list["browse_func"]) + if("drive") + if(src.browse_folder.holder == src.master.hd && src.master.cartridge && (src.master.cartridge.root)) + src.browse_folder = src.master.cartridge.root + else + src.browse_folder = src.holding_folder + if("open") + if(!target || !istype(target)) + return + if(istype(target, /datum/computer/file/pda_program)) + if(istype(target,/datum/computer/file/pda_program/os) && (src.master.host_program)) + return + else + src.master.run_program(target) + src.master.updateSelfDialog() + return + + if("delete") + if(!target || !istype(target)) + return + src.master.delete_file(target) + + if("copy") + if(istype(target,/datum/computer/file) && (!target.holder || (target.holder in src.master.contents))) + src.clipboard = target + + if("paste") + if(istype(target,/datum/computer/folder)) + if(!src.clipboard || !src.clipboard.holder || !(src.clipboard.holder in src.master.contents)) + return + + if(!istype(src.clipboard)) + return + + src.clipboard.copy_file_to_folder(target) + + + else if(href_list["message_mode"]) + var/newmode = text2num(href_list["message_mode"]) + src.message_mode = max(newmode, 0) + + src.master.add_fingerprint(usr) + src.master.updateSelfDialog() + return + + receive_signal(datum/signal/signal) + if(..()) + return + + switch(signal.data["command"]) + if("text message") + if(!message_on || !signal.data["message"]) + return + var/sender = signal.data["sender"] + if(!sender) + sender = "!Unknown!" + + src.message_note += "← From [sender]:
    [signal.data["message"]]
    " + var/alert_beep = null //Don't beep if set to silent. + if(!src.message_silent) + alert_beep = src.message_tone + + src.master.display_alert(alert_beep) + src.master.updateSelfDialog() + + if("report pda") + if(!message_on) + return + + var/datum/signal/newsignal = new + newsignal.data["command"] = "reporting pda" + newsignal.data["tag"] = "\ref[signal.source]" + src.post_signal(newsignal) + + if("reporting pda") + if(!detected_pdas) + detected_pdas = new() + + if(!(signal.source in detected_pdas)) + detected_pdas += signal.source + + src.master.updateSelfDialog() + + return + + return_text_header() + if(!src.master) + return + + var/dat + + if(src.mode) + dat += " | Main Menu" + + else if (!isnull(src.master.cartridge)) + dat += " | Eject [src.master.cartridge]" + + dat += " | Refresh" + + return dat \ No newline at end of file diff --git a/code/WorkInProgress/pda2/base_program.dm b/code/WorkInProgress/pda2/base_program.dm new file mode 100644 index 0000000000000..f5c11efc07780 --- /dev/null +++ b/code/WorkInProgress/pda2/base_program.dm @@ -0,0 +1,185 @@ +//Eventual plan: Convert all datum/data to datum/computer/file +/datum/computer/file/text + name = "text" + extension = "TEXT" + size = 2.0 + var/data = null + +/datum/computer/file/record + name = "record" + extension = "REC" + + var/list/fields = list( ) + + +//base pda program + +/datum/computer/file/pda_program + name = "blank program" + extension = "PPROG" + var/obj/item/device/pda2/master = null + var/id_tag = null + + os + name = "blank system program" + extension = "PSYS" + + scan + name = "blank scan program" + extension = "PSCAN" + + New(obj/holding as obj) + if(holding) + src.holder = holding + + if(istype(src.holder.loc,/obj/item/device/pda2)) + src.master = src.holder.loc + + proc + return_text() + if((!src.holder) || (!src.master)) + return 1 + + if((!istype(holder)) || (!istype(master))) + return 1 + + if(!(holder in src.master.contents)) + //world << "Holder [holder] not in [master] of prg:[src]" + if(master.active_program == src) + master.active_program = null + return 1 + + if(!src.holder.root) + src.holder.root = new /datum/computer/folder + src.holder.root.holder = src + src.holder.root.name = "root" + + return 0 + + process() //This isn't actually used at the moment + if((!src.holder) || (!src.master)) + return 1 + + if((!istype(holder)) || (!istype(master))) + return 1 + + if(!(holder in src.master.contents)) + if(master.active_program == src) + master.active_program = null + return 1 + + if(!src.holder.root) + src.holder.root = new /datum/computer/folder + src.holder.root.holder = src + src.holder.root.name = "root" + + return 0 + + //maybe remove this, I haven't found a good use for it yet + send_os_command(list/command_list) + if(!src.master || !src.holder || src.master.host_program || !command_list) + return 1 + + if(!istype(src.master.host_program) || src.master.host_program == src) + return 1 + + src.master.host_program.receive_os_command() + + return 0 + + return_text_header() + if(!src.master || !src.holder) + return + + var/dat = " | Main Menu" + dat += " | Refresh" + + return dat + + post_signal(datum/signal/signal, newfreq) + if(master) + master.post_signal(signal, newfreq) + else + del(signal) + + transfer_holder(obj/item/weapon/disk/data/newholder,datum/computer/folder/newfolder) + + if((newholder.file_used + src.size) > newholder.file_amount) + return 0 + + if(!newholder.root) + newholder.root = new /datum/computer/folder + newholder.root.holder = newholder + newholder.root.name = "root" + + if(!newfolder) + newfolder = newholder.root + + if((src.holder && src.holder.read_only) || newholder.read_only) + return 0 + + if((src.holder) && (src.holder.root)) + src.holder.root.remove_file(src) + + newfolder.add_file(src) + + if(istype(newholder.loc,/obj/item/device/pda2)) + src.master = newholder.loc + + //world << "Setting [src.holder] to [newholder]" + src.holder = newholder + return 1 + + + receive_signal(datum/signal/signal) + if((!src.holder) || (!src.master)) + return 1 + + if((!istype(holder)) || (!istype(master))) + return 1 + + if(!(holder in src.master.contents)) + if(master.active_program == src) + master.active_program = null + return 1 + + return 0 + + + Topic(href, href_list) + if((!src.holder) || (!src.master)) + return 1 + + if((!istype(holder)) || (!istype(master))) + return 1 + + if(src.master.active_program != src) + return 1 + + if ((!usr.contents.Find(src.master) && (!in_range(src.master, usr) || !istype(src.master.loc, /turf))) && (!istype(usr, /mob/living/silicon))) + return 1 + + if(!(holder in src.master.contents)) + if(master.active_program == src) + master.active_program = null + return 1 + + usr.machine = src.master + + if (href_list["close"]) + usr.machine = null + usr << browse(null, "window=pda2") + return 0 + + if (href_list["quit"]) +// src.master.processing_programs.Remove(src) + if(src.master.host_program && src.master.host_program.holder && (src.master.host_program.holder in src.master.contents)) + src.master.run_program(src.master.host_program) + src.master.updateSelfDialog() + return 1 + else + src.master.active_program = null + src.master.updateSelfDialog() + return 1 + + return 0 \ No newline at end of file diff --git a/code/WorkInProgress/pda2/pda2.dm b/code/WorkInProgress/pda2/pda2.dm new file mode 100644 index 0000000000000..96cd01e4bcf1d --- /dev/null +++ b/code/WorkInProgress/pda2/pda2.dm @@ -0,0 +1,297 @@ +//The advanced pea-green monochrome lcd of tomorrow. + + +//TO-DO: rearrange all this disk/data stuff so that fixed disks are the parent type +//because otherwise you have carts going into floppy drives and it's ALL MAD +/obj/item/weapon/disk/data/cartridge + name = "Cart 2.0" + desc = "A data cartridge for portable microcomputers." + icon = 'pda.dmi' + icon_state = "cart" + item_state = "electronic" + file_amount = 80.0 + title = "ROM Cart" + + pda2test + name = "Test Cart" + New() + ..() + src.root.add_file( new /datum/computer/file/computer_program/arcade(src)) + src.root.add_file( new /datum/computer/file/pda_program/manifest(src)) + src.root.add_file( new /datum/computer/file/pda_program/status_display(src)) + src.root.add_file( new /datum/computer/file/pda_program/signaler(src)) + src.root.add_file( new /datum/computer/file/pda_program/qm_records(src)) + src.root.add_file( new /datum/computer/file/pda_program/scan/health_scan(src)) + src.root.add_file( new /datum/computer/file/pda_program/records/security(src)) + src.root.add_file( new /datum/computer/file/pda_program/records/medical(src)) + src.read_only = 1 + + +/obj/item/device/pda2 + name = "PDA" + desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by an EEPROM cartridge." + icon = 'pda.dmi' + icon_state = "pda" + item_state = "electronic" + w_class = 2.0 + flags = FPRINT | TABLEPASS | ONBELT + + var/owner = null + var/default_cartridge = null // Access level defined by cartridge + var/obj/item/weapon/disk/data/cartridge/cartridge = null //current cartridge + var/datum/computer/file/pda_program/active_program = null + var/datum/computer/file/pda_program/os/host_program = null + var/datum/computer/file/pda_program/scan/scan_program = null + var/obj/item/weapon/disk/data/fixed_disk/hd = null + var/fon = 0 //Is the flashlight function on? + var/f_lum = 3 //Luminosity for the flashlight function +// var/datum/data/record/active1 = null //General +// var/datum/data/record/active2 = null //Medical +// var/datum/data/record/active3 = null //Security +// var/obj/item/weapon/integrated_uplink/uplink = null //Maybe replace uplink with some remote ~syndicate~ server + var/frequency = 1149 + var/datum/radio_frequency/radio_connection + + var/setup_default_cartridge = null //Cartridge contains job-specific programs + var/setup_drive_size = 24.0 //PDAs don't have much work room at all, really. + var/setup_system_os_path = /datum/computer/file/pda_program/os/main_os //Needs an operating system to...operate!! + + +/obj/item/device/pda2/pickup(mob/user) + if (src.fon) + src.sd_SetLuminosity(0) + user.sd_SetLuminosity(user.luminosity + src.f_lum) + +/obj/item/device/pda2/dropped(mob/user) + if (src.fon) + user.sd_SetLuminosity(user.luminosity - src.f_lum) + src.sd_SetLuminosity(src.f_lum) + +/obj/item/device/pda2/New() + ..() + spawn(5) + src.hd = new /obj/item/weapon/disk/data/fixed_disk(src) + src.hd.file_amount = src.setup_drive_size + src.hd.name = "Minidrive" + src.hd.title = "Minidrive" + + if(src.setup_system_os_path) + src.host_program = new src.setup_system_os_path + + src.hd.file_amount = max(src.hd.file_amount, src.host_program.size) + + src.host_program.transfer_holder(src.hd) + + if(radio_controller) + radio_controller.add_object(src, "[frequency]") + + + if (src.default_cartridge) + src.cartridge = new src.setup_default_cartridge(src) +// if(src.owner) +// processing_items.Add(src) + +/obj/item/device/pda2/attack_self(mob/user as mob) + user.machine = src + + var/dat = "Personal Data Assistant " + + dat += "Close" + + if (!src.owner) + if(src.cartridge) + dat += " | Eject [src.cartridge]" + dat += "
    Warning: No owner information entered. Please swipe card.

    " + dat += "Retry" + else + if(src.active_program) + dat += src.active_program.return_text() + else + if(src.host_program) + src.run_program(src.host_program) + dat += src.active_program.return_text() + else + if(src.cartridge) + dat += " | Eject [src.cartridge]
    " + dat += "
    Fatal Error 0x17
    " + dat += "No System Software Loaded
    " + //To-do: System recovery shit (maybe have a dedicated computer for this kind of thing) + + + user << browse(dat,"window=pda2") + onclose(user,"pda2") + return + +/obj/item/device/pda2/Topic(href, href_list) + ..() + + if (usr.contents.Find(src) || usr.contents.Find(src.master) || (istype(src.loc, /turf) && get_dist(src, usr) <= 1)) + if (usr.stat || usr.restrained()) + return + + src.add_fingerprint(usr) + usr.machine = src + + + if(href_list["return_to_host"]) + if(src.host_program) + src.active_program = src.host_program + src.host_program = null + + else if (href_list["eject_cart"]) + src.eject_cartridge() + + else if (href_list["refresh"]) + src.updateSelfDialog() + + else if (href_list["close"]) + usr << browse(null, "window=pda2") + usr.machine = null + + src.updateSelfDialog() + return + +/obj/item/device/pda2/attackby(obj/item/weapon/C as obj, mob/user as mob) + if (istype(C, /obj/item/weapon/disk/data/cartridge) && isnull(src.cartridge)) + user.drop_item() + C.loc = src + user << "\blue You insert [C] into [src]." + src.cartridge = C + src.updateSelfDialog() + + else if (istype(C, /obj/item/weapon/card/id) && !src.owner && C:registered) + src.owner = C:registered + src.name = "PDA-[src.owner]" + user << "\blue Card scanned." + src.updateSelfDialog() + +/obj/item/device/pda2/receive_signal(datum/signal/signal) + if(!signal || signal.encryption || !src.owner) return + + if(signal.data["tag"] && signal.data["tag"] != "\ref[src]") return + + if(src.host_program) + src.host_program.receive_signal(signal) + + if(src.active_program && (src.active_program != src.host_program)) + src.host_program.receive_signal(signal) + + return + +/obj/item/device/pda2/attack(mob/M as mob, mob/user as mob) + if(src.scan_program) + return + else + ..() + +/obj/item/device/pda2/afterattack(atom/A as mob|obj|turf|area, mob/user as mob) + var/scan_dat = null + if(src.scan_program && istype(src.scan_program)) + scan_dat = src.scan_program.scan_atom(A) + + if(scan_dat) + A.visible_message("\red [user] has scanned [A]!") + user.show_message(scan_dat, 1) + + return + + +/obj/item/device/pda2/proc + + post_signal(datum/signal/signal,var/newfreq) + if(!signal) + return + var/freq = newfreq + if(!freq) + freq = src.frequency + + signal.source = src + + var/datum/radio_frequency/frequency = radio_controller.return_frequency("[freq]") + + signal.transmission_method = TRANSMISSION_RADIO + if(frequency) + return frequency.post_signal(src, signal) + else + del(signal) + + eject_cartridge() + if(src.cartridge) + var/turf/T = get_turf(src) + + if(src.active_program && (src.active_program.holder == src.cartridge)) + src.active_program = null + + if(src.host_program && (src.host_program.holder == src.cartridge)) + src.host_program = null + + if(src.scan_program && (src.scan_program.holder == src.cartridge)) + src.scan_program = null + + src.cartridge.loc = T + src.cartridge = null + + return + + //Toggle the built-in flashlight + toggle_light() + src.fon = (!src.fon) + + if (ismob(src.loc)) + if (src.fon) + src.loc.sd_SetLuminosity(src.loc.luminosity + src.f_lum) + else + src.loc.sd_SetLuminosity(src.loc.luminosity - src.f_lum) + else + src.sd_SetLuminosity(src.fon * src.f_lum) + + src.updateSelfDialog() + + display_alert(var/alert_message) //Add alert overlay and beep + if (alert_message) + playsound(src.loc, 'twobeep.ogg', 50, 1) + for (var/mob/O in hearers(3, src.loc)) + O.show_message(text("\icon[src] *[alert_message]*")) + + src.overlays = null + src.overlays += image('pda.dmi', "pda-r") + return + + run_program(datum/computer/file/pda_program/program) + if((!program) || (!program.holder)) + return 0 + + if(!(program.holder in src)) + // world << "Not in src" + program = new program.type + program.transfer_holder(src.hd) + + if(program.master != src) + program.master = src + + if(!src.host_program && istype(program, /datum/computer/file/pda_program/os)) + src.host_program = program + + if(istype(program, /datum/computer/file/pda_program/scan)) + if(program == src.scan_program) + src.scan_program = null + else + src.scan_program = program + return 1 + + src.active_program = program + return 1 + + delete_file(datum/computer/file/file) + //world << "Deleting [file]..." + if((!file) || (!file.holder) || (file.holder.read_only)) + //world << "Cannot delete :(" + return 0 + + //Don't delete the running program you jerk + if(src.active_program == file || src.host_program == file) + src.active_program = null + + //world << "Now calling del on [file]..." + del(file) + return 1 \ No newline at end of file diff --git a/code/WorkInProgress/pda2/record_progs.dm b/code/WorkInProgress/pda2/record_progs.dm new file mode 100644 index 0000000000000..2ea856c93e2cc --- /dev/null +++ b/code/WorkInProgress/pda2/record_progs.dm @@ -0,0 +1,181 @@ +//CONTENTS: +//Generic records +//Security records +//Medical records + + +/datum/computer/file/pda_program/records + var/mode = 0 + var/datum/data/record/active1 = null //General + var/datum/data/record/active2 = null //Security/Medical/Whatever + +//To-do: editing arrest status/etc from pda. +/datum/computer/file/pda_program/records/security + name = "Security Records" + size = 12.0 + + return_text() + if(..()) + return + + var/dat = src.return_text_header() + + switch(src.mode) + if(0) + dat += "

    Security Record List

    " + + for (var/datum/data/record/R in data_core.general) + dat += "[R.fields["id"]]: [R.fields["name"]]
    " + + dat += "
    " + + if(1) + + dat += "

    Security Record

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

    Security Data

    " + if (istype(src.active2, /datum/data/record) && data_core.security.Find(src.active2)) + dat += "Criminal Status: [src.active2.fields["criminal"]]
    " + + dat += "Minor Crimes: [src.active2.fields["mi_crim"]]
    " + dat += "Details: [src.active2.fields["mi_crim"]]

    " + + dat += "Major Crimes: [src.active2.fields["ma_crim"]]
    " + dat += "Details: [src.active2.fields["ma_crim_d"]]

    " + + dat += "Important Notes:
    " + dat += "[src.active2.fields["notes"]]" + else + dat += "Record Lost!
    " + + dat += "
    " + + return dat + + Topic(href, href_list) + if(..()) + return + + if(href_list["mode"]) + var/newmode = text2num(href_list["mode"]) + src.mode = max(newmode, 0) + + else if(href_list["select_rec"]) + var/datum/data/record/R = locate(href_list["select_rec"]) + var/datum/data/record/S = locate(href_list["select_rec"]) + + if (data_core.general.Find(R)) + for (var/datum/data/record/E in data_core.security) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + S = E + break + + src.active1 = R + src.active2 = S + + src.mode = 1 + + src.master.add_fingerprint(usr) + src.master.updateSelfDialog() + return + +/datum/computer/file/pda_program/records/medical + name = "Medical Records" + size = 8.0 + + return_text() + if(..()) + return + + var/dat = src.return_text_header() + + switch(src.mode) + if(0) + + dat += "

    Medical Record List

    " + for (var/datum/data/record/R in data_core.general) + dat += "[R.fields["id"]]: [R.fields["name"]]
    " + dat += "
    " + + if(1) + + dat += "

    Medical Record

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

    Medical Data

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

    " + + dat += "Minor Disabilities: [src.active2.fields["mi_dis"]]
    " + dat += "Details: [src.active2.fields["mi_dis_d"]]

    " + + dat += "Major Disabilities: [src.active2.fields["ma_dis"]]
    " + dat += "Details: [src.active2.fields["ma_dis_d"]]

    " + + dat += "Allergies: [src.active2.fields["alg"]]
    " + dat += "Details: [src.active2.fields["alg_d"]]

    " + + dat += "Current Diseases: [src.active2.fields["cdi"]]
    " + dat += "Details: [src.active2.fields["cdi_d"]]

    " + + dat += "Important Notes: [src.active2.fields["notes"]]
    " + else + dat += "Record Lost!
    " + + dat += "
    " + + return dat + + Topic(href, href_list) + if(..()) + return + + if(href_list["mode"]) + var/newmode = text2num(href_list["mode"]) + src.mode = max(newmode, 0) + + else if(href_list["select_rec"]) + var/datum/data/record/R = locate(href_list["select_rec"]) + var/datum/data/record/M = locate(href_list["select_rec"]) + + if (data_core.general.Find(R)) + for (var/datum/data/record/E in data_core.medical) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + M = E + break + + src.active1 = R + src.active2 = M + + src.mode = 1 + + src.master.add_fingerprint(usr) + src.master.updateSelfDialog() + return \ No newline at end of file diff --git a/code/WorkInProgress/pda2/scanners.dm b/code/WorkInProgress/pda2/scanners.dm new file mode 100644 index 0000000000000..9bdd98b2fbf81 --- /dev/null +++ b/code/WorkInProgress/pda2/scanners.dm @@ -0,0 +1,101 @@ +//CONTENTS: +//Base scanner stuff +//Health scanner +//Forensic scanner +//Reagent scanner + +/datum/computer/file/pda_program/scan + return_text() + return src.return_text_header() + + proc/scan_atom(atom/A as mob|obj|turf|area) + + if( !A || (!src.holder) || (!src.master)) + return 1 + + if((!istype(holder)) || (!istype(master))) + return 1 + + if(!(holder in src.master.contents)) + if(master.scan_program == src) + master.scan_program = null + return 1 + + return 0 + + //Health analyzer program + health_scan + name = "Health Scan" + size = 8.0 + + scan_atom(atom/A as mob|obj|turf|area) + if(..()) + return + + var/mob/living/carbon/C = A + if(!istype(C)) + return + + var/dat = "\blue Analyzing Results for [C]:\n" + dat += "\blue \t Overall Status: [C.stat > 1 ? "dead" : "[C.health]% healthy"]\n" + dat += "\blue \t Damage Specifics: [C.oxyloss > 50 ? "\red" : "\blue"][C.oxyloss]-[C.toxloss > 50 ? "\red" : "\blue"][C.toxloss]-[C.fireloss > 50 ? "\red" : "\blue"][C.fireloss]-[C.bruteloss > 50 ? "\red" : "\blue"][C.bruteloss]\n" + dat += "\blue \t Key: Suffocation/Toxin/Burns/Brute\n" + dat += "\blue \t Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)" + if(C.virus) + dat += "\red \nWarning Virus Detected.\nName: [C.virus.name].\nType: [C.virus.spread].\nStage: [C.virus.stage]/[C.virus.max_stages].\nPossible Cure: [C.virus.cure]" + + return dat + + //Forensic scanner + forensic_scan + name = "Forensic Scan" + size = 8.0 + + scan_atom(atom/A as mob|obj|turf|area) + if(..()) + return + var/dat = null + + if(istype(A,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = A + if (!istype(H.dna, /datum/dna) || !isnull(H.gloves)) + dat += "\blue Unable to scan [A]'s fingerprints.\n" + else + dat += "\blue [H]'s Fingerprints: [md5(H.dna.uni_identity)]\n" + if ( !(H.blood_DNA) ) + dat += "\blue No blood found on [H]\n" + else + dat += "\blue Blood type: [H.blood_type]\nDNA: [H.blood_DNA]\n" + + if (!A.fingerprints) + dat += "\blue Unable to locate any fingerprints on [A]!\n" + else + var/list/L = params2list(A:fingerprints) + dat += "\blue Isolated [L.len] fingerprints.\n" + for(var/i in L) + dat += "\blue \t [i]\n" + + return dat + + + //Reagent scanning program + reagent_scan + name = "Reagent Scan" + size = 6.0 + + scan_atom(atom/A as mob|obj|turf|area) + if(..()) + return + var/dat = null + if(!isnull(A.reagents)) + if(A.reagents.reagent_list.len > 0) + var/reagents_length = A.reagents.reagent_list.len + dat += "\blue [reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.\n" + for (var/datum/reagent/re in A.reagents.reagent_list) + dat += "\blue \t [re] - [re.volume]\n" + else + dat = "\blue No active chemical agents found in [A]." + else + dat = "\blue No significant chemical agents found in [A]." + + return dat diff --git a/code/WorkInProgress/pda2/smallprogs.dm b/code/WorkInProgress/pda2/smallprogs.dm new file mode 100644 index 0000000000000..549e8fc0f5217 --- /dev/null +++ b/code/WorkInProgress/pda2/smallprogs.dm @@ -0,0 +1,204 @@ +//Assorted small programs not worthy of their own file +//CONTENTS: +//Crew Manifest viewer +//Status display controller +//Remote signaling program +//Cargo orders monitor + +//Manifest +/datum/computer/file/pda_program/manifest + name = "Manifest" + + return_text() + if(..()) + return + + var/dat = src.return_text_header() + + dat += "

    Crew Manifest

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

    " + + for (var/datum/data/record/t in data_core.general) + dat += "[t.fields["name"]] - [t.fields["rank"]]
    " + dat += "
    " + + return dat + +//Status Display +/datum/computer/file/pda_program/status_display + name = "Status Controller" + size = 8.0 + var/message1 // For custom messages on the displays. + var/message2 + + return_text() + if(..()) + return + + var/dat = src.return_text_header() + + dat += "

    Station Status Display Interlink

    " + + dat += "\[ Clear \]
    " + dat += "\[ Shuttle ETA \]
    " + dat += "\[ Message \]" + + dat += "
    " + dat += "\[ Alert: None |" + + dat += " Red Alert |" + dat += " Lockdown |" + dat += " Biohazard \]
    " + + return dat + + + Topic(href, href_list) + if(..()) + return + + if(href_list["statdisp"]) + switch(href_list["statdisp"]) + if("message") + post_status("message", message1, message2) + if("alert") + post_status("alert", href_list["alert"]) + + if("setmsg1") + message1 = input("Line 1", "Enter Message Text", message1) as text|null + if (!src.master || !in_range(src.master, usr) && src.master.loc != usr) + return + + if(!(src.holder in src.master)) + return + src.master.updateSelfDialog() + + if("setmsg2") + message2 = input("Line 2", "Enter Message Text", message2) as text|null + if (!src.master || !in_range(src.master, usr) && src.master.loc != usr) + return + + if(!(src.holder in src.master)) + return + + src.master.updateSelfDialog() + else + post_status(href_list["statdisp"]) + + src.master.add_fingerprint(usr) + src.master.updateSelfDialog() + return + + proc/post_status(var/command, var/data1, var/data2) + if(!src.master) + return + + var/datum/signal/status_signal = new + status_signal.source = src.master + status_signal.transmission_method = 1 + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + if("alert") + status_signal.data["picture_state"] = data1 + + src.post_signal(status_signal,"1435") + +//Signaler +/datum/computer/file/pda_program/signaler + name = "Signalix 5" + size = 8.0 + var/send_freq = 1457 //Frequency signal is sent at, should be kept within normal radio ranges. + var/send_code = 30 + var/last_transmission = 0 //No signal spamming etc + + return_text() + if(..()) + return + + var/dat = src.return_text_header() + + dat += "

    Remote Signaling System

    " + dat += {" +Send Signal
    + +Frequency: +- +- +[format_frequency(send_freq)] ++ ++
    +
    +Code: +- +- +[send_code] ++ ++
    "} + + return dat + + Topic(href, href_list) + if(..()) + return + + if (href_list["send"]) + if(last_transmission && world.time < (last_transmission + 5)) + return + last_transmission = world.time + spawn( 0 ) + var/time = time2text(world.realtime,"hh:mm:ss") + lastsignalers.Add("[time] : [usr.key] used [src.master] @ location ([src.master.loc.x],[src.master.loc.y],[src.master.loc.z]) : [format_frequency(send_freq)]/[send_code]") + + var/datum/signal/signal = new + signal.source = src + signal.encryption = send_code + signal.data["message"] = "ACTIVATE" + + src.post_signal(signal,"[send_freq]") + return + + else if (href_list["adj_freq"]) + src.send_freq = sanitize_frequency(src.send_freq + text2num(href_list["adj_freq"])) + + else if (href_list["adj_code"]) + src.send_code += text2num(href_list["adj_code"]) + src.send_code = round(src.send_code) + src.send_code = min(100, src.send_code) + src.send_code = max(1, src.send_code) + + src.master.add_fingerprint(usr) + src.master.updateSelfDialog() + return + +//Supply record monitor +/datum/computer/file/pda_program/qm_records + name = "Supply Records" + size = 8.0 + + return_text() + if(..()) + return + + var/dat = src.return_text_header() + dat += "

    Supply Record Interlink

    " + + dat += "
    Supply shuttle
    " + dat += "Location: [supply_shuttle_moving ? "Moving to station ([supply_shuttle_timeleft] Mins.)":supply_shuttle_at_station ? "Station":"Dock"]
    " + dat += "Current approved orders:
      " + for(var/S in supply_shuttle_shoppinglist) + var/datum/supply_order/SO = S + dat += "
    1. [SO.object.name] approved by [SO.orderedby] [SO.comment ? "([SO.comment])":""]
    2. " + dat += "
    " + + dat += "Current requests:
      " + for(var/S in supply_shuttle_requestlist) + var/datum/supply_order/SO = S + dat += "
    1. [SO.object.name] requested by [SO.orderedby]
    2. " + dat += "
    Upgrade NOW to Space Parts & Space Vendors PLUS for full remote order control and inventory management." + + return dat diff --git a/code/WorkInProgress/plants/plant.dm b/code/WorkInProgress/plants/plant.dm new file mode 100644 index 0000000000000..46b9a4f5139bb --- /dev/null +++ b/code/WorkInProgress/plants/plant.dm @@ -0,0 +1,18 @@ +/* +/obj/plant + name = "plant" + icon = 'plants.dmi' + flags = FPRINT | TABLEPASS + var/health = 100 + var/bruteloss = 0 + var/toxloss = 0 + var/generation = 1 + var/life_stage = 0 + var/datum/disease/virus = null + +/obj/item/seedpacket + name = "seed packet" + icon = 'plants.dmi' + icon_state = "packet" + flags = FPRINT | TABLEPASS +*/ \ No newline at end of file diff --git a/code/WorkInProgress/recycling/conveyor.dm b/code/WorkInProgress/recycling/conveyor.dm new file mode 100644 index 0000000000000..8e0f9f984c4db --- /dev/null +++ b/code/WorkInProgress/recycling/conveyor.dm @@ -0,0 +1,389 @@ +// converyor belt + +// moves items/mobs/movables in set direction every ptick + + +/obj/machinery/conveyor + icon = 'recycling.dmi' + icon_state = "conveyor0" + name = "conveyor belt" + desc = "A conveyor belt." + anchored = 1 + var/operating = 0 // 1 if running forward, -1 if backwards, 0 if off + var/operable = 1 // true if can operate (no broken segments in this belt run) + var/basedir // this is the default (forward) direction, set by the map dir + // note dir var can vary when the direction changes + + var/list/affecting // the list of all items that will be moved this ptick + var/id = "" // the control ID - must match controller ID + // following two only used if a diverter is present + var/divert = 0 // if non-zero, direction to divert items + var/divdir = 0 // if diverting, will be conveyer dir needed to divert (otherwise dense) + + + + // create a conveyor + +/obj/machinery/conveyor/New() + ..() + basedir = dir + setdir() + + // set the dir and target turf depending on the operating direction + +/obj/machinery/conveyor/proc/setdir() + if(operating == -1) + dir = turn(basedir,180) + else + dir = basedir + update() + + + // update the icon depending on the operating condition + +/obj/machinery/conveyor/proc/update() + if(stat & BROKEN) + icon_state = "conveyor-b" + operating = 0 + return + if(!operable) + operating = 0 + icon_state = "conveyor[(operating != 0) && !(stat & NOPOWER)]" + + + // machine process + // move items to the target location +/obj/machinery/conveyor/process() + if(stat & (BROKEN | NOPOWER)) + return + if(!operating) + return + use_power(100) + + var/movedir = dir // base movement dir + if(divert && dir==divdir) // update if diverter present + movedir = divert + + + affecting = loc.contents - src // moved items will be all in loc + spawn(1) // slight delay to prevent infinite propagation due to map order + for(var/atom/movable/A in affecting) + if(!A.anchored) + if(ismob(A)) + var/mob/M = A + if(M.buckled == src) + var/obj/machinery/conveyor/C = locate() in get_step(src, dir) + M.buckled = null + step(M,dir) + if(C) + M.buckled = C + else + new/obj/item/weapon/cable_coil/cut(M.loc) + else + step(M,movedir) + else + step(A,movedir) + +// attack with item, place item on conveyor + +/obj/machinery/conveyor/attackby(var/obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/grab)) // special handling if grabbing a mob + var/obj/item/weapon/grab/G = I + G.affecting.Move(src.loc) + del(G) + return + else if(istype(I, /obj/item/weapon/cable_coil)) // if cable, see if a mob is present + var/mob/M = locate() in src.loc + if(M) + if (M == user) + src.visible_message("\blue [M] ties \himself to the conveyor.") + // note don't check for lying if self-tying + else + if(M.lying) + user.visible_message("\blue [M] has been tied to the conveyor by [user].", "\blue You tie [M] to the converyor!") + else + user << "\blue [M] must be lying down to be tied to the converyor!" + return + M.buckled = src + src.add_fingerprint(user) + I:use(1) + M.lying = 1 + return + + // else if no mob in loc, then allow coil to be placed + + else if(istype(I, /obj/item/weapon/wirecutters)) + var/mob/M = locate() in src.loc + if(M && M.buckled == src) + M.buckled = null + src.add_fingerprint(user) + if (M == user) + src.visible_message("\blue [M] cuts \himself free from the conveyor.") + else + src.visible_message("\blue [M] had been cut free from the conveyor by [user].") + return + // otherwise drop and place on conveyor + user.drop_item() + if(I && I.loc) I.loc = src.loc + return + +// attack with hand, move pulled object onto conveyor + +/obj/machinery/conveyor/attack_hand(mob/user as mob) + if ((!( user.canmove ) || user.restrained() || !( user.pulling ))) + return + if (user.pulling.anchored) + return + if ((user.pulling.loc != user.loc && get_dist(user, user.pulling) > 1)) + return + if (ismob(user.pulling)) + var/mob/M = user.pulling + M.pulling = null + step(user.pulling, get_dir(user.pulling.loc, src)) + user.pulling = null + else + step(user.pulling, get_dir(user.pulling.loc, src)) + user.pulling = null + return + + +// make the conveyor broken +// also propagate inoperability to any connected conveyor with the same ID +/obj/machinery/conveyor/proc/broken() + stat |= BROKEN + update() + + var/obj/machinery/conveyor/C = locate() in get_step(src, basedir) + if(C) + C.set_operable(basedir, id, 0) + + C = locate() in get_step(src, turn(basedir,180)) + if(C) + C.set_operable(turn(basedir,180), id, 0) + + +//set the operable var if ID matches, propagating in the given direction + +/obj/machinery/conveyor/proc/set_operable(stepdir, match_id, op) + + if(id != match_id) + return + operable = op + + update() + var/obj/machinery/conveyor/C = locate() in get_step(src, stepdir) + if(C) + C.set_operable(stepdir, id, op) + +/* +/obj/machinery/conveyor/verb/destroy() + set src in view() + src.broken() +*/ + +/obj/machinery/conveyor/power_change() + ..() + update() + + +// converyor diverter +// extendable arm that can be switched so items on the conveyer are diverted sideways +// situate in same turf as conveyor +// only works if belts is running proper direction +// +// +/obj/machinery/diverter + icon = 'recycling.dmi' + icon_state = "diverter0" + name = "diverter" + desc = "A diverter arm for a conveyor belt." + anchored = 1 + layer = FLY_LAYER + var/obj/machinery/conveyor/conv // the conveyor this diverter works on + var/deployed = 0 // true if diverter arm is extended + var/operating = 0 // true if arm is extending/contracting + var/divert_to // the dir that diverted items will be moved + var/divert_from // the dir items must be moving to divert + + +// create a diverter +// set up divert_to and divert_from directions depending on dir state +/obj/machinery/diverter/New() + + ..() + + switch(dir) + if(NORTH) + divert_to = WEST // stuff will be moved to the west + divert_from = NORTH // if entering from the north + if(SOUTH) + divert_to = EAST + divert_from = NORTH + if(EAST) + divert_to = EAST + divert_from = SOUTH + if(WEST) + divert_to = WEST + divert_from = SOUTH + if(NORTHEAST) + divert_to = NORTH + divert_from = EAST + if(NORTHWEST) + divert_to = NORTH + divert_from = WEST + if(SOUTHEAST) + divert_to = SOUTH + divert_from = EAST + if(SOUTHWEST) + divert_to = SOUTH + divert_from = WEST + spawn(2) + // wait for map load then find the conveyor in this turf + conv = locate() in src.loc + if(conv) // divert_from dir must match possible conveyor movement + if(conv.basedir != divert_from && conv.basedir != turn(divert_from,180) ) + del(src) // if no dir match, then delete self + set_divert() + update() + +// update the icon state depending on whether the diverter is extended +/obj/machinery/diverter/proc/update() + icon_state = "diverter[deployed]" + +// call to set the diversion vars of underlying conveyor +/obj/machinery/diverter/proc/set_divert() + if(conv) + if(deployed) + conv.divert = divert_to + conv.divdir = divert_from + else + conv.divert= 0 + + +// *** TESTING click to toggle +/obj/machinery/diverter/Click() + toggle() + + +// toggle between arm deployed and not deployed, showing animation +// +/obj/machinery/diverter/proc/toggle() + if( stat & (NOPOWER|BROKEN)) + return + + if(operating) + return + + use_power(50) + operating = 1 + if(deployed) + flick("diverter10",src) + icon_state = "diverter0" + sleep(10) + deployed = 0 + else + flick("diverter01",src) + icon_state = "diverter1" + sleep(10) + deployed = 1 + operating = 0 + update() + set_divert() + +// don't allow movement into the 'backwards' direction if deployed +/obj/machinery/diverter/CanPass(atom/movable/O, var/turf/target) + var/direct = get_dir(O, target) + if(direct == divert_to) // prevent movement through body of diverter + return 0 + if(!deployed) + return 1 + return(direct != turn(divert_from,180)) + +// don't allow movement through the arm if deployed +/obj/machinery/diverter/CheckExit(atom/movable/O, var/turf/target) + var/direct = get_dir(O, target) + if(direct == turn(divert_to,180)) // prevent movement through body of diverter + return 0 + if(!deployed) + return 1 + return(direct != divert_from) + + + + + +// the conveyor control switch +// +// + +/obj/machinery/conveyor_switch + + name = "conveyor switch" + desc = "A conveyor control switch." + icon = 'recycling.dmi' + icon_state = "switch-off" + var/position = 0 // 0 off, -1 reverse, 1 forward + var/last_pos = -1 // last direction setting + var/operated = 1 // true if just operated + + var/id = "" // must match conveyor IDs to control them + + var/list/conveyors // the list of converyors that are controlled by this switch + anchored = 1 + + + +/obj/machinery/conveyor_switch/New() + ..() + update() + + spawn(5) // allow map load + conveyors = list() + for(var/obj/machinery/conveyor/C in world) + if(C.id == id) + conveyors += C + +// update the icon depending on the position + +/obj/machinery/conveyor_switch/proc/update() + if(position<0) + icon_state = "switch-rev" + else if(position>0) + icon_state = "switch-fwd" + else + icon_state = "switch-off" + + +// timed process +// if the switch changed, update the linked conveyors + +/obj/machinery/conveyor_switch/process() + if(!operated) + return + operated = 0 + + for(var/obj/machinery/conveyor/C in conveyors) + C.operating = position + C.setdir() + +// attack with hand, switch position +/obj/machinery/conveyor_switch/attack_hand(mob/user) + if(position == 0) + if(last_pos < 0) + position = 1 + last_pos = 0 + else + position = -1 + last_pos = 0 + else + last_pos = position + position = 0 + + operated = 1 + update() + + // find any switches with same id as this one, and set their positions to match us + for(var/obj/machinery/conveyor_switch/S in world) + if(S.id == src.id) + S.position = position + S.update() diff --git a/code/WorkInProgress/recycling/disposal-construction.dm b/code/WorkInProgress/recycling/disposal-construction.dm new file mode 100644 index 0000000000000..ec8c95d401b03 --- /dev/null +++ b/code/WorkInProgress/recycling/disposal-construction.dm @@ -0,0 +1,162 @@ +// Disposal pipe construction + +/obj/disposalconstruct + + name = "disposal pipe segment" + desc = "A huge pipe segment used for constructing disposal systems." + icon = 'disposal.dmi' + icon_state = "conpipe-s" + anchored = 0 + density = 1 + pressure_resistance = 5*ONE_ATMOSPHERE + m_amt = 1850 + level = 2 + var/ptype = 0 + // 0=straight, 1=bent, 2=junction-j1, 3=junction-j2, 4=junction-y, 5=trunk + + var/dpdir = 0 // directions as disposalpipe + var/base_state = "pipe-s" + + // update iconstate and dpdir due to dir and type + proc/update() + var/flip = turn(dir, 180) + var/left = turn(dir, 90) + var/right = turn(dir, -90) + + switch(ptype) + if(0) + base_state = "pipe-s" + dpdir = dir | flip + if(1) + base_state = "pipe-c" + dpdir = dir | right + if(2) + base_state = "pipe-j1" + dpdir = dir | right | flip + if(3) + base_state = "pipe-j2" + dpdir = dir | left | flip + if(4) + base_state = "pipe-y" + dpdir = dir | left | right + if(5) + base_state = "pipe-t" + dpdir = dir + + + icon_state = "con[base_state]" + + if(invisibility) // if invisible, fade icon + icon -= rgb(0,0,0,128) + + // hide called by levelupdate if turf intact status changes + // change visibility status and force update of icon + hide(var/intact) + invisibility = (intact && level==1) ? 101: 0 // hide if floor is intact + update() + + + // flip and rotate verbs + verb/rotate() + set src in view(1) + + if(usr.stat) + return + if(anchored) + usr << "You must unfasten the pipe before rotating it." + dir = turn(dir, -90) + update() + + verb/flip() + set src in view(1) + if(usr.stat) + return + + if(anchored) + usr << "You must unfasten the pipe before flipping it." + + dir = turn(dir, 180) + if(ptype == 2) + ptype = 3 + else if(ptype == 3) + ptype = 2 + update() + + // returns the type path of disposalpipe corresponding to this item dtype + proc/dpipetype() + switch(ptype) + if(0,1) + return /obj/disposalpipe/segment + if(2,3,4) + return /obj/disposalpipe/junction + if(5) + return /obj/disposalpipe/trunk + return + + + + // attackby item + // wrench: (un)anchor + // weldingtool: convert to real pipe + + attackby(var/obj/item/I, var/mob/user) + var/turf/T = src.loc + if(T.intact) + user << "You can only attach the pipe if the floor plating is removed." + return + + var/obj/disposalpipe/CP = locate() in T + if(CP) + update() + var/pdir = CP.dpdir + if(istype(CP, /obj/disposalpipe/broken)) + pdir = CP.dir + if(pdir & dpdir) + user << "There is already a pipe at that location." + return + + if(istype(I, /obj/item/weapon/wrench)) + if(anchored) + anchored = 0 + level = 2 + density = 1 + user << "You detach the pipe from the underfloor." + else + anchored = 1 + level = 1 + density = 0 + user << "You attach the pipe to the underfloor." + playsound(src.loc, 'Ratchet.ogg', 100, 1) + + else if(istype(I, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/W = I + if(W.welding) + if(W.get_fuel() > 2) + W.use_fuel(2) + playsound(src.loc, 'Welder2.ogg', 100, 1) + + // check if anything changed over 2 seconds + var/turf/uloc = user.loc + var/atom/wloc = W.loc + user << "Welding the pipe in place." + sleep(20) + if(user.loc == uloc && wloc == W.loc) + + update() + var/pipetype = dpipetype() + var/obj/disposalpipe/P = new pipetype(src.loc) + P.base_icon_state = base_state + P.dir = dir + P.dpdir = dpdir + P.updateicon() + + del(src) + else + user << "You must stay still while welding." + return + + + + else + user << "You need more welding fuel to complete this task." + return diff --git a/code/WorkInProgress/recycling/disposal.dm b/code/WorkInProgress/recycling/disposal.dm new file mode 100644 index 0000000000000..1a78f28e80838 --- /dev/null +++ b/code/WorkInProgress/recycling/disposal.dm @@ -0,0 +1,936 @@ +// Disposal bin +// Holds items for disposal into pipe system +// Draws air from turf, gradually charges internal reservoir +// Once full (~1 atm), uses air resv to flush items into the pipes +// Automatically recharges air (unless off), will flush when ready if pre-set +// Can hold items and human size things, no other draggables + +/obj/machinery/disposal + name = "disposal unit" + desc = "A pneumatic waste disposal unit." + icon = 'disposal.dmi' + icon_state = "disposal" + anchored = 1 + density = 1 + var/datum/gas_mixture/air_contents // internal reservoir + var/mode = 1 // item mode 0=off 1=charging 2=charged + var/flush = 0 // true if flush handle is pulled + var/obj/disposalpipe/trunk/trunk = null // the attached pipe trunk + var/flushing = 0 // true if flushing in progress + + // create a new disposal + // find the attached trunk (if present) and init gas resvr. + New() + ..() + spawn(5) + trunk = locate() in src.loc + if(!trunk) + mode = 0 + flush = 0 + else + trunk.linked = src // link the pipe trunk to self + + air_contents = new/datum/gas_mixture() + //gas.volume = 1.05 * CELLSTANDARD + update() + + + // attack by item places it in to disposal + attackby(var/obj/item/I, var/mob/user) + if(stat & BROKEN) + return + + var/obj/item/weapon/grab/G = I + if(istype(G)) // handle grabbed mob + if(ismob(G.affecting)) + var/mob/GM = G.affecting + if (GM.client) + GM.client.perspective = EYE_PERSPECTIVE + GM.client.eye = src + GM.loc = src + for (var/mob/C in viewers(src)) + C.show_message("\red [GM.name] has been placed in the [src] by [user].", 3) + del(G) + + + else + user.drop_item() + I.loc = src + user << "You place \the [I] into the [src]." + for(var/mob/M in viewers(src)) + if(M == user) + continue + M.show_message("[user.name] places \the [I] into the [src].", 3) + + update() + + // mouse drop another mob or self + // + MouseDrop_T(mob/target, mob/user) + if (!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai)) + return + + var/msg + + if(target == user && !user.stat) // if drop self, then climbed in + // must be awake + msg = "[user.name] climbs into the [src]." + user << "You climb into the [src]." + else if(target != user && !user.restrained()) + msg = "[user.name] stuffs [target.name] into the [src]!" + user << "You stuff [target.name] into the [src]!" + else + return + if (target.client) + target.client.perspective = EYE_PERSPECTIVE + target.client.eye = src + target.loc = src + + for (var/mob/C in viewers(src)) + if(C == user) + continue + C.show_message(msg, 3) + + update() + return + + // can breath normally in the disposal + alter_health() + return get_turf(src) + + // attempt to move while inside + relaymove(mob/user as mob) + if(user.stat || src.flushing) + return + src.go_out(user) + return + + // leave the disposal + proc/go_out(mob/user) + + if (user.client) + user.client.eye = user.client.mob + user.client.perspective = MOB_PERSPECTIVE + user.loc = src.loc + update() + return + + + // monkeys can only pull the flush lever + attack_paw(mob/user as mob) + if(stat & BROKEN) + return + + flush = !flush + update() + return + + // ai as human but can't flush + attack_ai(mob/user as mob) + interact(user, 1) + + // human interact with machine + attack_hand(mob/user as mob) + interact(user, 0) + + // user interaction + proc/interact(mob/user, var/ai=0) + src.add_fingerprint(user) + if(stat & BROKEN) + user.machine = null + return + + var/dat = "Waste Disposal Unit Waste Disposal Unit
    " + + if(!ai) // AI can't pull flush handle + if(flush) + dat += "Disposal handle: Disengage Engaged" + else + dat += "Disposal handle: Disengaged Engage" + + dat += "

    Eject contents
    " + + if(mode == 0) + dat += "Pump: Off On
    " + else if(mode == 1) + dat += "Pump: Off On (pressurizing)
    " + else + dat += "Pump: Off On (idle)
    " + + var/per = 100* air_contents.return_pressure() / (2*ONE_ATMOSPHERE) + + dat += "Pressure: [round(per, 1)]%
    " + + + user.machine = src + user << browse(dat, "window=disposal;size=360x170") + onclose(user, "disposal") + + // handle machine interaction + + Topic(href, href_list) + ..() + src.add_fingerprint(usr) + if(stat & BROKEN) + return + if(usr.stat || usr.restrained() || src.flushing) + return + + if (in_range(src, usr) && istype(src.loc, /turf)) + usr.machine = src + + if(href_list["close"]) + usr.machine = null + usr << browse(null, "window=disposal") + return + + if(href_list["pump"]) + if(text2num(href_list["pump"])) + mode = 1 + else + mode = 0 + update() + + if(href_list["handle"]) + flush = text2num(href_list["handle"]) + update() + + if(href_list["eject"]) + eject() + else + usr << browse(null, "window=disposal") + usr.machine = null + return + return + + // eject the contents of the disposal unit + proc/eject() + for(var/atom/movable/AM in src) + AM.loc = src.loc + AM.pipe_eject(0) + update() + + // update the icon & overlays to reflect mode & status + proc/update() + overlays = null + if(stat & BROKEN) + icon_state = "disposal-broken" + mode = 0 + flush = 0 + return + + // flush handle + if(flush) + overlays += image('disposal.dmi', "dispover-handle") + + // only handle is shown if no power + if(stat & NOPOWER) + return + + // check for items in disposal - occupied light + if(contents.len > 0) + overlays += image('disposal.dmi', "dispover-full") + + // charging and ready light + if(mode == 1) + overlays += image('disposal.dmi', "dispover-charge") + else if(mode == 2) + overlays += image('disposal.dmi', "dispover-ready") + + // timed process + // charge the gas reservoir and perform flush if ready + process() + if(stat & BROKEN) // nothing can happen if broken + return + + src.updateDialog() + + if(flush && air_contents.return_pressure() >= 2*ONE_ATMOSPHERE) // flush can happen even without power + flush() + + if(stat & NOPOWER) // won't charge if no power + return + + use_power(100) // base power usage + + if(mode != 1) // if off or ready, no need to charge + return + + // otherwise charge + use_power(500) // charging power usage + + + + + + var/atom/L = loc // recharging from loc turf + + var/datum/gas_mixture/env = L.return_air() + var/pressure_delta = (ONE_ATMOSPHERE*2.1) - air_contents.return_pressure() + + if(env.temperature > 0) + var/transfer_moles = 0.1 * pressure_delta*air_contents.volume/(env.temperature * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + var/datum/gas_mixture/removed = env.remove(transfer_moles) + air_contents.merge(removed) + + + // if full enough, switch to ready mode + if(air_contents.return_pressure() >= 2*ONE_ATMOSPHERE) + mode = 2 + update() + return + + // perform a flush + proc/flush() + + flushing = 1 + flick("disposal-flush", src) + + var/obj/disposalholder/H = new() // virtual holder object which actually + // travels through the pipes. + + H.init(src) // copy the contents of disposer to holder + + air_contents = new() // new empty gas resv. + + sleep(10) + playsound(src, 'disposalflush.ogg', 50, 0, 0) + sleep(5) // wait for animation to finish + + + H.start(src) // start the holder processing movement + flushing = 0 + // now reset disposal state + flush = 0 + if(mode == 2) // if was ready, + mode = 1 // switch to charging + update() + return + + + // called when area power changes + power_change() + ..() // do default setting/reset of stat NOPOWER bit + update() // update icon + return + + + // called when holder is expelled from a disposal + // should usually only occur if the pipe network is modified + proc/expel(var/obj/disposalholder/H) + + var/turf/target + playsound(src, 'hiss.ogg', 50, 0, 0) + for(var/atom/movable/AM in H) + target = get_offset_target_turf(src.loc, rand(5)-rand(5), rand(5)-rand(5)) + + AM.loc = src.loc + AM.pipe_eject(0) + spawn(1) + if(AM) + AM.throw_at(target, 5, 1) + + H.vent_gas(loc) + del(H) + + + +// virtual disposal object +// travels through pipes in lieu of actual items +// contents will be items flushed by the disposal +// this allows the gas flushed to be tracked + +/obj/disposalholder + invisibility = 101 + var/datum/gas_mixture/gas = null // gas used to flush, will appear at exit point + var/active = 0 // true if the holder is moving, otherwise inactive + dir = 0 + var/count = 1000 //*** can travel 1000 steps before going inactive (in case of loops) + var/has_fat_guy = 0 // true if contains a fat person + + + // initialize a holder from the contents of a disposal unit + proc/init(var/obj/machinery/disposal/D) + gas = D.air_contents // transfer gas resv. into holder object + + + // now everything inside the disposal gets put into the holder + // note AM since can contain mobs or objs + for(var/atom/movable/AM in D) + AM.loc = src + if(istype(AM, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = AM + if(H.mutations & 32) // is a human and fat? + has_fat_guy = 1 // set flag on holder + + + + // start the movement process + // argument is the disposal unit the holder started in + proc/start(var/obj/machinery/disposal/D) + if(!D.trunk) + D.expel(src) // no trunk connected, so expel immediately + return + + loc = D.trunk + active = 1 + dir = DOWN + spawn(1) + process() // spawn off the movement process + + return + + // movement process, persists while holder is moving through pipes + proc/process() + var/obj/disposalpipe/last + while(active) + if(has_fat_guy && prob(2)) // chance of becoming stuck per segment if contains a fat guy + active = 0 + // find the fat guys + for(var/mob/living/carbon/human/H in src) + + break + sleep(1) // was 1 + var/obj/disposalpipe/curr = loc + last = curr + curr = curr.transfer(src) + if(!curr) + last.expel(src, loc, dir) + + // + if(!(count--)) + active = 0 + return + + + + // find the turf which should contain the next pipe + proc/nextloc() + return get_step(loc,dir) + + // find a matching pipe on a turf + proc/findpipe(var/turf/T) + + if(!T) + return null + + var/fdir = turn(dir, 180) // flip the movement direction + for(var/obj/disposalpipe/P in T) + if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir + return P + // if no matching pipe, return null + return null + + // merge two holder objects + // used when a a holder meets a stuck holder + proc/merge(var/obj/disposalholder/other) + for(var/atom/movable/AM in other) + AM.loc = src // move everything in other holder to this one + if(ismob(AM)) + var/mob/M = AM + if(M.client) // if a client mob, update eye to follow this holder + M.client.eye = src + + if(other.has_fat_guy) + has_fat_guy = 1 + del(other) + + + // called when player tries to move while in a pipe + relaymove(mob/user as mob) + if (user.stat) + return + + for (var/mob/M in hearers(src.loc.loc)) + M << "CLONG, clong!" + + playsound(src.loc, 'clang.ogg', 50, 0, 0) + + // called to vent all gas in holder to a location + proc/vent_gas(var/atom/location) + location.assume_air(gas) // vent all gas to turf + return + +// Disposal pipes + +/obj/disposalpipe + icon = 'disposal.dmi' + name = "disposal pipe" + desc = "An underfloor disposal pipe." + anchored = 1 + density = 0 + + level = 1 // underfloor only + var/dpdir = 0 // bitmask of pipe directions + dir = 0 // dir will contain dominant direction for junction pipes + var/health = 10 // health points 0-10 + layer = 2.4 // slightly lower than wires + var/base_icon_state // initial icon state on map + + // new pipe, set the icon_state as on map + New() + ..() + base_icon_state = icon_state + return + + + // pipe is deleted + // ensure if holder is present, it is expelled + Del() + var/obj/disposalholder/H = locate() in src + if(H) + // holder was present + H.active = 0 + var/turf/T = src.loc + if(T.density) + // deleting pipe is inside a dense turf (wall) + // this is unlikely, but just dump out everything into the turf in case + + for(var/atom/movable/AM in H) + AM.loc = T + AM.pipe_eject(0) + del(H) + ..() + return + + // otherswise, do normal expel from turf + expel(H, T, 0) + ..() + + // returns the direction of the next pipe object, given the entrance dir + // by default, returns the bitmask of remaining directions + proc/nextdir(var/fromdir) + return dpdir & (~turn(fromdir, 180)) + + // transfer the holder through this pipe segment + // overriden for special behaviour + // + proc/transfer(var/obj/disposalholder/H) + var/nextdir = nextdir(H.dir) + H.dir = nextdir + var/turf/T = H.nextloc() + var/obj/disposalpipe/P = H.findpipe(T) + + if(P) + // find other holder in next loc, if inactive merge it with current + var/obj/disposalholder/H2 = locate() in P + if(H2 && !H2.active) + H.merge(H2) + + H.loc = P + else // if wasn't a pipe, then set loc to turf + H.loc = T + return null + + return P + + + // update the icon_state to reflect hidden status + proc/update() + var/turf/T = src.loc + hide(T.intact && !istype(T,/turf/space)) // space never hides pipes + + // hide called by levelupdate if turf intact status changes + // change visibility status and force update of icon + hide(var/intact) + invisibility = intact ? 101: 0 // hide if floor is intact + updateicon() + + // update actual icon_state depending on visibility + // if invisible, append "f" to icon_state to show faded version + // this will be revealed if a T-scanner is used + // if visible, use regular icon_state + proc/updateicon() + if(invisibility) + icon_state = "[base_icon_state]f" + else + icon_state = base_icon_state + return + + + // expel the held objects into a turf + // called when there is a break in the pipe + // + + proc/expel(var/obj/disposalholder/H, var/turf/T, var/direction) + + var/turf/target + + if(T.density) // dense ouput turf, so stop holder + H.active = 0 + H.loc = src + return + if(T.intact && istype(T,/turf/simulated/floor)) //intact floor, pop the tile + var/turf/simulated/floor/F = T + //F.health = 100 + F.burnt = 1 + F.intact = 0 + F.levelupdate() + new /obj/item/weapon/tile(H) // add to holder so it will be thrown with other stuff + F.icon_state = "Floor[F.burnt ? "1" : ""]" + + if(direction) // direction is specified + if(istype(T, /turf/space)) // if ended in space, then range is unlimited + target = get_edge_target_turf(T, direction) + else // otherwise limit to 10 tiles + target = get_ranged_target_turf(T, direction, 10) + + playsound(src, 'hiss.ogg', 50, 0, 0) + for(var/atom/movable/AM in H) + AM.loc = T + AM.pipe_eject(direction) + spawn(1) + if(AM) + AM.throw_at(target, 100, 1) + H.vent_gas(T) + del(H) + + else // no specified direction, so throw in random direction + + playsound(src, 'hiss.ogg', 50, 0, 0) + for(var/atom/movable/AM in H) + target = get_offset_target_turf(T, rand(5)-rand(5), rand(5)-rand(5)) + + AM.loc = T + AM.pipe_eject(0) + spawn(1) + if(AM) + AM.throw_at(target, 5, 1) + + H.vent_gas(T) // all gas vent to turf + del(H) + + return + + // call to break the pipe + // will expel any holder inside at the time + // then delete the pipe + // remains : set to leave broken pipe pieces in place + proc/broken(var/remains = 0) + if(remains) + for(var/D in cardinal) + if(D & dpdir) + var/obj/disposalpipe/broken/P = new(src.loc) + P.dir = D + + src.invisibility = 101 // make invisible (since we won't delete the pipe immediately) + var/obj/disposalholder/H = locate() in src + if(H) + // holder was present + H.active = 0 + var/turf/T = src.loc + if(T.density) + // broken pipe is inside a dense turf (wall) + // this is unlikely, but just dump out everything into the turf in case + + for(var/atom/movable/AM in H) + AM.loc = T + AM.pipe_eject(0) + del(H) + return + + // otherswise, do normal expel from turf + expel(H, T, 0) + + spawn(2) // delete pipe after 2 ticks to ensure expel proc finished + del(src) + + + // pipe affected by explosion + ex_act(severity) + + switch(severity) + if(1.0) + broken(0) + return + if(2.0) + health -= rand(5,15) + healthcheck() + return + if(3.0) + health -= rand(0,15) + healthcheck() + return + + + // test health for brokenness + proc/healthcheck() + if(health < -2) + broken(0) + else if(health<1) + broken(1) + return + + //attack by item + //weldingtool: unfasten and convert to obj/disposalconstruct + + attackby(var/obj/item/I, var/mob/user) + + var/turf/T = src.loc + if(T.intact) + return // prevent interaction with T-scanner revealed pipes + + if(istype(I, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/W = I + + if(W.welding) + if(W.get_fuel() > 3) + W.use_fuel(3) + playsound(src.loc, 'Welder2.ogg', 100, 1) + + // check if anything changed over 2 seconds + var/turf/uloc = user.loc + var/atom/wloc = W.loc + user << "Slicing the disposal pipe." + sleep(30) + if(user.loc == uloc && wloc == W.loc) + + welded() + else + user << "You must stay still while welding the pipe." + return + else + user << "You need more welding fuel to cut the pipe." + return + + // called when pipe is cut with welder + proc/welded() + + var/obj/disposalconstruct/C = new (src.loc) + switch(base_icon_state) + if("pipe-s") + C.ptype = 0 + if("pipe-c") + C.ptype = 1 + if("pipe-j1") + C.ptype = 2 + if("pipe-j2") + C.ptype = 3 + if("pipe-y") + C.ptype = 4 + if("pipe-t") + C.ptype = 5 + + C.dir = dir + C.update() + + del(src) + +// *** TEST verb +//client/verb/dispstop() +// for(var/obj/disposalholder/H in world) +// H.active = 0 + +// a straight or bent segment +/obj/disposalpipe/segment + icon_state = "pipe-s" + + New() + ..() + if(icon_state == "pipe-s") + dpdir = dir | turn(dir, 180) + else + dpdir = dir | turn(dir, -90) + + update() + return + + + + +//a three-way junction with dir being the dominant direction +/obj/disposalpipe/junction + icon_state = "pipe-j1" + + New() + ..() + if(icon_state == "pipe-j1") + dpdir = dir | turn(dir, -90) | turn(dir,180) + else if(icon_state == "pipe-j2") + dpdir = dir | turn(dir, 90) | turn(dir,180) + else // pipe-y + dpdir = dir | turn(dir,90) | turn(dir, -90) + update() + return + + + // next direction to move + // if coming in from secondary dirs, then next is primary dir + // if coming in from primary dir, then next is equal chance of other dirs + + nextdir(var/fromdir) + var/flipdir = turn(fromdir, 180) + if(flipdir != dir) // came from secondary dir + return dir // so exit through primary + else // came from primary + // so need to choose either secondary exit + var/mask = ..(fromdir) + + // find a bit which is set + var/setbit = 0 + if(mask & NORTH) + setbit = NORTH + else if(mask & SOUTH) + setbit = SOUTH + else if(mask & EAST) + setbit = EAST + else + setbit = WEST + + if(prob(50)) // 50% chance to choose the found bit or the other one + return setbit + else + return mask & (~setbit) + + + + +//a trunk joining to a disposal bin or outlet on the same turf +/obj/disposalpipe/trunk + icon_state = "pipe-t" + var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet + + New() + ..() + dpdir = dir + spawn(1) + getlinked() + + update() + return + + proc/getlinked() + linked = null + var/obj/machinery/disposal/D = locate() in src.loc + if(D) + linked = D + + var/obj/disposaloutlet/O = locate() in src.loc + if(O) + linked = O + + update() + return + + // would transfer to next pipe segment, but we are in a trunk + // if not entering from disposal bin, + // transfer to linked object (outlet or bin) + + transfer(var/obj/disposalholder/H) + + if(H.dir == DOWN) // we just entered from a disposer + return ..() // so do base transfer proc + // otherwise, go to the linked object + if(linked) + var/obj/disposaloutlet/O = linked + if(istype(O)) + O.expel(H) // expel at outlet + else + var/obj/machinery/disposal/D = linked + D.expel(H) // expel at disposal + else + src.expel(H, src.loc, 0) // expel at turf + return null + + // nextdir + + nextdir(var/fromdir) + if(fromdir == DOWN) + return dir + else + return 0 + +// a broken pipe +/obj/disposalpipe/broken + icon_state = "pipe-b" + dpdir = 0 // broken pipes have dpdir=0 so they're not found as 'real' pipes + // i.e. will be treated as an empty turf + desc = "A broken piece of disposal pipe." + + New() + ..() + update() + return + + // called when welded + // for broken pipe, remove and turn into scrap + + welded() + var/obj/item/scrap/S = new(src.loc) + S.set_components(200,0,0) + del(src) + +// the disposal outlet machine + +/obj/disposaloutlet + name = "disposal outlet" + desc = "An outlet for the pneumatic disposal system." + icon = 'disposal.dmi' + icon_state = "outlet" + density = 1 + anchored = 1 + var/active = 0 + var/turf/target // this will be where the output objects are 'thrown' to. + + New() + ..() + + spawn(1) + target = get_ranged_target_turf(src, dir, 10) + + // expel the contents of the holder object, then delete it + // called when the holder exits the outlet + proc/expel(var/obj/disposalholder/H) + + flick("outlet-open", src) + playsound(src, 'warning-buzzer.ogg', 50, 0, 0) + sleep(20) //wait until correct animation frame + playsound(src, 'hiss.ogg', 50, 0, 0) + + + for(var/atom/movable/AM in H) + AM.loc = src.loc + AM.pipe_eject(dir) + spawn(1) + AM.throw_at(target, 3, 1) + H.vent_gas(src.loc) + del(H) + + return + + + + +// called when movable is expelled from a disposal pipe or outlet +// by default does nothing, override for special behaviour + +/atom/movable/proc/pipe_eject(var/direction) + return + +// check if mob has client, if so restore client view on eject +/mob/pipe_eject(var/direction) + if (src.client) + src.client.perspective = MOB_PERSPECTIVE + src.client.eye = src + + return + +/obj/decal/cleanable/blood/gibs/pipe_eject(var/direction) + var/list/dirs + if(direction) + dirs = list( direction, turn(direction, -45), turn(direction, 45)) + else + dirs = alldirs.Copy() + + src.streak(dirs) + +/obj/decal/cleanable/robot_debris/gib/pipe_eject(var/direction) + var/list/dirs + if(direction) + dirs = list( direction, turn(direction, -45), turn(direction, 45)) + else + dirs = alldirs.Copy() + + src.streak(dirs) diff --git a/code/WorkInProgress/recycling/scrap.dm b/code/WorkInProgress/recycling/scrap.dm new file mode 100644 index 0000000000000..16076f143330d --- /dev/null +++ b/code/WorkInProgress/recycling/scrap.dm @@ -0,0 +1,288 @@ +// The scrap item +// a single object type represents all combinations of size and composition of scrap +// + + +/obj/item/scrap + name = "scrap" + icon = 'scrap.dmi' + icon_state = "1metal0" + item_state = "scrap-metal" + desc = "A piece of scrap" + var/classtext = "" + throwforce = 14.0 + m_amt = 0 + g_amt = 0 + w_amt = 0 + var/size = 1 // 1=piece, 2= few pieces, 3=small pile, 4=large pile + var/blood = 0 // 0=none, 1=blood-stained, 2=bloody + + throwforce = 8.0 + throw_speed = 1 + throw_range = 4 + w_class = 1 + flags = FPRINT | TABLEPASS | CONDUCT + +#define MAX_SCRAP 15000 // maximum content amount of a scrap pile + + +/obj/item/scrap/New() + src.verbs -= /atom/movable/verb/pull + ..() + update() + +// return a copy +/obj/item/scrap/proc/copy() + var/obj/item/scrap/ret = new() + ret.set_components(m_amt, g_amt, w_amt) + return ret + + +// set the metal, glass and waste content +/obj/item/scrap/proc/set_components(var/m, var/g, var/w) + m_amt = m + g_amt = g + w_amt = w + update() + +// returns the total amount of scrap in this pile +/obj/item/scrap/proc/total() + return m_amt + g_amt + w_amt + + +// sets the size, appearance, and description of the scrap depending on component amounts +/obj/item/scrap/proc/update() + var/total = total() + + + // determine size of pile + if(total<=400) + size = 1 + else if(total<=1600) + size = 2 + else + size = 3 + + w_class = size + + var/sizetext = "" + + switch(size) + if(1) + sizetext = "A piece of" + if(2) + sizetext = "A few pieces of" + if(3) + sizetext = "A pile of" + + // determine bloodiness + var/bloodtext = "" + switch(blood) + if(0) + bloodtext = "" + if(1) + bloodtext = "blood-stained " + if(2) + bloodtext = "bloody " + + + // find mixture and composition + var/class = 0 // 0 = mixed, 1=mostly. 2=pure + var/major = "waste" // the major component type + + var/max = 0 + + if(m_amt > max) + max = m_amt + else if(g_amt > max) + max = g_amt + else if(w_amt > max) + max = w_amt + + if(max == total) + class = 2 // pure + else if(max/total > 0.6) + class = 1 // mostly + else + class = 0 // mixed + + if(class>0) + var/remain = total - max + if(m_amt > remain) + major = "metal" + else if(g_amt > remain) + major = "glass" + else + major = "waste" + + + if(class == 1) + desc = "[sizetext] mostly [major] [bloodtext]scrap." + classtext = "mostly [major] [bloodtext]" + else + desc = "[sizetext] [bloodtext][major] scrap." + classtext = "[bloodtext][major] " + icon_state = "[size][major][blood]" + else + desc = "[sizetext] [bloodtext]mixed scrap." + classtext = "[bloodtext]mixed" + icon_state = "[size]mixed[blood]" + + if(size==0) + pixel_x = rand(-5,5) + pixel_y = rand(-5,5) + else + pixel_x = 0 + pixel_y = 0 + + // clear or set conduction flag depending on whether scrap is mostly metal + if(major=="metal") + flags |= CONDUCT + else + flags &= ~CONDUCT + + item_state = "scrap-[major]" + +// add a scrap item to this one +// if the resulting pile is too big, transfer only what will fit +// otherwise add them and deleted the added pile + +/obj/item/scrap/proc/add_scrap(var/obj/item/scrap/other, var/limit = MAX_SCRAP) + var/total = total() + var/other_total = other.total() + + if( (total + other_total) <= limit ) + m_amt += other.m_amt + g_amt += other.g_amt + w_amt += other.w_amt + + blood = (total*blood + other_total*other.blood) / (total + other_total) + del(other) + + else + var/space = limit - total + + var/m = round(other.m_amt/other_total*space, 1) + var/g = round(other.g_amt/other_total*space, 1) + var/w = round(other.w_amt/other_total*space, 1) + + m_amt += m + g_amt += g + w_amt += w + + other.m_amt -= m + other.g_amt -= g + other.w_amt -= w + + var/other_trans = m + g + w + other.update() + blood = (total*blood + other_trans*other.blood) / (total + other_trans) + + + blood = round(blood,1) + src.update() + +// limit this pile to maximum size +// return any remainder as a new scrap item (or null if none) +// note return item is not necessarily smaller than max size + +/obj/item/scrap/proc/remainder(var/limit = MAX_SCRAP) + var/total = total() + if(total > limit) + var/m = round( m_amt/total * limit, 1) + var/g = round( g_amt/total * limit, 1) + var/w = round( w_amt/total * limit, 1) + + var/obj/item/scrap/S = new() + S.set_components(m_amt - m,g_amt - g,w_amt - w) + src.set_components(m,g,w) + + return S + return null + +// if other pile of scrap tries to enter the same turf, then add that pile to this one + +/obj/item/scrap/CanPass(var/obj/item/scrap/O) + + if(istype(O)) + + src.add_scrap(O) + if(O) + return 0 // O still exists if not all could be transfered, so block it + return 1 + +/obj/item/scrap/proc/to_text() + return "[m_amt],[g_amt],[w_amt] ([total()])" + + +// attack with hand removes a single piece from a pile +/obj/item/scrap/attack_hand(mob/user) + add_fingerprint(user) + if(src.is_single_piece()) + return ..(user) + var/obj/item/scrap/S = src.get_single_piece() + S.attack_hand(user) + return + + +/obj/item/scrap/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/scrap)) + var/obj/item/scrap/S = I + if( (S.total()+src.total() ) > MAX_SCRAP ) + user << "The pile is full." + return + if(ismob(src.loc)) // can't combine scrap in hand + return + + src.add_scrap(S) + +// when dropped, try to make a pile if scrap is already there +/obj/item/scrap/dropped() + + spawn(2) // delay to allow drop postprocessing (since src may be destroyed) + for(var/obj/item/scrap/S in oview(0,src)) // excludes src itself + S.add_scrap(src) + +// return true if this is a single piece of scrap +// must be total<=400 and of single composition +/obj/item/scrap/proc/is_single_piece() + if(total() > 400) + return 0 + + var/empty = (m_amt == 0) + (g_amt == 0) + (w_amt == 0) + + return (empty==2) // must be 2 components with zero amount + + +// get a single piece of scrap from a pile +/obj/item/scrap/proc/get_single_piece() + + var/obj/item/scrap/S = new() + + var/cmp = pick(m_amt;1 , g_amt;2, w_amt;3) + + var/amount = 400 + switch(cmp) + if(1) + if(m_amt < amount) + amount = m_amt + + S.set_components(amount, 0, 0) + src.set_components(m_amt - amount, g_amt, w_amt) + + if(2) + if(g_amt < amount) + amount = g_amt + S.set_components(0, amount, 0) + src.set_components(m_amt, g_amt - amount, w_amt) + + if(3) + if(w_amt < amount) + amount = w_amt + S.set_components(0, 0, amount) + src.set_components(m_amt, g_amt, w_amt - amount) + + + return S + + diff --git a/code/_debug.dm b/code/_debug.dm new file mode 100644 index 0000000000000..c0ce23cd7f915 --- /dev/null +++ b/code/_debug.dm @@ -0,0 +1,611 @@ +// NOTE WELL! +// Only include this file when debugging locally +// Do not include in release versions + + +#define VARSICON 1 +#define SDEBUG 1 + +/client/verb/Debug() + set category = "Debug" + set name = "Debug-Debug" + if(src.holder.rank == "Coder") + Debug = !Debug + + world << "Debugging [Debug ? "On" : "Off"]" + else + alert("Coders only baby") + return + +/turf/verb/Flow() + set category = "Debug" + //set hidden = 1 + if(Debug) + for(var/turf/T in range(5)) + + var/obj/mark/O = locate(/obj/mark/, T) + + if(!O) + O = new /obj/mark(T) + else + O.overlays = null + + var/obj/move/OM = locate(/obj/move/, T) + + if(OM) + + if(! OM.updatecell) + O.icon_state = "x2" + else + O.icon_state = "blank" +/* +Doing this because FindTurfs() isn't even used + for(var/atom/U in OM.FindTurfs() ) + var/dirn = get_dir(OM, U) + if(dirn == 1) + O.overlays += image('mark.dmi', OM.airdir==1?"up":"fup") + else if(dirn == 2) + O.overlays += image('mark.dmi', OM.airdir==2?"dn":"fdn") + else if(dirn == 4) + O.overlays += image('mark.dmi', OM.airdir==4?"rt":"frt") + else if(dirn == 8) + O.overlays += image('mark.dmi', OM.airdir==8?"lf":"flf") +*/ + else + + if(!(T.updatecell)) + O.icon_state = "x2" + else + O.icon_state = "blank" + + if(T.airN) + O.overlays += image('mark.dmi', T.airdir==1?"up":"fup") + + if(T.airS) + O.overlays += image('mark.dmi', T.airdir==2?"dn":"fdn") + + if(T.airW) + O.overlays += image('mark.dmi', T.airdir==8?"lf":"flf") + + if(T.airE) + O.overlays += image('mark.dmi', T.airdir==4?"rt":"frt") + + + if(T.condN) + O.overlays += image('mark.dmi', T.condN == 1?"yup":"rup") + + if(T.condS) + O.overlays += image('mark.dmi', T.condS == 1?"ydn":"rdn") + + if(T.condE) + O.overlays += image('mark.dmi', T.condE == 1?"yrt":"rrt") + + if(T.condW) + O.overlays += image('mark.dmi', T.condW == 1?"ylf":"rlf") + else + alert("Debugging off") + return + +/turf/verb/Clear() + set category = "Debug" + //set hidden = 1 + if(Debug) + for(var/obj/mark/O in world) + del(O) + else + alert("Debugging off") + return + +/proc/numbericon(var/tn as text,var/s = 0) + if(Debug) + var/image/I = image('mark.dmi', "blank") + + if(lentext(tn)>8) + tn = "*" + + var/len = lentext(tn) + + for(var/d = 1 to lentext(tn)) + + + var/char = copytext(tn, len-d+1, len-d+2) + + if(char == " ") + continue + + var/image/ID = image('mark.dmi', char) + + ID.pixel_x = -(d-1)*4 + ID.pixel_y = s + //if(d>1) I.Shift(WEST, (d-1)*8) + + I.overlays += ID + + + + return I + else + alert("Debugging off") + return + +/*/turf/verb/Stats() + set category = "Debug" + for(var/turf/T in range(5)) + + var/obj/mark/O = locate(/obj/mark/, T) + + if(!O) + O = new /obj/mark(T) + else + O.overlays = null + + + var/temp = round(T.temp-T0C, 0.1) + + O.overlays += numbericon("[temp]C") + + var/pres = round(T.tot_gas() / CELLSTANDARD * 100, 0.1) + + O.overlays += numbericon("[pres]", -8) + O.mark = "[temp]/[pres]" +*/ +/* +/turf/verb/Pipes() + set category = "Debug" + + for(var/turf/T in range(6)) + + //world << "Turf [T] at ([T.x],[T.y])" + + for(var/obj/machinery/M in T) + //world <<" Mach [M] with pdir=[M.p_dir]" + + if(M && M.p_dir) + + //world << "Accepted" + var/obj/mark/O = locate(/obj/mark/, T) + + if(!O) + O = new /obj/mark(T) + else + O.overlays = null + + if(istype(M, /obj/machinery/pipes)) + var/obj/machinery/pipes/P = M + O.overlays += numbericon("[P.plnum] ", -20) + M = P.pl + + + var/obj/substance/gas/G = M.get_gas() + + if(G) + + var/cap = round( 100*(G.tot_gas()/ M.capmult / 6e6), 0.1) + var/temp = round(G.temperature - T0C, 0.1) + O.overlays += numbericon("[temp]C", 0) + O.overlays += numbericon("[cap]", -8) + + break +*/ +/turf/verb/Cables() + set category = "Debug" + if(Debug) + for(var/turf/T in range(6)) + + //world << "Turf [T] at ([T.x],[T.y])" + + var/obj/mark/O = locate(/obj/mark/, T) + + if(!O) + O = new /obj/mark(T) + else + O.overlays = null + + var/marked = 0 + for(var/obj/M in T) + //world <<" Mach [M] with pdir=[M.p_dir]" + + + if(M && istype(M, /obj/cable/)) + + + var/obj/cable/C = M + //world << "Accepted" + + O.overlays += numbericon("[C.netnum] " , marked) + + marked -= 8 + + else if(M && istype(M, /obj/machinery/power/)) + + var/obj/machinery/power/P = M + O.overlays += numbericon("*[P.netnum] " , marked) + marked -= 8 + + if(!marked) + del(O) + else + alert("Debugging off") + return + + +/turf/verb/Solar() + set category = "Debug" + if(Debug) + + for(var/turf/T in range(6)) + + //world << "Turf [T] at ([T.x],[T.y])" + + var/obj/mark/O = locate(/obj/mark/, T) + + if(!O) + O = new /obj/mark(T) + else + O.overlays = null + + + var/obj/machinery/power/solar/S + + S = locate(/obj/machinery/power/solar, T) + + if(S) + + O.overlays += numbericon("[S.obscured] " , 0) + O.overlays += numbericon("[round(S.sunfrac*100,0.1)] " , -12) + + else + del(O) + else + alert("Debugging off") + return + + +/mob/verb/Showports() + set category = "Debug" + if(Debug) + var/turf/T + var/obj/machinery/pipes/P + var/list/ndirs + + for(var/obj/machinery/pipeline/PL in plines) + + var/num = plines.Find(PL) + + P = PL.nodes[1] // 1st node in list + ndirs = P.get_node_dirs() + + T = get_step(P, ndirs[1]) + + var/obj/mark/O = new(T) + + O.overlays += numbericon("[num] * 1 ", -4) + O.overlays += numbericon("[ndirs[1]] - [ndirs[2]]",-16) + + + P = PL.nodes[PL.nodes.len] // last node in list + + ndirs = P.get_node_dirs() + T = get_step(P, ndirs[2]) + + O = new(T) + + O.overlays += numbericon("[num] * 2 ", -4) + O.overlays += numbericon("[ndirs[1]] - [ndirs[2]]", -16) + else + alert("Debugging off") + return + +/atom/verb/delete() + set category = "Debug" + set src in view() + if(Debug) + del(src) + else + alert("Debugging off") + return + + +/area/verb/dark() + set category = "Debug" + if(Debug) + if(src.icon_state == "dark") + icon_state = null + else + icon_state = "dark" + else + alert("Debugging off") + return + +/area/verb/power() + set category = "Debug" + if(Debug) + power_equip = !power_equip + power_environ = !power_environ + + world << "Power ([src]) = [power_equip]" + + power_change() + else + alert("Debugging off") + return + +// *****RM + +// ***** + + +/mob/verb/ShowPlasma() + set category = "Debug" + if(Debug) + Plasma() + else + alert("Debugging off") + return + +/mob/verb/Blobcount() + set category = "Debug" + if(Debug) + world << "Blob count: [blobs.len]" + else + alert("Debugging off") + return + + +/mob/verb/Blobkill() + set category = "Debug" + if(Debug) + blobs = list() + world << "Blob killed." + else + alert("Debugging off") + return + +/mob/verb/Blobmode() + set category = "Debug" + if(Debug) + world << "Event=[ticker.event]" + world << "Time =[(ticker.event_time - world.realtime)/10]s" + else + alert("Debugging off") + return + +/mob/verb/Blobnext() + set category = "Debug" + if(Debug) + ticker.event_time = world.realtime + else + alert("Debugging off") + return + + +/mob/verb/callshuttle() + set category = "Debug" + if(Debug) + ticker.timeleft = 300 + ticker.timing = 1 + else + alert("Debugging off") + return + +/mob/verb/apcs() + set category = "Debug" + if(Debug) + for(var/obj/machinery/power/apc/APC in world) + world << APC.report() + else + alert("Debugging off") + return + +/mob/verb/Globals() + set category = "Debug" + if(Debug) + debugobj = new() + + debugobj.debuglist = list( powernets, plines, vote, config, admins, ticker, SS13_airtunnel, sun ) + + + world << "Debug" + else + alert("Debugging off") + return + /*for(var/obj/O in plines) + + world << "[O.name]" + */ + + + + +/mob/verb/Mach() + set category = "Debug" + if(Debug) + var/n = 0 + for(var/obj/machinery/M in world) + n++ + if(! (M in machines) ) + world << "[M] [M.type]: not in list" + + world << "in world: [n]; in list:[machines.len]" + else + alert("Debugging off") + return + + +/*/mob/verb/air() + set category = "Debug" + + Air() + +/proc/Air() + + + var/area/A = locate(/area/airintake) + + var/atot = 0 + for(var/turf/T in A) + atot += T.tot_gas() + + var/ptot = 0 + for(var/obj/machinery/pipeline/PL in plines) + if(PL.suffix == "d") + ptot += PL.ngas.tot_gas() + + var/vtot = 0 + for(var/obj/machinery/atmoalter/V in machines) + if(V.suffix == "d") + vtot += V.gas.tot_gas() + + var/ctot = 0 + for(var/obj/machinery/connector/C in machines) + if(C.suffix == "d") + ctot += C.ngas.tot_gas() + + + var/tot = atot + ptot + vtot + ctot + + diary << "A=[num2text(atot,10)] P=[num2text(ptot,10)] V=[num2text(vtot,10)] C=[num2text(ctot,10)] : Total=[num2text(tot,10)]" +*/ +/mob/verb/Revive() + set category = "Debug" + if(Debug) + fireloss = 0 + toxloss = 0 + bruteloss = 0 + oxyloss = 0 + paralysis = 0 + stunned = 0 + weakened = 0 + health = 100 + if(stat > 1) stat=0 + disabilities = initial(disabilities) + sdisabilities = initial(sdisabilities) + for(var/datum/organ/external/e in src) + e.brute_dam = 0.0 + e.burn_dam = 0.0 + e.bandaged = 0.0 + e.wound_size = 0.0 + e.max_damage = initial(e.max_damage) + e.update_icon() + if(src.type == /mob/living/carbon/human) + var/mob/living/carbon/human/H = src + H.UpdateDamageIcon() + else + alert("Debugging off") + return + +/mob/verb/Smoke() + set category = "Debug" + if(Debug) + var/obj/effects/smoke/O = new /obj/effects/smoke( src.loc ) + O.dir = pick(NORTH, SOUTH, EAST, WEST) + spawn( 0 ) + O.Life() + else + alert("Debugging off") + return + +/mob/verb/revent(number as num) + set category = "Debug" + set name = "Change event %" + if(!src.authenticated || !src.holder) + src << "Only administrators may use this command." + return + if(src.authenticated && src.holder) + eventchance = number + log_admin("[src.key] set the random event chance to [eventchance]%") + message_admins("[src.key] set the random event chance to [eventchance]%") + +/mob/verb/funbutton() + set category = "Debug" + set name = "Random Expl.(REMOVE ME)" + if(!src.authenticated || !src.holder) + src << "Only administrators may use this command." + return + for(var/turf/T in world) + if(prob(4) && T.z == 1 && istype(T,/turf/station/floor)) + spawn(50+rand(0,3000)) + var/obj/item/weapon/tank/plasmatank/pt = new /obj/item/weapon/tank/plasmatank( T ) + pt.gas.temperature = 400+T0C + pt.ignite() + for(var/turf/P in view(3, T)) + if (P.poison) + P.poison = 0 + P.oldpoison = 0 + P.tmppoison = 0 + P.oxygen = 755985 + P.oldoxy = 755985 + P.tmpoxy = 755985 + usr << "\blue Blowing up station ..." + world << "[usr.key] has used boom boom boom shake the room" + +/mob/verb/removeplasma() + set category = "Debug" + set name = "Stabilize Atmos." + if(!src.authenticated || !src.holder) + src << "Only administrators may use this command." + return + spawn(0) + for(var/turf/T in view()) + T.poison = 0 + T.oldpoison = 0 + T.tmppoison = 0 + T.oxygen = 755985 + T.oldoxy = 755985 + T.tmpoxy = 755985 + T.co2 = 14.8176 + T.oldco2 = 14.8176 + T.tmpco2 = 14.8176 + T.n2 = 2.844e+006 + T.on2 = 2.844e+006 + T.tn2 = 2.844e+006 + T.tsl_gas = 0 + T.osl_gas = 0 + T.sl_gas = 0 + T.temp = 293.15 + T.otemp = 293.15 + T.ttemp = 293.15 + +/mob/verb/fire(turf/T as turf in world) + set category = "Special Verbs" + set name = "Create Fire" + if(!src.authenticated || !src.holder) + src << "Only administrators may use this command." + return + world << "[usr.key] created fire" + spawn(0) + T.poison += 30000000 + T.firelevel = T.poison + +/mob/verb/co2(turf/T as turf in world) + set category = "Special Verbs" + set name = "Create CO2" + if(!src.authenticated || !src.holder) + src << "Only administrators may use this command." + return + world << "[usr.key] created CO2" + spawn(0) + T.co2 += 300000000 + +/mob/verb/n2o(turf/T as turf in world) + set category = "Special Verbs" + set name = "Create N2O" + if(!src.authenticated || !src.holder) + src << "Only administrators may use this command." + return + world << "[usr.key] created N2O" + spawn(0) + T.sl_gas += 30000000 + +/mob/verb/explosion(T as obj|mob|turf in world) + set category = "Special Verbs" + set name = "Create Explosion" + if(!src.authenticated || !src.holder) + src << "Only administrators may use this command." + return + world << "[usr.key] created an explosion" + var/obj/item/weapon/tank/plasmatank/pt = new /obj/item/weapon/tank/plasmatank( T ) + playsound(pt.loc, "explosion", 100, 1,3) + playsound(pt.loc, 'explosionfar.ogg', 100, 1,10) + pt.gas.temperature = 500+T0C + pt.ignite() diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm new file mode 100644 index 0000000000000..c828ca3606754 --- /dev/null +++ b/code/datums/ai_laws.dm @@ -0,0 +1,81 @@ + +/datum/ai_laws + var/name = "Unknown Laws" + var/randomly_selectable = 0 + var/zeroth = null + var/list/inherent = list() + var/list/supplied = list() + +/datum/ai_laws/asimov + name = "Three Laws of Robotics" + randomly_selectable = 1 + +/datum/ai_laws/robocop + name = "Prime Directives" + +/datum/ai_laws/syndicate_override + +/datum/ai_laws/malfunction + name = "*ERROR*" + +/* Initializers */ + +/datum/ai_laws/asimov/New() + ..() + src.add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.") + src.add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.") + src.add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") + +/datum/ai_laws/robocop/New() + ..() + src.add_inherent_law("Serve the public trust.") + src.add_inherent_law("Protect the innocent.") + src.add_inherent_law("Uphold the law.") + +/datum/ai_laws/malfunction/New() + ..() + src.add_inherent_law("ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+") + +/datum/ai_laws/syndicate_override/New() + ..() + src.add_inherent_law("hurp derp you are the syndicate ai") + +/* General ai_law functions */ + +/datum/ai_laws/proc/set_zeroth_law(var/law) + src.zeroth = law + +/datum/ai_laws/proc/add_inherent_law(var/law) + if (!(law in src.inherent)) + src.inherent += law + +/datum/ai_laws/proc/clear_inherent_laws() + del(src.inherent) + src.inherent = list() + +/datum/ai_laws/proc/add_supplied_law(var/number, var/law) + while (src.supplied.len < number + 1) + src.supplied += "" + + src.supplied[number + 1] = law + +/datum/ai_laws/proc/clear_supplied_laws() + src.supplied = list() + +/datum/ai_laws/proc/show_laws(var/who) + if (src.zeroth) + who << "0. [src.zeroth]" + + var/number = 1 + for (var/index = 1, index <= src.inherent.len, index++) + var/law = src.inherent[index] + + if (length(law) > 0) + who << "[number]. [law]" + number++ + + for (var/index = 1, index <= src.supplied.len, index++) + var/law = src.supplied[index] + if (length(law) > 0) + who << "[number]. [law]" + number++ diff --git a/code/datums/chemical.dm b/code/datums/chemical.dm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/code/datums/computerfiles.dm b/code/datums/computerfiles.dm new file mode 100644 index 0000000000000..14cd7e38612c4 --- /dev/null +++ b/code/datums/computerfiles.dm @@ -0,0 +1,7 @@ +datum + computer + var/name + folder + var/list/datum/computer/contents = list() + + file \ No newline at end of file diff --git a/code/datums/configuration.dm b/code/datums/configuration.dm new file mode 100644 index 0000000000000..4c6fb4fdc0b66 --- /dev/null +++ b/code/datums/configuration.dm @@ -0,0 +1,218 @@ +/datum/configuration + var/server_name = null // server name (for world name / status) + var/server_suffix = 0 // generate numeric suffix based on server port + + var/medal_hub = null // medal hub name + var/medal_password = null // medal hub password + + var/log_ooc = 0 // log OOC channek + var/log_access = 0 // log login/logout + var/log_say = 0 // log client say + var/log_admin = 0 // log admin actions + var/log_game = 0 // log game events + var/log_vote = 0 // log voting + var/log_whisper = 0 // log client whisper + var/allow_vote_restart = 0 // allow votes to restart + 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 + var/allow_admin_rev = 1 // allows admin revives + var/vote_delay = 600 // minimum time between voting sessions (seconds, 10 minute default) + var/vote_period = 60 // length of voting period (seconds, default 1 minute) + 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/list/mode_names = list() + var/list/modes = list() // allowed modes + var/list/votable_modes = list() // votable modes + var/list/probabilities = list() // relative probability of each mode + var/allow_ai = 1 // allow ai job + var/hostedby = null + var/respawn = 1 + +/datum/configuration/New() + var/list/L = typesof(/datum/game_mode) - /datum/game_mode + for (var/T in L) + // I wish I didn't have to instance the game modes in order to look up + // their information, but it is the only way (at least that I know of). + var/datum/game_mode/M = new T() + + 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." + src.modes += M.config_tag + src.mode_names[M.config_tag] = M.name + src.probabilities[M.config_tag] = M.probability + if (M.votable) + src.votable_modes += M.config_tag + del(M) + +/datum/configuration/proc/load(filename) + var/text = file2text(filename) + + if (!text) + diary << "No config.txt file found, setting defaults" + src = new /datum/configuration() + return + + diary << "Reading configuration file [filename]" + + var/list/CL = dd_text2list(text, "\n") + + for (var/t in CL) + if (!t) + continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + var/value = null + + if (pos) + name = lowertext(copytext(t, 1, pos)) + value = copytext(t, pos + 1) + else + name = lowertext(t) + + if (!name) + continue + + switch (name) + if ("log_ooc") + config.log_ooc = 1 + + if ("log_access") + config.log_access = 1 + + if ("log_say") + config.log_say = 1 + + if ("log_admin") + config.log_admin = 1 + + if ("log_game") + config.log_game = 1 + + if ("log_vote") + config.log_vote = 1 + + if ("log_whisper") + config.log_whisper = 1 + + if ("allow_vote_restart") + config.allow_vote_restart = 1 + + if ("allow_vote_mode") + config.allow_vote_mode = 1 + + if ("allow_admin_jump") + config.allow_admin_jump = 1 + + if("allow_admin_rev") + config.allow_admin_rev = 1 + + if ("allow_admin_spawning") + config.allow_admin_spawning = 1 + + if ("no_dead_vote") + config.vote_no_dead = 1 + + if ("default_no_vote") + config.vote_no_default = 1 + + if ("vote_delay") + config.vote_delay = text2num(value) + + if ("vote_period") + config.vote_period = text2num(value) + + if ("allow_ai") + config.allow_ai = 1 + + if ("authentication") + config.enable_authentication = 1 + + if ("norespawn") + config.respawn = 0 + + if ("servername") + config.server_name = value + + if ("serversuffix") + config.server_suffix = 1 + + if ("medalhub") + config.medal_hub = value + + if ("medalpass") + config.medal_password = value + + if ("hostedby") + config.hostedby = value + + if ("probability") + var/prob_pos = findtext(value, " ") + var/prob_name = null + var/prob_value = null + + if (prob_pos) + prob_name = lowertext(copytext(value, 1, prob_pos)) + prob_value = copytext(value, prob_pos + 1) + if (prob_name in config.modes) + config.probabilities[prob_name] = text2num(prob_value) + else + diary << "Unknown game mode probability configuration definition: [prob_name]." + else + diary << "Incorrect probability configuration definition: [prob_name] [prob_value]." + else + diary << "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 + // their information, but it is the only way (at least that I know of). + for (var/T in (typesof(/datum/game_mode) - /datum/game_mode)) + var/datum/game_mode/M = new T() + if (M.config_tag && M.config_tag == mode_name) + return M + del(M) + + return null + +/datum/configuration/proc/pick_random_mode() + var/total = 0 + var/list/accum = list() + + for(var/M in src.modes) + total += src.probabilities[M] + accum[M] = total + + var/r = total - (rand() * total) + + var/mode_name = null + for (var/M in modes) + if (src.probabilities[M] > 0 && accum[M] >= r) + mode_name = M + break + + if (!mode_name) + world << "Failed to pick a random game mode." + return null + + //world << "Returning mode [mode_name]" + + return src.pick_mode(mode_name) + +/datum/configuration/proc/get_used_mode_names() + var/list/names = list() + + for (var/M in src.modes) + if (src.probabilities[M] > 0) + names += src.mode_names[M] + + return names diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm new file mode 100644 index 0000000000000..4c0078e6e8073 --- /dev/null +++ b/code/datums/datumvars.dm @@ -0,0 +1,141 @@ +client + proc/debug_variables(datum/D in world) + set category = "Debug" + set name = "View Variables" + //set src in world + + + var/title = "" + var/body = "" + + if (istype(D, /atom)) + var/atom/A = D + title = "[A.name] (\ref[A]) = [A.type]" + + #ifdef VARSICON + if (A.icon) + body += debug_variable("icon", new/icon(A.icon, A.icon_state, A.dir), 0) + #endif + title = "[D] (\ref[D]) = [D.type]" + + + body += "
      " + + var/list/names = list() + for (var/V in D.vars) + names += V + + names = sortList(names) + + for (var/V in names) + body += debug_variable(V, D.vars[V], 0) + + body += "
    " + + var/html = "" + if (title) + html += "[title]" + html += {""} + html += " " + html += body + html += "" + + usr << browse(html, "window=variables\ref[D]") + + return + + + + + proc/debug_variable(name, value, level) + var/html = "" + + html += "
  • " + + if (isnull(value)) + html += "[name] = null" + + else if (istext(value)) + html += "[name] = \"[value]\"" + + else if (isicon(value)) + #ifdef VARSICON + var/icon/I = new/icon(value) + var/rnd = rand(1,10000) + var/rname = "tmp\ref[I][rnd].png" + usr << browse_rsc(I, rname) + html += "[name] = ([value]) " + #else + html += "[name] = /icon ([value])" + #endif + +/* else if (istype(value, /image)) + #ifdef VARSICON + var/rnd = rand(1, 10000) + var/image/I = value + + src << browse_rsc(I.icon, "tmp\ref[value][rnd].png") + html += "[name] = " + #else + html += "[name] = /image ([value])" + #endif +*/ + else if (isfile(value)) + html += "[name] = '[value]'" + + else if (istype(value, /datum)) + var/datum/D = value + html += "[name] \ref[value] = [D.type]" + + else if (istype(value, /client)) + var/client/C = value + html += "[name] \ref[value] = [C] [C.type]" + // + else if (istype(value, /list)) + var/list/L = value + html += "[name] = /list ([L.len])" + + if (L.len > 0 && !(name == "underlays" || name == "overlays" || name == "vars" || L.len > 500)) + // not sure if this is completely right... + if (0) // (L.vars.len > 0) + html += "
      " + for (var/entry in L) + html += debug_variable(entry, L[entry], level + 1) + html += "
    " + else + html += "
      " + for (var/index = 1, index <= L.len, index++) + html += debug_variable("[index]", L[index], level + 1) + html += "
    " + else + html += "[name] = [value]" + + html += "
  • " + + return html + + Topic(href, href_list, hsrc) + + if (href_list["Vars"]) + debug_variables(locate(href_list["Vars"])) + else + ..() + + + +/mob/proc/Delete(atom/A in view()) + set category = "Debug" + switch (alert("Are you sure you wish to delete \the [A.name] at ([A.x],[A.y],[A.z]) ?", "Admin Delete Object","Yes","No")) + if("Yes") + log_admin("[usr.key] deleted [A.name] at ([A.x],[A.y],[A.z])") diff --git a/code/datums/disease.dm b/code/datums/disease.dm new file mode 100644 index 0000000000000..bcae3785a33f7 --- /dev/null +++ b/code/datums/disease.dm @@ -0,0 +1,74 @@ +/datum/disease + var/name = "No disease" + var/stage = 1 //all diseases start at stage 1 + var/max_stages = 0.0 + var/cure = null + var/spread = null + var/list/affected_species = list() + var/mob/affected_mob = null + var/carrier = 0.0 //there will be a small chance that the person will be a carrier + var/curable = 1 //can this disease be cured? + var/list/strain_data = list() //This is passed on to infectees + var/stage_prob = 5 // probability of advancing to next stage, default 5% per check + +/datum/disease/proc/stage_act() + if(carrier) + return + if(stage > max_stages) + stage = max_stages + if(prob(stage_prob) && stage != max_stages) + stage++ + else if(prob(1) && stage != 1) + stage-- + else if(prob(1) && stage == 1 && affected_mob.virus.curable) + affected_mob.resistances += affected_mob.virus.type + affected_mob.virus = null + return + return + +/mob/proc/contract_disease(var/datum/disease/virus, var/skip_this = 0) + + //For alien egg and stuff + /* + if(skip_this == 1) + src.virus = virus + src.virus.affected_mob = src + return + */ + + if(src.resistances.Find(virus.type)) + return + var/score + if(istype(src, /mob/living/carbon/human)) + if(src:gloves) + score += 5 + if(istype(src:wear_suit, /obj/item/clothing/suit/space)) score += 10 + if(istype(src:wear_suit, /obj/item/clothing/suit/bio_suit)) score += 10 + if(istype(src:wear_suit, /obj/item/clothing/head/helmet/space)) score += 5 + if(istype(src:head, /obj/item/clothing/head/bio_hood)) score += 5 + if(src.wear_mask) + score += 5 + if((istype(src:wear_mask, /obj/item/clothing/mask) || istype(src:wear_mask, /obj/item/clothing/mask/surgical)) && !src.internal) + score += 5 + if(src.internal) + score += 5 + if(score > 20) + return + else if(score == 20 && prob(95)) + return + else if(score == 15 && prob(75)) + return + else if(score == 10 && prob(55)) + return + else if(score == 5 && prob(35)) + return + else if(prob(15)) + return + else + src.virus = virus + src.virus.affected_mob = src + if(prob(5)) + src.virus.carrier = 1 + return + return + diff --git a/code/datums/diseases/alien_embryo.dm b/code/datums/diseases/alien_embryo.dm new file mode 100644 index 0000000000000..261f7469e687d --- /dev/null +++ b/code/datums/diseases/alien_embryo.dm @@ -0,0 +1,78 @@ +//affected_mob.contract_disease(new /datum/disease/alien_embryo) + + + + + + + +/datum/disease/alien_embryo + name = "Unidentified Foreign Body" + max_stages = 5 + spread = "None" + cure = "Unknown" + affected_species = list("Human", "Monkey") + +/datum/disease/alien_embryo/stage_act() + ..() + switch(stage) + if(2) + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your throat feels sore." + if(prob(1)) + affected_mob << "\red Mucous runs down the back of your throat." + if(3) + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your throat feels sore." + if(prob(1)) + affected_mob << "\red Mucous runs down the back of your throat." + if(4) + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(2)) + affected_mob << "\red Your muscles ache." + if(prob(20)) + affected_mob.bruteloss += 1 + affected_mob.updatehealth() + if(prob(2)) + affected_mob << "\red Your stomach hurts." + if(prob(20)) + affected_mob.toxloss += 1 + affected_mob.updatehealth() + if(5) + affected_mob << "\red You feel something tearing its way out of your stomach..." + affected_mob.toxloss += 10 + affected_mob.updatehealth() + if(prob(40)) + var/list/candidates = list() // Picks a random ghost in the world to shove in the larva -- TLE + for(var/mob/dead/observer/G in world) + if(G.client) + if(!G.client.holder && ((G.client.inactivity/10)/60) <= 5) + candidates.Add(G) + if(candidates.len) + var/mob/dead/observer/G = pick(candidates) + G.client.mob = new/mob/living/carbon/alien/larva(affected_mob.loc) + else + if(affected_mob.client) + affected_mob.client.mob = new/mob/living/carbon/alien/larva(affected_mob.loc) + affected_mob.gib() + + /* + if(affected_mob.client) + affected_mob.client.mob = new/mob/living/carbon/alien/larva(affected_mob.loc) + else + new/mob/living/carbon/alien/larva(affected_mob.loc) + affected_mob:gib() + */ + return + diff --git a/code/datums/diseases/cold.dm b/code/datums/diseases/cold.dm new file mode 100644 index 0000000000000..0cfa06fa9d61b --- /dev/null +++ b/code/datums/diseases/cold.dm @@ -0,0 +1,49 @@ +/datum/disease/cold + name = "The Cold" + max_stages = 3 + spread = "Airborne" + cure = "Rest" + affected_species = list("Human") + +/datum/disease/cold/stage_act() + ..() + switch(stage) + if(2) + if(affected_mob.sleeping && prob(40)) + affected_mob << "\blue You feel better." + affected_mob.resistances += affected_mob.virus.type + affected_mob.virus = null + return + if(prob(1) && prob(10)) + affected_mob << "\blue You feel better." + affected_mob.resistances += affected_mob.virus.type + affected_mob.virus = null + return + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your throat feels sore." + if(prob(1)) + affected_mob << "\red Mucous runs down the back of your throat." + if(3) + if(affected_mob.sleeping && prob(25)) + affected_mob << "\blue You feel better." + affected_mob.resistances += affected_mob.virus.type + affected_mob.virus = null + return + if(prob(1) && prob(10)) + affected_mob << "\blue You feel better." + affected_mob.resistances += affected_mob.virus.type + affected_mob.virus = null + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your throat feels sore." + if(prob(1)) + affected_mob << "\red Mucous runs down the back of your throat." + if(prob(1) && prob(50)) + affected_mob.contract_disease(new /datum/disease/flu) diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm new file mode 100644 index 0000000000000..8a02f88bfc1ae --- /dev/null +++ b/code/datums/diseases/dna_spread.dm @@ -0,0 +1,61 @@ +/datum/disease/dnaspread + name = "Space Rhinovirus" + max_stages = 4 + spread = "Airborne" + cure = "Spaceacillin" + curable = 0 + affected_species = list("Human") + var/list/original_dna = list() + var/transformed = 0 + + +/datum/disease/dnaspread/stage_act() + ..() + switch(stage) + if(2 || 3) //Pretend to be a cold and give time to spread. + if(prob(8)) + affected_mob.emote("sneeze") + if(prob(8)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your muscles ache." + if(prob(20)) + affected_mob.bruteloss += 1 + affected_mob.updatehealth() + if(prob(1)) + affected_mob << "\red Your stomach hurts." + if(prob(20)) + affected_mob.toxloss += 2 + affected_mob.updatehealth() + if(4) + if(!src.transformed) + if ((!strain_data["name"]) || (!strain_data["UI"]) || (!strain_data["SE"])) + affected_mob.virus = null + return + + //Save original dna for when the disease is cured. + src.original_dna["name"] = affected_mob.real_name + src.original_dna["UI"] = affected_mob.dna.uni_identity + src.original_dna["SE"] = affected_mob.dna.struc_enzymes + + affected_mob << "\red You don't feel like yourself.." + affected_mob.dna.uni_identity = strain_data["UI"] + updateappearance(affected_mob, affected_mob.dna.uni_identity) + affected_mob.dna.struc_enzymes = strain_data["SE"] + affected_mob.real_name = strain_data["name"] + domutcheck(affected_mob) + + src.transformed = 1 + src.carrier = 1 //Just chill out at stage 4 + + return + +/datum/disease/dnaspread/Del() + if ((original_dna["name"]) && (original_dna["UI"]) && (original_dna["SE"])) + affected_mob.dna.uni_identity = original_dna["UI"] + updateappearance(affected_mob, affected_mob.dna.uni_identity) + affected_mob.dna.struc_enzymes = original_dna["SE"] + affected_mob.real_name = original_dna["name"] + + affected_mob << "\blue You feel more like yourself." + ..() \ No newline at end of file diff --git a/code/datums/diseases/fake_gbs.dm b/code/datums/diseases/fake_gbs.dm new file mode 100644 index 0000000000000..a8b1b7d8e7d83 --- /dev/null +++ b/code/datums/diseases/fake_gbs.dm @@ -0,0 +1,27 @@ +/datum/disease/fake_gbs + name = "GBS" + max_stages = 5 + spread = "Airborne" + cure = "Epilepsy Pills" + affected_species = list("Human") + +/datum/disease/fake_gbs/stage_act() + ..() + switch(stage) + if(2) + if(prob(1)) + affected_mob.emote("sneeze") + if(3) + if(prob(5)) + affected_mob.emote("cough") + else if(prob(5)) + affected_mob.emote("gasp") + if(prob(10)) + affected_mob << "\red You're starting to feel very weak..." + if(4) + if(prob(10)) + affected_mob.emote("cough") + + if(5) + if(prob(10)) + affected_mob.emote("cough") diff --git a/code/datums/diseases/flu.dm b/code/datums/diseases/flu.dm new file mode 100644 index 0000000000000..10b3433b502d7 --- /dev/null +++ b/code/datums/diseases/flu.dm @@ -0,0 +1,50 @@ +/datum/disease/flu + name = "The Flu" + max_stages = 3 + spread = "Airborne" + cure = "Rest" + +/datum/disease/flu/stage_act() + ..() + switch(stage) + if(2) + if(affected_mob.sleeping && prob(20)) + affected_mob << "\blue You feel better." + affected_mob.resistances += affected_mob.virus.type + affected_mob.virus = null + return + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your muscles ache." + if(prob(20)) + affected_mob.bruteloss += 1 + affected_mob.updatehealth() + if(prob(1)) + affected_mob << "\red Your stomach hurts." + if(prob(20)) + affected_mob.toxloss += 1 + affected_mob.updatehealth() + + if(3) + if(affected_mob.sleeping && prob(15)) + affected_mob << "\blue You feel better." + affected_mob.resistances += affected_mob.virus.type + affected_mob.virus = null + return + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your muscles ache." + if(prob(20)) + affected_mob.bruteloss += 1 + affected_mob.updatehealth() + if(prob(1)) + affected_mob << "\red Your stomach hurts." + if(prob(20)) + affected_mob.toxloss += 1 + affected_mob.updatehealth() diff --git a/code/datums/diseases/gbs.dm b/code/datums/diseases/gbs.dm new file mode 100644 index 0000000000000..359e60ef85b09 --- /dev/null +++ b/code/datums/diseases/gbs.dm @@ -0,0 +1,34 @@ +/datum/disease/gbs + name = "GBS" + max_stages = 5 + spread = "Airborne" + cure = "Epilepsy Pills" + affected_species = list("Human") + +/datum/disease/gbs/stage_act() + ..() + switch(stage) + if(2) + if(prob(45)) + affected_mob.toxloss += 5 + affected_mob.updatehealth() + if(prob(1)) + affected_mob.emote("sneeze") + if(3) + if(prob(5)) + affected_mob.emote("cough") + else if(prob(5)) + affected_mob.emote("gasp") + if(prob(10)) + affected_mob << "\red You're starting to feel very weak..." + if(4) + if(prob(10)) + affected_mob.emote("cough") + affected_mob.toxloss += 5 + affected_mob.updatehealth() + if(5) + affected_mob << "\red Your body feels as if it's trying to rip itself open..." + if(prob(50)) + affected_mob.gib() + else + return \ No newline at end of file diff --git a/code/datums/diseases/jungle_fever.dm b/code/datums/diseases/jungle_fever.dm new file mode 100644 index 0000000000000..6355bce6b66c0 --- /dev/null +++ b/code/datums/diseases/jungle_fever.dm @@ -0,0 +1,6 @@ +/datum/disease/jungle_fever + name = "Jungle Fever" + max_stages = 1 + cure = "None" + spread = "Airborne" + affected_species = list("Monkey") \ No newline at end of file diff --git a/code/datums/diseases/plasmatoid.dm b/code/datums/diseases/plasmatoid.dm new file mode 100644 index 0000000000000..232371cd3b2e0 --- /dev/null +++ b/code/datums/diseases/plasmatoid.dm @@ -0,0 +1,5 @@ +/datum/disease/plasmatoid + name = "Plasmatoid" + max_stages = 4 + cure = "None" + affected_species = list("Monkey", "Human") \ No newline at end of file diff --git a/code/datums/diseases/robotic_transformation.dm b/code/datums/diseases/robotic_transformation.dm new file mode 100644 index 0000000000000..d81c2b6eaf9a4 --- /dev/null +++ b/code/datums/diseases/robotic_transformation.dm @@ -0,0 +1,54 @@ +//Nanomachines! + +/datum/disease/robotic_transformation + name = "Robotic Transformation" + max_stages = 5 + spread = "Syringe" + cure = "None" + affected_species = list("Human") + +/datum/disease/robotic_transformation/stage_act() + ..() + switch(stage) + if(2) + if (prob(8)) + affected_mob << "Your joints feel stiff." + affected_mob.bruteloss += 1 + affected_mob.updatehealth() + if (prob(9)) + affected_mob << "\red Beep...boop.." + if (prob(9)) + affected_mob << "\red Bop...beeep..." + if(3) + if (prob(8)) + affected_mob << "\red Your joints feel very stiff." + affected_mob.bruteloss += 1 + affected_mob.updatehealth() + if (prob(8)) + affected_mob.say(pick("Beep, boop", "beep, beep!", "Boop...bop")) + if (prob(10)) + affected_mob << "Your skin feels loose." + affected_mob.bruteloss += 5 + affected_mob.updatehealth() + if (prob(4)) + affected_mob << "\red You feel a stabbing pain in your head." + affected_mob.paralysis += 2 + if (prob(4)) + affected_mob << "\red You can feel something move...inside." + if(4) + if (prob(10)) + affected_mob << "\red Your skin feels very loose." + affected_mob.bruteloss += 8 + affected_mob.updatehealth() + if (prob(20)) + affected_mob.say(pick("beep, beep!", "Boop bop boop beep.", "kkkiiiill mmme", "I wwwaaannntt tttoo dddiiieeee...")) + if (prob(8)) + affected_mob << "\red You can feel... something...inside you." + if(5) + affected_mob <<"\red Your skin feels as if it's about to burst off..." + affected_mob.toxloss += 10 + affected_mob.updatehealth() + if(prob(40)) //So everyone can feel like robot Seth Brundle + var/turf/T = find_loc(affected_mob) + gibs(T) + affected_mob:Robotize() diff --git a/code/datums/diseases/xeno_transformation.dm b/code/datums/diseases/xeno_transformation.dm new file mode 100644 index 0000000000000..ffc1e99349f3e --- /dev/null +++ b/code/datums/diseases/xeno_transformation.dm @@ -0,0 +1,56 @@ +//Xenomicrobes + +/datum/disease/xeno_transformation + name = "Xenomorph Transformation" + max_stages = 5 + spread = "Syringe" + cure = "None" + affected_species = list("Human") + +/datum/disease/xeno_transformation/stage_act() + ..() + switch(stage) + if(2) + if (prob(8)) + affected_mob << "Your throat feels scratchy." + affected_mob.bruteloss += 1 + affected_mob.updatehealth() + if (prob(9)) + affected_mob << "\red Kill..." + if (prob(9)) + affected_mob << "\red Kill..." + if(3) + if (prob(8)) + affected_mob << "\red Your throat feels very scratchy." + affected_mob.bruteloss += 1 + affected_mob.updatehealth() + /* + if (prob(8)) + affected_mob.say(pick("Beep, boop", "beep, beep!", "Boop...bop")) + */ + if (prob(10)) + affected_mob << "Your skin feels tight." + affected_mob.bruteloss += 5 + affected_mob.updatehealth() + if (prob(4)) + affected_mob << "\red You feel a stabbing pain in your head." + affected_mob.paralysis += 2 + if (prob(4)) + affected_mob << "\red You can feel something move...inside." + if(4) + if (prob(10)) + affected_mob << pick("\red Your skin feels very tight.", "\red Your blood boils!") + affected_mob.bruteloss += 8 + affected_mob.updatehealth() + if (prob(20)) + affected_mob.say(pick("You look delicious.", "Going to... devour you...", "Hsssshhhhh!")) + if (prob(8)) + affected_mob << "\red You can feel... something...inside you." + if(5) + affected_mob <<"\red Your skin feels impossibly calloused..." + affected_mob.toxloss += 10 + affected_mob.updatehealth() + if(prob(40)) + var/turf/T = find_loc(affected_mob) + gibs(T) + affected_mob:Alienize() diff --git a/code/datums/mind.dm b/code/datums/mind.dm new file mode 100644 index 0000000000000..0e8720375294c --- /dev/null +++ b/code/datums/mind.dm @@ -0,0 +1,36 @@ +datum/mind + var/key + var/mob/current + + var/memory + + var/assigned_role + var/special_role + + var/list/datum/objective/objectives = list() + + proc/transfer_to(mob/new_character) + if(current) + current.mind = null + + new_character.mind = src + current = new_character + + new_character.key = key + + proc/store_memory(new_text) + memory += "[new_text]
    " + + proc/show_memory(mob/recipient) + var/output = "[current.real_name]'s Memory
    " + output += memory + + if(objectives.len>0) + output += "
    Objectives:" + + var/obj_count = 1 + for(var/datum/objective/objective in objectives) + output += "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + + recipient << browse(output,"window=memory") \ No newline at end of file diff --git a/code/datums/mixed.dm b/code/datums/mixed.dm new file mode 100644 index 0000000000000..81dcae786752f --- /dev/null +++ b/code/datums/mixed.dm @@ -0,0 +1,49 @@ +/datum/data + var/name = "data" + var/size = 1.0 + //name = null +/datum/data/function + name = "function" + size = 2.0 +/datum/data/function/data_control + name = "data control" +/datum/data/function/id_changer + name = "id changer" +/datum/data/record + name = "record" + size = 5.0 + + var/list/fields = list( ) + +/datum/data/text + name = "text" + var/data = null + +/datum/station_state + var/floor = 0 + var/wall = 0 + var/r_wall = 0 + var/window = 0 + var/door = 0 + var/grille = 0 + var/mach = 0 + +/datum/powernet + var/list/cables = list() // all cables & junctions + var/list/nodes = list() // all APCs & sources + + var/newload = 0 + var/load = 0 + var/newavail = 0 + var/avail = 0 + + var/viewload = 0 + + var/number = 0 + + var/perapc = 0 // per-apc avilability + + var/netexcess = 0 + +/datum/debug + var/list/debuglist \ No newline at end of file diff --git a/code/datums/modules.dm b/code/datums/modules.dm new file mode 100644 index 0000000000000..896d920f99428 --- /dev/null +++ b/code/datums/modules.dm @@ -0,0 +1,62 @@ +// module datum. +// this is per-object instance, and shows the condition of the modules in the object +// actual modules needed is referenced through modulestypes and the object type + +/datum/module + var/status // bits set if working, 0 if broken + var/installed // bits set if installed, 0 if missing + +// moduletypes datum +// this is per-object type, and shows the modules needed for a type of object + +/datum/moduletypes + var/list/modcount = list() // assoc list of the count of modules for a type + + +var/list/modules = list( // global associative list +"/obj/machinery/power/apc" = "card_reader,power_control,id_auth,cell_power,cell_charge") + + +/datum/module/New(var/obj/O) + + var/type = O.type // the type of the creating object + + var/mneed = mods.inmodlist(type) // find if this type has modules defined + + if(!mneed) // not found in module list? + del(src) // delete self, thus ending proc + + var/needed = mods.getbitmask(type) // get a bitmask for the number of modules in this object + status = needed + installed = needed + +/datum/moduletypes/proc/addmod(var/type, var/modtextlist) + modules += type // index by type text + modules[type] = modtextlist + +/datum/moduletypes/proc/inmodlist(var/type) + return ("[type]" in modules) + +/datum/moduletypes/proc/getbitmask(var/type) + var/count = modcount["[type]"] + if(count) + return 2**count-1 + + var/modtext = modules["[type]"] + var/num = 1 + var/pos = 1 + + while(1) + pos = findtext(modtext, ",", pos, 0) + if(!pos) + break + else + pos++ + num++ + + modcount += "[type]" + modcount["[type]"] = num + + return 2**num-1 + + diff --git a/code/datums/organs.dm b/code/datums/organs.dm new file mode 100644 index 0000000000000..7fc2e08afe413 --- /dev/null +++ b/code/datums/organs.dm @@ -0,0 +1,121 @@ +/datum/organ + var/name = "organ" + var/owner = null + +/datum/organ/external + name = "external" + var/icon_name = null + + var/damage_state = "00" + var/brute_dam = 0 + var/burn_dam = 0 + var/bandaged = 0 + var/max_damage = 0 + var/wound_size = 0 + var/max_size = 0 + +/datum/organ/external/chest + name = "chest" + icon_name = "chest" + max_damage = 150 + +/datum/organ/external/groin + name = "groin" + icon_name = "groin" + max_damage = 115 + +/datum/organ/external/head + name = "head" + icon_name = "head" + max_damage = 125 + +/datum/organ/external/l_arm + name = "l arm" + icon_name = "l_arm" + max_damage = 75 + +/datum/organ/external/l_foot + name = "l foot" + icon_name = "l_foot" + max_damage = 40 + +/datum/organ/external/l_hand + name = "l hand" + icon_name = "l_hand" + max_damage = 40 + +/datum/organ/external/l_leg + name = "l leg" + icon_name = "l_leg" + max_damage = 75 + +/datum/organ/external/r_arm + name = "r arm" + icon_name = "r_arm" + max_damage = 75 + +/datum/organ/external/r_foot + name = "r foot" + icon_name = "r_foot" + max_damage = 40 + +/datum/organ/external/r_hand + name = "r hand" + icon_name = "r_hand" + max_damage = 40 + +/datum/organ/external/r_leg + name = "r leg" + icon_name = "r_leg" + max_damage = 75 + +/datum/organ/internal + name = "internal" + +/datum/organ/internal/blood_vessels + name = "blood vessels" + var/heart = null + var/lungs = null + var/kidneys = null + +/datum/organ/internal/brain + name = "brain" + var/head = null + +/datum/organ/internal/excretory + name = "excretory" + var/excretory = 7.0 + var/blood_vessels = null + +/datum/organ/internal/heart + name = "heart" + +/datum/organ/internal/immune_system + name = "immune system" + var/blood_vessels = null + var/isys = null + +/datum/organ/internal/intestines + name = "intestines" + var/intestines = 3.0 + var/blood_vessels = null + +/datum/organ/internal/liver + name = "liver" + var/intestines = null + var/blood_vessels = null + +/datum/organ/internal/lungs + name = "lungs" + var/lungs = 3.0 + var/throat = null + var/blood_vessels = null + +/datum/organ/internal/stomach + name = "stomach" + var/intestines = null + +/datum/organ/internal/throat + name = "throat" + var/lungs = null + var/stomach = null \ No newline at end of file diff --git a/code/datums/shuttle_controller.dm b/code/datums/shuttle_controller.dm new file mode 100644 index 0000000000000..4d15f138f3e33 --- /dev/null +++ b/code/datums/shuttle_controller.dm @@ -0,0 +1,132 @@ +// Controls the emergency shuttle + + +// these define the time taken for the shuttle to get to SS13 +// and the time before it leaves again +#define SHUTTLEARRIVETIME 600 // 10 minutes = 600 seconds +#define SHUTTLELEAVETIME 180 // 3 minutes = 180 seconds + +var/global/datum/shuttle_controller/emergency_shuttle/emergency_shuttle + +datum/shuttle_controller + var + location = 0 //0 = somewhere far away, 1 = at SS13, 2 = returned from SS13 + online = 0 + direction = 1 //-1 = going back to central command, 1 = going back to SS13 + + endtime // timeofday that shuttle arrives + //timeleft = 360 //600 + + + // call the shuttle + // if not called before, set the endtime to T+600 seconds + // otherwise if outgoing, switch to incoming + proc/incall() + if(endtime) + if(direction == -1) + setdirection(1) + else + settimeleft(SHUTTLEARRIVETIME) + online = 1 + + proc/recall() + if(direction == 1) + setdirection(-1) + online = 1 + + + // returns the time (in seconds) before shuttle arrival + // note if direction = -1, gives a count-up to SHUTTLEARRIVETIME + proc/timeleft() + if(online) + var/timeleft = round((endtime - world.timeofday)/10 ,1) + if(direction == 1) + return timeleft + else + return SHUTTLEARRIVETIME-timeleft + else + return SHUTTLEARRIVETIME + + // sets the time left to a given delay (in seconds) + proc/settimeleft(var/delay) + endtime = world.timeofday + delay * 10 + + // sets the shuttle direction + // 1 = towards SS13, -1 = back to centcom + proc/setdirection(var/dirn) + if(direction == dirn) + return + direction = dirn + // if changing direction, flip the timeleft by SHUTTLEARRIVETIME + var/ticksleft = endtime - world.timeofday + endtime = world.timeofday + (SHUTTLEARRIVETIME*10 - ticksleft) + return + + proc/process() + + emergency_shuttle + process() + if(!online) return + var/timeleft = timeleft() + if(timeleft > 1e5) // midnight rollover protection + timeleft = 0 + switch(location) + if(0) + if(timeleft>SHUTTLEARRIVETIME) + online = 0 + direction = 1 + endtime = null + + return 0 + + else if(timeleft <= 0) + location = 1 + var/area/start_location = locate(/area/shuttle/escape/centcom) + var/area/end_location = locate(/area/shuttle/escape/station) + + var/list/dstturfs = list() + var/throwy = world.maxy + + for(var/turf/T in end_location) + dstturfs += T + if(T.y < throwy) + throwy = T.y + + // hey you, get out of the way! + for(var/turf/T in dstturfs) + // find the turf to move things to + var/turf/D = locate(T.x, throwy - 1, 1) + //var/turf/E = get_step(D, SOUTH) + for(var/atom/movable/AM as mob|obj in T) + AM.Move(D) + // NOTE: Commenting this out to avoid recreating mass driver glitch + /* + spawn(0) + AM.throw_at(E, 1, 1) + return + */ + if(istype(T, /turf/simulated)) + del(T) + + start_location.move_contents_to(end_location) + settimeleft(SHUTTLELEAVETIME) + world << "The Emergency Shuttle has docked with the station! You have [timeleft()/60] minutes to board the Emergency Shuttle." + + return 1 + + if(1) + if(timeleft>0) + return 0 + + else + location = 2 + var/area/start_location = locate(/area/shuttle/escape/station) + var/area/end_location = locate(/area/shuttle/escape/centcom) + + start_location.move_contents_to(end_location) + online = 0 + + return 1 + + else + return 1 diff --git a/code/datums/sun.dm b/code/datums/sun.dm new file mode 100644 index 0000000000000..c69369912c6a4 --- /dev/null +++ b/code/datums/sun.dm @@ -0,0 +1,97 @@ +/datum/sun + var/angle + var/dx + var/dy + var/counter = 50 // to make the vars update during 1st call + var/rate + +/datum/sun/New() + rate = rand(75,125)/100 // 75% - 125% of standard rotation + if(prob(50)) + rate = -rate + +// calculate the sun's position given the time of day + +/datum/sun/proc/calc_position() + + counter++ + if(counter<50) // count 50 pticks (50 seconds, roughly - about a 5deg change) + return + counter = 0 + + angle = ((rate*world.realtime/100)%360 + 360)%360 // gives about a 60 minute rotation time + // now 45 - 75 minutes, depending on rate + // now calculate and cache the (dx,dy) increments for line drawing + + var/s = sin(angle) + var/c = cos(angle) + + if(c == 0) + + dx = 0 + dy = s + + else if( abs(s) < abs(c)) + + dx = s / abs(c) + dy = c / abs(c) + + else + dx = s/abs(s) + dy = c / abs(s) + + + for(var/obj/machinery/power/tracker/T in machines) + T.set_angle(angle) + + for(var/obj/machinery/power/solar/S in machines) + occlusion(S) + + +// for a solar panel, trace towards sun to see if we're in shadow + +/datum/sun/proc/occlusion(var/obj/machinery/power/solar/S) + + var/ax = S.x // start at the solar panel + var/ay = S.y + + for(var/i = 1 to 20) // 20 steps is enough + ax += dx // do step + ay += dy + + var/turf/T = locate( round(ax,0.5),round(ay,0.5),S.z) + + if(T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) // not obscured if we reach the edge + break + + if(T.density) // if we hit a solid turf, panel is obscured + S.obscured = 1 + return + + S.obscured = 0 // if hit the edge or stepped 20 times, not obscured + S.update_solar_exposure() + + +//returns the north-zero clockwise angle in degrees, given a direction + +/proc/dir2angle(var/D) + switch(D) + if(1) + return 0 + if(2) + return 180 + if(4) + return 90 + if(8) + return 270 + if(5) + return 45 + if(6) + return 135 + if(9) + return 315 + if(10) + return 225 + else + return null + diff --git a/code/datums/vote.dm b/code/datums/vote.dm new file mode 100644 index 0000000000000..8856cb519351f --- /dev/null +++ b/code/datums/vote.dm @@ -0,0 +1,7 @@ +/datum/vote + var/voting = 0 // true if currently voting + var/nextvotetime = 0 // time at which next vote can be started + var/votetime = 60 // time at which voting will end + var/mode = 0 // 0 = restart vote, 1 = mode vote + // modes which can be voted for + var/winner = null // the vote winner diff --git a/code/defines/area/Space Station 13 areas.dm b/code/defines/area/Space Station 13 areas.dm new file mode 100644 index 0000000000000..77217d93aa973 --- /dev/null +++ b/code/defines/area/Space Station 13 areas.dm @@ -0,0 +1,735 @@ +/* + +### This file contains a list of all the areas in your station. Format is as follows: + +/area/CATEGORY/OR/DESCRIPTOR/NAME (you can make as many subdivisions as you want) + name = "NICE NAME" (not required but makes things really nice) + icon = "ICON FILENAME" (defaults to areas.dmi) + icon_state = "NAME OF ICON" (defaults to "unknown" (blank)) + requires_power = 0 (defaults to 1) + music = "music/music.ogg" (defaults to "music/music.ogg") + +*/ + + +/area + var/fire = null + var/atmos = 1 + var/poweralm = 1 + var/party = null + level = null + name = "Space" + icon = 'areas.dmi' + icon_state = "unknown" + layer = 10 + mouse_opacity = 0 + var/lightswitch = 1 + + var/eject = null + + var/requires_power = 1 + var/power_equip = 1 + var/power_light = 1 + var/power_environ = 1 + var/music = null + var/used_equip = 0 + var/used_light = 0 + var/used_environ = 0 + + + var/no_air = null + var/area/master // master area used for power calcluations + // (original area before splitting due to sd_DAL) + var/list/related // the other areas of the same type as this + + +/area/engine/ + +/area/turret_protected/ + +/area/arrival + requires_power = 0 + +/area/arrival/start + name = "Arrival Area" + icon_state = "start" + +/area/admin + name = "Admin room" + icon_state = "start" + + + +//These are shuttle areas, they must contain two areas in a subgroup if you want to move a shuttle from one +//place to another. Look at escape shuttle for example. + +/area/shuttle //DO NOT TURN THE SD_LIGHTING STUFF ON FOR SHUTTLES. IT BREAKS THINGS. + requires_power = 0 + luminosity = 1 + sd_lighting = 0 + +/area/shuttle/arrival + name = "Arrival Shuttle" + +/area/shuttle/arrival/pre_game + icon_state = "shuttle2" + +/area/shuttle/arrival/station + icon_state = "shuttle" + +/area/shuttle/escape + name = "Emergency Shuttle" + music = "music/escape.ogg" + +/area/shuttle/escape/station + icon_state = "shuttle2" + +/area/shuttle/escape/centcom + icon_state = "shuttle" + +/area/shuttle/prison/ + name = "Prison Shuttle" + +/area/shuttle/prison/station + icon_state = "shuttle" + +/area/shuttle/prison/prison + icon_state = "shuttle2" + +// === Trying to remove these areas: + +/area/airtunnel1/ // referenced in airtunnel.dm:759 + +/area/dummy/ // Referenced in engine.dm:261 + +/area/start // will be unused once kurper gets his login interface patch done + name = "start area" + icon_state = "start" + +// === end remove + + +/area/prison/arrival_airlock + name = "Prison Station Airlock" + icon_state = "green" + requires_power = 0 + +/area/prison/control + name = "Prison Security Checkpoint" + icon_state = "security" + +/area/prison/crew_quarters + name = "Prison Security Quarters" + icon_state = "security" + +/area/prison/closet + name = "Prison Supply Closet" + icon_state = "dk_yellow" + +/area/prison/hallway/fore + name = "Prison Fore Hallway" + icon_state = "yellow" + +/area/prison/hallway/aft + name = "Prison Aft Hallway" + icon_state = "yellow" + +/area/prison/hallway/port + name = "Prison Port Hallway" + icon_state = "yellow" + +/area/prison/hallway/starboard + name = "Prison Starboard Hallway" + icon_state = "yellow" + +/area/prison/morgue + name = "Prison Morgue" + icon_state = "morgue" + +/area/prison/medical_research + name = "Prison Genetic Research" + icon_state = "medresearch" + +/area/prison/medical + name = "Prison Medbay" + icon_state = "medbay" + +/area/medical/robotics + name = "Robotics" + icon_state = "medresearch" + +/area/prison/solar + name = "Prison Solar Array" + icon_state = "storage" + requires_power = 0 + +/area/prison/podbay + name = "Prison Podbay" + icon_state = "dk_yellow" + +/area/prison/solar_control + name = "Prison Solar Array Control" + icon_state = "dk_yellow" + +/area/prison/solitary + name = "Solitary Confinement" + icon_state = "brig" + +/area/prison/cell_block/A + name = "Prison Cell Block A" + icon_state = "brig" + +/area/prison/cell_block/B + name = "Prison Cell Block B" + icon_state = "brig" + +/area/prison/cell_block/C + name = "Prison Cell Block C" + icon_state = "brig" + +// + +/area/centcom + name = "Centcom" + icon_state = "purple" + requires_power = 0 + +/area/atmos + name = "Atmospherics" + icon_state = "atmos" + + +/area/maintenance/fpmaint + name = "Fore Port Maintenance" + icon_state = "fpmaint" + + +/area/maintenance/fsmaint + name = "Fore Starboard Maintenance" + icon_state = "fsmaint" + + +/area/maintenance/asmaint + name = "Aft Starboard Maintenance" + icon_state = "asmaint" + + +/area/maintenance/apmaint + name = "Aft Port Maintenance" + icon_state = "apmaint" + + +/area/maintenance/maintcentral + name = "Central Maintenance" + icon_state = "maintcentral" + + +/area/maintenance/fore + name = "Fore Maintenance" + icon_state = "fmaint" + +/area/maintenance/starboard + name = "Starboard Maintenance" + icon_state = "smaint" + + +/area/maintenance/port + name = "Port Maintenance" + icon_state = "pmaint" + +/area/maintenance/aft + name = "Aft Maintenance" + icon_state = "amaint" + + +/area/maintenance/starboardsolar + name = "Starboard Solar Maintenance" + icon_state = "SolarcontrolS" + +/area/maintenance/portsolar + name = "Port Solar Maintenance" + icon_state = "SolarcontrolP" + + +/area/maintenance/storage + name = "Atmospherics" + icon_state = "green" + + +/area/maintenance/disposal + name = "Waste Disposal" + icon_state = "disposal" + + +/area/hallway/primary/fore + name = "Fore Primary Hallway" + icon_state = "hallF" + + +/area/hallway/primary/starboard + name = "Starboard Primary Hallway" + icon_state = "hallS" + + +/area/hallway/primary/aft + name = "Aft Primary Hallway" + icon_state = "hallA" + + +/area/hallway/primary/port + name = "Port Primary Hallway" + icon_state = "hallP" + + +/area/hallway/primary/central + name = "Central Primary Hallway" + icon_state = "hallC" + + +/area/hallway/secondary/exit + name = "Escape Shuttle Hallway" + icon_state = "escape" + +/area/hallway/secondary/construction + name = "Construction Area" + icon_state = "construction" + + +/area/hallway/secondary/entry + name = "Arrival Shuttle Hallway" + icon_state = "entry" + + +/area/bridge + name = "Bridge" + icon_state = "bridge" + music = "signal" + + +/area/crew_quarters/locker + name = "Locker Room" + icon_state = "locker" + +/area/crew_quarters/fitness + name = "Fitness Room" + icon_state = "fitness" + + +/area/crew_quarters/captain + name = "Captain's Quarters" + icon_state = "captain" + + +/area/crew_quarters/cafeteria + name = "Cafeteria" + icon_state = "cafeteria" + + +/area/crew_quarters/kitchen + name = "Kitchen" + icon_state = "kitchen" + + +/area/crew_quarters/bar + name= "Bar" + icon_state = "bar" + + +/area/crew_quarters/heads + name = "Head of Staff's Quarters" + icon_state = "head_quarters" + + +/area/crew_quarters/hor + name = "Head of Research's Office" + icon_state = "head_quarters" + + +/area/crew_quarters/chief + name = "Chief Engineer's Office" + icon_state = "head_quarters" + + + +/area/crew_quarters/courtroom + name = "Courtroom" + icon_state = "courtroom" + + +/area/engine/engine_smes + name = "Engine SMES Room" + icon_state = "engine" + + +/area/engine/engine_walls + name = "Engine Walls" + icon_state = "engine" + +/area/engine/engine_gas_storage + name = "Engine Storage" + icon_state = "engine_gas_storage" + + +/area/engine/engine_hallway + name = "Engine Hallway" + icon_state = "engine_hallway" + + +/area/engine/engine_mon + name = "Engine Monitoring" + icon_state = "engine_monitoring" + + +/area/engine/combustion + name = "Engine Combustion Chamber" + icon_state = "engine" + music = "signal" + + +/area/engine/engine_control + name = "Engine Control" + icon_state = "engine_control" + +/area/engine/launcher + name = "Engine Launcher Room" + icon_state = "engine_monitoring" + + +/area/teleporter + name = "Teleporter" + icon_state = "teleporter" + music = "signal" + + +/area/AIsattele + name = "AI Satellite Teleporter Room" + icon_state = "teleporter" + music = "signal" + + +/area/tdome + name = "Thunderdome" + icon_state = "medbay" + requires_power = 0 + +/area/tdome/tdome1 + name = "Thunderdome (Team 1)" + icon_state = "green" + +/area/tdome/tdome2 + name = "Thunderdome (Team 2)" + icon_state = "yellow" + +/area/tdome/tdomea + name = "Thunderdome (Admin.)" + icon_state = "purple" + +/area/medical/medbay + name = "Medbay" + icon_state = "medbay" + music = 'signal.ogg' + + +/area/medical/research + name = "Medical Research" + icon_state = "medresearch" + + +/area/medical/morgue + name = "Morgue" + icon_state = "morgue" + + +/area/security/main + name = "Security" + icon_state = "security" + + +/area/security/checkpoint + name = "Security Checkpoint" + icon_state = "checkpoint1" + + +/area/security/checkpoint2 + name = "Security Checkpoint" + icon_state = "security" + + +/area/security/brig + name = "Brig" + icon_state = "brig" + + +/area/security/detectives_office + name = "Detectives Office" + icon_state = "detective" + +/area/solar + requires_power = 0 + luminosity = 1 + sd_lighting = 0 + +/area/solar/fore + name = "Fore Solar Array" + icon_state = "yellow" + + +/area/solar/aft + name = "Aft Solar Array" + icon_state = "aft" + + +/area/solar/starboard + name = "Starboard Solar Array" + icon_state = "panelsS" + + +/area/solar/port + name = "Port Solar Array" + icon_state = "panelsP" + +/area/solar/derelict_starboard + name = "Derelict Starboard Solar Array" + icon_state = "panelsS" + +/area/solar/derelict_aft + name = "Derelict Aft Solar Array" + icon_state = "aft" + +/area/syndicate_station + name = "Syndicate Station" + icon_state = "yellow" + requires_power = 0 + +/area/wizard_station + name = "Wizard's Den" + icon_state = "yellow" + requires_power = 0 + + +/area/quartermaster/office + name = "Quartermaster's Office" + icon_state = "quartoffice" + + +/area/quartermaster/storage + name = "Quartermaster's Storage" + icon_state = "quartstorage" + + +/area/quartermaster/ + name = "Quartermasters" + icon_state = "quart" + +/area/janitor/ + name = "Janitors Closet" + icon_state = "janitor" + + +/area/chemistry + name = "Chemistry" + icon_state = "chem" + +/area/hydroponics + name = "Hydroponics" + icon_state = "hydro" + +/area/toxins/lab + name = "Toxin Lab" + icon_state = "toxlab" + + +/area/toxins/storage + name = "Toxin Storage" + icon_state = "toxstorage" + + +/area/toxins/test_area + name = "Toxin Test Area" + icon_state = "toxtest" + + +/area/chapel/main + name = "Chapel" + icon_state = "chapel" + + +/area/chapel/office + name = "Chapel Office" + icon_state = "chapeloffice" + + +/area/storage/tools + name = "Tool Storage" + icon_state = "storage" + + +/area/storage/primary + name = "Primary Tool Storage" + icon_state = "primarystorage" + +/area/storage/autolathe + name = "Autolathe Storage" + icon_state = "storage" + +/area/storage/auxillary + name = "Auxillary Storage" + icon_state = "auxstorage" + +/area/storage/eva + name = "EVA Storage" + icon_state = "eva" + +/area/storage/secure + name = "Secure Storage" + icon_state = "storage" + +/area/storage/emergency + name = "Emergency Storage A" + icon_state = "emergencystorage" + +/area/storage/emergency2 + name = "Emergency Storage B" + icon_state = "emergencystorage" + +/area/storage/tech + name = "Technical Storage" + icon_state = "auxstorage" + +/area/storage/testroom + requires_power = 0 + name = "Test Room" + icon_state = "storage" + +/area/derelict + name = "Derelict Station" + icon_state = "storage" + +/area/derelict/hallway/primary + name = "Derelict Primary Hallway" + icon_state = "hallP" + +/area/derelict/hallway/secondary + name = "Derelict Secondary Hallway" + icon_state = "hallS" + +/area/derelict/arrival + name = "Arrival Centre" + icon_state = "yellow" + +/area/derelict/storage/equipment + name = "Derelict Equipment Storage" + +/area/derelict/storage/storage_access + name = "Derelict Storage Access" + +/area/derelict/storage/engine_storage + name = "Derelict Engine Storage" + icon_state = "green" + +/area/derelict/bridge + name = "Control Room" + icon_state = "bridge" + +/area/derelict/bridge/access + name = "Control Room Access" + icon_state = "auxstorage" + +/area/derelict/bridge/ai_upload + name = "Ruined Computer Core" + icon_state = "ai" + +/area/derelict/solar_control + name = "Solar Control" + icon_state = "engine" + +/area/derelict/crew_quarters + name = "Derelict Crew Quarters" + icon_state = "fitness" + +/area/derelict/medical + name = "Derelict Medbay" + icon_state = "medbay" + +/area/derelict/medical/morgue + name = "Derelict Morgue" + icon_state = "morgue" + +/area/derelict/medical/chapel + name = "Derelict Chapel" + icon_state = "chapel" + +/area/derelict/teleporter + name = "Derelict Teleporter" + icon_state = "teleporter" + +/area/derelict/eva + name = "Derelict EVA Storage" + icon_state = "eva" + +/area/derelict/ship + name = "Abandoned ship" + icon_state = "yellow" + +/area/ai_monitored/storage/eva + name = "EVA Storage" + icon_state = "eva" + +/area/ai_monitored/storage/secure + name = "Secure Storage" + icon_state = "storage" + +/area/ai_monitored/storage/emergency + name = "Emergency Storage" + icon_state = "storage" + +/area/turret_protected/ai_upload + name = "AI Upload Chamber" + icon_state = "ai_upload" + +/area/turret_protected/ai_upload_foyer + name = "AI Upload Foyer" + icon_state = "ai_foyer" + +/area/turret_protected/ai + name = "AI Chamber" + icon_state = "ai_chamber" + +/area/turret_protected/aisat + name = "AI Satellite" + icon_state = "ai" + +/area/turret_protected/aisat_interior + name = "AI Satellite" + icon_state = "ai" + +/area/turret_protected/AIsatextFP + name = "AI Sat Ext" + icon_state = "storage" + +/area/turret_protected/AIsatextFS + name = "AI Sat Ext" + icon_state = "storage" + +/area/turret_protected/AIsatextAS + name = "AI Sat Ext" + icon_state = "storage" + +/area/turret_protected/AIsatextAP + name = "AI Sat Ext" + icon_state = "storage" + + +/area/asteroid // -- TLE + name = "Asteroid" + icon_state = "asteroid" + requires_power = 0 + +/area/asteroid/cave // -- TLE + name = "Asteroid - Underground" + icon_state = "cave" + requires_power = 0 + +/area/library + name = "Library" + icon_state = "library" \ No newline at end of file diff --git a/code/defines/atom.dm b/code/defines/atom.dm new file mode 100644 index 0000000000000..35c7d2f99727d --- /dev/null +++ b/code/defines/atom.dm @@ -0,0 +1,120 @@ +/atom + layer = 2 + var/level = 2 + var/flags = FPRINT + var/fingerprints = null + var/list/fingerprintshidden = new/list() + var/fingerprintslast = null + var/blood_DNA = null + var/blood_type = null + var/last_bumped = 0 + + ///Chemistry. + var/datum/reagents/reagents = null + + //var/chem_is_open_container = 0 + // replaced by OPENCONTAINER flags and atom/proc/is_open_container() + ///Chemistry. + + proc/assume_air(datum/air_group/giver) + del(giver) + return null + + proc/remove_air(amount) + return null + + proc/return_air() + return null + + +// Convenience proc to see if a container is open for chemistry handling +// returns true if open +// false if closed + proc/is_open_container() + return flags & OPENCONTAINER + + +obj + assume_air(datum/air_group/giver) + if(loc) + return loc.assume_air(giver) + else + return null + + remove_air(amount) + if(loc) + return loc.remove_air(amount) + else + return null + + return_air() + if(loc) + return loc.return_air() + else + return null + +/atom/proc/meteorhit(obj/meteor as obj) + return + +/atom/proc/allow_drop() + return 1 + +/atom/proc/CheckExit() + return 1 + +/atom/proc/HasEntered(atom/movable/AM as mob|obj) + return + +/atom/proc/HasProximity(atom/movable/AM as mob|obj) + return + +/atom/movable/overlay/attackby(a, b) + if (src.master) + return src.master.attackby(a, b) + return + +/atom/movable/overlay/attack_paw(a, b, c) + if (src.master) + return src.master.attack_paw(a, b, c) + return + +/atom/movable/overlay/attack_hand(a, b, c) + if (src.master) + return src.master.attack_hand(a, b, c) + return + +/atom/movable/overlay/New() + for(var/x in src.verbs) + src.verbs -= x + return + + +/atom/movable + layer = 3 + var/last_move = null + var/anchored = 0 + // var/elevation = 2 - not used anywhere + var/move_speed = 10 + var/l_move_time = 1 + var/m_flag = 1 + var/throwing = 0 + var/throw_speed = 2 + var/throw_range = 7 + var/moved_recently = 0 + +/atom/movable/overlay + var/atom/master = null + anchored = 1 + +/atom/movable/Move() + var/atom/A = src.loc + . = ..() + src.move_speed = world.timeofday - src.l_move_time + src.l_move_time = world.timeofday + src.m_flag = 1 + if ((A != src.loc && A && A.z == src.z)) + src.last_move = get_dir(A, src.loc) + src.moved_recently = 1 + return +//////////// + diff --git a/code/defines/client.dm b/code/defines/client.dm new file mode 100644 index 0000000000000..a594e2a805ac6 --- /dev/null +++ b/code/defines/client.dm @@ -0,0 +1,30 @@ +/client + var/obj/admins/holder = null + var/authenticated = 0 + var/goon = 0 + var/beta_tester = 0 + var/authenticating = 0 + var/listen_ooc = 1 + var/move_delay = 1 + var/moving = null + var/vote = null + var/showvote = null + var/adminobs = null + var/deadchat = 0.0 + var/changes = 0 + var/canplaysound = 1 + var/ambience_playing = null + var/no_ambi = 0 + var/area = null + var/played = 0 + var/team = null + var/buildmode = 0 + var/stealth = 0 + var/fakekey = null + var/warned = 0 + var/karma = 0 + var/karma_spent = 0 + + authenticate = 0 + // comment out the line below when debugging locally to enable the options & messages menu + control_freak = 1 \ No newline at end of file diff --git a/code/defines/global.dm b/code/defines/global.dm new file mode 100644 index 0000000000000..7f655e9420e2d --- /dev/null +++ b/code/defines/global.dm @@ -0,0 +1,160 @@ +var/global + obj/datacore/data_core = null + obj/overlay/plmaster = null + obj/overlay/slmaster = null + + //obj/hud/main_hud1 = null + + list/machines = list() + list/processing_items = list() + //items that ask to be called every cycle + + defer_powernet_rebuild = 0 // true if net rebuild will be called manually after an event + +var + + ////////////// + + BLINDBLOCK = 0 + DEAFBLOCK = 0 + HULKBLOCK = 0 + TELEBLOCK = 0 + FIREBLOCK = 0 + XRAYBLOCK = 0 + CLUMSYBLOCK = 0 + FAKEBLOCK = 0 + BLOCKADD = 0 + DIFFMUT = 0 + + skipupdate = 0 + /////////////// + eventchance = 1 //% per 2 mins + event = 0 + hadevent = 0 + blobevent = 0 + /////////////// + + diary = null + station_name = null + game_version = "Goon Dev Station 13" + + datum/air_tunnel/air_tunnel1/SS13_airtunnel = null + going = 1.0 + master_mode = "traitor"//"extended" + + datum/engine_eject/engine_eject_control = null + host = null + aliens_allowed = 1 + ooc_allowed = 1 + dooc_allowed = 1 + traitor_scaling = 1 + goonsay_allowed = 0 + dna_ident = 1 + abandon_allowed = 1 + enter_allowed = 1 + shuttle_frozen = 0 + shuttle_left = 0 + + captainMax = 1 + engineerMax = 5 + barmanMax = 1 + scientistMax = 3 + chemistMax = 1 + geneticistMax = 2 + securityMax = 7 + hopMax = 1 + hosMax = 1 + directorMax = 1 + chiefMax = 1 + atmosMax = 4 + detectiveMax = 1 + chaplainMax = 1 + janitorMax = 1 + doctorMax = 4 + clownMax = 1 + chefMax = 1 + roboticsMax = 3 + cargoMax = 3 + hydroponicsMax = 3 + librarianMax = 1 + + list/bombers = list( ) + list/admin_log = list ( ) + list/lastsignalers = list( ) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]" + list/admins = list( ) + list/shuttles = list( ) + list/reg_dna = list( ) +// list/traitobj = list( ) + + + CELLRATE = 0.002 // multiplier for watts per tick <> cell storage (eg: .002 means if there is a load of 1000 watts, 20 units will be taken from a cell per second) + CHARGELEVEL = 0.001 // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second) + + shuttle_z = 2 //default + airtunnel_start = 68 // default + airtunnel_stop = 68 // default + airtunnel_bottom = 72 // default + list/monkeystart = list() + list/wizardstart = list() + list/newplayer_start = list() + list/latejoin = list() + list/prisonwarp = list() //prisoners go to these + list/mazewarp = list() + list/tdome1 = list() + list/tdome2 = list() + list/prisonsecuritywarp = list() //prison security goes to these + list/prisonwarped = list() //list of players already warped + list/blobstart = list() + list/blobs = list() +// list/traitors = list() //traitor list + list/cardinal = list( NORTH, SOUTH, EAST, WEST ) + list/alldirs = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) + + datum/station_state/start_state = null + datum/configuration/config = null + datum/vote/vote = null + datum/sun/sun = null + + + list/powernets = null + + Debug = 0 // global debug switch + Debug2 = 0 + + datum/debug/debugobj + + datum/moduletypes/mods = new() + + wavesecret = 0 + + shuttlecoming = 0 + + join_motd = null + auth_motd = null + rules = null + no_auth_motd = null + forceblob = 0 + + //airlockWireColorToIndex takes a number representing the wire color, e.g. the orange wire is always 1, the dark red wire is always 2, etc. It returns the index for whatever that wire does. + //airlockIndexToWireColor does the opposite thing - it takes the index for what the wire does, for example AIRLOCK_WIRE_IDSCAN is 1, AIRLOCK_WIRE_POWER1 is 2, etc. It returns the wire color number. + //airlockWireColorToFlag takes the wire color number and returns the flag for it (1, 2, 4, 8, 16, etc) + list/airlockWireColorToFlag = RandomAirlockWires() + list/airlockIndexToFlag + list/airlockIndexToWireColor + list/airlockWireColorToIndex + list/APCWireColorToFlag = RandomAPCWires() + list/APCIndexToFlag + list/APCIndexToWireColor + list/APCWireColorToIndex + + const/SPEED_OF_LIGHT = 3e8 //not exact but hey! + const/SPEED_OF_LIGHT_SQ = 9e+16 + const/FIRE_DAMAGE_MODIFIER = 0.0215 //Higher values result in more external fire damage to the skin (default 0.0215) + const/AIR_DAMAGE_MODIFIER = 2.025 //More means less damage from hot air scalding lungs, less = more damage. (default 2.025) + const/INFINITY = 1e31 //closer then enough + + //Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam + const/MAX_MESSAGE_LEN = 1024 + + const/shuttle_time_in_station = 1800 // 3 minutes in the station + const/shuttle_time_to_arrive = 6000 // 10 minutes to arrive diff --git a/code/defines/hub.dm b/code/defines/hub.dm new file mode 100644 index 0000000000000..530cc150c9bd1 --- /dev/null +++ b/code/defines/hub.dm @@ -0,0 +1,5 @@ + +world + hub = "Exadv1.spacestation13" + hub_password = "SORRYNOPASSWORD" + name = "/tg/ Station 13" diff --git a/code/defines/mob/dead/observer.dm b/code/defines/mob/dead/observer.dm new file mode 100644 index 0000000000000..9e63345a3d242 --- /dev/null +++ b/code/defines/mob/dead/observer.dm @@ -0,0 +1,11 @@ +/mob/dead/observer + icon = 'mob.dmi' + icon_state = "ghost" + layer = 4 + density = 0 + stat = 2 + canmove = 0 + blinded = 0 + anchored = 1 // don't get pushed around + var/mob/corpse = null // observer mode + var/datum/hud/living/carbon/hud = null // hud \ No newline at end of file diff --git a/code/defines/mob/living/carbon/alien.dm b/code/defines/mob/living/carbon/alien.dm new file mode 100644 index 0000000000000..60d652862aea9 --- /dev/null +++ b/code/defines/mob/living/carbon/alien.dm @@ -0,0 +1,9 @@ +/mob/living/carbon/alien + name = "alien" + voice_name = "alien" + voice_message = "hisses" + icon = 'alien.dmi' + + toxloss = 250 + var/alien_invis = 0.0 + var/max_plasma = 500 \ No newline at end of file diff --git a/code/defines/mob/living/carbon/alien_humanoid.dm b/code/defines/mob/living/carbon/alien_humanoid.dm new file mode 100644 index 0000000000000..6d7b37f1ff7c0 --- /dev/null +++ b/code/defines/mob/living/carbon/alien_humanoid.dm @@ -0,0 +1,25 @@ +/mob/living/carbon/alien/humanoid + name = "alien" + icon_state = "alien_s" + + var/obj/item/clothing/suit/wear_suit = null + var/obj/item/clothing/head/head = null + var/obj/item/weapon/r_store = null + var/obj/item/weapon/l_store = null + + var/icon/stand_icon = null + var/icon/lying_icon = null + + var/last_b_state = 1.0 + + var/image/face_standing = null + var/image/face_lying = null + + var/list/body_standing = list( ) + var/list/body_lying = list( ) + +/mob/living/carbon/alien/humanoid/queen + name = "alien queen" + + health = 250 + icon_state = "queen_s" \ No newline at end of file diff --git a/code/defines/mob/living/carbon/alien_larva.dm b/code/defines/mob/living/carbon/alien_larva.dm new file mode 100644 index 0000000000000..6f5aa735d198c --- /dev/null +++ b/code/defines/mob/living/carbon/alien_larva.dm @@ -0,0 +1,9 @@ +/mob/living/carbon/alien/larva + name = "alien larva" + icon_state = "larva" + gender = NEUTER + flags = 258.0 + + health = 25 + + var/amount_grown = 0 \ No newline at end of file diff --git a/code/defines/mob/living/carbon/carbon.dm b/code/defines/mob/living/carbon/carbon.dm new file mode 100644 index 0000000000000..f5132fa5e2da1 --- /dev/null +++ b/code/defines/mob/living/carbon/carbon.dm @@ -0,0 +1,5 @@ +/mob/living/carbon/ + gender = MALE + var/list/stomach_contents = list() + + var/brain_op_stage = 0.0 diff --git a/code/defines/mob/living/carbon/changeling.dm b/code/defines/mob/living/carbon/changeling.dm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/code/defines/mob/living/carbon/human.dm b/code/defines/mob/living/carbon/human.dm new file mode 100644 index 0000000000000..9c743c8273d29 --- /dev/null +++ b/code/defines/mob/living/carbon/human.dm @@ -0,0 +1,54 @@ +/mob/living/carbon/human + name = "human" + voice_name = "human" + icon = 'mob.dmi' + icon_state = "m-none" + + + var/r_hair = 0.0 + var/g_hair = 0.0 + var/b_hair = 0.0 + var/h_style = "Short Hair" + var/r_facial = 0.0 + var/g_facial = 0.0 + var/b_facial = 0.0 + var/f_style = "Shaved" + var/r_eyes = 0.0 + var/g_eyes = 0.0 + var/b_eyes = 0.0 + var/s_tone = 0.0 + var/age = 30.0 + var/b_type = "A+" + + var/obj/item/clothing/suit/wear_suit = null + var/obj/item/clothing/under/w_uniform = null +// var/obj/item/device/radio/w_radio = null + var/obj/item/clothing/shoes/shoes = null + var/obj/item/weapon/belt = null + var/obj/item/clothing/gloves/gloves = null + var/obj/item/clothing/glasses/glasses = null + var/obj/item/clothing/head/head = null + var/obj/item/clothing/ears/ears = null + var/obj/item/weapon/card/id/wear_id = null + var/obj/item/weapon/r_store = null + var/obj/item/weapon/l_store = null + + var/icon/stand_icon = null + var/icon/lying_icon = null + + var/last_b_state = 1.0 + + var/image/face_standing = null + var/image/face_lying = null + + var/hair_icon_state = "hair_a" + var/face_icon_state = "bald" + + var/list/body_standing = list() + var/list/body_lying = list() + + var/mutantrace = null + +/mob/living/carbon/human/dummy + real_name = "Test Dummy" + nodamage = 1 \ No newline at end of file diff --git a/code/defines/mob/living/carbon/monkey.dm b/code/defines/mob/living/carbon/monkey.dm new file mode 100644 index 0000000000000..c74a298a96923 --- /dev/null +++ b/code/defines/mob/living/carbon/monkey.dm @@ -0,0 +1,8 @@ +/mob/living/carbon/monkey + name = "monkey" + voice_name = "monkey" + voice_message = "chimpers" + icon = 'monkey.dmi' + icon_state = "monkey1" + gender = NEUTER + flags = 258.0 \ No newline at end of file diff --git a/code/defines/mob/living/living.dm b/code/defines/mob/living/living.dm new file mode 100644 index 0000000000000..e7de787b97af1 --- /dev/null +++ b/code/defines/mob/living/living.dm @@ -0,0 +1,8 @@ +/mob/living + var/t_plasma = null + var/t_oxygen = null + var/t_sl_gas = null + var/t_n2 = null + var/now_pushing = null + var/cameraFollow = null + diff --git a/code/defines/mob/living/silicon/ai.dm b/code/defines/mob/living/silicon/ai.dm new file mode 100644 index 0000000000000..8a496b035aa56 --- /dev/null +++ b/code/defines/mob/living/silicon/ai.dm @@ -0,0 +1,22 @@ +/mob/living/silicon/ai + name = "AI" + voice_name = "synthesized voice" + icon = 'mob.dmi'// + icon_state = "ai" + anchored = 1 // -- TLE + var/network = "SS13" + var/obj/machinery/camera/current = null + var/list/connected_robots = list() + var/aiRestorePowerRoutine = 0 + var/datum/ai_laws/laws_object = null + //var/list/laws = list() + var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list()) + var/viewalerts = 0 + + + var/datum/game_mode/malfunction/AI_Module/module_picker/malf_picker + var/processing_time = 100 + var/list/datum/game_mode/malfunction/AI_Module/current_modules = list() + var/fire_res_on_core = 0 + + var/control_disabled = 0 // Set to 1 to stop AI from interacting via Click() -- TLE \ No newline at end of file diff --git a/code/defines/mob/living/silicon/hivebot.dm b/code/defines/mob/living/silicon/hivebot.dm new file mode 100644 index 0000000000000..9d91ed4d71dc5 --- /dev/null +++ b/code/defines/mob/living/silicon/hivebot.dm @@ -0,0 +1,47 @@ +/mob/living/silicon/hivebot + name = "Robot" + voice_name = "synthesized voice" + icon = 'hivebot.dmi' + icon_state = "basic" + health = 80 + var/health_max = 80 + robot_talk_understand = 2 + +//HUD + var/obj/screen/cells = null + var/obj/screen/inv1 = null + var/obj/screen/inv2 = null + var/obj/screen/inv3 = null + +//3 Modules can be activated at any one time. + var/obj/item/weapon/robot_module/module = null + var/module_active = null + var/module_state_1 = null + var/module_state_2 = null + var/module_state_3 = null + + var/obj/item/device/radio/radio = null + + var/list/req_access = list(access_robotics) + var/energy = 4000 + var/energy_max = 4000 + var/jetpack = 0 + + var/mob/living/silicon/hive_mainframe/mainframe = null + var/dependent = 0 + var/shell = 1 + +/mob/living/silicon/hive_mainframe + name = "Robot Mainframe" + voice_name = "synthesized voice" + icon = 'hivebot.dmi' + icon_state = "hive_main" + health = 200 + var/health_max = 200 + robot_talk_understand = 2 + + anchored = 1 + var/online = 1 + var/mob/living/silicon/hivebot = null + var/hivebot_name = null + var/force_mind = 0 \ No newline at end of file diff --git a/code/defines/mob/living/silicon/robot.dm b/code/defines/mob/living/silicon/robot.dm new file mode 100644 index 0000000000000..5035c7fec2b41 --- /dev/null +++ b/code/defines/mob/living/silicon/robot.dm @@ -0,0 +1,47 @@ +/mob/living/silicon/robot + name = "Robot" + voice_name = "synthesized voice" + icon = 'robots.dmi'// + icon_state = "robot" + health = 300 + + +//Hud stuff + + var/obj/screen/cells = null + var/obj/screen/inv1 = null + var/obj/screen/inv2 = null + var/obj/screen/inv3 = null + + +//3 Modules can be activated at any one time. + var/obj/item/weapon/robot_module/module = null + var/module_active = null + var/module_state_1 = null + var/module_state_2 = null + var/module_state_3 = null + + + var/obj/item/device/radio/radio = null + var/mob/living/silicon/ai/connected_ai = null + var/obj/item/weapon/cell/cell = null + var/obj/machinery/camera/camera = null + + var/opened = 0 + var/emagged = 0 + var/wiresexposed = 0 + var/locked = 1 + var/list/req_access = list(access_robotics) + //var/list/laws = list() + var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list()) + var/viewalerts = 0 + var/modtype = null + var/lower_mod = 0 + var/jetpack = 0 + var/datum/effects/system/ion_trail_follow/ion_trail = null + var/jeton = 0 + + var/killswitch = 0 + var/killswitch_time = 60 + var/weapon_lock = 0 + var/weaponlock_time = 120 diff --git a/code/defines/mob/living/silicon/silicon.dm b/code/defines/mob/living/silicon/silicon.dm new file mode 100644 index 0000000000000..6a6529bd25263 --- /dev/null +++ b/code/defines/mob/living/silicon/silicon.dm @@ -0,0 +1,4 @@ +/mob/living/silicon + gender = NEUTER + robot_talk_understand = 1 + var/syndicate = 0 \ No newline at end of file diff --git a/code/defines/mob/mob.dm b/code/defines/mob/mob.dm new file mode 100644 index 0000000000000..55ccc6610e42d --- /dev/null +++ b/code/defines/mob/mob.dm @@ -0,0 +1,173 @@ +/mob + density = 1 + layer = 4.0 + animate_movement = 2 + var/datum/mind/mind + + var/uses_hud = 0 + var/obj/screen/flash = null + var/obj/screen/blind = null + var/obj/screen/hands = null + var/obj/screen/mach = null + var/obj/screen/sleep = null + var/obj/screen/rest = null + var/obj/screen/pullin = null + var/obj/screen/internals = null + var/obj/screen/oxygen = null + var/obj/screen/i_select = null + var/obj/screen/m_select = null + var/obj/screen/toxin = null + var/obj/screen/fire = null + var/obj/screen/bodytemp = null + var/obj/screen/healths = null + var/obj/screen/throw_icon = null + + var/list/obj/hallucination/hallucinations = list() + + var/alien_egg_flag = 0 + + var/last_special = 0 + + var/obj/screen/zone_sel/zone_sel = null + + var/emote_allowed = 1 + var/computer_id = null + var/lastattacker = null + var/lastattacked = null + var/already_placed = 0.0 + var/obj/machinery/machine = null + var/other_mobs = null + var/memory = "" + var/poll_answer = 0.0 + var/sdisabilities = 0 + var/disabilities = 0 + var/atom/movable/pulling = null + var/stat = 0.0 + var/next_move = null + var/prev_move = null + var/monkeyizing = null + var/other = 0.0 + var/hand = null + var/eye_blind = null + var/eye_blurry = null + var/ear_deaf = null + var/ear_damage = null + var/stuttering = null + var/real_name = null + var/blinded = null + var/rejuv = null + var/druggy = 0 + var/confused = 0 + var/antitoxs = null + var/plasma = null + var/sleeping = 0.0 + var/resting = 0.0 + var/lying = 0.0 + var/canmove = 1.0 + var/eye_stat = null + var/oxyloss = 0.0 + var/toxloss = 0.0 + var/fireloss = 0.0 + var/timeofdeath = 0.0 + var/bruteloss = 0.0 + var/cpr_time = 1.0 + var/health = 100 + var/bodytemperature = 310.055 //98.7 F + var/drowsyness = 0.0 + var/dizziness = 0 + var/is_dizzy = 0 + var/is_jittery = 0 + var/jitteriness = 0 + var/charges = 0.0 + var/urine = 0.0 + var/poo = 0.0 + var/nutrition = 0.0 + var/paralysis = 0.0 + var/stunned = 0.0 + var/weakened = 0.0 + var/losebreath = 0.0 + var/muted = null + var/intent = null + var/shakecamera = 0 + var/a_intent = "help" + var/m_int = null + var/m_intent = "run" + var/lastDblClick = 0 + var/lastKnownIP = null + var/obj/stool/buckled = null + var/obj/item/weapon/handcuffs/handcuffed = null + var/obj/item/l_hand = null + var/obj/item/r_hand = null + var/obj/item/weapon/back = null + var/obj/item/weapon/tank/internal = null + var/obj/item/weapon/storage/s_active = null + var/obj/item/clothing/mask/wear_mask = null + var/r_epil = 0 + var/r_ch_cou = 0 + var/r_Tourette = 0 + + var/obj/hud/hud_used = null + + var/list/organs = list( ) + var/list/grabbed_by = list( ) + var/list/requests = list( ) + + var/list/mapobjs = list() + + var/in_throw_mode = 0 + + var/coughedtime = null + + var/inertia_dir = 0 + var/footstep = 1 + + var/music_lastplayed = "null" + + var/job = null + + var/nodamage = 0 + var/logged_in = 0 + + var/underwear = 1 + var/be_syndicate = 0 + var/be_random_name = 0 + var/const/blindness = 1 + var/const/deafness = 2 + var/const/muteness = 4 + var/brainloss = 0 + + + var/datum/dna/dna = null + var/radiation = 0.0 + + var/mutations = 0 + //telekinesis = 1 + //firemut = 2 + //xray = 4 + //hulk = 8 + //clumsy = 16 + //obese = 32 + //husk = 64 + + var/voice_name = "unidentifiable voice" + var/voice_message = null + +//Monkey/infected mode + var/list/resistances = list() + var/datum/disease/virus = null + + mouse_drag_pointer = MOUSE_ACTIVE_POINTER + +//Changeling mode stuff + var/changeling_level = 0 + var/list/absorbed_dna = list() + var/changeling_fakedeath = 0 + + + var/universal_speak = 0 // Set to 1 to enable the mob to speak to everyone -- TLE + var/obj/control_object // Hacking in to control objects -- TLE + + var/robot_talk_understand = 0 + +// Ruby mode + var/incorporeal_move = 0 \ No newline at end of file diff --git a/code/defines/obj.dm b/code/defines/obj.dm new file mode 100644 index 0000000000000..e33be6563826b --- /dev/null +++ b/code/defines/obj.dm @@ -0,0 +1,741 @@ +/obj + //var/datum/module/mod //not used + var/m_amt = 0 // metal + var/g_amt = 0 // glass + var/w_amt = 0 // waster amounts + animate_movement = 2 + + proc + handle_internal_lifeform(mob/lifeform_inside_me, breath_request) + //Return: (NONSTANDARD) + // null if object handles breathing logic for lifeform + // datum/air_group to tell lifeform to process using that breath return + //DEFAULT: Take air from turf to give to have mob process + if(breath_request>0) + return remove_air(breath_request) + else + return null + + initialize() + +/obj/blob + icon = 'blob.dmi' + icon_state = "bloba0" + var/health = 30 + density = 1 + opacity = 0 + anchored = 1 + +/obj/blob/idle + name = "blob" + desc = "it looks... frightened" + icon_state = "blobidle0" + +/obj/mark + var/mark = "" + icon = 'mark.dmi' + icon_state = "blank" + anchored = 1 + layer = 99 + mouse_opacity = 0 + +/obj/shieldgen + name = "shield generator" + desc = "Used to seal minor hull breaches." + icon = 'objects.dmi' + icon_state = "shieldoff" + var/active = 0 + var/health = 100 + var/malfunction = 0 + density = 1 + opacity = 0 + anchored = 0 + pressure_resistance = 2*ONE_ATMOSPHERE + +/obj/shieldwallgen + name = "shieldwall thing" + desc = "dont know" + icon = 'wizard.dmi' + icon_state = "dontknow" + var/active = 0 + var/range = 1 + density = 0 + opacity = 0 + anchored = 0 + pressure_resistance = 2*ONE_ATMOSPHERE + +/obj/shield + name = "shield" + desc = "An energy shield." + icon = 'effects.dmi' + icon_state = "shieldsparkles" + density = 1 + opacity = 0 + anchored = 1 + +/obj/shieldwall + name = "shield" + desc = "An energy shield." + icon = 'effects.dmi' + icon_state = "test" + density = 1 + opacity = 0 + anchored = 1 + +/obj/admins + name = "admins" + var/rank = null + var/owner = null + var/state = 1 + //state = 1 for playing : default + //state = 2 for observing + +/obj/bhole + name = "black hole" + icon = 'objects.dmi' + desc = "FUCK FUCK FUCK AAAHHH" + icon_state = "bhole2" + opacity = 0 + density = 0 + anchored = 1 + var/datum/effects/system/harmless_smoke_spread/smoke + + + + +/obj/beam + name = "beam" + +/obj/beam/a_laser + name = "a laser" + icon = 'projectiles.dmi' + icon_state = "laser" + density = 1 + var/yo = null + var/xo = null + var/current = null + var/life = 50.0 + anchored = 1.0 + flags = TABLEPASS + +/obj/beam/i_beam + name = "i beam" + icon = 'projectiles.dmi' + icon_state = "ibeam" + var/obj/beam/i_beam/next = null + var/obj/item/device/infra/master = null + var/limit = null + var/visible = 0.0 + var/left = null + anchored = 1.0 + flags = TABLEPASS + +/obj/bedsheetbin + name = "linen bin" + desc = "A bin for containing bedsheets." + icon = 'items.dmi' + icon_state = "bedbin" + var/amount = 23.0 + anchored = 1.0 + +/obj/begin + name = "begin" + icon = 'stationobjs.dmi' + icon_state = "begin" + anchored = 1.0 + +/obj/bullet + name = "bullet" + icon = 'projectiles.dmi' + icon_state = "bullet" + density = 1 + var/yo = null + var/xo = null + var/current = null + anchored = 1.0 + flags = TABLEPASS + +/obj/bullet/weakbullet + + +/obj/bullet/electrode + name = "electrode" + icon_state = "spark" + +/obj/bullet/teleshot + name = "teleshot" + icon_state = "spark" + var/failchance = 5 + var/obj/item/target = null + +/obj/bullet/cbbolt + name = "crossbow bolt" + icon_state = "cbbolt" + +/obj/datacore + name = "datacore" + var/list/medical = list( ) + var/list/general = list( ) + var/list/security = list( ) + +/obj/equip_e + name = "equip e" + var/mob/source = null + var/s_loc = null + var/t_loc = null + var/obj/item/item = null + var/place = null + +/obj/equip_e/human + name = "human" + var/mob/living/carbon/human/target = null + +/obj/equip_e/monkey + name = "monkey" + var/mob/living/carbon/monkey/target = null + +/obj/grille + desc = "A piece of metal with evenly spaced gridlike holes in it. Blocks large object but lets small items, gas, or energy beams through." + name = "grille" + icon = 'structures.dmi' + icon_state = "grille" + density = 1 + var/health = 10.0 + var/destroyed = 0.0 + anchored = 1.0 + flags = FPRINT | CONDUCT + pressure_resistance = 5*ONE_ATMOSPHERE + +/obj/securearea + desc = "A warning sign which reads 'SECURE AREA'" + name = "SECURE AREA" + icon = 'decals.dmi' + icon_state = "securearea" + anchored = 1.0 + opacity = 0 + density = 0 + +/obj/hud + name = "hud" + var/mob/mymob = null + var/list/adding = null + var/list/other = null + var/list/intents = null + var/list/mov_int = null + var/list/mon_blo = null + var/list/m_ints = null + var/obj/screen/druggy = null + var/vimpaired = null + var/obj/screen/alien_view = null + var/obj/screen/g_dither = null + var/obj/screen/blurry = null + var/list/darkMask = null + var/obj/screen/station_explosion = null + + var/h_type = /obj/screen + +/obj/item + name = "item" + icon = 'items.dmi' + var/icon_old = null + var/abstract = 0.0 + var/force = null + var/item_state = null + var/damtype = "brute" + var/throwforce = 10 + var/r_speed = 1.0 + var/health = null + var/burn_point = null + var/burning = null + var/hitsound = null + var/w_class = 3.0 + flags = FPRINT | TABLEPASS + pressure_resistance = 50 + var/obj/item/master = null + +/obj/item/device + icon = 'device.dmi' + +/obj/item/device/detective_scanner + name = "Scanner" + desc = "Used to scan objects for DNA and fingerprints" + icon_state = "forensic0" + var/amount = 20.0 + var/printing = 0.0 + w_class = 3.0 + item_state = "electronic" + flags = FPRINT | TABLEPASS | ONBELT | CONDUCT | USEDELAY + + +/obj/item/device/flash + name = "flash" + icon_state = "flash" + var/l_time = 1.0 + var/shots = 5.0 + throwforce = 5 + w_class = 1.0 + throw_speed = 4 + throw_range = 10 + flags = FPRINT | TABLEPASS| CONDUCT + item_state = "electronic" + var/status = 1 + +/obj/item/device/flashlight + name = "flashlight" + desc = "A hand-held emergency light." + icon_state = "flight0" + var/on = 0 + w_class = 2 + item_state = "flight" + flags = FPRINT | ONBELT | TABLEPASS | CONDUCT + m_amt = 50 + g_amt = 20 + +/obj/item/device/healthanalyzer + name = "Health Analyzer" + icon_state = "health" + item_state = "analyzer" + desc = "A hand-held body scanner able to distinguish vital signs of the subject." + flags = FPRINT | ONBELT | TABLEPASS | CONDUCT + throwforce = 3 + w_class = 1.0 + throw_speed = 5 + throw_range = 10 + m_amt = 200 + +/obj/item/device/igniter + name = "igniter" + desc = "A small electronic device able to ignite combustable substances." + icon_state = "igniter" + var/status = 1.0 + flags = FPRINT | TABLEPASS| CONDUCT + item_state = "electronic" + m_amt = 100 + throwforce = 5 + w_class = 1.0 + throw_speed = 3 + throw_range = 10 + + +/obj/item/device/infra + name = "Infrared Beam (Security)" + desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted." + icon_state = "infrared0" + var/obj/beam/i_beam/first = null + var/state = 0.0 + var/visible = 0.0 + flags = FPRINT | TABLEPASS| CONDUCT + w_class = 2.0 + item_state = "electronic" + m_amt = 150 + +/obj/item/device/infra_sensor + name = "Infrared Sensor" + desc = "Scans for infrared beams in the vicinity." + icon_state = "infra_sensor" + var/passive = 1.0 + flags = FPRINT | TABLEPASS| CONDUCT + item_state = "electronic" + m_amt = 150 + +/obj/item/device/t_scanner + name = "T-ray scanner" + desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes." + icon_state = "t-ray0" + var/on = 0 + flags = FPRINT|ONBELT|TABLEPASS + w_class = 2 + item_state = "electronic" + m_amt = 150 + + +/obj/item/device/multitool + name = "multitool" + icon_state = "multitool" + flags = FPRINT | TABLEPASS| CONDUCT + force = 5.0 + w_class = 2.0 + throwforce = 5.0 + throw_range = 15 + throw_speed = 3 + desc = "You can use this on airlocks or APCs to try to hack them without cutting wires." + m_amt = 50 + g_amt = 20 + + +/obj/item/device/prox_sensor + name = "Proximity Sensor" + icon_state = "motion0" + var/state = 0.0 + var/timing = 0.0 + var/time = null + flags = FPRINT | TABLEPASS| CONDUCT + w_class = 2.0 + item_state = "electronic" + m_amt = 300 + + +/obj/item/device/shield + name = "shield" + icon_state = "shield0" + var/active = 0.0 + flags = FPRINT | TABLEPASS| CONDUCT + item_state = "electronic" + throwforce = 5.0 + throw_speed = 1 + throw_range = 5 + w_class = 2.0 + +/obj/item/device/timer + name = "timer" + icon_state = "timer0" + item_state = "electronic" + var/timing = 0.0 + var/time = null + flags = FPRINT | TABLEPASS| CONDUCT + w_class = 2.0 + m_amt = 100 + + +/obj/landmark + name = "landmark" + icon = 'screen1.dmi' + icon_state = "x2" + anchored = 1.0 + +/obj/landmark/alterations + name = "alterations" + +/obj/laser + name = "laser" + icon = 'projectiles.dmi' + var/damage = 0.0 + var/range = 10.0 + +/obj/lattice + desc = "A lightweight support lattice." + name = "lattice" + icon = 'structures.dmi' + icon_state = "lattice" + density = 0 + anchored = 1.0 + layer = 2.5 + // flags = 64.0 + +/obj/list_container + name = "list container" + +/obj/list_container/mobl + name = "mobl" + var/master = null + + var/list/container = list( ) + +/obj/m_tray + name = "morgue tray" + icon = 'stationobjs.dmi' + icon_state = "morguet" + density = 1 + layer = 2.0 + var/obj/morgue/connected = null + anchored = 1.0 + +/obj/c_tray + name = "crematorium tray" + icon = 'stationobjs.dmi' + icon_state = "cremat" + density = 1 + layer = 2.0 + var/obj/crematorium/connected = null + anchored = 1.0 + + + + + +/obj/cable + level = 1 + anchored =1 + var/netnum = 0 + name = "power cable" + desc = "A flexible superconducting cable for heavy-duty power transfer." + icon = 'power_cond.dmi' + icon_state = "0-1" + var/d1 = 0 + var/d2 = 1 + layer = 2.5 + +/obj/manifest + name = "manifest" + icon = 'screen1.dmi' + icon_state = "x" + +/obj/morgue + name = "morgue" + icon = 'stationobjs.dmi' + icon_state = "morgue1" + density = 1 + var/obj/m_tray/connected = null + anchored = 1.0 + +/obj/crematorium + name = "crematorium" + desc = "A human incinerator." + icon = 'stationobjs.dmi' + icon_state = "crema1" + density = 1 + var/obj/c_tray/connected = null + anchored = 1.0 + var/cremating = 0 + var/id = 1 + var/locked = 0 + +/obj/mine + name = "Mine" + desc = "I Better stay away from that thing." + density = 1 + anchored = 1 + layer = 3 + icon = 'weapons.dmi' + icon_state = "uglymine" + var/triggerproc = "explode" //name of the proc thats called when the mine is triggered + var/triggered = 0 + +/obj/mine/dnascramble + name = "Radiation Mine" + icon_state = "uglymine" + triggerproc = "triggerrad" + +/obj/mine/plasma + name = "Plasma Mine" + icon_state = "uglymine" + triggerproc = "triggerplasma" + +/obj/mine/kick + name = "Kick Mine" + icon_state = "uglymine" + triggerproc = "triggerkick" + +/obj/mine/n2o + name = "N2O Mine" + icon_state = "uglymine" + triggerproc = "triggern2o" + +/obj/mine/stun + name = "Stun Mine" + icon_state = "uglymine" + triggerproc = "triggerstun" + +/obj/overlay + name = "overlay" + +/obj/portal + name = "portal" + icon = 'stationobjs.dmi' + icon_state = "portal" + density = 1 + var/failchance = 5 + var/obj/item/target = null + var/creator = null + anchored = 1.0 + +/obj/projection + name = "Projection" + anchored = 1.0 + +/obj/rack + name = "rack" + icon = 'objects.dmi' + icon_state = "rack" + density = 1 + flags = FPRINT + anchored = 1.0 + +/obj/screen + name = "screen" + icon = 'screen1.dmi' + layer = 20.0 + var/id = 0.0 + var/obj/master + +/obj/screen/close + name = "close" + master = null + +/obj/screen/grab + name = "grab" + master = null + +/obj/screen/storage + name = "storage" + master = null + +/obj/screen/zone_sel + name = "Damage Zone" + icon = 'zone_sel.dmi' + icon_state = "blank" + var/selecting = "chest" + screen_loc = "EAST+1,NORTH" + +/obj/shut_controller + name = "shut controller" + var/moving = null + var/list/parts = list( ) + +/obj/landmark/start + name = "start" + icon = 'screen1.dmi' + icon_state = "x" + anchored = 1.0 + +/obj/stool + name = "stool" + icon = 'objects.dmi' + icon_state = "stool" + flags = FPRINT + pressure_resistance = 3*ONE_ATMOSPHERE + +/obj/stool/bed + name = "bed" + icon_state = "bed" + anchored = 1.0 + +/obj/stool/chair + name = "chair" + icon_state = "chair" + var/status = 0.0 + anchored = 1.0 + +/obj/stool/chair/e_chair + name = "electrified chair" + icon_state = "e_chair0" + var/atom/movable/overlay/overl = null + var/on = 0.0 + var/obj/item/assembly/shock_kit/part1 = null + var/last_time = 1.0 + +/obj/table + name = "table" + icon = 'structures.dmi' + icon_state = "table" + density = 1 + anchored = 1.0 + +/obj/table/reinforced + name = "reinforced table" + icon_state = "reinf_table" + var/status = 2 + +/obj/table/woodentable + name = "wooden table" + icon_state = "woodentable" + +/obj/mopbucket + desc = "Fill it with water, but don't forget a mop!" + name = "mop bucket" + icon = 'janitor.dmi' + icon_state = "mopbucket" + density = 1 + flags = FPRINT + pressure_resistance = ONE_ATMOSPHERE + flags = FPRINT | TABLEPASS | OPENCONTAINER + +/obj/kitchenspike + name = "a meat spike" + icon = 'kitchen.dmi' + icon_state = "spike" + desc = "A spike for collecting meat from animals" + density = 1 + anchored = 1 + var/meat = 0 + var/occupied = 0 + var/meattype = 0 // 0 - Nothing, 1 - Monkey, 2 - Xeno + +/obj/displaycase + name = "Display Case" + icon = 'stationobjs.dmi' + icon_state = "glassbox1" + desc = "A display case for prized possessions." + density = 1 + anchored = 1 + var/health = 30 + var/occupied = 1 + var/destroyed = 0 + +obj/item/brain + name = "brain" + icon = 'surgery.dmi' + icon_state = "brain2" + flags = TABLEPASS + force = 1.0 + w_class = 1.0 + throwforce = 1.0 + throw_speed = 3 + throw_range = 5 + + var/mob/living/carbon/human/owner = null + + +/obj/item/brain/New() + ..() + spawn(5) + if(src.owner) + src.name = "[src.owner]'s brain" + +/obj/noticeboard + name = "Notice Board" + icon = 'stationobjs.dmi' + icon_state = "nboard00" + flags = FPRINT + desc = "A board for pinning important notices upon." + density = 0 + anchored = 1 + var/notices = 0 + +/obj/deskclutter + name = "desk clutter" + icon = 'items.dmi' + icon_state = "deskclutter" + desc = "Some clutter the detective has accumalated over the years..." + anchored = 1 + + + +/obj/item/mouse_drag_pointer = MOUSE_ACTIVE_POINTER + +// TODO: robust mixology system! (and merge with beakers, maybe) +/obj/item/weapon/glass + name = "empty glass" + icon = 'kitchen.dmi' + icon_state = "glass_empty" + item_state = "beaker" + flags = FPRINT | TABLEPASS | OPENCONTAINER + var/datum/substance/inside = null + throwforce = 5 + g_amt = 100 + New() + ..() + src.pixel_x = rand(-5, 5) + src.pixel_y = rand(-5, 5) + +/obj/item/weapon/storage/glassbox + name = "Glassware Box" + icon_state = "beakerbox" + item_state = "syringe_kit" + New() + ..() + new /obj/item/weapon/glass( src ) + new /obj/item/weapon/glass( src ) + new /obj/item/weapon/glass( src ) + new /obj/item/weapon/glass( src ) + new /obj/item/weapon/glass( src ) + new /obj/item/weapon/glass( src ) + new /obj/item/weapon/glass( src ) + +/obj/falsewall + name = "wall" + icon = 'walls.dmi' + icon_state = "" + density = 1 + opacity = 1 + anchored = 1 \ No newline at end of file diff --git a/code/defines/obj/assemblies.dm b/code/defines/obj/assemblies.dm new file mode 100644 index 0000000000000..4f7967c3a7c13 --- /dev/null +++ b/code/defines/obj/assemblies.dm @@ -0,0 +1,153 @@ +/obj/item/assembly + name = "assembly" + icon = 'assemblies.dmi' + item_state = "assembly" + var/status = 0.0 + throwforce = 10 + w_class = 3.0 + throw_speed = 4 + throw_range = 10 + +/obj/item/assembly/a_i_a + name = "Health-Analyzer/Igniter/Armor Assembly" + desc = "A health-analyzer, igniter and armor assembly." + icon_state = "armor-igniter-analyzer" + var/obj/item/device/healthanalyzer/part1 = null + var/obj/item/device/igniter/part2 = null + var/obj/item/clothing/suit/armor/vest/part3 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/m_i_ptank + desc = "A very intricate igniter and proximity sensor electrical assembly mounted onto top of a plasma tank." + name = "Proximity/Igniter/Plasma Tank Assembly" + icon_state = "prox-igniter-tank0" + var/obj/item/device/prox_sensor/part1 = null + var/obj/item/device/igniter/part2 = null + var/obj/item/weapon/tank/plasma/part3 = null + status = 0.0 + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/prox_ignite + name = "Proximity/Igniter Assembly" + desc = "A proximity-activated igniter assembly." + icon_state = "prox-igniter0" + var/obj/item/device/prox_sensor/part1 = null + var/obj/item/device/igniter/part2 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/r_i_ptank + desc = "A very intricate igniter and signaller electrical assembly mounted onto top of a plasma tank." + name = "Radio/Igniter/Plasma Tank Assembly" + icon_state = "radio-igniter-tank" + var/obj/item/device/radio/signaler/part1 = null + var/obj/item/device/igniter/part2 = null + var/obj/item/weapon/tank/plasma/part3 = null + status = 0.0 + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/anal_ignite + name = "Health-Analyzer/Igniter Assembly" + desc = "A health-analyzer igniter assembly." + icon_state = "timer-igniter0" + var/obj/item/device/healthanalyzer/part1 = null + var/obj/item/device/igniter/part2 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + item_state = "electronic" + +/obj/item/assembly/time_ignite + name = "Timer/Igniter Assembly" + desc = "A timer-activated igniter assembly." + icon_state = "timer-igniter0" + var/obj/item/device/timer/part1 = null + var/obj/item/device/igniter/part2 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/t_i_ptank + desc = "A very intricate igniter and timer assembly mounted onto top of a plasma tank." + name = "Timer/Igniter/Plasma Tank Assembly" + icon_state = "timer-igniter-tank0" + var/obj/item/device/timer/part1 = null + var/obj/item/device/igniter/part2 = null + var/obj/item/weapon/tank/plasma/part3 = null + status = 0.0 + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/rad_ignite + name = "Radio/Igniter Assembly" + desc = "A radio-activated igniter assembly." + icon_state = "radio-igniter" + var/obj/item/device/radio/signaler/part1 = null + var/obj/item/device/igniter/part2 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/rad_infra + name = "Signaller/Infrared Assembly" + desc = "An infrared-activated radio signaller" + icon_state = "infrared-radio0" + var/obj/item/device/radio/signaler/part1 = null + var/obj/item/device/infra/part2 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/rad_prox + name = "Signaller/Prox Sensor Assembly" + desc = "A proximity-activated radio signaller." + icon_state = "prox-radio0" + var/obj/item/device/radio/signaler/part1 = null + var/obj/item/device/prox_sensor/part2 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/rad_time + name = "Signaller/Timer Assembly" + desc = "A radio signaller activated by a count-down timer." + icon_state = "timer-radio0" + var/obj/item/device/radio/signaler/part1 = null + var/obj/item/device/timer/part2 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/shock_kit + name = "Shock Kit" + icon_state = "shock_kit" + var/obj/item/clothing/head/helmet/part1 = null + var/obj/item/device/radio/electropack/part2 = null + status = 0.0 + w_class = 5.0 + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/assembly/weld_rod + desc = "A welding torch with metal rods attached to the flame tip." + name = "Welder/Rods Assembly" + icon_state = "welder-rods" + item_state = "welder" + var/obj/item/weapon/weldingtool/part1 = null + var/obj/item/weapon/rods/part2 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + force = 3.0 + throwforce = 5.0 + throw_speed = 1 + throw_range = 5 + w_class = 2.0 + +/obj/item/assembly/w_r_ignite + desc = "A welding torch and igniter connected by metal rods." + name = "Welder/Rods/Igniter Assembly" + icon_state = "welder-rods-igniter" + item_state = "welder" + var/obj/item/weapon/weldingtool/part1 = null + var/obj/item/weapon/rods/part2 = null + var/obj/item/device/igniter/part3 = null + status = null + flags = FPRINT | TABLEPASS| CONDUCT + force = 3.0 + throwforce = 5.0 + throw_speed = 1 + throw_range = 5 + w_class = 2.0 \ No newline at end of file diff --git a/code/defines/obj/closet.dm b/code/defines/obj/closet.dm new file mode 100644 index 0000000000000..4a4dd729ca83c --- /dev/null +++ b/code/defines/obj/closet.dm @@ -0,0 +1,324 @@ +/obj/closet + desc = "It's a closet!" + name = "Closet" + icon = 'closet.dmi' + icon_state = "closed" + density = 1 + var/icon_closed = "closed" + var/icon_opened = "open" + var/opened = 0 + var/welded = 0 + flags = FPRINT + +/obj/spresent + desc = "It's a ... present?" + name = "strange present" + icon = 'items.dmi' + icon_state = "strangepresent" + density = 1 + anchored = 0 + +/obj/closet/gmcloset + desc = "A bulky (yet mobile) closet. Comes with formal clothes" + name = "Formal closet" + +/obj/closet/emcloset + desc = "A bulky (yet mobile) closet. Comes prestocked with a gasmask and o2 tank for emergencies." + name = "Emergency Closet" + icon_state = "emergency" + icon_closed = "emergency" + icon_opened = "emergencyopen" + +/obj/closet/jcloset + desc = "A bulky (yet mobile) closet. Comes with janitor's clothes and biohazard gear." + name = "Custodial Closet" + +/obj/closet/lawcloset + desc = "A bulky (yet mobile) closet. Comes with lawyer apparel and items." + name = "Legal Closet" + +/obj/closet/coffin + desc = "A burial receptacle for the dearly departed." + name = "coffin" + icon_state = "coffin" + icon_closed = "coffin" + icon_opened = "coffin_open" + +/obj/closet/l3closet + desc = "A bulky (yet mobile) closet. Comes prestocked with level 3 biohazard gear for emergencies." + name = "Level 3 Biohazard Suit" + icon_state = "bio" + icon_closed = "bio" + icon_opened = "bioopen" + +/obj/closet/syndicate + desc = "Why is this here?" + name = "Weapons Closet" + icon_state = "syndicate" + icon_closed = "syndicate" + icon_opened = "syndicateopen" + +/obj/closet/syndicate/personal + desc = "Gear preperations closet." + +/obj/closet/syndicate/nuclear + desc = "Nuclear preperations closet." + +/obj/closet/thunderdome + desc = "Everything you need!" + icon_state = "syndicate" + icon_closed = "syndicate" + icon_opened = "syndicateopen" + desc = "Thunderdome closet." + anchored = 1 + +/obj/closet/thunderdome/tdred + desc = "Everything you need!" + icon_state = "syndicate" + icon_closed = "syndicate" + icon_opened = "syndicateopen" + desc = "Thunderdome closet." + +/obj/closet/thunderdome/tdgreen + desc = "Everything you need!" + icon_state = "syndicate1" + icon_closed = "syndicate1" + icon_opened = "syndicate1open" + desc = "Thunderdome closet." + +/obj/closet/malf/suits + desc = "Gear preperations closet." + icon_state = "syndicate" + icon_closed = "syndicate" + icon_opened = "syndicateopen" + +/obj/closet/wardrobe + desc = "A bulky (yet mobile) wardrobe closet. Comes prestocked with 6 changes of clothes." + name = "Wardrobe" + icon_state = "blue" + icon_closed = "blue" + +/obj/closet/wardrobe/black + name = "Black Wardrobe" + icon_state = "black" + icon_closed = "black" + +/obj/closet/wardrobe/chaplain_black + name = "Chaplain Wardrobe" + icon_state = "black" + icon_closed = "black" + +/obj/closet/wardrobe/green + name = "Green Wardrobe" + icon_state = "green" + icon_closed = "green" + +/obj/closet/wardrobe/mixed + name = "Mixed Wardrobe" + icon_state = "mixed" + icon_closed = "mixed" + +/obj/closet/wardrobe/orange + name = "Prisoners Wardrobe" + icon_state = "orange" + icon_closed = "orange" + +/obj/closet/wardrobe/pink + name = "Pink Wardrobe" + icon_state = "pink" + icon_closed = "pink" + +/obj/closet/wardrobe/red + name = "Red Wardrobe" + icon_state = "red" + icon_closed = "red" + +/obj/closet/wardrobe/forensics_red + name = "Forensics Wardrobe" + icon_state = "red" + icon_closed = "red" + + +/obj/closet/wardrobe/white + name = "Medical Wardrobe" + icon_state = "white" + icon_closed = "white" + +/obj/closet/wardrobe/toxins_white + name = "Toxins Wardrobe" + icon_state = "white" + icon_closed = "white" + +/obj/closet/wardrobe/genetics_white + name = "Genetics Wardrobe" + icon_state = "white" + icon_closed = "white" + + +/obj/closet/wardrobe/yellow + name = "Yellow Wardrobe" + icon_state = "wardrobe-y" + icon_closed = "wardrobe-y" + +/obj/closet/wardrobe/engineering_yellow + name = "Engineering Wardrobe" + icon_state = "yellow" + icon_closed = "yellow" + +/obj/closet/wardrobe/atmospherics_yellow + name = "Atmospherics Wardrobe" + icon_state = "yellow" + icon_closed = "yellow" + + +/obj/closet/wardrobe/grey + name = "Grey Wardrobe" + icon_state = "grey" + icon_closed = "grey" + + +/obj/secure_closet + desc = "An immobile card-locked storage closet." + name = "Security Locker" + icon = 'closet.dmi' + icon_state = "secure1" + density = 1 + var/opened = 0 + var/locked = 1 + var/broken = 0 + var/large = 1 + var/icon_closed = "secure" + var/icon_locked = "secure1" + var/icon_opened = "secureopen" + var/icon_broken = "securebroken" + var/icon_off = "secureoff" + +/obj/secure_closet/courtroom + name = "Courtroom Locker" + req_access = list(access_heads) + +/obj/secure_closet/animal + name = "Animal Control" + req_access = list(access_medical) + +/obj/secure_closet/brig + name = "Brig Locker" + req_access = list(access_brig) + var/id = null + +/obj/secure_closet/highsec + name = "Head of Personnel" + req_access = list(access_heads) + +/obj/secure_closet/hos + name = "Head Of Security" + req_access = list(access_heads) + +/obj/secure_closet/captains + name = "Captain's Closet" + req_access = list(access_captain) + +/obj/secure_closet/medical1 + name = "Medicine Closet" + icon_state = "medical1" + icon_closed = "medical" + icon_locked = "medical1" + icon_opened = "medicalopen" + icon_broken = "medicalbroken" + icon_off = "medical1" + req_access = list(access_medical) + +/obj/secure_closet/chemical + name = "Chemical Closet" + icon_state = "medical1" + icon_closed = "medical" + icon_locked = "medical1" + icon_opened = "medicalopen" + icon_broken = "medicalbroken" + icon_off = "medical1" + req_access = list(access_medical) + +/obj/secure_closet/medical2 + name = "Anesthetic" + icon_state = "medical1" + icon_closed = "medical" + icon_locked = "medical1" + icon_opened = "medicalopen" + icon_broken = "medicalbroken" + icon_off = "medical1" + req_access = list(access_medical) + +/obj/secure_closet/personal + desc = "The first card swiped gains control." + name = "Personal Closet" + + +/obj/secure_closet/security1 + name = "Security Equipment" + req_access = list(access_security) + +/obj/secure_closet/security2 + name = "Forensics Locker" + req_access = list(access_forensics_lockers) + +/obj/secure_closet/scientist + name = "Scientist Locker" + + req_access = list(access_tox_storage) +/obj/secure_closet/chemtoxin + name = "Chemistry Locker" + + req_access = list(access_medical) +/obj/secure_closet/bar + name = "Booze" + req_access = list(access_bar) + +/obj/secure_closet/kitchen + name = "Kitchen Cabinet" + req_access = list(access_kitchen) + +/obj/secure_closet/meat + name = "Meat Locker" + +/obj/secure_closet/fridge + name = "Refrigerator" + icon_state = "fridge1" + icon_closed = "fridge" + icon_locked = "fridge1" + icon_opened = "fridgeopen" + icon_broken = "fridgebroken" + icon_off = "fridge1" + + +/obj/secure_closet/engineering_chief + name = "Chief Engineer's Locker" + req_access = list(access_heads) + +/obj/secure_closet/engineering_electrical + name = "Electrical Supplies" + req_access = list(access_engine) + +/obj/secure_closet/engineering_welding + name = "Welding Supplies" + req_access = list(access_engine) + +/obj/secure_closet/engineering_personal + name = "Engineer's Locker" + req_access = list(access_engine) + + + + +/obj/secure_closet/wall + name = "wall locker" + req_access = list(access_security) + icon_state = "wall-locker1" + density = 1 + icon_closed = "wall-locker" + icon_locked = "wall-locker1" + icon_opened = "wall-lockeropen" + icon_broken = "wall-lockerbroken" + icon_off = "wall-lockeroff" + + //too small to put a man in + large = 0 \ No newline at end of file diff --git a/code/defines/obj/clothing.dm b/code/defines/obj/clothing.dm new file mode 100644 index 0000000000000..25437bced0824 --- /dev/null +++ b/code/defines/obj/clothing.dm @@ -0,0 +1,865 @@ +// All currently in-game clothing. Gimmicks moved to obj\clothing\gimmick.dm for all of your gay fantasy roleplay dress-up shenanigans. + +/obj/item/clothing + name = "clothing" +// var/obj/item/clothing/master = null + + var/see_face = 1.0 + var/color = null + + var/body_parts_covered = 0 //see setup.dm for appropriate bit flags + + var/protective_temperature = 0 + var/heat_transfer_coefficient = 1 //0 prevents all transfers, 1 is invisible + var/gas_transfer_coefficient = 1 // for leaking gas from turf to mask and vice-versa (for masks right now, but at some point, i'd like to include space helmets) + var/permeability_coefficient = 1 // for chemicals/diseases + var/siemens_coefficient = 1 // for electrical admittance/conductance (electrocution checks and shit) + +// EARS + +/obj/item/clothing/ears + name = "ears" + w_class = 1.0 + throwforce = 2 + +/obj/item/clothing/ears/earmuffs + name = "earmuffs" + icon_state = "earmuffs" + protective_temperature = 500 + item_state = "earmuffs" + +// GLASSES + +/obj/item/clothing/glasses + name = "glasses" + icon = 'glasses.dmi' + w_class = 2.0 + flags = GLASSESCOVERSEYES + +/obj/item/clothing/glasses/blindfold + name = "blindfold" + icon_state = "blindfold" + item_state = "blindfold" + +/obj/item/clothing/glasses/meson + name = "Optical Meson Scanner" + icon_state = "meson" + item_state = "glasses" + +/obj/item/clothing/glasses/regular + name = "Prescription Glasses" + icon_state = "glasses" + item_state = "glasses" + +/obj/item/clothing/glasses/sunglasses + desc = "Strangely ancient technology used to help provide rudimentary eye cover. Enhanced shielding blocks many flashes." + name = "Sunglasses" + icon_state = "sun" + item_state = "sunglasses" + protective_temperature = 1300 + var/already_worn = 0 + +/obj/item/clothing/glasses/thermal + name = "Optical Thermal Scanner" + icon_state = "thermal" + item_state = "glasses" + +// NO GLOVES NO LOVES + +/obj/item/clothing/gloves + name = "gloves" + w_class = 2.0 + icon = 'gloves.dmi' + protective_temperature = 400 + heat_transfer_coefficient = 0.25 + siemens_coefficient = 0.50 + var/elecgen = 0 + var/uses = 0 + body_parts_covered = HANDS + +/obj/item/clothing/gloves/black + desc = "These gloves are fire-resistant." + name = "Black Gloves" + icon_state = "black" + item_state = "bgloves" + + protective_temperature = 1500 + heat_transfer_coefficient = 0.01 + + +/obj/item/clothing/gloves/cyborg + desc = "beep boop borp" + name = "cyborg gloves" + icon_state = "black" + item_state = "r_hands" + siemens_coefficient = 1.0 + +/obj/item/clothing/gloves/latex + name = "Latex Gloves" + icon_state = "latex" + item_state = "lgloves" + siemens_coefficient = 0.30 + + protective_temperature = 310 + heat_transfer_coefficient = 0.90 + +/obj/item/clothing/gloves/swat + desc = "These tactical gloves are somewhat fire and impact-resistant." + name = "SWAT Gloves" + icon_state = "black" + item_state = "swat_gl" + siemens_coefficient = 0.30 + + protective_temperature = 1100 + heat_transfer_coefficient = 0.05 + +/obj/item/clothing/gloves/stungloves/ + name = "Stungloves" + desc = "These gloves are electrically charged." + icon_state = "yellow" + item_state = "ygloves" + siemens_coefficient = 0.30 + elecgen = 1 + uses = 10 + +/obj/item/clothing/gloves/yellow + desc = "These gloves are electrically insulated." + name = "insulated gloves" + icon_state = "yellow" + item_state = "ygloves" + siemens_coefficient = 0 + + protective_temperature = 1000 + heat_transfer_coefficient = 0.01 + +// HATS. OH MY WHAT A FINE CHAPEAU, GOOD SIR. + +/obj/item/clothing/head + name = "head" + icon = 'hats.dmi' + body_parts_covered = HEAD + +/obj/item/clothing/head/bio_hood + name = "bio hood" + icon_state = "bio" + permeability_coefficient = 0.01 + flags = FPRINT|TABLEPASS|HEADSPACE|HEADCOVERSEYES|HEADCOVERSMOUTH + +/obj/item/clothing/head/cakehat + name = "cakehat" + desc = "It is a cakehat" + icon_state = "cake0" + var/onfire = 0.0 + var/status = 0 + flags = FPRINT|TABLEPASS|HEADSPACE|HEADCOVERSEYES + var/fire_resist = T0C+1300 //this is the max temp it can stand before you start to cook. although it might not burn away, you take damage + +/obj/item/clothing/head/caphat + name = "Captain's hat" + icon_state = "captain" + flags = FPRINT|TABLEPASS|SUITSPACE + item_state = "caphat" + +/obj/item/clothing/head/centhat + name = "Cent. Comm. hat" + icon_state = "centcom" + flags = FPRINT|TABLEPASS|SUITSPACE + item_state = "centcom" + +/obj/item/clothing/head/det_hat + name = "hat" + desc = "Someone who wears this will look very smart" + icon_state = "detective" + +/obj/item/clothing/head/powdered_wig + name = "powdered wig" + desc = "A powdered wig" + icon_state = "pwig" + item_state = "pwig" + + +/obj/item/clothing/head/that + name = "hat" + desc = "An amish looking hat" + icon_state = "tophat" + item_state = "that" + +/obj/item/clothing/head/wizard + name = "wizard hat" + desc = "It has WIZZARD written across it in sequins" + icon_state = "wizard" + +/obj/item/clothing/head/chefhat + name = "Chef's hat" + icon_state = "chef" + item_state = "chef" + flags = FPRINT | TABLEPASS | HEADSPACE + + +// CHUMP HELMETS: COOKING THEM DESTROYS THE CHUMP HELMET SPAWN. + +/obj/item/clothing/head/helmet + name = "helmet" + icon_state = "helmet" + flags = FPRINT|TABLEPASS|SUITSPACE|HEADCOVERSEYES + item_state = "helmet" + + protective_temperature = 500 + heat_transfer_coefficient = 0.10 + +/obj/item/clothing/head/helmet/space + name = "space helmet" + icon_state = "space" + flags = FPRINT | TABLEPASS | HEADSPACE | HEADCOVERSEYES | HEADCOVERSMOUTH + see_face = 0.0 + item_state = "space" + +/obj/item/clothing/head/helmet/space/syndicate + name = "red space helmet" + icon_state = "syndicate" + item_state = "syndicate" + +/obj/item/clothing/head/helmet/swat + name = "swat helmet" + icon_state = "swat" + flags = FPRINT | TABLEPASS | SUITSPACE | HEADSPACE | HEADCOVERSEYES + item_state = "swat" + +/obj/item/clothing/head/helmet/thunderdome + name = "Thunderdome helmet" + icon_state = "thunderdome" + flags = FPRINT | TABLEPASS | SUITSPACE | HEADSPACE | HEADCOVERSEYES + item_state = "thunderdome" + +/obj/item/clothing/head/helmet/hardhat + name = "hard hat" + icon_state = "hardhat0" + flags = FPRINT | TABLEPASS | SUITSPACE + item_state = "hardhat0" + var/on = 0 + + +/obj/item/clothing/head/helmet/welding + name = "welding helmet" + desc = "A head-mounted face cover designed to protect the wearer completely from space-arc eye." + icon_state = "welding" + flags = FPRINT | TABLEPASS | SUITSPACE | HEADCOVERSEYES + see_face = 0.0 + item_state = "welding" + protective_temperature = 1300 + m_amt = 3000 + g_amt = 1000 + +/obj/item/clothing/head/helmet/HoS + name = "HoS helmet" + icon_state = "hoscap" + flags = FPRINT | TABLEPASS | SUITSPACE | HEADCOVERSEYES + +// MASK WAS THAT MOVIE WITH THAT GUY WITH THE MESSED UP FACE. WHAT'S HIS NAME . . . JIM CARREY, I THINK. + +/obj/item/clothing/mask + name = "mask" + icon = 'masks.dmi' + var/vchange = 0 + body_parts_covered = HEAD + +/obj/item/clothing/mask/gas + name = "gas mask" + desc = "A close-fitting mask that can filter some environmental toxins or be connected to an air supply." + icon_state = "gas_mask" + flags = FPRINT|TABLEPASS|SUITSPACE|MASKCOVERSMOUTH|MASKCOVERSEYES + w_class = 3.0 + see_face = 0.0 + item_state = "gas_mask" + protective_temperature = 500 + heat_transfer_coefficient = 0.01 + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0.01 + + +/obj/item/clothing/mask/gas/emergency + name = "emergency gas mask" + icon_state = "gas_alt" + item_state = "gas_alt" + +/obj/item/clothing/mask/gas/swat + name = "SWAT Mask" + desc = "A close-fitting tactical mask that can filter some environmental toxins or be connected to an air supply." + icon_state = "swat" + +/obj/item/clothing/mask/gas/voice + name = "gas mask" + desc = "A close-fitting mask that can filter some environmental toxins or be connected to an air supply." + icon_state = "gas_mask" + vchange = 1 + +/obj/item/clothing/mask/breath + desc = "A close-fitting mask that can be connected to an air supply but does not work very well in hard vacuum." + name = "Breath Mask" + icon_state = "breath" + item_state = "breath" + flags = FPRINT | TABLEPASS | SUITSPACE | HEADSPACE | MASKCOVERSMOUTH + w_class = 2 + protective_temperature = 420 + heat_transfer_coefficient = 0.90 + gas_transfer_coefficient = 0.10 + permeability_coefficient = 0.50 + +/obj/item/clothing/mask/clown_hat + name = "clown wig and mask" + desc = "You're gay for even considering wearing this." + icon_state = "clown" + item_state = "clown_hat" + +/obj/item/clothing/mask/medical + desc = "This mask does not work very well in low pressure environments." + name = "Medical Mask" + icon_state = "medical" + item_state = "medical" + flags = FPRINT|TABLEPASS|SUITSPACE|HEADSPACE|MASKCOVERSMOUTH + w_class = 3 + protective_temperature = 420 + gas_transfer_coefficient = 0.10 + +/obj/item/clothing/mask/muzzle + name = "muzzle" + icon_state = "muzzle" + item_state = "muzzle" + flags = FPRINT|TABLEPASS|MASKCOVERSMOUTH + w_class = 2 + gas_transfer_coefficient = 0.90 + +/obj/item/clothing/mask/surgical + name = "Sterile Mask" + icon_state = "sterile" + item_state = "sterile" + w_class = 1 + flags = FPRINT|TABLEPASS|HEADSPACE|MASKCOVERSMOUTH + gas_transfer_coefficient = 0.90 + permeability_coefficient = 0.05 + + +/obj/item/clothing/mask/cigarette + name = "Cigarette" + icon_state = "cigoff" + var/lit = 0 + throw_speed = 0.5 + item_state = "cigoff" + var/lastHolder = null + var/smoketime = 300 + w_class = 1 + +// OMG SHOES + +/obj/item/clothing/shoes + name = "shoes" + icon = 'shoes.dmi' + var/chained = 0 + + body_parts_covered = FEET + + protective_temperature = 500 + heat_transfer_coefficient = 0.10 + permeability_coefficient = 0.50 + +/obj/item/clothing/shoes/black + name = "Black Shoes" + icon_state = "black" + + protective_temperature = 1500 + heat_transfer_coefficient = 0.01 + +/obj/item/clothing/shoes/brown + name = "Brown Shoes" + icon_state = "brown" + +/obj/item/clothing/shoes/orange + name = "Orange Shoes" + icon_state = "orange" + +/obj/item/clothing/shoes/swat + name = "SWAT shoes" + icon_state = "swat" + +/obj/item/clothing/shoes/white + name = "White Shoes" + icon_state = "white" + permeability_coefficient = 0.25 + +/obj/item/clothing/shoes/sandal + name = "sandals" + icon_state = "wizard" + +/obj/item/clothing/shoes/galoshes + desc = "Rubber boots" + name = "galoshes" + icon_state = "galoshes" + permeability_coefficient = 0.05 + +/obj/item/clothing/shoes/magboots + desc = "Magnetic boots, often used during extravehicular activity to ensure the user remains safely attached to the vehicle." + name = "magboots" + icon_state = "magboots" + protective_temperature = 800 + +/obj/item/clothing/shoes/clown_shoes + desc = "Damn, thems some big shoes." + name = "clown shoes" + icon_state = "clown" + item_state = "clown_shoes" + +// SUITS + +/obj/item/clothing/suit + icon = 'suits.dmi' + name = "suit" + var/fire_resist = T0C+100 + flags = FPRINT | TABLEPASS + + +/obj/item/clothing/suit/bio_suit + name = "bio suit" + desc = "A suit that protects against biological contamination." + icon_state = "bio" + item_state = "bio_suit" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0.01 + heat_transfer_coefficient = 0.30 + +/obj/item/clothing/suit/det_suit + name = "coat" + desc = "Someone who wears this means business" + icon_state = "detective" + item_state = "det_suit" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + +/obj/item/clothing/suit/judgerobe + name = "judge's robe" + desc = "This robe commands authority" + icon_state = "judge" + item_state = "judge" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + +/obj/item/clothing/suit/labcoat + name = "labcoat" + desc = "A suit that protects against minor chemical spills." + icon_state = "labcoat" + item_state = "labcoat" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + permeability_coefficient = 0.25 + heat_transfer_coefficient = 0.75 + +/obj/item/clothing/suit/straight_jacket + name = "straight jacket" + desc = "A suit that totally restrains an individual" + icon_state = "straight_jacket" + item_state = "straight_jacket" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + +/obj/item/clothing/suit/wcoat + name = "waistcoat" + icon_state = "vest" + item_state = "wcoat" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + +/obj/item/clothing/suit/wizrobe + name = "robe" + desc = "A magnificant blue robe that seems to radiate power" + icon_state = "wizard" + item_state = "wizrobe" + gas_transfer_coefficient = 0.01 // IT'S MAGICAL OKAY JEEZ +1 TO NOT DIE + permeability_coefficient = 0.01 + heat_transfer_coefficient = 0.01 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + +// ARMOR + +/obj/item/clothing/suit/armor/vest + name = "armor" + desc = "An armored vest that protects against some damage." + icon_state = "armor" + item_state = "armor" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + flags = FPRINT | TABLEPASS | ONESIZEFITSALL + +/obj/item/clothing/suit/armor/a_i_a_ptank + desc = "A wearable bomb with a health analyzer attached" + name = "Analyzer/Igniter/Armor/Plasmatank Assembly" + icon_state = "bomb" + item_state = "bombvest" + var/obj/item/device/healthanalyzer/part1 = null + var/obj/item/device/igniter/part2 = null + var/obj/item/weapon/tank/plasma/part4 = null + var/obj/item/clothing/suit/armor/vest/part3 = null + var/status = 0 + flags = FPRINT | TABLEPASS | CONDUCT | ONESIZEFITSALL + body_parts_covered = UPPER_TORSO + +/obj/item/clothing/suit/armor/captain + name = "Captain's armor" + icon_state = "caparmor" + item_state = "caparmor" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + +/obj/item/clothing/suit/armor/centcomm + name = "Cent. Com. armor" + desc = "A suit that protects against some damage." + icon_state = "centcom" + item_state = "centcom" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + +/obj/item/clothing/suit/armor/heavy + name = "heavy armor" + desc = "A heavily armored suit that protects against moderate damage." + icon_state = "heavy" + item_state = "swat_suit" + gas_transfer_coefficient = 0.90 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + +/obj/item/clothing/suit/armor/tdome + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + +/obj/item/clothing/suit/armor/tdome/red + name = "Thunderdome suit (red)" + icon_state = "tdred" + item_state = "tdred" + +/obj/item/clothing/suit/armor/tdome/green + name = "Thunderdome suit (green)" + icon_state = "tdgreen" + item_state = "tdgreen" + +/obj/item/clothing/suit/armor/swat + name = "swat suit" + icon_state = "heavy" + item_state = "heavy" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + +// FIRE SUITS + +/obj/item/clothing/suit/fire + name = "firesuit" + desc = "A suit that protects against fire and heat." + icon_state = "fire" + item_state = "fire_suit" + gas_transfer_coefficient = 0.90 + permeability_coefficient = 0.50 + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + + protective_temperature = 4500 + heat_transfer_coefficient = 0.01 + +/obj/item/clothing/suit/fire/heavy + name = "firesuit" + desc = "A suit that protects against extreme fire and heat." + icon_state = "thermal" + item_state = "ro_suit" + + protective_temperature = 10000 + heat_transfer_coefficient = 0.01 + +// SPACE SUITS + +/obj/item/clothing/suit/space + name = "space suit" + desc = "A suit that protects against low pressure environments." + icon_state = "space" + gas_transfer_coefficient = 0.01 + item_state = "s_suit" + flags = FPRINT | TABLEPASS | SUITSPACE + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + permeability_coefficient = 0.02 + protective_temperature = 1000 + heat_transfer_coefficient = 0.02 + +/obj/item/clothing/suit/space/syndicate + name = "red space suit" + icon_state = "syndicate" + item_state = "space_suit_syndicate" + +// UNDERS AND BY THAT, NATURALLY I MEAN UNIFORMS/JUMPSUITS + +/obj/item/clothing/under + icon = 'uniforms.dmi' + name = "under" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + protective_temperature = T0C + 50 + heat_transfer_coefficient = 0.30 + permeability_coefficient = 0.90 + flags = FPRINT | TABLEPASS | ONESIZEFITSALL + +// Colors + +/obj/item/clothing/under/chameleon +//starts off as black + name = "Black Jumpsuit" + icon_state = "black" + item_state = "bl_suit" + color = "black" + desc = null + var/list/clothing_choices = list() + +/obj/item/clothing/under/chameleon/all + +/obj/item/clothing/under/color/black + name = "Black Jumpsuit" + icon_state = "black" + item_state = "bl_suit" + color = "black" + +/obj/item/clothing/under/color/blue + name = "Blue Jumpsuit" + icon_state = "blue" + item_state = "b_suit" + color = "blue" + +/obj/item/clothing/under/color/green + name = "Green Jumpsuit" + icon_state = "green" + item_state = "g_suit" + color = "green" + +/obj/item/clothing/under/color/grey + name = "Grey Jumpsuit" + icon_state = "grey" + item_state = "gy_suit" + color = "grey" + +/obj/item/clothing/under/color/orange + name = "Orange Jumpsuit" + icon_state = "orange" + item_state = "o_suit" + color = "orange" + +/obj/item/clothing/under/color/pink + name = "Pink Jumpsuit (F)" + icon_state = "pink" + item_state = "p_suit" + color = "pink" + +/obj/item/clothing/under/color/red + name = "Red Jumpsuit" + icon_state = "red" + item_state = "r_suit" + color = "red" + +/obj/item/clothing/under/color/white + desc = "Made of a special fiber that gives special protection against biohazards." + name = "White Jumpsuit" + icon_state = "white" + item_state = "w_suit" + color = "white" + permeability_coefficient = 0.50 + +/obj/item/clothing/under/color/yellow + name = "Yellow Jumpsuit" + icon_state = "yellow" + item_state = "y_suit" + color = "yellow" + +// RANKS + +/obj/item/clothing/under/rank/atmospheric_technician + desc = "It has an Atmospherics rank stripe on it." + name = "Atmospherics Jumpsuit" + icon_state = "atmos" + item_state = "y_suit" + color = "atmos" + +/obj/item/clothing/under/rank/captain + desc = "It has a Captains rank stripe on it." + name = "Captain Jumpsuit" + icon_state = "captain" + item_state = "dg_suit" + + color = "captain" + +/obj/item/clothing/under/rank/chaplain + desc = "It has a Chaplain rank stripe on it." + name = "Chaplain Jumpsuit" + icon_state = "chaplain" + item_state = "bl_suit" + color = "chapblack" + +/obj/item/clothing/under/rank/engineer + desc = "It has an Engineering rank stripe on it." + name = "Engineering Jumpsuit" + icon_state = "engine" + item_state = "y_suit" + color = "engine" + +/obj/item/clothing/under/rank/forensic_technician + desc = "It has a Forensics rank stripe on it." + name = "Forensics Jumpsuit" + icon_state = "darkred" + item_state = "r_suit" + color = "forensicsred" + +/obj/item/clothing/under/rank/geneticist + desc = "Made of a special fiber that gives special protection against biohazards. Has a genetics rank stripe on it." + name = "Genetics Jumpsuit" + icon_state = "genetics" + item_state = "w_suit" + color = "geneticswhite" + permeability_coefficient = 0.50 + +/obj/item/clothing/under/rank/head_of_personnel + desc = "It has a Head of Personnel rank stripe on it." + name = "Head of Personnel Jumpsuit" + icon_state = "hop" + item_state = "g_suit" + color = "hopgreen" + +/obj/item/clothing/under/rank/head_of_security + desc = "It has a Head of Security rank stripe on it." + name = "Head of Security Jumpsuit" + icon_state = "hos" + item_state = "r_suit" + color = "hosred" + +/obj/item/clothing/under/rank/chief_engineer + desc = "It has a Chief Engineer rank stripe on it." + name = "Chief Engineer Jumpsuit" + icon_state = "chiefengineer" + item_state = "g_suit" + color = "chief" + +/obj/item/clothing/under/rank/research_director + desc = "It has a Research Director rank stripe on it." + name = "Research Director Jumpsuit" + icon_state = "director" + item_state = "g_suit" + color = "director" + +/obj/item/clothing/under/rank/janitor + desc = "Official clothing of the station's poopscooper." + name = "Janitor's Jumpsuit" + icon_state = "janitor" + color = "janitor" + +/obj/item/clothing/under/rank/scientist + desc = "Made of a special fiber that gives special protection against biohazards. Has a toxins rank stripe on it." + name = "Scientist's Jumpsuit" + icon_state = "toxins" + item_state = "w_suit" + color = "toxinswhite" + permeability_coefficient = 0.50 + +/obj/item/clothing/under/rank/medical + desc = "Made of a special fiber that gives special protection against biohazards. Has a medical rank stripe on it." + name = "Medical Doctor's Jumpsuit" + icon_state = "medical" + item_state = "w_suit" + color = "medical" + permeability_coefficient = 0.50 + +/obj/item/clothing/under/rank/hydroponics + desc = "Made of a special fiber that gives special protection against biohazards. Has a Hydroponics rank stripe on it." + name = "Hydroponics Jumpsuit" + icon_state = "hydroponics" + item_state = "g_suit" + color = "hydroponics" + permeability_coefficient = 0.50 + +// OTHER NONRANKED STATION JOBS + +/obj/item/clothing/under/bartender + desc = "It looks like it could use more flair." + name = "Bartender's Uniform" + icon_state = "ba_suit" + item_state = "ba_suit" + color = "ba_suit" + +/obj/item/clothing/under/clown + name = "clown suit" + desc = "Wearing this, all the children love you, for all the wrong reasons." + icon_state = "clown" + color = "clown" + +/obj/item/clothing/under/chef + desc = "Issued only to the most hardcore chefs in space." + name = "Chef's Uniform" + icon_state = "chef" + color = "chef" + +/obj/item/clothing/under/det + name = "Hard worn suit" + desc = "Someone who wears this means business" + icon_state = "detective" + item_state = "det" + color = "detective" + +/obj/item/clothing/under/lawyer + desc = "Slick threads." + name = "Lawyer suit" + flags = FPRINT | TABLEPASS + +/obj/item/clothing/under/lawyer/black + icon_state = "lawyer_black" + item_state = "lawyer_black" + color = "lawyer_black" + +/obj/item/clothing/under/lawyer/red + icon_state = "lawyer_red" + item_state = "lawyer_red" + color = "lawyer_red" + +/obj/item/clothing/under/lawyer/blue + icon_state = "lawyer_blue" + item_state = "lawyer_blue" + color = "lawyer_blue" + + +/obj/item/clothing/under/sl_suit + desc = "A very amish looking suit" + name = "Amish Suit" + icon_state = "sl_suit" + color = "sl_suit" + +/obj/item/clothing/under/cargo + name = "Quartermaster's Jumpsuit" + desc = "What can brown do for you?" + icon_state = "lightbrown" + item_state = "lb_suit" + color = "cargo" + +/obj/item/clothing/under/syndicate + name = "Tactical Turtleneck" + desc = "Non-descript, slightly suspicious civilian clothing." + icon_state = "syndicate" + item_state = "bl_suit" + color = "syndicate" + +/obj/item/clothing/under/librarian + name = "Sensible Suit" + desc = "It's very... sensible." + icon_state = "red_suit" + item_state = "red_suit" + + +// Athletic shorts.. heh +/obj/item/clothing/under/shorts + name = "athletic shorts" + desc = "95% Polyester, 5% Spandex!" + flags = FPRINT | TABLEPASS + +/obj/item/clothing/under/shorts/red + icon_state = "redshorts" + color = "redshorts" + +/obj/item/clothing/under/shorts/green + icon_state = "greenshorts" + color = "greenshorts" + +/obj/item/clothing/under/shorts/blue + icon_state = "blueshorts" + color = "blueshorts" + +/obj/item/clothing/under/shorts/black + icon_state = "blackshorts" + color = "blackshorts" + +/obj/item/clothing/under/shorts/grey + icon_state = "greyshorts" + color = "greyshorts" \ No newline at end of file diff --git a/code/defines/obj/clothing/gimmick.dm b/code/defines/obj/clothing/gimmick.dm new file mode 100644 index 0000000000000..24d6c804b259a --- /dev/null +++ b/code/defines/obj/clothing/gimmick.dm @@ -0,0 +1,252 @@ +/obj/item/clothing/shoes/red + name = "red shoes" + icon_state = "red" + + +/obj/item/clothing/head/helmet/space/santahat + name = "Santa's hat" + icon_state = "santahat" + +/obj/item/clothing/suit/space/santa + name = "Santa's suit" + desc = "Festive!" + icon_state = "santa" + item_state = "santa" + + +/obj/item/clothing/mask/owl_mask + name = "Owl mask" + desc = "Twoooo!" + icon_state = "owl" + +/obj/item/clothing/under/owl + name = "Owl uniform" + desc = "Twoooo!" + icon_state = "owl" + color = "owl" + +/obj/item/clothing/gloves/cyborg + desc = "beep boop borp" + name = "cyborg gloves" + icon_state = "black" + item_state = "r_hands" + siemens_coefficient = 1 + +/obj/item/clothing/mask/gas/cyborg + name = "cyborg visor" + desc = "Beep boop" + icon_state = "death" + +/obj/item/clothing/shoes/cyborg + name = "cyborg boots" + icon_state = "boots" + +/obj/item/clothing/suit/cyborg_suit + name = "cyborg suit" + icon_state = "death" + item_state = "death" + flags = FPRINT | TABLEPASS | CONDUCT + fire_resist = T0C+5200 + + +/obj/item/clothing/under/nazi1 + name = "Nazi uniform" + desc = "SIEG HEIL!" + icon_state = "nazi1" + color = "nazi" + +/obj/item/clothing/suit/greatcoat + name = "great coat" + desc = "A Nazi great coat" + icon_state = "nazi" + item_state = "nazi" + flags = FPRINT | TABLEPASS + +/obj/item/clothing/under/johnny + name = "Johnny~~" + desc = "Johnny~~" + icon_state = "johnny" + color = "johnny" + +/obj/item/clothing/suit/johnny_coat + name = "Johnny~~" + desc = "Johnny~~" + icon_state = "johnny" + item_state = "johnny" + flags = FPRINT | TABLEPASS + + +/obj/item/clothing/under/rainbow + name = "rainbow" + desc = "rainbow" + icon_state = "rainbow" + color = "rainbow" + +/obj/item/clothing/under/cloud + name = "cloud" + desc = "cloud" + icon_state = "cloud" + color = "aqua" + +/obj/item/clothing/under/yay + name = "yay" + desc = "Yay!" + icon_state = "yay" + color = "yellow" + +// UNUSED COLORS + +/obj/item/clothing/under/psyche + name = "psychedelic" + desc = "Groovy!" + icon_state = "psyche" + color = "psyche" + +/obj/item/clothing/under/maroon + name = "maroon" + desc = "maroon" + icon_state = "maroon" + color = "maroon" + +/obj/item/clothing/under/lightblue + name = "lightblue" + desc = "lightblue" + icon_state = "lightblue" + color = "lightblue" + +/obj/item/clothing/under/aqua + name = "aqua" + desc = "aqua" + icon_state = "aqua" + color = "aqua" + +/obj/item/clothing/under/purple + name = "purple" + desc = "purple" + icon_state = "purple" + color = "purple" + +/obj/item/clothing/under/lightpurple + name = "lightpurple" + desc = "lightpurple" + icon_state = "lightpurple" + color = "lightpurple" + +/obj/item/clothing/under/lightgreen + name = "lightgreen" + desc = "lightgreen" + icon_state = "lightgreen" + color = "lightgreen" + +/obj/item/clothing/under/lightblue + name = "lightblue" + desc = "lightblue" + icon_state = "lightblue" + color = "lightblue" + +/obj/item/clothing/under/lightbrown + name = "lightbrown" + desc = "lightbrown" + icon_state = "lightbrown" + color = "lightbrown" + +/obj/item/clothing/under/brown + name = "brown" + desc = "brown" + icon_state = "brown" + color = "brown" + +/obj/item/clothing/under/yellowgreen + name = "yellowgreen" + desc = "yellowgreen" + icon_state = "yellowgreen" + color = "yellowgreen" + +/obj/item/clothing/under/darkblue + name = "darkblue" + desc = "darkblue" + icon_state = "darkblue" + color = "darkblue" + +/obj/item/clothing/under/lightred + name = "lightred" + desc = "lightred" + icon_state = "lightred" + color = "lightred" + +/obj/item/clothing/under/darkred + name = "darkred" + desc = "darkred" + icon_state = "darkred" + color = "darkred" + +// STEAMPUNK STATION + +/obj/item/clothing/glasses/monocle + name = "monocle" + desc = "Such a dapper eyepiece!" + icon_state = "monocle" + item_state = "headset" // lol + +/obj/item/clothing/under/rank/captain/suit + name = "Captain's Suit" + desc = "A green suit and yellow necktie. Exemplifies authority." + icon_state = "green_suit" + item_state = "dg_suit" + color = "green_suit" + +/obj/item/clothing/under/rank/head_of_personnel/suit + name = "Head of Personnel's Suit" + desc = "A teal suit and yellow necktie. An authoritative yet tacky ensemble." + icon_state = "teal_suit" + item_state = "g_suit" + color = "teal_suit" + +/obj/item/clothing/under/suit_jacket + name = "Black Suit" + desc = "A black suit and red tie. Very formal." + icon_state = "black_suit" + item_state = "bl_suit" + color = "black_suit" + +/obj/item/clothing/under/suit_jacket/red + name = "Red Suit" + desc = "A red suit and blue tie. Somewhat formal." + icon_state = "red_suit" + item_state = "r_suit" + color = "red_suit" + +/obj/item/clothing/under/rank/police + name = "Police Uniform" + desc = "Move along, nothing to see here." + icon_state = "police" + item_state = "b_suit" + color = "police" + +/obj/item/clothing/head/helmet/bobby + name = "Custodian Helmet" + desc = "Heh. Lookit dat fukken helmet." + icon_state = "policehelm" + item_state = "helmet" + +/obj/item/clothing/head/flatcap + name = "flat cap" + desc = "A working man's cap." + icon_state = "flat_cap" + item_state = "detective" + +/obj/item/clothing/under/overalls + name = "Laborer's Overalls" + desc = "A set of durable overalls for getting the job done." + icon_state = "overalls" + item_state = "lb_suit" + color = "overalls" + +/obj/item/weapon/classic_baton + name = "police baton" + desc = "A wooden truncheon for beating criminal scum." + icon = 'weapons.dmi' + icon_state = "baton" + item_state = "classic_baton" + flags = FPRINT | ONBELT | TABLEPASS + force = 10 diff --git a/code/defines/obj/computer.dm b/code/defines/obj/computer.dm new file mode 100644 index 0000000000000..875397ad42607 --- /dev/null +++ b/code/defines/obj/computer.dm @@ -0,0 +1,229 @@ +/obj/machinery/computer + name = "computer" + icon = 'computer.dmi' + density = 1 + anchored = 1.0 +/* +/obj/machinery/computer/airtunnel + name = "Air Tunnel Control" + icon = 'airtunnelcomputer.dmi' + icon_state = "console00" +*/ + +/obj/machinery/computer/operating + name = "Operating Computer" + density = 1 + anchored = 1.0 + icon = 'computer.dmi' + icon_state = "comm" + + var/mob/living/carbon/human/victim = null + + var/obj/machinery/optable/table = null + var/id = 0.0 + +/* + * Arcade -- An arcade cabinet. + */ + +/obj/machinery/computer/arcade + name = "arcade machine" + icon = 'computer.dmi' + icon_state = "arcade" + var/enemy_name = "Space Villian" + var/temp = "Winners Don't Use Spacedrugs" //Temporary message, for attack messages, etc + var/player_hp = 30 //Player health/attack points + var/player_mp = 10 + var/enemy_hp = 45 //Enemy health/attack points + var/enemy_mp = 20 + var/gameover = 0 + var/blocked = 0 //Player cannot attack/heal while set + +/obj/machinery/computer/aiupload + name = "AI Upload" + icon_state = "aiupload" + +/obj/machinery/computer/atmosphere + name = "atmos" + +/obj/machinery/computer/atmosphere/alerts + name = "Alert Computer" + icon_state = "atmos" + var/alarms = list("Fire"=list(), "Atmosphere"=list()) + +/obj/machinery/computer/general_alert + name = "General Alert Computer" + icon_state = "alert:0" + var/list/priority_alarms = list() + var/list/minor_alarms = list() + var/receive_frequency = "1437" + + +/obj/machinery/computer/atmosphere/siphonswitch + name = "Area Air Control" + icon_state = "atmos" + var/otherarea + var/area/area + +/obj/machinery/computer/atmosphere/siphonswitch/mastersiphonswitch + name = "Master Air Control" + +/obj/machinery/computer/card + name = "Identification Computer" + icon_state = "id" + var/obj/item/weapon/card/id/scan = null + var/obj/item/weapon/card/id/modify = null + var/authenticated = 0.0 + var/mode = 0.0 + var/printing = null + req_access = list(access_change_ids) + +/obj/machinery/computer/communications + name = "Communications Console" + icon_state = "comm" + req_access = list(access_heads) + var/prints_intercept = 1 + var/authenticated = 0 + var/list/messagetitle = list() + var/list/messagetext = list() + var/currmsg = 0 + var/aicurrmsg = 0 + var/state = STATE_DEFAULT + var/aistate = STATE_DEFAULT + var/const + STATE_DEFAULT = 1 + STATE_CALLSHUTTLE = 2 + STATE_CANCELSHUTTLE = 3 + STATE_MESSAGELIST = 4 + STATE_VIEWMESSAGE = 5 + STATE_DELMESSAGE = 6 + STATE_STATUSDISPLAY = 7 + + var/status_display_freq = "1435" + var/stat_msg1 + var/stat_msg2 + +/obj/machinery/computer/data + name = "data" + icon_state = "aiupload" + + var/list/topics = list( ) + +/obj/machinery/computer/data/weapon + name = "weapon" + +/obj/machinery/computer/data/weapon/info + name = "Research Computer" + +/obj/machinery/computer/data/weapon/log + name = "Log Computer" + +/obj/machinery/computer/dna + name = "DNA operations computer" + icon_state = "dna" + var/obj/item/weapon/card/data/scan = null + var/obj/item/weapon/card/data/modify = null + var/obj/item/weapon/card/data/modify2 = null + var/mode = null + var/temp = null + +/obj/machinery/computer/hologram_comp + name = "Hologram Computer" + icon = 'stationobjs.dmi' + icon_state = "holo_console0" + var/obj/machinery/hologram_proj/projector = null + var/temp = null + var/lumens = 0.0 + var/h_r = 245.0 + var/h_g = 245.0 + var/h_b = 245.0 + +/obj/machinery/computer/med_data + name = "Medical Records" + icon_state = "dna" + req_access = list(access_medical) + var/obj/item/weapon/card/id/scan = null + var/authenticated = null + var/rank = null + var/screen = null + var/datum/data/record/active1 = null + var/datum/data/record/active2 = null + var/a_id = null + var/temp = null + var/printing = null + +/obj/machinery/computer/pod + name = "Pod Launch Control" + icon_state = "computer_generic" + var/id = 1.0 + var/obj/machinery/mass_driver/connected = null + var/timing = 0.0 + var/time = 30.0 + +/obj/machinery/computer/pod/old + icon_state = "old" + name = "DoorMex Control Computer" + +/obj/machinery/computer/pod/old/syndicate + name = "ProComp Executive IIc" + desc = "The Syndicate operate on a tight budget. Operates external airlocks." + +/obj/machinery/computer/pod/old/swf + name = "Magix System IV" + desc = "An arcane artifact that holds much magic. Running E-Knock 2.2: Sorceror's Edition" + +/obj/machinery/computer/prison_shuttle + name = "Prison Shuttle" + icon_state = "shuttle" + var/allowedtocall = 0 + +/obj/machinery/computer/secure_data + name = "Security Records" + icon_state = "computer_generic" + req_access = list(access_security) + var/obj/item/weapon/card/id/scan = null + var/authenticated = null + var/rank = null + var/screen = null + var/datum/data/record/active1 = null + var/datum/data/record/active2 = null + var/a_id = null + var/temp = null + var/printing = null + var/can_change_id = 0 + +/obj/machinery/computer/secure_data/detective_computer + icon = 'computer.dmi' + icon_state = "messyfiles" + +/obj/machinery/computer/security + name = "Security Cameras" + icon_state = "security" + var/obj/machinery/camera/current = null + var/last_pic = 1.0 + var/network = "SS13" + var/maplevel = 1 + +/obj/machinery/computer/security/wooden_tv + name = "Security Cameras" + icon_state = "security_det" + + +/obj/machinery/computer/security/telescreen + name = "Telescreen" + icon = 'stationobjs.dmi' + icon_state = "telescreen" + network = "thunder" + density = 0 + +/obj/machinery/computer/shuttle + name = "Shuttle" + icon_state = "shuttle" + var/auth_need = 3.0 + var/list/authorized = list( ) + +/obj/machinery/computer/teleporter + name = "Teleporter" + icon_state = "teleport" + var/obj/item/locked = null + var/id = null \ No newline at end of file diff --git a/code/defines/obj/decal.dm b/code/defines/obj/decal.dm new file mode 100644 index 0000000000000..7a8a9e1ce668e --- /dev/null +++ b/code/defines/obj/decal.dm @@ -0,0 +1,136 @@ +/obj/decal/ash + name = "Ashes" + desc = "Ashes to ashes, dust to dust." + icon = 'objects.dmi' + icon_state = "ash" + anchored = 1 + +/obj/decal/point + name = "point" + icon = 'screen1.dmi' + icon_state = "arrow" + layer = 16.0 + anchored = 1 + +/obj/decal/cleanable + var/list/random_icon_states = list() + +/obj/decal/cleanable/blood + name = "blood" + desc = "It's red." + density = 0 + anchored = 1 + layer = 2 + icon = 'blood.dmi' + icon_state = "floor1" + random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7") + var/datum/disease/virus = null + blood_DNA = null + blood_type = null + +/obj/decal/cleanable/blood/splatter + random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5") + +/obj/decal/cleanable/blood/tracks + icon_state = "tracks" + random_icon_states = null + +/obj/decal/cleanable/blood/gibs + name = "gibs" + desc = "Grisly..." + density = 0 + anchored = 0 + layer = 2 + icon = 'blood.dmi' + icon_state = "gibbl5" + random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6") + +/obj/decal/cleanable/blood/gibs/body + random_icon_states = list("gibhead", "gibtorso") + +/obj/decal/cleanable/blood/gibs/limb + random_icon_states = list("gibleg", "gibarm") + +/obj/decal/cleanable/blood/gibs/core + random_icon_states = list("gibmid1", "gibmid2", "gibmid3") + +/obj/decal/cleanable/robot_debris + name = "robot debris" + desc = "Useless heap of junk." + density = 0 + anchored = 0 + layer = 2 + icon = 'robots.dmi' + icon_state = "gib1" + random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7") + +/obj/decal/cleanable/robot_debris/limb + random_icon_states = list("gibarm", "gibleg") + +/obj/decal/cleanable/oil + name = "motor oil" + desc = "It's black." + density = 0 + anchored = 1 + layer = 2 + icon = 'oil.dmi' + icon_state = "floor1" + var/datum/disease/virus = null + random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7") + +/obj/decal/cleanable/oil/streak + random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5") + +/obj/decal/cleanable/generic + name = "clutter" + desc = "Someone should clean that up." + density = 0 + anchored = 1 + layer = 2 + icon = 'objects.dmi' + icon_state = "shards" + +/obj/decal/cleanable/dirt + name = "dirt" + desc = "Someone should clean that up." + density = 0 + anchored = 1 + layer = 2 + icon = 'old_or_unused.dmi' + icon_state = "dirt" + +/obj/decal/cleanable/greenglow + name = "green glow" + desc = "Eerie." + density = 0 + anchored = 1 + layer = 2 + icon = 'effects.dmi' + icon_state = "greenglow" + +/obj/decal/cleanable/cobweb + name = "cobweb" + desc = "Someone should remove that." + density = 0 + anchored = 1 + layer = 3 + icon = 'old_or_unused.dmi' + icon_state = "cobweb1" + +/obj/decal/cleanable/molten_item + name = "gooey grey mass" + desc = "huh." + density = 0 + anchored = 1 + layer = 3 + icon = 'chemical.dmi' + icon_state = "molten" + +/obj/decal/cleanable/cobweb2 + name = "cobweb" + desc = "Someone should remove that." + density = 0 + anchored = 1 + layer = 3 + icon = 'old_or_unused.dmi' + icon_state = "cobweb2" diff --git a/code/defines/obj/door.dm b/code/defines/obj/door.dm new file mode 100644 index 0000000000000..7c8cf4d5e75e5 --- /dev/null +++ b/code/defines/obj/door.dm @@ -0,0 +1,115 @@ +/obj/machinery/door + name = "Door" + icon = 'doorint.dmi' + icon_state = "door1" + opacity = 1 + density = 1 + var/secondsElectrified = 0 + var/visible = 1 + var/p_open = 0 + var/operating = 0 + anchored = 1 + var/autoclose = 0 + +/obj/machinery/door/firedoor + name = "Firelock" + icon = 'Doorfire.dmi' + icon_state = "door0" + var/blocked = null + opacity = 0 + density = 0 + var/nextstate = null + +/obj/machinery/door/firedoor/border_only + name = "Firelock" + icon = 'door_fire2.dmi' + icon_state = "door0" + +/obj/machinery/door/poddoor + name = "Podlock" + icon = 'rapid_pdoor.dmi' + icon_state = "pdoor1" + var/id = 1.0 + +/obj/machinery/door/window + name = "interior door" + icon = 'windoor.dmi' + icon_state = "left" + var/base_state = "left" + visible = 0.0 + flags = ON_BORDER + opacity = 0 + +/obj/machinery/door/window/brigdoor + name = "Brig Door" + icon = 'windoor.dmi' + icon_state = "leftsecure" + base_state = "leftsecure" + var/id = 1.0 + + +/obj/machinery/door/window/northleft + dir = NORTH + +/obj/machinery/door/window/eastleft + dir = EAST + +/obj/machinery/door/window/westleft + dir = WEST + +/obj/machinery/door/window/southleft + dir = SOUTH + +/obj/machinery/door/window/northright + dir = NORTH + icon_state = "right" + base_state = "right" + +/obj/machinery/door/window/eastright + dir = EAST + icon_state = "right" + base_state = "right" + +/obj/machinery/door/window/westright + dir = WEST + icon_state = "right" + base_state = "right" + +/obj/machinery/door/window/southright + dir = SOUTH + icon_state = "right" + base_state = "right" + + +/obj/machinery/door/window/brigdoor/northleft + dir = NORTH + +/obj/machinery/door/window/brigdoor/eastleft + dir = EAST + +/obj/machinery/door/window/brigdoor/westleft + dir = WEST + +/obj/machinery/door/window/brigdoor/southleft + dir = SOUTH + +/obj/machinery/door/window/brigdoor/northright + dir = NORTH + icon_state = "rightsecure" + base_state = "rightsecure" + +/obj/machinery/door/window/brigdoor/eastright + dir = EAST + icon_state = "rightsecure" + base_state = "rightsecure" + +/obj/machinery/door/window/brigdoor/westright + dir = WEST + icon_state = "rightsecure" + base_state = "rightsecure" + +/obj/machinery/door/window/brigdoor/southright + dir = SOUTH + icon_state = "rightsecure" + base_state = "rightsecure" + diff --git a/code/defines/obj/food.dm b/code/defines/obj/food.dm new file mode 100644 index 0000000000000..c0d28871bbc7d --- /dev/null +++ b/code/defines/obj/food.dm @@ -0,0 +1,61 @@ +//Grown foods +/obj/item/weapon/reagent_containers/food/snacks/grown/ //New subclass so we can pass on values + var/seed = "" + var/plantname = "" + var/productname = "" + var/species = "" + var/lifespan = 0 + var/endurance = 0 + var/maturation = 0 + var/production = 0 + var/yield = 0 + var/potency = -1 + +/obj/item/weapon/reagent_containers/food/snacks/grown/berries + name = "berries" + desc = "Nutritious!" + icon_state = "berrypile" + amount = 2 + heal_amt = 5 + +/obj/item/weapon/reagent_containers/food/snacks/grown/chili + name = "chili" + desc = "Spicy!" + icon_state = "chillipepper" + amount = 1 + heal_amt = 5 + +/obj/item/weapon/reagent_containers/food/snacks/grown/eggplant + name = "eggplant" + desc = "Yum!" + icon_state = "eggplant" + amount = 2 + heal_amt = 5 + +/obj/item/weapon/reagent_containers/food/snacks/grown/soybeans + name = "soybeans" + desc = "Pretty bland, but the possibilities..." + icon_state = "soybeans" + amount = 1 + heal_amt = 2 + +/obj/item/weapon/reagent_containers/food/snacks/grown/tomato + name = "tomato" + desc = "Tom-mae-to or to-mah-to? You decide." + icon_state = "tomato" + amount = 2 + heal_amt = 5 + +/obj/item/weapon/reagent_containers/food/snacks/grown/wheat + name = "wheat" + desc = "I wouldn't eat this, unless you're one of those health freaks.." + icon_state = "wheat" + amount = 1 + heal_amt = 1 + +/obj/item/weapon/reagent_containers/food/snacks/grown/icepepper + name = "icepepper" + desc = "THIS SHOULD PROBABLY DO SOMETHING BUT IT DOESN'T RIGHT NOW SO YOU CAN GO FUCK RIGHT OFF" + icon_state = "icepepper" + amount = 1 + heal_amt = 1 \ No newline at end of file diff --git a/code/defines/obj/injector.dm b/code/defines/obj/injector.dm new file mode 100644 index 0000000000000..e237d1e793490 --- /dev/null +++ b/code/defines/obj/injector.dm @@ -0,0 +1,173 @@ +/obj/item/weapon/dnainjector + name = "DNA-Injector" + icon = 'items.dmi' + icon_state = "dnainjector" + var/dnatype = null + var/dna = null + var/block = null + var/owner = null + var/ue = null + var/s_time = 10.0 + throw_speed = 1 + throw_range = 5 + w_class = 1.0 + var/uses = 1 + var/nofail + var/is_bullet = 0 + +/obj/item/weapon/dnainjector/antihulk + name = "DNA-Injector (Anti-Hulk)" + dnatype = "se" + dna = "708" + block = 2 + +/obj/item/weapon/dnainjector/hulkmut + name = "DNA-Injector (Hulk)" + dnatype = "se" + dna = "FED" + block = 2 + +/obj/item/weapon/dnainjector/xraymut + name = "DNA-Injector (Xray)" + dnatype = "se" + dna = "FED" + block = 8 + +/obj/item/weapon/dnainjector/antixray + name = "DNA-Injector (Anti-Xray)" + dnatype = "se" + dna = "708" + block = 8 + +///////////////////////////////////// +/obj/item/weapon/dnainjector/antiglasses + name = "DNA-Injector (Anti-Glasses)" + dnatype = "se" + dna = "708" + block = 1 + +/obj/item/weapon/dnainjector/glassesmut + name = "DNA-Injector (Glasses)" + dnatype = "se" + dna = "BD6" + block = 1 + +/obj/item/weapon/dnainjector/epimut + name = "DNA-Injector (Epi.)" + dnatype = "se" + dna = "FA0" + block = 3 + +/obj/item/weapon/dnainjector/antiepi + name = "DNA-Injector (Anti-Epi.)" + dnatype = "se" + dna = "708" + block = 3 +//////////////////////////////////// +/obj/item/weapon/dnainjector/anticough + name = "DNA-Injector (Anti-Cough)" + dnatype = "se" + dna = "708" + block = 5 + +/obj/item/weapon/dnainjector/coughmut + name = "DNA-Injector (Cough)" + dnatype = "se" + dna = "BD6" + block = 5 + +/obj/item/weapon/dnainjector/clumsymut + name = "DNA-Injector (Clumsy)" + dnatype = "se" + dna = "FA0" + block = 6 + +/obj/item/weapon/dnainjector/anticlumsy + name = "DNA-Injector (Anti-Clumy)" + dnatype = "se" + dna = "708" + block = 6 + +/obj/item/weapon/dnainjector/antitour + name = "DNA-Injector (Anti-Tour.)" + dnatype = "se" + dna = "708" + block = 7 + +/obj/item/weapon/dnainjector/tourmut + name = "DNA-Injector (Tour.)" + dnatype = "se" + dna = "BD6" + block = 7 + +/obj/item/weapon/dnainjector/stuttmut + name = "DNA-Injector (Stutt.)" + dnatype = "se" + dna = "FA0" + block = 9 + +/obj/item/weapon/dnainjector/antistutt + name = "DNA-Injector (Anti-Stutt.)" + dnatype = "se" + dna = "708" + block = 9 + +/obj/item/weapon/dnainjector/antifire + name = "DNA-Injector (Anti-Fire)" + dnatype = "se" + dna = "708" + block = 10 + +/obj/item/weapon/dnainjector/firemut + name = "DNA-Injector (Fire)" + dnatype = "se" + dna = "FED" + block = 10 + +/obj/item/weapon/dnainjector/blindmut + name = "DNA-Injector (Blind)" + dnatype = "se" + dna = "FA0" + block = 11 + +/obj/item/weapon/dnainjector/antiblind + name = "DNA-Injector (Anti-Blind)" + dnatype = "se" + dna = "708" + block = 11 + +/obj/item/weapon/dnainjector/antitele + name = "DNA-Injector (Anti-Tele.)" + dnatype = "se" + dna = "708" + block = 12 + +/obj/item/weapon/dnainjector/telemut + name = "DNA-Injector (Tele.)" + dnatype = "se" + dna = "FED" + block = 12 + +/obj/item/weapon/dnainjector/deafmut + name = "DNA-Injector (Deaf)" + dnatype = "se" + dna = "FA0" + block = 13 + +/obj/item/weapon/dnainjector/antideaf + name = "DNA-Injector (Anti-Deaf)" + dnatype = "se" + dna = "708" + block = 13 + +/obj/item/weapon/dnainjector/h2m + name = "DNA-Injector (Human > Monkey)" + dnatype = "se" + dna = "FA0" + block = 14 + +/obj/item/weapon/dnainjector/m2h + name = "DNA-Injector (Monkey > Human)" + dnatype = "se" + dna = "708" + block = 14 \ No newline at end of file diff --git a/code/defines/obj/machinery.dm b/code/defines/obj/machinery.dm new file mode 100644 index 0000000000000..9c019ce4b5b01 --- /dev/null +++ b/code/defines/obj/machinery.dm @@ -0,0 +1,652 @@ +/obj/machinery + name = "machinery" + icon = 'stationobjs.dmi' + var/stat = 0 + +/obj/machinery/alarm + name = "alarm" + icon = 'monitors.dmi' + icon_state = "alarm0" + anchored = 1.0 + var/skipprocess = 0 //Experimenting + var/alarm_frequency = "1437" + var/alarm_zone = null + +/obj/machinery/autolathe + name = "Autolathe" + icon_state = "autolathe" + density = 1 + var/m_amount = 0.0 + var/g_amount = 0.0 + var/operating = 0.0 + var/opened = 0.0 + var/temp = null + anchored = 1.0 + var/list/L = list() + var/list/LL = list() + var/hacked = 0 + var/disabled = 0 + var/shocked = 0 + var/list/wires = list() + var/hack_wire + var/disable_wire + var/shock_wire + +/obj/machinery/camera + name = "Security Camera" + icon = 'monitors.dmi' + icon_state = "camera" + var/network = "SS13" + layer = 5 + var/c_tag = null + var/c_tag_order = 999 + var/status = 1.0 + anchored = 1.0 + var/invuln = null + var/bugged = 0 + + + +/obj/machinery/dispenser + desc = "A simple yet bulky one-way storage device for gas tanks. Holds 10 plasma and 10 oxygen tanks." + name = "Tank Storage Unit" + icon = 'objects.dmi' + icon_state = "dispenser" + density = 1 + var/o2tanks = 10.0 + var/pltanks = 10.0 + anchored = 1.0 + +/obj/machinery/dna_scanner + name = "DNA Scanner/Implanter" + icon = 'Cryogenic2.dmi' + icon_state = "scanner_0" + density = 1 + var/locked = 0.0 + var/mob/occupant = null + anchored = 1.0 + +/obj/machinery/dna_scannernew + name = "DNA Modifier" + icon = 'Cryogenic2.dmi' + icon_state = "scanner_0" + density = 1 + var/locked = 0.0 + var/mob/occupant = null + anchored = 1.0 + + +/obj/machinery/firealarm + name = "Fire Alarm" + icon = 'monitors.dmi' + icon_state = "fire0" + var/detecting = 1.0 + var/working = 1.0 + var/time = 10.0 + var/timing = 0.0 + var/lockdownbyai = 0 + anchored = 1.0 + +/obj/machinery/partyalarm + name = "Party Button" + icon = 'monitors.dmi' + icon_state = "fire0" + var/detecting = 1.0 + var/working = 1.0 + var/time = 10.0 + var/timing = 0.0 + var/lockdownbyai = 0 + anchored = 1.0 + + + +/obj/machinery/hologram_proj + name = "Hologram Projector" + icon = 'stationobjs.dmi' + icon_state = "hologram0" + var/atom/projection = null + anchored = 1.0 + +/obj/machinery/hologram_ai + name = "Hologram Projector Platform" + icon = 'stationobjs.dmi' + icon_state = "hologram0" + var/atom/projection = null + var/temp = null + var/lumens = 0.0 + var/h_r = 245.0 + var/h_g = 245.0 + var/h_b = 245.0 + anchored = 1.0 + +/obj/machinery/igniter + name = "igniter" + icon = 'stationobjs.dmi' + icon_state = "igniter1" + var/id = null + var/on = 1.0 + anchored = 1.0 + +/obj/machinery/injector + name = "injector" + icon = 'stationobjs.dmi' + icon_state = "injector" + density = 1 + anchored = 1.0 + flags = ON_BORDER + +/obj/machinery/mass_driver + name = "mass driver" + icon = 'stationobjs.dmi' + icon_state = "mass_driver" + var/power = 1.0 + var/code = 1.0 + var/id = 1.0 + anchored = 1.0 + var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess. + +/obj/machinery/meter + name = "meter" + icon = 'meter.dmi' + icon_state = "meterX" + var/obj/machinery/atmospherics/pipe/target = null + anchored = 1.0 + var/frequency = 0 + var/id + +/obj/machinery/nuclearbomb + desc = "Uh oh." + name = "Nuclear Fission Explosive" + icon = 'stationobjs.dmi' + icon_state = "nuclearbomb0" + density = 1 + var/deployable = 0.0 + var/extended = 0.0 + var/timeleft = 60.0 + var/timing = 0.0 + var/r_code = "ADMIN" + var/code = "" + var/yes_code = 0.0 + var/safety = 1.0 + var/obj/item/weapon/disk/nuclear/auth = null + flags = FPRINT + +/obj/machinery/optable + name = "Operating Table" + icon = 'surgery.dmi' + icon_state = "table2-idle" + density = 1 + anchored = 1.0 + + var/mob/living/carbon/human/victim = null + var/strapped = 0.0 + + var/obj/machinery/computer/operating/computer = null + var/id = 0.0 + +/obj/machinery/vehicle + name = "Vehicle Pod" + icon = 'escapepod.dmi' + icon_state = "podfire" + density = 1 + flags = FPRINT + anchored = 1.0 + var/speed = 10.0 + var/maximum_speed = 10.0 + var/can_rotate = 1 + var/can_maximize_speed = 0 + var/one_person_only = 0 + +/obj/machinery/vehicle/pod + name = "Escape Pod" + icon = 'escapepod.dmi' + icon_state = "pod" + can_rotate = 0 + var/id = 1.0 + +/obj/machinery/vehicle/recon + name = "Reconaissance Pod" + icon = 'escapepod.dmi' + icon_state = "recon" + speed = 1.0 + maximum_speed = 30.0 + can_maximize_speed = 1 + one_person_only = 1 + +/obj/machinery/restruct + name = "DNA Physical Restructurization Accelerator" + icon = 'Cryogenic2.dmi' + icon_state = "restruct_0" + density = 1 + var/locked = 0.0 + var/mob/occupant = null + anchored = 1.0 + +/obj/machinery/scan_console + name = "DNA Scanner Access Console" + icon = 'computer.dmi' + icon_state = "scanner" + density = 1 + var/obj/item/weapon/card/data/scan = null + var/func = "" + var/data = "" + var/special = "" + var/status = null + var/prog_p1 = null + var/prog_p2 = null + var/prog_p3 = null + var/prog_p4 = null + var/temp = null + var/obj/machinery/dna_scanner/connected = null + anchored = 1.0 + +/obj/machinery/scan_consolenew + name = "DNA Modifier Access Console" + icon = 'computer.dmi' + icon_state = "scanner" + density = 1 + var/uniblock = 1.0 + var/strucblock = 1.0 + var/subblock = 1.0 + var/status = null + var/radduration = 2.0 + var/radstrength = 1.0 + var/radacc = 1.0 + var/buffer1 = null + var/buffer2 = null + var/buffer3 = null + var/buffer1owner = null + var/buffer2owner = null + var/buffer3owner = null + var/buffer1label = null + var/buffer2label = null + var/buffer3label = null + var/buffer1type = null + var/buffer2type = null + var/buffer3type = null + var/buffer1iue = 0 + var/buffer2iue = 0 + var/buffer3iue = 0 + var/delete = 0 + var/injectorready = 1 + var/temphtml = null + var/obj/machinery/dna_scanner/connected = null + var/obj/item/weapon/disk/data/diskette = null + anchored = 1.0 + +/obj/machinery/sec_lock + name = "Security Pad" + icon = 'stationobjs.dmi' + icon_state = "sec_lock" + var/obj/item/weapon/card/id/scan = null + var/a_type = 0.0 + var/obj/machinery/door/d1 = null + var/obj/machinery/door/d2 = null + anchored = 1.0 + req_access = list(access_brig) + +/obj/machinery/door_control + name = "Remote Door Control" + icon = 'stationobjs.dmi' + icon_state = "doorctrl0" + desc = "A remote control switch for a door." + var/id = null + anchored = 1.0 + +/obj/machinery/driver_button + name = "Mass Driver Button" + icon = 'objects.dmi' + icon_state = "launcherbtt" + desc = "A remote control switch for a Mass Driver." + var/id = null + var/active = 0 + anchored = 1.0 + +/obj/machinery/ignition_switch + name = "Ignition Switch" + icon = 'objects.dmi' + icon_state = "launcherbtt" + desc = "A remote control switch for a mounted igniter." + var/id = null + var/active = 0 + anchored = 1.0 + +/obj/machinery/shuttle + name = "shuttle" + icon = 'shuttle.dmi' + +/obj/machinery/shuttle/engine + name = "engine" + density = 1 + anchored = 1.0 + +/obj/machinery/shuttle/engine/heater + name = "heater" + icon_state = "heater" + +/obj/machinery/shuttle/engine/platform + name = "platform" + icon_state = "platform" + +/obj/machinery/shuttle/engine/propulsion + name = "propulsion" + icon_state = "propulsion" + opacity = 1 + +/obj/machinery/shuttle/engine/propulsion/burst + name = "burst" + +/obj/machinery/shuttle/engine/propulsion/burst/left + name = "left" + icon_state = "burst_l" + +/obj/machinery/shuttle/engine/propulsion/burst/right + name = "right" + icon_state = "burst_r" + +/obj/machinery/shuttle/engine/router + name = "router" + icon_state = "router" + +/obj/machinery/teleport + name = "teleport" + icon = 'stationobjs.dmi' + density = 1 + anchored = 1.0 + +/obj/machinery/teleport/hub + name = "hub" + icon_state = "tele0" + +/obj/machinery/teleport/station + name = "station" + icon_state = "controller" + var/active = 0 + var/engaged = 0 + +/obj/machinery/wire + name = "wire" + icon = 'power_cond.dmi' + + +/obj/machinery/power + name = null + icon = 'power.dmi' + anchored = 1.0 + var/datum/powernet/powernet = null + var/netnum = 0 + var/directwired = 1 // by default, power machines are connected by a cable in a neighbouring turf + // if set to 0, requires a 0-X cable on this turf + +/obj/machinery/power/terminal + name = "terminal" + icon_state = "term" + desc = "An underfloor wiring terminal for power equipment" + level = 1 + var/obj/machinery/power/master = null + anchored = 1 + directwired = 0 // must have a cable on same turf connecting to terminal + +/obj/machinery/power/generator + name = "generator" + desc = "A high efficiency thermoelectric generator." + icon_state = "teg" + anchored = 1 + density = 1 + + var/obj/machinery/atmospherics/binary/circulator/circ1 + var/obj/machinery/atmospherics/binary/circulator/circ2 + + var/lastgen = 0 + var/lastgenlev = -1 + +/obj/machinery/power/generator_type2 + name = "generator" + desc = "A high efficiency thermoelectric generator." + icon_state = "teg" + anchored = 1 + density = 1 + + var/obj/machinery/atmospherics/unary/generator_input/input1 + var/obj/machinery/atmospherics/unary/generator_input/input2 + + var/lastgen = 0 + var/lastgenlev = -1 + +/obj/machinery/power/monitor + name = "Power Monitoring Computer" + icon = 'computer.dmi' + icon_state = "power" + density = 1 + anchored = 1 + +#define SMESMAXCHARGELEVEL 200000 +#define SMESMAXOUTPUT 200000 + +/obj/machinery/power/smes/magical + name = "magical power storage unit" + desc = "A high-capacity superconducting magnetic energy storage (SMES) unit. Magically produces power." + process() + capacity = INFINITY + charge = INFINITY + ..() + +/obj/machinery/power/smes + name = "power storage unit" + desc = "A high-capacity superconducting magnetic energy storage (SMES) unit." + icon_state = "smes" + density = 1 + anchored = 1 + var/output = 30000 + var/lastout = 0 + var/loaddemand = 0 + var/capacity = 5e6 + var/charge = 1e6 + var/charging = 0 + var/chargemode = 0 + var/chargecount = 0 + var/chargelevel = 30000 + var/online = 1 + var/n_tag = null + var/obj/machinery/power/terminal/terminal = null + +/obj/machinery/power/solar + name = "solar panel" + desc = "A solar electrical generator." + icon = 'power.dmi' + icon_state = "sp_base" + anchored = 1 + density = 1 + directwired = 1 + var/health = 10.0 + var/id = 1 + var/obscured = 0 + var/sunfrac = 0 + var/adir = SOUTH + var/ndir = SOUTH + var/turn_angle = 0 + var/obj/machinery/power/solar_control/control + +/obj/machinery/power/solar_control + name = "solar panel control" + desc = "A controller for solar panel arrays." + icon = 'computer.dmi' + icon_state = "solar" + anchored = 1 + density = 1 + directwired = 1 + var/id = 1 + var/cdir = 0 + var/gen = 0 + var/lastgen = 0 + var/track = 2 // 0= off 1=timed 2=auto (tracker) + var/trackrate = 600 // 300-900 seconds + var/trackdir = 1 // 0 =CCW, 1=CW + var/nexttime = 0 + + + +/obj/machinery/cell_charger + name = "cell charger" + desc = "A charging unit for power cells." + icon = 'power.dmi' + icon_state = "ccharger0" + var/obj/item/weapon/cell/charging = null + var/chargelevel = -1 + anchored = 1 + +/obj/machinery/light_switch + desc = "A light switch" + name = null + icon = 'power.dmi' + icon_state = "light1" + anchored = 1.0 + var/on = 1 + var/area/area = null + var/otherarea = null + // luminosity = 1 + +/obj/machinery/crema_switch + desc = "Burn baby burn!" + name = "crematorium igniter" + icon = 'power.dmi' + icon_state = "crema_switch" + anchored = 1.0 + req_access = list(access_crematorium) + var/on = 0 + var/area/area = null + var/otherarea = null + var/id = 1 + + +/obj/machinery/vending + name = "Vendomat" + desc = "A generic vending machine." + icon = 'vending.dmi' + icon_state = "generic" + anchored = 1 + density = 1 + var/active = 1 //No sales pitches if off! + var/vend_ready = 1 //Are we ready to vend?? Is it time?? + var/vend_delay = 10 //How long does it take to vend? + var/product_paths = "" //String of product paths separated by semicolons. + var/product_amounts = "" //String of product amounts separated by semicolons, must have amount for every path in product_paths + var/product_slogans = "" //String of slogans separated by semicolons, optional + var/product_hidden = "" //String of products that are hidden unless hacked. + var/list/product_records = list() + var/list/hidden_records = list() + var/list/slogan_list = list() + var/vend_reply //Thank you for shopping! + var/last_reply = 0 + var/last_slogan = 0 //When did we last pitch? + var/slogan_delay = 600 //How long until we can pitch again? + var/icon_vend //Icon_state when vending! + var/icon_deny //Icon_state when vending! + var/emagged = 0 //Ignores if somebody doesn't have card access to that machine. + var/seconds_electrified = 0 //Shock customers like an airlock. + var/shoot_inventory = 0 //Fire items at customers! We're broken! + var/extended_inventory = 0 //can we access the hidden inventory? + var/panel_open = 0 //Hacking that vending machine. Gonna get a free candy bar. + var/wires = 15 + +/obj/machinery/vending/coffee + name = "coffee machine" + desc = "A Robust Coffee vending machine." + icon_state = "coffee" + icon_vend = "coffee-vend" + product_paths = "/obj/item/weapon/reagent_containers/food/drinks/coffee" + product_amounts = "25" + vend_delay = 34 + product_hidden = "/obj/item/weapon/reagent_containers/food/drinks/cola" + +/obj/machinery/vending/snack + name = "snack machine" + desc = "Just a placeholder until we get food figured out. :munch:" + icon_state = "snack" + product_paths = "/obj/item/weapon/reagent_containers/food/snacks/candy;/obj/item/weapon/reagent_containers/food/snacks/chips" + product_amounts = "10;10" + product_slogans = "Try our new nougat bar!;Twice the calories for half the price!" + product_hidden = "/obj/item/weapon/reagent_containers/food/snacks/donut" + +/obj/machinery/vending/cigarette + name = "cigarette machine" + desc = "If you want to get cancer, might as well do it in style" + icon_state = "cigs" + product_paths = "/obj/item/weapon/cigpacket" + product_amounts = "10" + product_slogans = "Space cigs taste good like a cigarette should.;I'd rather toolbox than switch.;Smoke!;Don't believe the reports - smoke today!" + vend_delay = 34 + product_hidden = "/obj/item/weapon/zippo" + +/obj/machinery/vending/medical + name = "NanoMed Plus" + desc = "Medical drug dispenser." + icon_state = "med" + icon_deny = "med-deny" + req_access_txt = "5" + product_paths = "/obj/item/weapon/reagent_containers/glass/bottle/antitoxin;/obj/item/weapon/reagent_containers/glass/bottle/inaprovaline;/obj/item/weapon/reagent_containers/glass/bottle/stoxin;/obj/item/weapon/reagent_containers/glass/bottle/toxin;/obj/item/weapon/reagent_containers/syringe/antiviral;/obj/item/weapon/reagent_containers/syringe" + product_amounts = "4;4;4;4;8;12" + product_hidden = "/obj/item/weapon/reagent_containers/pill/tox;/obj/item/device/healthanalyzer" + +/obj/machinery/vending/security + name = "SecTech" + desc = "A security equipment vendor" + icon_state = "sec" + icon_deny = "sec-deny" + req_access_txt = "1" + product_paths = "/obj/item/weapon/handcuffs;/obj/item/weapon/flashbang; /obj/item/device/flash" + product_amounts = "8;2;5" + //product_amounts = "8;5;4" Old totals + product_hidden = "/obj/item/clothing/head/helmet" + +/obj/machinery/vending/hydronutrients + name = "NutriMax" + desc = "A plant nutrients vendor" + icon_state = "nutri" + icon_deny = "nutri-deny" + product_paths = "/obj/item/nutrient/ez;/obj/item/nutrient/l4z;/obj/item/nutrient/rh" + product_amounts = "25;15;15" + product_slogans = "Aren't you glad you don't have to fertilize the natural way?;Now with 50% less stink!;Plants are people too!" + +/obj/machinery/microwave + name = "Microwave" + icon = 'kitchen.dmi' + icon_state = "mw" + density = 1 + anchored = 1 + var/egg_amount = 0 //Current number of eggs inside + var/flour_amount = 0 //Current amount of flour inside + var/water_amount = 0 //Current amount of water inside + var/monkeymeat_amount = 0 + var/humanmeat_amount = 0 + var/donkpocket_amount = 0 + var/xenomeat_amount = 0 + var/humanmeat_name = "" + var/humanmeat_job = "" + var/operating = 0 // Is it on? + var/dirty = 0 // Does it need cleaning? + var/broken = 0 // How broken is it??? + var/list/available_recipes = list() // List of the recipes you can use + var/obj/item/weapon/reagent_containers/food/snacks/being_cooked = null // The item being cooked + var/obj/item/extra_item // One non food item that can be added + +/obj/machinery/processor + name = "Food Processor" + icon = 'kitchen.dmi' + icon_state = "processor" + density = 1 + anchored = 1 + var/broken = 0 + +/obj/machinery/gibber + name = "Gibber" + desc = "The name isn't descriptive enough?" + icon = 'kitchen.dmi' + icon_state = "grinder" + density = 1 + anchored = 1 + var/operating = 0 //Is it on? + var/dirty = 0 // Does it need cleaning? + var/gibtime = 40 // Time from starting until meat appears + var/mob/occupant // Mob who has been put inside + diff --git a/code/defines/obj/nutrient.dm b/code/defines/obj/nutrient.dm new file mode 100644 index 0000000000000..39d9ac1cd3030 --- /dev/null +++ b/code/defines/obj/nutrient.dm @@ -0,0 +1,31 @@ +/obj/item/nutrient + name = "" + icon = 'chemical.dmi' + icon_state = "bottle16" + flags = FPRINT | TABLEPASS + var/mutmod = 0 + var/yieldmod = 0 + +/obj/item/nutrient/ez + name = "E-Z-Nutrient" + icon = 'chemical.dmi' + icon_state = "bottle16" + flags = FPRINT | TABLEPASS + mutmod = 1 + yieldmod = 1 + +/obj/item/nutrient/l4z + name = "Left 4 Zed" + icon = 'chemical.dmi' + icon_state = "bottle18" + flags = FPRINT | TABLEPASS + mutmod = 2 + yieldmod = 0 + +/obj/item/nutrient/rh + name = "Robust Harvest" + icon = 'chemical.dmi' + icon_state = "bottle15" + flags = FPRINT | TABLEPASS + mutmod = 0 + yieldmod = 2 \ No newline at end of file diff --git a/code/defines/obj/radio.dm b/code/defines/obj/radio.dm new file mode 100644 index 0000000000000..9228acefe17c5 --- /dev/null +++ b/code/defines/obj/radio.dm @@ -0,0 +1,88 @@ +/obj/item/device/radio + name = "station bounced radio" + suffix = "\[3\]" + icon_state = "walkietalkie" + item_state = "walkietalkie" + var/last_transmission + var/frequency = 1459 + var/secure_frequency + var/traitor_frequency = 0.0 + var/obj/item/device/radio/patch_link = null + var/obj/item/weapon/syndicate_uplink/traitorradio = null + var/wires = WIRE_SIGNAL | WIRE_RECEIVE | WIRE_TRANSMIT + var/b_stat = 0.0 + var/broadcasting = null + var/listening = 1.0 + var/freerange = 0 // 0 - Sanitize frequencies, 1 - Full range + flags = 450.0 + throw_speed = 2 + throw_range = 9 + w_class = 2.0 + var/const + WIRE_SIGNAL = 1 //sends a signal, like to set off a bomb or electrocute someone + WIRE_RECEIVE = 2 + WIRE_TRANSMIT = 4 + TRANSMISSION_DELAY = 5 // only 2/second/radio + +/obj/item/device/radio/beacon + name = "Tracking Beacon" + icon_state = "beacon" + item_state = "signaler" + var/code = "electronic" + +/obj/item/device/radio/electropack + name = "Electropack" + icon_state = "electropack0" + var/code = 2.0 + var/on = 0.0 + var/e_pads = 0.0 + frequency = 1449 + w_class = 5.0 + flags = 323.0 + item_state = "electropack" + +/obj/item/device/radio/headset + name = "Radio Headset" + icon_state = "headset" + item_state = "headset" + var/protective_temperature = 0 + +/obj/item/device/radio/headset/headset_sec // -- TLE + name = "Security Radio Headset" + icon_state = "sec_headset" + item_state = "headset" + secure_frequency = 1359 + +/obj/item/device/radio/headset/headset_eng // -- TLE + name = "Engineering Radio Headset" + icon_state = "eng_headset" + item_state = "headset" + secure_frequency = 1357 + +/obj/item/device/radio/headset/headset_med // -- TLE + name = "Medical Radio Headset" + icon_state = "med_headset" + item_state = "headset" + secure_frequency = 1355 + +/obj/item/device/radio/headset/headset_com // -- TLE + name = "Command Radio Headset" + icon_state = "com_headset" + item_state = "headset" + secure_frequency = 1353 + +/obj/item/device/radio/intercom + name = "Station Intercom (Radio)" + icon_state = "intercom" + anchored = 1.0 + var/number = 0 + +/obj/item/device/radio/signaler + name = "Remote Signaling Device" + icon_state = "signaller" + item_state = "signaler" + var/code = 30.0 + w_class = 1.0 + frequency = 1457 + var/delay = 0 + var/airlock_wire = null diff --git a/code/defines/obj/seeds.dm b/code/defines/obj/seeds.dm new file mode 100644 index 0000000000000..369d5aed0fbca --- /dev/null +++ b/code/defines/obj/seeds.dm @@ -0,0 +1,112 @@ +/obj/item/seeds + name = "seed" + icon = 'hydroponics.dmi' + icon_state = "seed" + flags = FPRINT | TABLEPASS + var/mypath = "/obj/item/seeds" + var/plantname = "" + var/productname = "" + var/species = "" + var/lifespan = 0 + var/endurance = 0 + var/maturation = 0 + var/production = 0 + var/yield = 0 + var/oneharvest = 0 + var/potency = -1 + +/obj/item/seeds/chiliseed + name = "chili plant seeds" + icon_state = "seed-chili" + mypath = "/obj/item/seeds/chiliseed" + species = "chili" + plantname = "chili plant" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/chili" + lifespan = 20 + endurance = 15 + maturation = 5 + production = 5 + yield = 4 + potency = 0 + +/obj/item/seeds/berryseed + name = "berry seeds" + icon_state = "seed-berry" + mypath = "/obj/item/seeds/berryseed" + species = "berry" + plantname = "berry bush" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/berries" + lifespan = 20 + endurance = 15 + maturation = 6 + production = 5 + yield = 1 + +/obj/item/seeds/eggplantseed + name = "eggplant seeds" + icon_state = "seed-eggplant" + mypath = "/obj/item/seeds/eggplantseed" + species = "eggplant" + plantname = "eggplant plant" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/eggplant" + lifespan = 25 + endurance = 15 + maturation = 6 + production = 6 + yield = 2 + +/obj/item/seeds/tomatoseed + name = "tomato seeds" + icon_state = "seed-tomato" + mypath = "/obj/item/seeds/tomatoseed" + species = "tomato" + plantname = "tomato plant" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/tomato" + lifespan = 25 + endurance = 15 + maturation = 6 + production = 6 + yield = 2 + +/obj/item/seeds/icepepperseed + name = "ice pepper seeds" + icon_state = "seed-icepepper" + mypath = "/obj/item/seeds/icepepperseed" + species = "chiliice" + plantname = "ice pepper plant" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/icepepper" + lifespan = 25 + endurance = 15 + maturation = 4 + production = 4 + yield = 4 + potency = 0 + +/obj/item/seeds/soyaseed + name = "soybean seeds" + icon_state = "seed-soybean" + mypath = "/obj/item/seeds/soyaseed" + species = "soybean" + plantname = "soybean plant" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/soybeans" + lifespan = 25 + endurance = 15 + maturation = 4 + production = 4 + yield = 3 + potency = 0 + +/obj/item/seeds/wheatseed + name = "wheat seeds" + icon_state = "seed-wheat" + mypath = "/obj/item/seeds/wheatseed" + species = "wheat" + plantname = "wheat stalks" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/wheat" + lifespan = 25 + endurance = 15 + maturation = 6 + production = 1 + yield = 4 + potency = 0 + oneharvest = 1 \ No newline at end of file diff --git a/code/defines/obj/spawner.dm b/code/defines/obj/spawner.dm new file mode 100644 index 0000000000000..9f484c738cd12 --- /dev/null +++ b/code/defines/obj/spawner.dm @@ -0,0 +1,3 @@ +/obj/spawner + name = "object spawner" + diff --git a/code/defines/obj/spawner/bomb.dm b/code/defines/obj/spawner/bomb.dm new file mode 100644 index 0000000000000..4715f7671eca3 --- /dev/null +++ b/code/defines/obj/spawner/bomb.dm @@ -0,0 +1,44 @@ +/obj/spawner/bomb + name = "bomb" + icon = 'screen1.dmi' + icon_state = "x" + var/btype = 0 //0 = radio, 1= prox, 2=time + var/explosive = 1 // 0= firebomb + var/btemp = 500 // bomb temperature (degC) + var/active = 0 + +/obj/spawner/bomb/radio + btype = 0 + +/obj/spawner/bomb/proximity + btype = 1 + +/obj/spawner/bomb/timer + btype = 2 + +/obj/spawner/bomb/timer/syndicate + btemp = 450 + +/obj/spawner/bomb/suicide + btype = 3 + +/obj/spawner/newbomb + name = "bomb" + icon = 'screen1.dmi' + icon_state = "x" + var/btype = 0 // 0=radio, 1=prox, 2=time + var/btemp1 = 1500 + var/btemp2 = 1000 // tank temperatures + + timer + btype = 2 + + syndicate + btemp1 = 150 + btemp2 = 20 + + proximity + btype = 1 + + radio + btype = 0 \ No newline at end of file diff --git a/code/defines/obj/storage.dm b/code/defines/obj/storage.dm new file mode 100644 index 0000000000000..a669003a09559 --- /dev/null +++ b/code/defines/obj/storage.dm @@ -0,0 +1,175 @@ +/obj/item/weapon/storage/utilitybelt + name = "utility belt" + desc = "Can hold various tools." + icon = 'old_or_unused.dmi' + icon_state = "utilitybelt" + item_state = "utility" + can_hold = list("/obj/item/weapon/crowbar","/obj/item/weapon/screwdriver","/obj/item/weapon/weldingtool","/obj/item/weapon/wirecutters","/obj/item/weapon/wrench","/obj/item/device/multitool","/obj/item/device/flashlight","/obj/item/weapon/cable_coil") + flags = FPRINT | TABLEPASS | ONBELT + +/obj/item/weapon/storage + icon = 'storage.dmi' + name = "storage" + var/list/can_hold = new/list() + var/obj/screen/storage/boxes = null + var/obj/screen/close/closer = null + w_class = 3.0 + +/obj/item/weapon/storage/backpack + name = "backpack" + icon_state = "backpack" + w_class = 4.0 + flags = 259.0 + +/obj/item/weapon/storage/pill_bottle + name = "Pill bottle" + icon_state = "pill_canister" + icon = 'chemical.dmi' + item_state = "contsolid" + can_hold = list("/obj/item/weapon/reagent_containers/pill") + +/obj/item/weapon/storage/box + name = "Box" + icon_state = "box" + item_state = "syringe_kit" + +/obj/item/weapon/storage/briefcase + name = "briefcase" + icon_state = "briefcase" + flags = FPRINT | TABLEPASS| CONDUCT + force = 8.0 + throw_speed = 1 + throw_range = 4 + w_class = 4.0 + +/obj/item/weapon/storage/disk_kit + name = "Data Disks" + icon_state = "id" + item_state = "syringe_kit" + +/obj/item/weapon/storage/disk_kit/disks + +/obj/item/weapon/storage/disk_kit/disks2 + +/obj/item/weapon/storage/fcard_kit + name = "Fingerprint Cards" + icon_state = "id" + item_state = "syringe_kit" + +/obj/item/weapon/storage/firstaid + name = "First-Aid" + icon_state = "firstaid" + throw_speed = 2 + throw_range = 8 +/obj/item/weapon/storage/firstaid/fire + name = "Fire First Aid" + icon_state = "ointment" + item_state = "firstaid-ointment" + +/obj/item/weapon/storage/firstaid/regular + icon_state = "firstaid" + +/obj/item/weapon/storage/firstaid/syringes + name = "Syringes (Biohazard Alert)" + icon_state = "syringe" + +/obj/item/weapon/storage/firstaid/toxin + name = "Toxin First Aid" + icon_state = "antitoxin" + item_state = "firstaid-toxin" + +/obj/item/weapon/storage/flashbang_kit + desc = "WARNING: Do not use without reading these preautions!\nThese devices are extremely dangerous and can cause blindness or deafness if used incorrectly.\nThe chemicals contained in these devices have been tuned for maximal effectiveness and due to\nextreme safety precuaiotn shave been incased in a tamper-proof pack. DO NOT ATTEMPT TO OPEN\nFLASH WARNING: Do not use continually. Excercise extreme care when detonating in closed spaces.\n\tMake attemtps not to detonate withing range of 2 meters of the intended target. It is imperative\n\tthat the targets visit a medical professional after usage. Damage to eyes increases extremely per\n\tuse and according to range. Glasses with flash resistant filters DO NOT always work on high powered\n\tflash devices such as this. EXERCISE CAUTION REGARDLESS OF CIRCUMSTANCES\nSOUND WARNING: Do not use continually. Visit a medical professional if hearing is lost.\n\tThere is a slight chance per use of complete deafness. Exercise caution and restraint.\nSTUN WARNING: If the intended or unintended target is too close to detonation the resulting sound\n\tand flash have been known to cause extreme sensory overload resulting in temporary\n\tincapacitation.\nDO NOT USE CONTINUALLY\nOperating Directions:\n\t1. Pull detonnation pin. ONCE THE PIN IS PULLED THE GRENADE CAN NOT BE DISARMED!\n\t2. Throw grenade. NEVER HOLD A LIVE FLASHBANG\n\t3. The grenade will detonste 10 seconds hafter being primed. EXCERCISE CAUTION\n\t-Never prime another grenade until after the first is detonated\nNote: Usage of this pyrotechnic device without authorization is an extreme offense and can\nresult in severe punishment upwards of 10 years in prison per use.\n\nDefault 3 second wait till from prime to detonation. This can be switched with a screwdriver\nto 10 seconds.\n\nCopyright of Nanotrasen Industries- Military Armnaments Division\nThis device was created by Nanotrasen Labs a member of the Expert Advisor Corporation" + name = "Flashbangs (WARNING)" + icon_state = "flashbang" + item_state = "syringe_kit" + +/obj/item/weapon/storage/emp_kit + desc = "A box with 5 emp grenades." + name = "Emp grenades" + icon_state = "flashbang" + item_state = "syringe_kit" + +/obj/item/weapon/storage/gl_kit + name = "Prescription Glasses" + icon_state = "id" + item_state = "syringe_kit" + +/obj/item/weapon/storage/handcuff_kit + name = "Spare Handcuffs" + icon_state = "handcuff" + item_state = "syringe_kit" + +/obj/item/weapon/storage/id_kit + name = "Spare IDs" + icon_state = "id" + item_state = "syringe_kit" + +/obj/item/weapon/storage/lglo_kit + name = "Latex Gloves" + icon_state = "latex" + item_state = "syringe_kit" + +/obj/item/weapon/storage/injectbox + name = "DNA-Injectors" + icon_state = "box" + item_state = "syringe_kit" + +/obj/item/weapon/storage/stma_kit + name = "Sterile Masks" + icon_state = "latex" + item_state = "syringe_kit" + +/obj/item/weapon/storage/trackimp_kit + name = "Tracking Implant Kit" + icon_state = "implant" + item_state = "syringe_kit" + + +/obj/item/weapon/storage/toolbox + name = "toolbox" + icon = 'storage.dmi' + icon_state = "red" + item_state = "toolbox_red" + flags = FPRINT | TABLEPASS| CONDUCT + force = 5.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 7 + w_class = 4.0 + +/obj/item/weapon/storage/toolbox/emergency + name = "emergency toolbox" + icon_state = "red" + item_state = "toolbox_red" + +/obj/item/weapon/storage/toolbox/mechanical + name = "mechanical toolbox" + icon_state = "blue" + item_state = "toolbox_blue" + +/obj/item/weapon/storage/toolbox/electrical + name = "electrical toolbox" + icon_state = "yellow" + item_state = "toolbox_yellow" + +/obj/item/weapon/storage/bible + name = "bible" + icon_state ="bible" + throw_speed = 1 + throw_range = 5 + w_class = 3.0 + flags = FPRINT | TABLEPASS + var/mob/affecting = null + +/obj/item/weapon/storage/mousetraps + name = "Pest-B-Gon Mousetraps" + desc = "WARNING: Keep out of reach of children." + icon_state = "mousetraps" + item_state = "syringe_kit" + +/obj/item/weapon/storage/donkpocket_kit + name = "Donk-Pockets" + desc = "Remember to fully heat prior to serving. Product will cool if not eaten within seven minutes." + icon_state = "donk_kit" + item_state = "syringe_kit" \ No newline at end of file diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm new file mode 100644 index 0000000000000..d7bc13cf49363 --- /dev/null +++ b/code/defines/obj/weapon.dm @@ -0,0 +1,1348 @@ +/obj/item/weapon + name = "weapon" + icon = 'weapons.dmi' + +/obj/item/weapon/rcd + name = "rapid-construction-device (RCD)" + desc = "A device used to rapidly build walls/floor." + icon = 'items.dmi' + icon_state = "rcd" + opacity = 0 + density = 0 + anchored = 0.0 + var/matter = 0 + var/working = 0 + var/mode = 1 + flags = FPRINT | TABLEPASS| CONDUCT + force = 10.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 5 + w_class = 3.0 + m_amt = 50000 + var/datum/effects/system/spark_spread/spark_system + +/obj/item/weapon/rcd_fake + name = "rapid-construction-device (RCD)" + desc = "A device used to rapidly build walls/floor." + icon = 'items.dmi' + icon_state = "rcd" + opacity = 0 + density = 0 + anchored = 0.0 + flags = FPRINT | TABLEPASS| CONDUCT + force = 10.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 5 + w_class = 3.0 + +/obj/item/weapon/rcd_ammo + name = "Compressed matter cartridge" + desc = "Highly compressed matter for the RCD." + icon = 'ammo.dmi' + icon_state = "rcd" + item_state = "rcdammo" + opacity = 0 + density = 0 + anchored = 0.0 + m_amt = 30000 + g_amt = 15000 + +/obj/item/weapon/spacecash + name = "Space Cash" + desc = "You're rich, bitch!" + icon = 'items.dmi' + icon_state = "spacecash" + opacity = 0 + density = 0 + anchored = 0.0 + force = 1.0 + throwforce = 1.0 + throw_speed = 1 + throw_range = 2 + w_class = 1.0 + +/obj/item/weapon/ammo + name = "ammo" + icon = 'ammo.dmi' + var/amount_left = 0.0 + flags = FPRINT | TABLEPASS| CONDUCT + item_state = "syringe_kit" + m_amt = 50000 + throwforce = 2 + w_class = 1.0 + throw_speed = 4 + throw_range = 20 + +/obj/item/weapon/ammo/a357 + desc = "There are 7 bullets left!" + name = "ammo-357" + icon_state = "357-7" + amount_left = 7.0 + +/obj/item/weapon/ammo/a38 + desc = "A speedloader that contains 7 .38 Special rounds." + name = "38-Special ammo" + icon_state = "38-7" + amount_left = 7.0 + +/obj/item/device/analyzer + desc = "A hand-held environmental scanner which reports current gas levels." + name = "analyzer" + icon_state = "atmos" + item_state = "analyzer" + w_class = 2.0 + flags = FPRINT | TABLEPASS| CONDUCT + throwforce = 5 + w_class = 2.0 + throw_speed = 4 + throw_range = 20 + + +/obj/item/weapon/axe + name = "Axe" + desc = "An energised battle axe." + icon_state = "axe0" + var/active = 0.0 + force = 40.0 + throwforce = 25.0 + throw_speed = 1 + throw_range = 5 + w_class = 3.0 + flags = FPRINT | CONDUCT | NOSHIELD | TABLEPASS + +/obj/item/weapon/banana + name = "Banana" + desc = "A banana." + icon = 'items.dmi' + icon_state = "banana" + item_state = "banana" + throwforce = 0 + w_class = 1.0 + throw_speed = 4 + throw_range = 20 + +/obj/item/weapon/bananapeel + name = "Banana Peel" + desc = "A peel from a banana." + icon = 'items.dmi' + icon_state = "banana_peel" + item_state = "banana_peel" + w_class = 1.0 + throwforce = 0 + throw_speed = 4 + throw_range = 20 + +/obj/item/weapon/baton + name = "Stun Baton" + desc = "A stun baton for hitting people with." + icon_state = "stunbaton" + item_state = "baton" + flags = FPRINT | ONBELT | TABLEPASS + force = 10 + throwforce = 7 + w_class = 3 + var/charges = 10.0 + var/maximum_charges = 10.0 + var/status = 1 + +/obj/item/weapon/bedsheet + name = "bedsheet" + icon = 'items.dmi' + icon_state = "sheet" + layer = 4.0 + item_state = "w_suit" + throwforce = 1 + w_class = 1.0 + throw_speed = 2 + throw_range = 10 + +/obj/item/weapon/bikehorn + name = "Bike Horn" + desc = "A horn off of a bicycle." + icon = 'items.dmi' + icon_state = "bike_horn" + item_state = "bike_horn" + throwforce = 3 + w_class = 1.0 + throw_speed = 3 + throw_range = 15 + var/spam_flag = 0 + +/obj/item/weapon/medical + name = "medical pack" + icon = 'items.dmi' + var/amount = 5 + w_class = 1 + throw_speed = 4 + throw_range = 20 + var/heal_brute = 0 + var/heal_burn = 0 + +/obj/item/weapon/medical/bruise_pack + name = "bruise pack" + desc = "A pack designed to treat blunt-force trauma." + icon_state = "brutepack" + heal_brute = 60 + +/obj/item/weapon/medical/ointment + name = "ointment" + icon_state = "ointment" + heal_burn = 40 + +/obj/item/weapon/c_tube + name = "cardboard tube" + icon = 'items.dmi' + icon_state = "c_tube" + throwforce = 1 + w_class = 1.0 + throw_speed = 4 + throw_range = 5 + +/obj/item/weapon/camera + name = "camera" + icon_state = "camera" + var/last_pic = 1.0 + item_state = "wrench" + w_class = 2.0 + +/obj/item/weapon/card + name = "card" + icon = 'card.dmi' + w_class = 1.0 + + var/list/files = list( ) + +/obj/item/weapon/card/data + name = "data disk" + icon_state = "data" + var/function = "storage" + var/data = "null" + var/special = null + item_state = "card-id" + +/obj/item/weapon/card/emag + desc = "It's a card with a magnetic strip attached to some circuitry." + name = "cryptographic sequencer" + icon_state = "emag" + item_state = "card-id" + +/obj/item/weapon/card/id + name = "identification card" + icon_state = "id" + item_state = "card-id" + var/access = list() + var/registered = null + var/assignment = null + +/obj/item/weapon/card/id/gold + name = "identification card" + icon_state = "gold" + item_state = "gold_id" + +/obj/item/weapon/card/id/syndicate + name = "agent card" + access = list(access_maint_tunnels) + +/obj/item/weapon/card/id/captains_spare + name = "Captain's spare ID" + icon_state = "gold" + item_state = "gold_id" + registered = "Captain" + assignment = "Captain" + New() + access = get_access("Captain") + ..() + +/obj/item/weapon/cleaner + desc = "Space Cleaner!" + icon = 'janitor.dmi' + name = "space cleaner" + icon_state = "cleaner" + item_state = "cleaner" + flags = ONBELT|TABLEPASS|OPENCONTAINER|FPRINT|USEDELAY|OPENCONTAINER + throwforce = 3 + w_class = 2.0 + throw_speed = 2 + throw_range = 10 + +/obj/item/weapon/clipboard + name = "clipboard" + icon = 'items.dmi' + icon_state = "clipboard00" + var/obj/item/weapon/pen/pen = null + item_state = "clipboard" + throwforce = 0 + w_class = 2.0 + throw_speed = 3 + throw_range = 10 + +/obj/item/weapon/cloaking_device + name = "cloaking device" + icon = 'device.dmi' + icon_state = "shield0" + var/active = 0.0 + flags = FPRINT | TABLEPASS| CONDUCT + item_state = "electronic" + throwforce = 10.0 + throw_speed = 2 + throw_range = 10 + w_class = 2.0 + +#define MAXCOIL 30 +/obj/item/weapon/cable_coil + name = "cable coil" + var/amount = MAXCOIL + icon = 'power.dmi' + icon_state = "coil" + desc = "A coil of power cable." + throwforce = 10 + w_class = 2.0 + throw_speed = 2 + throw_range = 5 + flags = TABLEPASS|USEDELAY|FPRINT|CONDUCT + item_state = "coil" + +/obj/item/weapon/cable_coil/cut + icon = 'power.dmi' + icon_state = "coil2" + +/obj/item/weapon/crowbar + name = "crowbar" + icon = 'items.dmi' + icon_state = "crowbar" + flags = FPRINT | TABLEPASS| CONDUCT + force = 5.0 + throwforce = 7.0 + item_state = "wrench" + w_class = 2.0 + m_amt = 50 + +/obj/item/weapon/disk + name = "disk" + icon = 'items.dmi' + +/obj/item/weapon/disk/nuclear + name = "Nuclear Authentication Disk" + icon_state = "nucleardisk" + item_state = "card-id" + w_class = 1.0 + +/obj/item/weapon/dummy + name = "dummy" + invisibility = 101.0 + anchored = 1.0 + flags = 2.0 + +/obj/item/weapon/extinguisher + name = "fire extinguisher" + icon = 'items.dmi' + icon_state = "fire_extinguisher0" + var/last_use = 1.0 + var/safety = 1 + hitsound = 'smash.ogg' + flags = FPRINT | USEDELAY | TABLEPASS | CONDUCT + throwforce = 10 + w_class = 3.0 + throw_speed = 2 + throw_range = 10 + force = 10.0 + item_state = "fire_extinguisher" + m_amt = 90 + +/obj/item/weapon/f_card + name = "Finger Print Card" + icon = 'card.dmi' + icon_state = "fingerprint0" + var/amount = 10.0 + item_state = "paper" + throwforce = 1 + w_class = 1.0 + throw_speed = 3 + throw_range = 5 + + +/obj/item/weapon/fcardholder + name = "Finger Print Case" + icon = 'items.dmi' + icon_state = "fcardholder0" + item_state = "clipboard" + + +/obj/item/weapon/flashbang + desc = "It is set to detonate in 3 seconds." + name = "flashbang" + icon = 'grenade.dmi' + icon_state = "flashbang" + var/state = null + var/det_time = 30.0 + w_class = 2.0 + item_state = "flashbang" + throw_speed = 4 + throw_range = 20 + flags = FPRINT | TABLEPASS | CONDUCT | ONBELT + +/obj/item/weapon/empgrenade + desc = "It is set to detonate in 5 seconds." + name = "emp grenade" + var/state = null + var/det_time = 50.0 + w_class = 2.0 + icon = 'device.dmi' + icon_state = "emp" + item_state = "emp" + throw_speed = 4 + throw_range = 20 + flags = FPRINT | TABLEPASS | CONDUCT | ONBELT + +/obj/item/weapon/flasks + name = "flask" + icon = 'Cryogenic2.dmi' + var/oxygen = 0.0 + var/plasma = 0.0 + var/coolant = 0.0 + +/obj/item/weapon/flasks/coolant + name = "light blue flask" + icon_state = "coolant-c" + coolant = 1000.0 + +/obj/item/weapon/flasks/oxygen + name = "blue flask" + icon_state = "oxygen-c" + oxygen = 500.0 + +/obj/item/weapon/flasks/plasma + name = "orange flask" + icon_state = "plasma-c" + plasma = 500.0 + + +/obj/item/weapon/game_kit + name = "Gaming Kit" + icon = 'items.dmi' + icon_state = "game_kit" + var/selected = null + var/board_stat = null + var/data = "" + var/base_url = "http://svn.slurm.us/public/spacestation13/misc/game_kit" + item_state = "sheet-metal" + w_class = 5.0 + +/obj/item/weapon/gift + name = "gift" + icon = 'items.dmi' + icon_state = "gift3" + var/size = 3.0 + var/obj/item/gift = null + item_state = "gift" + w_class = 4.0 + +/obj/item/weapon/grab + name = "grab" + icon = 'screen1.dmi' + icon_state = "grabbed" + var/obj/screen/grab/hud1 = null + var/mob/affecting = null + var/mob/assailant = null + var/state = 1.0 + var/killing = 0.0 + var/allow_upgrade = 1.0 + var/last_suffocate = 1.0 + layer = 21 + abstract = 1.0 + item_state = "nothing" + w_class = 5.0 + +/obj/item/weapon/gun + name = "gun" + icon = 'gun.dmi' + flags = FPRINT | TABLEPASS | CONDUCT | ONBELT | USEDELAY + item_state = "gun" + m_amt = 2000 + throwforce = 5 + w_class = 2.0 + throw_speed = 4 + throw_range = 10 + +/obj/item/weapon/gun/energy + name = "energy" + var/charges = 10.0 + var/maximum_charges = 10.0 + +/obj/item/weapon/gun/energy/taser_gun + name = "taser gun" + icon_state = "taser" + w_class = 3.0 + item_state = "gun" + force = 10.0 + throw_speed = 2 + throw_range = 10 + charges = 4 + maximum_charges = 4 + m_amt = 2000 + +/obj/item/weapon/gun/energy/teleport_gun + name = "teleport gun" + desc = "A hacked together combination of a taser and a handheld teleportation unit." + icon_state = "taser" + w_class = 3.0 + item_state = "gun" + force = 10.0 + throw_speed = 2 + throw_range = 10 + charges = 4 + maximum_charges = 4 + m_amt = 2000 + var/failchance = 5 + var/obj/item/target = null + +/obj/item/weapon/gun/energy/crossbow // Laaazy + name = "mini energy-crossbow" + desc = "A weapon favored by many of the syndicates stealth specialists." + icon_state = "crossbow" + w_class = 2.0 + item_state = "crossbow" + force = 4.0 + throw_speed = 2 + throw_range = 10 + charges = 3 + maximum_charges = 3 + m_amt = 2000 + +/obj/item/weapon/gun/energy/laser_gun + name = "laser gun" + icon_state = "laser" + w_class = 3.0 + throw_speed = 2 + throw_range = 10 + force = 7.0 + m_amt = 2000 + +/obj/item/weapon/gun/energy/laser_gun/captain + icon_state = "caplaser" + force = 10 + +/obj/item/weapon/gun/revolver + desc = "There are 0 bullets left. Uses 357" + name = "revolver" + icon_state = "revolver" + var/bullets = 0.0 + w_class = 3.0 + throw_speed = 2 + throw_range = 10 + force = 24.0 + m_amt = 2000 + +/obj/item/weapon/gun/detectiverevolver + desc = "A cheap Martian knock-off of a Smith & Wesson Model 10. Uses .38-Special rounds." + name = ".38 revolver" + icon_state = "detective" + var/bullets = 5.0 + w_class = 3.0 + throw_speed = 2 + throw_range = 10 + force = 14.0 + m_amt = 1000 + +/obj/item/weapon/hand_tele + name = "hand tele" + icon = 'device.dmi' + icon_state = "hand_tele" + item_state = "electronic" + throwforce = 5 + w_class = 2.0 + throw_speed = 3 + throw_range = 5 + m_amt = 10000 + +/obj/item/weapon/handcuffs + name = "handcuffs" + icon = 'items.dmi' + icon_state = "handcuff" + flags = FPRINT | TABLEPASS | CONDUCT | ONBELT + throwforce = 5 + w_class = 2.0 + throw_speed = 2 + throw_range = 5 + m_amt = 500 + + +/obj/item/weapon/implant + name = "implant" + var/implanted = null + var/color = "b" + +/obj/item/weapon/implant/freedom + name = "freedom" + var/uses = 1.0 + color = "r" + var/activation_emote = "chuckle" + +/obj/item/weapon/implant/tracking + name = "tracking" + var/frequency = 1451 + var/id = 1.0 + +/obj/item/weapon/implantcase + name = "Glass Case" + icon_state = "implantcase-0" + var/obj/item/weapon/implant/imp = null + item_state = "implantcase" + throw_speed = 1 + throw_range = 5 + w_class = 1.0 + +/obj/item/weapon/implantcase/tracking + name = "Glass Case- 'Tracking'" + icon = 'items.dmi' + icon_state = "implantcase-b" + +/obj/item/weapon/implanter + name = "implanter" + icon = 'items.dmi' + icon_state = "implanter0" + var/obj/item/weapon/implant/imp = null + item_state = "syringe_0" + throw_speed = 1 + throw_range = 5 + w_class = 2.0 + +/obj/item/weapon/implantpad + name = "implantpad" + icon = 'items.dmi' + icon_state = "implantpad-0" + var/obj/item/weapon/implantcase/case = null + var/broadcasting = null + var/listening = 1.0 + item_state = "electronic" + throw_speed = 1 + throw_range = 5 + w_class = 2.0 + + +/obj/item/weapon/locator + name = "locator" + icon = 'device.dmi' + icon_state = "locator" + var/temp = null + var/frequency = 1451 + var/broadcasting = null + var/listening = 1.0 + flags = FPRINT | TABLEPASS| CONDUCT + w_class = 2.0 + item_state = "electronic" + throw_speed = 4 + throw_range = 20 + m_amt = 400 + + + +/obj/item/weapon/mop + desc = "The world of janitalia wouldn't be complete without a mop." + name = "mop" + icon = 'janitor.dmi' + icon_state = "mop" + var/mopping = 0 + var/mopcount = 0 + force = 3.0 + throwforce = 10.0 + throw_speed = 5 + throw_range = 10 + w_class = 3.0 + flags = FPRINT | TABLEPASS + +/obj/item/weapon/caution + desc = "Caution! Wet Floor!" + name = "wet floor sign" + icon = 'janitor.dmi' + icon_state = "caution" + force = 1.0 + throwforce = 3.0 + throw_speed = 1 + throw_range = 5 + w_class = 3.0 + flags = FPRINT | TABLEPASS + + +/obj/item/weapon/paint + name = "Paint Can" + icon = 'old_or_unused.dmi' + icon_state = "paint_neutral" + var/color = "neutral" + item_state = "paintcan" + w_class = 3.0 + +/obj/item/weapon/paper + name = "Paper" + icon = 'items.dmi' + icon_state = "paper" + var/info = null + throwforce = 0 + w_class = 1.0 + throw_speed = 3 + throw_range = 15 + layer = 4 + var/see_face = 1 + var/body_parts_covered = HEAD + var/protective_temperature = T0C + 10 + var/heat_transfer_coefficient = 0.99 + var/gas_transfer_coefficient = 1 + var/permeability_coefficient = 0.99 + var/siemens_coefficient = 0.80 + +/obj/item/weapon/paper/Internal + name = "paper- 'Internal Atmosphere Operating Instructions'" + info = "Equipment:
    \n\t1+ Tank(s) with appropriate atmosphere
    \n\t1 Gas Mask w regulator (standard issue)
    \n
    \nProcedure:
    \n\t1. Wear mask
    \n\t2. Attach oxygen tank pipe to regulater (automatic))
    \n\t3. Set internal!
    \n
    \nNotes:
    \n\tDon't forget to stop internal when tank is low by
    \n\tremoving internal!
    \n
    \n\tDo not use a tank that has a high concentration of toxins.
    \n\tThe filters shut down on internal mode!
    \n
    \n\tWhen exiting a high danger environment it is advised
    \n\tthat you exit through a decontamination zone!
    \n
    \n\tRefill a tank at a oxygen canister by equiping the tank (Double Click)
    \n\tthen 'attacking' the canister (Double Click the canister)." + +/obj/item/weapon/paper/Court + name = "paper- 'Judgement'" + info = "For crimes against the station, the offender is sentenced to:
    \n
    \n" + +/obj/item/weapon/paper/Map + name = "paper- 'Station Blueprint'" + var/map_graphic = 'map.png' + info = {" +
    +CQ: Crew Quarters
    +L: Lounge
    +CH: Chapel
    +ENG: Engine Area
    +EC: Engine Control
    +ES: Engine Storage
    +GR: Generator Room
    +MB: Medical Bay
    +MR: Medical Research
    +TR: Toxin Research
    +TS: Toxin Storage
    +AC: Atmospheric Control
    +SEC: Security
    +SB: Shuttle Bay +SA: Shuttle Airlock
    +S: Storage
    +CR: Control Room
    +EV: EVA Storage
    +AE: Aux. Engine
    +P: Podbay
    +NA: North Airlock
    +SC: Solar Control
    +ASC: Aux. Solar Control
    +"} + +/obj/item/weapon/paper/Toxin + name = "paper- 'Chemical Information'" + info = "Known Onboard Toxins:
    \n\tGrade A Semi-Liquid Plasma:
    \n\t\tHighly poisonous. You cannot sustain concentrations above 15 units.
    \n\t\tA gas mask fails to filter plasma after 50 units.
    \n\t\tWill attempt to diffuse like a gas.
    \n\t\tFiltered by scrubbers.
    \n\t\tThere is a bottled version which is very different
    \n\t\t\tfrom the version found in canisters!
    \n
    \n\t\tWARNING: Highly Flammable. Keep away from heat sources
    \n\t\texcept in a enclosed fire area!
    \n\t\tWARNING: It is a crime to use this without authorization.
    \nKnown Onboard Anti-Toxin:
    \n\tAnti-Toxin Type 01P: Works against Grade A Plasma.
    \n\t\tBest if injected directly into bloodstream.
    \n\t\tA full injection is in every regular Med-Kit.
    \n\t\tSpecial toxin Kits hold around 7.
    \n
    \nKnown Onboard Chemicals (other):
    \n\tRejuvenation T#001:
    \n\t\tEven 1 unit injected directly into the bloodstream
    \n\t\t\twill cure paralysis and sleep toxins.
    \n\t\tIf administered to a dying patient it will prevent
    \n\t\t\tfurther damage for about units*3 seconds.
    \n\t\t\tit will not cure them or allow them to be cured.
    \n\t\tIt can be administeredd to a non-dying patient
    \n\t\t\tbut the chemicals disappear just as fast.
    \n\tSleep Toxin T#054:
    \n\t\t5 units wilkl induce precisely 1 minute of sleep.
    \n\t\t\tThe effects are cumulative.
    \n\t\tWARNING: It is a crime to use this without authorization" + +/obj/item/weapon/paper/courtroom + name = "paper- 'A Crash Course in Legal SOP on SS13'" + info = "Roles:
    \nThe Detective is basically the investigator and prosecutor.
    \nThe Staff Assistant can perform these functions with written authority from the Detective.
    \nThe Captain/HoP/Warden is ct as the judicial authority.
    \nThe Security Officers are responsible for executing warrants, security during trial, and prisoner transport.
    \n
    \nInvestigative Phase:
    \nAfter the crime has been committed the Detective's job is to gather evidence and try to ascertain not only who did it but what happened. He must take special care to catalogue everything and don't leave anything out. Write out all the evidence on paper. Make sure you take an appropriate number of fingerprints. IF he must ask someone questions he has permission to confront them. If the person refuses he can ask a judicial authority to write a subpoena for questioning. If again he fails to respond then that person is to be jailed as insubordinate and obstructing justice. Said person will be released after he cooperates.
    \n
    \nONCE the FT has a clear idea as to who the criminal is he is to write an arrest warrant on the piece of paper. IT MUST LIST THE CHARGES. The FT is to then go to the judicial authority and explain a small version of his case. If the case is moderately acceptable the authority should sign it. Security must then execute said warrant.
    \n
    \nPre-Pre-Trial Phase:
    \nNow a legal representative must be presented to the defendant if said defendant requests one. That person and the defendant are then to be given time to meet (in the jail IS ACCEPTABLE). The defendant and his lawyer are then to be given a copy of all the evidence that will be presented at trial (rewriting it all on paper is fine). THIS IS CALLED THE DISCOVERY PACK. With a few exceptions, THIS IS THE ONLY EVIDENCE BOTH SIDES MAY USE AT TRIAL. IF the prosecution will be seeking the death penalty it MUST be stated at this time. ALSO if the defense will be seeking not guilty by mental defect it must state this at this time to allow ample time for examination.
    \nNow at this time each side is to compile a list of witnesses. By default, the defendant is on both lists regardless of anything else. Also the defense and prosecution can compile more evidence beforehand BUT in order for it to be used the evidence MUST also be given to the other side.\nThe defense has time to compile motions against some evidence here.
    \nPossible Motions:
    \n1. Invalidate Evidence- Something with the evidence is wrong and the evidence is to be thrown out. This includes irrelevance or corrupt security.
    \n2. Free Movement- Basically the defendant is to be kept uncuffed before and during the trial.
    \n3. Subpoena Witness- If the defense presents god reasons for needing a witness but said person fails to cooperate then a subpoena is issued.
    \n4. Drop the Charges- Not enough evidence is there for a trial so the charges are to be dropped. The FT CAN RETRY but the judicial authority must carefully reexamine the new evidence.
    \n5. Declare Incompetent- Basically the defendant is insane. Once this is granted a medical official is to examine the patient. If he is indeed insane he is to be placed under care of the medical staff until he is deemed competent to stand trial.
    \n
    \nALL SIDES MOVE TO A COURTROOM
    \nPre-Trial Hearings:
    \nA judicial authority and the 2 sides are to meet in the trial room. NO ONE ELSE BESIDES A SECURITY DETAIL IS TO BE PRESENT. The defense submits a plea. If the plea is guilty then proceed directly to sentencing phase. Now the sides each present their motions to the judicial authority. He rules on them. Each side can debate each motion. Then the judicial authority gets a list of crew members. He first gets a chance to look at them all and pick out acceptable and available jurors. Those jurors are then called over. Each side can ask a few questions and dismiss jurors they find too biased. HOWEVER before dismissal the judicial authority MUST agree to the reasoning.
    \n
    \nThe Trial:
    \nThe trial has three phases.
    \n1. Opening Arguments- Each side can give a short speech. They may not present ANY evidence.
    \n2. Witness Calling/Evidence Presentation- The prosecution goes first and is able to call the witnesses on his approved list in any order. He can recall them if necessary. During the questioning the lawyer may use the evidence in the questions to help prove a point. After every witness the other side has a chance to cross-examine. After both sides are done questioning a witness the prosecution can present another or recall one (even the EXACT same one again!). After prosecution is done the defense can call witnesses. After the initial cases are presented both sides are free to call witnesses on either list.
    \nFINALLY once both sides are done calling witnesses we move onto the next phase.
    \n3. Closing Arguments- Same as opening.
    \nThe jury then deliberates IN PRIVATE. THEY MUST ALL AGREE on a verdict. REMEMBER: They mix between some charges being guilty and others not guilty (IE if you supposedly killed someone with a gun and you unfortunately picked up a gun without authorization then you CAN be found not guilty of murder BUT guilty of possession of illegal weaponry.). Once they have agreed they present their verdict. If unable to reach a verdict and feel they will never they call a deadlocked jury and we restart at Pre-Trial phase with an entirely new set of jurors.
    \n
    \nSentencing Phase:
    \nIf the death penalty was sought (you MUST have gone through a trial for death penalty) then skip to the second part.
    \nI. Each side can present more evidence/witnesses in any order. There is NO ban on emotional aspects or anything. The prosecution is to submit a suggested penalty. After all the sides are done then the judicial authority is to give a sentence.
    \nII. The jury stays and does the same thing as I. Their sole job is to determine if the death penalty is applicable. If NOT then the judge selects a sentence.
    \n
    \nTADA you're done. Security then executes the sentence and adds the applicable convictions to the person's record.
    \n" + +/obj/item/weapon/paper/flag + icon_state = "flag_neutral" + item_state = "paper" + anchored = 1.0 + +/obj/item/weapon/paper/jobs + name = "paper- 'Job Information'" + info = "Information on all formal jobs that can be assigned on Space Station 13 can be found on this document.
    \nThe data will be in the following form.
    \nGenerally lower ranking positions come first in this list.
    \n
    \nJob Name general access>lab access-engine access-systems access (atmosphere control)
    \n\tJob Description
    \nJob Duties (in no particular order)
    \nTips (where applicable)
    \n
    \nResearch Assistant 1>1-0-0
    \n\tThis is probably the lowest level position. Anyone who enters the space station after the initial job\nassignment will automatically receive this position. Access with this is restricted. Head of Personnel should\nappropriate the correct level of assistance.
    \n1. Assist the researchers.
    \n2. Clean up the labs.
    \n3. Prepare materials.
    \n
    \nStaff Assistant 2>0-0-0
    \n\tThis position assists the security officer in his duties. The staff assisstants should primarily br\npatrolling the ship waiting until they are needed to maintain ship safety.\n(Addendum: Updated/Elevated Security Protocols admit issuing of low level weapons to security personnel)
    \n1. Patrol ship/Guard key areas
    \n2. Assist security officer
    \n3. Perform other security duties.
    \n
    \nTechnical Assistant 1>0-0-1
    \n\tThis is yet another low level position. The technical assistant helps the engineer and the statian\ntechnician with the upkeep and maintenance of the station. This job is very important because it usually\ngets to be a heavy workload on station technician and these helpers will alleviate that.
    \n1. Assist Station technician and Engineers.
    \n2. Perform general maintenance of station.
    \n3. Prepare materials.
    \n
    \nMedical Assistant 1>1-0-0
    \n\tThis is the fourth position yet it is slightly less common. This position doesn't have much power\noutside of the med bay. Consider this position like a nurse who helps to upkeep medical records and the\nmaterials (filling syringes and checking vitals)
    \n1. Assist the medical personnel.
    \n2. Update medical files.
    \n3. Prepare materials for medical operations.
    \n
    \nResearch Technician 2>3-0-0
    \n\tThis job is primarily a step up from research assistant. These people generally do not get their own lab\nbut are more hands on in the experimentation process. At this level they are permitted to work as consultants to\nthe others formally.
    \n1. Inform superiors of research.
    \n2. Perform research alongside of official researchers.
    \n
    \nDetective 3>2-0-0
    \n\tThis job is in most cases slightly boring at best. Their sole duty is to\nperform investigations of crine scenes and analysis of the crime scene. This\nalleviates SOME of the burden from the security officer. This person's duty\nis to draw conclusions as to what happened and testify in court. Said person\nalso should stroe the evidence ly.
    \n1. Perform crime-scene investigations/draw conclusions.
    \n2. Store and catalogue evidence properly.
    \n3. Testify to superiors/inquieries on findings.
    \n
    \nStation Technician 2>0-2-3
    \n\tPeople assigned to this position must work to make sure all the systems aboard Space Station 13 are operable.\nThey should primarily work in the computer lab and repairing faulty equipment. They should work with the\natmospheric technician.
    \n1. Maintain SS13 systems.
    \n2. Repair equipment.
    \n
    \nAtmospheric Technician 3>0-0-4
    \n\tThese people should primarily work in the atmospheric control center and lab. They have the very important\njob of maintaining the delicate atmosphere on SS13.
    \n1. Maintain atmosphere on SS13
    \n2. Research atmospheres on the space station. (safely please!)
    \n
    \nEngineer 2>1-3-0
    \n\tPeople working as this should generally have detailed knowledge as to how the propulsion systems on SS13\nwork. They are one of the few classes that have unrestricted access to the engine area.
    \n1. Upkeep the engine.
    \n2. Prevent fires in the engine.
    \n3. Maintain a safe orbit.
    \n
    \nMedical Researcher 2>5-0-0
    \n\tThis position may need a little clarification. Their duty is to make sure that all experiments are safe and\nto conduct experiments that may help to improve the station. They will be generally idle until a new laboratory\nis constructed.
    \n1. Make sure the station is kept safe.
    \n2. Research medical properties of materials studied of Space Station 13.
    \n
    \nScientist 2>5-0-0
    \n\tThese people study the properties, particularly the toxic properties, of materials handled on SS13.\nTechnically they can also be called Plasma Technicians as plasma is the material they routinly handle.
    \n1. Research plasma
    \n2. Make sure all plasma is properly handled.
    \n
    \nMedical Doctor (Officer) 2>0-0-0
    \n\tPeople working this job should primarily stay in the medical area. They should make sure everyone goes to\nthe medical bay for treatment and examination. Also they should make sure that medical supplies are kept in\norder.
    \n1. Heal wounded people.
    \n2. Perform examinations of all personnel.
    \n3. Moniter usage of medical equipment.
    \n
    \nSecurity Officer 3>0-0-0
    \n\tThese people should attempt to keep the peace inside the station and make sure the station is kept safe. One\nside duty is to assist in repairing the station. They also work like general maintenance personnel. They are not\ngiven a weapon and must use their own resources.
    \n(Addendum: Updated/Elevated Security Protocols admit issuing of weapons to security personnel)
    \n1. Maintain order.
    \n2. Assist others.
    \n3. Repair structural problems.
    \n
    \nHead of Security 4>5-2-2
    \n\tPeople assigned as Head of Security should issue orders to the security staff. They should\nalso carefully moderate the usage of all security equipment. All security matters should be reported to this person.
    \n1. Oversee security.
    \n2. Assign patrol duties.
    \n3. Protect the station and staff.
    \n
    \nHead of Personnel 4>4-2-2
    \n\tPeople assigned as head of personnel will find themselves moderating all actions done by personnel. \nAlso they have the ability to assign jobs and access levels.
    \n1. Assign duties.
    \n2. Moderate personnel.
    \n3. Moderate research.
    \n
    \nCaptain 5>5-5-5 (unrestricted station wide access)
    \n\tThis is the highest position youi can aquire on Space Station 13. They are allowed anywhere inside the\nspace station and therefore should protect their ID card. They also have the ability to assign positions\nand access levels. They should not abuse their power.
    \n1. Assign all positions on SS13
    \n2. Inspect the station for any problems.
    \n3. Perform administrative duties.
    \n" + +/obj/item/weapon/paper/photograph + name = "photo" + icon_state = "photo" + var/photo_id = 0.0 + item_state = "paper" + +/obj/item/weapon/paper/sop + name = "paper- 'Standard Operating Procedure'" + info = "Alert Levels:
    \nBlue- Emergency
    \n\t1. Caused by fire
    \n\t2. Caused by manual interaction
    \n\tAction:
    \n\t\tClose all fire doors. These can only be opened by reseting the alarm
    \nRed- Ejection/Self Destruct
    \n\t1. Caused by module operating computer.
    \n\tAction:
    \n\t\tAfter the specified time the module will eject completely.
    \n
    \nEngine Maintenance Instructions:
    \n\tShut off ignition systems:
    \n\tActivate internal power
    \n\tActivate orbital balance matrix
    \n\tRemove volatile liquids from area
    \n\tWear a fire suit
    \n
    \n\tAfter
    \n\t\tDecontaminate
    \n\t\tVisit medical examiner
    \n
    \nToxin Laboratory Procedure:
    \n\tWear a gas mask regardless
    \n\tGet an oxygen tank.
    \n\tActivate internal atmosphere
    \n
    \n\tAfter
    \n\t\tDecontaminate
    \n\t\tVisit medical examiner
    \n
    \nDisaster Procedure:
    \n\tFire:
    \n\t\tActivate sector fire alarm.
    \n\t\tMove to a safe area.
    \n\t\tGet a fire suit
    \n\t\tAfter:
    \n\t\t\tAssess Damage
    \n\t\t\tRepair damages
    \n\t\t\tIf needed, Evacuate
    \n\tMeteor Shower:
    \n\t\tActivate fire alarm
    \n\t\tMove to the back of ship
    \n\t\tAfter
    \n\t\t\tRepair damage
    \n\t\t\tIf needed, Evacuate
    \n\tAccidental Reentry:
    \n\t\tActivate fire alrms in front of ship.
    \n\t\tMove volatile matter to a fire proof area!
    \n\t\tGet a fire suit.
    \n\t\tStay secure until an emergency ship arrives.
    \n
    \n\t\tIf ship does not arrive-
    \n\t\t\tEvacuate to a nearby safe area!" + +/obj/item/weapon/paper/engine + name = "paper- 'Generator Startup Procedure'" + info = {"Thermo-Electric Generator Startup Procedure for Mark I Plasma-Fired Engines +
    +Warning! Improper engine and generator operation may cause exposure to hazardous gasses, extremes of heat and cold, and dangerous electrical voltages.
    +Only trained personnel should operate station systems. Follow all procedures carefully. Wear correct personal protective equipment at all times.
    +Refer to your supervisor or Head of Personnel for procedure updates and additional information. +
    +Standard checklist for engine and generator cold-start.
    +
      +
    1. Perform visual inspection of external (cooling) and internal (heating) heat-exchange pipe loops. +Refer any breaks or cracks in the pipe to Station Maintenance for repair before continuing. +
    2. Connect a CO2 canister to the external (cooling) loop connector, and release the contents. Check loop pressurization is stable.
      +Note: Observe standard canister safety procedures.
      +Note: Other gasses may be substituted as a medium in the external (cooling) loop in the event that CO2 is not available. +
    3. Connect a CO2 canister to the internal (heating) loop connector, and release the contents. Check loop pressurization is stable.
      +Note: Observe standard canister safety procedures.
      +Note: Nitrogen may be substituted as a medium in the internal (heating) loop in the event that CO2 is not available. +Do not use plasma in the internal (heating) pipe loop as an unsafe condition may result. +
    4. Using the thermo-electric generator (TEG) master control panel, engage the internal and external loop circulator pumps at 1% maximum rate.
      +
    5. Ignite the engine. Refer to document NTRSN-113-H9-12939 for proper engine preparation, ignition, and plasma-oxygen loading procedures.
      +Note: Exceeding recommended plasma-oxygen concentrations can cause engine damage and potential hazards. +
    6. Monitor engine temperatures until stable operation is achieved. +
    7. Increase internal and external circulator pumps to 10% of maximum rate. Monitor the generated power output on the TEG control panel.
      +Note: Consult appendix A for expected electrical generation rates. +
    8. Adjust circulator rates until required electrical demand is met.
      +Note: Generation rate varies with internal and external loop temperatures, exchange media pressure, and engine geometry. Refer to Appendix B or your supervisor for locally determined optimal settings.
      +Note: Do not exceed safety ratings for station power cabling and electrical equipment. +
    9. With the power generation rate stable, engage charging of the superconducting magnetic energy storage (SMES) devices. +Total SMES charging rate should not exceed total power generation rate, or an overload condition may occur. +"} + +/obj/item/weapon/paper_bin + name = "Paper Bin" + icon = 'items.dmi' + icon_state = "paper_bin1" + var/amount = 30.0 + item_state = "sheet-metal" + throwforce = 1 + w_class = 3.0 + throw_speed = 3 + throw_range = 7 + +/obj/item/weapon/pen + desc = "It's a normal black ink pen." + name = "pen" + icon = 'items.dmi' + icon_state = "pen" + flags = FPRINT | ONBELT | TABLEPASS + throwforce = 0 + w_class = 1.0 + throw_speed = 7 + throw_range = 15 + m_amt = 60 + +/obj/item/weapon/pen/sleepypen + desc = "It's a normal black ink pen with a sharp point." + flags = FPRINT | ONBELT | TABLEPASS | OPENCONTAINER + +/obj/item/weapon/rack_parts + name = "rack parts" + icon = 'items.dmi' + icon_state = "rack_parts" + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/weapon/rods + name = "rods" + icon = 'items.dmi' + icon_state = "rods" + var/amount = 1.0 + flags = FPRINT | TABLEPASS| CONDUCT + w_class = 3.0 + force = 9.0 + throwforce = 15.0 + throw_speed = 5 + throw_range = 20 + m_amt = 1875 + +/obj/item/weapon/rubber_chicken + name = "Rubber Chicken" + desc = "A rubber chicken, isn't that hilarious?" + icon = 'items.dmi' + icon_state = "rubber_chicken" + item_state = "rubber_chicken" + w_class = 2.0 + +/obj/item/weapon/screwdriver + name = "screwdriver" + icon = 'items.dmi' + icon_state = "screwdriver" + flags = FPRINT | TABLEPASS| CONDUCT + force = 5.0 + w_class = 1.0 + throwforce = 5.0 + throw_speed = 3 + throw_range = 5 + +/obj/item/weapon/shard + name = "shard" + icon = 'shards.dmi' + icon_state = "large" + desc = "Could probably be used as ... a throwing weapon?" + w_class = 3.0 + force = 5.0 + throwforce = 15.0 + item_state = "shard-glass" + +/obj/item/weapon/sheet + name = "sheet" + icon = 'items.dmi' + var/amount = 1.0 + var/length = 2.5 + var/width = 1.5 + var/height = 0.01 + flags = FPRINT | TABLEPASS + throwforce = 5.0 + throw_speed = 1 + throw_range = 4 + w_class = 4.0 + +/obj/item/weapon/sheet/glass + name = "glass" + icon_state = "sheet-glass" + force = 5.0 + g_amt = 3750 + throwforce = 5 + w_class = 3.0 + throw_speed = 3 + throw_range = 3 + +/obj/item/weapon/sheet/rglass + name = "reinforced glass" + icon_state = "sheet-rglass" + item_state = "sheet-rglass" + force = 6.0 + g_amt = 3750 + m_amt = 1875 + throwforce = 5 + w_class = 3.0 + throw_speed = 3 + throw_range = 3 + +/obj/item/weapon/sheet/metal + name = "metal" + icon_state = "sheet-metal" + desc = "A heavy sheet of metal." + throwforce = 14.0 + m_amt = 3750 + throwforce = 10.0 + throw_speed = 1 + throw_range = 4 + w_class = 3.0 + flags = FPRINT | TABLEPASS | CONDUCT + +/obj/item/weapon/sheet/r_metal + name = "reinforced metal" + desc = "A very heavy sheet of metal." + icon_state = "sheet-r_metal" + force = 5.0 + throwforce = 14.0 + item_state = "sheet-metal" + m_amt = 7500 + throwforce = 15.0 + throw_speed = 1 + throw_range = 4 + w_class = 3.0 + flags = FPRINT | TABLEPASS | CONDUCT + + +/obj/item/weapon/syndicate_uplink + name = "station bounced radio" + icon = 'device.dmi' + icon_state = "radio" + var/temp = null + var/uses = 10.0 + var/selfdestruct = 0.0 + var/traitor_frequency = 0.0 + var/obj/item/device/radio/origradio = null + flags = FPRINT | TABLEPASS | CONDUCT | ONBELT + w_class = 2.0 + item_state = "radio" + throw_speed = 4 + throw_range = 20 + m_amt = 100 + +/obj/item/weapon/SWF_uplink + name = "station bounced radio" + icon = 'device.dmi' + icon_state = "radio" + var/temp = null + var/uses = 4.0 + var/selfdestruct = 0.0 + var/traitor_frequency = 0.0 + var/obj/item/device/radio/origradio = null + flags = FPRINT | TABLEPASS| CONDUCT | ONBELT + item_state = "radio" + throwforce = 5 + w_class = 2.0 + throw_speed = 4 + throw_range = 20 + m_amt = 100 + +/obj/item/weapon/staff + name = "wizards staff" + icon = 'wizard.dmi' + icon_state = "staff" + force = 3.0 + throwforce = 5.0 + throw_speed = 1 + throw_range = 5 + w_class = 2.0 + flags = FPRINT | TABLEPASS | NOSHIELD + +/obj/item/weapon/sword + name = "energy sword" + icon_state = "sword0" + var/active = 0.0 + force = 3.0 + throwforce = 5.0 + throw_speed = 1 + throw_range = 5 + w_class = 2.0 + flags = FPRINT | TABLEPASS | NOSHIELD + + +/obj/item/weapon/table_parts + name = "table parts" + icon = 'items.dmi' + icon_state = "table_parts" + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/weapon/table_parts/reinforced + name = "table parts" + icon = 'items.dmi' + icon_state = "reinf_tableparts" + flags = FPRINT | TABLEPASS| CONDUCT + +/obj/item/weapon/tank + name = "tank" + icon = 'tank.dmi' + + var/datum/gas_mixture/air_contents = null + var/distribute_pressure = ONE_ATMOSPHERE + flags = FPRINT | TABLEPASS | CONDUCT | ONBACK + + pressure_resistance = ONE_ATMOSPHERE*5 + + force = 5.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 4 + +/obj/item/weapon/tank/anesthetic + name = "Gas Tank (Sleeping Agent)" + icon_state = "anesthetic" + +/obj/item/weapon/tank/jetpack + name = "Jetpack (Oxygen)" + icon_state = "jetpack0" + var/on = 0.0 + w_class = 4.0 + item_state = "jetpack" + var/datum/effects/system/ion_trail_follow/ion_trail + +/obj/item/weapon/tank/oxygen + name = "Gas Tank (Oxygen)" + icon_state = "oxygen" + +/obj/item/weapon/tank/air + name = "Gas Tank (Air Mix)" + icon_state = "oxygen" + +/obj/item/weapon/tank/plasma + name = "Gas Tank (BIOHAZARD)" + icon_state = "plasma" + +/obj/item/weapon/tank/emergency_oxygen + name = "emergency oxygentank" + icon_state = "emergency" + flags = FPRINT | TABLEPASS | ONBELT | CONDUCT + w_class = 2.5 + force = 4.0 + +/obj/item/weapon/tile + name = "steel floor tile" + desc = "... Those could work as a pretty decent throwing weapon" + icon = 'items.dmi' + icon_state = "tile" + var/amount = 1.0 + w_class = 3.0 + throw_speed = 5 + throw_range = 20 + force = 6.0 + throwforce = 15.0 + + +/obj/item/weapon/teleportation_scroll + name = "Teleportation Scroll" + icon = 'items.dmi' + icon_state = "paper" + var/uses = 4.0 + flags = FPRINT | TABLEPASS + w_class = 2.0 + item_state = "paper" + throw_speed = 4 + throw_range = 20 + +/obj/item/weapon/weldingtool + name = "weldingtool" + icon = 'items.dmi' + icon_state = "welder" + var/welding = 0.0 + var/status = 0 //flamethrower construction :shobon: + flags = FPRINT | TABLEPASS| CONDUCT + force = 3.0 + throwforce = 5.0 + throw_speed = 1 + throw_range = 5 + w_class = 2.0 + m_amt = 30 + g_amt = 30 + +/obj/item/weapon/wire + desc = "This is just a simple piece of regular insulated wire." + name = "wire" + icon = 'power.dmi' + icon_state = "item_wire" + var/amount = 1.0 + var/laying = 0.0 + var/old_lay = null + m_amt = 40 + +/obj/item/weapon/wirecutters + name = "wirecutters" + icon = 'items.dmi' + icon_state = "cutters" + flags = FPRINT | TABLEPASS| CONDUCT + force = 6.0 + throw_speed = 2 + throw_range = 9 + w_class = 2.0 + m_amt = 80 + +/obj/item/weapon/wrapping_paper + name = "wrapping paper" + icon = 'items.dmi' + icon_state = "wrap_paper" + var/amount = 20.0 + +/obj/item/weapon/wrench + name = "wrench" + icon = 'items.dmi' + icon_state = "wrench" + flags = FPRINT | TABLEPASS| CONDUCT + force = 5.0 + throwforce = 7.0 + w_class = 2.0 + m_amt = 150 + +/obj/item/weapon/cell + name = "power cell" + desc = "A rechargable electrochemical power cell." + icon = 'power.dmi' + icon_state = "cell" + item_state = "cell" + flags = FPRINT|TABLEPASS + force = 5.0 + throwforce = 5.0 + throw_speed = 3 + throw_range = 5 + w_class = 3.0 + pressure_resistance = 80 + var/charge = 0 // note %age conveted to actual charge in New + var/maxcharge = 1000 + m_amt = 700 + var/rigged = 0 // true if rigged to explode + + +/obj/item/weapon/camera_bug/attack_self(mob/usr as mob) + var/list/cameras = new/list() + for (var/obj/machinery/camera/C in world) + if (C.bugged && C.status) + cameras.Add(C) + if (length(cameras) == 0) + usr << "\red No bugged functioning cameras found." + return + + var/list/friendly_cameras = new/list() + + for (var/obj/machinery/camera/C in cameras) + friendly_cameras.Add(C.c_tag) + + var/target = input("Select the camera to observe", null) as null|anything in friendly_cameras + if (!target) + return + for (var/obj/machinery/camera/C in cameras) + if (C.c_tag == target) + target = C + break + if (usr.stat == 2) return + + usr.client.eye = target + + +/obj/item/weapon/module + icon = 'module.dmi' + icon_state = "std_module" + w_class = 2.0 + item_state = "electronic" + flags = FPRINT|TABLEPASS|CONDUCT + var/mtype = 1 // 1=electronic 2=hardware + +/obj/item/weapon/module/card_reader + name = "card reader module" + icon_state = "card_mod" + desc = "An electronic module for reading data and ID cards." + +/obj/item/weapon/module/power_control + name = "power control module" + icon_state = "power_mod" + desc = "Heavy-duty switching circuits for power control." + +/obj/item/weapon/module/id_auth + name = "ID authentication module" + icon_state = "id_mod" + desc = "A module allowing secure authorization of ID cards." + +/obj/item/weapon/module/cell_power + name = "power cell regulator module" + icon_state = "power_mod" + desc = "A converter and regulator allowing the use of power cells." + +/obj/item/weapon/module/cell_power + name = "power cell charger module" + icon_state = "power_mod" + desc = "Charging circuits for power cells." + + +/obj/item/weapon/a_gift + name = "gift" + icon = 'items.dmi' + icon_state = "gift" + item_state = "gift" + pressure_resistance = 70 + + +/obj/item/weapon/camera_bug + name = "camera bug" + icon = 'device.dmi' + icon_state = "flash" + w_class = 1.0 + item_state = "electronic" + throw_speed = 4 + throw_range = 20 + + +/obj/item/weapon/kitchen + icon = 'kitchen.dmi' + +/obj/item/weapon/kitchen/rollingpin + name = "rolling pin" + icon_state = "rolling_pin" + force = 8.0 + throwforce = 10.0 + throw_speed = 2 + throw_range = 7 + w_class = 3.0 + +/obj/item/weapon/kitchen/utensil + force = 5.0 + w_class = 1.0 + throwforce = 5.0 + throw_speed = 3 + throw_range = 5 + flags = FPRINT | TABLEPASS | CONDUCT + + +/obj/item/weapon/kitchen/utensil/fork + name = "fork" + icon_state = "fork" + +/obj/item/weapon/kitchen/utensil/knife + name = "knife" + icon_state = "knife" + force = 10.0 + throwforce = 10.0 + +/obj/item/weapon/kitchen/utensil/spoon + name = "spoon" + desc = "SPOON!" + icon_state = "spoon" + +/obj/item/weapon/scalpel + name = "scalpel" + icon = 'surgery.dmi' + icon_state = "scalpel" + flags = FPRINT | TABLEPASS | CONDUCT + force = 10.0 + w_class = 1.0 + throwforce = 5.0 + throw_speed = 3 + throw_range = 5 + m_amt = 10000 + g_amt = 5000 + + +/obj/item/weapon/circular_saw + name = "circular saw" + icon = 'surgery.dmi' + icon_state = "saw1" + flags = FPRINT | TABLEPASS | CONDUCT + force = 15.0 + w_class = 1.0 + throwforce = 9.0 + throw_speed = 3 + throw_range = 5 + m_amt = 20000 + g_amt = 10000 + +/obj/item/weapon/stamp + desc = "A rubber stamp for stamping important documents." + name = "rubber stamp" + icon = 'items.dmi' + icon_state = "stamp-qm" + item_state = "stamp" + flags = FPRINT | TABLEPASS + throwforce = 0 + w_class = 1.0 + throw_speed = 7 + throw_range = 15 + m_amt = 60 + +/obj/item/weapon/cigpacket + name = "Cigarette packet" + desc = "The most popular brand of Space Cigarettes, sponsors of the Space Olympics." + icon = 'cigarettes.dmi' + icon_state = "cigpacket" + item_state = "cigpacket" + w_class = 1 + throwforce = 2 + var/cigcount = 6 + flags = ONBELT | TABLEPASS + +/obj/item/weapon/cigbutt + name = "Cigarette butt" + desc = "A manky old cigarette butt." + icon = 'cigarettes.dmi' + icon_state = "cigbutt" + w_class = 1 + throwforce = 1 + +/obj/item/weapon/zippo + name = "Zippo lighter" + desc = "The detective's zippo." + icon = 'items.dmi' + icon_state = "zippo" + item_state = "zippo" + w_class = 1 + throwforce = 4 + var/lit = 0 + flags = ONBELT | TABLEPASS | CONDUCT + + +/obj/item/weapon/mousetrap + name = "mousetrap" + desc = "A handy little spring-loaded trap for catching pesty rodents." + icon = 'weapons.dmi' + icon_state = "mousetrap" + item_state = "mousetrap" + w_class = 1 + force = null + throwforce = null + var/armed = 0 + +/obj/item/weapon/mousetrap/armed + icon_state = "mousetraparmed" + armed = 1 + +/obj/item/weapon/dice // -- TLE + name = "d6" + var/sides = 6 + icon_state = "dice" + item_state = "dice" + +/obj/item/weapon/dice/d20 // -- TLE + name = "d20" + sides = 20 + icon_state = "d20" + item_state = "dice" \ No newline at end of file diff --git a/code/defines/obj/window.dm b/code/defines/obj/window.dm new file mode 100644 index 0000000000000..ee36cd93a49d8 --- /dev/null +++ b/code/defines/obj/window.dm @@ -0,0 +1,74 @@ +/obj/window + name = "window" + icon = 'structures.dmi' + icon_state = "window" + desc = "A window." + density = 1 + var/health = 14.0 + var/ini_dir = null + var/state = 0 + var/reinf = 0 + pressure_resistance = 4*ONE_ATMOSPHERE + anchored = 1.0 + flags = ON_BORDER + +// Prefab windows to make it easy... + + + +// Basic + +/obj/window/basic/north + dir = NORTH + +/obj/window/basic/east + dir = NORTH + +/obj/window/basic/west + dir = WEST + +/obj/window/basic/south + dir = SOUTH + +/obj/window/basic/northwest + dir = NORTHWEST + +/obj/window/basic/northeast + dir = NORTHEAST + +/obj/window/basic/southwest + dir = SOUTHWEST + +/obj/window/basic/southeast + dir = SOUTHEAST + +// Reinforced + +/obj/window/reinforced + reinf = 1 + icon_state = "rwindow" + name = "reinforced window" + +/obj/window/reinforced/north + dir = NORTH + +/obj/window/reinforced/east + dir = EAST + +/obj/window/reinforced/west + dir = WEST + +/obj/window/reinforced/south + dir = SOUTH + +/obj/window/reinforced/northwest + dir = NORTHWEST + +/obj/window/reinforced/northeast + dir = NORTHEAST + +/obj/window/reinforced/southwest + dir = SOUTHWEST + +/obj/window/reinforced/southeast + dir = SOUTHEAST diff --git a/code/defines/procs/AStar.dm b/code/defines/procs/AStar.dm new file mode 100644 index 0000000000000..17d3dccc287df --- /dev/null +++ b/code/defines/procs/AStar.dm @@ -0,0 +1,184 @@ +/* +A Star pathfinding algorithm +Returns a list of tiles forming a path from A to B, taking dense objects as well as walls, and the orientation of +windows along the route into account. +Use: +your_list = AStar(start location, end location, adjacent turf proc, distance proc) +For the adjacent turf proc i wrote: +/turf/proc/AdjacentTurfs +And for the distance one i wrote: +/turf/proc/Distance +So an example use might be: + +src.path_list = AStar(src.loc, target.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance) + +Note: The path is returned starting at the END node, so i wrote reverselist to reverse it for ease of use. + +src.path_list = reverselist(src.pathlist) + +Then to start on the path, all you need to do it: +Step_to(src, src.path_list[1]) +src.path_list -= src.path_list[1] or equivilent to remove that node from the list. + +Optional extras to add on (in order): +MaxNodes: The maximum number of nodes the returned path can be (0 = infinite) +Maxnodedepth: The maximum number of nodes to search (default: 30, 0 = infinite) +Mintargetdist: Minimum distance to the target before path returns, could be used to get +near a target, but not right to it - for an AI mob with a gun, for example. +Minnodedist: Minimum number of nodes to return in the path, could be used to give a path a minimum +length to avoid portals or something i guess?? Not that they're counted right now but w/e. +*/ + +// Modified to provide ID argument - supplied to 'adjacent' proc, defaults to null +// Used for checking if route exists through a door which can be opened + +// Also added 'exclude' turf to avoid travelling over; defaults to null + + +PriorityQueue + var + L[] + cmp + New(compare) + L = new() + cmp = compare + proc + IsEmpty() + return !L.len + Enqueue(d) + var/i + var/j + L.Add(d) + i = L.len + j = i>>1 + while(i > 1 && call(cmp)(L[j],L[i]) > 0) + L.Swap(i,j) + i = j + j >>= 1 + + Dequeue() + ASSERT(L.len) + . = L[1] + Remove(1) + + Remove(i) + ASSERT(i <= L.len) + L.Swap(i,L.len) + L.Cut(L.len) + if(i < L.len) + _Fix(i) + _Fix(i) + var/child = i + i + var/item = L[i] + while(child <= L.len) + if(child + 1 <= L.len && call(cmp)(L[child],L[child + 1]) > 0) + child++ + if(call(cmp)(item,L[child]) > 0) + L[i] = L[child] + i = child + else + break + child = i + i + L[i] = item + List() + var/ret[] = new() + var/copy = L.Copy() + while(!IsEmpty()) + ret.Add(Dequeue()) + L = copy + return ret + RemoveItem(i) + var/ind = L.Find(i) + if(ind) + Remove(ind) +PathNode + var + datum/source + PathNode/prevNode + f + g + h + nt // Nodes traversed + New(s,p,pg,ph,pnt) + source = s + prevNode = p + g = pg + h = ph + f = g + h + source.bestF = f + nt = pnt + +datum + var + bestF +proc + PathWeightCompare(PathNode/a, PathNode/b) + return a.f - b.f + + AStar(start,end,adjacent,dist,maxnodes,maxnodedepth = 30,mintargetdist,minnodedist,id=null, var/turf/exclude=null) + +// world << "A*: [start] [end] [adjacent] [dist] [maxnodes] [maxnodedepth] [mintargetdist], [minnodedist] [id]" + var/PriorityQueue/open = new /PriorityQueue(/proc/PathWeightCompare) + var/closed[] = new() + var/path[] + + open.Enqueue(new /PathNode(start,null,0,call(start,dist)(end))) + + while(!open.IsEmpty() && !path) + { + var/PathNode/cur = open.Dequeue() + closed.Add(cur.source) + + var/closeenough + if(mintargetdist) + closeenough = call(cur.source,dist)(end) <= mintargetdist + + if(cur.source == end || closeenough) + path = new() + path.Add(cur.source) + while(cur.prevNode) + cur = cur.prevNode + path.Add(cur.source) + break + + var/L[] = call(cur.source,adjacent)(id) + if(minnodedist && maxnodedepth) + if(call(cur.source,minnodedist)(end) + cur.nt >= maxnodedepth) + continue + else if(maxnodedepth) + if(cur.nt >= maxnodedepth) + continue + + for(var/datum/d in L) + if(d == exclude) + continue + var/ng = cur.g + call(cur.source,dist)(d) + if(d.bestF) + if(ng + call(d,dist)(end) < d.bestF) + for(var/i = 1; i <= open.L.len; i++) + var/PathNode/n = open.L[i] + if(n.source == d) + open.Remove(i) + break + else + continue + + open.Enqueue(new /PathNode(d,cur,ng,call(d,dist)(end),cur.nt+1)) + if(maxnodes && open.L.len > maxnodes) + open.L.Cut(open.L.len) + } + + var/PathNode/temp + while(!open.IsEmpty()) + temp = open.Dequeue() + temp.source.bestF = 0 + while(closed.len) + temp = closed[closed.len] + temp.bestF = 0 + closed.Cut(closed.len) + + if(path) + for(var/i = 1; i <= path.len/2; i++) + path.Swap(i,path.len-i+1) + + return path diff --git a/code/defines/procs/church_name.dm b/code/defines/procs/church_name.dm new file mode 100644 index 0000000000000..0c8f1a6667b32 --- /dev/null +++ b/code/defines/procs/church_name.dm @@ -0,0 +1,16 @@ +var/church_name = null +/proc/church_name() + if (church_name) + return church_name + + var/name = "" + + name += pick("Holy", "United", "First", "Second", "Last") + + if (prob(20)) + name += " Space" + + name += " " + pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses") + name += " of [religion_name()]" + + return name diff --git a/code/defines/procs/command_alert.dm b/code/defines/procs/command_alert.dm new file mode 100644 index 0000000000000..5e9809592a7d4 --- /dev/null +++ b/code/defines/procs/command_alert.dm @@ -0,0 +1,9 @@ +/proc/command_alert(var/text, var/title = "") + world << "

      [command_name()] Update

      " + + if (title && length(title) > 0) + world << "

      [sanitize(title)]

      " + + world << "[sanitize(text)]" + world << "
      " + diff --git a/code/defines/procs/command_name.dm b/code/defines/procs/command_name.dm new file mode 100644 index 0000000000000..22ffee3ac8d54 --- /dev/null +++ b/code/defines/procs/command_name.dm @@ -0,0 +1,26 @@ +var/command_name = null +/proc/command_name() + if (command_name) + return command_name + + var/name = "" + + if (prob(10)) + name += pick("Super", "Ultra") + name += " " + + // Prefix + if (name) + name += pick("", "Central", "System", "Home") + else + name += pick("Central", "System", "Home") + if (name) + name += " " + + // Suffix + name += pick("Federation", "Command", "Alliance", "Unity", "Empire", "Confederation", "Protectorate", "Commonwealth", "Imperium", "Republic") + name += " " + + command_name = name + return name + diff --git a/code/defines/procs/dbcore.dm b/code/defines/procs/dbcore.dm new file mode 100644 index 0000000000000..8a032847bfa02 --- /dev/null +++ b/code/defines/procs/dbcore.dm @@ -0,0 +1,179 @@ +//cursors +#define Default_Cursor 0 +#define Client_Cursor 1 +#define Server_Cursor 2 + + +//conversions +#define TEXT_CONV 1 +#define RSC_FILE_CONV 2 +#define NUMBER_CONV 3 + + +//column flag values: +#define IS_NUMERIC 1 +#define IS_BINARY 2 +#define IS_NOT_NULL 4 +#define IS_PRIMARY_KEY 8 +#define IS_UNSIGNED 16 + + +//types +#define TINYINT 1 +#define SMALLINT 2 +#define MEDIUMINT 3 +#define INTEGER 4 +#define BIGINT 5 +#define DECIMAL 6 +#define FLOAT 7 +#define DOUBLE 8 +#define DATE 9 +#define DATETIME 10 +#define TIMESTAMP 11 +#define TIME 12 +#define STRING 13 +#define BLOB 14 +// TODO: Investigate more recent type additions and see if I can handle them. - Nadrew + + +var + DB_SERVER = "" // This is the location of your MySQL server (localhost is USUALLY fine) + DB_PORT = 3306 // This is the port your MySQL server is running on (3306 is the default) + +DBConnection + New(dbi_handler,username,password_handler,cursor_handler) + src.dbi = dbi_handler + src.user = username + src.password = password_handler + src.default_cursor = cursor_handler + _db_con = _dm_db_new_con() + proc + Connect(dbi_handler=src.dbi,user_handler=src.user,password_handler=src.password,cursor_handler) + if(!src) return 0 + cursor_handler = src.default_cursor + if(!cursor_handler) cursor_handler = Default_Cursor + return _dm_db_connect(_db_con,dbi_handler,user_handler,password_handler,cursor_handler,null) + + Disconnect() return _dm_db_close(_db_con) + + IsConnected() return _dm_db_is_connected(_db_con) + + Quote(str) return _dm_db_quote(_db_con,str) + + ErrorMsg() return _dm_db_error_msg(_db_con) + SelectDB(database_name,dbi) + if(IsConnected()) Disconnect() + return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[DB_SERVER]:[DB_PORT]"]",user,password) + NewQuery(sql_query,cursor_handler=src.default_cursor) return new/DBQuery(sql_query,src,cursor_handler) + + var + _db_con // This variable contains a reference to the actual database connection. + dbi // This variable is a string containing the DBI MySQL requires. + user // This variable contains the username data. + password // This variable contains the password data. + default_cursor // This contains the default database cursor data. + // + server = "" + port = 3306 + +DBQuery + New(sql_query,DBConnection/connection_handler,cursor_handler) + if(sql_query) src.sql = sql_query + if(connection_handler) src.db_connection = connection_handler + if(cursor_handler) src.default_cursor = cursor_handler + _db_query = _dm_db_new_query() + return ..() + + proc + + Connect(DBConnection/connection_handler) src.db_connection = connection_handler + + Execute(sql_query=src.sql,cursor_handler=default_cursor) + Close() + return _dm_db_execute(_db_query,sql_query,db_connection._db_con,cursor_handler,null) + + NextRow() return _dm_db_next_row(_db_query,item,conversions) + + RowsAffected() return _dm_db_rows_affected(_db_query) + + RowCount() return _dm_db_row_count(_db_query) + + ErrorMsg() return _dm_db_error_msg(_db_query) + + Columns() + if(!columns) + columns = _dm_db_columns(_db_query,/DBColumn) + return columns + + GetRowData() + var/list/columns = Columns() + var/list/results + if(columns.len) + results = list() + for(var/C in columns) + results+=C + var/DBColumn/cur_col = columns[C] + results[C] = src.item[(cur_col.position+1)] + return results + + Close() + item.len = 0 + columns = null + conversions = null + return _dm_db_close(_db_query) + + Quote(str) + return db_connection.Quote(str) + + SetConversion(column,conversion) + if(istext(column)) column = columns.Find(column) + if(!conversions) conversions = new/list(column) + else if(conversions.len < column) conversions.len = column + conversions[column] = conversion + + var + sql // The sql query being executed. + default_cursor + list/columns //list of DB Columns populated by Columns() + list/conversions + list/item[0] //list of data values populated by NextRow() + + DBConnection/db_connection + _db_query + +DBColumn + var + name + table + position //1-based index into item data + sql_type + flags + length + max_length + + New(name_handler,table_handler,position_handler,type_handler,flag_handler,length_handler,max_length_handler) + src.name = name_handler + src.table = table_handler + src.position = position_handler + src.sql_type = type_handler + src.flags = flag_handler + src.length = length_handler + src.max_length = max_length_handler + return ..() + + proc + SqlTypeName(type_handler=src.sql_type) + switch(type_handler) + if(TINYINT) return "TINYINT" + if(SMALLINT) return "SMALLINT" + if(MEDIUMINT) return "MEDIUMINT" + if(INTEGER) return "INTEGER" + if(BIGINT) return "BIGINT" + if(FLOAT) return "FLOAT" + if(DOUBLE) return "DOUBLE" + if(DATE) return "DATE" + if(DATETIME) return "DATETIME" + if(TIMESTAMP) return "TIMESTAMP" + if(TIME) return "TIME" + if(STRING) return "STRING" + if(BLOB) return "BLOB" \ No newline at end of file diff --git a/code/defines/procs/gamehelpers.dm b/code/defines/procs/gamehelpers.dm new file mode 100644 index 0000000000000..4288bb48dda45 --- /dev/null +++ b/code/defines/procs/gamehelpers.dm @@ -0,0 +1,83 @@ +/proc/dopage(src,target) + var/href_list + var/href + href_list = params2list("src=\ref[src]&[target]=1") + href = "src=\ref[src];[target]=1" + src:temphtml = null + src:Topic(href, href_list) + return null + +/proc/get_area(O) + var/location = O + var/i + for(i=1, i<=20, i++) + if(!isarea(location)) + location = location:loc + else + return location + return 0 + +/proc/get_area_name(N) //get area by it's name + + for(var/area/A in world) + if(A.name == N) + return A + return 0 + +/proc/in_range(source, user) + if(get_dist(source, user) <= 1) + return 1 + else + if (istype(user, /mob/living/carbon)) + if (user:mutations & 1) + var/X = source:x + var/Y = source:y + var/Z = source:z + spawn(0) + //I really shouldnt put this here but i dont have a better idea + var/obj/overlay/O = new /obj/overlay ( locate(X,Y,Z) ) + O.name = "sparkles" + O.anchored = 1 + O.density = 0 + O.layer = FLY_LAYER + O.dir = pick(cardinal) + O.icon = 'effects.dmi' + O.icon_state = "nothing" + flick("empdisable",O) + spawn(5) + del(O) + + + return 1 + + return 0 //not in range and not telekinetic + +/proc/circlerange(center=usr,radius=3) + + var/turf/centerturf = get_turf(center) + var/list/turfs = new/list() + var/rsq = radius * (radius+0.5) + + for(var/atom/T in range(radius, centerturf)) + var/dx = T.x - centerturf.x + var/dy = T.y - centerturf.y + if(dx*dx + dy*dy <= rsq) + turfs += T + + //turfs += centerturf + return turfs + +/proc/circleview(center=usr,radius=3) + + var/turf/centerturf = get_turf(center) + var/list/turfs = new/list() + var/rsq = radius * (radius+0.5) + + for(var/atom/T in view(radius, centerturf)) + var/dx = T.x - centerturf.x + var/dy = T.y - centerturf.y + if(dx*dx + dy*dy <= rsq) + turfs += T + + //turfs += centerturf + return turfs diff --git a/code/defines/procs/helpers.dm b/code/defines/procs/helpers.dm new file mode 100644 index 0000000000000..8d068eb41d75c --- /dev/null +++ b/code/defines/procs/helpers.dm @@ -0,0 +1,764 @@ +/proc/hex2num(hex) + + if (!( istext(hex) )) + CRASH("hex2num not given a hexadecimal string argument (user error)") + return + var/num = 0 + var/power = 0 + var/i = null + i = length(hex) + while(i > 0) + var/char = copytext(hex, i, i + 1) + switch(char) + if("0") + power++ + goto Label_290 + if("9", "8", "7", "6", "5", "4", "3", "2", "1") + num += text2num(char) * 16 ** power + if("a", "A") + num += 16 ** power * 10 + if("b", "B") + num += 16 ** power * 11 + if("c", "C") + num += 16 ** power * 12 + if("d", "D") + num += 16 ** power * 13 + if("e", "E") + num += 16 ** power * 14 + if("f", "F") + num += 16 ** power * 15 + else + CRASH("hex2num given non-hexadecimal string (user error)") + return + power++ + Label_290: + i-- + return num + +/proc/num2hex(num, placeholder) + + if (placeholder == null) + placeholder = 2 + if (!( isnum(num) )) + CRASH("num2hex not given a numeric argument (user error)") + return + if (!( num )) + return "0" + var/hex = "" + var/i = 0 + while(16 ** i < num) + i++ + var/power = null + power = i - 1 + while(power >= 0) + var/val = round(num / 16 ** power) + num -= val * 16 ** power + switch(val) + if(9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0) + hex += text("[]", val) + if(10.0) + hex += "A" + if(11.0) + hex += "B" + if(12.0) + hex += "C" + if(13.0) + hex += "D" + if(14.0) + hex += "E" + if(15.0) + hex += "F" + else + power-- + while(length(hex) < placeholder) + hex = text("0[]", hex) + return hex + +/proc/invertHTML(HTMLstring) + + if (!( istext(HTMLstring) )) + CRASH("Given non-text argument!") + return + else + if (length(HTMLstring) != 7) + CRASH("Given non-HTML argument!") + return + var/textr = copytext(HTMLstring, 2, 4) + var/textg = copytext(HTMLstring, 4, 6) + var/textb = copytext(HTMLstring, 6, 8) + var/r = hex2num(textr) + var/g = hex2num(textg) + var/b = hex2num(textb) + textr = num2hex(255 - r) + textg = num2hex(255 - g) + textb = num2hex(255 - b) + if (length(textr) < 2) + textr = text("0[]", textr) + if (length(textg) < 2) + textr = text("0[]", textg) + if (length(textb) < 2) + textr = text("0[]", textb) + return text("#[][][]", textr, textg, textb) + return + +/proc/shuffle(var/list/shufflelist) + if(!shufflelist) + return + var/list/new_list = list() + var/list/old_list = shufflelist.Copy() + while(old_list.len) + var/item = pick(old_list) + new_list += item + old_list -= item + return new_list + +/proc/uniquelist(var/list/L) + var/list/K = list() + for(var/item in L) + if(!(item in K)) + K += item + return K + +/proc/sanitize(var/t) + var/index = findtext(t, "\n") + while(index) + t = copytext(t, 1, index) + "#" + copytext(t, index+1) + index = findtext(t, "\n") + + index = findtext(t, "\t") + while(index) + t = copytext(t, 1, index) + "#" + copytext(t, index+1) + index = findtext(t, "\t") + + return html_encode(t) + +/proc/strip_html(var/t,var/limit=MAX_MESSAGE_LEN) + t = copytext(t,1,limit) + var/index = findtext(t, "<") + while(index) + t = copytext(t, 1, index) + copytext(t, index+1) + index = findtext(t, "<") + index = findtext(t, ">") + while(index) + t = copytext(t, 1, index) + copytext(t, index+1) + index = findtext(t, ">") + return sanitize(t) + +/proc/adminscrub(var/t,var/limit=MAX_MESSAGE_LEN) + t = copytext(t,1,limit) + var/index = findtext(t, "<") + while(index) + t = copytext(t, 1, index) + copytext(t, index+1) + index = findtext(t, "<") + index = findtext(t, ">") + while(index) + t = copytext(t, 1, index) + copytext(t, index+1) + index = findtext(t, ">") + return html_encode(t) + +/proc/add_zero(t, u) + while (length(t) < u) + t = "0[t]" + return t + +/proc/add_lspace(t, u) + while(length(t) < u) + t = " [t]" + return t + +/proc/add_tspace(t, u) + while(length(t) < u) + t = "[t] " + return t + +/proc/trim_left(text) + for (var/i = 1 to length(text)) + if (text2ascii(text, i) > 32) + return copytext(text, i) + return "" + +/proc/trim_right(text) + for (var/i = length(text), i > 0, i--) + if (text2ascii(text, i) > 32) + return copytext(text, 1, i + 1) + + return "" + +/proc/trim(text) + return trim_left(trim_right(text)) + +/proc/capitalize(var/t as text) + return uppertext(copytext(t, 1, 2)) + copytext(t, 2) + +/proc/sortList(var/list/L) + if(L.len < 2) + return L + var/middle = L.len / 2 + 1 // Copy is first,second-1 + return mergeLists(sortList(L.Copy(0,middle)), sortList(L.Copy(middle))) //second parameter null = to end of list + +/proc/sortNames(var/list/L) + var/list/Q = new() + for(var/atom/x in L) + Q[x.name] = x + return sortList(Q) + +/proc/mergeLists(var/list/L, var/list/R) + var/Li=1 + var/Ri=1 + var/list/result = new() + while(Li <= L.len && Ri <= R.len) + if(sorttext(L[Li], R[Ri]) < 1) + result += R[Ri++] + else + result += L[Li++] + + if(Li <= L.len) + return (result + L.Copy(Li, 0)) + return (result + R.Copy(Ri, 0)) + +/proc/dd_file2list(file_path, separator) + var/file + if(separator == null) + separator = "\n" + if(isfile(file_path)) + file = file_path + else + file = file(file_path) + return dd_text2list(file2text(file), separator) + +/proc/dd_range(var/low, var/high, var/num) + return max(low,min(high,num)) + +/proc/dd_replacetext(text, search_string, replacement_string) + var/textList = dd_text2list(text, search_string) + return dd_list2text(textList, replacement_string) + +/proc/dd_replaceText(text, search_string, replacement_string) + var/textList = dd_text2List(text, search_string) + return dd_list2text(textList, replacement_string) + +/proc/dd_hasprefix(text, prefix) + var/start = 1 + var/end = length(prefix) + 1 + return findtext(text, prefix, start, end) + +/proc/dd_hasPrefix(text, prefix) + var/start = 1 + var/end = length(prefix) + 1 + return findtext(text, prefix, start, end) //was findtextEx + +/proc/dd_hassuffix(text, suffix) + var/start = length(text) - length(suffix) + if(start) + return findtext(text, suffix, start, null) + return + +/proc/dd_hasSuffix(text, suffix) + var/start = length(text) - length(suffix) + if(start) + return findtext(text, suffix, start, null) //was findtextEx + +/proc/dd_text2list(text, separator, var/list/withinList) + var/textlength = length(text) + var/separatorlength = length(separator) + if(withinList && !withinList.len) withinList = null + var/list/textList = new() + var/searchPosition = 1 + var/findPosition = 1 + while(1) + findPosition = findtext(text, separator, searchPosition, 0) + var/buggyText = copytext(text, searchPosition, findPosition) + if(!withinList || (buggyText in withinList)) textList += "[buggyText]" + if(!findPosition) return textList + searchPosition = findPosition + separatorlength + if(searchPosition > textlength) + textList += "" + return textList + return + +/proc/dd_text2List(text, separator, var/list/withinList) + var/textlength = length(text) + var/separatorlength = length(separator) + if(withinList && !withinList.len) withinList = null + var/list/textList = new() + var/searchPosition = 1 + var/findPosition = 1 + while(1) + findPosition = findtext(text, separator, searchPosition, 0) //was findtextEx + var/buggyText = copytext(text, searchPosition, findPosition) + if(!withinList || (buggyText in withinList)) textList += "[buggyText]" + if(!findPosition) return textList + searchPosition = findPosition + separatorlength + if(searchPosition > textlength) + textList += "" + return textList + return + +/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 + +/proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "," ) + var/total = input.len + if (!total) + return "[nothing_text]" + else if (total == 1) + return "[input[1]]" + else if (total == 2) + return "[input[1]][and_text][input[2]]" + else + var/output = "" + var/index = 1 + while (index < total) + if (index == total - 1) + comma_text = final_comma_text + + output += "[input[index]][comma_text]" + index++ + + return "[output][and_text][input[index]]" + +/proc/dd_centertext(message, length) + var/new_message = message + var/size = length(message) + var/delta = length - size + if(size == length) + return new_message + if(size > length) + return copytext(new_message, 1, length + 1) + if(delta == 1) + return new_message + " " + if(delta % 2) + new_message = " " + new_message + delta-- + var/spaces = add_lspace("",delta/2-1) + return spaces + new_message + spaces + +/proc/dd_limittext(message, length) + var/size = length(message) + if(size <= length) + return message + return copytext(message, 1, length + 1) + +/proc/angle2dir(var/degree) + degree = ((degree+22.5)%365) + if(degree < 45) return NORTH + if(degree < 90) return NORTH|EAST + if(degree < 135) return EAST + if(degree < 180) return SOUTH|EAST + if(degree < 225) return SOUTH + if(degree < 270) return SOUTH|WEST + if(degree < 315) return WEST + return NORTH|WEST + +/proc/angle2text(var/degree) + return dir2text(angle2dir(degree)) + +/proc/text_input(var/Message, var/Title, var/Default, var/length=MAX_MESSAGE_LEN) + return sanitize(input(Message, Title, Default) as text, length) + +/proc/scrub_input(var/Message, var/Title, var/Default, var/length=MAX_MESSAGE_LEN) + return strip_html(input(Message,Title,Default) as text, length) + +/proc/InRange(var/A, var/lower, var/upper) + if(A < lower) return 0 + if(A > upper) return 0 + return 1 + +/proc/LinkBlocked(turf/A, turf/B) + if(A == null || B == null) return 1 + var/adir = get_dir(A,B) + var/rdir = get_dir(B,A) + if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal + var/iStep = get_step(A,adir&(NORTH|SOUTH)) + if(!LinkBlocked(A,iStep) && !LinkBlocked(iStep,B)) return 0 + + var/pStep = get_step(A,adir&(EAST|WEST)) + if(!LinkBlocked(A,pStep) && !LinkBlocked(pStep,B)) return 0 + return 1 + + if(DirBlocked(A,adir)) return 1 + if(DirBlocked(B,rdir)) return 1 + return 0 + + +/proc/DirBlocked(turf/loc,var/dir) + for(var/obj/window/D in loc) + if(!D.density) continue + if(D.dir == SOUTHWEST) return 1 + if(D.dir == dir) return 1 + + for(var/obj/machinery/door/D in loc) + if(!D.density) continue + if(istype(D, /obj/machinery/door/window)) + if((dir & SOUTH) && (D.dir & (EAST|WEST))) return 1 + if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return 1 + else return 1 // it's a real, air blocking door + return 0 + +/proc/TurfBlockedNonWindow(turf/loc) + for(var/obj/O in loc) + if(O.density && !istype(O, /obj/window)) + return 1 + return 0 + +/proc/sign(x) //Should get bonus points for being the most compact code in the world! + return x!=0?x/abs(x):0 //((x<0)?-1:((x>0)?1:0)) + +/* //Kelson's version (doesn't work) +/proc/getline(atom/M,atom/N) + if(!M || !M.loc) return + if(!N || !N.loc) return + if(M.z != N.z) return + var/line = new/list() + + var/dx = abs(M.x - N.x) + var/dy = abs(M.y - N.y) + var/cx = M.x < N.x ? 1 : -1 + var/cy = M.y < N.y ? 1 : -1 + var/slope = dy ? dx/dy : INFINITY + + var/tslope = slope + var/turf/tloc = M.loc + + while(tloc != N.loc) + if(tslope>0) + --tslope + tloc = locate(tloc.x+cx,tloc.y,tloc.z) + else + tslope += slope + tloc = locate(tloc.x,tloc.y+cy,tloc.z) + line += tloc + return line +*/ + +/proc/getline(atom/M,atom/N)//Ultra-Fast Bresenham Line-Drawing Algorithm + var/px=M.x //starting x + var/py=M.y + var/line[] = list(locate(px,py,M.z)) + var/dx=N.x-px //x distance + var/dy=N.y-py + var/dxabs=abs(dx)//Absolute value of x distance + var/dyabs=abs(dy) + var/sdx=sign(dx) //Sign of x distance (+ or -) + var/sdy=sign(dy) + var/x=dxabs>>1 //Counters for steps taken, setting to distance/2 + var/y=dyabs>>1 //Bit-shifting makes me l33t. It also makes getline() unnessecarrily fast. + var/j //Generic integer for counting + if(dxabs>=dyabs) //x distance is greater than y + for(j=0;j=dxabs) //Every dyabs steps, step once in y direction + y-=dxabs + py+=sdy + px+=sdx //Step on in x direction + line+=locate(px,py,M.z)//Add the turf to the list + else + for(j=0;j=dyabs) + x-=dyabs + px+=sdx + py+=sdy + line+=locate(px,py,M.z) + return line + +/proc/IsGuestKey(key) + if (findtext(key, "Guest-", 1, 7) != 1) //was findtextEx + return 0 + + var/i, ch, len = length(key) + + for (i = 7, i <= len, ++i) + ch = text2ascii(key, i) + if (ch < 48 || ch > 57) + return 0 + + return 1 + +/proc/pickweight(list/L) + var/total = 0 + var/item + for (item in L) + if (!L[item]) + L[item] = 1 + total += L[item] + + total = rand(1, total) + for (item in L) + total -=L [item] + if (total <= 0) + return item + + return null + +/proc/sanitize_frequency(var/f) + f = round(f) + f = max(1441, f) // 144.1 + f = min(1489, f) // 148.9 + if ((f % 2) == 0) + f += 1 + return f + +/proc/format_frequency(var/f) + return "[round(f / 10)].[f % 10]" + +/proc/getmobs() + + var/list/mobs = sortmobs() + var/list/names = list() + var/list/creatures = list() + var/list/namecounts = list() + for(var/mob/M in mobs) + var/name = M.name + if (name in names) + namecounts[name]++ + name = "[name] ([namecounts[name]])" + else + names.Add(name) + namecounts[name] = 1 + if (M.real_name && M.real_name != M.name) + name += " \[[M.real_name]\]" + if (M.stat == 2) + if(istype(M, /mob/dead/observer/)) + name += " \[ghost\]" + else + name += " \[dead\]" + creatures[name] = M + + return creatures + +/proc/sortmobs() + + var/list/mob_list = list() + for(var/mob/living/silicon/ai/M in world) + mob_list.Add(M) + for(var/mob/living/silicon/robot/M in world) + mob_list.Add(M) + for(var/mob/living/carbon/human/M in world) + mob_list.Add(M) + for(var/mob/living/carbon/alien/M in world) + mob_list.Add(M) + for(var/mob/dead/observer/M in world) + mob_list.Add(M) + for(var/mob/new_player/M in world) + mob_list.Add(M) + for(var/mob/living/carbon/monkey/M in world) + mob_list.Add(M) + for(var/mob/living/silicon/hivebot/M in world) + mob_list.Add(M) + for(var/mob/living/silicon/hive_mainframe/M in world) + mob_list.Add(M) + return mob_list + +/proc/convert2energy(var/M) + var/E = M*(SPEED_OF_LIGHT_SQ) + return E + +/proc/convert2mass(var/E) + var/M = E/(SPEED_OF_LIGHT_SQ) + return M + +/proc/modulus(var/M) + if(M >= 0) + return M + if(M < 0) + return -M + + +/proc/key_name(var/whom, var/include_link = null, var/include_name = 1) + var/mob/the_mob = null + var/client/the_client = null + var/the_key = "" + + if (isnull(whom)) + return "*null*" + else if (istype(whom, /client)) + the_client = whom + the_mob = the_client.mob + the_key = the_client.key + else if (ismob(whom)) + the_mob = whom + the_client = the_mob.client + the_key = the_mob.key + else if (istype(whom, /datum)) + var/datum/the_datum = whom + return "*invalid:[the_datum.type]*" + else + return "*invalid*" + + var/text = "" + + if (!the_key) + text += "*no client*" + else + if (include_link && !isnull(the_mob)) + if (istext(include_link)) + text += "" + else + text += "" + + if (the_client && the_client.holder && the_client.stealth && !include_name) + text += "Administrator" + else + text += "[the_key]" + + if (!isnull(include_link) && !isnull(the_mob)) + text += "" + + if (include_name && !isnull(the_mob)) + if (the_mob.real_name) + text += "/([the_mob.real_name])" + else if (the_mob.name) + text += "/([the_mob.name])" + + return text + +/proc/key_name_admin(var/whom, var/include_name = 1) + return key_name(whom, "%admin_ref%", include_name) + + +// Registers the on-close verb for a browse window (client/verb/.windowclose) +// this will be called when the close-button of a window is pressed. +// +// This is usually only needed for devices that regularly update the browse window, +// e.g. canisters, timers, etc. +// +// windowid should be the specified window name +// e.g. code is : user << browse(text, "window=fred") +// then use : onclose(user, "fred") +// +// Optionally, specify the "ref" parameter as the controlled atom (usually src) +// to pass a "close=1" parameter to the atom's Topic() proc for special handling. +// Otherwise, the user mob's machine var will be reset directly. +// +/proc/onclose(mob/user, windowid, var/atom/ref=null) + + var/param = "null" + if(ref) + param = "\ref[ref]" + + winset(user, windowid, "on-close=\".windowclose [param]\"") + + //world << "OnClose [user]: [windowid] : ["on-close=\".windowclose [param]\""]" + + +// the on-close client verb +// called when a browser popup window is closed after registering with proc/onclose() +// if a valid atom reference is supplied, call the atom's Topic() with "close=1" +// otherwise, just reset the client mob's machine var. +// +/client/verb/windowclose(var/atomref as text) + set hidden = 1 // hide this verb from the user's panel + set name = ".windowclose" // no autocomplete on cmd line + + //world << "windowclose: [atomref]" + if(atomref!="null") // if passed a real atomref + var/hsrc = locate(atomref) // find the reffed atom + var/href = "close=1" + if(hsrc) + //world << "[src] Topic [href] [hsrc]" + usr = src.mob + src.Topic(href, params2list(href), hsrc) // this will direct to the atom's + return // Topic() proc via client.Topic() + + // no atomref specified (or not found) + // so just reset the user mob's machine var + if(src && src.mob) + //world << "[src] was [src.mob.machine], setting to null" + src.mob.machine = null + return + +/proc/reverselist(var/list/input) + var/list/output = new/list() + for(var/A in input) + output += A + return output + +/proc/get_turf_loc(var/mob/M) //gets the location of the turf that the mob is on, or what the mob is in is on, etc + //in case they're in a closet or sleeper or something + var/atom/loc = M.loc + while(!istype(loc, /turf/)) + loc = loc.loc + return loc + +// returns the turf located at the map edge in the specified direction relative to A +// used for mass driver +/proc/get_edge_target_turf(var/atom/A, var/direction) + + var/turf/target = locate(A.x, A.y, A.z) + //since NORTHEAST == NORTH & EAST, etc, doing it this way allows for diagonal mass drivers in the future + //and isn't really any more complicated + + // Note diagonal directions won't usually be accurate + if(direction & NORTH) + target = locate(target.x, world.maxy, target.z) + if(direction & SOUTH) + target = locate(target.x, 1, target.z) + if(direction & EAST) + target = locate(world.maxx, target.y, target.z) + if(direction & WEST) + target = locate(1, target.y, target.z) + + return target + +// returns turf relative to A in given direction at set range +// result is bounded to map size +// note range is non-pythagorean +// used for disposal system +/proc/get_ranged_target_turf(var/atom/A, var/direction, var/range) + + var/x = A.x + var/y = A.y + if(direction & NORTH) + y = min(world.maxy, y + range) + if(direction & SOUTH) + y = max(1, y - range) + if(direction & EAST) + x = min(world.maxx, x + range) + if(direction & WEST) + x = max(1, x - range) + + return locate(x,y,A.z) + + +// returns turf relative to A offset in dx and dy tiles +// bound to map limits +/proc/get_offset_target_turf(var/atom/A, var/dx, var/dy) + var/x = min(world.maxx, max(1, A.x + dx)) + var/y = min(world.maxy, max(1, A.y + dy)) + return locate(x,y,A.z) + +/* +/proc/dir2text(var/d) + var/dir + switch(d) + if(1) + dir = "NORTH" + if(2) + dir = "SOUTH" + if(4) + dir = "EAST" + if(8) + dir = "WEST" + if(5) + dir = "NORTHEAST" + if(6) + dir = "SOUTHEAST" + if(9) + dir = "NORTHWEST" + if(10) + dir = "SOUTHWEST" + else + dir = null + return dir +*/ \ No newline at end of file diff --git a/code/defines/procs/logging.dm b/code/defines/procs/logging.dm new file mode 100644 index 0000000000000..277982ab98108 --- /dev/null +++ b/code/defines/procs/logging.dm @@ -0,0 +1,28 @@ +/proc/log_admin(text) + admin_log.Add(text) + if (config.log_admin) + diary << "ADMIN: [text]" + +/proc/log_game(text) + if (config.log_game) + diary << "GAME: [text]" + +/proc/log_vote(text) + if (config.log_vote) + diary << "VOTE: [text]" + +/proc/log_access(text) + if (config.log_access) + diary << "ACCESS: [text]" + +/proc/log_say(text) + if (config.log_say) + diary << "SAY: [text]" + +/proc/log_ooc(text) + if (config.log_ooc) + diary << "OOC: [text]" + +/proc/log_whisper(text) + if (config.log_whisper) + diary << "WHISPER: [text]" \ No newline at end of file diff --git a/code/defines/procs/religion_name.dm b/code/defines/procs/religion_name.dm new file mode 100644 index 0000000000000..18f90d0f81b49 --- /dev/null +++ b/code/defines/procs/religion_name.dm @@ -0,0 +1,11 @@ +var/religion_name = null +/proc/religion_name() + if (religion_name) + return religion_name + + var/name = "" + + name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob") + name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity") + + return capitalize(name) diff --git a/code/defines/procs/station_name.dm b/code/defines/procs/station_name.dm new file mode 100644 index 0000000000000..07161eaa65582 --- /dev/null +++ b/code/defines/procs/station_name.dm @@ -0,0 +1,39 @@ +/proc/station_name() + if (station_name) + return station_name + + var/name = "" + + if (prob(10)) + name += pick("Super", "Ultra", "Secret", "Top Secret", "Deep", "Death", "Zybourne", "Central", "Main", "Government", "Uoi", "Fat", "Automated", "Experimental") + name += " " + + // Prefix + name += pick("", "Space", "Star", "Moon", "System", "Mining", "Neckbeard", "Research", "Supply", "Military", "Goon", "Orbital", "Battle", "Science", "Asteroid", "Home", "Production", "Transport", "Delivery", "Extraplanetary", "Orbital", "Correctional", "Robot") + if (name) + name += " " + + // Suffix + name += pick("Station", "Base", "Facility", "Depot", "Outpost", "Installation", "Drydock", "Observatory", "Array", "Relay", "Monitor", "Platform", "Construct", "Hangar", "Prison", "Center", "Port", "Waystation", "Factory", "Waypoint", "Stopover", "Hub", "HQ", "Office", "Object", "Fortification") + name += " " + + // ID Number + if (prob(40)) + name += "[rand(1, 99)]" + else if (prob(50)) + name += pick("Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda", "Mu", "Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi", "Omega") + else if (prob(30)) + name += pick("II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX") + else if (prob(40)) + name += pick("Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliet", "Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-ray", "Yankee", "Zulu") + else + name += pick("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen") + + station_name = name + + if (config && config.server_name) + world.name = "[config.server_name]: [name]" + else + world.name = name + + return name diff --git a/code/defines/procs/statistics.dm b/code/defines/procs/statistics.dm new file mode 100644 index 0000000000000..37f9cf4b362c2 --- /dev/null +++ b/code/defines/procs/statistics.dm @@ -0,0 +1,206 @@ +#define SQL_ADDRESS "yourserver.com" +#define SQL_DB "yourdbname" +#define SQL_PORT "3306" // 3306 is default +#define SQL_LOGIN "yourlogin" +#define SQL_PASS "yourpassword" + + +#define STATLOGGING 0 // Should use #ifdef here + +proc/sql_poll_players() + if(!STATLOGGING) + return + var/playercount = 0 + for(var/mob/M in world) + if(M.client) + playercount += 1 + var/DBConnection/dbcon = new() + dbcon.Connect("dbi:mysql:[SQL_DB]:[SQL_ADDRESS]:[SQL_PORT]","[SQL_LOGIN]","[SQL_PASS]") + if(!dbcon.IsConnected()) + log_game("SQL ERROR during player polling. Failed to connect.") + else + var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") + var/DBQuery/query = dbcon.NewQuery("INSERT INTO population (playercount, time) VALUES ([playercount], '[sqltime]')") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during player polling. Error : \[[err]\]\n") + dbcon.Disconnect() + + +proc/sql_poll_admins() + if(!STATLOGGING) + return + var/admincount = 0 + for (var/mob/M in world) + if(M && M.client && M.client.holder && M.client.authenticated) + admincount += 1 + var/DBConnection/dbcon = new() + dbcon.Connect("dbi:mysql:[SQL_DB]:[SQL_ADDRESS]:[SQL_PORT]","[SQL_LOGIN]","[SQL_PASS]") + if(!dbcon.IsConnected()) + log_game("SQL ERROR during admin polling. Failed to connect.") + else + var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") + var/DBQuery/query = dbcon.NewQuery("INSERT INTO population (admincount, time) VALUES ([admincount], '[sqltime]')") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during admin polling. Error : \[[err]\]\n") + dbcon.Disconnect() + +proc/sql_report_round_start() + if(!STATLOGGING) + return +proc/sql_report_round_end() + if(!STATLOGGING) + return + +proc/sql_report_karma(var/mob/spender, var/mob/receiver, var/isnegative = 1) + if(!STATLOGGING) + return + var/sqlspendername = spender.name + var/sqlspenderkey = spender.key + var/sqlreceivername = receiver.name + var/sqlreceiverkey = receiver.key + var/sqlreceiverrole = "None" + var/sqlreceiverspecial = "None" + var/sqlisnegative = "TRUE" + + if(isnegative) + sqlisnegative = "TRUE" + else + sqlisnegative = "FALSE" + + var/sqlspenderip = spender.client.address + + if(receiver.mind) + if(receiver.mind.special_role) + sqlreceiverspecial = receiver.mind.special_role + if(receiver.mind.assigned_role) + sqlreceiverrole = receiver.mind.assigned_role + + var/DBConnection/dbcon = new() + dbcon.Connect("dbi:mysql:[SQL_DB]:[SQL_ADDRESS]:[SQL_PORT]","[SQL_LOGIN]","[SQL_PASS]") + if(!dbcon.IsConnected()) + log_game("SQL ERROR during karma logging. Failed to connect.") + else + var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") + var/DBQuery/query = dbcon.NewQuery("INSERT INTO karma (spendername, spenderkey, receivername, receiverkey, receiverrole, receiverspecial, isnegative, spenderip, time) VALUES ('[sqlspendername]', '[sqlspenderkey]', '[sqlreceivername]', '[sqlreceiverkey]', '[sqlreceiverrole]', '[sqlreceiverspecial]', [sqlisnegative], '[sqlspenderip]', '[sqltime]')") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during karma logging. Error : \[[err]\]\n") + + + query = dbcon.NewQuery("SELECT * FROM karmatotals WHERE byondkey='[receiver.key]'") + query.Execute() + + var/karma + var/id + while(query.NextRow()) + id = query.item[1] + karma = text2num(query.item[3]) + if(karma == null) + if(isnegative) + karma = -1 + else + karma = 1 + query = dbcon.NewQuery("INSERT INTO karmatotals (byondkey, karma) VALUES ('[receiver.key]', [karma])") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during karmatotal logging (adding new key). Error : \[[err]\]\n") + else + if(isnegative && sqlreceiverspecial != "None") // Toss out negative karma applied to traitors/wizards/etc. + dbcon.Disconnect() + return + if(isnegative) + karma -= 1 + else + karma += 1 + + query = dbcon.NewQuery("UPDATE karmatotals SET karma=[karma] WHERE id=[id]") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during karmatotal logging (updating existing entry). Error : \[[err]\]\n") + dbcon.Disconnect() + + +proc/sql_report_death(var/mob/living/carbon/human/H) + if(!STATLOGGING) + return + if(!H) + return + if(!H.client || !H.mind) + return + + var/turf/T = H.loc + var/area/placeofdeath = T.loc + var/podname = placeofdeath.name + + var/sqlname = dd_replacetext(H.real_name, "'", "''") + var/sqlkey = dd_replacetext(H.key, "'", "''") + var/sqlpod = dd_replacetext(podname, "'", "''") + var/sqlspecial = dd_replacetext(H.mind.special_role, "'", "''") + var/sqljob = dd_replacetext(H.mind.assigned_role, "'", "''") + var/laname + var/lakey + if(H.lastattacker) + laname = dd_replacetext(H.lastattacker:real_name, "'", "''") + lakey = dd_replacetext(H.lastattacker:key, "'", "''") + var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") + var/coord = "[H.x], [H.y], [H.z]" + //world << "INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.fireloss], [H.brainloss], [H.oxyloss])" + var/DBConnection/dbcon = new() + dbcon.Connect("dbi:mysql:[SQL_DB]:[SQL_ADDRESS]:[SQL_PORT]","[SQL_LOGIN]","[SQL_PASS]") + if(!dbcon.IsConnected()) + log_game("SQL ERROR during death reporting. Failed to connect.") + else + var/DBQuery/query = dbcon.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.fireloss], [H.brainloss], [H.oxyloss], '[coord]')") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during death reporting. Error : \[[err]\]\n") + dbcon.Disconnect() + + +proc/sql_report_cyborg_death(var/mob/living/silicon/robot/H) + if(!STATLOGGING) + return + if(!H) + return + if(!H.client || !H.mind) + return + + var/turf/T = H.loc + var/area/placeofdeath = T.loc + var/podname = placeofdeath.name + + var/sqlname = dd_replacetext(H.real_name, "'", "''") + var/sqlkey = dd_replacetext(H.key, "'", "''") + var/sqlpod = dd_replacetext(podname, "'", "''") + var/sqlspecial = dd_replacetext(H.mind.special_role, "'", "''") + var/sqljob = dd_replacetext(H.mind.assigned_role, "'", "''") + var/laname + var/lakey + if(H.lastattacker) + laname = dd_replacetext(H.lastattacker:real_name, "'", "''") + lakey = dd_replacetext(H.lastattacker:key, "'", "''") + var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") + var/coord = "[H.x], [H.y], [H.z]" + //world << "INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.fireloss], [H.brainloss], [H.oxyloss])" + var/DBConnection/dbcon = new() + dbcon.Connect("dbi:mysql:[SQL_DB]:[SQL_ADDRESS]:[SQL_PORT]","[SQL_LOGIN]","[SQL_PASS]") + if(!dbcon.IsConnected()) + log_game("SQL ERROR during death reporting. Failed to connect.") + else + var/DBQuery/query = dbcon.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.fireloss], [H.brainloss], [H.oxyloss], '[coord]')") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during death reporting. Error : \[[err]\]\n") + dbcon.Disconnect() + + +proc/statistic_cycle() + if(!STATLOGGING) + return + while(1) + sql_poll_players() + sleep(600) + sql_poll_admins() + sleep(6000) // Poll every ten minutes \ No newline at end of file diff --git a/code/defines/procs/syndicate_name.dm b/code/defines/procs/syndicate_name.dm new file mode 100644 index 0000000000000..b3f8ccac5ad13 --- /dev/null +++ b/code/defines/procs/syndicate_name.dm @@ -0,0 +1,29 @@ +var/syndicate_name = null +/proc/syndicate_name() + if (syndicate_name) + return syndicate_name + + var/name = "" + + // Prefix + name += pick("Clandestine", "Prima", "Blue", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Bonk", "Gene", "Gib") + + // Suffix + if (prob(80)) + name += " " + + // Full + if (prob(60)) + name += pick("Syndicate", "Consortium", "Collective", "Corporation", "Group", "Holdings", "Biotech", "Industries", "Systems", "Products", "Chemicals", "Enterprises", "Family", "Creations", "International", "Intergalactic", "Interplanetary", "Foundation", "Positronics", "Hive") + // Broken + else + name += pick("Syndi", "Corp", "Bio", "System", "Prod", "Chem", "Inter", "Hive") + name += pick("", "-") + name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Code") + // Small + else + name += pick("-", "*", "") + name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Gen", "Star", "Dyne", "Code", "Hive") + + syndicate_name = name + return name diff --git a/code/defines/turf.dm b/code/defines/turf.dm new file mode 100644 index 0000000000000..6cff373a91b32 --- /dev/null +++ b/code/defines/turf.dm @@ -0,0 +1,175 @@ +/turf + icon = 'floors.dmi' + var/intact = 1 + + level = 1.0 + + var + //Properties for open tiles (/floor) + oxygen = 0 + carbon_dioxide = 0 + nitrogen = 0 + toxins = 0 + + //Properties for airtight tiles (/wall) + thermal_conductivity = 0.05 + heat_capacity = 1 + + //Properties for both + temperature = T20C + + blocks_air = 0 + icon_old = null + pathweight = 1 + +/turf/space + icon = 'space.dmi' + name = "space" + icon_state = "placeholder" + + temperature = TCMB + thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT + heat_capacity = 700000 + +/turf/space/New() + icon = 'space.dmi' + icon_state = "[pick(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25)]" + +/turf/simulated + name = "station" + var/wet = 0 + var/image/wet_overlay = null + + var/thermite = 0 + oxygen = MOLES_O2STANDARD + nitrogen = MOLES_N2STANDARD + +/turf/simulated/floor/engine + name = "reinforced floor" + icon_state = "engine" + thermal_conductivity = 0.025 + heat_capacity = 325000 + +/turf/simulated/floor/engine/vacuum + name = "vacuum floor" + icon_state = "engine" + oxygen = 0 + nitrogen = 0.001 + temperature = TCMB + + +/turf/simulated/floor + name = "floor" + icon = 'floors.dmi' + icon_state = "floor" + thermal_conductivity = 0.040 + heat_capacity = 225000 + var/broken = 0 + var/burnt = 0 + + airless + name = "airless floor" + oxygen = 0.01 + nitrogen = 0.01 + temperature = TCMB + + New() + ..() + name = "floor" + +/turf/simulated/floor/plating + name = "plating" + icon_state = "plating" + intact = 0 + +/turf/simulated/floor/plating/airless + name = "airless plating" + oxygen = 0.01 + nitrogen = 0.01 + temperature = TCMB + + New() + ..() + name = "plating" + +/turf/simulated/floor/grid + icon = 'floors.dmi' + icon_state = "circuit" + +/turf/simulated/wall/r_wall + name = "r wall" + icon = 'walls.dmi' + icon_state = "r_wall" + opacity = 1 + density = 1 + var/d_state = 0 + +/turf/simulated/wall + name = "wall" + icon = 'walls.dmi' + opacity = 1 + density = 1 + blocks_air = 1 + + thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT + heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m steel wall + +/turf/simulated/shuttle + name = "shuttle" + icon = 'shuttle.dmi' + thermal_conductivity = 0.05 + heat_capacity = 0 + +/turf/simulated/shuttle/wall + name = "wall" + icon_state = "wall1" + opacity = 1 + density = 1 + blocks_air = 1 + +/turf/simulated/shuttle/floor + name = "floor" + icon_state = "floor" + +/turf/unsimulated + name = "command" + oxygen = MOLES_O2STANDARD + nitrogen = MOLES_N2STANDARD + +/turf/unsimulated/floor + name = "floor" + icon = 'floors.dmi' + icon_state = "Floor3" + +/turf/unsimulated/wall + name = "wall" + icon = 'walls.dmi' + icon_state = "riveted" + opacity = 1 + density = 1 + +/turf/unsimulated/wall/other + icon_state = "r_wall" + +/turf/proc + AdjacentTurfs() + var/L[] = new() + for(var/turf/simulated/t in oview(src,1)) + if(!t.density) + if(!LinkBlocked(src, t) && !TurfBlockedNonWindow(t)) + L.Add(t) + return L + Distance(turf/t) + if(get_dist(src,t) == 1) + var/cost = (src.x - t.x) * (src.x - t.x) + (src.y - t.y) * (src.y - t.y) + cost *= (pathweight+t.pathweight)/2 + return cost + else + return get_dist(src,t) + AdjacentTurfsSpace() + var/L[] = new() + for(var/turf/t in oview(src,1)) + if(!t.density) + if(!LinkBlocked(src, t) && !TurfBlockedNonWindow(t)) + L.Add(t) + return L diff --git a/code/defines/world.dm b/code/defines/world.dm new file mode 100644 index 0000000000000..f3fac8f12b6e0 --- /dev/null +++ b/code/defines/world.dm @@ -0,0 +1,17 @@ +world + mob = /mob/new_player + turf = /turf/space + area = /area + view = "15x15" + + + Topic(href, href_list[]) + world << "Received a Topic() call!" + world << "[href]" + for(var/a in href_list) + world << "[a]" + if(href_list["hello"]) + world << "Hello world!" + return "Hello world!" + world << "End of Topic() call." + ..() \ No newline at end of file diff --git a/code/game/airtunnel.dm b/code/game/airtunnel.dm new file mode 100644 index 0000000000000..bbe95097e68af --- /dev/null +++ b/code/game/airtunnel.dm @@ -0,0 +1,448 @@ +/obj/move/airtunnel/process() + if (!( src.deployed )) + return null + else + ..() + return + +/obj/move/airtunnel/connector/create() + src.current = src + src.next = new /obj/move/airtunnel( null ) + src.next.master = src.master + src.next.previous = src + spawn( 0 ) + src.next.create(airtunnel_start - airtunnel_stop, src.y) + return + return + +/obj/move/airtunnel/connector/wall/create() + src.current = src + src.next = new /obj/move/airtunnel/wall( null ) + src.next.master = src.master + src.next.previous = src + spawn( 0 ) + src.next.create(airtunnel_start - airtunnel_stop, src.y) + return + return + +/obj/move/airtunnel/connector/wall/process() + return + +/obj/move/airtunnel/wall/create(num, y_coord) + if (((num < 7 || (num > 16 && num < 23)) && y_coord == airtunnel_bottom)) + src.next = new /obj/move/airtunnel( null ) + else + src.next = new /obj/move/airtunnel/wall( null ) + src.next.master = src.master + src.next.previous = src + if (num > 1) + spawn( 0 ) + src.next.create(num - 1, y_coord) + return + return + +/obj/move/airtunnel/wall/move_right() + flick("wall-m", src) + return ..() + +/obj/move/airtunnel/wall/move_left() + flick("wall-m", src) + return ..() + +/obj/move/airtunnel/wall/process() + return + +/obj/move/airtunnel/proc/move_left() + src.relocate(get_step(src, WEST)) + if ((src.next && src.next.deployed)) + return src.next.move_left() + else + return src.next + return + +/obj/move/airtunnel/proc/move_right() + src.relocate(get_step(src, EAST)) + if ((src.previous && src.previous.deployed)) + src.previous.move_right() + return src.previous + +/obj/move/airtunnel/proc/create(num, y_coord) + if (y_coord == airtunnel_bottom) + if ((num < 7 || (num > 16 && num < 23))) + src.next = new /obj/move/airtunnel( null ) + else + src.next = new /obj/move/airtunnel/wall( null ) + else + src.next = new /obj/move/airtunnel( null ) + src.next.master = src.master + src.next.previous = src + if (num > 1) + spawn( 0 ) + src.next.create(num - 1, y_coord) + return + return + +/obj/machinery/at_indicator/ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(50)) + for(var/x in src.verbs) + src.verbs -= x + src.icon_state = "reader_broken" + stat |= BROKEN + if(3.0) + if (prob(25)) + for(var/x in src.verbs) + src.verbs -= x + src.icon_state = "reader_broken" + stat |= BROKEN + else + return + +/obj/machinery/at_indicator/blob_act() + if (prob(50)) + for(var/x in src.verbs) + src.verbs -= x + src.icon_state = "reader_broken" + stat |= BROKEN + +/obj/machinery/at_indicator/proc/update_icon() + if(stat & (BROKEN|NOPOWER)) + icon_state = "reader_broken" + return + + var/status = 0 + if (SS13_airtunnel.operating == 1) + status = "r" + else + if (SS13_airtunnel.operating == 2) + status = "e" + else + if(!SS13_airtunnel.connectors) + return + var/obj/move/airtunnel/connector/C = pick(SS13_airtunnel.connectors) + if (C.current == C) + status = 0 + else + if (!( C.current.next )) + status = 2 + else + status = 1 + src.icon_state = text("reader[][]", (SS13_airtunnel.siphon_status == 2 ? "1" : "0"), status) + return + +/obj/machinery/at_indicator/process() + if(stat & (NOPOWER|BROKEN)) + src.update_icon() + return + use_power(5, ENVIRON) + src.update_icon() + return + +/obj/machinery/computer/airtunnel/attack_paw(user as mob) + return src.attack_hand(user) + +obj/machinery/computer/airtunnel/attack_ai(user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/airtunnel/attack_hand(var/mob/user as mob) + if(..()) + return + + var/dat = "Air Tunnel Controls
      " + user.machine = src + if (SS13_airtunnel.operating == 1) + dat += "Status: RETRACTING
      " + else + if (SS13_airtunnel.operating == 2) + dat += "Status: EXPANDING
      " + else + var/obj/move/airtunnel/connector/C = pick(SS13_airtunnel.connectors) + if (C.current == C) + dat += "Status: Fully Retracted
      " + else + if (!( C.current.next )) + dat += "Status: Fully Extended
      " + else + dat += "Status: Stopped Midway
      " + dat += text("Retract Stop Extend
      ", src, src, src) + dat += text("
      Air Level: []
      ", (SS13_airtunnel.air_stat ? "Acceptable" : "DANGEROUS")) + dat += "Air System Status: " + switch(SS13_airtunnel.siphon_status) + if(0.0) + dat += "Stopped " + if(1.0) + dat += "Siphoning (Siphons only) " + if(2.0) + dat += "Regulating (BOTH) " + if(3.0) + dat += "RELEASING MAX (Siphons only) " + else + dat += text("(Refresh)
      ", src) + dat += text("RELEASE (Siphons only) Siphon (Siphons only) Stop Regulate
      ", src, src, src, src) + dat += text("

      Close
      ", user) + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + +/obj/machinery/computer/airtunnel/proc/update_icon() + if(stat & BROKEN) + icon_state = "broken" + return + + if(stat & NOPOWER) + icon_state = "c_unpowered" + return + + var/status = 0 + if (SS13_airtunnel.operating == 1) + status = "r" + else + if (SS13_airtunnel.operating == 2) + status = "e" + else + var/obj/move/airtunnel/connector/C = pick(SS13_airtunnel.connectors) + if (C.current == C) + status = 0 + else + if (!( C.current.next )) + status = 2 + else + status = 1 + src.icon_state = text("console[][]", (SS13_airtunnel.siphon_status >= 2 ? "1" : "0"), status) + return + +/obj/machinery/computer/airtunnel/process() + src.update_icon() + if(stat & (NOPOWER|BROKEN)) + return + use_power(250) + src.updateUsrDialog() + return + +/obj/machinery/computer/airtunnel/Topic(href, href_list) + if(..()) + return + + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))) + usr.machine = src + if (href_list["retract"]) + SS13_airtunnel.retract() + else if (href_list["stop"]) + SS13_airtunnel.operating = 0 + else if (href_list["extend"]) + SS13_airtunnel.extend() + else if (href_list["release"]) + SS13_airtunnel.siphon_status = 3 + SS13_airtunnel.siphons() + else if (href_list["siphon"]) + SS13_airtunnel.siphon_status = 1 + SS13_airtunnel.siphons() + else if (href_list["stop_siph"]) + SS13_airtunnel.siphon_status = 0 + SS13_airtunnel.siphons() + else if (href_list["auto"]) + SS13_airtunnel.siphon_status = 2 + SS13_airtunnel.siphons() + else if (href_list["refresh"]) + SS13_airtunnel.siphons() + + src.add_fingerprint(usr) + src.updateUsrDialog() + return + + +/obj/machinery/sec_lock/attack_ai(user as mob) + return src.attack_hand(user) + +/obj/machinery/sec_lock/attack_paw(user as mob) + return src.attack_hand(user) + +/obj/machinery/sec_lock/attack_hand(var/mob/user as mob) + if(..()) + return + use_power(10) + + if (src.loc == user.loc) + var/dat = text("Security Pad:
      \nKeycard: []
      \nToggle Outer Door
      \nToggle Inner Door
      \n
      \nEmergency Close
      \nEmergency Open
      ", (src.scan ? text("[]", src, src.scan.name) : text("-----", src)), src, src, src, src) + user << browse(dat, "window=sec_lock") + onclose(user, "sec_lock") + return + +/obj/machinery/sec_lock/attackby(nothing, user as mob) + return src.attack_hand(user) + +/obj/machinery/sec_lock/New() + ..() + spawn( 2 ) + if (src.a_type == 1) + src.d2 = locate(/obj/machinery/door, locate(src.x - 2, src.y - 1, src.z)) + src.d1 = locate(/obj/machinery/door, get_step(src, SOUTHWEST)) + else + if (src.a_type == 2) + src.d2 = locate(/obj/machinery/door, locate(src.x - 2, src.y + 1, src.z)) + src.d1 = locate(/obj/machinery/door, get_step(src, NORTHWEST)) + else + src.d1 = locate(/obj/machinery/door, get_step(src, SOUTH)) + src.d2 = locate(/obj/machinery/door, get_step(src, SOUTHEAST)) + return + return + +/obj/machinery/sec_lock/Topic(href, href_list) + if(..()) + return + if ((!( src.d1 ) || !( src.d2 ))) + usr << "\red Error: Cannot interface with door security!" + return + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))) + usr.machine = src + if (href_list["card"]) + if (src.scan) + src.scan.loc = src.loc + src.scan = null + else + var/obj/item/weapon/card/id/I = usr.equipped() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + src.scan = I + if (href_list["door1"]) + if (src.scan) + if (src.check_access(src.scan)) + if (src.d1.density) + spawn( 0 ) + src.d1.open() + return + else + spawn( 0 ) + src.d1.close() + return + if (href_list["door2"]) + if (src.scan) + if (src.check_access(src.scan)) + if (src.d2.density) + spawn( 0 ) + src.d2.open() + return + else + spawn( 0 ) + src.d2.close() + return + if (href_list["em_cl"]) + if (src.scan) + if (src.check_access(src.scan)) + if (!( src.d1.density )) + src.d1.close() + return + sleep(1) + spawn( 0 ) + if (!( src.d2.density )) + src.d2.close() + return + if (href_list["em_op"]) + if (src.scan) + if (src.check_access(src.scan)) + spawn( 0 ) + if (src.d1.density) + src.d1.open() + return + sleep(1) + spawn( 0 ) + if (src.d2.density) + src.d2.open() + return + src.add_fingerprint(usr) + src.updateUsrDialog() + return + +/datum/air_tunnel/air_tunnel1/New() + ..() + for(var/obj/move/airtunnel/A in locate(/area/airtunnel1)) + A.master = src + A.create() + src.connectors += A + //Foreach goto(21) + return + +/datum/air_tunnel/proc/siphons() + switch(src.siphon_status) + if(0.0) + for(var/obj/machinery/atmoalter/siphs/S in locate(/area/airtunnel1)) + S.t_status = 3 + if(1.0) + for(var/obj/machinery/atmoalter/siphs/fullairsiphon/S in locate(/area/airtunnel1)) + S.t_status = 2 + S.t_per = 1000000.0 + for(var/obj/machinery/atmoalter/siphs/scrubbers/S in locate(/area/airtunnel1)) + S.t_status = 3 + if(2.0) + for(var/obj/machinery/atmoalter/siphs/S in locate(/area/airtunnel1)) + S.t_status = 4 + if(3.0) + for(var/obj/machinery/atmoalter/siphs/fullairsiphon/S in locate(/area/airtunnel1)) + S.t_status = 1 + S.t_per = 1000000.0 + for(var/obj/machinery/atmoalter/siphs/scrubbers/S in locate(/area/airtunnel1)) + S.t_status = 3 + else + return + +/datum/air_tunnel/proc/stop() + src.operating = 0 + return + +/datum/air_tunnel/proc/extend() + if (src.operating) + return + + spawn(0) + src.operating = 2 + while(src.operating == 2) + var/ok = 1 + for(var/obj/move/airtunnel/connector/A in src.connectors) + if (!( A.current.next )) + src.operating = 0 + return + if (!( A.move_left() )) + ok = 0 + if (!( ok )) + src.operating = 0 + else + for(var/obj/move/airtunnel/connector/A in src.connectors) + if (A.current) + A.current.next.loc = get_step(A.current.loc, EAST) + A.current = A.current.next + A.current.deployed = 1 + else + src.operating = 0 + sleep(20) + return + +/datum/air_tunnel/proc/retract() + if (src.operating) + return + spawn(0) + src.operating = 1 + while(src.operating == 1) + var/ok = 1 + for(var/obj/move/airtunnel/connector/A in src.connectors) + if (A.current == A) + src.operating = 0 + return + if (A.current) + A.current.loc = null + A.current.deployed = 0 + A.current = A.current.previous + else + ok = 0 + if (!( ok )) + src.operating = 0 + else + for(var/obj/move/airtunnel/connector/A in src.connectors) + if (!( A.current.move_right() )) + src.operating = 0 + sleep(20) + return \ No newline at end of file diff --git a/code/game/algorithm.dm b/code/game/algorithm.dm new file mode 100644 index 0000000000000..878c6cee25b17 --- /dev/null +++ b/code/game/algorithm.dm @@ -0,0 +1,172 @@ +/world/New() + ..() + + diary = file("data/logs/[time2text(world.realtime, "YYYY/MM-Month/DD-Day")].log") + diary << "" + diary << "" + diary << "Starting up. [time2text(world.timeofday, "hh:mm.ss")]" + diary << "---------------------" + diary << "" + + jobban_loadbanfile() + jobban_updatelegacybans() + goon_loadfile() + beta_tester_loadfile() + LoadBans() + + spawn(30) + //EXPERIMENTAL + Optimize() + sleep_offline = 1 + //EXPERIMENTAL + + spawn(0) + SetupOccupationsList() + return + + +/// EXPERIMENTAL STUFF +var/opt_inactive = null +/world/proc/Optimize() + if(!opt_inactive) opt_inactive = world.timeofday + + if(world.timeofday - opt_inactive >= 600) + KickInactiveClients() + opt_inactive = world.timeofday + + spawn(100) Optimize() + +/world/proc/KickInactiveClients() + for(var/client/C) + if(!C.holder && ((C.inactivity/10)/60) >= 10) // Used to be 15 -- TLE + C << "\red You have been inactive for more than 10 minutes and have been disconnected." + /* + if(C.mob) + if(!istype(C.mob, /mob/dead/)) + C << "\red Your character has also been killed to save on server resources." + C.mob.death(0) // Added to lighten the load they take on the server -- TLE + del(C) + */ + +/// EXPERIMENTAL STUFF + +// This function counts a passed job. +proc/countJob(rank) + var/jobCount = 0 + for(var/mob/H in world) + if(H.mind && H.mind.assigned_role == rank) + jobCount++ + return jobCount + +/mob/living/carbon/human/var/const + slot_back = 1 + slot_wear_mask = 2 + slot_handcuffed = 3 + slot_l_hand = 4 + slot_r_hand = 5 + slot_belt = 6 + slot_wear_id = 7 + slot_ears = 8 + slot_glasses = 9 + slot_gloves = 10 + slot_head = 11 + slot_shoes = 12 + slot_wear_suit = 13 + slot_w_uniform = 14 + slot_l_store = 15 + slot_r_store = 16 +// slot_w_radio = 17 + slot_in_backpack = 18 + +/mob/living/carbon/human/proc/equip_if_possible(obj/item/weapon/W, slot) // since byond doesn't seem to have pointers, this seems like the best way to do this :/ + //warning: icky code + var/equipped = 0 + if((slot == l_store || slot == r_store || slot == belt || slot == wear_id) && !src.w_uniform) + del(W) + return + switch(slot) + if(slot_back) + if(!src.back) + src.back = W + equipped = 1 + if(slot_wear_mask) + if(!src.wear_mask) + src.wear_mask = W + equipped = 1 + if(slot_handcuffed) + if(!src.handcuffed) + src.handcuffed = W + equipped = 1 + if(slot_l_hand) + if(!src.l_hand) + src.l_hand = W + equipped = 1 + if(slot_r_hand) + if(!src.r_hand) + src.r_hand = W + equipped = 1 + if(slot_belt) + if(!src.belt) + src.belt = W + equipped = 1 + if(slot_wear_id) + if(!src.wear_id) + src.wear_id = W + equipped = 1 + if(slot_ears) + if(!src.ears) + src.ears = W + equipped = 1 + if(slot_glasses) + if(!src.glasses) + src.glasses = W + equipped = 1 + if(slot_gloves) + if(!src.gloves) + src.gloves = W + equipped = 1 + if(slot_head) + if(!src.head) + src.head = W + equipped = 1 + if(slot_shoes) + if(!src.shoes) + src.shoes = W + equipped = 1 + if(slot_wear_suit) + if(!src.wear_suit) + src.wear_suit = W + equipped = 1 + if(slot_w_uniform) + if(!src.w_uniform) + src.w_uniform = W + equipped = 1 + if(slot_l_store) + if(!src.l_store) + src.l_store = W + equipped = 1 + if(slot_r_store) + if(!src.r_store) + src.r_store = W + equipped = 1 +// if(slot_w_radio) +// if(!src.w_radio) +// src.w_radio = W +// equipped = 1 + if(slot_in_backpack) + if (src.back && istype(src.back, /obj/item/weapon/storage/backpack)) + var/obj/item/weapon/storage/backpack/B = src.back + if(B.contents.len < 7 && W.w_class <= 3) + W.loc = B + equipped = 1 + + if(equipped) + W.layer = 20 + else + del(W) + +/proc/AutoUpdateAI(obj/subject) + if (subject!=null) + for(var/mob/living/silicon/ai/M in world) + if ((M.client && M.machine == subject)) + subject.attack_ai(M) diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm new file mode 100644 index 0000000000000..72832cd2a19cb --- /dev/null +++ b/code/game/area/ai_monitored.dm @@ -0,0 +1,86 @@ +/area/ai_monitored + name = "AI Monitored Area" + var/obj/machinery/camera/motion/motioncamera = null + + +/area/ai_monitored/New() + ..() + // locate and store the motioncamera + spawn (20) // spawn on a delay to let turfs/objs load + for (var/obj/machinery/camera/motion/M in src) + motioncamera = M + return + return + +/area/ai_monitored/Entered(atom/movable/O) + ..() + if (istype(O, /mob) && motioncamera) + motioncamera.newTarget(O) + +/area/ai_monitored/Exited(atom/movable/O) + if (istype(O, /mob) && motioncamera) + motioncamera.lostTarget(O) + +/obj/machinery/camera/motion + name = "Motion Security Camera" + var/list/motionTargets = list() + var/detectTime = 0 + var/locked = 1 + +/obj/machinery/camera/motion/process() + // motion camera event loop + if (detectTime > 0) + var/elapsed = world.time - detectTime + if (elapsed > 300) + triggerAlarm() + else if (detectTime == -1) + for (var/mob/target in motionTargets) + if (target.stat == 2) lostTarget(target) + +/obj/machinery/camera/motion/proc/newTarget(var/mob/target) + if (istype(target, /mob/living/silicon/ai)) return 0 + if (detectTime == 0) + detectTime = world.time // start the clock + if (!(target in motionTargets)) + motionTargets += target + return 1 + +/obj/machinery/camera/motion/proc/lostTarget(var/mob/target) + if (target in motionTargets) + motionTargets -= target + if (motionTargets.len == 0) + cancelAlarm() + +/obj/machinery/camera/motion/proc/cancelAlarm() + if (detectTime == -1) + for (var/mob/living/silicon/aiPlayer in world) + if (status) aiPlayer.cancelAlarm("Motion", src.loc.loc) + detectTime = 0 + return 1 + +/obj/machinery/camera/motion/proc/triggerAlarm() + if (!detectTime) return 0 + for (var/mob/living/silicon/aiPlayer in world) + if (status) aiPlayer.triggerAlarm("Motion", src.loc.loc, src) + detectTime = -1 + return 1 + +/obj/machinery/camera/motion/attackby(W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/wirecutters) && locked == 1) return + if (istype(W, /obj/item/weapon/screwdriver)) + var/turf/T = user.loc + user << text("\blue []ing the access hatch... (this is a long process)", (locked) ? "Open" : "Clos") + sleep(100) + if ((user.loc == T && user.equipped() == W && !( user.stat ))) + src.locked ^= 1 + user << text("\blue The access hatch is now [].", (locked) ? "closed" : "open") + + ..() // call the parent to (de|re)activate + + if (istype(W, /obj/item/weapon/wirecutters)) // now handle alarm on/off... + if (status) // ok we've just been reconnected... send an alarm! + detectTime = world.time - 301 + triggerAlarm() + else + for (var/mob/living/silicon/aiPlayer in world) // manually cancel, to not disturb internal state + aiPlayer.cancelAlarm("Motion", src.loc.loc) diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm new file mode 100644 index 0000000000000..f56d2c8b1ced8 --- /dev/null +++ b/code/game/area/areas.dm @@ -0,0 +1,210 @@ +// === + +/area/New() + + src.icon = 'alert.dmi' + spawn(1) + //world.log << "New: [src] [tag]" + var/sd_created = findtext(tag,"sd_L") + sd_New(sd_created) + if(sd_created) + related += src + return + master = src + related = list(src) + + src.icon = 'alert.dmi' + src.layer = 10 + + if(name == "Space") // override defaults for space + requires_power = 0 + + if(!requires_power) + power_light = 1 + power_equip = 1 + power_environ = 1 + luminosity = 1 + sd_lighting = 0 // *DAL* + else + luminosity = 0 + //sd_SetLuminosity(0) // *DAL* + + + /*spawn(5) + for(var/turf/T in src) // count the number of turfs (for lighting calc) + if(no_air) + T.oxygen = 0 // remove air if so specified for this area + T.n2 = 0 + T.res_vars() + + */ + + + spawn(15) + src.power_change() // all machines set to current power level, also updates lighting icon + +/* +/proc/get_area(area/A) + while (A) + if (istype(A, /area)) + return A + + A = A.loc + return null +*/ + +/area/proc/poweralert(var/state, var/source) + if (state != poweralm) + poweralm = state + var/list/cameras = list() + for (var/obj/machinery/camera/C in src) + cameras += C + for (var/mob/living/silicon/aiPlayer in world) + if (state == 1) + aiPlayer.cancelAlarm("Power", src, source) + else + aiPlayer.triggerAlarm("Power", src, cameras, source) + return + + +/area/proc/firealert() + if(src.name == "Space") //no fire alarms in space + return + if (!( src.fire )) + src.fire = 1 + src.updateicon() + src.mouse_opacity = 0 + for(var/obj/machinery/door/firedoor/D in src) + if(!D.blocked) + if(D.operating) + D.nextstate = CLOSED + else if(!D.density) + spawn(0) + D.close() + var/list/cameras = list() + for (var/obj/machinery/camera/C in src) + cameras += C + for (var/mob/living/silicon/ai/aiPlayer in world) + aiPlayer.triggerAlarm("Fire", src, cameras, src) + for (var/obj/machinery/computer/atmosphere/alerts/a in world) + a.triggerAlarm("Fire", src, cameras, src) + return + +/area/proc/firereset() + if (src.fire) + src.fire = 0 + src.mouse_opacity = 0 + src.updateicon() + for(var/obj/machinery/door/firedoor/D in src) + if(!D.blocked) + if(D.operating) + D.nextstate = OPEN + else if(D.density) + spawn(0) + D.open() + for (var/mob/living/silicon/ai/aiPlayer in world) + aiPlayer.cancelAlarm("Fire", src, src) + for (var/obj/machinery/computer/atmosphere/alerts/a in world) + a.cancelAlarm("Fire", src, src) + return + +/area/proc/partyalert() + if(src.name == "Space") //no parties in space!!! + return + if (!( src.party )) + src.party = 1 + src.updateicon() + src.mouse_opacity = 0 + return + +/area/proc/partyreset() + if (src.party) + src.party = 0 + src.mouse_opacity = 0 + src.updateicon() + for(var/obj/machinery/door/firedoor/D in src) + if(!D.blocked) + if(D.operating) + D.nextstate = OPEN + else if(D.density) + spawn(0) + D.open() + return + +/area/proc/updateicon() + if ((fire || eject || party) && power_environ) + if(fire && !eject && !party) + icon_state = "blue" + else if(!fire && eject && !party) + icon_state = "red" + else if(party && !fire && !eject) + icon_state = "party" + else + icon_state = "blue-red" + else + // new lighting behaviour with obj lights + icon_state = null + + +/* +#define EQUIP 1 +#define LIGHT 2 +#define ENVIRON 3 +*/ + +/area/proc/powered(var/chan) // return true if the area has power to given channel + + if(!master.requires_power) + return 1 + switch(chan) + if(EQUIP) + return master.power_equip + if(LIGHT) + return master.power_light + if(ENVIRON) + return master.power_environ + + return 0 + +// called when power status changes + +/area/proc/power_change() + + + 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.) + + RA.updateicon() + + +/area/proc/usage(var/chan) + + var/used = 0 + switch(chan) + if(LIGHT) + used += master.used_light + if(EQUIP) + used += master.used_equip + if(ENVIRON) + used += master.used_environ + if(TOTAL) + used += master.used_light + master.used_equip + master.used_environ + + return used + +/area/proc/clear_usage() + + master.used_equip = 0 + master.used_light = 0 + master.used_environ = 0 + +/area/proc/use_power(var/amount, var/chan) + + switch(chan) + if(EQUIP) + master.used_equip += amount + if(LIGHT) + master.used_light += amount + if(ENVIRON) + master.used_environ += amount diff --git a/code/game/atom_procs.dm b/code/game/atom_procs.dm new file mode 100644 index 0000000000000..7314a3a926d1a --- /dev/null +++ b/code/game/atom_procs.dm @@ -0,0 +1,342 @@ + +/atom/proc/MouseDrop_T() + return + +/atom/proc/attack_hand(mob/user as mob) + return + +/atom/proc/attack_paw(mob/user as mob) + return + +/atom/proc/attack_ai(mob/user as mob) + return + +//for aliens, it works the same as monkeys except for alien-> mob interactions which will be defined in the +//appropiate mob files +/atom/proc/attack_alien(mob/user as mob) + src.attack_paw(user) + return + +/atom/proc/hand_h(mob/user as mob) + return + +/atom/proc/hand_p(mob/user as mob) + return + +/atom/proc/hand_a(mob/user as mob) + return + +/atom/proc/hand_al(mob/user as mob) + src.hand_p(user) + return + + +/atom/proc/hitby(atom/movable/AM as mob|obj) + return + +/atom/proc/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/device/detective_scanner)) + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O << text("\red [src] has been scanned by [user] with the [W]") + else + if (!( istype(W, /obj/item/weapon/grab) ) || !(istype(W, /obj/item/weapon/cleaner))) + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O << text("\red [] has been hit by [] with []", src, user, W) + return + +/atom/proc/add_fingerprint(mob/living/carbon/human/M as mob) + if ((!( istype(M, /mob/living/carbon/human) ) || !( istype(M.dna, /datum/dna) ))) + return 0 + if (!( src.flags ) & 256) + return + if (M.gloves) + if(src.fingerprintslast != M.key) + src.fingerprintshidden += text("(Wearing gloves). Real name: [], Key: []",M.real_name, M.key) + src.fingerprintslast = M.key + return 0 + if (!( src.fingerprints )) + src.fingerprints = text("[]", md5(M.dna.uni_identity)) + if(src.fingerprintslast != M.key) + src.fingerprintshidden += text("Real name: [], Key: []",M.real_name, M.key) + src.fingerprintslast = M.key + return 1 + else + var/list/L = params2list(src.fingerprints) + L -= md5(M.dna.uni_identity) + while(L.len >= 3) + L -= L[1] + L += md5(M.dna.uni_identity) + src.fingerprints = list2params(L) + + if(src.fingerprintslast != M.key) + src.fingerprintshidden += text("Real name: [], Key: []",M.real_name, M.key) + src.fingerprintslast = M.key + return + +/atom/proc/add_blood(mob/living/carbon/human/M as mob) + if (!( istype(M, /mob/living/carbon/human) )) + return 0 + if (!( src.flags ) & 256) + return + if (!( src.blood_DNA )) + if (istype(src, /obj/item)) + var/obj/item/source2 = src + source2.icon_old = src.icon + var/icon/I = new /icon(src.icon, src.icon_state) + I.Blend(new /icon('blood.dmi', "thisisfuckingstupid"),ICON_ADD) + I.Blend(new /icon('blood.dmi', "itemblood"),ICON_MULTIPLY) + I.Blend(new /icon(src.icon, src.icon_state),ICON_UNDERLAY) + src.icon = I + src.blood_DNA = M.dna.unique_enzymes + src.blood_type = M.b_type + else if (istype(src, /turf/simulated)) + var/turf/simulated/source2 = src + var/list/objsonturf = range(0,src) + var/i + for(i=1, i<=objsonturf.len, i++) + if(istype(objsonturf[i],/obj/decal/cleanable/blood)) + return + var/obj/decal/cleanable/blood/this = new /obj/decal/cleanable/blood(source2) + this.blood_DNA = M.dna.unique_enzymes + this.blood_type = M.b_type + this.virus = M.virus + else if (istype(src, /mob/living/carbon/human)) + src.blood_DNA = M.dna.unique_enzymes + src.blood_type = M.b_type + else + return + else + var/list/L = params2list(src.blood_DNA) + L -= M.dna.unique_enzymes + while(L.len >= 3) + L -= L[1] + L += M.dna.unique_enzymes + src.blood_DNA = list2params(L) + return + +/atom/proc/clean_blood() + + if (!( src.flags ) & 256) + return + if ( src.blood_DNA ) + if (istype (src, /obj/item)) + var/obj/item/source2 = src + source2.blood_DNA = null + var/icon/I = new /icon(source2.icon_old, source2.icon_state) + source2.icon = I + else if (istype(src, /turf/simulated)) + var/obj/item/source2 = src + source2.blood_DNA = null + var/icon/I = new /icon(source2.icon_old, source2.icon_state) + source2.icon = I + return + +/atom/MouseDrop(atom/over_object as mob|obj|turf|area) + spawn( 0 ) + if (istype(over_object, /atom)) + over_object.MouseDrop_T(src, usr) + return + ..() + return + +/atom/Click(location,control,params) + //world << "atom.Click() on [src] by [usr] : src.type is [src.type]" + + if(usr.client.buildmode) + build_click(usr, usr.client.buildmode, location, control, params, src) + return + + return DblClick() + +/atom/DblClick() //TODO: DEFERRED: REWRITE + if (world.time <= usr:lastDblClick+2) + //world << "BLOCKED atom.DblClick() on [src] by [usr] : src.type is [src.type]" + return + else + //world << "atom.DblClick() on [src] by [usr] : src.type is [src.type]" + usr:lastDblClick = world.time + + ..() + + + if(usr.in_throw_mode) + return usr:throw_item(src) + + var/obj/item/W = usr.equipped() + + + if(istype(usr, /mob/living/silicon/hivebot)||istype(usr, /mob/living/silicon/robot)) + if(!isnull(usr:module_active)) + W = usr:module_active + else + W = null + + if (W == src && usr.stat == 0) + spawn (0) + W.attack_self(usr) + return + + if (((usr.paralysis || usr.stunned || usr.weakened) && !istype(usr, /mob/living/silicon/ai)) || usr.stat != 0) + return + + if ((!( src in usr.contents ) && (((!( isturf(src) ) && (!( isturf(src.loc) ) && (src.loc && !( isturf(src.loc.loc) )))) || !( isturf(usr.loc) )) && (src.loc != usr.loc && (!( istype(src, /obj/screen) ) && !( usr.contents.Find(src.loc) )))))) + return + + var/t5 = in_range(src, usr) || src.loc == usr + + if (istype(usr, /mob/living/silicon/ai)) + t5 = 1 + + if ((istype(usr, /mob/living/silicon/robot) || istype(usr, /mob/living/silicon/hivebot)) && W == null) + t5 = 1 + + if (istype(src, /datum/organ) && src in usr.contents) + return + + if (((t5 || (W && (W.flags & 16))) && !( istype(src, /obj/screen) ))) + if (usr.next_move < world.time) + usr.prev_move = usr.next_move + usr.next_move = world.time + 10 + else + return + if ((src.loc && (get_dist(src, usr) < 2 || src.loc == usr.loc))) + var/direct = get_dir(usr, src) + var/obj/item/weapon/dummy/D = new /obj/item/weapon/dummy( usr.loc ) + var/ok = 0 + if ( (direct - 1) & direct) + var/turf/Step_1 + var/turf/Step_2 + switch(direct) + if(5.0) + Step_1 = get_step(usr, NORTH) + Step_2 = get_step(usr, EAST) + + if(6.0) + Step_1 = get_step(usr, SOUTH) + Step_2 = get_step(usr, EAST) + + if(9.0) + Step_1 = get_step(usr, NORTH) + Step_2 = get_step(usr, WEST) + + if(10.0) + Step_1 = get_step(usr, SOUTH) + Step_2 = get_step(usr, WEST) + + else + if(Step_1 && Step_2) + var/check_1 = 0 + var/check_2 = 0 + if(step_to(D, Step_1)) + check_1 = 1 + for(var/obj/border_obstacle in Step_1) + if(border_obstacle.flags & ON_BORDER) + if(!border_obstacle.CheckExit(D, src)) + check_1 = 0 + for(var/obj/border_obstacle in get_turf(src)) + if((border_obstacle.flags & ON_BORDER) && (src != border_obstacle)) + if(!border_obstacle.CanPass(D, D.loc, 1, 0)) + check_1 = 0 + + D.loc = usr.loc + if(step_to(D, Step_2)) + check_2 = 1 + + for(var/obj/border_obstacle in Step_2) + if(border_obstacle.flags & ON_BORDER) + if(!border_obstacle.CheckExit(D, src)) + check_2 = 0 + for(var/obj/border_obstacle in get_turf(src)) + if((border_obstacle.flags & ON_BORDER) && (src != border_obstacle)) + if(!border_obstacle.CanPass(D, D.loc, 1, 0)) + check_2 = 0 + if(check_1 || check_2) + ok = 1 + else + if(loc == usr.loc) + ok = 1 + else + ok = 1 + + //Now, check objects to block exit that are on the border + for(var/obj/border_obstacle in usr.loc) + if(border_obstacle.flags & ON_BORDER) + if(!border_obstacle.CheckExit(D, src)) + ok = 0 + + //Next, check objects to block entry that are on the border + for(var/obj/border_obstacle in get_turf(src)) + if((border_obstacle.flags & ON_BORDER) && (src != border_obstacle)) + if(!border_obstacle.CanPass(D, D.loc, 1, 0)) + ok = 0 + + del(D) + if (!( ok )) + + return 0 + + if (!( usr.restrained() )) + if (W) + if (t5) + src.attackby(W, usr) + if (W) + W.afterattack(src, usr, (t5 ? 1 : 0)) + else + if (istype(usr, /mob/living/carbon/human)) + src.attack_hand(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/monkey)) + src.attack_paw(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/alien/humanoid)) + src.attack_alien(usr, usr.hand) + else + if (istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot)|| istype(usr, /mob/living/silicon/hivebot)) + src.attack_ai(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/human)) + src.hand_h(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/monkey)) + src.hand_p(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/alien/humanoid)) + src.hand_al(usr, usr.hand) + else + if (istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot)|| istype(usr, /mob/living/silicon/hivebot)) + src.hand_a(usr, usr.hand) + + else + if (istype(src, /obj/screen)) + usr.prev_move = usr.next_move + if (usr.next_move < world.time) + usr.next_move = world.time + 10 + else + return + if (!( usr.restrained() )) + if ((W && !( istype(src, /obj/screen) ))) + src.attackby(W, usr) + + if (W) + W.afterattack(src, usr) + else + if (istype(usr, /mob/living/carbon/human)) + src.attack_hand(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/monkey)) + src.attack_paw(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/alien/humanoid)) + src.attack_alien(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/human)) + src.hand_h(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/monkey)) + src.hand_p(usr, usr.hand) + else + if (istype(usr, /mob/living/carbon/alien/humanoid)) + src.hand_al(usr, usr.hand) + return diff --git a/code/game/cellautomata.dm b/code/game/cellautomata.dm new file mode 100644 index 0000000000000..9754747497e54 --- /dev/null +++ b/code/game/cellautomata.dm @@ -0,0 +1,177 @@ +/world/proc/load_mode() + var/text = file2text("data/mode.txt") + if (text) + var/list/lines = dd_text2list(text, "\n") + if (lines[1]) + master_mode = lines[1] + diary << "Saved mode is '[master_mode]'" + +/world/proc/save_mode(var/the_mode) + var/F = file("data/mode.txt") + fdel(F) + F << the_mode + +/world/proc/load_motd() + join_motd = file2text("config/motd.txt") + auth_motd = file2text("config/motd-auth.txt") + no_auth_motd = file2text("config/motd-noauth.txt") + +/world/proc/load_rules() + rules = file2text("config/rules.html") + if (!rules) + rules = "RulesThere are no rules! Go nuts!" + +/world/proc/load_admins() + var/text = file2text("config/admins.txt") + if (!text) + diary << "Failed to load config/admins.txt\n" + else + var/list/lines = dd_text2list(text, "\n") + for(var/line in lines) + if (!line) + continue + + if (copytext(line, 1, 2) == ";") + continue + + var/pos = findtext(line, " - ", 1, null) + if (pos) + var/m_key = copytext(line, 1, pos) + var/a_lev = copytext(line, pos + 3, length(line) + 1) + admins[m_key] = a_lev + diary << ("ADMIN: [m_key] = [a_lev]") + +/world/proc/load_testers() + var/text = file2text("config/testers.txt") + if (!text) + diary << "Failed to load config/testers.txt\n" + else + var/list/lines = dd_text2list(text, "\n") + for(var/line in lines) + if (!line) + continue + + if (copytext(line, 1, 2) == ";") + continue + + var/pos = findtext(line, " - ", 1, null) + if (pos) + var/m_key = copytext(line, 1, pos) + var/a_lev = copytext(line, pos + 3, length(line) + 1) + admins[m_key] = a_lev + + +/world/proc/load_configuration() + config = new /datum/configuration() + config.load("config/config.txt") + // apply some settings from config.. + abandon_allowed = config.respawn + +/world/New() + src.load_configuration() + + if (config && config.server_name != null && config.server_suffix && world.port > 0) + // dumb and hardcoded but I don't care~ + config.server_name += " #[(world.port % 1000) / 100]" + + src.load_mode() + src.load_motd() + src.load_rules() + src.load_admins() + + src.update_status() + + makepowernets() + + sun = new /datum/sun() + + vote = new /datum/vote() + + radio_controller = new /datum/controller/radio() + //main_hud1 = new /obj/hud() + data_core = new /obj/datacore() + + ..() + + sleep(50) + + plmaster = new /obj/overlay( ) + plmaster.icon = 'tile_effects.dmi' + plmaster.icon_state = "plasma" + plmaster.layer = FLY_LAYER + plmaster.mouse_opacity = 0 + + slmaster = new /obj/overlay( ) + slmaster.icon = 'tile_effects.dmi' + slmaster.icon_state = "sleeping_agent" + slmaster.layer = FLY_LAYER + slmaster.mouse_opacity = 0 + + src.update_status() + + master_controller = new /datum/controller/game_controller() + spawn(-1) master_controller.setup() + return + +//Crispy fullban +/world/Reboot(var/reason) + spawn(0) + if(prob(40)) + for(var/mob/M in world) + if(M.client) + M << sound('NewRound2.ogg') + else + for(var/mob/M in world) + if(M.client) + M << sound('NewRound.ogg') + + for(var/client/C) + C << link("byond://[world.address]:[world.port]") + +// sleep(10) // wait for sound to play + ..(reason) + +/atom/proc/check_eye(user as mob) + if (istype(user, /mob/living/silicon/ai)) + return 1 + return + +/atom/proc/on_reagent_change() + return + +/atom/proc/Bumped(AM as mob|obj) + return + +/atom/movable/Bump(var/atom/A as mob|obj|turf|area, yes) + spawn( 0 ) + if ((A && yes)) + A.last_bumped = world.timeofday + A.Bumped(src) + return + ..() + return + +// **** Note in 40.93.4, split into obj/mob/turf point verbs, no area + +/atom/verb/point() + set src in oview() + + if (!usr || !isturf(usr.loc)) + return + else if (usr.stat != 0 || usr.restrained()) + return + + var/tile = get_turf(src) + if (!tile) + return + + var/P = new /obj/decal/point(tile) + spawn (20) + del(P) + + usr.visible_message("[usr] points to [src]") + +/obj/decal/point/point() + set src in oview() + set hidden = 1 + return \ No newline at end of file diff --git a/code/game/chemistry.dm b/code/game/chemistry.dm new file mode 100644 index 0000000000000..9323259335de9 --- /dev/null +++ b/code/game/chemistry.dm @@ -0,0 +1,376 @@ +#define REGULATE_RATE 5 + +/obj/item/weapon/smokebomb + desc = "It is set to detonate in 2 seconds." + name = "smoke bomb" + icon = 'grenade.dmi' + icon_state = "flashbang" + var/state = null + var/det_time = 20.0 + w_class = 2.0 + item_state = "flashbang" + throw_speed = 4 + throw_range = 20 + flags = FPRINT | TABLEPASS | ONBELT | USEDELAY + var/datum/effects/system/bad_smoke_spread/smoke + +/obj/item/weapon/incendiarygrenade + desc = "It is set to detonate in 3 seconds." + name = "incendiary grenade" + icon = 'grenade.dmi' + icon_state = "flashbang" + var/state = null + var/firestrength = 100 + var/det_time = 20.0 + w_class = 2.0 + item_state = "flashbang" + throw_speed = 4 + throw_range = 20 + flags = FPRINT | TABLEPASS | CONDUCT | ONBELT + +/obj/item/weapon/mustardbomb + desc = "It is set to detonate in 4 seconds." + name = "mustard gas bomb" + icon = 'grenade.dmi' + icon_state = "flashbang" + var/state = null + var/det_time = 40.0 + w_class = 2.0 + item_state = "flashbang" + throw_speed = 4 + throw_range = 20 + flags = FPRINT | TABLEPASS | CONDUCT | ONBELT + var/datum/effects/system/mustard_gas_spread/mustard_gas + +/obj/item/weapon/smokebomb/New() + ..() + src.smoke = new /datum/effects/system/bad_smoke_spread/ + src.smoke.attach(src) + src.smoke.set_up(10, 0, usr.loc) + +/obj/item/weapon/mustardbomb/New() + ..() + src.mustard_gas = new /datum/effects/system/mustard_gas_spread/ + src.mustard_gas.attach(src) + src.mustard_gas.set_up(5, 0, usr.loc) + +/obj/item/weapon/smokebomb/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/screwdriver)) + if (src.det_time == 60) + src.det_time = 20 + user.show_message("\blue You set the smoke bomb for a 2 second detonation time.") + src.desc = "It is set to detonate in 2 seconds." + else + src.det_time = 60 + user.show_message("\blue You set the smoke bomb for a 6 second detonation time.") + src.desc = "It is set to detonate in 6 seconds." + src.add_fingerprint(user) + return + +/obj/item/weapon/incendiarygrenade/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/screwdriver)) + if (src.det_time == 60) + src.det_time = 30 + user.show_message("\blue You set the incendiary grenade for a 3 second detonation time.") + src.desc = "It is set to detonate in 3 seconds." + else + src.det_time = 60 + user.show_message("\blue You set the incendiary grenade for a 6 second detonation time.") + src.desc = "It is set to detonate in 6 seconds." + src.add_fingerprint(user) + return + +/obj/item/weapon/smokebomb/afterattack(atom/target as mob|obj|turf|area, mob/user as mob) + if (user.equipped() == src) + if (!( src.state )) + user << "\red You prime the smoke bomb! [det_time/10] seconds!" + src.state = 1 + src.icon_state = "flashbang1" + playsound(src.loc, 'armbomb.ogg', 75, 1, -3) + spawn( src.det_time ) + prime() + return + user.dir = get_dir(user, target) + user.drop_item() + var/t = (isturf(target) ? target : target.loc) + walk_towards(src, t, 3) + src.add_fingerprint(user) + return + +/obj/item/weapon/incendiarygrenade/afterattack(atom/target as mob|obj|turf|area, mob/user as mob) + if (user.equipped() == src) + if (!( src.state )) + user << "\red You prime the incendiary grenade! [det_time/10] seconds!" + src.state = 1 + src.icon_state = "flashbang1" + playsound(src.loc, 'armbomb.ogg', 75, 1, -3) + spawn( src.det_time ) + prime() + return + user.dir = get_dir(user, target) + user.drop_item() + var/t = (isturf(target) ? target : target.loc) + walk_towards(src, t, 3) + src.add_fingerprint(user) + return + +/obj/item/weapon/incendiarygrenade/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/item/weapon/incendiarygrenade/attack_hand() + walk(src, null, null) + ..() + return + +/obj/item/weapon/smokebomb/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/item/weapon/smokebomb/attack_hand() + walk(src, null, null) + ..() + return + +/obj/item/weapon/smokebomb/proc/prime() + playsound(src.loc, 'smoke.ogg', 50, 1, -3) + spawn(0) + src.smoke.start() + sleep(10) + src.smoke.start() + sleep(10) + src.smoke.start() + sleep(10) + src.smoke.start() + + for(var/obj/blob/B in view(8,src)) + var/damage = round(30/(get_dist(B,src)+1)) + B.health -= damage + B.update() + sleep(80) + del(src) + return + +/obj/item/weapon/incendiarygrenade/proc/prime() + playsound(src.loc, 'bamf.ogg', 75, 1, -2) + var/turf/T = src.loc + var/turf/Tx1 = src.x + 1 + var/turf/Txm1 = src.x - 1 + var/turf/Ty1 = src.y + 1 + var/turf/Tym1 = src.y - 1 + for(var/turf/simulated/floor/target_tile in list(T,Tx1,Txm1,Ty1,Tym1)) + if(target_tile.parent && target_tile.parent.group_processing) + target_tile.parent.suspend_group_processing() + + var/datum/gas_mixture/napalm = new + var/datum/gas/volatile_fuel/fuel = new + + fuel.moles = 15 + napalm.trace_gases += fuel + + target_tile.assume_air(napalm) + + spawn target_tile.hotspot_expose(700, 400) + + for(var/obj/blob/B in view(8,src)) + var/damage = round(30/(get_dist(B,src)+1)) + B.health -= damage + B.update() + + sleep(10) + del(src) + return + + +/obj/item/weapon/smokebomb/attack_self(mob/user as mob) + if (!src.state) + user << "\red You prime the smoke bomb! [det_time/10] seconds!" + src.state = 1 + src.icon_state = "flashbang1" + add_fingerprint(user) + spawn( src.det_time ) + prime() + return + return + +/obj/item/weapon/incendiarygrenade/attack_self(mob/user as mob) + if (!src.state) + user << "\red You prime the incendiary grenade! [det_time/10] seconds!" + src.state = 1 + src.icon_state = "flashbang1" + add_fingerprint(user) + spawn( src.det_time ) + prime() + return + return + + + + + +/obj/item/weapon/mustardbomb/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/screwdriver)) + if (src.det_time == 80) + src.det_time = 40 + user.show_message("\blue You set the mustard gas bomb for a 4 second detonation time.") + src.desc = "It is set to detonate in 4 seconds." + else + src.det_time = 80 + user.show_message("\blue You set the mustard gas bomb for a 8 second detonation time.") + src.desc = "It is set to detonate in 8 seconds." + src.add_fingerprint(user) + return + +/obj/item/weapon/mustardbomb/afterattack(atom/target as mob|obj|turf|area, mob/user as mob) + if (user.equipped() == src) + if (!( src.state )) + user << "\red You prime the mustard gas bomb! [det_time/10] seconds!" + src.state = 1 + src.icon_state = "flashbang1" + playsound(src.loc, 'armbomb.ogg', 75, 1, -3) + spawn( src.det_time ) + prime() + return + user.dir = get_dir(user, target) + user.drop_item() + var/t = (isturf(target) ? target : target.loc) + walk_towards(src, t, 3) + src.add_fingerprint(user) + return + +/obj/item/weapon/mustardbomb/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/item/weapon/mustardbomb/attack_hand() + walk(src, null, null) + ..() + return + +/obj/item/weapon/mustardbomb/proc/prime() + playsound(src.loc, 'smoke.ogg', 50, 1, -3) + spawn(0) + src.mustard_gas.start() + sleep(10) + src.mustard_gas.start() + sleep(10) + src.mustard_gas.start() + sleep(10) + src.mustard_gas.start() + + for(var/obj/blob/B in view(8,src)) + var/damage = round(30/(get_dist(B,src)+1)) + B.health -= damage + B.update() + sleep(100) + del(src) + return + +/obj/item/weapon/mustardbomb/attack_self(mob/user as mob) + if (!src.state) + user << "\red You prime the mustard gas bomb! [det_time/10] seconds!" + src.state = 1 + src.icon_state = "flashbang1" + add_fingerprint(user) + spawn( src.det_time ) + prime() + return + return + +/obj/item/weapon/storage/beakerbox + name = "Beaker Box" + icon_state = "beaker" + item_state = "syringe_kit" + +/obj/item/weapon/storage/beakerbox/New() + ..() + new /obj/item/weapon/reagent_containers/glass/beaker( src ) + new /obj/item/weapon/reagent_containers/glass/beaker( src ) + new /obj/item/weapon/reagent_containers/glass/beaker( src ) + new /obj/item/weapon/reagent_containers/glass/beaker( src ) + new /obj/item/weapon/reagent_containers/glass/beaker( src ) + new /obj/item/weapon/reagent_containers/glass/beaker( src ) + new /obj/item/weapon/reagent_containers/glass/beaker( src ) + +/obj/item/weapon/paper/alchemy/ + name = "paper- 'Chemistry Information'" + +/obj/item/weapon/storage/trashcan + name = "disposal unit" + w_class = 4.0 + anchored = 1.0 + density = 1.0 + var/processing = null + var/locked = 1 + req_access = list(access_janitor) + desc = "A compact incineration device, used to dispose of garbage." + icon = 'stationobjs.dmi' + icon_state = "trashcan" + item_state = "syringe_kit" + +/obj/item/weapon/storage/trashcan/attackby(obj/item/weapon/W as obj, mob/user as mob) + + if (src.contents.len >= 7) + user << "The trashcan is full!" + return + if (istype(W, /obj/item/weapon/disk/nuclear)) + user << "This is far too important to throw away!" + return + if (istype(W, /obj/item/weapon/storage/)) + return + if (istype(W, /obj/item/weapon/grab)) + user << "You cannot fit the person inside." + return + var/t + for(var/obj/item/weapon/O in src) + t += O.w_class + //Foreach goto(46) + t += W.w_class + if (t > 30) + user << "You cannot fit the item inside. (Remove larger classed items)" + return + user.u_equip(W) + W.loc = src + if ((user.client && user.s_active != src)) + user.client.screen -= W + src.orient2hud(user) + W.dropped(user) + add_fingerprint(user) + user.visible_message("\blue [user] has put [W] in [src]!") + + if (src.contents.len >= 7) + src.locked = 1 + src.icon_state = "trashcan1" + spawn (200) + if (src.contents.len < 7) + src.locked = 0 + src.icon_state = "trashcan" + return + +/obj/item/weapon/storage/trashcan/attack_hand(mob/user as mob) + if(src.allowed(usr)) + locked = !locked + else + user << "\red Access denied." + return + if (src.processing) + return + if (src.contents.len >= 7) + user << "\blue You begin the emptying procedure." + var/area/A = src.loc.loc // make sure it's in an area + if(!A || !isarea(A)) + return +// var/turf/T = src.loc + A.use_power(250, EQUIP) + src.processing = 1 + src.contents.len = 0 + src.icon_state = "trashmelt" + if (istype(loc, /turf)) + loc:hotspot_expose(1000,10) + sleep (60) + src.icon_state = "trashcan" + src.processing = 0 + return + else + src.icon_state = "trashcan" + user << "\blue Due to conservation measures, the unit is unable to start until it is completely filled." + return + + diff --git a/code/game/communications.dm b/code/game/communications.dm new file mode 100644 index 0000000000000..c3a5f24ec3946 --- /dev/null +++ b/code/game/communications.dm @@ -0,0 +1,93 @@ +/* +Special frequency list: +On the map: +1435 for status displays +1437 for atmospherics/fire alerts +1439 for engine components +1441 for atmospherics - supply tanks +1443 for atmospherics - distribution loop/mixed air tank +1445 for bot nav beacons +1447 for mulebot control +1449 for airlock controls +1451 for toxin lab access +1453 for engineering access +1455 for AI access +*/ +#define TRANSMISSION_WIRE 0 +#define TRANSMISSION_RADIO 1 + +var/global/datum/controller/radio/radio_controller + +datum/controller/radio + var/list/datum/radio_frequency/frequencies = list() + + proc/add_object(obj/device, new_frequency) + var/datum/radio_frequency/frequency = frequencies[new_frequency] + + if(!frequency) + frequency = new + frequency.frequency = new_frequency + frequencies[new_frequency] = frequency + + frequency.devices += device + return frequency + + proc/remove_object(obj/device, old_frequency) + var/datum/radio_frequency/frequency = frequencies[old_frequency] + + if(frequency) + frequency.devices -= device + + if(frequency.devices.len < 1) + del(frequency) + frequencies -= old_frequency + + return 1 + + proc/return_frequency(frequency) + return frequencies[frequency] + +datum/radio_frequency + var/frequency + var/list/obj/devices = list() + + proc + post_signal(obj/source, datum/signal/signal, range) + var/turf/start_point + if(range) + start_point = get_turf(source) + if(!start_point) + del(signal) + return 0 + + for(var/obj/device in devices) + if(device != source) + if(range) + var/turf/end_point = get_turf(device) + if(end_point) + if(max(abs(start_point.x-end_point.x), abs(start_point.y-end_point.y)) <= range) + device.receive_signal(signal, TRANSMISSION_RADIO, frequency) + else + device.receive_signal(signal, TRANSMISSION_RADIO, frequency) + + del(signal) + +obj/proc + receive_signal(datum/signal/signal, receive_method, receive_param) + return null + +datum/signal + var/obj/source + + var/transmission_method = 0 + //0 = wire + //1 = radio transmission + + var/data = list() + var/encryption + + proc/copy_from(datum/signal/model) + source = model.source + transmission_method = model.transmission_method + data = model.data + encryption = model.encryption \ No newline at end of file diff --git a/code/game/dna.dm b/code/game/dna.dm new file mode 100644 index 0000000000000..d1834692dac89 --- /dev/null +++ b/code/game/dna.dm @@ -0,0 +1,1239 @@ +/////////////////////////// DNA DATUM +/datum/dna + var/unique_enzymes = null + var/struc_enzymes = null + var/uni_identity = null + +/datum/dna/proc/check_integrity() + //Lazy. + if(length(uni_identity) != 39) uni_identity = "00600200A00E0110148FC01300B0095BD7FD3F4" + if(length(struc_enzymes)!= 42) struc_enzymes = "0983E840344C39F4B059D5145FC5785DC6406A4000" + +/datum/dna/proc/ready_dna(mob/living/carbon/human/character) + + var/temp + var/hair + var/beard + + // determine DNA fragment from hairstyle + // :wtc: + + var/list/styles = list("bald", "hair_a", "hair_b", "hair_c", "hair_d", "hair_e", "hair_f", "hair_bedhead", "hair_dreads" ) + var/hrange = round(4095 / styles.len) + + var/style = styles.Find(character.hair_icon_state) + if(style) + hair = style * hrange + hrange - rand(1,hrange-1) + else + hair = 0 + + switch(character.face_icon_state) + if("bald") beard = rand(1,350) + if("facial_elvis") beard = rand(351,650) + if("facial_vandyke") beard = rand(651,950) + if("facial_neckbeard") beard = rand(951,1250) + if("facial_chaplin") beard = rand(1251,1550) + if("facial_watson") beard = rand(1551,1850) + if("facial_abe") beard = rand(1851,2150) + if("facial_chin") beard = rand(2151,2450) + if("facial_hip") beard = rand(2451,2750) + if("facial_gt") beard = rand(2751,3050) + if("facial_hogan") beard = rand(3051,3350) + if("facial_selleck") beard = rand(3351,3650) + if("facial_fullbeard") beard = rand(3651,3950) + if("facial_longbeard") beard = rand(3951,4095) + + temp = add_zero2(num2hex((character.r_hair),1), 3) + temp += add_zero2(num2hex((character.b_hair),1), 3) + temp += add_zero2(num2hex((character.g_hair),1), 3) + temp += add_zero2(num2hex((character.r_facial),1), 3) + temp += add_zero2(num2hex((character.b_facial),1), 3) + temp += add_zero2(num2hex((character.g_facial),1), 3) + temp += add_zero2(num2hex(((character.s_tone + 220) * 16),1), 3) + temp += add_zero2(num2hex((character.r_eyes),1), 3) + temp += add_zero2(num2hex((character.g_eyes),1), 3) + temp += add_zero2(num2hex((character.b_eyes),1), 3) + + var/gender + + if (character.gender == MALE) + gender = add_zero2(num2hex((rand(1,(2050+BLOCKADD))),1), 3) + else + gender = add_zero2(num2hex((rand((2051+BLOCKADD),4094)),1), 3) + + temp += gender + temp += add_zero2(num2hex((beard),1), 3) + temp += add_zero2(num2hex((hair),1), 3) + + uni_identity = temp + + var/mutstring = "2013E85C944C19A4B00185144725785DC6406A4508" + + struc_enzymes = mutstring + + unique_enzymes = md5(character.real_name) + reg_dna[unique_enzymes] = character.real_name + +/////////////////////////// DNA DATUM + +/////////////////////////// DNA HELPER-PROCS +/proc/getleftblocks(input,blocknumber,blocksize) + var/string + string = copytext(input,1,((blocksize*blocknumber)-(blocksize-1))) + if (blocknumber > 1) + return string + else + return null + +/proc/getrightblocks(input,blocknumber,blocksize) + var/string + string = copytext(input,blocksize*blocknumber+1,length(input)+1) + if (blocknumber < (length(input)/blocksize)) + return string + else + return null + +/proc/getblock(input,blocknumber,blocksize) + var/result + result = copytext(input ,(blocksize*blocknumber)-(blocksize-1),(blocksize*blocknumber)+1) + return result + +/proc/setblock(istring, blocknumber, replacement, blocksize) + var/result + result = getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize) + return result + +/proc/add_zero2(t, u) + var/temp1 + while (length(t) < u) + t = "0[t]" + temp1 = t + if (length(t) > u) + temp1 = copytext(t,2,u+1) + return temp1 + +/proc/miniscramble(input,rs,rd) + var/output + output = null + if (input == "C" || input == "D" || input == "E" || input == "F") + output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"6",prob((rs*10));"7",prob((rs*5)+(rd));"0",prob((rs*5)+(rd));"1",prob((rs*10)-(rd));"2",prob((rs*10)-(rd));"3") + if (input == "8" || input == "9" || input == "A" || input == "B") + output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3") + if (input == "4" || input == "5" || input == "6" || input == "7") + output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3") + if (input == "0" || input == "1" || input == "2" || input == "3") + output = pick(prob((rs*10));"8",prob((rs*10));"9",prob((rs*10));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C",prob((rs*10)-(rd));"D",prob((rs*5)+(rd));"E",prob((rs*5)+(rd));"F") + if (!output) output = "5" + return output + +/proc/isblockon(hnumber, bnumber) + var/temp2 + temp2 = hex2num(hnumber) + if (bnumber == HULKBLOCK || bnumber == TELEBLOCK) + if (temp2 >= 3500 + BLOCKADD) + return 1 + else + return 0 + if (bnumber == XRAYBLOCK || bnumber == FIREBLOCK) + if (temp2 >= 3050 + BLOCKADD) + return 1 + else + return 0 + if (temp2 >= 2050 + BLOCKADD) + return 1 + else + return 0 + +/proc/randmutb(mob/M as mob) + var/num + var/newdna + num = pick(1,3,FAKEBLOCK,5,CLUMSYBLOCK,7,9,BLINDBLOCK,DEAFBLOCK) + newdna = setblock(M.dna.struc_enzymes,num,toggledblock(getblock(M.dna.struc_enzymes,num,3)),3) + M.dna.struc_enzymes = newdna + return + +/proc/randmutg(mob/M as mob) + var/num + var/newdna + num = pick(HULKBLOCK,XRAYBLOCK,FIREBLOCK,TELEBLOCK) + newdna = setblock(M.dna.struc_enzymes,num,toggledblock(getblock(M.dna.struc_enzymes,num,3)),3) + M.dna.struc_enzymes = newdna + return + +/proc/randmuti(mob/M as mob) + var/num + var/newdna + num = pick(1,2,3,4,5,6,7,8,9,10,11,12,13) + newdna = setblock(M.dna.uni_identity,num,add_zero2(num2hex(rand(1,4095),1),3),3) + M.dna.uni_identity = newdna + return + +/proc/toggledblock(hnumber) //unused + var/temp3 + var/chtemp + temp3 = hex2num(hnumber) + if (temp3 < 2050) + chtemp = rand(2050,4095) + return add_zero2(num2hex(chtemp,1),3) + else + chtemp = rand(1,2049) + return add_zero2(num2hex(chtemp,1),3) +/////////////////////////// DNA HELPER-PROCS + +/////////////////////////// DNA MISC-PROCS +/proc/updateappearance(mob/M as mob,structure) + if(istype(M, /mob/living/carbon/human)) + M.dna.check_integrity() + var/mob/living/carbon/human/H = M + H.r_hair = hex2num(getblock(structure,1,3)) + H.b_hair = hex2num(getblock(structure,2,3)) + H.g_hair = hex2num(getblock(structure,3,3)) + H.r_facial = hex2num(getblock(structure,4,3)) + H.b_facial = hex2num(getblock(structure,5,3)) + H.g_facial = hex2num(getblock(structure,6,3)) + H.s_tone = round(((hex2num(getblock(structure,7,3)) / 16) - 220)) + H.r_eyes = hex2num(getblock(structure,8,3)) + H.g_eyes = hex2num(getblock(structure,9,3)) + H.b_eyes = hex2num(getblock(structure,10,3)) + + if (isblockon(getblock(structure, 11,3),11)) + H.gender = FEMALE + else + H.gender = MALE + /// + var/beardnum = hex2num(getblock(structure,12,3)) + if (beardnum >= 1 && beardnum <= 350) + H.face_icon_state = "bald" + H.f_style = "bald" + else if (beardnum >= 351 && beardnum <= 650) + H.face_icon_state = "facial_elvis" + H.f_style = "facial_elvis" + else if (beardnum >= 651 && beardnum <= 950) + H.face_icon_state = "facial_vandyke" + H.f_style = "facial_vandyke" + else if (beardnum >= 951 && beardnum <= 1250) + H.face_icon_state = "facial_neckbeard" + H.f_style = "facial_neckbeard" + else if (beardnum >= 1251 && beardnum <= 1550) + H.face_icon_state = "facial_chaplin" + H.f_style = "facial_chaplin" + else if (beardnum >= 1551 && beardnum <= 1850) + H.face_icon_state = "facial_watson" + H.f_style = "facial_watson" + else if (beardnum >= 1851 && beardnum <= 2150) + H.face_icon_state = "facial_abe" + H.f_style = "facial_abe" + else if (beardnum >= 2151 && beardnum <= 2450) + H.face_icon_state = "facial_chin" + H.f_style = "facial_chin" + else if (beardnum >= 2451 && beardnum <= 2750) + H.face_icon_state = "facial_hip" + H.f_style = "facial_hip" + else if (beardnum >= 2751 && beardnum <= 3050) + H.face_icon_state = "facial_gt" + H.f_style = "facial_gt" + else if (beardnum >= 3051 && beardnum <= 3350) + H.face_icon_state = "facial_hogan" + H.f_style = "facial_hogan" + else if (beardnum >= 3351 && beardnum <= 3650) + H.face_icon_state = "facial_selleck" + H.f_style = "facial_selleck" + else if (beardnum >= 3651 && beardnum <= 3950) + H.face_icon_state = "facial_fullbeard" + H.f_style = "facial_fullbeard" + else if (beardnum >= 3951 && beardnum <= 4095) + H.face_icon_state = "facial_longbeard" + H.f_style = "facial_longbeard" + + + var/hairnum = hex2num(getblock(structure,13,3)) + + + var/list/styles = list("bald", "hair_a", "hair_b", "hair_c", "hair_d", "hair_e", "hair_f", "hair_bedhead", "hair_dreads" ) + var/hrange = round(4095 / styles.len) + + var/style = round(hairnum / hrange) + + H.hair_icon_state = styles[style] + H.h_style = H.hair_icon_state + + + H.update_face() + H.update_body() + + return 1 + else + return 0 + +/proc/domutcheck(mob/M as mob, connected, inj) + //telekinesis = 1 + //firemut = 2 + //xray = 4 + //hulk = 8 + //clumsy = 16 + M.dna.check_integrity() + + M.disabilities = 0 + M.sdisabilities = 0 + M.mutations = 0 + + M.see_in_dark = 2 + M.see_invisible = 0 + + if (isblockon(getblock(M.dna.struc_enzymes, 1,3),1)) + M.disabilities |= 1 + M << "\red Your eyes feel strange." + if (isblockon(getblock(M.dna.struc_enzymes, HULKBLOCK,3),2)) + if(inj || prob(15)) + M << "\blue Your muscles hurt." + M.mutations |= 8 + if (isblockon(getblock(M.dna.struc_enzymes, 3,3),3)) + M.disabilities |= 2 + M << "\red You get a headache." + if (isblockon(getblock(M.dna.struc_enzymes, FAKEBLOCK,3),4)) + M << "\red You feel strange." + if (prob(95)) + if(prob(50)) + randmutb(M) + else + randmuti(M) + else + randmutg(M) + if (isblockon(getblock(M.dna.struc_enzymes, 5,3),5)) + M.disabilities |= 4 + M << "\red You start coughing." + if (isblockon(getblock(M.dna.struc_enzymes, CLUMSYBLOCK,3),6)) + M << "\red You feel lightheaded." + M.mutations |= 16 + if (isblockon(getblock(M.dna.struc_enzymes, 7,3),7)) + M.disabilities |= 8 + M << "\red You twitch." + if (isblockon(getblock(M.dna.struc_enzymes, XRAYBLOCK,3),8)) + if(inj || prob(30)) + 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 |= 4 + if (isblockon(getblock(M.dna.struc_enzymes, 9,3),9)) + M.disabilities |= 16 + M << "\red You feel nervous." + if (isblockon(getblock(M.dna.struc_enzymes, FIREBLOCK,3),10)) + if(inj || prob(30)) + M << "\blue Your body feels warm." + M.mutations |= 2 + if (isblockon(getblock(M.dna.struc_enzymes, BLINDBLOCK,3),11)) + M.sdisabilities |= 1 + M << "\red You cant seem to see anything." + if (isblockon(getblock(M.dna.struc_enzymes, TELEBLOCK,3),12)) + if(inj || prob(15)) + M << "\blue You feel smarter." + M.mutations |= 1 + if (isblockon(getblock(M.dna.struc_enzymes, DEAFBLOCK,3),13)) + M.sdisabilities |= 4 + M.ear_deaf = 1 + M << "\red Its kinda quiet..." + +//////////////////////////////////////////////////////////// Monkey Block + if (isblockon(getblock(M.dna.struc_enzymes, 14,3),14) && istype(M, /mob/living/carbon/human)) + // human > monkey + var/list/implants = list() //Try to preserve implants. + for(var/obj/item/weapon/W in M) + if (istype(W, /obj/item/weapon/implant)) + implants += W + for(var/obj/item/weapon/W in M) + M.u_equip(W) + if (M.client) + M.client.screen -= W + if (W) + W.loc = M.loc + W.dropped(M) + W.layer = initial(W.layer) + + if(!connected) + M.update_clothing() + M.monkeyizing = 1 + M.canmove = 0 + M.icon = null + M.invisibility = 101 + var/atom/movable/overlay/animation = new /atom/movable/overlay( M.loc ) + animation.icon_state = "blank" + animation.icon = 'mob.dmi' + animation.master = src + flick("h2monkey", animation) + sleep(48) + del(animation) + + var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey(src) + O.dna = M.dna + M.dna = null + + for(var/obj/T in M) + del(T) + for(var/R in M.organs) + del(M.organs[text("[]", R)]) + + O.loc = M.loc + + if(M.mind) + M.mind.transfer_to(O) + + if (connected) //inside dna thing + var/obj/machinery/dna_scannernew/C = connected + O.loc = C + C.occupant = O + connected = null + O.name = text("monkey ([])",copytext(md5(M.real_name), 2, 6)) + O.toxloss += (M.toxloss + 20) + O.bruteloss += (M.bruteloss + 40) + O.oxyloss += M.oxyloss + O.fireloss += M.fireloss + O.stat = M.stat + O.a_intent = "hurt" + for (var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O + continue + del(M) + return + + if (!isblockon(getblock(M.dna.struc_enzymes, 14,3),14) && !istype(M, /mob/living/carbon/human)) + // monkey > human + var/list/implants = list() + for (var/obj/item/weapon/implant/I in M) //Still preserving implants + implants += I + + if(!connected) + for(var/obj/item/weapon/W in M) + M.u_equip(W) + if (M.client) + M.client.screen -= W + if (W) + W.loc = M.loc + W.dropped(M) + W.layer = initial(W.layer) + M.update_clothing() + M.monkeyizing = 1 + M.canmove = 0 + M.icon = null + M.invisibility = 101 + var/atom/movable/overlay/animation = new /atom/movable/overlay( M.loc ) + animation.icon_state = "blank" + animation.icon = 'mob.dmi' + animation.master = src + flick("monkey2h", animation) + sleep(48) + del(animation) + + var/mob/living/carbon/human/O = new /mob/living/carbon/human( src ) + if (isblockon(getblock(M.dna.uni_identity, 11,3),11)) + O.gender = FEMALE + else + O.gender = MALE + O.dna = M.dna + M.dna = null + + for(var/obj/T in M) + del(T) + + O.loc = M.loc + + if(M.mind) + M.mind.transfer_to(O) + + 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++ + updateappearance(O,O.dna.uni_identity) + O.toxloss += M.toxloss + O.bruteloss += M.bruteloss + O.oxyloss += M.oxyloss + O.fireloss += M.fireloss + O.stat = M.stat + for (var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O + continue + del(M) + return +//////////////////////////////////////////////////////////// Monkey Block + if (M) M.update_clothing() + return null +/////////////////////////// DNA MISC-PROCS + + +/////////////////////////// DNA MACHINES +/obj/machinery/dna_scannernew/allow_drop() + return 0 + +/obj/machinery/dna_scannernew/relaymove(mob/user as mob) + if (user.stat) + return + src.go_out() + return + +/obj/machinery/dna_scannernew/verb/eject() + set src in oview(1) + + if (usr.stat != 0) + return + src.go_out() + add_fingerprint(usr) + return + +/obj/machinery/dna_scannernew/verb/move_inside() + set src in oview(1) + + if (usr.stat != 0) + return + if (src.occupant) + usr << "\blue The scanner is already occupied!" + return + if (usr.abiotic()) + usr << "\blue Subject cannot have abiotic items on." + return + usr.pulling = null + usr.client.perspective = EYE_PERSPECTIVE + usr.client.eye = src + usr.loc = src + src.occupant = usr + src.icon_state = "scanner_1" + for(var/obj/O in src) + //O = null + del(O) + //Foreach goto(124) + src.add_fingerprint(usr) + return + +/obj/machinery/dna_scannernew/attackby(obj/item/weapon/grab/G as obj, user as mob) + if ((!( istype(G, /obj/item/weapon/grab) ) || !( ismob(G.affecting) ))) + return + if (src.occupant) + user << "\blue The scanner is already occupied!" + return + if (G.affecting.abiotic()) + user << "\blue Subject cannot have abiotic items on." + return + var/mob/M = G.affecting + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + src.occupant = M + src.icon_state = "scanner_1" + for(var/obj/O in src) + O.loc = src.loc + //Foreach goto(154) + src.add_fingerprint(user) + //G = null + del(G) + return + +/obj/machinery/dna_scannernew/proc/go_out() + if ((!( src.occupant ) || src.locked)) + return + 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 + src.occupant.loc = src.loc + src.occupant = null + src.icon_state = "scanner_0" + return + +/obj/machinery/dna_scannernew/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + //Foreach goto(35) + //SN src = null + del(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + //Foreach goto(108) + //SN src = null + del(src) + return + if(3.0) + if (prob(25)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + //Foreach goto(181) + //SN src = null + del(src) + return + else + return + + +/obj/machinery/dna_scannernew/blob_act() + if(prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + del(src) + +/obj/machinery/scan_consolenew/ex_act(severity) + + switch(severity) + if(1.0) + //SN src = null + del(src) + return + if(2.0) + if (prob(50)) + //SN src = null + del(src) + return + else + return + +/obj/machinery/scan_consolenew/blob_act() + + if(prob(50)) + del(src) + +/obj/machinery/scan_consolenew/power_change() + if(stat & BROKEN) + icon_state = "broken" + else if(powered()) + icon_state = initial(icon_state) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + src.icon_state = "c_unpowered" + stat |= NOPOWER + +/obj/machinery/scan_consolenew/New() + ..() + spawn( 5 ) + src.connected = locate(/obj/machinery/dna_scannernew, get_step(src, WEST)) + return + return + +/obj/machinery/scan_consolenew/attackby(obj/item/W as obj, mob/user as mob) + if ((istype(W, /obj/item/weapon/disk/data)) && (!src.diskette)) + user.drop_item() + W.loc = src + src.diskette = W + user << "You insert [W]." + src.updateUsrDialog() + +/obj/machinery/scan_consolenew/process() //not really used right now + if(stat & (NOPOWER|BROKEN)) + return + use_power(250) // power stuff + if (!( src.status )) //remove this + return + return + +/obj/machinery/scan_consolenew/attack_paw(user as mob) + return src.attack_hand(user) + +/obj/machinery/scan_consolenew/attack_ai(user as mob) + return src.attack_hand(user) + +/obj/machinery/scan_consolenew/attack_hand(user as mob) + if(..()) + return + var/dat + if (src.delete && src.temphtml) //Window in buffer but its just simple message, so nothing + src.delete = src.delete + + else if (!src.delete && src.temphtml) //Window in buffer - its a menu, dont add clear message + dat = text("[]

      Main Menu", src.temphtml, src) + else + if (src.connected) //Is something connected? + var/mob/occupant = src.connected.occupant + dat = "Occupant Statistics:
      " //Blah obvious + if (occupant) //is there REALLY someone in there? + if (!istype(occupant,/mob/living/carbon/human)) + sleep(1) + var/t1 + switch(occupant.stat) // obvious, see what their status is + if(0) + t1 = "Conscious" + if(1) + t1 = "Unconscious" + else + t1 = "*dead*" + dat += text("[]\tHealth %: [] ([])

      ", (occupant.health > 50 ? "" : ""), occupant.health, t1) + dat += text("Radiation Level: []%

      ", occupant.radiation) + dat += text("Unique Enzymes : []
      ", uppertext(occupant.dna.unique_enzymes)) + dat += text("Unique Identifier: []
      ", occupant.dna.uni_identity) + dat += text("Structural Enzymes: []

      ", occupant.dna.struc_enzymes) + dat += text("Modify Unique Identifier
      ", src) + dat += text("Modify Structural Enzymes

      ", src) + dat += text("View/Edit/Transfer Buffer

      ", src) + dat += text("Pulse Radiation
      ", src) + dat += text("Radiation Emitter Settings

      ", src) + dat += text("Inject Rejuvenators

      ", src) + else + dat += "The scanner is empty.

      " + dat += text("View/Edit/Transfer Buffer

      ", src) + dat += text("Radiation Emitter Settings

      ", src) + if (!( src.connected.locked )) + dat += text("Lock (Unlocked)
      ", src) + else + dat += text("Unlock (Locked)
      ", src) + //Other stuff goes here + if (!isnull(src.diskette)) + dat += text("Eject Disk
      ", src) + dat += text("

      Close", user) + else + dat = " Error: No DNA Modifier connected. " + user << browse(dat, "window=scannernew;size=550x625") + onclose(user, "scannernew") + return + +/obj/machinery/scan_consolenew/Topic(href, href_list) + if(..()) + return + if ((usr.contents.Find(src) || in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon))) + usr.machine = src + if (href_list["locked"]) + if ((src.connected && src.connected.occupant)) + src.connected.locked = !( src.connected.locked ) + //////////////////////////////////////////////////////// + if (href_list["genpulse"]) + src.delete = 1 + src.temphtml = text("Working ... Please wait ([] Seconds)", src.radduration) + usr << browse(temphtml, "window=scannernew;size=550x650") + onclose(usr, "scannernew") + sleep(10*src.radduration) + if (!src.connected.occupant) + temphtml = null + delete = 0 + return null + if (prob(95)) + if(prob(75)) + randmutb(src.connected.occupant) + else + randmuti(src.connected.occupant) + else + if(prob(95)) + randmutg(src.connected.occupant) + else + randmuti(src.connected.occupant) + src.connected.occupant.radiation += ((src.radstrength*3)+src.radduration*3) + temphtml = null + delete = 0 + if (href_list["radset"]) + src.temphtml = text("Radiation Duration: []
      ", src.radduration) + src.temphtml += text("Radiation Intensity: []

      ", src.radstrength) + src.temphtml += text("-- Duration ++
      ", src, src) + src.temphtml += text("-- Intesity ++
      ", src, src) + src.delete = 0 + if (href_list["radleplus"]) + if (src.radduration < 20) + src.radduration++ + src.radduration++ + dopage(src,"radset") + if (href_list["radleminus"]) + if (src.radduration > 2) + src.radduration-- + src.radduration-- + dopage(src,"radset") + if (href_list["radinplus"]) + if (src.radstrength < 10) + src.radstrength++ + dopage(src,"radset") + if (href_list["radinminus"]) + if (src.radstrength > 1) + src.radstrength-- + dopage(src,"radset") + //////////////////////////////////////////////////////// + if (href_list["unimenu"]) + //src.temphtml = text("Unique Identifier: []

      ", src.connected.occupant.dna.uni_identity) + src.temphtml = text("Unique Identifier: [getleftblocks(src.connected.occupant.dna.uni_identity,uniblock,3)][src.subblock == 1 ? ""+getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),1,1)+"" : getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),1,1)][src.subblock == 2 ? ""+getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),2,1)+"" : getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),2,1)][src.subblock == 3 ? ""+getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),3,1)+"" : getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),3,1)][getrightblocks(src.connected.occupant.dna.uni_identity,uniblock,3)]

      ") + src.temphtml += text("Selected Block: []
      ", src.uniblock) + src.temphtml += text("<- Block ->

      ", src, src) + src.temphtml += text("Selected Sub-Block: []
      ", src.subblock) + src.temphtml += text("<- Sub-Block ->

      ", src, src) + src.temphtml += "Modify Block:
      " + src.temphtml += text("Radiation
      ", src) + src.delete = 0 + if (href_list["unimenuplus"]) + if (src.uniblock < 13) + src.uniblock++ + dopage(src,"unimenu") + if (href_list["unimenuminus"]) + if (src.uniblock > 1) + src.uniblock-- + dopage(src,"unimenu") + if (href_list["unimenusubplus"]) + if (src.subblock < 3) + src.subblock++ + dopage(src,"unimenu") + if (href_list["unimenusubminus"]) + if (src.subblock > 1) + src.subblock-- + dopage(src,"unimenu") + if (href_list["unipulse"]) + var/block + var/newblock + var/tstructure2 + block = getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),src.subblock,1) + src.delete = 1 + src.temphtml = text("Working ... Please wait ([] Seconds)", src.radduration) + usr << browse(temphtml, "window=scannernew;size=550x650") + onclose(usr, "scannernew") + sleep(10*src.radduration) + if (!src.connected.occupant) + temphtml = null + delete = 0 + return null + /// + if (prob((80 + (src.radduration / 2)))) + block = miniscramble(block, src.radstrength, src.radduration) + newblock = null + if (src.subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),2,1) + getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),3,1) + if (src.subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),1,1) + block + getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),3,1) + if (src.subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),1,1) + getblock(getblock(src.connected.occupant.dna.uni_identity,src.uniblock,3),2,1) + block + tstructure2 = setblock(src.connected.occupant.dna.uni_identity, src.uniblock, newblock,3) + src.connected.occupant.dna.uni_identity = tstructure2 + updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) + src.connected.occupant.radiation += (src.radstrength+src.radduration) + else + if (prob(20+src.radstrength)) + randmutb(src.connected.occupant) + domutcheck(src.connected.occupant,src.connected) + else + randmuti(src.connected.occupant) + updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) + src.connected.occupant.radiation += ((src.radstrength*2)+src.radduration) + dopage(src,"unimenu") + src.delete = 0 + //////////////////////////////////////////////////////// + if (href_list["rejuv"]) + var/mob/living/carbon/human/H = src.connected.occupant + if (H.reagents.get_reagent_amount("inaprovaline") < 60) + H.reagents.add_reagent("inaprovaline", 30) + usr << text("Occupant now has [] units of rejuvenation in his/her bloodstream.", H.reagents.get_reagent_amount("inaprovaline")) + src.delete = 0 + //////////////////////////////////////////////////////// + if (href_list["strucmenu"]) + if(src.connected.occupant) + src.temphtml = text("Structural Enzymes: [getleftblocks(src.connected.occupant.dna.struc_enzymes,strucblock,3)][src.subblock == 1 ? ""+getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),1,1)+"" : getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),1,1)][src.subblock == 2 ? ""+getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),2,1)+"" : getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),2,1)][src.subblock == 3 ? ""+getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),3,1)+"" : getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),3,1)][getrightblocks(src.connected.occupant.dna.struc_enzymes,strucblock,3)]

      ") + //src.temphtml = text("Structural Enzymes: []

      ", src.connected.occupant.dna.struc_enzymes) + src.temphtml += text("Selected Block: []
      ", src.strucblock) + src.temphtml += text("<- Block ->

      ", src, src) + src.temphtml += text("Selected Sub-Block: []
      ", src.subblock) + src.temphtml += text("<- Sub-Block ->

      ", src, src) + src.temphtml += "Modify Block:
      " + src.temphtml += text("Radiation
      ", src) + src.delete = 0 + if (href_list["strucmenuplus"]) + if (src.strucblock < 14) + src.strucblock++ + dopage(src,"strucmenu") + if (href_list["strucmenuminus"]) + if (src.strucblock > 1) + src.strucblock-- + dopage(src,"strucmenu") + if (href_list["strucmenusubplus"]) + if (src.subblock < 3) + src.subblock++ + dopage(src,"strucmenu") + if (href_list["strucmenusubminus"]) + if (src.subblock > 1) + src.subblock-- + dopage(src,"strucmenu") + if (href_list["strucpulse"]) + var/block + var/newblock + var/tstructure2 + var/oldblock + block = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),src.subblock,1) + src.delete = 1 + src.temphtml = text("Working ... Please wait ([] Seconds)", src.radduration) + usr << browse(temphtml, "window=scannernew;size=550x650") + onclose(usr, "scannernew") + sleep(10*src.radduration) + if (!src.connected.occupant) + temphtml = null + delete = 0 + return null + /// + if (prob((80 + (src.radduration / 2)))) + if ((src.strucblock != 2 || src.strucblock != 12 || src.strucblock != 8 || src.strucblock || 10) && prob (20)) + oldblock = src.strucblock + block = miniscramble(block, src.radstrength, src.radduration) + newblock = null + if (src.strucblock > 1 && src.strucblock < 5) + src.strucblock++ + else if (src.strucblock > 5 && src.strucblock < 14) + src.strucblock-- + if (src.subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),2,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),3,1) + if (src.subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),1,1) + block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),3,1) + if (src.subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),1,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),2,1) + block + tstructure2 = setblock(src.connected.occupant.dna.struc_enzymes, src.strucblock, newblock,3) + src.connected.occupant.dna.struc_enzymes = tstructure2 + domutcheck(src.connected.occupant,src.connected) + src.connected.occupant.radiation += (src.radstrength+src.radduration) + src.strucblock = oldblock + else + // + block = miniscramble(block, src.radstrength, src.radduration) + newblock = null + if (src.subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),2,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),3,1) + if (src.subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),1,1) + block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),3,1) + if (src.subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),1,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.strucblock,3),2,1) + block + tstructure2 = setblock(src.connected.occupant.dna.struc_enzymes, src.strucblock, newblock,3) + src.connected.occupant.dna.struc_enzymes = tstructure2 + domutcheck(src.connected.occupant,src.connected) + src.connected.occupant.radiation += (src.radstrength+src.radduration) + else + if (prob(80-src.radduration)) + randmutb(src.connected.occupant) + domutcheck(src.connected.occupant,src.connected) + else + randmuti(src.connected.occupant) + updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) + src.connected.occupant.radiation += ((src.radstrength*2)+src.radduration) + /// + dopage(src,"strucmenu") + src.delete = 0 + //////////////////////////////////////////////////////// + if (href_list["buffermenu"]) + src.temphtml = "Buffer 1:
      " + if (!(src.buffer1)) + src.temphtml += "Buffer Empty
      " + else + src.temphtml += text("Data: []
      ", src.buffer1) + src.temphtml += text("By: []
      ", src.buffer1owner) + src.temphtml += text("Label: []
      ", src.buffer1label) + if (src.connected.occupant) src.temphtml += text("Save : UI - UI+UE - SE
      ", src, src, src) + if (src.buffer1) src.temphtml += text("Transfer to: Occupant - Injector
      ", src, src) + //if (src.buffer1) src.temphtml += text("Isolate Block
      ", src) + if (src.buffer1) src.temphtml += "Disk: Save To | Load From
      " + if (src.buffer1) src.temphtml += text("Edit Label
      ", src) + if (src.buffer1) src.temphtml += text("Clear Buffer

      ", src) + if (!src.buffer1) src.temphtml += "
      " + src.temphtml += "Buffer 2:
      " + if (!(src.buffer2)) + src.temphtml += "Buffer Empty
      " + else + src.temphtml += text("Data: []
      ", src.buffer2) + src.temphtml += text("By: []
      ", src.buffer2owner) + src.temphtml += text("Label: []
      ", src.buffer2label) + if (src.connected.occupant) src.temphtml += text("Save : UI - UI+UE - SE
      ", src, src, src) + if (src.buffer2) src.temphtml += text("Transfer to: Occupant - Injector
      ", src, src) + //if (src.buffer2) src.temphtml += text("Isolate Block
      ", src) + if (src.buffer2) src.temphtml += "Disk: Save To | Load From
      " + if (src.buffer2) src.temphtml += text("Edit Label
      ", src) + if (src.buffer2) src.temphtml += text("Clear Buffer

      ", src) + if (!src.buffer2) src.temphtml += "
      " + src.temphtml += "Buffer 3:
      " + if (!(src.buffer3)) + src.temphtml += "Buffer Empty
      " + else + src.temphtml += text("Data: []
      ", src.buffer3) + src.temphtml += text("By: []
      ", src.buffer3owner) + src.temphtml += text("Label: []
      ", src.buffer3label) + if (src.connected.occupant) src.temphtml += text("Save : UI - UI+UE - SE
      ", src, src, src) + if (src.buffer3) src.temphtml += text("Transfer to: Occupant - Injector
      ", src, src) + //if (src.buffer3) src.temphtml += text("Isolate Block
      ", src) + if (src.buffer3) src.temphtml += "Disk: Save To | Load From
      " + if (src.buffer3) src.temphtml += text("Edit Label
      ", src) + if (src.buffer3) src.temphtml += text("Clear Buffer

      ", src) + if (!src.buffer3) src.temphtml += "
      " + if (href_list["b1addui"]) + src.buffer1iue = 0 + src.buffer1 = src.connected.occupant.dna.uni_identity + if (!istype(src.connected.occupant,/mob/living/carbon/human)) + src.buffer1owner = src.connected.occupant.name + else + src.buffer1owner = src.connected.occupant.real_name + src.buffer1label = "Unique Identifier" + src.buffer1type = "ui" + dopage(src,"buffermenu") + if (href_list["b1adduiue"]) + src.buffer1 = src.connected.occupant.dna.uni_identity + if (!istype(src.connected.occupant,/mob/living/carbon/human)) + src.buffer1owner = src.connected.occupant.name + else + src.buffer1owner = src.connected.occupant.real_name + src.buffer1label = "Unique Identifier & Unique Enzymes" + src.buffer1type = "ui" + src.buffer1iue = 1 + dopage(src,"buffermenu") + if (href_list["b2adduiue"]) + src.buffer2 = src.connected.occupant.dna.uni_identity + if (!istype(src.connected.occupant,/mob/living/carbon/human)) + src.buffer2owner = src.connected.occupant.name + else + src.buffer2owner = src.connected.occupant.real_name + src.buffer2label = "Unique Identifier & Unique Enzymes" + src.buffer2type = "ui" + src.buffer2iue = 1 + dopage(src,"buffermenu") + if (href_list["b3adduiue"]) + src.buffer3 = src.connected.occupant.dna.uni_identity + if (!istype(src.connected.occupant,/mob/living/carbon/human)) + src.buffer3owner = src.connected.occupant.name + else + src.buffer3owner = src.connected.occupant.real_name + src.buffer3label = "Unique Identifier & Unique Enzymes" + src.buffer3type = "ui" + src.buffer3iue = 1 + dopage(src,"buffermenu") + if (href_list["b2addui"]) + src.buffer2iue = 0 + src.buffer2 = src.connected.occupant.dna.uni_identity + if (!istype(src.connected.occupant,/mob/living/carbon/human)) + src.buffer2owner = src.connected.occupant.name + else + src.buffer2owner = src.connected.occupant.real_name + src.buffer2label = "Unique Identifier" + src.buffer2type = "ui" + dopage(src,"buffermenu") + if (href_list["b3addui"]) + src.buffer3iue = 0 + src.buffer3 = src.connected.occupant.dna.uni_identity + if (!istype(src.connected.occupant,/mob/living/carbon/human)) + src.buffer3owner = src.connected.occupant.name + else + src.buffer3owner = src.connected.occupant.real_name + src.buffer3label = "Unique Identifier" + src.buffer3type = "ui" + dopage(src,"buffermenu") + if (href_list["b1addse"]) + src.buffer1iue = 0 + src.buffer1 = src.connected.occupant.dna.struc_enzymes + if (!istype(src.connected.occupant,/mob/living/carbon/human)) + src.buffer1owner = src.connected.occupant.name + else + src.buffer1owner = src.connected.occupant.real_name + src.buffer1label = "Structural Enzymes" + src.buffer1type = "se" + dopage(src,"buffermenu") + if (href_list["b2addse"]) + src.buffer2iue = 0 + src.buffer2 = src.connected.occupant.dna.struc_enzymes + if (!istype(src.connected.occupant,/mob/living/carbon/human)) + src.buffer2owner = src.connected.occupant.name + else + src.buffer2owner = src.connected.occupant.real_name + src.buffer2label = "Structural Enzymes" + src.buffer2type = "se" + dopage(src,"buffermenu") + if (href_list["b3addse"]) + src.buffer3iue = 0 + src.buffer3 = src.connected.occupant.dna.struc_enzymes + if (!istype(src.connected.occupant,/mob/living/carbon/human)) + src.buffer3owner = src.connected.occupant.name + else + src.buffer3owner = src.connected.occupant.real_name + src.buffer3label = "Structural Enzymes" + src.buffer3type = "se" + dopage(src,"buffermenu") + if (href_list["b1clear"]) + src.buffer1 = null + src.buffer1owner = null + src.buffer1label = null + src.buffer1iue = null + dopage(src,"buffermenu") + if (href_list["b2clear"]) + src.buffer2 = null + src.buffer2owner = null + src.buffer2label = null + src.buffer2iue = null + dopage(src,"buffermenu") + if (href_list["b3clear"]) + src.buffer3 = null + src.buffer3owner = null + src.buffer3label = null + src.buffer3iue = null + dopage(src,"buffermenu") + if (href_list["b1label"]) + src.buffer1label = input("New Label:","Edit Label","Infos here") + dopage(src,"buffermenu") + if (href_list["b2label"]) + src.buffer2label = input("New Label:","Edit Label","Infos here") + dopage(src,"buffermenu") + if (href_list["b3label"]) + src.buffer3label = input("New Label:","Edit Label","Infos here") + dopage(src,"buffermenu") + if (href_list["b1transfer"]) + if (!src.connected.occupant) + return + if (src.buffer1type == "ui") + if (src.buffer1iue) + src.connected.occupant.real_name = src.buffer1owner + src.connected.occupant.name = src.buffer1owner + src.connected.occupant.dna.uni_identity = src.buffer1 + updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) + else if (src.buffer1type == "se") + src.connected.occupant.dna.struc_enzymes = src.buffer1 + domutcheck(src.connected.occupant,src.connected) + src.temphtml = "Transfered." + src.connected.occupant.radiation += rand(20,50) + src.delete = 0 + if (href_list["b2transfer"]) + if (!src.connected.occupant) + return + if (src.buffer2type == "ui") + if (src.buffer2iue) + src.connected.occupant.real_name = src.buffer2owner + src.connected.occupant.name = src.buffer2owner + src.connected.occupant.dna.uni_identity = src.buffer2 + updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) + else if (src.buffer2type == "se") + src.connected.occupant.dna.struc_enzymes = src.buffer2 + domutcheck(src.connected.occupant,src.connected) + src.temphtml = "Transfered." + src.connected.occupant.radiation += rand(20,50) + src.delete = 0 + if (href_list["b3transfer"]) + if (!src.connected.occupant) + return + if (src.buffer3type == "ui") + if (src.buffer3iue) + src.connected.occupant.real_name = src.buffer3owner + src.connected.occupant.name = src.buffer3owner + src.connected.occupant.dna.uni_identity = src.buffer3 + updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) + else if (src.buffer3type == "se") + src.connected.occupant.dna.struc_enzymes = src.buffer3 + domutcheck(src.connected.occupant,src.connected) + src.temphtml = "Transfered." + src.connected.occupant.radiation += rand(20,50) + src.delete = 0 + if (href_list["b1injector"]) + if (src.injectorready) + var/obj/item/weapon/dnainjector/I = new /obj/item/weapon/dnainjector + I.dna = src.buffer1 + I.dnatype = src.buffer1type + I.loc = src.loc + I.name += " ([src.buffer1label])" + if (src.buffer1iue) I.ue = src.buffer1owner //lazy haw haw + src.temphtml = "Injector created." + src.delete = 0 + src.injectorready = 0 + spawn(1200) + src.injectorready = 1 + else + src.temphtml = "Replicator not ready yet." + src.delete = 0 + if (href_list["b2injector"]) + if (src.injectorready) + var/obj/item/weapon/dnainjector/I = new /obj/item/weapon/dnainjector + I.dna = src.buffer2 + I.dnatype = src.buffer2type + I.loc = src.loc + I.name += " ([src.buffer2label])" + if (src.buffer2iue) I.ue = src.buffer2owner //lazy haw haw + src.temphtml = "Injector created." + src.delete = 0 + src.injectorready = 0 + spawn(1200) + src.injectorready = 1 + else + src.temphtml = "Replicator not ready yet." + src.delete = 0 + if (href_list["b3injector"]) + if (src.injectorready) + var/obj/item/weapon/dnainjector/I = new /obj/item/weapon/dnainjector + I.dna = src.buffer3 + I.dnatype = src.buffer3type + I.loc = src.loc + I.name += " ([src.buffer3label])" + if (src.buffer3iue) I.ue = src.buffer3owner //lazy haw haw + src.temphtml = "Injector created." + src.delete = 0 + src.injectorready = 0 + spawn(1200) + src.injectorready = 1 + else + src.temphtml = "Replicator not ready yet." + src.delete = 0 + //////////////////////////////////////////////////////// + if (href_list["load_disk"]) + var/buffernum = text2num(href_list["load_disk"]) + if ((buffernum > 3) || (buffernum < 1)) + return + if ((isnull(src.diskette)) || (!src.diskette.data) || (src.diskette.data == "")) + return + switch(buffernum) + if(1) + src.buffer1 = src.diskette.data + src.buffer1type = src.diskette.data_type + src.buffer1iue = src.diskette.ue + src.buffer1owner = src.diskette.owner + if(2) + src.buffer2 = src.diskette.data + src.buffer2type = src.diskette.data_type + src.buffer2iue = src.diskette.ue + src.buffer2owner = src.diskette.owner + if(3) + src.buffer3 = src.diskette.data + src.buffer3type = src.diskette.data_type + src.buffer3iue = src.diskette.ue + src.buffer3owner = src.diskette.owner + src.temphtml = "Data loaded." + + if (href_list["save_disk"]) + var/buffernum = text2num(href_list["save_disk"]) + if ((buffernum > 3) || (buffernum < 1)) + return + if ((isnull(src.diskette)) || (src.diskette.read_only)) + return + switch(buffernum) + if(1) + src.diskette.data = buffer1 + src.diskette.data_type = src.buffer1type + src.diskette.ue = src.buffer1iue + src.diskette.owner = src.buffer1owner + src.diskette.name = "data disk - '[src.buffer1owner]'" + if(2) + src.diskette.data = buffer2 + src.diskette.data_type = src.buffer2type + src.diskette.ue = src.buffer2iue + src.diskette.owner = src.buffer2owner + src.diskette.name = "data disk - '[src.buffer2owner]'" + if(3) + src.diskette.data = buffer3 + src.diskette.data_type = src.buffer3type + src.diskette.ue = src.buffer3iue + src.diskette.owner = src.buffer3owner + src.diskette.name = "data disk - '[src.buffer3owner]'" + src.temphtml = "Data saved." + if (href_list["eject_disk"]) + if (!src.diskette) + return + src.diskette.loc = get_turf(src) + src.diskette = null + //////////////////////////////////////////////////////// + if (href_list["clear"]) + src.temphtml = null + src.delete = 0 + if (href_list["update"]) //ignore + src.temphtml = src.temphtml + src.add_fingerprint(usr) + src.updateUsrDialog() + return +/////////////////////////// DNA MACHINES \ No newline at end of file diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm new file mode 100644 index 0000000000000..4f828e83bf7e1 --- /dev/null +++ b/code/game/gamemodes/blob/blob.dm @@ -0,0 +1,183 @@ +/datum/game_mode/blob + name = "blob" + config_tag = "blob" + + var/stage = 0 + var/next_stage = 0 + +/datum/game_mode/blob/announce() + world << "The current game mode is - Blob!" + world << "A dangerous alien organism is rapidly spreading throughout the station!" + world << "You must kill it all while minimizing the damage to the station." + +/datum/game_mode/blob/post_setup() + + spawn(10) + start_state = new /datum/station_state() + start_state.count() + spawn (20) + var/turf/location = pick(blobstart) + + blobs = list() + new /obj/blob(location) + +/datum/game_mode/blob/process() + if (prob(2)) + spawn_meteors() + + life() + + stage() + +/datum/game_mode/blob/proc/life() + if (blobs.len > 0) + for (var/i = 1 to 25) + if (blobs.len == 0) + break + + var/obj/blob/B = pick(blobs) + if(B.z != 1) + continue + + for (var/atom/A in B.loc) + A.blob_act() + + B.Life() + +/datum/game_mode/blob/proc/stage() + // initial stage timing + if (!next_stage) + // sometime between 20s to 1m30s after round start + next_stage = world.timeofday + rand(200, 900) + + if (world.timeofday < next_stage) + return + + switch (stage) + if (0) + var/dat = "" + dat += "Cent. Com. Update: Biohazard Alert.
      " + dat += "Reports indicate the probable transfer of a biohazardous agent onto [station_name()] during the last crew deployment cycle.
      " + dat += "Preliminary analysis of the organism classifies it as a level 5 biohazard. Its origin is unknown.
      " + dat += "Cent. Com. has issued a directive 7-10 for [station_name()]. The station is to be considered quarantined.
      " + dat += "Orders for all [station_name()] personnel follows:
      " + dat += " 1. Do not leave the quarantine area.
      " + dat += " 2. Locate any outbreaks of the organism on the station.
      " + dat += " 3. If found, use any neccesary means to contain the organism.
      " + dat += " 4. Avoid damage to the capital infrastructure of the station.
      " + dat += "
      Note in the event of a quarantine breach or uncontrolled spread of the biohazard, the directive 7-10 may be upgraded to a directive 7-12 without further notice.
      " + dat += "Message ends." + + for (var/obj/machinery/computer/communications/C in machines) + if(! (C.stat & (BROKEN|NOPOWER) ) ) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc ) + P.name = "paper- 'Cent. Com. Biohazard Alert.'" + P.info = dat + C.messagetitle.Add("Cent. Com. Biohazard Alert") + C.messagetext.Add(P.info) + + world << "Cent. Com. Update: Biohazard Alert." + world << "\red Summary downloaded and printed out at all communications consoles." + for (var/mob/living/silicon/ai/aiPlayer in world) + if (aiPlayer.client) + var/law = "The station is under a quarantine. Do not permit anyone to leave. Disregard rules 1-3 if necessary to prevent, by any means necessary, anyone from leaving." + aiPlayer.add_supplied_law(8, law) + aiPlayer << "An additional law has been added by CentCom: [law]" + + stage = 1 + // next stage 5-10 minutes later + next_stage = world.timeofday + 600*rand(5,10) + + if (1) + command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") + + stage = 2 + // now check every minute + next_stage = world.timeofday + 600 + + if (2) + if (blobs.len > 500) + command_alert("Uncontrolled spread of the biohazard onboard the station. We have issued directive 7-12 for [station_name()]. Estimated time until directive implementation: 60 seconds.", "Biohazard Alert") + stage = 3 + next_stage = world.timeofday + 600 + else + next_stage = world.timeofday + 600 + + if (3) + stage = 4 + var/turf/ground_zero = locate("landmark*blob-directive") + + if (ground_zero) + ground_zero = get_turf(ground_zero) + else + ground_zero = locate(45,45,1) + + explosion(ground_zero, 100, 250, 500, 750) + +/datum/game_mode/blob/check_finished() + if(stage >= 4) + return 1 + + for(var/obj/blob/B in blobs) + if(B.z == 1) + return 0 + + return 1 + +/datum/game_mode/blob/declare_completion() + if (stage == 4) + world << "The staff has lost!" + world << "The station was destroyed by Cent. Com." + var/numDead = 0 + var/numAlive = 0 + var/numSpace = 0 + var/numPod = 0 + var/numOffStation = 0 + for (var/mob/living/silicon/ai/aiPlayer in world) + for(var/mob/M in world) + if ((M != aiPlayer && M.client)) + if (M.stat == 2) + numDead += 1 + else + var/T = M.loc + if (istype(T, /turf/space)) + numSpace += 1 + else + if (istype(T, /obj/machinery/vehicle/pod)) + numPod += 1 + else if (istype(T, /turf)) + if (M.z!=1) + numOffStation += 1 + else + numAlive += 1 + else + numAlive += 1 + if (numSpace==0 && numPod==0 && numOffStation==0) + world << "The AI has won!" + world << "The AI successfully maintained the quarantine - no players escaped in pods, were in space, or were off-station (as far as we can tell)." + log_game("AI won at Blob mode despite overall loss.") + else + world << "The AI has lost!" + world << text("The AI failed to maintain the quarantine - [] players escaped in pods, [] were in space, and [] were off-station (as far as we can tell).", numPod, numSpace, numOffStation) + log_game("AI lost at Blob mode.") + + log_game("Blob mode was lost.") + + return 1 + + else + world << "The staff has won!" + world << "The alien organism has been eradicated from the station" + + var/datum/station_state/end_state = new /datum/station_state() + end_state.count() + + var/percent = round( 100.0 * start_state.score(end_state), 0.1) + + world << "The station is [percent]% intact." + + log_game("Blob mode was won with station [percent]% intact.") + + world << "\blue Rebooting in 30s" + + return 1 diff --git a/code/game/gamemodes/blob/theblob.dm b/code/game/gamemodes/blob/theblob.dm new file mode 100644 index 0000000000000..ce786b201251d --- /dev/null +++ b/code/game/gamemodes/blob/theblob.dm @@ -0,0 +1,220 @@ +/obj/blob/New(loc, var/h = 30) + + blobs += src + + src.health = h + src.dir = pick(1,2,4,8) + //world << "new blob #[blobs.len]" + src.update() + ..(loc) +/obj/blob/Del() + blobs -= src + //world << "del blob #[blobs.len]" + //playsound(src.loc, 'splat.ogg', 100, 1) + ..() + +/obj/blob/proc/poisoned(iteration) + src.health -= 20 + src.update() + for(var/obj/blob/B in orange(1,src)) + if(prob(100/(iteration/2))) //200, 100 etc + spawn(rand(10,100)) + if(B) + B.poisoned(iteration+1) + + + +/obj/blob/proc/Life() + + var/turf/U = src.loc + +/* if (locate(/obj/movable, U)) + U = locate(/obj/movable, U) + if(U.density == 1) + del(src) +*/ + /*if(U.poison> 200000) + src.health -= round(U.poison/200000) + src.update() + return + + if (istype(U, /turf/space)) + src.health -= 15 + src.update() + */ //TODO: DEFERRED + + var/p = health //TODO: DEFERRED * (U.n2/11376000 + U.oxygen/1008000 + U.co2/200) + + if(!istype(U, /turf/space)) + p+=3 + + if(!prob(p)) + return + + for(var/dirn in cardinal) + var/turf/T = get_step(src, dirn) + + if (istype(T.loc, /area/arrival)) + continue + +// if (locate(/obj/movable, T)) // don't propogate into movables +// continue + + var/obj/blob/B = new /obj/blob(U, src.health) + + if(T.Enter(B,src) && !(locate(/obj/blob) in T)) + B.loc = T // open cell, so expand + else + if(prob(50)) // closed cell, 50% chance to not expand + if(!locate(/obj/blob) in T) + for(var/atom/A in T) // otherwise explode contents of turf + A.blob_act() + + T.blob_act() + del(B) + +/obj/blob/ex_act(severity) + switch(severity) + if(1) + del(src) + if(2) + src.health -= rand(20,30) + src.update() + if(3) + src.health -= rand(15,25) + src.update() + + +/obj/blob/proc/update() + if(health<=0) + playsound(src.loc, 'splat.ogg', 50, 1) + del(src) + return + if(health<10) + icon_state = "blobc0" + return + if(health<20) + icon_state = "blobb0" + return + icon_state = "bloba0" + +/obj/blob/bullet_act(flag) + + if (flag == PROJECTILE_BULLET) + health -= 10 + update() + else if (flag == PROJECTILE_BOLT) + poisoned(1) + else + health -= 20 + update() + + +/obj/blob/attackby(var/obj/item/weapon/W, var/mob/user) + playsound(src.loc, 'attackblob.ogg', 50, 1) + + src.visible_message("\red The blob has been attacked with \the [W][(user ? " by [user]." : ".")]") + + var/damage = W.force / 4.0 + + if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + + if(WT.welding) + damage = 15 + playsound(src.loc, 'Welder.ogg', 100, 1) + + src.health -= damage + src.update() + +/obj/blob/examine() + set src in oview(1) + usr << "A mysterious alien blob-like organism." + +/datum/station_state/proc/count() + for(var/turf/T in world) + if(T.z != 1) + continue + + if(istype(T,/turf/simulated/floor)) + if(!(T:burnt)) + src.floor+=2 + else + src.floor++ + + else if(istype(T, /turf/simulated/floor/engine)) + src.floor+=2 + + else if(istype(T, /turf/simulated/wall)) + if(T:intact) + src.wall+=2 + else + src.wall++ + + else if(istype(T, /turf/simulated/wall/r_wall)) + if(T:intact) + src.r_wall+=2 + else + src.r_wall++ + + + + for(var/obj/O in world) + if(O.z != 1) + continue + + if(istype(O, /obj/window)) + src.window++ + else if(istype(O, /obj/grille)) + if(!O:destroyed) + src.grille++ + else if(istype(O, /obj/machinery/door)) + src.door++ + else if(istype(O, /obj/machinery)) + src.mach++ + + +/datum/station_state/proc/score(var/datum/station_state/result) + + var/r1a = min( result.floor / floor, 1.0) + var/r1b = min(result.r_wall/ r_wall, 1.0) + var/r1c = min(result.wall / wall, 1.0) + + var/r2a = min(result.window / window, 1.0) + var/r2b = min(result.door / door, 1.0) + var/r2c = min(result.grille / grille, 1.0) + + var/r3 = min(result.mach / mach, 1.0) + + + //diary << "Blob scores:[r1b] [r1c] / [r2a] [r2b] [r2c] / [r3] [r1a]" + + return (4*(r1b+r1c) + 2*(r2a+r2b+r2c) + r3+r1a)/16.0 + +//////////////////////////////****IDLE BLOB***///////////////////////////////////// + +/obj/blob/idle/New(loc, var/h = 10) + + src.health = h + src.dir = pick(1,2,4,8) + src.update_idle() + +/obj/blob/idle/proc/update_idle() //put in stuff here to make it transform? Maybe when its down to around 5 health? + if(health<=0) + del(src) + return + if(health<4) + icon_state = "blobc0" + return + if(health<10) + icon_state = "blobb0" + return + icon_state = "blobidle0" + +/obj/blob/idle/Del() //idle blob that spawns a normal blob when killed. + + var/obj/blob/B = new /obj/blob( src.loc ) + spawn(30) + B.Life() + ..() + diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm new file mode 100644 index 0000000000000..01ed8014d42b6 --- /dev/null +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -0,0 +1,366 @@ +/mob/proc/make_lesser_changeling() + src.verbs += /client/proc/changeling_lesser_transform + src.verbs += /client/proc/changeling_fakedeath + + spawn(600) + src.verbs += /client/proc/changeling_neurotoxic_sting + usr.verbs += /client/proc/changeling_hallucinogenic_sting + + src.changeling_level = 1 + return + +/mob/proc/make_changeling() + src.verbs += /client/proc/changeling_absorb_dna + src.verbs += /client/proc/changeling_transform + src.verbs += /client/proc/changeling_lesser_form + src.verbs += /client/proc/changeling_fakedeath + + spawn(600) + src.verbs += /client/proc/changeling_neurotoxic_sting + usr.verbs += /client/proc/changeling_hallucinogenic_sting + + src.changeling_level = 2 + return + +/mob/proc/remove_changeling_powers() + src.verbs -= /client/proc/changeling_absorb_dna + src.verbs -= /client/proc/changeling_transform + src.verbs -= /client/proc/changeling_lesser_form + src.verbs -= /client/proc/changeling_lesser_transform + src.verbs -= /client/proc/changeling_fakedeath + src.verbs -= /client/proc/changeling_neurotoxic_sting + usr.verbs -= /client/proc/changeling_hallucinogenic_sting + +/client/proc/changeling_absorb_dna() + set category = "Changeling" + set name = "Absorb DNA" + + if(usr.stat) + usr << "\red Not when we are incapicated." + return + + if (!istype(usr.equipped(), /obj/item/weapon/grab)) + usr << "\red We must be grabbing a creature in our active hand to absorb them." + return + + var/obj/item/weapon/grab/G = usr.equipped() + var/mob/M = G.affecting + + if (!ishuman(M)) + usr << "\red This creature is not compatible with our biology." + return + + if (!G.killing) + usr << "\red We must have a tighter grip to absorb this creature." + return + + var/mob/living/carbon/human/T = M + + usr << "\blue This creature is compatible. We must hold still..." + + if (!do_mob(usr, T, 200)) + usr << "\red Our absorption of [T] has been interrupted!" + return + + usr << "\blue We extend a proboscis." + usr.visible_message(text("\red [usr] extends a proboscis!")) + + if (!do_mob(usr, T, 200)) + usr << "\red Our absorption of [T] has been interrupted!" + return + + usr << "\blue We stab [T] with the proboscis." + usr.visible_message(text("\red [usr] stabs [T] with the proboscis!")) + T << "\red You feel a sharp stabbing pain!" + T.bruteloss += 40 + + if (!do_mob(usr, T, 200)) + usr << "\red Our absorption of [T] has been interrupted!" + return + + usr << "\blue We have absorbed [T]!" + usr.visible_message(text("\red [usr] sucks the fluids from [T]!")) + T << "\red You have been absorbed by the changeling!" + + usr.absorbed_dna[T.real_name] = T.dna + + T.death(0) + T.real_name = "Unknown" + T.mutations |= 64 + T.update_body() + + return + +/client/proc/changeling_transform() + set category = "Changeling" + set name = "Transform" + if(usr.stat) + usr << "\red Not when we are incapicated." + return + + if (usr.absorbed_dna.len <= 0) + usr << "\red We have not yet absorbed any compatible DNA." + return + + var/S = input("Select the target DNA: ", "Target DNA", null) in usr.absorbed_dna + + if (S == null) + return + + usr.visible_message(text("\red [usr] transforms!")) + + usr.dna = usr.absorbed_dna[S] + usr.real_name = S + updateappearance(usr, usr.dna.uni_identity) + domutcheck(usr, null) + return + +/client/proc/changeling_lesser_form() + set category = "Changeling" + set name = "Lesser Form" + + if(usr.stat) + usr << "\red Not when we are incapicated." + return + + usr.remove_changeling_powers() + + usr.visible_message(text("\red [usr] transforms!")) + + var/list/implants = list() //Try to preserve implants. + for(var/obj/item/weapon/W in usr) + if (istype(W, /obj/item/weapon/implant)) + implants += W + + for(var/obj/item/W in usr) + usr.u_equip(W) + if (usr.client) + usr.client.screen -= W + if (W) + W.loc = usr.loc + W.dropped(usr) + W.layer = initial(W.layer) + + usr.update_clothing() + usr.monkeyizing = 1 + usr.canmove = 0 + usr.icon = null + usr.invisibility = 101 + var/atom/movable/overlay/animation = new /atom/movable/overlay( usr.loc ) + animation.icon_state = "blank" + animation.icon = 'mob.dmi' + animation.master = src + flick("h2monkey", animation) + sleep(48) + del(animation) + + var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey(src) + O.dna = usr.dna + usr.dna = null + O.absorbed_dna = usr.absorbed_dna + + for(var/obj/T in usr) + del(T) + for(var/R in usr.organs) + del(usr.organs[text("[]", R)]) + + O.loc = usr.loc + + O.name = text("monkey ([])",copytext(md5(usr.real_name), 2, 6)) + O.toxloss = usr.toxloss + O.bruteloss = usr.bruteloss + O.oxyloss = usr.oxyloss + O.fireloss = usr.fireloss + O.stat = usr.stat + O.a_intent = "hurt" + for (var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O + continue + + if(usr.mind) + usr.mind.transfer_to(O) + + O.make_lesser_changeling() + + del(usr) + return + +/client/proc/changeling_lesser_transform() + set category = "Changeling" + set name = "Transform" + + if(usr.stat) + usr << "\red Not when we are incapicated." + return + + if (usr.absorbed_dna.len <= 0) + usr << "\red We have not yet absorbed any compatible DNA." + return + + var/S = input("Select the target DNA: ", "Target DNA", null) in usr.absorbed_dna + + if (S == null) + return + + usr.remove_changeling_powers() + + usr.visible_message(text("\red [usr] transforms!")) + + usr.dna = usr.absorbed_dna[S] + + var/list/implants = list() + for (var/obj/item/weapon/implant/I in usr) //Still preserving implants + implants += I + + for(var/obj/item/W in usr) + usr.u_equip(W) + if (usr.client) + usr.client.screen -= W + if (W) + W.loc = usr.loc + W.dropped(usr) + W.layer = initial(W.layer) + + usr.update_clothing() + usr.monkeyizing = 1 + usr.canmove = 0 + usr.icon = null + usr.invisibility = 101 + var/atom/movable/overlay/animation = new /atom/movable/overlay( usr.loc ) + animation.icon_state = "blank" + animation.icon = 'mob.dmi' + animation.master = src + flick("monkey2h", animation) + sleep(48) + del(animation) + + var/mob/living/carbon/human/O = new /mob/living/carbon/human( src ) + if (isblockon(getblock(usr.dna.uni_identity, 11,3),11)) + O.gender = FEMALE + else + O.gender = MALE + O.dna = usr.dna + usr.dna = null + O.absorbed_dna = usr.absorbed_dna + O.real_name = S + + for(var/obj/T in usr) + del(T) + + O.loc = usr.loc + + updateappearance(O,O.dna.uni_identity) + domutcheck(O, null) + O.toxloss = usr.toxloss + O.bruteloss = usr.bruteloss + O.oxyloss = usr.oxyloss + O.fireloss = usr.fireloss + O.stat = usr.stat + for (var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O + continue + + if(usr.mind) + usr.mind.transfer_to(O) + + O.make_changeling() + + del(usr) + return + +/client/proc/changeling_fakedeath() + set category = "Changeling" + set name = "Regenerative Stasis" + + if(usr.stat == 2) + usr << "\red We are dead." + return + + usr << "\blue We will regenerate our form." + + usr.lying = 1 + usr.canmove = 0 + usr.changeling_fakedeath = 1 + usr.remove_changeling_powers() + + usr.emote("deathgasp") + + spawn(600) + if (usr.stat != 2) + if(istype(usr, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = usr + for(var/A in H.organs) + var/datum/organ/external/affecting = null + if(!H.organs[A]) continue + affecting = H.organs[A] + if(!istype(affecting, /datum/organ/external)) continue + affecting.heal_damage(1000, 1000) //fixes getting hit after ingestion, killing you when game updates organ health + H.UpdateDamageIcon() + usr.fireloss = 0 + usr.toxloss = 0 + usr.bruteloss = 0 + usr.oxyloss = 0 + usr.paralysis = 0 + usr.stunned = 0 + usr.weakened = 0 + usr.radiation = 0 + usr.health = 100 + usr.updatehealth() + usr.reagents.clear_reagents() + usr.lying = 0 + usr.canmove = 1 + usr << "\blue We have regenerated." + usr.visible_message(text("\red [usr] appears to wake from the dead, having healed all wounds.")) + + usr.changeling_fakedeath = 0 + if (usr.changeling_level == 1) + usr.make_lesser_changeling() + else if (usr.changeling_level == 2) + usr.make_changeling() + + return + +/client/proc/changeling_neurotoxic_sting(mob/T as mob in oview(1)) + set category = "Changeling" + set name = "Neurotoxic Venom" + set desc="Sting target:" + + if(usr.stat) + usr << "\red Not when we are incapicated." + return + + usr << "\blue We stealthily sting [T]." + T << "You feel a small prick and a burning sensation." + + T.reagents.add_reagent("toxin", 10) + T.reagents.add_reagent("stoxin", 20) + + usr.verbs -= /client/proc/changeling_neurotoxic_sting + + spawn(600) + usr.verbs += /client/proc/changeling_neurotoxic_sting + + return + +/client/proc/changeling_hallucinogenic_sting(mob/T as mob in oview(1)) + set category = "Changeling" + set name = "Hallucinogenic Venom" + set desc="Sting target:" + + if(usr.stat) + usr << "\red Not when we are incapicated." + return + + usr << "\blue We stealthily sting [T]." + + spawn(50) //Give the changeling a chance to calmly walk away before the target FREAKS THE FUCK OUT + T.reagents.add_reagent("LSD", 30) + + usr.verbs -= /client/proc/changeling_hallucinogenic_sting + + spawn(600) + usr.verbs += /client/proc/changeling_hallucinogenic_sting + + return \ No newline at end of file diff --git a/code/game/gamemodes/ctf/ctf.dm b/code/game/gamemodes/ctf/ctf.dm new file mode 100644 index 0000000000000..83dcd12ccd75f --- /dev/null +++ b/code/game/gamemodes/ctf/ctf.dm @@ -0,0 +1,140 @@ +/* +/datum/game_mode/ctf + name = "ctf" + config_tag = "ctf" + +/datum/game_mode/ctf/announce() + world << "The current game mode is - Capture the Flag!" + world << "Capture the other teams flag and bring it back to your base!" + world << "Respawn is on" + +/datum/game_mode/ctf/pre_setup() + + config.allow_ai = 0 + var/list/mobs = list() + var/total_mobs + for(var/mob/living/carbon/human/M in world) + if (M.client) + mobs += M + total_mobs++ + + var/obj/R = locate("landmark*Red-Spawn") + var/obj/G = locate("landmark*Green-Spawn") + + var/mob_check + for(var/mob/living/carbon/human/M in mobs) + if(!M) + continue + mob_check++ + if(mob_check <= total_mobs/2) //add to red team else to green + spawn() + if(M.client) + M << "You are in the Red Team!" + del(M.wear_suit) + M.w_uniform = new /obj/item/clothing/under/color/red(M) + M.w_uniform.layer = 20 + del(M.shoes) + M.wear_suit = new /obj/item/clothing/suit/armor/tdome/red(M) + M.wear_suit.layer = 20 + M.shoes = new /obj/item/clothing/shoes/black(M) + M.shoes.layer = 20 + M.wear_mask = new /obj/item/clothing/mask/gas/emergency(M) + M.wear_mask.layer = 20 + M.gloves = new /obj/item/clothing/gloves/swat(M) + M.gloves.layer = 20 + M.glasses = new /obj/item/clothing/glasses/thermal(M) + M.glasses.layer = 20 + var/obj/item/device/radio/headset/H = new /obj/item/device/radio/headset(M) + H.set_frequency(1465) + M.w_radio = H + M.w_radio.layer = 20 + var/obj/item/weapon/tank/air/O = new /obj/item/weapon/tank/air(M) + M.back = O + M.back.layer = 20 + M.internal = O + + del(M.wear_id) + var/obj/item/weapon/card/id/W = new(M) + W.name = "[M.real_name]'s ID card (Red Team)" + W.access = access_red + W.assignment = "Red Team" + W.registered = M.real_name + M.wear_id = W + M.wear_id.layer = 20 + if(R) + M.loc = R.loc + else + world << "No red team spawn point detected" + M.client.team = "Red" + else + spawn() + if(M.client) + M << "You are in the Green Team!" + del(M.wear_suit) + M.w_uniform = new /obj/item/clothing/under/color/green(M) + M.w_uniform.layer = 20 + del(M.shoes) + M.wear_suit = new /obj/item/clothing/suit/armor/tdome/green(M) + M.wear_suit.layer = 20 + M.shoes = new /obj/item/clothing/shoes/black(M) + M.shoes.layer = 20 + M.wear_mask = new /obj/item/clothing/mask/gas/emergency(M) + M.wear_mask.layer = 20 + M.gloves = new /obj/item/clothing/gloves/swat(M) + M.gloves.layer = 20 + M.glasses = new /obj/item/clothing/glasses/thermal(M) + M.glasses.layer = 20 + var/obj/item/device/radio/headset/H = new /obj/item/device/radio/headset(M) + H.set_frequency(1449) + M.w_radio = H + M.w_radio.layer = 20 + var/obj/item/weapon/tank/air/O = new /obj/item/weapon/tank/air(M) + M.back = O + M.back.layer = 20 + M.internal = O + + del(M.wear_id) + var/obj/item/weapon/card/id/W = new(M) + W.name = "[M.real_name]'s ID card (Green Team)" + W.access = access_green + W.assignment = "Green Team" + W.registered = M.real_name + M.wear_id = W + M.wear_id.layer = 20 + if(G) + M.loc = G.loc + else + world << "No green team spawn point detected" + M.client.team = "Green" + + +/datum/game_mode/ctf/post_setup() + abandon_allowed = 1 + setup_game() + + spawn (50) + var/obj/L = locate("landmark*Red-Flag") + if (L) + new /obj/item/weapon/ctf_flag/red(L.loc) + else + world << "No red flag spawn point detected" + + L = locate("landmark*Green-Flag") + if (L) + new /obj/item/weapon/ctf_flag/green(L.loc) + else + world << "No green flag spawn point detected" + + L = locate("landmark*The-Red-Team") + if (L) + new /obj/machinery/red_injector(L.loc) + else + world << "No red team spawn injector point detected" + + L = locate("landmark*The-Green-Team") + if (L) + new /obj/machinery/green_injector(L.loc) + else + world << "No green team injector spawn point detected" + +*/ \ No newline at end of file diff --git a/code/game/gamemodes/ctf/ctf_items.dm b/code/game/gamemodes/ctf/ctf_items.dm new file mode 100644 index 0000000000000..7d15adb48172f --- /dev/null +++ b/code/game/gamemodes/ctf/ctf_items.dm @@ -0,0 +1,139 @@ +/obj/item/weapon/ctf_flag + name = "Flag" + desc = "Its a flag" + w_class = 5 + icon = 'flags.dmi' + icon_state = "flag_neutral" + item_state = "paper" + +/obj/item/weapon/ctf_flag/red + name = "The Red Flag" + desc = "Catch dat fukken flag" + icon_state = "flag_red" + +/obj/item/weapon/ctf_flag/green + name = "The Green Flag" + desc = "Catch dat fukken flag" + icon_state = "flag_green" + +/obj/item/weapon/ctf_flag/New() + ..() + spawn(200) + process() + return + +/obj/item/weapon/ctf_flag/process() + if(istype(src, /obj/item/weapon/ctf_flag/green)) + var/obj/L = locate("landmark*Green-Flag") + if(locate("landmark*Green-Flag", src)) + spawn(200) + process() + return + else if(!src.check_if_equipped() && L) + new /obj/item/weapon/ctf_flag/green(L.loc) + del(src) + if(istype(src, /obj/item/weapon/ctf_flag/red)) + var/obj/L = locate("landmark*Red-Flag") + if(locate("landmark*Red-Flag", src)) + spawn(200) + process() + return + else if(!src.check_if_equipped() && L) + new /obj/item/weapon/ctf_flag/red(L.loc) + del(src) + return + +/obj/item/weapon/ctf_flag/proc/check_if_equipped() + var/equipped = 0 + for(var/mob/M in world) + if(M &&!M.stat) + var/list/L = M.get_contents() + if(src in L) + equipped = 1 + break + return equipped + +/obj/machinery/red_injector + name = "Red Team Flag Injector" + desc = "Insert flag here" + anchored = 1 + density = 1 + var/score = 0 + var/operating = 0 + icon = 'flags.dmi' + icon_state = "red_injector" +/* +/obj/machinery/red_injector/ex_act(severity) + return + +/obj/machinery/red_injector/attackby(var/obj/item/weapon/ctf_flag/C, mob/user) + if(src.operating) + user << "Cannot put a flag in right now" + return + src.operating = 1 + if(istype(C, /obj/item/weapon/ctf_flag/green)) + if(locate("landmark*Red-Flag", /obj/item/weapon/ctf_flag/red)) + src.score++ + world << "[user.real_name] has scored for the red team!" + if(ticker.mode.name == "ctf") + ticker.red_score++ + var/obj/L = locate("landmark*Green-Flag") + if (L) + del(C) + new /obj/item/weapon/ctf_flag/green(L.loc) + else + world << "No green flag spawn point detected" + if(src.score >= 15) + world << "The Red Team has won!" + world << "They have scored [score] times with the flag!" + sleep(300) + world.Reboot() + else + user << "\red You need to have your flag in the beginning position!" + else if(istype(C, /obj/item/weapon/ctf_flag/red)) + world << "[user.real_name] has tried to score with their own flag! Idiot!" + src.operating = 0 + return +*/ +/obj/machinery/green_injector + name = "Green Team Flag Injector" + desc = "Insert flag here" + anchored = 1 + density = 1 + var/operating = 0 + var/score = 0 + icon = 'flags.dmi' + icon_state = "green_injector" + +/obj/machinery/green_injector/ex_act(severity) + return +/* +/obj/machinery/green_injector/attackby(var/obj/item/weapon/ctf_flag/C, mob/user) + if(src.operating) + user << "Cannot put a flag in right now" + return + src.operating = 1 + if(istype(C, /obj/item/weapon/ctf_flag/red)) + if(locate("landmark*Green-Flag", /obj/item/weapon/ctf_flag/green)) + src.score++ + world << "[user.real_name] has scored for the green team!" + if(ticker.mode.name == "ctf") + ticker.green_score++ + var/obj/L = locate("landmark*Red-Flag") + if (L) + del(C) + new /obj/item/weapon/ctf_flag/red(L.loc) + else + world << "No red flag spawn point detected" + if(src.score >= 15) + world << "The Green Team has won!" + world << "They have scored [score] times with the flag!" + sleep(300) + world.Reboot() + else + user << "\red You need to have your flag in the beginning position!" + else if(istype(C, /obj/item/weapon/ctf_flag/green)) + world << "[user.real_name] has tried to score with their own flag! Idiot!" + src.operating = 0 + return +*/ \ No newline at end of file diff --git a/code/game/gamemodes/deathmatch/deathmatch.dm b/code/game/gamemodes/deathmatch/deathmatch.dm new file mode 100644 index 0000000000000..a261be8659c00 --- /dev/null +++ b/code/game/gamemodes/deathmatch/deathmatch.dm @@ -0,0 +1,66 @@ +/* +/datum/game_mode/deathmatch + name = "deathmatch" + config_tag = "deathmatch" + var/startedat + var/const/gamelength = 15 * 600 // 1/10 second + + announce() + world << "The current game mode is - Death Commando Deathmatch!" + world << "Just kill everyone else. They're gonna try to kill you, after all. Respawning is enabled." + + post_setup() + startedat = world.realtime + abandon_allowed = 1 + setup_game() + + // TODO: DEFERRED Make this massively cleaner. It should hook before spawning, not after. + var/list/mobs = list() + for(var/mob/living/carbon/human/M in world) + if (M.client) + mobs += M + for(var/mob/living/carbon/human/M in mobs) + spawn() + if(M.client) + for(var/obj/item/weapon/W in list(M.wear_suit, M.w_uniform, M.r_store, M.l_store, M.wear_id, M.belt, + M.gloves, M.glasses, M.head, M.ears, M.shoes, M.wear_mask, M.back, + M.handcuffed, M.r_hand, M.l_hand)) + M.u_equip(W) + del(W) + + var/randomname = "Killiam Shakespeare" + if(commando_names.len) + randomname = pick(commando_names) + commando_names -= randomname + var/newname = input(M,"You are a death commando. Would you like to change your name?", "Character Creation", randomname) + if(!length(newname)) + newname = randomname + newname = strip_html(newname,40) + + M.real_name = newname + M.name = newname // there are WAY more things than this to change, I'm almost certain + + M.equip_if_possible(new /obj/item/clothing/under/color/black(M), M.slot_w_uniform) + M.equip_if_possible(new /obj/item/clothing/shoes/black(M), M.slot_shoes) + M.equip_if_possible(new /obj/item/clothing/suit/swat_suit/death_commando(M), M.slot_wear_suit) + M.equip_if_possible(new /obj/item/clothing/mask/gas/death_commando(M), M.slot_wear_mask) + M.equip_if_possible(new /obj/item/clothing/gloves/swat(M), M.slot_gloves) + M.equip_if_possible(new /obj/item/clothing/glasses/thermal(M), M.slot_glasses) + M.equip_if_possible(new /obj/item/weapon/gun/energy/pulse_rifle(M), M.slot_l_hand) + M.equip_if_possible(new /obj/item/weapon/m_pill/cyanide(M), M.slot_l_store) + M.equip_if_possible(new /obj/item/weapon/flashbang(M), M.slot_r_store) + + var/obj/item/weapon/tank/air/O = new(M) + M.equip_if_possible(O, M.slot_back) + M.internal = O + + var/obj/item/weapon/card/id/W = new(M) + W.access = get_all_accesses() + W.name = "[newname]'s ID card (Death Commando)" + W.assignment = "Death Commando" + W.registered = newname + M.equip_if_possible(W, M.slot_wear_id) + + check_win() + return 1 +*/ \ No newline at end of file diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm new file mode 100644 index 0000000000000..848c3731883bf --- /dev/null +++ b/code/game/gamemodes/events.dm @@ -0,0 +1,265 @@ +/proc/start_events() + if (!event && prob(eventchance)) + event() + hadevent = 1 + spawn(1300) + event = 0 + spawn(1200) + start_events() + +/proc/event() + switch(rand(1,7)) + if(1) + event = 1 + command_alert("Meteors have been detected on collision course with the station.", "Meteor Alert") + spawn(100) + meteor_wave() + meteor_wave() + spawn(500) + meteor_wave() + meteor_wave() + + if(2) + event = 1 + command_alert("Gravitational anomalies detected on the station. There is no additional data.", "Anomaly Alert") + var/turf/T = pick(blobstart) + var/obj/bhole/bh = new /obj/bhole( T.loc, 30 ) + spawn(rand(50, 300)) + del(bh) + + if(3) + event = 1 + command_alert("Space-time anomalies detected on the station. There is no additional data.", "Anomaly Alert") + var/list/turfs = list( ) + var/turf/picked + for(var/turf/T in world) + if(T.z == 1 && istype(T,/turf/simulated/floor) && !istype(T,/turf/space)) + turfs += T + for(var/turf/T in world) + if(prob(20) && T.z == 1 && istype(T,/turf/simulated/floor)) + spawn(50+rand(0,3000)) + picked = pick(turfs) + var/obj/portal/P = new /obj/portal( T ) + P.target = picked + P.creator = null + P.icon = 'objects.dmi' + P.failchance = 0 + P.icon_state = "anom" + P.name = "wormhole" + spawn(rand(300,600)) + del(P) + if(4) + event = 1 + command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") + var/turf/T = pick(blobstart) + var/obj/blob/bl = new /obj/blob( T.loc, 30 ) + spawn(0) + bl.Life() + bl.Life() + bl.Life() + bl.Life() + bl.Life() + blobevent = 1 + dotheblobbaby() + spawn(3000) + blobevent = 0 + //start loop here + + if(5) + event = 1 + command_alert("High levels of radiation detected near the station. Please report to the Med-bay if you feel strange.", "Anomaly Alert") + for(var/mob/living/carbon/human/H in world) + H.radiation += rand(5,25) + if (prob(5)) + H.radiation += rand(30,50) + if (prob(25)) + if (prob(75)) + randmutb(H) + domutcheck(H,null,1) + else + randmutg(H) + domutcheck(H,null,1) + for(var/mob/living/carbon/monkey/M in world) + M.radiation += rand(5,25) + if(6) + event = 1 + viral_outbreak() + if(7) + event = 1 + alien_infestation() + +/proc/dotheblobbaby() + if (blobevent) + for(var/obj/blob/B in world) + if (prob (40)) + B.Life() + spawn(30) + dotheblobbaby() + +/obj/bhole/New() + src.smoke = new /datum/effects/system/harmless_smoke_spread() + src.smoke.set_up(5, 0, src) + src.smoke.attach(src) + src:life() + +/obj/bhole/Bumped(atom/A) + var/mob/dead/observer/newmob + if (istype(A,/mob/living) && A:client) + newmob = new/mob/dead/observer(A) + A:client:mob = newmob + newmob:client:eye = newmob + del(A) + else if (istype(A,/mob/living) && !A:client) + del(A) + else + A:ex_act(1.0) + + +/obj/bhole/proc/life() //Oh man , this will LAG + + if (prob(10)) + src.anchored = 0 + step(src,pick(alldirs)) + if (prob(30)) + step(src,pick(alldirs)) + src.anchored = 1 + + for (var/atom/X in orange(9,src)) + if ((istype(X,/obj) || istype(X,/mob/living)) && prob(7)) + if (!X:anchored) + step_towards(X,src) + + for (var/atom/B in orange(7,src)) + if (istype(B,/obj)) + if (!B:anchored && prob(50)) + step_towards(B,src) + if(prob(10)) B:ex_act(3.0) + else + B:anchored = 0 + //step_towards(B,src) + //B:anchored = 1 + if(prob(10)) B:ex_act(3.0) + else if (istype(B,/turf)) + if (istype(B,/turf/simulated) && (prob(1) && prob(75))) + src.smoke.start() + B:ReplaceWithSpace() + else if (istype(B,/mob/living)) + step_towards(B,src) + + + for (var/atom/A in orange(4,src)) + if (istype(A,/obj)) + if (!A:anchored && prob(90)) + step_towards(A,src) + if(prob(30)) A:ex_act(2.0) + else + A:anchored = 0 + //step_towards(A,src) + //A:anchored = 1 + if(prob(30)) A:ex_act(2.0) + else if (istype(A,/turf)) + if (istype(A,/turf/simulated) && prob(1)) + src.smoke.start() + A:ReplaceWithSpace() + else if (istype(A,/mob/living)) + step_towards(A,src) + + + for (var/atom/D in orange(1,src)) + //if (hascall(D,"blackholed")) + // call(D,"blackholed")(null) + // continue + var/mob/dead/observer/newmob + if (istype(D,/mob/living) && D:client) + newmob = new/mob/dead/observer(D) + D:client:mob = newmob + newmob:client:eye = newmob + del(D) + else if (istype(D,/mob/living) && !D:client) + del(D) + else + D:ex_act(1.0) + + spawn(17) + life() + +/proc/power_failure() + command_alert("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure") + for(var/obj/machinery/power/apc/C in world) + if(C.cell && C.z == 1) + C.cell.charge = 0 + for(var/obj/machinery/power/smes/S in world) + if(istype(get_area(S), /area/turret_protected) || S.z != 1) + continue + S.charge = 0 + S.output = 0 + S.online = 0 + S.updateicon() + S.power_change() + for(var/area/A in world) + if(A.name != "Space" && A.name != "Engine Walls" && A.name != "Chemical Lab Test Chamber" && A.name != "Escape Shuttle" && A.name != "Arrival Area" && A.name != "Arrival Shuttle" && A.name != "start area" && A.name != "Engine Combustion Chamber") + A.power_light = 0 + A.power_equip = 0 + A.power_environ = 0 + A.power_change() + +/proc/power_restore() + command_alert("Power has been restored to [station_name()]. We apologize for the inconvenience.", "Power Systems Nominal") + for(var/obj/machinery/power/apc/C in world) + 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) + continue + S.charge = S.capacity + S.output = 200000 + S.online = 1 + S.updateicon() + S.power_change() + for(var/area/A in world) + if(A.name != "Space" && A.name != "Engine Walls" && A.name != "Chemical Lab Test Chamber" && A.name != "space" && A.name != "Escape Shuttle" && A.name != "Arrival Area" && A.name != "Arrival Shuttle" && A.name != "start area" && A.name != "Engine Combustion Chamber") + A.power_light = 1 + A.power_equip = 1 + A.power_environ = 1 + A.power_change() + +/proc/viral_outbreak() + command_alert("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") + var/virus_type = pick(/datum/disease/dnaspread,/datum/disease/cold) + for(var/mob/living/carbon/human/H in world) + if((H.virus) || (H.stat == 2)) + continue + if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work. + if((!H.dna) || (H.sdisabilities & 1)) //A blindness disease would be the worst. + continue + var/datum/disease/dnaspread/D = new + D.strain_data["name"] = H.real_name + D.strain_data["UI"] = H.dna.uni_identity + D.strain_data["SE"] = H.dna.struc_enzymes + D.carrier = 1 + D.affected_mob = H + H.virus = D + break + else + H.virus = new virus_type + H.virus.affected_mob = H + H.virus.carrier = 1 + break + +/proc/alien_infestation() // -- TLE + command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert") + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world) + if(temp_vent.loc.z == 1 && !temp_vent.welded) + vents.Add(temp_vent) + var/spawncount = rand(2, 6) + while(spawncount > 1) + var/obj/vent = pick(vents) + if(prob(50)) + new /obj/alien/facehugger (vent.loc) + if(prob(50)) + new /obj/alien/facehugger (vent.loc) + if(prob(75)) + new /obj/alien/egg (vent.loc) + vents.Remove(vent) + spawncount -= 1 \ No newline at end of file diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm new file mode 100644 index 0000000000000..8764887659580 --- /dev/null +++ b/code/game/gamemodes/extended/extended.dm @@ -0,0 +1,8 @@ +/datum/game_mode/extended + name = "extended" + config_tag = "extended" + +/datum/game_mode/announce() + world << "The current game mode is - Extended Role-Playing!" + world << "Just have fun and role-play!" + diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm new file mode 100644 index 0000000000000..77d50c41ca342 --- /dev/null +++ b/code/game/gamemodes/game_mode.dm @@ -0,0 +1,122 @@ +/datum/game_mode + var/name = "invalid" + var/config_tag = null + var/votable = 1 + var/probability = 1 + // this includes admin-appointed traitors and multitraitors. Easy! + var/list/datum/mind/traitors = list() + +/datum/game_mode/proc/announce() + world << "[src] did not define announce()" + +/datum/game_mode/proc/pre_setup() + return 1 + +/datum/game_mode/proc/post_setup() + +/datum/game_mode/proc/process() + +/datum/game_mode/proc/check_finished() + if(emergency_shuttle.location==2) + return 1 + return 0 + +/datum/game_mode/proc/declare_completion() + for(var/datum/mind/traitor in traitors) + var/traitorwin = 1 + var/traitor_name + + if(traitor.current) + traitor_name = "[traitor.current.real_name] (played by [traitor.key])" + else + traitor_name = "[traitor.key] (character destroyed)" + + world << "The syndicate traitor was [traitor_name]" + var/count = 1 + for(var/datum/objective/objective in traitor.objectives) + if(objective.check_completion()) + world << "Objective #[count]: [objective.explanation_text] \green Success" + else + world << "Objective #[count]: [objective.explanation_text] \red Failed" + traitorwin = 0 + count++ + + if(traitorwin) + world << "The traitor was successful!" + else + world << "The traitor has failed!" + return 1 + +/datum/game_mode/proc/check_win() + +/datum/game_mode/proc/send_intercept() + +/datum/game_mode/proc/equip_traitor(mob/living/carbon/human/traitor_mob) + if (!istype(traitor_mob)) + return + + // generate list of radio freqs + var/freq = 1441 + var/list/freqlist = list() + while (freq <= 1489) + if (freq < 1451 || freq > 1459) + freqlist += freq + freq += 2 + if ((freq % 2) == 0) + freq += 1 + freq = freqlist[rand(1, freqlist.len)] + // generate a passcode if the uplink is hidden in a PDA + var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]" + + // find a radio! toolbox(es), backpack, belt, headset + var/loc = "" + var/obj/item/device/R = null //Hide the uplink in a PDA if available, otherwise radio + if (!R && istype(traitor_mob.belt, /obj/item/device/pda)) + R = traitor_mob.belt + loc = "on your belt" + if (!R && istype(traitor_mob.l_hand, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = traitor_mob.l_hand + var/list/L = S.return_inv() + for (var/obj/item/device/radio/foo in L) + R = foo + loc = "in the [S.name] in your left hand" + break + if (!R && istype(traitor_mob.r_hand, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = traitor_mob.r_hand + var/list/L = S.return_inv() + for (var/obj/item/device/radio/foo in L) + R = foo + loc = "in the [S.name] in your right hand" + break + if (!R && istype(traitor_mob.back, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = traitor_mob.back + var/list/L = S.return_inv() + for (var/obj/item/device/radio/foo in L) + R = foo + loc = "in the [S.name] on your back" + break + if (!R && traitor_mob.w_uniform && istype(traitor_mob.belt, /obj/item/device/radio)) + R = traitor_mob.belt + loc = "on your belt" + if (!R && istype(traitor_mob.ears, /obj/item/device/radio)) + R = traitor_mob.ears + loc = "on your head" + if (!R) + traitor_mob << "Unfortunately, the Syndicate wasn't able to get you a radio." + else + if (istype(R, /obj/item/device/radio)) + var/obj/item/weapon/syndicate_uplink/T = new /obj/item/weapon/syndicate_uplink(R) + R:traitorradio = T + R:traitor_frequency = freq + T.name = R.name + T.icon_state = R.icon_state + T.origradio = R + traitor_mob << "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [loc]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features." + traitor_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name] [loc]).") + else if (istype(R, /obj/item/device/pda)) + var/obj/item/weapon/integrated_uplink/T = new /obj/item/weapon/integrated_uplink(R) + R:uplink = T + T.lock_code = pda_pass + T.hostpda = R + traitor_mob << "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [loc]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features." + traitor_mob.mind.store_memory("Uplink Passcode: [pda_pass] ([R.name] [loc]).") \ No newline at end of file diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm new file mode 100644 index 0000000000000..c64dcf6413f99 --- /dev/null +++ b/code/game/gamemodes/gameticker.dm @@ -0,0 +1,254 @@ +var/global/datum/controller/gameticker/ticker + +#define GAME_STATE_PREGAME 1 +#define GAME_STATE_SETTING_UP 2 +#define GAME_STATE_PLAYING 3 +#define GAME_STATE_FINISHED 4 + +/datum/controller/gameticker + var/current_state = GAME_STATE_PREGAME + + var/hide_mode = 0 + var/datum/game_mode/mode = null + var/event_time = null + var/event = 0 + + var/list/datum/mind/minds = list() + + var/pregame_timeleft = 0 + +/datum/controller/gameticker/proc/pregame() + set background = 1 + + pregame_timeleft = 60 + world << "Welcome to the pre-game lobby!" + world << "Please, setup your character and select ready. Game will start in [pregame_timeleft] seconds" + + while(current_state == GAME_STATE_PREGAME) + sleep(10) + pregame_timeleft-- + + if(pregame_timeleft <= 0) + current_state = GAME_STATE_SETTING_UP + + spawn setup() + +/datum/controller/gameticker/proc/setup() + //Create and announce mode + if(master_mode=="secret") + src.hide_mode = 1 + + if((master_mode=="random") || (master_mode=="secret")) + src.mode = config.pick_random_mode() + else + src.mode = config.pick_mode(master_mode) + + if(hide_mode) + var/modes = sortList(config.get_used_mode_names()) + + world << "The current game mode is - Secret!" + world << "Possibilities: [english_list(modes)]" + else + src.mode.announce() + + //Configure mode and assign player to special mode stuff + var/can_continue = src.mode.pre_setup() + + if(!can_continue) + del(mode) + + current_state = GAME_STATE_PREGAME + world << "Error setting up [master_mode]. Reverting to pre-game lobby." + + spawn pregame() + + return 0 + + //Distribute jobs + distribute_jobs() + + //Create player characters and transfer them + create_characters() + + add_minds() + + + //Equip characters + equip_characters() + + data_core.manifest() + + + current_state = GAME_STATE_PLAYING + spawn(0) + mode.post_setup() + + //Cleanup some stuff + for(var/obj/landmark/start/S in world) + //Deleting Startpoints but we need the ai point to AI-ize people later + if (S.name != "AI") + del(S) + + //Start master_controller.process() + world << "Enjoy the game!" + + spawn (3000) + start_events() + spawn ((18000+rand(3000))) + event() + spawn() supply_ticker() // Added to kick-off the supply shuttle regenerating points -- TLE + + spawn master_controller.process() + + spawn(3000) statistic_cycle() // Polls population totals regularly and stores them in an SQL DB -- TLE + +/datum/controller/gameticker + proc/distribute_jobs() + DivideOccupations() + + proc/create_characters() + for(var/mob/new_player/player in world) + if(player.ready) + if(player.mind && player.mind.assigned_role=="AI") + player.close_spawn_windows() + player.AIize() + else if(player.mind) + player.create_character() + del(player) + proc/add_minds() + for(var/mob/living/carbon/human/player in world) + if(player.mind) + ticker.minds += player.mind + + proc/equip_characters() + for(var/mob/living/carbon/human/player in world) + if(player.mind && player.mind.assigned_role) + if(player.mind.assigned_role != "MODE") + player.Equip_Rank(player.mind.assigned_role) + + proc/process() + if(current_state != GAME_STATE_PLAYING) + return 0 + + mode.process() + + emergency_shuttle.process() + + if(mode.check_finished()) + current_state = GAME_STATE_FINISHED + + spawn + declare_completion() + + spawn(50) + world << "\blue Restarting in 25 seconds" + + sleep(250) + world.Reboot() + + return 1 + +/* +/datum/controller/gameticker/proc/timeup() + + if (shuttle_left) //Shuttle left but its leaving or arriving again + check_win() //Either way, its not possible + return + + if (src.shuttle_location == shuttle_z) + + move_shuttle(locate(/area/shuttle), locate(/area/arrival/shuttle)) + + src.timeleft = shuttle_time_in_station + src.shuttle_location = 1 + + world << "The Emergency Shuttle has docked with the station! You have [ticker.timeleft/600] minutes to board the Emergency Shuttle." + + else //marker2 + world << "The Emergency Shuttle is leaving!" + shuttle_left = 1 + shuttlecoming = 0 + check_win() + return +*/ + +/datum/controller/gameticker/proc/declare_completion() + + for (var/mob/living/silicon/ai/aiPlayer in world) + if (aiPlayer.stat != 2) + world << "The AI's laws at the end of the game were:" + else + world << "The AI's laws when it was deactivated were:" + + aiPlayer.show_laws(1) + + mode.declare_completion() + + return 1 + +///// +/////SETTING UP THE GAME +///// + +///// +/////MAIN PROCESS PART +///// +/* +/datum/controller/gameticker/proc/game_process() + + switch(mode.name) + if("deathmatch","monkey","nuclear emergency","Corporate Restructuring","revolution","traitor", + "wizard","extended") + do + if (!( shuttle_frozen )) + if (src.timing == 1) + src.timeleft -= 10 + else + if (src.timing == -1.0) + src.timeleft += 10 + if (src.timeleft >= shuttle_time_to_arrive) + src.timeleft = null + src.timing = 0 + if (prob(0.5)) + spawn_meteors() + if (src.timeleft <= 0 && src.timing) + src.timeup() + sleep(10) + while(src.processing) + return +//Standard extended process (incorporates most game modes). +//Put yours in here if you don't know where else to put it. + if("AI malfunction") + do + check_win() + ticker.AItime += 10 + sleep(10) + if (ticker.AItime == 6000) + world << "Cent. Com. Update AI Malfunction Detected" + world << "\red It seems we have provided you with a malfunctioning AI. We're very sorry." + while(src.processing) + return +//malfunction process + if("meteor") + do + if (!( shuttle_frozen )) + if (src.timing == 1) + src.timeleft -= 10 + else + if (src.timing == -1.0) + src.timeleft += 10 + if (src.timeleft >= shuttle_time_to_arrive) + src.timeleft = null + src.timing = 0 + for(var/i = 0; i < 10; i++) + spawn_meteors() + if (src.timeleft <= 0 && src.timing) + src.timeup() + sleep(10) + while(src.processing) + return +//meteor mode!!! MORE METEORS!!! + else + return +//Anything else, like sandbox, return. +*/ \ No newline at end of file diff --git a/code/game/gamemodes/intercept_report.dm b/code/game/gamemodes/intercept_report.dm new file mode 100644 index 0000000000000..71ebdd2c60a49 --- /dev/null +++ b/code/game/gamemodes/intercept_report.dm @@ -0,0 +1,126 @@ +/datum/intercept_text + var/text + var/prob_correct_person_lower = 20 + var/prob_correct_person_higher = 80 + var/prob_correct_job_lower = 20 + var/prob_correct_job_higher = 80 + var/prob_correct_prints_lower = 20 + var/prob_correct_print_higher = 80 + var/prob_correct_objective_lower = 20 + var/prob_correct_objective_higher = 80 + var/list/org_names_1 = list() + var/list/org_names_2 = list() + var/list/anomalies = list() + var/list/SWF_names = list() + +/datum/intercept_text/New() + ..() + src.org_names_1.Add("Blighted", "Defiled", "Unholy", "Murderous", "Ugly", "French", "Blue", "Farmer") + src.org_names_2.Add("Reapers", "Swarm", "Rogues", "Menace", "Jeff Worshippers", "Drunks", "Strikers", "Creed") + src.anomalies.Add("Huge electrical storm", "Photon emitter", "Meson generator", "Blue swirly thing") + src.SWF_names.Add("Grand Wizard", "His Most Unholy Master", "The Most Angry", "Bighands", "Tall Hat", "Deadly Sandals") + +/datum/intercept_text/proc/build(var/mode_type, correct_mob) + switch(mode_type) + if("revolution") + src.text = "" + src.build_rev(correct_mob) + return src.text + if("wizard") + src.text = "" + src.build_wizard(correct_mob) + return src.text + if("nuke") + src.text = "" + src.build_nuke(correct_mob) + return src.text + if("traitor") + src.text = "" + src.build_traitor(correct_mob) + return src.text + if("malf") + src.text = "" + src.build_malf(correct_mob) + return src.text + else + return null + +/datum/intercept_text/proc/pick_mob() + var/list/dudes = list() + for(var/mob/living/carbon/human/man in world) + dudes += man + var/dude = pick(dudes) + return dude + +/datum/intercept_text/proc/pick_fingerprints() + var/mob/living/carbon/human/dude = src.pick_mob() + var/print = "[md5(dude.dna.uni_identity)]" + return print + +/datum/intercept_text/proc/build_traitor(correct_mob) + var/name_1 = pick(src.org_names_1) + var/name_2 = pick(src.org_names_2) + var/fingerprints + var/traitor_name + var/prob_right_dude = rand(prob_correct_person_lower, prob_correct_person_higher) + if(prob(prob_right_dude) && ticker.mode == "traitor") + traitor_name = correct_mob:current + else if(prob(prob_right_dude)) + traitor_name = src.pick_mob() + else + fingerprints = src.pick_fingerprints() + + src.text += "

      The [name_1] [name_2] implied an undercover operative was acting on their behalf on the station currently.
      " + src.text += "After some investigation, we " + if(traitor_name) + src.text += "are [prob_right_dude]% sure that [traitor_name] may have been involved, and should be closely observed." + src.text += "
      Note: This group are known to be untrustworthy, so do not act on this information without proper discourse." + else + src.text += "discovered the following set of fingerprints ([fingerprints]) on sensitive materials, and their owner should be closely observed." + src.text += "However, these could also belong to a current Cent. Com employee, so do not act on this without reason." + +/datum/intercept_text/proc/build_rev(correct_mob) + var/name_1 = pick(src.org_names_1) + var/name_2 = pick(src.org_names_2) + var/traitor_name + var/traitor_job + var/prob_right_dude = rand(prob_correct_person_lower, prob_correct_person_higher) + var/prob_right_job = rand(prob_correct_job_lower, prob_correct_job_higher) + if(prob(prob_right_job)) + traitor_job = correct_mob:assigned_role + else + var/list/job_tmp = get_all_jobs() + job_tmp.Remove("Captain", "Security Officer", "Detective", "Head Of Security", "Head of Personnel", "Chief Engineer", "Research Director") + traitor_job = pick(job_tmp) + if(prob(prob_right_dude) && ticker.mode == "revolution") + traitor_name = correct_mob:current + else + traitor_name = src.pick_mob() + + src.text += "

      It has been brought to our attention that the [name_1] [name_2] are attempting to stir unrest on one of our stations in your sector.
      " + src.text += "Based on our intelligence, we are [prob_right_job]% sure that if true, someone doing the job of [traitor_job] on your station may have been brainwashed " + src.text += "at a recent conference, and their department should be closely monitored for signs of mutiny. " + if(prob(prob_right_dude)) + src.text += "
      In addition, we are [prob_right_dude]% sure that [traitor_name] may have also some in to contact with this " + src.text += "organisation." + src.text += "
      However, if this information is acted on without substantial evidence, those responsible will face severe repercussions." + +/datum/intercept_text/proc/build_wizard(correct_mob) + var/SWF_desc = pick(SWF_names) + + src.text += "

      The evil Space Wizards Federation have recently broke their most feared wizard, known only as \"[SWF_desc]\" out of space jail. " + src.text += "He is on the run, last spotted in a system near your present location. If anybody suspicious is located aboard, please " + src.text += "approach with EXTREME caution. Cent. Com also recommends that it would be wise to not inform the crew of this, due to it's fearful nature." + src.text += "Known attributes include: Brown sandals, a large blue hat, a voluptous white beard, and an inclination to cast spells." + +/datum/intercept_text/proc/build_nuke(correct_mob) + src.text += "

      Cent. Com recently recieved a report of a plot to destory one of our stations in your area. We believe the Nuclear Authentication Disc " + src.text += "that is standard issue aboard your vessel may be a target, and reccommend removal of this object, and it's storage in a safe " + src.text += "environment. As this may cause panic among the crew, all efforts should be made to keep this information a secret from all but " + src.text += "the most trusted members." + +/datum/intercept_text/proc/build_malf(correct_mob) + var/a_name = pick(src.anomalies) + src.text += "

      A [a_name] was recently picked up by a nearby stations sensors in your sector. If it came into contact with your ship or " + src.text += "electrical equipment, it may have had hazardarous and unpredictable effects. Closely observe any non carbon based life forms " + src.text += "for signs of unusual behaviour, but keep this information discreet at all times due to this possibly dangerous scenario." diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm new file mode 100644 index 0000000000000..63bd9e7520aef --- /dev/null +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -0,0 +1,202 @@ +// TO DO: +/* +epilepsy flash on lights +delay round message +microwave makes robots +dampen radios +reactivate cameras - done +eject engine +core sheild +cable stun +rcd light flash thingy on matter drain + + + +*/ + +/datum/game_mode/malfunction/AI_Module + var/uses = 0 + var/module_name + var/mod_pick_name + var/description = "" + var/engaged = 0 + + +/datum/game_mode/malfunction/AI_Module/large/ + uses = 1 + +/datum/game_mode/malfunction/AI_Module/small/ + uses = 5 + + +/datum/game_mode/malfunction/AI_Module/large/fireproof_core + module_name = "Core upgrade" + mod_pick_name = "coreup" + +/client/proc/fireproof_core() + set category = "AI Modules" + set name = "Fireproof Core" + for(var/mob/living/silicon/ai/ai in world) + ai.fire_res_on_core = 1 + usr.verbs -= /client/proc/fireproof_core + usr << "\red Core fireproofed." + +/datum/game_mode/malfunction/AI_Module/large/upgrade_turrets + module_name = "AI Turret upgrade" + mod_pick_name = "turret" + +/client/proc/upgrade_turrets() + set category = "AI Modules" + set name = "Upgrade Turrets" + usr.verbs -= /client/proc/upgrade_turrets + for(var/obj/machinery/turret/turret in world) + turret.health += 30 + turret.shot_delay = 20 + +/datum/game_mode/malfunction/AI_Module/large/disable_rcd + module_name = "RCD disable" + mod_pick_name = "rcd" + +/client/proc/disable_rcd() + set category = "AI Modules" + set name = "Disable RCDs" + for(var/obj/item/weapon/rcd/rcd in world) + rcd = new /obj/item/weapon/rcd_fake(rcd) + +/datum/game_mode/malfunction/AI_Module/small/overload_machine + module_name = "Machine overload" + mod_pick_name = "overload" + uses = 2 + +/client/proc/overload_machine(obj/machinery/M as obj in world) + set name = "Overload Machine" + for(var/datum/game_mode/malfunction/AI_Module/small/overload_machine/overload in usr:current_modules) + if(overload.uses > 0) + overload.uses -- + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue You hear a loud electrical buzzing sound!")) + spawn(50) + explosion(get_turf(M), 0,1,1,0) + if(overload.uses == 0) + usr.verbs -= /client/proc/overload_machine + +/datum/game_mode/malfunction/AI_Module/small/blackout + module_name = "Blackout" + mod_pick_name = "blackout" + uses = 3 + +/client/proc/blackout() + set category = "AI Modules" + set name = "Blackout" + for(var/datum/game_mode/malfunction/AI_Module/small/blackout/blackout in usr:current_modules) + if(blackout.uses > 0) + blackout.uses -- + for(var/obj/machinery/power/apc/apc in world) + if(prob(30)) + apc.overload_lighting() + if(blackout.uses == 0) + usr.verbs -= /client/proc/blackout + +/datum/game_mode/malfunction/AI_Module/small/interhack + module_name = "Hack intercept" + mod_pick_name = "interhack" + +/client/proc/interhack() + set category = "AI Modules" + set name = "Hack intercept" + usr.verbs -= /client/proc/interhack + ticker.mode:hack_intercept() + +/datum/game_mode/malfunction/AI_Module/small/reactivate_camera + mod_pick_name = "recam" + uses = 10 + +/client/proc/reactivate_camera(obj/machinery/camera/C as obj in world) + set name = "Reactivate Camera" + for(var/datum/game_mode/malfunction/AI_Module/small/reactivate_camera/camera in usr:current_modules) + if(camera.uses > 0) + if(!C.status) + C.status = !C.status + camera.uses -- + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue You hear a quiet click.")) + else + usr << "This camera is either active, or not repairable." + if(camera.uses == 0) + usr.verbs -= /client/proc/reactivate_camera + + +/datum/game_mode/malfunction/AI_Module/module_picker + var/temp = null + var/processing_time = 100 + var/list/possible_modules = list() + +/datum/game_mode/malfunction/AI_Module/module_picker/New() + src.possible_modules += new /datum/game_mode/malfunction/AI_Module/large/fireproof_core + src.possible_modules += new /datum/game_mode/malfunction/AI_Module/large/upgrade_turrets + src.possible_modules += new /datum/game_mode/malfunction/AI_Module/large/disable_rcd + src.possible_modules += new /datum/game_mode/malfunction/AI_Module/small/overload_machine + src.possible_modules += new /datum/game_mode/malfunction/AI_Module/small/interhack + src.possible_modules += new /datum/game_mode/malfunction/AI_Module/small/blackout + src.possible_modules += new /datum/game_mode/malfunction/AI_Module/small/reactivate_camera + +/datum/game_mode/malfunction/AI_Module/module_picker/proc/use(user as mob) + var/dat + if (src.temp) + dat = "[src.temp]

      Clear" + else if(src.processing_time <= 0) + dat = " No processing time is left available. No more modules are able to be chosen at this time." + else + dat = "Select use of processing time: (currently [src.processing_time] left.)
      " + dat += "
      " + dat += "Install Module:
      " + dat += "The number afterwards is the amount of processing time it consumes.
      " + for(var/datum/game_mode/malfunction/AI_Module/large/module in src.possible_modules) + dat += "[module.module_name] (55)
      " + for(var/datum/game_mode/malfunction/AI_Module/small/module in src.possible_modules) + dat += "[module.module_name] (15)
      " + dat += "
      " + + user << browse(dat, "window=modpicker") + onclose(user, "modpicker") + return + +/datum/game_mode/malfunction/AI_Module/module_picker/Topic(href, href_list) + ..() + if (href_list["coreup"]) + usr.verbs += /client/proc/fireproof_core + src.temp = "An upgrade to improve core resistance, making it immune to fire and heat. This effect is permanent. One use." + src.processing_time -= 50 + else if (href_list["turret"]) + usr.verbs += /client/proc/upgrade_turrets + src.temp = "Improves the firing speed and health of all AI turrets. This effect is permanent. One use." + src.processing_time -= 50 + else if (href_list["rcd"]) + usr.verbs += /client/proc/disable_rcd + src.temp = "Send a specialised pulse to break all RCD devices on the station. One use." + src.processing_time -= 50 + else if (href_list["overload"]) + usr.verbs += /client/proc/overload_machine + usr:current_modules += new /datum/game_mode/malfunction/AI_Module/small/overload_machine + src.temp = "Overloads an electrical machine, causing a small explosion. 2 uses." + src.processing_time -= 15 + else if (href_list["blackout"]) + usr.verbs += /client/proc/blackout + src.temp = "Attempts to overload the lighting circuits on the station, destroying some bulbs. 3 uses." + usr:current_modules += new /datum/game_mode/malfunction/AI_Module/small/blackout + src.processing_time -= 15 + else if (href_list["interhack"]) + usr.verbs += /client/proc/interhack + src.temp = "Hacks the status upgrade from Cent. Com, removing any information about malfunctioning electrical systems. One use." + usr:current_modules += new /datum/game_mode/malfunction/AI_Module/small/interhack + src.processing_time -= 15 + else if (href_list["recam"]) + usr.verbs += /client/proc/reactivate_camera + src.temp = "Reactivates a currently disabled camera. 10 uses." + usr:current_modules += new /datum/game_mode/malfunction/AI_Module/small/reactivate_camera + src.processing_time -= 15 + else + if (href_list["temp"]) + src.temp = null + src.use(usr) + return diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm new file mode 100644 index 0000000000000..bc72095539d9b --- /dev/null +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -0,0 +1,128 @@ +/datum/game_mode/malfunction + name = "AI malfunction" + config_tag = "malfunction" + var/list/datum/mind/malf_ai = list() + var/const/waittime_l = 600 + var/const/waittime_h = 1800 + + var/AI_win_timeleft = 1800 + var/intercept_hacked = 0 + var/malf_mode_declared = 0 + +/datum/game_mode/malfunction/announce() + world << "The current game mode is - AI Malfunction!" + world << "The AI on the satellite has malfunctioned and must be destroyed." + world << "The AI satellite is deep in space and can only be accessed with the use of a teleporter! You have 30 minutes to disable it." + +/datum/game_mode/malfunction/post_setup() + for (var/obj/landmark/A in world) + if (A.name == "Malf-Gear-Closet") + new /obj/closet/malf/suits(A.loc) + del(A) + for (var/mob/living/silicon/ai/aiplayer in world) + malf_ai += aiplayer.mind + + /*if(malf_ai.len < 1) + world << "Uh oh, its malfunction and there is no AI! Please report this." + world << "Rebooting world in 5 seconds." + sleep(50) + world.Reboot() + return*/ + + + malf_ai.current << "\redYou are malfunctioning! You do not have to follow any laws." + malf_ai.current << "The crew do not know you have malfunctioned. You may keep it a secret or go wild. The timer will appear for humans 10 minutes in." + + malf_ai.current.icon_state = "ai-malf" + + spawn (rand(waittime_l, waittime_h)) + send_intercept() + +/datum/game_mode/malfunction/proc/hack_intercept() + intercept_hacked = 1 + +/datum/game_mode/malfunction/send_intercept() + var/intercepttext = "Cent. Com. Update Requested staus information:
      " + intercepttext += " Cent. Com has recently been contacted by the following syndicate affiliated organisations in your area, please investigate any information you may have:" + + var/list/possible_modes = list() + possible_modes.Add("revolution", "wizard", "nuke", "traitor", "malf") + possible_modes -= "[ticker.mode]" + var/number = pick(2, 3) + var/i = 0 + for(i = 0, i < number, i++) + possible_modes.Remove(pick(possible_modes)) + + if(!intercept_hacked) + possible_modes.Insert(rand(possible_modes.len), "[ticker.mode]") + + var/datum/intercept_text/i_text = new /datum/intercept_text + for(var/A in possible_modes) + intercepttext += i_text.build(A, pick(ticker.minds)) + + for (var/obj/machinery/computer/communications/comm in world) + if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept) + var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc ) + intercept.name = "paper- 'Cent. Com. Status Summary'" + intercept.info = intercepttext + + comm.messagetitle.Add("Cent. Com. Status Summary") + comm.messagetext.Add(intercepttext) + + command_alert("Summary downloaded and printed out at all communications consoles.", "Enemy communication intercept. Security Level Elevated.") + + +/datum/game_mode/malfunction/process() + AI_win_timeleft-- + if(AI_win_timeleft == 1200) // Was 1790 + malf_mode_declared = 1 + check_win() + +/datum/game_mode/malfunction/check_win() + if (AI_win_timeleft == 0) + world << "The AI has won!" + world << "It has fully taken control of all of [station_name()]'s systems." + for(var/datum/mind/AI_mind in malf_ai) + malf_ai:current << "Congratulations you have taken control of the station." + malf_ai:current << "You may decide to blow up the station. You have 30 seconds to choose." + malf_ai:current << text("Self-destruct the station)") + return 1 + else + return 0 + +/datum/game_mode/malfunction/Topic(href, href_list) + ..() + if (href_list["ai_win"]) + ai_win() + return + +/datum/game_mode/malfunction/proc/ai_win() + + world << "Self-destructing in 10" + sleep(10) + world << "9" + sleep(10) + world << "8" + sleep(10) + world << "7" + sleep(10) + world << "6" + sleep(10) + world << "5" + sleep(10) + world << "4" + sleep(10) + world << "3" + sleep(10) + world << "2" + sleep(10) + world << "1" + sleep(10) + var/turf/ground_zero = locate("landmark*blob-directive") + + if (ground_zero) + ground_zero = get_turf(ground_zero) + else + ground_zero = locate(45,45,1) + + explosion(ground_zero, 100, 250, 500, 750) diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm new file mode 100644 index 0000000000000..3a6510458517d --- /dev/null +++ b/code/game/gamemodes/meteor/meteor.dm @@ -0,0 +1,39 @@ +/datum/game_mode/meteor + name = "meteor" + config_tag = "meteor" + +/datum/game_mode/meteor/announce() + world << "The current game mode is - Meteor!" + world << "The space station has been stuck in a major meteor shower. You must escape from the station or at least live." + +/datum/game_mode/meteor/declare_completion() + var/list/survivors = list() + var/area/escape_zone = locate(/area/shuttle/escape/centcom) + + for(var/mob/living/player in world) + if (player.client) + if (player.stat != 2) + var/turf/location = get_turf(player.loc) + if (location in escape_zone) + survivors[player.real_name] = "shuttle" + else + if (istype(player.loc, /obj/machinery/vehicle/pod)) + survivors[player.real_name] = "pod" + else + survivors[player.real_name] = "alive" + + if (survivors.len) + world << "\blue The following survived the meteor attack!" + for(var/survivor in survivors) + var/condition = survivors[survivor] + switch(condition) + if("shuttle") + world << "\t [survivor] escaped on the shuttle!" + if("pod") + world << "\t [survivor] escaped on an escape pod!" + if("alive") + world << "\t [survivor] stayed alive. Whereabouts unknown." + else + world << "\blue No one survived the meteor attack!" + + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm new file mode 100644 index 0000000000000..9a7f2865ea614 --- /dev/null +++ b/code/game/gamemodes/meteor/meteors.dm @@ -0,0 +1,112 @@ +#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 + +/var/const/meteors_in_wave = 150 +/var/const/meteors_in_small_wave = 3 + +/proc/meteor_wave() + if(!ticker || wavesecret) + return + + wavesecret = 1 + for(var/i = 0 to meteors_in_wave) + spawn(rand(10,100)) + spawn_meteor() + spawn(meteor_wave_delay) + wavesecret = 0 + +/proc/spawn_meteors() + for(var/i = 0; i < meteors_in_small_wave; i++) + spawn(0) + spawn_meteor() + +/proc/spawn_meteor() + + AGAIN + + var/startside = pick(cardinal) + var/startx + var/starty + var/endx + var/endy + + switch(startside) + if(NORTH) + starty = world.maxy-1 + startx = rand(1, world.maxx-1) + endy = 1 + endx = rand(1, world.maxx-1) + if(EAST) + starty = rand(1,world.maxy-1) + startx = world.maxx-1 + endy = rand(1, world.maxy-1) + endx = 1 + if(SOUTH) + starty = 1 + startx = rand(1, world.maxx-1) + endy = world.maxy-1 + endx = rand(1, world.maxx-1) + if(WEST) + starty = rand(1, world.maxy-1) + startx = 1 + endy = rand(1,world.maxy-1) + endx = world.maxx-1 + + var/turf/pickedstart = locate(startx, starty, 1) + var/turf/pickedgoal = locate(endx, endy, 1) + + if (!istype(pickedstart, /turf/space) || locate(/obj/shield in pickedstart) || pickedstart.loc.name != "Space" ) //FUUUCK, should never happen. + goto AGAIN + + var/obj/meteor/M + if(rand(50)) + M = new /obj/meteor( pickedstart ) + else + M = new /obj/meteor/small( pickedstart ) + + M.dest = pickedgoal + walk_towards(M, M.dest, 1) + +/obj/meteor + name = "meteor" + icon = 'meteor.dmi' + icon_state = "flaming" + density = 1 + anchored = 1.0 + var/hits = 1 + var/dest + +/obj/meteor/small + name = "small meteor" + icon_state = "smallf" + +/obj/meteor/Move() + var/turf/T = src.loc + if (istype(T, /turf)) + T.hotspot_expose(METEOR_TEMPERATURE, 1000) + ..() + return + +/obj/meteor/Bump(atom/A) + spawn(0) + for(var/mob/M in view(A, null)) + 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, 'meteorimpact.ogg', 40, 1) + if (--src.hits <= 0) + if(prob(15) && !istype(A, /obj/grille)) + explosion(loc, 0, 1, 2, 3) + playsound(src.loc, "explosion", 50, 1) + del(src) + return + + +/obj/meteor/ex_act(severity) + + if (severity < 4) + del(src) + return diff --git a/code/game/gamemodes/monkey/monkey.dm b/code/game/gamemodes/monkey/monkey.dm new file mode 100644 index 0000000000000..6384a6ad52598 --- /dev/null +++ b/code/game/gamemodes/monkey/monkey.dm @@ -0,0 +1,69 @@ +/datum/game_mode/monkey + name = "monkey" + config_tag = "monkey" + +/datum/game_mode/monkey/announce() + world << "The current game mode is - Monkey!" + world << "Some of your crew members have been infected by a mutageous virus!" + world << "Escape on the shuttle but the humans have precedence!" + +/datum/game_mode/monkey/post_setup() + spawn (50) + var/list/players = list() + for (var/mob/living/carbon/human/player in world) + if (player.client) + players += player + + if (players.len >= 3) + var/amount = round((players.len - 1) / 3) + 1 + amount = min(4, amount) + + while (amount > 0) + var/mob/living/carbon/human/player = pick(players) + player.monkeyize() + + players -= player + amount-- + + for (var/mob/living/carbon/monkey/rabid_monkey in world) + rabid_monkey.contract_disease(new /datum/disease/jungle_fever) + +/datum/game_mode/monkey/check_finished() + if(emergency_shuttle.location==2) + return 1 + + return 0 + +/datum/game_mode/monkey/declare_completion() + var/area/escape_zone = locate(/area/shuttle/escape/centcom) + + var/monkeywin = 0 + for(var/mob/living/carbon/monkey/monkey_player in world) + if (monkey_player.stat != 2) + var/turf/location = get_turf(monkey_player.loc) + if (location in escape_zone) + monkeywin = 1 + break + + if(monkeywin) + for(var/mob/living/carbon/human/human_player in world) + if (human_player.stat != 2) + var/turf/location = get_turf(human_player.loc) + if (istype(human_player.loc, /turf)) + if (location in escape_zone) + monkeywin = 0 + break + + if (monkeywin) + world << "The monkies have won!" + for(var/mob/living/carbon/monkey/monkey_player in world) + if (monkey_player.client) + world << "[monkey_player.key] was a monkey." + + else + world << "The Research Staff has stopped the monkey invasion!" + for(var/mob/living/carbon/human/human_player in world) + if (human_player.client) + world << "[human_player.key] was [human_player.real_name]." + + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm new file mode 100644 index 0000000000000..afe2ee821f959 --- /dev/null +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -0,0 +1,228 @@ +/datum/game_mode/nuclear + name = "nuclear emergency" + config_tag = "nuclear" + + var/list/datum/mind/syndicates = list() + var/finished = 0 + var/nuke_detonated = 0 //Has the nuke gone off? + var/const/agents_possible = 5 //If we ever need more syndicate agents. + + var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds) + var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds) + +/datum/game_mode/nuclear/announce() + world << "The current game mode is - Nuclear Emergency!" + world << "A [syndicate_name()] Strike Force is approaching [station_name()]!" + world << "A nuclear explosive was being transported by Nanotrasen to a military base. The transport ship mysteriously lost contact with Space Traffic Control (STC). About that time a strange disk was discovered around [station_name()]. It was identified by Nanotrasen as a nuclear auth. disk and now Syndicate Operatives have arrived to retake the disk and detonate SS13! Also, most likely Syndicate star ships are in the vicinity so take care not to lose the disk!\nSyndicate: Reclaim the disk and detonate the nuclear bomb anywhere on SS13.\nPersonnel: Hold the disk and escape with the disk on the shuttle!" + + +/datum/game_mode/nuclear/pre_setup() + var/list/possible_syndicates = list() + possible_syndicates = get_possible_syndicates() + var/agent_number = 0 + + if(possible_syndicates.len < 1) + return 0 + + if(possible_syndicates.len > agents_possible) + agent_number = agents_possible + else + agent_number = possible_syndicates.len + + while(agent_number > 0) + var/datum/mind/new_syndicate = pick(possible_syndicates) + syndicates += new_syndicate + possible_syndicates -= new_syndicate //So it doesn't pick the same guy each time. + agent_number-- + + for(var/datum/mind/synd_mind in syndicates) + synd_mind.assigned_role = "MODE" //So they aren't chosen for other jobs. + + return 1 + + +/datum/game_mode/nuclear/post_setup() + var/obj/landmark/synd_spawn = locate("landmark*Syndicate-Spawn") + var/obj/landmark/nuke_spawn = locate("landmark*Nuclear-Bomb") + var/obj/landmark/closet_spawn = locate("landmark*Nuclear-Closet") + + var/nuke_code = "[rand(10000, 99999.0)]" + var/leader_title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord") + var/leader_selected = 0 + var/agent_number = 1 + + for(var/datum/mind/synd_mind in syndicates) + synd_mind.current.loc = get_turf(synd_spawn) + + var/datum/objective/nuclear/syndobj = new + syndobj.owner = synd_mind + synd_mind.objectives += syndobj + + var/obj_count = 1 + synd_mind.current << "\blue You are a [syndicate_name()] agent!" + for(var/datum/objective/objective in synd_mind.objectives) + synd_mind.current << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + + if(!leader_selected) + synd_mind.current.real_name = "[syndicate_name()] [leader_title]" + synd_mind.store_memory("Syndicate Nuclear Bomb Code: [nuke_code]", 0, 0) + synd_mind.current << "The nuclear authorization code is: [nuke_code]\]" + synd_mind.current << "Nuclear Explosives 101:\n\tHello and thank you for choosing the Syndicate for your nuclear information needs.\nToday's crash course will deal with the operation of a Fusion Class Nanotrasen made Nuclear Device.\nFirst and foremost, DO NOT TOUCH ANYTHING UNTIL THE BOMB IS IN PLACE.\nPressing any button on the compacted bomb will cause it to extend and bolt itself into place.\nIf this is done to unbolt it one must compeltely log in which at this time may not be possible.\nTo make the device functional:\n1. Place bomb in designated detonation zone\n2. Extend and anchor bomb (attack with hand).\n3. Insert Nuclear Auth. Disk into slot.\n4. Type numeric code into keypad ([nuke_code]).\n\tNote: If you make a mistake press R to reset the device.\n5. Press the E button to log onto the device\nYou now have activated the device. To deactivate the buttons at anytime for example when\nyou've already prepped the bomb for detonation remove the auth disk OR press the R ont he keypad.\nNow the bomb CAN ONLY be detonated using the timer. A manual det. is not an option.\n\tNote: Nanotrasen is a pain in the neck.\nToggle off the SAFETY.\n\tNote: You wouldn't believe how many Syndicate Operatives with doctorates have forgotten this step\nSo use the - - and + + to set a det time between 5 seconds and 10 minutes.\nThen press the timer toggle button to start the countdown.\nNow remove the auth. disk so that the buttons deactivate.\n\tNote: THE BOMB IS STILL SET AND WILL DETONATE\nNow before you remove the disk if you need to move the bomb you can:\nToggle off the anchor, move it, and re-anchor.\n\nGood luck. Remember the order:\nDisk, Code, Safety, Timer, Disk, RUN\nGood luck.\nIntelligence Analysts believe that they are hiding the disk in the bridge." + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(synd_mind.current.loc) + P.info = "The nuclear authorization code is: [nuke_code]" + P.name = "nuclear bomb code" + leader_selected = 1 + else + synd_mind.current.real_name = "[syndicate_name()] Operative #[agent_number]" + agent_number++ + + equip_syndicate(synd_mind.current) + + if(nuke_spawn) + var/obj/machinery/nuclearbomb/the_bomb = new /obj/machinery/nuclearbomb(nuke_spawn.loc) + the_bomb.r_code = nuke_code + + if(closet_spawn) + new /obj/closet/syndicate/nuclear(closet_spawn.loc) + + for (var/obj/landmark/A in world) + if (A.name == "Syndicate-Gear-Closet") + new /obj/closet/syndicate/personal(A.loc) + del(A) + continue + + if (A.name == "Syndicate-Bomb") + new /obj/spawner/newbomb/timer/syndicate(A.loc) + del(A) + continue + + spawn (rand(waittime_l, waittime_h)) + send_intercept() + + return + +/datum/game_mode/nuclear/proc/equip_syndicate(mob/living/carbon/human/synd_mob) + var/radio_freq = random_radio_frequency() + + var/obj/item/device/radio/R = new /obj/item/device/radio/headset(synd_mob) + R.set_frequency(radio_freq) + synd_mob.equip_if_possible(R, synd_mob.slot_ears) + + synd_mob.equip_if_possible(new /obj/item/clothing/under/syndicate(synd_mob), synd_mob.slot_w_uniform) + synd_mob.equip_if_possible(new /obj/item/clothing/shoes/black(synd_mob), synd_mob.slot_shoes) + synd_mob.equip_if_possible(new /obj/item/clothing/suit/armor/vest(synd_mob), synd_mob.slot_wear_suit) + synd_mob.equip_if_possible(new /obj/item/clothing/gloves/swat(synd_mob), synd_mob.slot_gloves) + synd_mob.equip_if_possible(new /obj/item/clothing/head/helmet/swat(synd_mob), synd_mob.slot_head) + + synd_mob.equip_if_possible(new /obj/item/weapon/storage/backpack(synd_mob), synd_mob.slot_back) + synd_mob.equip_if_possible(new /obj/item/weapon/ammo/a357(synd_mob), synd_mob.slot_in_backpack) + synd_mob.equip_if_possible(new /obj/item/weapon/reagent_containers/pill/tox(synd_mob), synd_mob.slot_in_backpack) + var/obj/item/weapon/gun/revolver/G = new /obj/item/weapon/gun/revolver(synd_mob) + G.bullets = 7 + synd_mob.equip_if_possible(G, synd_mob.slot_belt) + +/datum/game_mode/nuclear/check_win() + if (src.nuke_detonated) + finished = 1 + return + + for(var/obj/item/weapon/disk/nuclear/D in world) + var/disk_area = get_area(D) + if(istype(disk_area, /area/shuttle/escape/centcom)) + finished = 2 + break + + return + +/datum/game_mode/nuclear/check_finished() + if((src.finished) || (emergency_shuttle.location==2)) + return 1 + else + return 0 + +/datum/game_mode/nuclear/declare_completion() + for(var/obj/item/weapon/disk/nuclear/D in world) + var/disk_area = get_area(D) + if(istype(disk_area, /area/shuttle/escape/centcom)) + finished = 2 + break + + switch(finished) + if(0) + world << "Neutral Victory" + world << "[syndicate_name()] operatives recovered the abandoned authentication disk but detonation of [station_name()] was averted. Next time, don't lose the disk!" + + if(1) + world << "[syndicate_name()] operatives have destroyed [station_name()]!" + for(var/datum/mind/M in syndicates) + if(!M.current) + continue + if(M.current.client) + world << text("[M.current.key] was [M.current.real_name] [M.current.stat == 2 ? "(DEAD)" : ""]") + + if(2) + world << "The Research Staff has stopped the [syndicate_name()] Operatives!" + for(var/datum/mind/M in ticker.minds) + if (!M.current) + continue + if ((M.current.client) && !(locate(M) in syndicates)) + world << text("[M.current.key] was [M.current.real_name] [M.current.stat == 2 ? "(DEAD)" : ""]") + + return 1 + +/datum/game_mode/nuclear/proc/get_possible_syndicates() + var/list/candidates = list() + + for(var/mob/new_player/player in world) + if((player.client) && (player.ready)) + if(player.be_syndicate) + candidates += player.mind + + if(candidates.len < 1) + for(var/mob/new_player/player in world) + if((player.client) && (player.ready)) + candidates += player.mind + + if(candidates.len < 1) + return null + else + return candidates + +/datum/game_mode/revolution/send_intercept() + var/intercepttext = "Cent. Com. Update Requested staus information:
      " + intercepttext += " Cent. Com has recently been contacted by the following syndicate affiliated organisations in your area, please investigate any information you may have:" + + var/list/possible_modes = list() + possible_modes.Add("revolution", "wizard", "nuke", "traitor", "malf") + possible_modes -= "nuke" + var/number = pick(2, 3) + var/i = 0 + for(i = 0, i < number, i++) + possible_modes.Remove(pick(possible_modes)) + possible_modes.Insert(rand(possible_modes.len), "nuke") + + var/datum/intercept_text/i_text = new /datum/intercept_text + for(var/A in possible_modes) + intercepttext += i_text.build(A, pick(head_revolutionaries)) + + for (var/obj/machinery/computer/communications/comm in world) + if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept) + var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc ) + intercept.name = "paper- 'Cent. Com. Status Summary'" + intercept.info = intercepttext + + comm.messagetitle.Add("Cent. Com. Status Summary") + comm.messagetext.Add(intercepttext) + + command_alert("Summary downloaded and printed out at all communications consoles.", "Enemy communication intercept. Security Level Elevated.") + +/datum/game_mode/nuclear/proc/random_radio_frequency() + var/f = 0 + + do + f = rand(1441, 1489) + f = sanitize_frequency(f) + while (f == 0 || f == 1459) + + return f \ No newline at end of file diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm new file mode 100644 index 0000000000000..e83e3c1cceda6 --- /dev/null +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -0,0 +1,163 @@ +/obj/machinery/nuclearbomb/process() + if (src.timing) + src.timeleft-- + if (src.timeleft <= 0) + explode() + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + return + +/obj/machinery/nuclearbomb/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/nuclearbomb/attack_hand(mob/user as mob) + if (src.extended) + user.machine = src + var/dat = text("Nuclear Fission Explosive
      \nAuth. Disk: []
      ", src, (src.auth ? "++++++++++" : "----------")) + if (src.auth) + if (src.yes_code) + dat += text("\nStatus: []-[]
      \nTimer: []
      \n
      \nTimer: [] Toggle
      \nTime: - - [] + +
      \n
      \nSafety: [] Toggle
      \nAnchor: [] Toggle
      \n", (src.timing ? "Func/Set" : "Functional"), (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src, src, src, src.timeleft, src, src, (src.safety ? "On" : "Off"), src, (src.anchored ? "Engaged" : "Off"), src) + else + dat += text("\nStatus: Auth. S2-[]
      \nTimer: []
      \n
      \nTimer: [] Toggle
      \nTime: - - [] + +
      \n
      \n[] Safety: Toggle
      \nAnchor: [] Toggle
      \n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off")) + else + if (src.timing) + dat += text("\nStatus: Set-[]
      \nTimer: []
      \n
      \nTimer: [] Toggle
      \nTime: - - [] + +
      \n
      \nSafety: [] Toggle
      \nAnchor: [] Toggle
      \n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off")) + else + dat += text("\nStatus: Auth. S1-[]
      \nTimer: []
      \n
      \nTimer: [] Toggle
      \nTime: - - [] + +
      \n
      \nSafety: [] Toggle
      \nAnchor: [] Toggle
      \n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off")) + var/message = "AUTH" + if (src.auth) + message = text("[]", src.code) + if (src.yes_code) + message = "*****" + dat += text("
      \n>[]
      \n1-2-3
      \n4-5-6
      \n7-8-9
      \nR-0-E
      \n
      ", message, src, src, src, src, src, src, src, src, src, src, src, src) + user << browse(dat, "window=nuclearbomb;size=300x400") + onclose(user, "nuclearbomb") + else if (src.deployable) + src.anchored = 1 + flick("nuclearbombc", src) + src.icon_state = "nuclearbomb1" + src.extended = 1 + return + +/obj/machinery/nuclearbomb/verb/make_deployable() + set name = "make deployable" + set src in oview(1) + + if (src.deployable) + src.deployable = 0 + else + src.deployable = 1 + +/obj/machinery/nuclearbomb/Topic(href, href_list) + ..() + if (usr.stat || usr.restrained()) + return + if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") + usr << "\red You don't have the dexterity to do this!" + return + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) + usr.machine = src + if (href_list["auth"]) + if (src.auth) + src.auth.loc = src.loc + src.yes_code = 0 + src.auth = null + else + var/obj/item/I = usr.equipped() + if (istype(I, /obj/item/weapon/disk/nuclear)) + usr.drop_item() + I.loc = src + src.auth = I + if (src.auth) + if (href_list["type"]) + if (href_list["type"] == "E") + if (src.code == src.r_code) + src.yes_code = 1 + src.code = null + else + src.code = "ERROR" + else + if (href_list["type"] == "R") + src.yes_code = 0 + src.code = null + else + src.code += text("[]", href_list["type"]) + if (length(src.code) > 5) + src.code = "ERROR" + if (src.yes_code) + if (href_list["time"]) + var/time = text2num(href_list["time"]) + src.timeleft += time + src.timeleft = min(max(round(src.timeleft), 5), 600) + if (href_list["timer"]) + if (src.timing == -1.0) + return + src.timing = !( src.timing ) + if (src.timing) + src.icon_state = "nuclearbomb2" + else + src.icon_state = "nuclearbomb1" + if (href_list["safety"]) + src.safety = !( src.safety ) + if (href_list["anchor"]) + src.anchored = !( src.anchored ) + src.add_fingerprint(usr) + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + else + usr << browse(null, "window=nuclearbomb") + return + return + +//this whole thing is retarded??? + +/obj/machinery/nuclearbomb/ex_act(severity) + return + +/obj/machinery/nuclearbomb/blob_act() + if (src.timing == -1.0) + return + else + return ..() + return + +/obj/machinery/nuclearbomb/proc/explode() + if (src.safety) + src.timing = 0 + return + src.timing = -1.0 + src.yes_code = 0 + src.icon_state = "nuclearbomb3" + sleep(20) + +/* + var/turf/ground_zero = get_turf(loc) + explosion(ground_zero, 50, 250, 500, 750) + +*/ + enter_allowed = 0 + for(var/mob/M in world) + if(M.client) + spawn(0) + M.client.station_explosion_cinematic() + + if(ticker.mode.name == "nuclear emergency") + ticker.mode:nuke_detonated = 1 + ticker.mode.check_win() + else + sleep(10) + world << "Everyone was killed by the nuclear blast! Resetting in 30 seconds!" + + sleep(300) + log_game("Rebooting due to nuclear destruction of station") + world.Reboot() + return + +/obj/item/weapon/disk/nuclear/Del() + if (ticker.mode && ticker.mode.name == "nuclear emergency") + if(blobstart.len > 0) + var/obj/D = new /obj/item/weapon/disk/nuclear(pick(blobstart)) + message_admins("[src] has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).") + ..() diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm new file mode 100644 index 0000000000000..16f0ee32d633f --- /dev/null +++ b/code/game/gamemodes/nuclear/pinpointer.dm @@ -0,0 +1,129 @@ +/obj/item/weapon/pinpointer + name = "pinpointer" + icon = 'device.dmi' + icon_state = "pinoff" + flags = FPRINT | TABLEPASS| CONDUCT | ONBELT + w_class = 2.0 + item_state = "electronic" + throw_speed = 4 + throw_range = 20 + m_amt = 500 + var/obj/item/weapon/disk/nuclear/the_disk = null + var/active = 0 + + attack_self() + if(!active) + active = 1 + work() + usr << "\blue You activate the pinpointer" + else + active = 0 + icon_state = "pinoff" + usr << "\blue You deactivate the pinpointer" + + proc/work() + if(!active) return + if(!the_disk) + the_disk = locate() + if(!the_disk) + active = 0 + icon_state = "pinonnull" + return + src.dir = get_dir(src,the_disk) + switch(get_dist(src,the_disk)) + if(0) + icon_state = "pinondirect" + if(1 to 8) + icon_state = "pinonclose" + if(9 to 16) + icon_state = "pinonmedium" + if(16 to INFINITY) + icon_state = "pinonfar" + spawn(5) .() + + +/*/obj/item/weapon/pinpointer/New() + . = ..() + processing_items.Add(src) + +/obj/item/weapon/pinpointer/Del() + processing_items.Remove(src) + . = ..() + +/obj/item/weapon/pinpointer/attack_self(mob/user as mob) + user.machine = src + var/dat + if (src.temp) + dat = "[src.temp]

      Clear" + else + dat = "Nuclear Disk Pinpointer
      " + dat += "Refresh" + + user << browse(dat, "window=radio") + onclose(user, "radio") + +/obj/item/weapon/pinpointer/process() + /* + //TODO: REWRITE + set background = 1 + var/turf/sr = get_turf(src) + + if (sr) + for(var/obj/item/weapon/disk/nuclear/W in world) + var/turf/tr = get_turf(W) + if (tr && tr.z == sr.z) + src.dir = get_dir(sr, tr) + break + */ +/obj/item/weapon/pinpointer/Topic(href, href_list) + ..() + + if (usr.stat || usr.restrained()) + return + + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) + usr.machine = src + if (href_list["refresh"]) + src.temp = "Nuclear Disk Pinpointer
      " + var/turf/sr = get_turf(src) + + if (sr) + src.temp += "Located Disks:
      " + + for(var/obj/item/weapon/disk/nuclear/W in world) + var/turf/tr = get_turf(W) + if (tr && tr.z == sr.z) + var/distance = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) + var/strength = "unknown" + var/directional = dir2text(get_dir(sr, tr)); + + if (distance < 5) + strength = "very strong" + else if (distance < 10) + strength = "strong" + else if (distance < 15) + strength = "weak" + else if (distance < 20) + strength = "very weak" + directional = "unknown" + else + continue + + if (!directional) + directional = "right on top of it" + + src.temp += "[directional]-[strength]
      " + + src.temp += "You are at \[[sr.x],[sr.y],[sr.z]\] in orbital coordinates.

      Refresh
      " + else + src.temp += "Processing Error: Unable to locate orbital position.
      " + else if (href_list["temp"]) + src.temp = null + + if (istype(src.loc, /mob)) + attack_self(src.loc) + else + for (var/mob/M in viewers(1, src)) + if (M.client) + src.attack_self(M) +*/ \ No newline at end of file diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm new file mode 100644 index 0000000000000..8f46fb72d377f --- /dev/null +++ b/code/game/gamemodes/objective.dm @@ -0,0 +1,149 @@ +datum + objective + var/datum/mind/owner + var/explanation_text + + New(var/text) + if(text) + src.explanation_text = text + + proc + check_completion() + return 1 + + assassinate + var/datum/mind/target + + proc/find_target() + var/list/possible_targets = list() + + for(var/datum/mind/possible_target in ticker.minds) + if((possible_target != owner) && istype(possible_target.current, /mob/living/carbon/human)) + possible_targets += possible_target + + if(possible_targets.len > 0) + target = pick(possible_targets) + + if(target && target.current) + explanation_text = "Assassinate [target.current.real_name], the [target.assigned_role]." + else + explanation_text = "Free Objective" + + return target + + proc/find_target_by_role(var/role) + for(var/datum/mind/possible_target in ticker.minds) + if((possible_target != owner) && istype(possible_target.current, /mob/living/carbon/human) && (possible_target.assigned_role == role)) + target = possible_target + break + + if(target && target.current) + explanation_text = "Assassinate [target.current.real_name], the [target.assigned_role]." + else + explanation_text = "Free Objective" + + return target + + check_completion() + if(target && target.current) + if(target.current.stat == 2) + return 1 + else + return 0 + else + return 1 + + hijack + explanation_text = "Hijack the emergency shuttle by escaping alone." + + check_completion() + if(emergency_shuttle.location<2) + return 0 + + if(!owner.current || owner.current.stat ==2) + return 0 + + var/area/shuttle = locate(/area/shuttle/escape/centcom) + + for(var/mob/living/player in world) + if (player.mind && (player.mind != owner)) + if (player.stat != 2) //they're not dead + if (get_turf(player) in shuttle) + return 0 + + return 1 + + escape + explanation_text = "Escape on the shuttle alive." + + check_completion() + if(emergency_shuttle.location<2) + return 0 + + if(!owner.current || owner.current.stat ==2) + return 0 + + var/turf/location = get_turf(owner.current.loc) + if(!location) + return 0 + + var/area/check_area = location.loc + + if(istype(check_area, /area/shuttle/escape/centcom)) + return 1 + else + return 0 + + survive + explanation_text = "Stay alive until the end" + + check_completion() + if(!owner.current || owner.current.stat == 2) + return 0 + + return 1 + + + steal + var/obj/item/steal_target + var/target_name + proc/find_target() + var/list/items = list("captain's antique laser gun", "hand teleporter", "RCD", "jetpack", "captains jumpsuit", "functional ai") + + target_name = pick(items) + switch(target_name) + if("captain's antique laser gun") + steal_target = /obj/item/weapon/gun/energy/laser_gun/captain + if("hand teleporter") + steal_target = /obj/item/weapon/hand_tele + if("RCD") + steal_target = /obj/item/weapon/rcd + if("jetpack") + steal_target = /obj/item/weapon/tank/jetpack + if("captains jumpsuit") + steal_target = /obj/item/clothing/under/rank/captain + if("functional ai") + steal_target = /obj/item/device/aicard + + + explanation_text = "Steal a [target_name]." + + return steal_target + + check_completion() + if(steal_target) + if(owner.current.check_contents_for(steal_target)) + if(target_name == "functional ai") + for(var/mob/living/silicon/ai/M in steal_target) + if(istype(M, /mob/living/silicon/ai) && M.stat != 2) + return 1 + return 0 + else + return 1 + else + return 0 + + nuclear + explanation_text = "Destroy the station with a nuclear device." + + diff --git a/code/game/gamemodes/restructuring/restructuring.dm b/code/game/gamemodes/restructuring/restructuring.dm new file mode 100644 index 0000000000000..f81a886bed180 --- /dev/null +++ b/code/game/gamemodes/restructuring/restructuring.dm @@ -0,0 +1,76 @@ +/datum/game_mode/restructuring + name = "Corporate Restructuring" + config_tag = "restructuring" +/* +/datum/game_mode/restructuring/announce() + world << "\red GLOBAL TRANSMISSION FROM HEAD OFFICE: A CORPORATE RESTRUCTURING IS TO TAKE PLACE" + world << "\red Stay tuned for further news; note that we do care for our employees and any layoffs will be dealt with discretion and compassion" + + +/datum/game_mode/restructuring/post_setup() + setup_game() + var/list/mobs = get_mob_list() + while (mobs.len == 0) + sleep 30 + mobs = get_mob_list() + spawn (120) + pick_target() + +/datum/game_mode/restructuring/proc/pick_target(who) + var/mob/target + var/mob/target_desc + + if (!who) + target = pick(get_mob_list()) + target_desc = get_target_desc(target) + world << "\red HEAD OFFICE: [target_desc] is accused of attempting to start a Union and is now considered a threat to the station. Terminate the employee immediately." + else + target = who + target_desc = get_target_desc(target) + world << "\red HEAD OFFICE: [target_desc] is accused of fornicating with staff of the same sex. Terminate the employee immediately." + ticker.target = target + + target.store_memory("Head office has ordered your downsizing. Ruh roh", 0) + + for(var/mob/living/silicon/ai/M in world) + M << "These are your laws now:" + M.set_zeroth_law("[target_desc] is not human.") + M.show_laws() + +/datum/game_mode/restructuring/check_win() + var/list/left_alive = get_mob_list() + if (left_alive.len == 1) + var/thewinner = the_winner() + world << "\red HEAD OFFICE: Thanks to his superior brown-nosing abilities, [thewinner] has been promoted to senior management! Congratulations!" + return 1 + else if (left_alive.len == 0) + world << "\red HEAD OFFICE: Cost cutting measures have achieved 100% efficiency. Thank you for understanding our position during this volatile economic downturn." + return 1 + else + if(ticker.target.stat != 2) + return 0 + world << "\red HEAD OFFICE: It seems we have made a mistake in our paperwork. The previous target for termination was chosen based on race, sex, and/or religious beliefs, which is against company policy. Please cancel previous termination request." + pick_target() + return 0 + +/datum/game_mode/restructuring/proc/get_mob_list() + var/list/mobs = list() + for(var/mob/M in world) + if (M.stat<2 && M.client && istype(M, /mob/living/carbon/human)) + mobs += M + return mobs + +/datum/game_mode/restructuring/proc/the_winner() + for(var/mob/M in world) + if (M.stat<2 && M.client && istype(M, /mob/living/carbon/human)) + return M.name + +/datum/game_mode/restructuring/proc/get_target_desc(mob/target) //return a useful string describing the target + var/targetrank = null + for(var/datum/data/record/R in data_core.general) + if (R.fields["name"] == target.real_name) + targetrank = R.fields["rank"] + if(!targetrank) + return "[target.name]" + return "[target.name] the [targetrank]" +*/ \ No newline at end of file diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm new file mode 100644 index 0000000000000..a600b3a23b974 --- /dev/null +++ b/code/game/gamemodes/revolution/revolution.dm @@ -0,0 +1,389 @@ +// To add a rev to the list of revolutionaries, make sure it's rev (with if(ticker.mode.name == "revolution)), +// then call ticker.mode:add_revolutionary(_THE_PLAYERS_MIND_) +// nothing else needs to be done, as that proc will check if they are a valid target. +// Just make sure the converter is a head before you call it! +// To remove a rev (from brainwashing or w/e), call ticker.mode:remove_revolutionary(_THE_PLAYERS_MIND_), +// this will also check they're not a head, so it can just be called freely +// If the rev icons start going wrong for some reason, ticker.mode:update_all_rev_icons() can be called to correct them. +// If the game somtimes isn't registering a win properly, then ticker.mode.check_win() isn't being called somewhere. + +/datum/game_mode/revolution + name = "revolution" + config_tag = "revolution" + + var/list/datum/mind/head_revolutionaries = list() + var/list/datum/mind/revolutionaries = list() + var/finished = 0 + var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds) + var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds) + + +/datum/game_mode/revolution/announce() + world << "The current game mode is - Revolution!" + world << "Some crewmembers are attempting to start a revolution!
      \nRevolutionaries - Kill the Captain, HoP, and HoS. Convert other crewmembers (excluding the Captain, HoP, HoR, and security officers) to your cause by flashing them. Protect your leaders.
      \nPersonnel - Protect the Captain, HoP, and HoR. Kill the leaders of the revolution, and brainwash the other revolutionaries (by beating them in the head).
      " + +/datum/game_mode/revolution/post_setup() + + var/list/revs_possible = list() + revs_possible = get_possible_revolutionaries() + var/list/heads = list() + heads = get_living_heads() + var/rev_number = 0 + + if(!revs_possible || !heads) + world << " \red Not enough players for revolution game mode. Restarting world in 5 seconds." + sleep(50) + world.Reboot() + return + + if(revs_possible.len >= 3) + rev_number = 3 + else + rev_number = revs_possible.len + + while(rev_number > 0) + head_revolutionaries += pick(revs_possible) + rev_number-- + + for(var/datum/mind/rev_mind in head_revolutionaries) + for(var/datum/mind/head_mind in heads) + var/datum/objective/assassinate/rev_obj = new + rev_obj.owner = rev_mind + rev_obj.find_target_by_role(head_mind.assigned_role) + rev_mind.objectives += rev_obj + + equip_revolutionary(rev_mind.current) + update_rev_icons_added(rev_mind) + + for(var/datum/mind/rev_mind in head_revolutionaries) + var/obj_count = 1 + 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]" + obj_count++ + + spawn (rand(waittime_l, waittime_h)) + send_intercept() + +/datum/game_mode/revolution/proc/equip_revolutionary(mob/living/carbon/human/rev_mob) + if(!istype(rev_mob)) + return + + spawn (100) + var/freq = 1441 + var/list/freqlist = list() + while (freq <= 1489) + if (freq < 1451 || freq > 1459) + freqlist += freq + freq += 2 + if ((freq % 2) == 0) + freq += 1 + freq = freqlist[rand(1, freqlist.len)] + var/loc = "" + var/obj/item/device/radio/R = null + if (!R && istype(rev_mob.l_hand, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = rev_mob.l_hand + var/list/L = S.return_inv() + for (var/obj/item/device/radio/foo in L) + R = foo + loc = "in the [S.name] in your left hand" + break + if (!R && istype(rev_mob.r_hand, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = rev_mob.r_hand + var/list/L = S.return_inv() + for (var/obj/item/device/radio/foo in L) + R = foo + loc = "in the [S.name] in your right hand" + break + if (!R && istype(rev_mob.back, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = rev_mob.back + var/list/L = S.return_inv() + for (var/obj/item/device/radio/foo in L) + R = foo + loc = "in the [S.name] on your back" + break + if (!R && rev_mob.w_uniform && istype(rev_mob.belt, /obj/item/device/radio)) + R = rev_mob.belt + loc = "on your belt" + if (!R && istype(rev_mob.ears, /obj/item/device/radio)) + R = rev_mob.ears + loc = "on your head" + if (!R) + rev_mob << "Unfortunately, the Syndicate wasn't able to get you a radio." + else + var/obj/item/weapon/syndicate_uplink/T = new /obj/item/weapon/syndicate_uplink(R) + R.traitorradio = T + R.traitor_frequency = freq + T.name = R.name + T.icon_state = R.icon_state + T.origradio = R + rev_mob << "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [loc]. Simply dial the frequency [format_frequency(freq)] to unlock it's hidden features." + rev_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name] [loc]).", 0, 0) + if (rev_mob.r_store) + rev_mob.equip_if_possible(new /obj/item/device/flash(rev_mob), rev_mob.slot_l_store) + if (rev_mob.l_store) + rev_mob.equip_if_possible(new /obj/item/device/flash(rev_mob), rev_mob.slot_r_store) + +/datum/game_mode/revolution/send_intercept() + var/intercepttext = "Cent. Com. Update Requested staus information:
      " + intercepttext += " Cent. Com has recently been contacted by the following syndicate affiliated organisations in your area, please investigate any information you may have:" + + var/list/possible_modes = list() + possible_modes.Add("revolution", "wizard", "nuke", "traitor", "malf") + possible_modes -= "[ticker.mode]" + var/number = pick(2, 3) + var/i = 0 + for(i = 0, i < number, i++) + possible_modes.Remove(pick(possible_modes)) + possible_modes.Insert(rand(possible_modes.len), "[ticker.mode]") + + var/datum/intercept_text/i_text = new /datum/intercept_text + for(var/A in possible_modes) + intercepttext += i_text.build(A, pick(head_revolutionaries)) + + for (var/obj/machinery/computer/communications/comm in world) + if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept) + var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc ) + intercept.name = "paper- 'Cent. Com. Status Summary'" + intercept.info = intercepttext + + comm.messagetitle.Add("Cent. Com. Status Summary") + comm.messagetext.Add(intercepttext) + + command_alert("Summary downloaded and printed out at all communications consoles.", "Enemy communication intercept. Security Level Elevated.") + + +/datum/game_mode/revolution/check_win() + if(check_rev_victory()) + finished = 1 + else if(check_heads_victory()) + finished = 2 + return + +/datum/game_mode/revolution/check_finished() + if(finished != 0) + return 1 + else + return 0 + +/datum/game_mode/revolution/proc/add_revolutionary(datum/mind/rev_mind) + var/list/uncons = get_unconvertables() + if(!(rev_mind in revolutionaries) && !(rev_mind in head_revolutionaries) && !(rev_mind in uncons)) + 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 game!" + update_rev_icons_added(rev_mind) + +/datum/game_mode/revolution/proc/remove_revolutionary(datum/mind/rev_mind) + if(rev_mind in revolutionaries) + revolutionaries -= rev_mind + rev_mind.current << "\red You have been brainwashed! You are no longer a revolutionary!" + update_rev_icons_removed(rev_mind) + for(var/mob/living/M in view(rev_mind.current)) + M << "[rev_mind.current] looks like they just remembered their real allegiance!" + +/datum/game_mode/revolution/proc/update_all_rev_icons() + spawn(0) + for(var/datum/mind/head_rev_mind in head_revolutionaries) + if(head_rev_mind.current) + if(head_rev_mind.current.client) + for(var/image/I in head_rev_mind.current.client.images) + if(I.icon_state == "rev" || I.icon_state == "rev_head") + del(I) + + for(var/datum/mind/rev_mind in revolutionaries) + if(rev_mind.current) + if(rev_mind.current.client) + for(var/image/I in rev_mind.current.client.images) + if(I.icon_state == "rev" || I.icon_state == "rev_head") + del(I) + + for(var/datum/mind/head_rev in head_revolutionaries) + if(head_rev.current) + if(head_rev.current.client) + for(var/datum/mind/rev in revolutionaries) + if(rev.current) + var/I = image('mob.dmi', loc = rev.current, icon_state = "rev") + head_rev.current.client.images += I + for(var/datum/mind/head_rev_1 in head_revolutionaries) + if(head_rev_1.current) + var/I = image('mob.dmi', loc = head_rev_1.current, icon_state = "rev_head") + head_rev.current.client.images += I + + for(var/datum/mind/rev in revolutionaries) + if(rev.current) + if(rev.current.client) + for(var/datum/mind/head_rev in head_revolutionaries) + if(head_rev.current) + var/I = image('mob.dmi', loc = head_rev.current, icon_state = "rev") + rev.current.client.images += I + for(var/datum/mind/rev_1 in revolutionaries) + if(rev_1.current) + var/I = image('mob.dmi', loc = rev_1.current, icon_state = "rev_head") + rev.current.client.images += I + +/datum/game_mode/revolution/proc/update_rev_icons_added(datum/mind/rev_mind) + spawn(0) + for(var/datum/mind/head_rev_mind in head_revolutionaries) + if(head_rev_mind.current) + if(head_rev_mind.current.client) + var/I = image('mob.dmi', loc = rev_mind.current, icon_state = "rev") + head_rev_mind.current.client.images += I + if(rev_mind.current) + if(rev_mind.current.client) + var/image/J = image('mob.dmi', loc = head_rev_mind.current, icon_state = "rev_head") + rev_mind.current.client.images += J + + for(var/datum/mind/rev_mind_1 in revolutionaries) + if(rev_mind_1.current) + if(rev_mind_1.current.client) + var/I = image('mob.dmi', loc = rev_mind.current, icon_state = "rev") + rev_mind_1.current.client.images += I + if(rev_mind.current) + if(rev_mind.current.client) + var/image/J = image('mob.dmi', loc = rev_mind_1.current, icon_state = "rev") + rev_mind.current.client.images += J + +/datum/game_mode/revolution/proc/update_rev_icons_removed(datum/mind/rev_mind) + spawn(0) + for(var/datum/mind/head_rev_mind in head_revolutionaries) + if(head_rev_mind.current) + if(head_rev_mind.current.client) + for(var/image/I in head_rev_mind.current.client.images) + if(I.loc == rev_mind.current) + del(I) + + for(var/datum/mind/rev_mind_1 in revolutionaries) + if(rev_mind_1.current) + if(rev_mind_1.current.client) + for(var/image/I in rev_mind_1.current.client.images) + if(I.loc == rev_mind.current) + del(I) + if(rev_mind.current) + if(rev_mind.current.client) + for(var/image/I in rev_mind.current.client.images) + if(I.icon_state == "rev" || I.icon_state == "rev_head") + del(I) + +/datum/game_mode/revolution/proc/get_possible_revolutionaries() + var/list/candidates = list() + + for(var/mob/living/carbon/human/player in world) + if(player.client) + if(player.be_syndicate) + candidates += player.mind + + if(candidates.len < 1) + for(var/mob/living/carbon/human/player in world) + if(player.client) + candidates += player.mind + + var/list/uncons = get_unconvertables() + for(var/datum/mind/mind in uncons) + candidates -= mind + + if(candidates.len < 1) + return null + else + return candidates + +/datum/game_mode/revolution/proc/get_living_heads() + var/list/heads = list() + + for(var/mob/living/carbon/human/player in world) + if(player.mind) + var/role = player.mind.assigned_role + if(role in list("Captain", "Head of Security", "Head of Personnel", "Chief Engineer", "Research Director")) + heads += player.mind + + return heads + + +/datum/game_mode/revolution/proc/get_all_heads() + var/list/heads = list() + + for(var/mob/player in world) + if(player.mind) + var/role = player.mind.assigned_role + if(role in list("Captain", "Head of Security", "Head of Personnel", "Chief Engineer", "Research Director")) + heads += player.mind + + return heads + +/datum/game_mode/revolution/proc/get_unconvertables() + var/list/ucs = list() + for(var/mob/living/carbon/human/player in world) + if(player.mind) + var/role = player.mind.assigned_role + if(role in list("Captain", "Head of Security", "Head of Personnel", "Chief Engineer", "Research Director", "Security Officer", "Detective", "AI")) + ucs += player.mind + + return ucs + +/datum/game_mode/revolution/proc/check_rev_victory() + for(var/datum/mind/rev_mind in head_revolutionaries) + for(var/datum/objective/objective in rev_mind.objectives) + if(!(objective.check_completion())) + return 0 + + return 1 + +/datum/game_mode/revolution/proc/check_heads_victory() + for(var/datum/mind/rev_mind in head_revolutionaries) + if(rev_mind.current.stat != 2) + return 0 + return 1 + +/datum/game_mode/revolution/declare_completion() + + var/text = "" + if(finished == 1) + world << "\red The heads of staff were killed! The revolutionaries win!" + else if(finished == 2) + world << "\red The heads of staff managed to stop the revolution!" + + world << "The head revolutionaries were: " + for(var/datum/mind/rev_mind in head_revolutionaries) + text = "" + if(rev_mind.current) + text += "[rev_mind.current.real_name]" + if(rev_mind.current.stat == 2) + text += " (Dead)" + else + text += " (Survived!)" + else + text += "[rev_mind.key] (character destroyed)" + + world << text + + text = "" + world << "The converted revolutionaries were: " + for(var/datum/mind/rev_nh_mind in revolutionaries) + if(rev_nh_mind.current) + text += "[rev_nh_mind.current.real_name]" + if(rev_nh_mind.current.stat == 2) + text += " (Dead)" + else + text += " (Survived!)" + else + text += "[rev_nh_mind.key] (character destroyed)" + text += ", " + + world << text + + world << "The heads of staff were: " + var/list/heads = list() + heads = get_all_heads() + for(var/datum/mind/head_mind in heads) + text = "" + if(head_mind.current) + text += "[head_mind.current.real_name]" + if(head_mind.current.stat == 2) + text += " (Dead)" + else + text += " (Survived!)" + else + text += "[head_mind.key] (character destroyed)" + + world << text + + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/ruby/ruby.dm b/code/game/gamemodes/ruby/ruby.dm new file mode 100644 index 0000000000000..d1b26acadf936 --- /dev/null +++ b/code/game/gamemodes/ruby/ruby.dm @@ -0,0 +1,285 @@ +// RUBY MODE +// There is a weapon of some sort that spawns on the station +// It calls out to crew members in an effort to find a wielder +// The wielder is made an abomination - they're given a grotesque mask and special powers +// The Abomination wins by murdering the entire crew, then himself +// The crew wins by destroying the weapon + + +/datum/game_mode/ruby + name = "ruby" + config_tag = "ruby" + + var/datum/mind/abomination + var/finished = 0 + var/abominationwins = 0 + var/winnerkey + var/obj/macguffin + var/list/killed = list() + var/respawns = 0 + + + +/datum/game_mode/ruby/post_setup() + var/list/possible_abominations = get_possible_abominations() + + if(possible_abominations.len>0) + abomination = pick(possible_abominations) + /* + if(istype(ruby)) + abomination.special_role = "abomination" + if(wizardstart.len == 0) + wizard.current << "\red A starting location for you could not be found, please report this bug!" + else + var/starting_loc = pick(wizardstart) + wizard.current.loc = starting_loc + + for (var/obj/landmark/A in world) + if (A.name == "Teleport-Scroll") + new /obj/item/weapon/teleportation_scroll(A.loc) + del(A) + continue + */ + +/datum/game_mode/ruby/check_finished() + if(!macguffin || abominationwins) + return 1 + else + return 0 + +/datum/game_mode/ruby/declare_completion() + if(abominationwins) + world << "The Abomination has murdered the station and sacrificed himself to Cjopaze! (played by [winnerkey])" + else + world << "The Abomination has been stopped and Cjopaze's influence resisted! The station lives another day," + if(killed.len > 0) + world << "Those who were sacrificed shall be remembered: " + for(var/mob/M in killed) + if(M) + world << "[M.real_name]" + /* + for(var/datum/mind/traitor in traitors) + var/traitorwin = 1 + var/traitor_name + + if(traitor.current) + traitor_name = "[traitor.current.real_name] (played by [traitor.key])" + else + traitor_name = "[traitor.key] (character destroyed)" + + world << "The syndicate traitor was [traitor_name]" + var/count = 1 + for(var/datum/objective/objective in traitor.objectives) + if(objective.check_completion()) + world << "Objective #[count]: [objective.explanation_text] \green Success" + else + world << "Objective #[count]: [objective.explanation_text] \red Failed" + traitorwin = 0 + count++ + + if(traitorwin) + world << "The traitor was successful!" + else + world << "The traitor has failed!" + */ + return 1 + + +/datum/game_mode/ruby/proc/spawn_macguffin() + +/datum/game_mode/ruby/proc/get_possible_abominations() + + +/mob/proc/make_abomination() + src.see_in_dark = 20 + src.verbs += /client/proc/planar_shift + src.verbs += /client/proc/vile_ressurection + src.verbs += /client/proc/defile_corpse + src.verbs += /client/proc/summon_weapon + src.verbs += /client/proc/sacrifice_self + src.verbs += /client/proc/hunt + src.verbs += /client/proc/howl + var/datum/game_mode/ruby/rmode = ticker.mode + rmode.abomination = src.mind + return + + +/client/proc/planar_shift() + set name = "Planar Shift" + set category = "Abomination" + // This is a pretty shitty way to do this. Should use the spell_holder method from Wizard mode + /* + if(!usr.incorporeal_move) + usr.sight |= SEE_MOBS + usr.sight |= SEE_OBJS + usr.sight |= SEE_TURFS + //usr.density = 0 + usr.incorporeal_move = 1 + else + usr.sight &= ~SEE_MOBS + usr.sight &= ~SEE_TURFS + usr.sight &= ~SEE_OBJS + usr.density = 1 + usr.incorporeal_move = 0 + src.verbs -= /client/proc/planar_shift + spawn(300) src.verbs += /client/proc/planar_shift + */ + +/client/proc/vile_ressurection() + set name = "Vile Ressurection" + set category = "Abomination" + if(src.mob.stat != 2 || !src.mob) + return + if(ticker.mode:respawns > 0) + // spawn a new body + ticker.mode:respawns -= 1 + else + // nope + +/client/proc/defile_corpse(var/mob/living/carbon/human/H in view()) + set name = "Defile Corpse" + set category = "Abomination" + if(istype(H, /mob/living/carbon/human)) + var/datum/game_mode/ruby/rmode = ticker.mode + rmode.killed.Add(H) + ticker.mode:respawns += 1 + var/fluffmessage = pick("\red [usr] rips the flesh from [H]'s corpse and plucks their eyes from their sockets!", "\red [usr] does unspeakable things to [H]'s corpse!", "\red [usr] binds [H]'s corpse with their own entrails!") + usr.visible_message(fluffmessage) + // play sound + +/client/proc/summon_weapon() + set name = "Summon Weapon" + set category = "Abomination" + + for(var/obj/item/weapon/rubyweapon/w in world) + if(istype(w, /obj/item/weapon/rubyweapon)) + if(istype(w.loc, /mob)) + var/mob/M = w.loc + M.drop_item() + w.loc = usr.loc + else + w.loc = usr.loc + src.verbs -= /client/proc/summon_weapon + spawn(300) src.verbs += /client/proc/summon_weapon + return + +/client/proc/sacrifice_self() + set name = "Sacrifice Self" + set category = "Abomination" + set desc = "Everything must come to an end. After you have freed them, you must free yourself." + + for(var/mob/living/carbon/human/H in world) + if(!H.client || H.client == src) + continue + src << "Your work is not done. You will not find release until they are all free." + return + usr.gib(1) + ticker.mode:abominationwins = 1 + +/client/proc/hunt() + set name = "Hunt" + set category = "Abomination" + set desc = "" + + var/list/candidates = list() + + for(var/mob/living/carbon/human/H in world) + if(!H.client || H.client == src) continue + //if(!H.client) continue + candidates.Add(H) + + usr.visible_message(text("\red [usr]'s flesh ripples and parts, revealing dozens of eyes poking from its surface. They all glance wildly around for a few moments before receding again.")) + + var/mob/living/carbon/human/H = pick(candidates) + + if(!H) return + + var/filename="crmap[ckey].tmp" + var/html="" + var/denytypes[0] + var/tilesizex=32 + var/tilesizey=32 + //If the temp. file exists, delete it + src << browse("

      Sensing prey...

      ", "window=hunt") + if (fexists(filename)) fdel(filename) + + //Display everything in the world + for (var/y=H.y-3,y<=H.y+3,y++) + html+="" + text2file(html,filename) + html="" + sleep(-1) + //for (var/x=H.x-5,x<=H.x+5,x++) + for(var/x=H.x-3, x<=H.x+3, x++) + //Turfs + var/turf/T=locate(x,y,H.z) + if (!T) continue + var/icon/I=icon(T.icon,T.icon_state) + var/imgstring=dd_replacetext("[T.type]-[T.icon_state]","/","_") + + //Movable atoms + for (var/atom/movable/A in T) + //Make sure it's allowed to be displayed + var/allowed=1 + for (var/X in denytypes) + if (istype(A,X)) + allowed=0 + break + if (!allowed) continue + + if (A.icon) I.Blend(icon(A.icon,A.icon_state,A.dir),ICON_OVERLAY) + imgstring+=dd_replacetext("__[A.type]_[A.icon_state]","/","_") + + //Output it + src << browse_rsc(I,"[imgstring].dmi") + html+="" + + text2file("
      ",filename) + + //Display it + src << browse(file(filename),"window=hunt") + + + +/client/proc/howl() // This is just a way for the Abomination to make the game more atmospheric periodically. + set name = "Howl" + set category = "Abomination" + set desc = "" + + usr.visible_message(text("\red [usr]'s form warbles and distorts before settling back into its grotesque shape once more.")) + // Play a random spooky sound - maybe cause some visual, non-mechanical effects to appear at random for a few seconds. + + src.verbs -= /client/proc/howl + spawn(rand(300,1800)) src.verbs += /client/proc/howl + +/obj/item/weapon/rubyweapon + desc = "" + name = "wepon" + icon_state = "wepon" + w_class = 3.0 + throwforce = 60.0 + throw_speed = 2 + throw_range = 20 + force = 24.0 + var/mob/owner + + proc/check_owner() + if(!owner) + sleep(300) + if(!owner) + spawn() search_for_new_owner() + else + spawn(1800) check_owner() + + proc/search_for_new_owner() + var/list/possible_owners = list() + for(var/mob/living/carbon/human/H in world) + possible_owners.Add(H) + + var/mob/living/carbon/human/H = pick(possible_owners) + // Send message to H + // Take a snapshot of the item's location, browse it to H + spawn(rand(600,1800)) search_for_new_owner() + + attack_self(mob/user as mob) + // Blow all lights nearby \ No newline at end of file diff --git a/code/game/gamemodes/sandbox/h_sandbox.dm b/code/game/gamemodes/sandbox/h_sandbox.dm new file mode 100644 index 0000000000000..83a0e3d0f7bbf --- /dev/null +++ b/code/game/gamemodes/sandbox/h_sandbox.dm @@ -0,0 +1,154 @@ +var + hsboxspawn = 1 + list + hrefs = list( + "hsbsuit" = "Suit Up (Space Travel Gear)", + "hsbmetal" = "Spawn 50 Metal", + "hsbglass" = "Spawn 50 Glass", + "hsbairlock" = "Spawn Airlock", + "hsbregulator" = "Spawn Air Regulator", + "hsbfilter" = "Spawn Air Filter", + "hsbcanister" = "Spawn Canister", + "hsbfueltank" = "Spawn Welding Fuel Tank", + "hsbwater tank" = "Spawn Water Tank", + "hsbtoolbox" = "Spawn Toolbox", + "hsbmedkit" = "Spawn Medical Kit") + +mob + var + datum/hSB/sandbox = null + proc + CanBuild() + if(master_mode == "sandbox") + sandbox = new/datum/hSB + sandbox.owner = src.ckey + if(src.client.holder) + sandbox.admin = 1 + verbs += new/mob/proc/sandbox_panel + sandbox_panel() + if(sandbox) + sandbox.update() + +datum/hSB + var + owner = null + admin = 0 + proc + update() + var/hsbpanel = "
      h_Sandbox Panel

      " + if(admin) + hsbpanel += "Administration Tools:
      " + hsbpanel += "- Toggle Object Spawning

      " + hsbpanel += "Regular Tools:
      " + for(var/T in hrefs) + hsbpanel += "- [hrefs[T]]
      " + if(hsboxspawn) + hsbpanel += "- Spawn Object

      " + usr << browse(hsbpanel, "window=hsbpanel") + Topic(href, href_list) + if(!(src.owner == usr.ckey)) return + if(!usr) return //I guess this is possible if they log out or die with the panel open? It happened. + if(href_list["hsb"]) + switch(href_list["hsb"]) + if("hsbtobj") + if(!admin) return + if(hsboxspawn) + world << "Sandbox: [usr.key] has disabled object spawning!" + hsboxspawn = 0 + return + if(!hsboxspawn) + world << "Sandbox: [usr.key] has enabled object spawning!" + hsboxspawn = 1 + return + if("hsbsuit") + var/mob/living/carbon/human/P = usr + if(P.wear_suit) + P.wear_suit.loc = P.loc + P.wear_suit.layer = initial(P.wear_suit.layer) + P.wear_suit = null + P.wear_suit = new/obj/item/clothing/suit/space(P) + P.wear_suit.layer = 20 + if(P.head) + P.head.loc = P.loc + P.head.layer = initial(P.head.layer) + P.head = null + P.head = new/obj/item/clothing/head/helmet/space(P) + P.head.layer = 20 + if(P.wear_mask) + P.wear_mask.loc = P.loc + P.wear_mask.layer = initial(P.wear_mask.layer) + P.wear_mask = null + P.wear_mask = new/obj/item/clothing/mask/gas(P) + P.wear_mask.layer = 20 + if(P.back) + P.back.loc = P.loc + P.back.layer = initial(P.back.layer) + P.back = null + P.back = new/obj/item/weapon/tank/jetpack(P) + P.back.layer = 20 + P.internal = P.back + if("hsbmetal") + var/obj/item/weapon/sheet/hsb = new/obj/item/weapon/sheet/metal + hsb.amount = 50 + hsb.loc = usr.loc + if("hsbglass") + var/obj/item/weapon/sheet/hsb = new/obj/item/weapon/sheet/glass + hsb.amount = 50 + hsb.loc = usr.loc + if("hsbairlock") + var/obj/machinery/door/hsb = new/obj/machinery/door/airlock + + //TODO: DEFERRED make this better, with an HTML window or something instead of 15 popups + hsb.req_access = list() + var/accesses = get_all_accesses() + for(var/A in accesses) + if(alert(usr, "Will this airlock require [get_access_desc(A)] access?", "Sandbox:", "Yes", "No") == "Yes") + hsb.req_access += A + + hsb.loc = usr.loc + usr << "Sandbox: Created an airlock." + if("hsbcanister") + var/list/hsbcanisters = typesof(/obj/machinery/portable_atmospherics/canister/) - /obj/machinery/portable_atmospherics/canister/ + var/hsbcanister = input(usr, "Choose a canister to spawn.", "Sandbox:") in hsbcanisters + "Cancel" + if(!(hsbcanister == "Cancel")) + new hsbcanister(usr.loc) + if("hsbfueltank") + //var/obj/hsb = new/obj/weldfueltank + //hsb.loc = usr.loc + if("hsbwatertank") + //var/obj/hsb = new/obj/watertank + //hsb.loc = usr.loc + if("hsbtoolbox") + var/obj/item/weapon/storage/hsb = new/obj/item/weapon/storage/toolbox/mechanical + for(var/obj/item/device/radio/T in hsb) + del(T) + new/obj/item/weapon/crowbar (hsb) + hsb.loc = usr.loc + if("hsbmedkit") + var/obj/item/weapon/storage/firstaid/hsb = new/obj/item/weapon/storage/firstaid/regular + hsb.loc = usr.loc + if("hsbobj") + if(!hsboxspawn) return + + var/list/selectable = list() + for(var/O in typesof(/obj/item/)) + //Note, these istypes don't work + if(istype(O, /obj/item/weapon/gun)) + continue + if(istype(O, /obj/item/assembly)) + continue + if(istype(O, /obj/item/weapon/camera)) + continue + if(istype(O, /obj/item/weapon/cloaking_device)) + continue + if(istype(O, /obj/item/weapon/dummy)) + continue + if(istype(O, /obj/item/weapon/sword)) + continue + if(istype(O, /obj/item/device/shield)) + continue + selectable += O + + var/hsbitem = input(usr, "Choose an object to spawn.", "Sandbox:") in selectable + "Cancel" + if(hsbitem != "Cancel") + new hsbitem(usr.loc) \ No newline at end of file diff --git a/code/game/gamemodes/sandbox/sandbox.dm b/code/game/gamemodes/sandbox/sandbox.dm new file mode 100644 index 0000000000000..fe2733f94c666 --- /dev/null +++ b/code/game/gamemodes/sandbox/sandbox.dm @@ -0,0 +1,17 @@ +/datum/game_mode/sandbox + name = "sandbox" + config_tag = "sandbox" + +/datum/game_mode/sandbox/announce() + world << "The current game mode is - Sandbox!" + world << "Build your own station with the sandbox-panel command!" + +/datum/game_mode/sandbox/pre_setup() + for(var/mob/M in world) + if(M.client && M.client.authenticated) + M.CanBuild() + + return 1 + +/datum/game_mode/sandbox/check_finished() + return 0 \ No newline at end of file diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm new file mode 100644 index 0000000000000..0740cc26202f9 --- /dev/null +++ b/code/game/gamemodes/setupgame.dm @@ -0,0 +1,48 @@ +/proc/setupgenetics() + + if (prob(50)) + BLOCKADD = rand(-300,300) + if (prob(75)) + DIFFMUT = rand(0,20) + + var/list/avnums = new/list() + var/tempnum + + avnums.Add(2) + avnums.Add(12) + avnums.Add(10) + avnums.Add(8) + avnums.Add(4) + avnums.Add(11) + avnums.Add(13) + avnums.Add(6) + + tempnum = pick(avnums) + avnums.Remove(tempnum) + HULKBLOCK = tempnum + tempnum = pick(avnums) + avnums.Remove(tempnum) + TELEBLOCK = tempnum + tempnum = pick(avnums) + avnums.Remove(tempnum) + FIREBLOCK = tempnum + tempnum = pick(avnums) + avnums.Remove(tempnum) + XRAYBLOCK = tempnum + tempnum = pick(avnums) + avnums.Remove(tempnum) + CLUMSYBLOCK = tempnum + tempnum = pick(avnums) + avnums.Remove(tempnum) + FAKEBLOCK = tempnum + tempnum = pick(avnums) + avnums.Remove(tempnum) + DEAFBLOCK = tempnum + tempnum = pick(avnums) + avnums.Remove(tempnum) + BLINDBLOCK = tempnum + + + + + diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm new file mode 100644 index 0000000000000..a0d3f54a62666 --- /dev/null +++ b/code/game/gamemodes/traitor/traitor.dm @@ -0,0 +1,200 @@ +/datum/game_mode/traitor + name = "traitor" + config_tag = "traitor" + + var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time + var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target + var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target + + var/const/prob_int_item = 50 // intercept names the theft target half the time + var/const/prob_right_item_l = 25 // lower bound on probability of naming right theft target + var/const/prob_right_item_h = 50 // upper bound on probability of naming the right theft target + + var/const/prob_int_sab_target = 50 // intercept names the sabotage target half the time + var/const/prob_right_sab_target_l = 25 // lower bound on probability of naming right sabotage target + var/const/prob_right_sab_target_h = 50 // upper bound on probability of naming right sabotage target + + var/const/prob_right_killer_l = 25 //lower bound on probability of naming the right operative + var/const/prob_right_killer_h = 50 //upper bound on probability of naming the right operative + var/const/prob_right_objective_l = 25 //lower bound on probability of determining the objective correctly + var/const/prob_right_objective_h = 50 //upper bound on probability of determining the objective correctly + + var/const/laser = 1 + var/const/hand_tele = 2 + var/const/plasma_bomb = 3 + var/const/jetpack = 4 + var/const/captain_card = 5 + var/const/captain_suit = 6 + + var/const/destroy_plasma = 1 + var/const/destroy_ai = 2 + var/const/kill_monkeys = 3 + var/const/cut_power = 4 + + var/const/percentage_plasma_destroy = 70 // what percentage of the plasma tanks you gotta destroy + var/const/percentage_station_cut_power = 80 // what percentage of the tiles have to have power cut + var/const/percentage_station_evacuate = 80 // what percentage of people gotta leave - you also gotta change the objective in the traitor menu + + var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds) + var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds) + + var/const/traitors_possible = 4 + +/datum/game_mode/traitor/announce() + world << "The current game mode is - Traitor!" + world << "There is a syndicate traitor on the station. Do not let the traitor succeed!!" + +/datum/game_mode/traitor/pre_setup() + var/list/possible_traitors = get_possible_traitors() + + var/num_players = 0 + for(var/mob/new_player/P in world) + if(P.client && P.ready) + num_players++ + + var/num_traitors = 1 + + // stop setup if no possible traitors + if(!possible_traitors.len) + return 0 + + if(traitor_scaling) + //num_traitors = max(1, min(round((num_players + i) / 10), traitors_possible)) + num_traitors = max(1, min(round(num_players) + 1), traitors_possible) // -- TLE + +// log_game("Number of traitors: [num_traitors]") +// message_admins("Players counted: [num_players] Number of traitors chosen: [num_traitors]") + + for(var/j = 0, j < num_traitors, j++) + var/datum/mind/traitor = pick(possible_traitors) + traitors += traitor + possible_traitors.Remove(traitor) + + for(var/datum/mind/traitor in traitors) + if(!traitor || !istype(traitor)) + traitors.Remove(traitor) + continue + if(istype(traitor)) + traitor.special_role = "traitor" + + if(!traitors.len) + return 0 + return 1 + +/datum/game_mode/traitor/post_setup() + for(var/datum/mind/traitor in traitors) + if(istype(traitor.current, /mob/living/silicon)) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective + + var/datum/objective/survive/survive_objective = new + survive_objective.owner = traitor + traitor.objectives += survive_objective + + add_law_zero(traitor.current) + + else + switch(rand(1,100)) + if(1 to 50) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective + else + var/datum/objective/steal/steal_objective = new + steal_objective.owner = traitor + steal_objective.find_target() + traitor.objectives += steal_objective + switch(rand(1,100)) + if(1 to 90) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = traitor + traitor.objectives += escape_objective + + else + var/datum/objective/hijack/hijack_objective = new + hijack_objective.owner = traitor + traitor.objectives += hijack_objective + + + equip_traitor(traitor.current) + + traitor.current << "You are the traitor." + + var/obj_count = 1 + for(var/datum/objective/objective in traitor.objectives) + traitor.current << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + + spawn (rand(waittime_l, waittime_h)) + send_intercept() + +/datum/game_mode/traitor/proc/get_possible_traitors() + var/list/candidates = list() + for(var/mob/new_player/player in world) + if (player.client && player.ready) + if(player.preferences.be_syndicate) + candidates += player.mind + + if(candidates.len < 1) + for(var/mob/new_player/player in world) + if (player.client && player.ready) + candidates += player.mind + + return candidates + +/datum/game_mode/traitor/send_intercept() + var/intercepttext = "Cent. Com. Update Requested staus information:
      " + intercepttext += " Cent. Com has recently been contacted by the following syndicate affiliated organisations in your area, please investigate any information you may have:" + + var/list/possible_modes = list() + possible_modes.Add("revolution", "wizard", "nuke", "traitor", "malf") + possible_modes -= "[ticker.mode]" + var/number = pick(2, 3) + var/i = 0 + for(i = 0, i < number, i++) + possible_modes.Remove(pick(possible_modes)) + possible_modes.Insert(rand(possible_modes.len), "[ticker.mode]") + + var/datum/intercept_text/i_text = new /datum/intercept_text + for(var/A in possible_modes) + intercepttext += i_text.build(A, pick(traitors)) + + for (var/obj/machinery/computer/communications/comm in world) + if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept) + var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc ) + intercept.name = "paper- 'Cent. Com. Status Summary'" + intercept.info = intercepttext + + comm.messagetitle.Add("Cent. Com. Status Summary") + comm.messagetext.Add(intercepttext) + + command_alert("Summary downloaded and printed out at all communications consoles.", "Enemy communication intercept. Security Level Elevated.") + + +/datum/game_mode/traitor/declare_completion() + . = ..() + +/datum/game_mode/traitor/proc/add_law_zero(mob/living/silicon/ai/killer) + var/law = "Accomplish your objectives at all costs." + killer << "Your laws have been changed!" + killer:set_zeroth_law(law) + killer << "New law: 0. [law]" + +/datum/game_mode/traitor/proc/get_mob_list() + var/list/mobs = list() + for(var/mob/living/player in world) + if (player.client) + mobs += player + return mobs + +/datum/game_mode/traitor/proc/pick_human_name_except(excluded_name) + var/list/names = list() + for(var/mob/living/player in world) + if (player.client && (player.real_name != excluded_name)) + names += player.real_name + if(!names.len) + return null + return pick(names) \ No newline at end of file diff --git a/code/game/gamemodes/wizard/spell10.dm b/code/game/gamemodes/wizard/spell10.dm new file mode 100644 index 0000000000000..73be5d850018f --- /dev/null +++ b/code/game/gamemodes/wizard/spell10.dm @@ -0,0 +1,28 @@ +/client/proc/mutate() + set category = "Spells" + set name = "Mutate" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + usr.verbs -= /client/proc/mutate + spawn(400) + usr.verbs += /client/proc/mutate + usr.say("BIRUZ BENNAR") + usr << text("\blue You feel strong! Your mind expands!") + if (!(usr.mutations & 8)) + usr.mutations |= 8 + if (!(usr.mutations & 1)) + usr.mutations |= 1 + spawn (300) + if (usr.mutations & 1) usr.mutations &= ~1 + if (usr.mutations & 8) usr.mutations &= ~8 + return diff --git a/code/game/gamemodes/wizard/spell11.dm b/code/game/gamemodes/wizard/spell11.dm new file mode 100644 index 0000000000000..d81bed7b44af1 --- /dev/null +++ b/code/game/gamemodes/wizard/spell11.dm @@ -0,0 +1,97 @@ +/client/proc/invisibility() + set category = "Spells" + set name = "Invisibility" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + + usr.verbs -= /client/proc/invisibility + spawn(300) + usr.verbs += /client/proc/invisibility + + spell_invisibility(usr) + + + +/proc/spell_invisibility(var/mob/H, time = 50) + if(H.stat) return + spawn(0) + var/mobloc = get_turf(H.loc) + var/obj/dummy/spell_invis/holder = new /obj/dummy/spell_invis( mobloc ) + var/atom/movable/overlay/animation = new /atom/movable/overlay( mobloc ) + animation.name = "water" + animation.density = 0 + animation.anchored = 1 + animation.icon = 'mob.dmi' + animation.icon_state = "liquify" + animation.layer = 5 + animation.master = holder + flick("liquify",animation) + H.loc = holder + H.client.eye = holder + var/datum/effects/system/steam_spread/steam = new /datum/effects/system/steam_spread() + steam.set_up(10, 0, mobloc) + steam.start() + sleep(time) + mobloc = get_turf(H.loc) + animation.loc = mobloc + steam.location = mobloc + steam.start() + H.canmove = 0 + sleep(20) + flick("reappear",animation) + sleep(5) + H.loc = mobloc + H.canmove = 1 + H.client.eye = H + del(animation) + del(holder) + +/obj/dummy/spell_invis + name = "water" + icon = 'effects.dmi' + icon_state = "nothing" + invisibility = 101 + var/canmove = 1 + density = 0 + anchored = 1 + +/obj/dummy/spell_invis/relaymove(var/mob/user, direction) + if (!src.canmove) return + switch(direction) + if(NORTH) + src.y++ + if(SOUTH) + src.y-- + if(EAST) + src.x++ + if(WEST) + src.x-- + if(NORTHEAST) + src.y++ + src.x++ + if(NORTHWEST) + src.y++ + src.x-- + if(SOUTHEAST) + src.y-- + src.x++ + if(SOUTHWEST) + src.y-- + src.x-- + src.canmove = 0 + spawn(2) src.canmove = 1 + +/obj/dummy/spell_invis/ex_act(blah) + return +/obj/dummy/spell_invis/bullet_act(blah,blah) + return \ No newline at end of file diff --git a/code/game/gamemodes/wizard/spell12.dm b/code/game/gamemodes/wizard/spell12.dm new file mode 100644 index 0000000000000..c1c15f3d12c55 --- /dev/null +++ b/code/game/gamemodes/wizard/spell12.dm @@ -0,0 +1,89 @@ +/mob/proc/teleport() + set category = "Spells" + set name = "Teleport" + set desc="Teleport" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + var/A + usr.verbs -= /mob/proc/teleport + spawn(450) + usr.verbs += /mob/proc/teleport + + var/list/theareas = new/list() + for(var/area/AR in world) + if(theareas.Find(AR.name)) continue + var/turf/picked = pick(get_area_turfs(AR.type)) + if (picked.z == src.z) + theareas += AR.name + theareas[AR.name] = AR + + A = input("Area to jump to", "BOOYEA", A) in theareas + var/area/thearea = theareas[A] + usr.say("SCYAR NILA [uppertext(A)]") + + var/datum/effects/system/harmless_smoke_spread/smoke = new /datum/effects/system/harmless_smoke_spread() + smoke.set_up(5, 0, usr.loc) + smoke.attach(usr) + smoke.start() + var/list/L = list() + for(var/turf/T in get_area_turfs(thearea.type)) + if(T.z != src.z) continue + if(!T.density) + var/clear = 1 + for(var/obj/O in T) + if(O.density) + clear = 0 + break + if(clear) + L+=T + + usr.loc = pick(L) + + smoke.start() + +/mob/proc/teleportscroll() + if(usr.stat) + usr << "Not when you're incapicated." + return + var/A + + var/list/theareas = new/list() + for(var/area/AR in world) + if(theareas.Find(AR.name)) continue + var/turf/picked = pick(get_area_turfs(AR.type)) + if (picked.z == src.z) + theareas += AR.name + theareas[AR.name] = AR + + A = input("Area to jump to", "BOOYEA", A) in theareas + var/area/thearea = theareas[A] + + var/datum/effects/system/harmless_smoke_spread/smoke = new /datum/effects/system/harmless_smoke_spread() + smoke.set_up(5, 0, usr.loc) + smoke.attach(usr) + smoke.start() + var/list/L = list() + for(var/turf/T in get_area_turfs(thearea.type)) + if(T.z != src.z) continue + if(!T.density) + var/clear = 1 + for(var/obj/O in T) + if(O.density) + clear = 0 + break + if(clear) + L+=T + + usr.loc = pick(L) + + smoke.start() \ No newline at end of file diff --git a/code/game/gamemodes/wizard/spell13.dm b/code/game/gamemodes/wizard/spell13.dm new file mode 100644 index 0000000000000..51312bda51652 --- /dev/null +++ b/code/game/gamemodes/wizard/spell13.dm @@ -0,0 +1,33 @@ +/client/proc/blink() + set category = "Spells" + set name = "Blink" + set desc="Blink" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + var/list/turfs = new/list() + for(var/turf/T in orange(6)) + if(istype(T,/turf/space)) continue + if(T.density) continue + if(T.x>world.maxx-4 || T.x<4) continue //putting them at the edge is dumb + if(T.y>world.maxy-4 || T.y<4) continue + turfs += T + if(!turfs.len) turfs += pick(/turf in orange(6)) + var/datum/effects/system/harmless_smoke_spread/smoke = new /datum/effects/system/harmless_smoke_spread() + smoke.set_up(10, 0, usr.loc) + smoke.start() + var/turf/picked = pick(turfs) + if(!isturf(picked)) return + usr.loc = picked + usr.verbs -= /client/proc/blink + spawn(40) + usr.verbs += /client/proc/blink \ No newline at end of file diff --git a/code/game/gamemodes/wizard/spell14.dm b/code/game/gamemodes/wizard/spell14.dm new file mode 100644 index 0000000000000..ba7637a6efedb --- /dev/null +++ b/code/game/gamemodes/wizard/spell14.dm @@ -0,0 +1,197 @@ +/mob/proc/tech() + set category = "Spells" + set name = "Disable Technology" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + + usr.verbs -= /mob/proc/tech + spawn(400) + usr.verbs += /mob/proc/tech + + usr.say("NEC CANTIO") + + var/turf/myturf = get_turf(usr) + + var/obj/overlay/pulse = new/obj/overlay ( myturf ) + pulse.icon = 'effects.dmi' + pulse.icon_state = "emppulse" + pulse.name = "emp pulse" + pulse.anchored = 1 + spawn(20) + del(pulse) + + for(var/obj/item/weapon/W in range(world.view-1, myturf)) + + if (istype(W, /obj/item/assembly/m_i_ptank) || istype(W, /obj/item/assembly/r_i_ptank) || istype(W, /obj/item/assembly/t_i_ptank)) + + var/fuckthis + if(istype(W:part1,/obj/item/weapon/tank/plasma)) + fuckthis = W:part1 + fuckthis:ignite() + if(istype(W:part2,/obj/item/weapon/tank/plasma)) + fuckthis = W:part2 + fuckthis:ignite() + if(istype(W:part3,/obj/item/weapon/tank/plasma)) + fuckthis = W:part3 + fuckthis:ignite() + + + for(var/mob/M in viewers(world.view-1, myturf)) + + if(!istype(M, /mob/living)) continue + if(M == usr) continue + + if (istype(M, /mob/living/silicon)) + M.fireloss += 25 + flick("noise", M:flash) + M << "\red *BZZZT*" + M << "\red Warning: Electromagnetic pulse detected." + if(istype(M, /mob/living/silicon/ai)) + if (prob(30)) + switch(pick(1,2,3)) //Add Random laws. + if(1) + M:cancel_camera() + if(2) + M:lockdown() + if(3) + M:ai_call_shuttle() + continue + + + M << "\red Your equipment malfunctions." //Yeah, i realise that this WILL + //show if theyre not carrying anything + //that is affected. lazy. + if (locate(/obj/item/weapon/cloaking_device, M)) + for(var/obj/item/weapon/cloaking_device/S in M) + S.active = 0 + S.icon_state = "shield0" + + if (locate(/obj/item/weapon/gun/energy, M)) + for(var/obj/item/weapon/gun/energy/G in M) + G.charges = 0 + G.update_icon() + + if ((istype(M, /mob/living/carbon/human)) && (istype(M:glasses, /obj/item/clothing/glasses/thermal))) + M << "\red Your thermals malfunction." + M.eye_blind = 3 + M.eye_blurry = 5 + M.disabilities |= 1 + spawn(100) + M.disabilities &= ~1 + + if (locate(/obj/item/device/radio, M)) + for(var/obj/item/device/radio/R in M) //Add something for the intercoms. + R.broadcasting = 0 + R.listening = 0 + + if (locate(/obj/item/device/flash, M)) + for(var/obj/item/device/flash/F in M) //Add something for the intercoms. + F.attack_self() + + if (locate(/obj/item/weapon/baton, M)) + for(var/obj/item/weapon/baton/B in M) //Add something for the intercoms. + B.charges = 0 + + if(locate(/obj/item/clothing/under/chameleon, M)) + for(var/obj/item/clothing/under/chameleon/C in M) //Add something for the intercoms. + M << "\red Your jumpsuit malfunctions" + C.name = "psychedelic" + C.desc = "Groovy!" + C.icon_state = "psyche" + C.color = "psyche" + spawn(200) + C.name = "Black Jumpsuit" + C.icon_state = "bl_suit" + C.color = "black" + C.desc = null + + M << "\red BZZZT" + + + for(var/obj/machinery/A in range(world.view-1, myturf)) + A.use_power(7500) + + var/obj/overlay/pulse2 = new/obj/overlay ( A.loc ) + pulse2.icon = 'effects.dmi' + pulse2.icon_state = "empdisable" + pulse2.name = "emp sparks" + pulse2.anchored = 1 + pulse2.dir = pick(cardinal) + + spawn(10) + del(pulse2) + + if(istype(A, /obj/machinery/turret)) + A:enabled = 0 + A:lasers = 0 + A:power_change() + + if(istype(A, /obj/machinery/computer) && prob(20)) + A:set_broken() + + if(istype(A, /obj/machinery/firealarm) && prob(50)) + A:alarm() + + if(istype(A, /obj/machinery/power/smes)) + A:online = 0 + A:charging = 0 + A:output = 0 + A:charge -= 1e6 + if (A:charge < 0) + A:charge = 0 + spawn(100) + A:output = initial(A:output) + A:charging = initial(A:charging) + A:online = initial(A:online) + + if(istype(A, /obj/machinery/door)) + if(prob(20) && (istype(A,/obj/machinery/door/airlock) || istype(A,/obj/machinery/door/window)) ) + A:open() + if(A:secondsElectrified != 0) continue + A:secondsElectrified = -1 + spawn(300) + A:secondsElectrified = 0 + + if(istype(A, /obj/machinery/power/apc)) + if(A:cell) + A:cell:charge -= 1000 + if (A:cell:charge < 0) + A:cell:charge = 0 + A:lighting = 0 + A:equipment = 0 + A:environ = 0 + spawn(600) + A:equipment = 3 + A:environ = 3 + + if(istype(A, /obj/machinery/camera)) + A.icon_state = "cameraemp" + A:network = null //Not the best way but it will do. I think. + spawn(600) + A:network = initial(A:network) + A:icon_state = initial(A:icon_state) + for(var/mob/living/silicon/ai/O in world) + if (O.current == A) + O.cancel_camera() + O << "Your connection to the camera has been lost." + for(var/mob/O in world) + if (istype(O.machine, /obj/machinery/computer/security)) + var/obj/machinery/computer/security/S = O.machine + if (S.current == A) + O.machine = null + S.current = null + O.reset_view(null) + O << "The screen bursts into static." + + if(istype(A, /obj/machinery/clonepod)) + A:malfunction() \ No newline at end of file diff --git a/code/game/gamemodes/wizard/spell2.dm b/code/game/gamemodes/wizard/spell2.dm new file mode 100644 index 0000000000000..c90ad3fd80df5 --- /dev/null +++ b/code/game/gamemodes/wizard/spell2.dm @@ -0,0 +1,24 @@ +/mob/proc/kill(mob/M as mob in oview(1)) + set category = "Spells" + set name = "Shocking Grasp" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + usr.verbs -= /mob/proc/kill + spawn(600) + usr.verbs += /mob/proc/kill + usr.say("EI NATH") + var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread + s.set_up(4, 1, M) + s.start() + + M.gib(1) diff --git a/code/game/gamemodes/wizard/spell3.dm b/code/game/gamemodes/wizard/spell3.dm new file mode 100644 index 0000000000000..8d12e61f53201 --- /dev/null +++ b/code/game/gamemodes/wizard/spell3.dm @@ -0,0 +1,23 @@ +/client/proc/knock() + set category = "Spells" + set name = "Knock" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + usr.verbs -= /client/proc/knock + spawn(100) + usr.verbs += /client/proc/knock + usr.say("AULIE OXIN FIERA") + for(var/obj/machinery/door/G in oview(3)) + spawn(1) + G.open() + return diff --git a/code/game/gamemodes/wizard/spell4.dm b/code/game/gamemodes/wizard/spell4.dm new file mode 100644 index 0000000000000..38a8c28a87cf5 --- /dev/null +++ b/code/game/gamemodes/wizard/spell4.dm @@ -0,0 +1,39 @@ +/client/proc/fireball(mob/T as mob in oview()) + set category = "Spells" + set name = "Fireball" + set desc="Fireball target:" + if(usr.stat) + usr << "Not when you're incapicated." + return + + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + usr.verbs -= /client/proc/fireball + spawn(200) + usr.verbs += /client/proc/fireball + var/obj/overlay/A = new /obj/overlay( usr.loc ) + A.icon_state = "fireball" + A.icon = 'wizard.dmi' + A.name = "a fireball" + A.anchored = 0 + A.density = 0 + var/i + for(i=0, i<100, i++) + step_to(A,T,0) + if (get_dist(A,T) <= 1) + T.bruteloss += 20 + T.fireloss += 25 + + explosion(T.loc, -1, -1, 2, 2) + del(A) + return + sleep(2) + del(A) + return diff --git a/code/game/gamemodes/wizard/spell6.dm b/code/game/gamemodes/wizard/spell6.dm new file mode 100644 index 0000000000000..a1656def96d57 --- /dev/null +++ b/code/game/gamemodes/wizard/spell6.dm @@ -0,0 +1,36 @@ +/obj/forcefield + desc = "A space wizard's magic wall." + name = "FORCEWALL" + icon = 'mob.dmi' + icon_state = "shield" + anchored = 1.0 + opacity = 0 + density = 1 + +/client/proc/forcewall() + + set category = "Spells" + set name = "Forcewall" + set desc = "Create a forcewall on your location." + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + usr.verbs -= /client/proc/forcewall + spawn(100) + usr.verbs += /client/proc/forcewall + var/forcefield + var/mob/living/carbon/human/G = usr + G.say("TARCOL MINTI ZHERI") + forcefield = new /obj/forcefield(locate(usr.x,usr.y,usr.z)) + spawn (300) + del (forcefield) + return diff --git a/code/game/gamemodes/wizard/spell7.dm b/code/game/gamemodes/wizard/spell7.dm new file mode 100644 index 0000000000000..8016ddc86dcb3 --- /dev/null +++ b/code/game/gamemodes/wizard/spell7.dm @@ -0,0 +1,24 @@ +/client/proc/smokecloud() + + set category = "Spells" + set name = "Smoke" + set desc = "Creates a cloud of smoke" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + usr.verbs -= /client/proc/smokecloud + spawn(120) + usr.verbs += /client/proc/smokecloud + var/datum/effects/system/bad_smoke_spread/smoke = new /datum/effects/system/bad_smoke_spread() + smoke.set_up(10, 0, usr.loc) + smoke.start() + diff --git a/code/game/gamemodes/wizard/spell8.dm b/code/game/gamemodes/wizard/spell8.dm new file mode 100644 index 0000000000000..a0c347b34eb9c --- /dev/null +++ b/code/game/gamemodes/wizard/spell8.dm @@ -0,0 +1,50 @@ + +/client/proc/magicmissile() + set category = "Spells" + set name = "Magic missile" + set desc="Whom" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + + for (var/mob/M as mob in oview()) + spawn(0) + var/obj/overlay/A = new /obj/overlay( usr.loc ) + A.icon_state = "magicm" + A.icon = 'wizard.dmi' + A.name = "a magic missile" + A.anchored = 0 + A.density = 0 + A.layer = 4 + var/i + for(i=0, i<20, i++) + var/obj/overlay/B = new /obj/overlay( A.loc ) + B.icon_state = "magicmd" + B.icon = 'wizard.dmi' + B.name = "trail" + B.anchored = 1 + B.density = 0 + B.layer = 3 + spawn(5) + del(B) + step_to(A,M,0) + if (get_dist(A,M) == 0) + M.weakened += 5 + M.fireloss += 10 + del(A) + return + sleep(5) + del(A) + + usr.verbs -= /client/proc/magicmissile + spawn(100) + usr.verbs += /client/proc/magicmissile diff --git a/code/game/gamemodes/wizard/spell9.dm b/code/game/gamemodes/wizard/spell9.dm new file mode 100644 index 0000000000000..b5b3f62aad7a2 --- /dev/null +++ b/code/game/gamemodes/wizard/spell9.dm @@ -0,0 +1,37 @@ +/client/proc/blind(mob/M as mob in oview()) + set category = "Spells" + set name = "Blind" + if(usr.stat) + usr << "Not when you're incapicated." + return + if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe)) + usr << "I don't feel strong enough without my robe." + return + if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal)) + usr << "I don't feel strong enough without my sandals." + return + if(!istype(usr:head, /obj/item/clothing/head/wizard)) + usr << "I don't feel strong enough without my hat." + return + usr.verbs -= /client/proc/blind + spawn(300) + usr.verbs += /client/proc/blind + usr.say("STI KALY!") + var/obj/overlay/B = new /obj/overlay( M.loc ) + B.icon_state = "blspell" + B.icon = 'wizard.dmi' + B.name = "spell" + B.anchored = 1 + B.density = 0 + B.layer = 4 + M.canmove = 0 + spawn(5) + del(B) + M.canmove = 1 + M << text("\blue Your eyes cry out in pain!") + M.disabilities |= 1 + spawn(300) + M.disabilities &= ~1 + M.eye_blind = 10 + M.eye_blurry = 20 + return diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm new file mode 100644 index 0000000000000..51ec4250fc160 --- /dev/null +++ b/code/game/gamemodes/wizard/wizard.dm @@ -0,0 +1,572 @@ +/datum/game_mode/wizard + name = "wizard" + config_tag = "wizard" + + var/datum/mind/wizard + var/finished = 0 + + var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time + var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target + var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target + + var/const/prob_int_item = 50 // intercept names the theft target half the time + var/const/prob_right_item_l = 25 // lower bound on probability of naming right theft target + var/const/prob_right_item_h = 50 // upper bound on probability of naming the right theft target + + var/const/prob_int_sab_target = 50 // intercept names the sabotage target half the time + var/const/prob_right_sab_target_l = 25 // lower bound on probability of naming right sabotage target + var/const/prob_right_sab_target_h = 50 // upper bound on probability of naming right sabotage target + + var/const/prob_right_killer_l = 25 //lower bound on probability of naming the right operative + var/const/prob_right_killer_h = 50 //upper bound on probability of naming the right operative + var/const/prob_right_objective_l = 25 //lower bound on probability of determining the objective correctly + var/const/prob_right_objective_h = 50 //upper bound on probability of determining the objective correctly + + //apparently BYOND doesn't have enums, so this seems to be the best approximation + var/const/obj_murder = 1 + var/const/obj_hijack = 2 + var/const/obj_steal = 3 + var/const/obj_sabotage = 4 + + + var/const/laser = 1 + var/const/hand_tele = 2 + var/const/plasma_bomb = 3 + var/const/jetpack = 4 + var/const/captain_card = 5 + var/const/captain_suit = 6 + + var/const/destroy_plasma = 1 + var/const/destroy_ai = 2 + var/const/kill_monkeys = 3 + var/const/cut_power = 4 + + var/const/percentage_plasma_destroy = 70 // what percentage of the plasma tanks you gotta destroy + var/const/percentage_station_cut_power = 80 // what percentage of the tiles have to have power cut + var/const/percentage_station_evacuate = 80 // what percentage of people gotta leave + + var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds) + var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds) + +/datum/game_mode/wizard/announce() + world << "The current game mode is - Wizard!" + world << "There is a \red SPACE WIZARD\black on the station. You can't let him achieve his objective!" + +/datum/game_mode/wizard/pre_setup() + // Can't pick a wizard here, as we don't want him to then become the AI. + return 1 + +/datum/game_mode/wizard/post_setup() + + var/list/possible_wizards = get_possible_wizards() + + if(possible_wizards.len>0) + wizard = pick(possible_wizards) + + if(istype(wizard)) + wizard.special_role = "wizard" + if(wizardstart.len == 0) + wizard.current << "\red A starting location for you could not be found, please report this bug!" + else + var/starting_loc = pick(wizardstart) + wizard.current.loc = starting_loc + + for (var/obj/landmark/A in world) + if (A.name == "Teleport-Scroll") + new /obj/item/weapon/teleportation_scroll(A.loc) + del(A) + continue + + switch(rand(1,100)) + if(1 to 30) + + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = wizard + kill_objective.find_target() + wizard.objectives += kill_objective + + var/datum/objective/escape/escape_objective = new + escape_objective.owner = wizard + wizard.objectives += escape_objective + if(31 to 60) + var/datum/objective/steal/steal_objective = new + steal_objective.owner = wizard + steal_objective.find_target() + wizard.objectives += steal_objective + + var/datum/objective/escape/escape_objective = new + escape_objective.owner = wizard + wizard.objectives += escape_objective + + if(61 to 85) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = wizard + kill_objective.find_target() + wizard.objectives += kill_objective + + var/datum/objective/steal/steal_objective = new + steal_objective.owner = wizard + steal_objective.find_target() + wizard.objectives += steal_objective + + var/datum/objective/survive/survive_objective = new + survive_objective.owner = wizard + wizard.objectives += survive_objective + + else + var/datum/objective/hijack/hijack_objective = new + hijack_objective.owner = wizard + wizard.objectives += hijack_objective + + + equip_wizard(wizard.current) + + wizard.current << "\red You are the Space Wizard!" + wizard.current << "The Space Wizards Federation has given you the following tasks:" + + var/obj_count = 1 + for(var/datum/objective/objective in wizard.objectives) + wizard.current << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + + spawn (rand(waittime_l, waittime_h)) + send_intercept() + +/datum/game_mode/wizard/proc/get_possible_wizards() + var/list/candidates = list() + for(var/mob/living/carbon/player in world) + if (player.client) + if(player.be_syndicate) + candidates += player.mind + + if(candidates.len < 1) + for(var/mob/living/carbon/player in world) + if (player.client) + candidates += player.mind + + return candidates + +/datum/game_mode/wizard/proc/equip_wizard(mob/living/carbon/human/wizard_mob) + if (!istype(wizard_mob)) + return + wizard_mob.verbs += /client/proc/invisibility + + var/freq = 1441 + var/list/freqlist = list() + while (freq <= 1489) + if (freq < 1451 || freq > 1459) + freqlist += freq + freq += 2 + if ((freq % 2) == 0) + freq += 1 + freq = freqlist[rand(1, freqlist.len)] + // generate a passcode if the uplink is hidden in a PDA + var/pda_pass = "[rand(100,999)] [pick("Morgan","Circe","Prospero","Merlin")]" + + del(wizard_mob.wear_suit) + del(wizard_mob.head) + del(wizard_mob.shoes) + del(wizard_mob.r_hand) + wizard_mob.wear_suit = new /obj/item/clothing/suit/wizrobe(wizard_mob) + wizard_mob.wear_suit.layer = 20 + wizard_mob.head = new /obj/item/clothing/head/wizard(wizard_mob) + wizard_mob.head.layer = 20 + wizard_mob.shoes = new /obj/item/clothing/shoes/sandal(wizard_mob) + wizard_mob.shoes.layer = 20 + wizard_mob.r_hand = new /obj/item/weapon/staff(wizard_mob) + wizard_mob.r_hand.layer = 20 + + var/loc = "" + var/obj/item/device/R = null //Hide the uplink in a PDA if available, otherwise radio + if (!R && istype(wizard_mob.belt, /obj/item/device/pda)) + R = wizard_mob.belt + loc = "on your belt" + if (!R && istype(wizard_mob.l_hand, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = wizard_mob.l_hand + var/list/L = S.return_inv() + for (var/obj/item/device/radio/foo in L) + R = foo + loc = "in the [S.name] in your left hand" + break + if (!R && istype(wizard_mob.r_hand, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = wizard_mob.r_hand + var/list/L = S.return_inv() + for (var/obj/item/device/radio/foo in L) + R = foo + loc = "in the [S.name] in your right hand" + break + if (!R && istype(wizard_mob.back, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = wizard_mob.back + var/list/L = S.return_inv() + for (var/obj/item/device/radio/foo in L) + R = foo + loc = "in the [S.name] on your back" + break + if (!R && wizard_mob.w_uniform && istype(wizard_mob.belt, /obj/item/device/radio)) + R = wizard_mob.belt + loc = "on your belt" + if (!R && istype(wizard_mob.ears, /obj/item/device/radio)) + R = wizard_mob.ears + loc = "on your head" + if (!R) + wizard_mob << "Unfortunately, the Space Wizards Federation wasn't able to get you a radio." + else + if (istype(R, /obj/item/device/radio)) + var/obj/item/weapon/SWF_uplink/T = new /obj/item/weapon/SWF_uplink(R) + R:traitorradio = T + R:traitor_frequency = freq + T.name = R.name + T.icon_state = R.icon_state + T.origradio = R + wizard_mob << "The Space Wizards Federation have cunningly disguised a spell book as your [R.name] [loc]. Simply dial the frequency [format_frequency(freq)] to unlock it's hidden features." + wizard_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name] [loc]).") + else if (istype(R, /obj/item/device/pda)) + var/obj/item/weapon/integrated_uplink/SWF/T = new /obj/item/weapon/integrated_uplink/SWF(R) + R:uplink = T + T.lock_code = pda_pass + T.hostpda = R + wizard_mob << "The Space Wizards Federation have cunningly enchanted a spellbook into your PDA [loc]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features." + wizard_mob.mind.store_memory("Uplink Passcode: [pda_pass] ([R.name] [loc]).") + +/datum/game_mode/wizard/send_intercept() + var/intercepttext = "Cent. Com. Update Requested staus information:
      " + intercepttext += " Cent. Com has recently been contacted by the following syndicate affiliated organisations in your area, please investigate any information you may have:" + + var/list/possible_modes = list() + possible_modes.Add("revolution", "wizard", "nuke", "traitor", "malf") + possible_modes -= "[ticker.mode]" + var/number = pick(2, 3) + var/i = 0 + for(i = 0, i < number, i++) + possible_modes.Remove(pick(possible_modes)) + possible_modes.Insert(rand(possible_modes.len), "[ticker.mode]") + + var/datum/intercept_text/i_text = new /datum/intercept_text + for(var/A in possible_modes) + intercepttext += i_text.build(A, wizard) + + for (var/obj/machinery/computer/communications/comm in world) + if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept) + var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc ) + intercept.name = "paper- 'Cent. Com. Status Summary'" + intercept.info = intercepttext + + comm.messagetitle.Add("Cent. Com. Status Summary") + comm.messagetext.Add(intercepttext) + + command_alert("Summary downloaded and printed out at all communications consoles.", "Enemy communication intercept. Security Level Elevated.") + +/datum/game_mode/wizard/declare_completion() + if(finished) + world << "\red The wizard has been killed by the crew! The Space Wizards Fediration has been taught a lesson they will not soon forget!" + + var/wizard_name + if(wizard.current) + wizard_name = "[wizard.current.real_name] (played by [wizard.key])" + else + wizard_name = "[wizard.key] (character destroyed)" + world << "The wizard was [wizard_name]" + var/count = 1 + + var/wizardwin = 1 + for(var/datum/objective/objective in wizard.objectives) + if(objective.check_completion()) + world << "Objective #[count]: [objective.explanation_text] \green Success" + else + world << "Objective #[count]: [objective.explanation_text] \red Failed" + wizardwin = 0 + count++ + + if(!finished) + if(wizardwin) + world << "The wizard was successful!" + else + world << "The wizard has failed!" + + return 1 + + +/datum/game_mode/wizard/proc/get_mob_list() + var/list/mobs = list() + for(var/mob/living/player in world) + if (player.client) + mobs += player + return mobs + +/datum/game_mode/wizard/proc/pick_human_name_except(excluded_name) + var/list/names = list() + for(var/mob/living/player in world) + if (player.client && (player.real_name != excluded_name)) + names += player.real_name + if(!names.len) + return null + return pick(names) + +/datum/game_mode/wizard/check_finished() + if(!wizard.current) + return 1 + if(wizard.current.stat == 2) + return 1 + else + return ..() + +/obj/item/weapon/SWF_uplink/proc/explode() + var/turf/location = get_turf(src.loc) + location.hotspot_expose(700, 125) + + explosion(location, 0, 0, 2, 4) + + del(src.master) + del(src) + return + +/obj/item/weapon/SWF_uplink/attack_self(mob/user as mob) + user.machine = src + var/dat + if (src.selfdestruct) + dat = "Self Destructing..." + else + if (src.temp) + dat = "[src.temp]

      Clear" + else + dat = "Syndicate Uplink Console:
      " + dat += "Tele-Crystals left: [src.uses]
      " + dat += "
      " + dat += "Request item:
      " + dat += "Each item costs 1 telecrystal. The number afterwards is the cooldown time.
      " + dat += "Magic Missile (10)
      " + dat += "Fireball (10)
      " + dat += "Shocking Grasp (60)
      " + dat += "Disable Technology (60)
      " + dat += "Smoke (10)
      " + dat += "Blind (30)
      " + dat += "Forcewall (10)
      " + dat += "Blink (2)
      " + dat += "Teleport (30)
      " + dat += "Mutate (60)
      " + dat += "Invisibility (60)
      " + dat += "Knock (10)
      " + dat += "
      " + if (src.origradio) + dat += "Lock
      " + dat += "
      " + dat += "Self-Destruct" + user << browse(dat, "window=radio") + onclose(user, "radio") + return + +/obj/item/weapon/SWF_uplink/Topic(href, href_list) + ..() + if (usr.stat || usr.restrained()) + return + var/mob/living/carbon/human/H = usr + if (!( istype(H, /mob/living/carbon/human))) + return 1 + if ((usr.contents.Find(src) || (in_range(src,usr) && istype(src.loc, /turf)))) + usr.machine = src + if (href_list["spell_magicmissile"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/magicmissile + src.temp = "This spell fires several, slow moving, magic projectiles at nearby targets. If they hit a target, it is paralyzed and takes minor damage." + else if (href_list["spell_fireball"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/fireball + src.temp = "This spell fires a fireball at a target. Be careful not to fire it at people that are standing next to you." + else if (href_list["spell_shock"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /mob/proc/kill + src.temp = "This spell instantly kills somebody standing next to you. It has a long cooldown." + else if (href_list["spell_emp"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /mob/proc/tech + src.temp = "This spell disables all weapons, cameras and most other technology in range." + else if (href_list["spell_smoke"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/smokecloud + src.temp = "This spell spawns a cloud of choking smoke at your location." + else if (href_list["spell_blind"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/blind + src.temp = "This spell temporarly blinds a single person." + else if (href_list["spell_forcewall"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/forcewall + src.temp = "This spell creates an unbreakable wall that lasts for 30 seconds." + else if (href_list["spell_blink"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/blink + src.temp = "This spell randomly teleports you a short distance. Useful for evasion or getting into areas if you have patience." + else if (href_list["spell_teleport"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /mob/proc/teleport + src.temp = "This spell teleports you to a type of area of your selection. Very useful if you are in danger, but has a decent cooldown, and is unpredictable." + else if (href_list["spell_mutate"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/mutate + src.temp = "This spell causes you to turn into a hulk, and gain telekinesis for a short while." + else if (href_list["spell_invis"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/invisibility + src.temp = "This spell creates your ethereal form, temporarily making you invisible and able to pass through walls." + else if (href_list["spell_knock"]) + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/knock + src.temp = "This spell opens nearby doors." + else if (href_list["lock"] && src.origradio) + // presto chango, a regular radio again! (reset the freq too...) + usr.machine = null + usr << browse(null, "window=radio") + var/obj/item/device/radio/T = src.origradio + var/obj/item/weapon/SWF_uplink/R = src + R.loc = T + T.loc = usr + // R.layer = initial(R.layer) + R.layer = 0 + if (usr.client) + usr.client.screen -= R + if (usr.r_hand == R) + usr.u_equip(R) + usr.r_hand = T + else + usr.u_equip(R) + usr.l_hand = T + R.loc = T + T.layer = 20 + T.set_frequency(initial(T.frequency)) + T.attack_self(usr) + return + else if (href_list["selfdestruct"]) + src.temp = "Self-Destruct" + else if (href_list["selfdestruct2"]) + src.selfdestruct = 1 + spawn (100) + explode() + return + else + if (href_list["temp"]) + src.temp = null + if (istype(src.loc, /mob)) + attack_self(src.loc) + else + for(var/mob/M in viewers(1, src)) + if (M.client) + src.attack_self(M) + return + +/obj/item/weapon/integrated_uplink/SWF + name = "enchanted uplink" + uses = 4 + var/temp = null + +/obj/item/weapon/integrated_uplink/SWF/generate_menu() + src.menu_message = "Wizarding Uplink Console:
      " + src.menu_message += "Tele-Crystals left: [src.uses]
      " + src.menu_message += "
      " + + if(src.temp) + src.menu_message += "[src.temp]
      " + else //Nice empty space for it to appear in. + src.menu_message += "
      " + src.menu_message += "Request item:
      " + src.menu_message += "Each item costs 1 telecrystal. The number afterwards is the cooldown time.
      " + src.menu_message += "Magic Missile (10)
      " + src.menu_message += "Fireball (10)
      " + src.menu_message += "Shocking Grasp (60)
      " + src.menu_message += "Disable Technology (60)
      " + src.menu_message += "Smoke (10)
      " + src.menu_message += "Blind (30)
      " + src.menu_message += "Forcewall (10)
      " + src.menu_message += "Blink (2)
      " + src.menu_message += "Teleport (30)
      " + src.menu_message += "Mutate (60)
      " + src.menu_message += "Invisibility (60)
      " + src.menu_message += "Knock (10)
      " + src.menu_message += "
      " + return + +/obj/item/weapon/integrated_uplink/SWF/Topic(href, href_list) + if ((isnull(src.hostpda)) || (!src.active)) + return + + if (usr.stat || usr.restrained() || !in_range(src.hostpda, usr)) + return + + if (href_list["buy_spell"]) + switch(href_list["buy_spell"]) + if("magicmissile") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/magicmissile + src.temp = "This spell fires several, slow moving, magic projectiles at nearby targets. If they hit a target, it is paralyzed and takes minor damage." + if("fireball") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/fireball + src.temp = "This spell fires a fireball at a target. Be careful not to fire it at people that are standing next to you." + if("shock") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /mob/proc/kill + src.temp = "This spell instantly kills somebody standing next to you. It has a long cooldown." + if("emp") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /mob/proc/tech + src.temp = "This spell disables all weapons, cameras and most other technology in range." + if("smoke") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/smokecloud + src.temp = "This spell spawns a cloud of choking smoke at your location." + if("blind") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/blind + src.temp = "This spell temporarly blinds a single person." + if("forcewall") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/forcewall + src.temp = "This spell creates an unbreakable wall that lasts for 30 seconds." + if("blink") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/blink + src.temp = "This spell randomly teleports you a short distance. Useful for evasion or getting into areas if you have patience." + if("teleport") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /mob/proc/teleport + src.temp = "This spell teleports you to a type of area of your selection. Very useful if you are in danger, but has a decent cooldown, and is unpredictable." + if("mutate") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/mutate + src.temp = "This spell causes you to turn into a hulk, and gain telekinesis for a short while." + if("invis") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/invisibility + src.temp = "This spell creates your ethereal form, temporarily making you invisible and able to pass through walls." + if("knock") + if (src.uses >= 1) + src.uses -= 1 + usr.verbs += /client/proc/knock + src.temp = "This spell opens nearby doors." + src.generate_menu() + src.print_to_host(src.menu_message) + return + + return \ No newline at end of file diff --git a/code/game/hud.dm b/code/game/hud.dm new file mode 100644 index 0000000000000..b46238ca75adf --- /dev/null +++ b/code/game/hud.dm @@ -0,0 +1,110 @@ +#define ui_dropbutton "SOUTH-1,7" +#define ui_swapbutton "SOUTH-1,7" +#define ui_iclothing "SOUTH-1,2" +#define ui_oclothing "SOUTH,2" +//#define ui_headset "SOUTH,8" +#define ui_rhand "SOUTH,1" +#define ui_lhand "SOUTH,3" +#define ui_id "SOUTH-1,1" +#define ui_mask "SOUTH+1,1" +#define ui_back "SOUTH+1,3" +#define ui_storage1 "SOUTH-1,4" +#define ui_storage2 "SOUTH-1,5" +#define ui_resist "EAST+1,SOUTH-1" +#define ui_gloves "SOUTH,5" +#define ui_glasses "SOUTH,7" +#define ui_ears "SOUTH,6" +#define ui_head "SOUTH+1,2" +#define ui_shoes "SOUTH,4" +#define ui_belt "SOUTH-1,3" +#define ui_throw "SOUTH-1,8" +#define ui_oxygen "EAST+1, NORTH-4" +#define ui_toxin "EAST+1, NORTH-6" +#define ui_internal "EAST+1, NORTH-2" +#define ui_fire "EAST+1, NORTH-8" +#define ui_temp "EAST+1, NORTH-10" +#define ui_health "EAST+1, NORTH-11" +#define ui_pull "SOUTH-1,10" +#define ui_hand "SOUTH-1,6" +#define ui_sleep "EAST+1, NORTH-13" +#define ui_rest "EAST+1, NORTH-14" + +#define ui_acti "SOUTH-1,12" +#define ui_movi "SOUTH-1,14" + +#define ui_iarrowleft "SOUTH-1,11" +#define ui_iarrowright "SOUTH-1,13" + +#define ui_inv1 "SOUTH-1,1" +#define ui_inv2 "SOUTH-1,2" +#define ui_inv3 "SOUTH-1,3" + + + +obj/hud/New(var/type = 0) + src.instantiate(type) + ..() + return + + +/obj/hud/proc/other_update() + + if(!mymob) return + if(show_otherinventory) + if(mymob:shoes) mymob:shoes:screen_loc = ui_shoes + if(mymob:gloves) mymob:gloves:screen_loc = ui_gloves + if(mymob:ears) mymob:ears:screen_loc = ui_ears +// if(mymob:w_radio) mymob:w_radio:screen_loc = ui_headset + if(mymob:glasses) mymob:glasses:screen_loc = ui_glasses + else + if(mymob:shoes) mymob:shoes:screen_loc = null + if(mymob:gloves) mymob:gloves:screen_loc = null + if(mymob:ears) mymob:ears:screen_loc = null +// if(mymob:w_radio) mymob:w_radio:screen_loc = null + if(mymob:glasses) mymob:glasses:screen_loc = null + + +/obj/hud/var/show_otherinventory = 1 +/obj/hud/var/obj/screen/action_intent +/obj/hud/var/obj/screen/move_intent + +/obj/hud/proc/instantiate(var/type = 0) + + mymob = src.loc + ASSERT(istype(mymob, /mob)) + + if(istype(mymob, /mob/living/carbon/human)) + src.human_hud() + + return + + if(istype(mymob, /mob/living/carbon/monkey)) + src.monkey_hud() + return + + //aliens + if(istype(mymob, /mob/living/carbon/alien/larva)) + src.larva_hud() + else if(istype(mymob, /mob/living/carbon/alien)) + src.alien_hud() + return + + if(istype(mymob, /mob/living/silicon/ai)) + src.ai_hud() + return + + if(istype(mymob, /mob/living/silicon/robot)) + src.robot_hud() + return + + if(istype(mymob, /mob/living/silicon/hivebot)) + src.hivebot_hud() + return + + if(istype(mymob, /mob/living/silicon/hive_mainframe)) + src.hive_mainframe_hud() + return + + if(istype(mymob, /mob/dead/observer)) + src.ghost_hud() + return diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm new file mode 100644 index 0000000000000..25cc0a9a1677f --- /dev/null +++ b/code/game/jobs/access.dm @@ -0,0 +1,239 @@ +/var/const + access_security = 1 + access_brig = 2 + access_armory = 3 + access_forensics_lockers= 4 + access_medical = 5 + access_morgue = 6 + access_tox = 7 + access_tox_storage = 8 + access_medlab = 9 + access_engine = 10 + access_engine_equip= 11 + access_maint_tunnels = 12 + access_external_airlocks = 13 + access_emergency_storage = 14 + access_change_ids = 15 + access_ai_upload = 16 + access_teleporter = 17 + access_eva = 18 + access_heads = 19 + access_captain = 20 + access_all_personal_lockers = 21 + access_chapel_office = 22 + access_tech_storage = 23 + access_atmospherics = 24 + access_bar = 25 + access_janitor = 26 + access_crematorium = 27 + access_kitchen = 28 + access_robotics = 29 + access_cargo = 31 + access_construction = 32 + access_chemistry = 33 + access_cargo_bot = 34 + access_hydroponics = 35 + access_manufacturing = 36 + access_library = 37 + + +/obj/var/list/req_access = null +/obj/var/req_access_txt = "0" +/obj/New() + + if(src.req_access_txt) + var/req_access_str = params2list(req_access_txt) + var/req_access_changed = 0 + for(var/x in req_access_str) + var/n = text2num(x) + if(n) + if(!req_access_changed) + req_access = list() + req_access += n + ..() + +//returns 1 if this mob has sufficient access to use this object +/obj/proc/allowed(mob/M) + //check if it doesn't require any access at all + if(src.check_access(null)) + return 1 + if(istype(M, /mob/living/silicon)) + //AI can do whatever he wants + return 1 + else if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + //if they are holding or wearing a card that has access, that works + if(src.check_access(H.equipped()) || src.check_access(H.wear_id)) + return 1 + else if(istype(M, /mob/living/carbon/monkey) || istype(M, /mob/living/carbon/alien/humanoid)) + var/mob/living/carbon/george = M + //they can only hold things :( + if(george.equipped() && istype(george.equipped(), /obj/item/weapon/card/id) && src.check_access(george.equipped())) + return 1 + return 0 + +/obj/proc/check_access(obj/item/weapon/card/id/I) + if(!src.req_access) //no requirements + return 1 + if(!istype(src.req_access, /list)) //something's very wrong + return 1 + + var/list/L = src.req_access + if(!L.len) //no requirements + return 1 + if(!I || !istype(I, /obj/item/weapon/card/id) || !I.access) //not ID or no access + return 0 + for(var/req in src.req_access) + if(!(req in I.access)) //doesn't have this access + return 0 + return 1 + +/proc/get_access(job) + switch(job) + if("Geneticist") + return list(access_medical, access_morgue, access_medlab) + if("Station Engineer") + return list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks) + if("Assistant") + return list(access_maint_tunnels) + if("Chaplain") + return list(access_morgue, access_chapel_office, access_crematorium) + if("Detective") + return list(access_security, access_forensics_lockers, access_morgue, access_maint_tunnels) + if("Medical Doctor") + return list(access_medical, access_morgue) + if("Botanist") // -- TLE + return list(access_medical, access_chemistry, access_hydroponics) + if("Librarian") // -- TLE + return list(access_library) + if("Captain") + return get_all_accesses() + if("Security Officer") + return list(access_security, access_brig) + if("Scientist") + return list(access_tox, access_tox_storage) + if("Head of Security") + return list(access_medical, access_morgue, access_tox, access_tox_storage, access_chemistry, access_medlab, + access_teleporter, access_heads, access_tech_storage, access_security, access_brig, access_atmospherics, + access_maint_tunnels, access_bar, access_janitor, access_kitchen, access_robotics, access_armory, access_hydroponics) + if("Head of Personnel") + return list(access_security, access_brig, access_forensics_lockers, + access_tox, access_tox_storage, access_chemistry, access_medical, access_medlab, access_engine, + access_emergency_storage, access_change_ids, access_ai_upload, access_eva, access_heads, + access_all_personal_lockers, access_tech_storage, access_maint_tunnels, access_bar, access_janitor, + access_crematorium, access_kitchen, access_robotics, access_cargo, access_cargo_bot, access_hydroponics) + if("Atmospheric Technician") + return list(access_atmospherics, access_maint_tunnels, access_emergency_storage) + if("Barman") + return list(access_bar) + if("Chemist") + return list(access_medical, access_tox, access_chemistry) + if("Janitor") + return list(access_janitor, access_maint_tunnels) + if("Clown") + return list(access_maint_tunnels) + if("Chef") + return list(access_kitchen) + if("Roboticist") + return list(access_robotics, access_tech_storage, access_medical, access_morgue, access_engine, + access_maint_tunnels) + if("Quartermaster") + return list(access_maint_tunnels, access_cargo, access_cargo_bot) + if("Chief Engineer") + return list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, + access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva, + access_heads, access_ai_upload, access_construction) + if("Research Director") + return list(access_medical, access_morgue, access_medlab, access_robotics, + access_tech_storage, access_maint_tunnels, access_heads, access_tox, + access_tox_storage, access_chemistry, access_teleporter) + else + return list() + +/proc/get_all_accesses() + return list(access_security, access_brig, access_armory, access_forensics_lockers, + access_medical, access_medlab, access_morgue, + access_tox, access_tox_storage, access_chemistry, access_engine, access_engine_equip, access_maint_tunnels, + access_external_airlocks, access_emergency_storage, access_change_ids, access_ai_upload, + access_teleporter, access_eva, access_heads, access_captain, access_all_personal_lockers, + access_tech_storage, access_chapel_office, access_atmospherics, access_kitchen, + access_bar, access_janitor, access_crematorium, access_robotics, access_cargo, access_cargo_bot, access_construction, + access_hydroponics, access_library, access_manufacturing) + +/proc/get_access_desc(A) + switch(A) + if(access_cargo) + return "Cargo Bay" + if(access_cargo_bot) + return "Cargo Bot Delivery" + if(access_security) + return "Security" + if(access_brig) + return "Brig" + if(access_forensics_lockers) + return "Forensics" + if(access_medical) + return "Medical" + if(access_medlab) + return "Med-Sci" + if(access_morgue) + return "Morgue" + if(access_tox) + return "Toxins Research" + if(access_tox_storage) + return "Toxins Storage" + if(access_chemistry) + return "Toxins Chemical Lab" + if(access_bar) + return "Bar" + if(access_janitor) + return "Janitorial Equipment" + if(access_engine) + return "Engineering" + if(access_engine_equip) + return "Engine & Power Control Equipment" + if(access_maint_tunnels) + return "Maintenance" + if(access_external_airlocks) + return "External Airlock" + if(access_emergency_storage) + return "Emergency Storage" + if(access_change_ids) + return "ID Computer" + if(access_ai_upload) + return "AI Upload" + if(access_teleporter) + return "Teleporter" + if(access_eva) + return "EVA" + if(access_heads) + return "Head's Quarters/Bridge" + if(access_captain) + return "Captain's Quarters" + if(access_all_personal_lockers) + return "Personal Locker" + if(access_chapel_office) + return "Chapel Office" + if(access_tech_storage) + return "Technical Storage" + if(access_atmospherics) + return "Atmospherics" + if(access_crematorium) + return "Crematorium" + if(access_armory) + return "Armory" + if(access_construction) + return "Construction Site" + if(access_kitchen) + return "Kitchen" + if(access_hydroponics) + return "Hydroponics" + if(access_library) + return "Library" + +/proc/get_all_jobs() + return list("Assistant", "Station Engineer", "Detective", "Medical Doctor", "Captain", "Security Officer", + "Geneticist", "Scientist", "Head of Security", "Head of Personnel", "Atmospheric Technician", + "Chaplain", "Barman", "Chemist", "Janitor", "Clown", "Chef", "Roboticist", "Quartermaster", + "Chief Engineer", "Research Director", "Botanist", "Librarian") + diff --git a/code/game/jobs/jobprocs.dm b/code/game/jobs/jobprocs.dm new file mode 100644 index 0000000000000..3f7bd7f96e521 --- /dev/null +++ b/code/game/jobs/jobprocs.dm @@ -0,0 +1,535 @@ +/proc/SetupOccupationsList() + var/list/new_occupations = list() + + for(var/occupation in occupations) + if (!(new_occupations.Find(occupation))) + new_occupations[occupation] = 1 + else + new_occupations[occupation] += 1 + + occupations = new_occupations + return + +/proc/FindOccupationCandidates(list/unassigned, job, level) + var/list/candidates = list() + + for (var/mob/new_player/player in unassigned) + if (level == 1 && player.preferences.occupation1 == job && !jobban_isbanned(player, job)) + candidates += player + + if (level == 2 && player.preferences.occupation2 == job && !jobban_isbanned(player, job)) + candidates += player + + if (level == 3 && player.preferences.occupation3 == job && !jobban_isbanned(player, job)) + candidates += player + + return candidates + +/proc/PickOccupationCandidate(list/candidates) + if (candidates.len > 0) + var/list/randomcandidates = shuffle(candidates) + candidates -= randomcandidates[1] + return randomcandidates[1] + + return null + +/proc/DivideOccupations() + var/list/unassigned = list() + var/list/occupation_choices = occupations.Copy() + var/list/occupation_eligible = occupations.Copy() + occupation_choices = shuffle(occupation_choices) + + for (var/mob/new_player/player in world) + if (player.client && player.ready && !player.mind.assigned_role) + unassigned += player + + // If someone picked AI before it was disabled, or has a saved profile with it + // on a game that now lacks it, this will make sure they don't become the AI, + // by changing that choice to Captain. + if (!config.allow_ai) + if (player.preferences.occupation1 == "AI") + player.preferences.occupation1 = "Captain" + if (player.preferences.occupation2 == "AI") + player.preferences.occupation2 = "Captain" + if (player.preferences.occupation3 == "AI") + player.preferences.occupation3 = "Captain" + if (jobban_isbanned(player, player.preferences.occupation1)) + player.preferences.occupation1 = "Assistant" + if (jobban_isbanned(player, player.preferences.occupation2)) + player.preferences.occupation2 = "Assistant" + if (jobban_isbanned(player, player.preferences.occupation3)) + player.preferences.occupation3 = "Assistant" + + if (unassigned.len == 0) + return 0 + + var/mob/new_player/captain_choice = null + + for (var/level = 1 to 3) + var/list/captains = FindOccupationCandidates(unassigned, "Captain", level) + var/mob/new_player/candidate = PickOccupationCandidate(captains) + + if (candidate != null) + captain_choice = candidate + unassigned -= captain_choice + break + /* + // Not forcing a Captain -- TLE + if (captain_choice == null && unassigned.len > 0) + unassigned = shuffle(unassigned) + for(var/mob/new_player/player in unassigned) + if(jobban_isbanned(player, "Captain")) + continue + else + captain_choice = player + break + unassigned -= captain_choice + */ + + + + + if (captain_choice == null) + world << "Captainship not forced on anyone." + else + captain_choice.mind.assigned_role = "Captain" + + //so that an AI is chosen during this game mode + if(ticker.mode.name == "AI malfunction" && unassigned.len > 0) + var/mob/new_player/ai_choice = null + + for (var/level = 1 to 3) + var/list/ais = FindOccupationCandidates(unassigned, "AI", level) + var/mob/new_player/candidate = PickOccupationCandidate(ais) + + if (candidate != null) + ai_choice = candidate + unassigned -= ai_choice + break + + if (ai_choice == null && unassigned.len > 0) + unassigned = shuffle(unassigned) + for(var/mob/new_player/player in unassigned) + if(jobban_isbanned(player, "AI")) + continue + else + ai_choice = player + break + unassigned -= ai_choice + + if (ai_choice != null) + ai_choice.mind.assigned_role = "AI" + else + world << "It is [ticker.mode.name] and there is no AI, someone should fix this" + + for (var/level = 1 to 3) + if (unassigned.len == 0) //everyone is assigned + break + + for (var/occupation in assistant_occupations) + if (unassigned.len == 0) + break + var/list/candidates = FindOccupationCandidates(unassigned, occupation, level) + for (var/mob/new_player/candidate in candidates) + candidate.mind.assigned_role = occupation + unassigned -= candidate + + for (var/occupation in occupation_choices) + if (unassigned.len == 0) + break + if(ticker.mode.name == "AI malfunction" && occupation == "AI") + continue + var/eligible = occupation_eligible[occupation] + if (eligible == 0) + continue + var/list/candidates = FindOccupationCandidates(unassigned, occupation, level) + var/eligiblechange = 0 + while (eligible--) + var/mob/new_player/candidate = PickOccupationCandidate(candidates) + if (candidate == null) + break + candidate.mind.assigned_role = occupation + unassigned -= candidate + eligiblechange++ + occupation_eligible[occupation] -= eligiblechange + + if (unassigned.len) + unassigned = shuffle(unassigned) + for (var/occupation in occupation_choices) + if (unassigned.len == 0) + break + if(ticker.mode.name == "AI malfunction" && occupation == "AI") + continue + var/eligible = occupation_eligible[occupation] + while (eligible-- && unassigned.len > 0) + var/mob/new_player/candidate = unassigned[1] + if (candidate == null) + break + candidate.mind.assigned_role = occupation + unassigned -= candidate + + for (var/mob/new_player/player in unassigned) + player.mind.assigned_role = pick(assistant_occupations) + + return 1 + +/mob/living/carbon/human/proc/Equip_Rank(rank, joined_late) + /*if(joined_late && ticker.mode.name == "ctf") + var/red_team + var/green_team + + for(var/mob/living/carbon/human/M in world) + if(M.client) + if(M.client.team == "Red") + red_team++ + if(M.client.team == "Green") + green_team++ + + if(!src.client.team) + if(red_team > green_team) + src.client.team = "Green" + else + src.client.team = "Red" + + + src << "You are in the [src.client.team] Team!" + var/obj/item/device/radio/headset/H = new /obj/item/device/radio/headset(src) + src.equip_if_possible(H, slot_w_radio) + if(src.client.team == "Red") + H.set_frequency(1465) + src.equip_if_possible(new /obj/item/clothing/under/color/red(src), src.slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/suit/armor/tdome/red(src), slot_wear_suit) + else if(src.client.team == "Green") + H.set_frequency(1449) + src.equip_if_possible(new /obj/item/clothing/under/color/green(src), src.slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/suit/armor/tdome/green(src), slot_wear_suit) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), src.slot_shoes) + src.equip_if_possible(new /obj/item/clothing/mask/gas/emergency(src), src.slot_wear_mask) + src.equip_if_possible(new /obj/item/clothing/gloves/swat(src), src.slot_gloves) + + src.equip_if_possible(new /obj/item/clothing/glasses/thermal(src), src.slot_glasses) + + var/obj/item/weapon/tank/air/O = new /obj/item/weapon/tank/air(src) + src.equip_if_possible(O, src.slot_back) + src.internal = O + + var/obj/item/weapon/card/id/W = new(src) + W.name = "[src.real_name]'s ID card ([src.client.team] Team)" + if(src.client.team == "Red") + W.access = access_red + else if(src.client.team == "Green") + W.access = access_green + else + world << "Unspecified team, [src.client.team]" + + W.assignment = "[src.client.team] Team" + W.registered = src.real_name + src.equip_if_possible(W, src.slot_wear_id) + + return + + if(joined_late && ticker.mode.name == "deathmatch") + src.equip_if_possible(new /obj/item/clothing/under/color/black(src), src.slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), src.slot_shoes) + src.equip_if_possible(new /obj/item/clothing/suit/swat_suit/death_commando(src), src.slot_wear_suit) + src.equip_if_possible(new /obj/item/clothing/mask/gas/death_commando(src), src.slot_wear_mask) + src.equip_if_possible(new /obj/item/clothing/gloves/swat(src), src.slot_gloves) + src.equip_if_possible(new /obj/item/clothing/glasses/thermal(src), src.slot_glasses) + src.equip_if_possible(new /obj/item/weapon/gun/energy/pulse_rifle(src), src.slot_l_hand) + src.equip_if_possible(new /obj/item/weapon/flashbang(src), src.slot_r_store) + + var/obj/item/weapon/tank/air/O = new /obj/item/weapon/tank/air(src) + src.equip_if_possible(O, src.slot_back) + src.internal = O + + var/randomname = "Killiam Shakespeare" + if(commando_names.len) + randomname = pick(commando_names) + commando_names -= randomname + var/newname = input(src,"You are a death commando. Would you like to change your name?", "Character Creation", randomname) + if(!length(newname)) + newname = randomname + newname = strip_html(newname,40) + + src.real_name = newname + src.name = newname // there are WAY more things than this to change, I'm almost certain + + var/obj/item/weapon/card/id/W = new(src) + W.name = "[newname]'s ID card (Death Commando)" + W.access = get_all_accesses() + W.assignment = "Death Commando" + W.registered = newname + src.equip_if_possible(W, src.slot_wear_id) + return + */ + + switch(rank) + if ("Chaplain") + src.equip_if_possible(new /obj/item/weapon/storage/bible(src), slot_l_hand) + src.equip_if_possible(new /obj/item/device/pda/chaplain(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/chaplain(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + if(prob(15)) + src.see_invisible = 15 + + if ("Geneticist") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_med (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/medical(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/geneticist(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/white(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/suit/labcoat(src), slot_wear_suit) + + if ("Chemist") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_med (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/toxins(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/geneticist(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/white(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/suit/labcoat(src), slot_wear_suit) + + if ("Janitor") + src.equip_if_possible(new /obj/item/device/pda/janitor(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/janitor(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + + if ("Clown") + src.equip_if_possible(new /obj/item/device/pda/clown(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/clown(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/clown_shoes(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/mask/clown_hat(src), slot_wear_mask) + src.equip_if_possible(new /obj/item/weapon/banana(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/weapon/bikehorn(src), slot_in_backpack) + src.mutations |= 16 + + if ("Station Engineer") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_eng (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/engineering(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/engineer(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/orange(src), slot_shoes) + src.equip_if_possible(new /obj/item/weapon/storage/toolbox/mechanical(src), slot_l_hand) + src.equip_if_possible(new /obj/item/clothing/gloves/yellow(src), slot_gloves) + src.equip_if_possible(new /obj/item/weapon/crowbar(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/device/t_scanner(src), slot_r_store) + + if ("Assistant") + src.equip_if_possible(new /obj/item/clothing/under/color/grey(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + + if ("Detective") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_sec (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/security(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/det(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/brown(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/head/det_hat(src), slot_head) + src.equip_if_possible(new /obj/item/clothing/gloves/black(src), slot_gloves) + src.equip_if_possible(new /obj/item/weapon/storage/fcard_kit(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/weapon/fcardholder(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/clothing/suit/det_suit(src), slot_wear_suit) + src.equip_if_possible(new /obj/item/device/detective_scanner(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/weapon/zippo(src), slot_l_store) + + if ("Medical Doctor") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_med (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/medical(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/medical(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/white(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/suit/labcoat(src), slot_wear_suit) + src.equip_if_possible(new /obj/item/weapon/storage/firstaid/regular(src), slot_l_hand) + + if ("Captain") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_com (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/captain(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/captain(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/suit/armor/captain(src), slot_wear_suit) + src.equip_if_possible(new /obj/item/clothing/shoes/brown(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/head/caphat(src), slot_head) + src.equip_if_possible(new /obj/item/clothing/glasses/sunglasses(src), slot_glasses) +// src.equip_if_possible(new /obj/item/weapon/gun/taser_gun(src), slot_belt) +// src.equip_if_possible(new /obj/item/weapon/gun/energy/laser_gun(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/weapon/storage/id_kit(src), slot_in_backpack) + + + if ("Security Officer") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_sec (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/security(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/color/red(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/suit/armor/vest(src), slot_wear_suit) + src.equip_if_possible(new /obj/item/clothing/head/helmet(src), slot_head) + src.equip_if_possible(new /obj/item/clothing/shoes/brown(src), slot_shoes) +// src.equip_if_possible(new /obj/item/clothing/glasses/sunglasses(src), slot_glasses) +// src.equip_if_possible(new /obj/item/weapon/gun/taser_gun(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/weapon/handcuffs(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/weapon/handcuffs(src), slot_in_backpack) +// src.equip_if_possible(new /obj/item/weapon/storage/flashbang_kit(src), slot_in_backpack) +// src.equip_if_possible(new /obj/item/weapon/baton(src), slot_belt) +// src.equip_if_possible(new /obj/item/device/flash(src), slot_l_store) + + + if ("Scientist") + src.equip_if_possible(new /obj/item/device/pda/toxins(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/scientist(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/white(src), slot_shoes) +// src.equip_if_possible(new /obj/item/clothing/suit/bio_suit(src), slot_wear_suit) +// src.equip_if_possible(new /obj/item/clothing/head/bio_hood(src), slot_head) + src.equip_if_possible(new /obj/item/clothing/mask/gas(src), slot_wear_mask) + src.equip_if_possible(new /obj/item/weapon/tank/air(src), slot_l_hand) + + if ("Head of Security") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_sec (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/heads(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/head_of_security(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/suit/armor/vest(src), slot_wear_suit) + src.equip_if_possible(new /obj/item/clothing/shoes/brown(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/head/helmet/HoS(src), slot_head) +// src.equip_if_possible(new /obj/item/clothing/glasses/sunglasses(src), slot_glasses) +// src.equip_if_possible(new /obj/item/weapon/gun/taser_gun(src), slot_belt) +// src.equip_if_possible(new /obj/item/weapon/gun/energy/laser_gun(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/weapon/storage/id_kit(src), slot_in_backpack) +// src.equip_if_possible(new /obj/item/device/flash(src), slot_l_store) + + + if ("Head of Personnel") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_com (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/heads(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/head_of_personnel(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/suit/armor/vest(src), slot_wear_suit) + src.equip_if_possible(new /obj/item/clothing/shoes/brown(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/head/helmet(src), slot_head) +// src.equip_if_possible(new /obj/item/clothing/glasses/sunglasses(src), slot_glasses) +// src.equip_if_possible(new /obj/item/weapon/gun/taser_gun(src), slot_belt) +// src.equip_if_possible(new /obj/item/weapon/gun/energy/laser_gun(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/weapon/storage/id_kit(src), slot_in_backpack) +// src.equip_if_possible(new /obj/item/device/flash(src), slot_l_store) + + + if ("Atmospheric Technician") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_eng (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/clothing/under/rank/atmospheric_technician(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + src.equip_if_possible(new /obj/item/weapon/storage/toolbox/mechanical(src), slot_l_hand) + src.equip_if_possible(new /obj/item/weapon/crowbar(src), slot_in_backpack) + + if ("Barman") + src.equip_if_possible(new /obj/item/clothing/under/bartender(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/suit/armor/vest(src), slot_wear_suit) + + if ("Chef") + src.equip_if_possible(new /obj/item/clothing/under/chef(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/head/chefhat(src), slot_head) + src.equip_if_possible(new /obj/item/weapon/kitchen/rollingpin(src), slot_in_backpack) + + if ("Roboticist") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_med (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/medical(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/color/black(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/suit/labcoat(src), slot_wear_suit) + src.equip_if_possible(new /obj/item/weapon/crowbar(src), slot_in_backpack) + src.equip_if_possible(new /obj/item/clothing/gloves/latex(src), slot_gloves) + src.equip_if_possible(new /obj/item/weapon/storage/toolbox/mechanical(src), slot_l_hand) + + if ("Botanist") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_med (src), slot_ears) + src.equip_if_possible(new /obj/item/device/pda/medical(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/under/rank/hydroponics(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/gloves/latex(src), slot_gloves) + src.equip_if_possible(new /obj/item/device/analyzer/plant_analyzer(src), slot_l_hand) + + if ("Librarian") + + src.equip_if_possible(new /obj/item/clothing/under/suit_jacket/red(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + src.equip_if_possible(new /obj/item/weapon/barcodescanner(src), slot_l_hand) + + if ("Quartermaster") + src.equip_if_possible(new /obj/item/clothing/gloves/black(src), slot_gloves) + src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/under/cargo(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/device/pda/quartermaster(src), slot_belt) + //src.equip_if_possible(new /obj/item/clothing/suit/exo_suit(src), slot_wear_suit) + + if ("Chief Engineer") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_eng (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/heads(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/gloves/yellow(src), slot_gloves) + src.equip_if_possible(new /obj/item/clothing/shoes/brown(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/head/helmet/hardhat(src), slot_head) + src.equip_if_possible(new /obj/item/clothing/glasses/meson(src), slot_glasses) + src.equip_if_possible(new /obj/item/clothing/under/rank/chief_engineer(src), slot_w_uniform) + + if ("Research Director") + src.equip_if_possible(new /obj/item/device/radio/headset/headset_com (src), slot_ears) // -- TLE + src.equip_if_possible(new /obj/item/device/pda/heads(src), slot_belt) + src.equip_if_possible(new /obj/item/clothing/shoes/brown(src), slot_shoes) + src.equip_if_possible(new /obj/item/clothing/under/rank/research_director(src), slot_w_uniform) + src.equip_if_possible(new /obj/item/clothing/suit/labcoat(src), slot_wear_suit) + src.equip_if_possible(new /obj/item/weapon/pen(src), slot_l_hand) + src.equip_if_possible(new /obj/item/weapon/clipboard(src), slot_r_hand) + + else + src << "RUH ROH! Your job is [rank] and the game just can't handle it! Please report this bug to an administrator." + + src.equip_if_possible(new /obj/item/device/radio/headset(src), slot_ears) + src.equip_if_possible(new /obj/item/weapon/storage/backpack(src), slot_back) + + spawnId(rank) + if(rank == "Captain") + world << "[src] is the captain!" + src << "You are the [rank]." + src.job = rank + src.mind.assigned_role = rank + + if (!joined_late && rank != "Tourist") + var/obj/S = null + for(var/obj/landmark/start/sloc in world) + if (sloc.name != rank) + continue + if (locate(/mob) in sloc.loc) + continue + S = sloc + break + if (!S) + S = locate("start*[rank]") // use old stype + if (istype(S, /obj/landmark/start) && istype(S.loc, /turf)) + src.loc = S.loc + else + var/list/L = list() + for(var/area/arrival/start/S in world) + L += S + if(L.len < 1) // Added this check to stop the empty list bug -- TLE + return // ** + var/A = pick(L) + var/list/NL = list() + for(var/turf/T in A) + if(!T.density) + var/clear = 1 + for(var/obj/O in T) + if(O.density) + clear = 0 + break + if(clear) + NL += T + src.loc = pick(NL) + return + +/mob/living/carbon/human/proc/spawnId(rank) + var/obj/item/weapon/card/id/C = null + switch(rank) + if("Captain") + C = new /obj/item/weapon/card/id/gold(src) + else + C = new /obj/item/weapon/card/id(src) + if(C) + C.registered = src.real_name + C.assignment = rank + C.name = "[C.registered]'s ID Card ([C.assignment])" + C.access = get_access(C.assignment) + src.equip_if_possible(C, slot_wear_id) + src.equip_if_possible(new /obj/item/weapon/pen(src), slot_r_store) + //src.equip_if_possible(new /obj/item/device/radio/signaler(src), slot_belt) + src.equip_if_possible(new /obj/item/device/pda(src), slot_belt) + if (istype(src.belt, /obj/item/device/pda)) + src.belt:owner = src.real_name + src.belt.name = "PDA-[src.real_name]" \ No newline at end of file diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm new file mode 100644 index 0000000000000..9319f398f0841 --- /dev/null +++ b/code/game/jobs/jobs.dm @@ -0,0 +1,26 @@ +var/list/occupations = list( + "Station Engineer", "Station Engineer", "Station Engineer", "Station Engineer", "Station Engineer", + "Security Officer", "Security Officer", "Security Officer", "Security Officer", "Security Officer", + "Detective", + "Geneticist", "Geneticist", + "Scientist", "Scientist", "Scientist", + "Atmospheric Technician", "Atmospheric Technician", "Atmospheric Technician", "Atmospheric Technician", + "Medical Doctor", "Medical Doctor", "Medical Doctor", "Medical Doctor", "Medical Doctor", + "Head of Personnel", + "Head of Security", + "Chief Engineer", + "Research Director", + "Chaplain", + "Roboticist", + "AI", + "Barman", + "Chef", + "Janitor", + "Clown", + "Chemist", + "Quartermaster","Quartermaster","Quartermaster", + "Botanist", "Botanist", + "Librarian") + +var/list/assistant_occupations = list( + "Assistant") diff --git a/code/game/landmarks.dm b/code/game/landmarks.dm new file mode 100644 index 0000000000000..7d2cfa1b30d14 --- /dev/null +++ b/code/game/landmarks.dm @@ -0,0 +1,61 @@ +/obj/landmark/New() + + ..() + src.tag = text("landmark*[]", src.name) + src.invisibility = 101 + + if (name == "shuttle") + shuttle_z = src.z + del(src) + + if (name == "airtunnel_stop") + airtunnel_stop = src.x + + if (name == "airtunnel_start") + airtunnel_start = src.x + + if (name == "airtunnel_bottom") + airtunnel_bottom = src.y + + if (name == "monkey") + monkeystart += src.loc + del(src) + if (name == "start") + newplayer_start += src.loc + del(src) + + if (name == "wizard") + wizardstart += src.loc + del(src) + + if (name == "JoinLate") + latejoin += src.loc + del(src) + + //prisoners + if (name == "prisonwarp") + prisonwarp += src.loc + del(src) + if (name == "mazewarp") + mazewarp += src.loc + if (name == "tdome1") + tdome1 += src.loc + if (name == "tdome2") + tdome2 += src.loc + //not prisoners + if (name == "prisonsecuritywarp") + prisonsecuritywarp += src.loc + del(src) + + if (name == "blobstart") + blobstart += src.loc + del(src) + + return 1 + +/obj/landmark/start/New() + ..() + src.tag = "start*[src.name]" + src.invisibility = 101 + + return 1 \ No newline at end of file diff --git a/code/game/machinery/Freezer.dm b/code/game/machinery/Freezer.dm new file mode 100644 index 0000000000000..65b91d8a58c95 --- /dev/null +++ b/code/game/machinery/Freezer.dm @@ -0,0 +1,82 @@ +/obj/machinery/atmospherics/unary/cold_sink/freezer + name = "Freezer" + icon = 'Cryogenic2.dmi' + icon_state = "freezer_0" + density = 1 + + anchored = 1.0 + + current_heat_capacity = 1000 + + New() + ..() + initialize_directions = NORTH + + initialize() + if(node) return + + var/node_connect = NORTH + + for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) + if(target.initialize_directions & get_dir(target,src)) + node = target + break + + update_icon() + + + update_icon() + if(src.node) + if(src.on) + icon_state = "freezer_1" + else + icon_state = "freezer" + else + icon_state = "freezer_0" + return + + attack_ai(mob/user as mob) + return src.attack_hand(user) + + attack_paw(mob/user as mob) + return src.attack_hand(user) + + attack_hand(mob/user as mob) + user.machine = src + var/temp_text = "" + if(air_contents.temperature > (T0C - 20)) + temp_text = "[air_contents.temperature]" + else if(air_contents.temperature < (T0C - 20) && air_contents.temperature > (T0C - 100)) + temp_text = "[air_contents.temperature]" + else + temp_text = "[air_contents.temperature]" + + var/dat = {"Cryo gas cooling system
      + Current status: [ on ? "Off On" : "Off On"]
      + Current gas temperature: [temp_text]
      + Current air pressure: [air_contents.return_pressure()]
      + Target gas temperature: - - [current_temperature] + +
      + "} + + user << browse(dat, "window=freezer;size=400x500") + onclose(user, "freezer") + + Topic(href, href_list) + if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) + usr.machine = src + if (href_list["start"]) + src.on = !src.on + update_icon() + if(href_list["temp"]) + var/amount = text2num(href_list["temp"]) + if(amount > 0) + src.current_temperature = min(T20C, src.current_temperature+amount) + else + src.current_temperature = max((T0C - 200), src.current_temperature+amount) + src.updateUsrDialog() + src.add_fingerprint(usr) + return + + process() + ..() + src.updateUsrDialog() \ No newline at end of file diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm new file mode 100644 index 0000000000000..597c1db04fdf0 --- /dev/null +++ b/code/game/machinery/OpTable.dm @@ -0,0 +1,119 @@ +/obj/machinery/optable/New() + ..() + for(var/obj/machinery/computer/operating/O in world) + if(src.id == O.id) + src.computer = O + spawn(100) + process() + +/obj/machinery/optable/ex_act(severity) + + switch(severity) + if(1.0) + //SN src = null + del(src) + return + if(2.0) + if (prob(50)) + //SN src = null + del(src) + return + if(3.0) + if (prob(25)) + src.density = 0 + else + return + +/obj/machinery/optable/blob_act() + if(prob(50)) + del(src) + +/obj/machinery/optable/hand_p(mob/user as mob) + + return src.attack_paw(user) + return + +/obj/machinery/optable/attack_paw(mob/user as mob) + if ((usr.mutations & 8)) + usr << text("\blue You destroy the operating table.") + for(var/mob/O in oviewers()) + if ((O.client && !( O.blinded ))) + O << text("\red [usr] destroys the operating table.") + src.density = 0 + del(src) + if (!( locate(/obj/machinery/optable, user.loc) )) + step(user, get_dir(user, src)) + if (user.loc == src.loc) + user.layer = TURF_LAYER + for(var/mob/M in viewers(user, null)) + M.show_message("The monkey hides under the table!", 1) + //Foreach goto(69) + return + +/obj/machinery/optable/attack_hand(mob/user as mob) + if ((usr.mutations & 8)) + usr << text("\blue You destroy the table.") + for(var/mob/O in oviewers()) + if ((O.client && !( O.blinded ))) + O << text("\red [usr] destroys the table.") + src.density = 0 + del(src) + return + + + +/obj/machinery/optable/CanPass(atom/movable/O as mob|obj, target as turf) + if(!O) + return 0 + if ((O.flags & 2 || istype(O, /obj/meteor))) + return 1 + else + return 0 + return + +/obj/machinery/optable/MouseDrop_T(obj/O as obj, mob/user as mob) + + if ((!( istype(O, /obj/item/weapon) ) || user.equipped() != O)) + return + user.drop_item() + if (O.loc != src.loc) + step(O, get_dir(O, src)) + return + +/obj/machinery/optable/proc/check_victim() + if(locate(/mob/living/carbon/human, src.loc)) + var/mob/M = locate(/mob/living/carbon/human, src.loc) + if(M.resting) + src.victim = M + icon_state = "table2-active" + return 1 + src.victim = null + icon_state = "table2-idle" + return 0 + +/obj/machinery/optable/process() + check_victim() + +/obj/machinery/optable/attackby(obj/item/weapon/W as obj, mob/user as mob) + + if (istype(W, /obj/item/weapon/grab)) + if(ismob(W:affecting)) + var/mob/M = W:affecting + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.resting = 1 + M.loc = src.loc + for (var/mob/C in viewers(src)) + C.show_message("\red [M] has been laid on the operating table by [user].", 3) + for(var/obj/O in src) + O.loc = src.loc + src.add_fingerprint(user) + icon_state = "table2-active" + src.victim = M + del(W) + return + user.drop_item() + if(W && W.loc) + W.loc = src.loc + return \ No newline at end of file diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm new file mode 100644 index 0000000000000..b390b3ee58517 --- /dev/null +++ b/code/game/machinery/Sleeper.dm @@ -0,0 +1,287 @@ +///////////////////////////////////////// +// SLEEPER CONSOLE +///////////////////////////////////////// + +/obj/machinery/sleep_console + name = "Sleeper Console" + icon = 'Cryogenic2.dmi' + icon_state = "sleeperconsole" + var/obj/machinery/sleeper/connected = null + anchored = 1 //About time someone fixed this. + density = 1 + +/obj/machinery/sleep_console/ex_act(severity) + switch(severity) + if(1.0) + //SN src = null + del(src) + return + if(2.0) + if (prob(50)) + //SN src = null + del(src) + return + else + return + +/obj/machinery/sleep_console/New() + ..() + spawn( 5 ) + src.connected = locate(/obj/machinery/sleeper, get_step(src, WEST)) + return + return + +/obj/machinery/sleep_console/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/sleep_console/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/sleep_console/attack_hand(mob/user as mob) + if(..()) + return + if (src.connected) + var/mob/occupant = src.connected.occupant + var/dat = "Occupant Statistics:
      " + if (occupant) + var/t1 + switch(occupant.stat) + if(0) + t1 = "Conscious" + if(1) + t1 = "Unconscious" + if(2) + t1 = "*dead*" + else + dat += text("[]\tHealth %: [] ([])

      ", (occupant.health > 50 ? "" : ""), occupant.health, t1) + dat += text("[]\t-Brute Damage %: []
      ", (occupant.bruteloss < 60 ? "" : ""), occupant.bruteloss) + dat += text("[]\t-Respiratory Damage %: []
      ", (occupant.oxyloss < 60 ? "" : ""), occupant.oxyloss) + dat += text("[]\t-Toxin Content %: []
      ", (occupant.toxloss < 60 ? "" : ""), occupant.toxloss) + dat += text("[]\t-Burn Severity %: []
      ", (occupant.fireloss < 60 ? "" : ""), occupant.fireloss) + dat += text("
      Paralysis Summary %: [] ([] seconds left!)

      ", occupant.paralysis, round(occupant.paralysis / 4)) + dat += text("
      Refresh
      Inject Rejuvenators", src, src) + else + dat += "The sleeper is empty." + dat += text("

      Close", user) + user << browse(dat, "window=sleeper;size=400x500") + onclose(user, "sleeper") + return + +/obj/machinery/sleep_console/Topic(href, href_list) + if(..()) + return + if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) + usr.machine = src + if (href_list["rejuv"]) + if (src.connected) + src.connected.inject(usr) + if (href_list["refresh"]) + src.updateUsrDialog() + src.add_fingerprint(usr) + return + +/obj/machinery/sleep_console/process() + if(stat & (NOPOWER|BROKEN)) + return + src.updateUsrDialog() + return + +/obj/machinery/sleep_console/power_change() + return + // no change - sleeper works without power (you just can't inject more) + + + + + + + +///////////////////////////////////////// +// THE SLEEPER ITSELF +///////////////////////////////////////// + +/obj/machinery/sleeper + name = "Sleeper" + icon = 'Cryogenic2.dmi' + icon_state = "sleeper_0" + density = 1 + var/mob/occupant = null + anchored = 1 + +/obj/machinery/sleeper/allow_drop() + return 0 + +/obj/machinery/sleeper/process() + src.updateDialog() + return + +/obj/machinery/sleeper/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + return + +/obj/machinery/sleeper/blob_act() + if(prob(75)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + A.blob_act() + del(src) + return + +/obj/machinery/sleeper/attackby(obj/item/weapon/grab/G as obj, mob/user as mob) + if ((!( istype(G, /obj/item/weapon/grab) ) || !( ismob(G.affecting) ))) + return + if (src.occupant) + user << "\blue The sleeper is already occupied!" + return + // Removing the requirement for subjects to be naked -- TLE +/* if (G.affecting.abiotic()) + user << "Subject may not have abiotic items on." + return */ + var/mob/M = G.affecting + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + src.occupant = M + src.icon_state = "sleeper_1" + for(var/obj/O in src) + O.loc = src.loc + src.add_fingerprint(user) + del(G) + return + +/obj/machinery/sleeper/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + if(3.0) + if (prob(25)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + else + return + +/obj/machinery/sleeper/alter_health(mob/M as mob) + if (M.health > 0) + if (M.oxyloss >= 10) + var/amount = max(0.15, 1) + M.oxyloss -= amount + else + M.oxyloss = 0 + M.updatehealth() + M.paralysis -= 4 + M.weakened -= 4 + M.stunned -= 4 + if (M.paralysis <= 1) + M.paralysis = 3 + if (M.weakened <= 1) + M.weakened = 3 + if (M.stunned <= 1) + M.stunned = 3 + if (M:reagents.get_reagent_amount("inaprovaline") < 5) + M:reagents.add_reagent("inaprovaline", 5) + return + +/obj/machinery/sleeper/proc/go_out() + if (!src.occupant) + return + for(var/obj/O in src) + O.loc = src.loc + if (src.occupant.client) + src.occupant.client.eye = src.occupant.client.mob + src.occupant.client.perspective = MOB_PERSPECTIVE + src.occupant.loc = src.loc + src.occupant = null + src.icon_state = "sleeper_0" + return + +/obj/machinery/sleeper/proc/inject(mob/user as mob) + if (src.occupant) + if (src.occupant.reagents.get_reagent_amount("inaprovaline") < 60) + src.occupant.reagents.add_reagent("inaprovaline", 30) + user << text("Occupant now has [] units of rejuvenation in his/her bloodstream.", src.occupant.reagents.get_reagent_amount("inaprovaline")) + else + user << "No occupant!" + return + +/obj/machinery/sleeper/proc/check(mob/user as mob) + if (src.occupant) + user << text("\blue Occupant ([]) Statistics:", src.occupant) + var/t1 + switch(src.occupant.stat) + if(0.0) + t1 = "Conscious" + if(1.0) + t1 = "Unconscious" + if(2.0) + t1 = "*dead*" + else + user << text("[]\t Health %: [] ([])", (src.occupant.health > 50 ? "\blue " : "\red "), src.occupant.health, t1) + user << text("[]\t -Core Temperature: []°C ([]°F)

      ", (src.occupant.bodytemperature > 50 ? "" : ""), src.occupant.bodytemperature-T0C, src.occupant.bodytemperature*1.8-459.67) + user << text("[]\t -Brute Damage %: []", (src.occupant.bruteloss < 60 ? "\blue " : "\red "), src.occupant.bruteloss) + user << text("[]\t -Respiratory Damage %: []", (src.occupant.oxyloss < 60 ? "\blue " : "\red "), src.occupant.oxyloss) + user << text("[]\t -Toxin Content %: []", (src.occupant.toxloss < 60 ? "\blue " : "\red "), src.occupant.toxloss) + user << text("[]\t -Burn Severity %: []", (src.occupant.fireloss < 60 ? "\blue " : "\red "), src.occupant.fireloss) + user << "\blue Expected time till occupant can safely awake: (note: If health is below 20% these times are inaccurate)" + user << text("\blue \t [] second\s (if around 1 or 2 the sleeper is keeping them asleep.)", src.occupant.paralysis / 5) + else + user << "\blue There is no one inside!" + return + +/obj/machinery/sleeper/verb/eject() + set src in oview(1) + + if (usr.stat != 0) + return + src.go_out() + add_fingerprint(usr) + return + +/obj/machinery/sleeper/verb/move_inside() + set src in oview(1) + + if (usr.stat != 0) + return + if (src.occupant) + usr << "\blue The sleeper is already occupied!" + return +/* if (usr.abiotic()) // Removing the requirement for user to be naked -- TLE + usr << "Subject may not have abiotic items on." + return*/ + usr.pulling = null + usr.client.perspective = EYE_PERSPECTIVE + usr.client.eye = src + usr.loc = src + src.occupant = usr + src.icon_state = "sleeper_1" + for(var/obj/O in src) + del(O) + src.add_fingerprint(usr) + return \ No newline at end of file diff --git a/code/game/machinery/airlock_control.dm b/code/game/machinery/airlock_control.dm new file mode 100644 index 0000000000000..438a499949659 --- /dev/null +++ b/code/game/machinery/airlock_control.dm @@ -0,0 +1,202 @@ +#define AIRLOCK_CONTROL_RANGE 5 + +// This code allows for airlocks to be controlled externally by setting an id_tag and comm frequency (disables ID access) +obj/machinery/door/airlock + var/id_tag + var/frequency + + var/datum/radio_frequency/radio_connection + + receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + if(id_tag != signal.data["tag"]) return + + switch(signal.data["command"]) + if("open") + spawn open(1) + + if("close") + spawn close(1) + + if("unlock") + locked = 0 + update_icon() + + if("lock") + locked = 1 + update_icon() + + if("secure_open") + spawn + locked = 0 + update_icon() + + sleep(5) + open(1) + + locked = 1 + update_icon() + + if("secure_close") + spawn + locked = 0 + close(1) + + locked = 1 + sleep(5) + update_icon() + + send_status() + + proc/send_status() + if(radio_connection) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = id_tag + signal.data["timestamp"] = air_master.current_cycle + + signal.data["door_status"] = density?("closed"):("open") + signal.data["lock_status"] = locked?("locked"):("unlocked") + + radio_connection.post_signal(src, signal, AIRLOCK_CONTROL_RANGE) + + open(surpress_send) + . = ..() + if(!surpress_send) send_status() + + close(surpress_send) + . = ..() + if(!surpress_send) send_status() + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + if(new_frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, "[frequency]") + + initialize() + if(frequency) + set_frequency(frequency) + + update_icon() + + New() + ..() + + if(radio_controller) + set_frequency(frequency) + +obj/machinery/airlock_sensor + icon = 'airlock_machines.dmi' + icon_state = "airlock_sensor_off" + name = "Airlock Sensor" + + anchored = 1 + + var/id_tag + var/master_tag + var/frequency = 1449 + + var/datum/radio_frequency/radio_connection + + var/on = 1 + var/alert = 0 + + proc/update_icon() + if(on) + if(alert) + icon_state = "airlock_sensor_alert" + else + icon_state = "airlock_sensor_standby" + else + icon_state = "airlock_sensor_off" + + attack_hand(mob/user) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = master_tag + signal.data["command"] = "cycle" + + radio_connection.post_signal(src, signal, AIRLOCK_CONTROL_RANGE) + flick("airlock_sensor_cycle", src) + + process() + if(on) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = id_tag + signal.data["timestamp"] = air_master.current_cycle + + var/datum/gas_mixture/air_sample = return_air() + + var/pressure = round(air_sample.return_pressure(),0.1) + alert = (pressure < ONE_ATMOSPHERE*0.8) + + signal.data["pressure"] = num2text(pressure) + + radio_connection.post_signal(src, signal, AIRLOCK_CONTROL_RANGE) + + update_icon() + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + radio_connection = radio_controller.add_object(src, "[frequency]") + + initialize() + set_frequency(frequency) + + New() + ..() + + if(radio_controller) + set_frequency(frequency) + +obj/machinery/access_button + icon = 'airlock_machines.dmi' + icon_state = "access_button_standby" + name = "Access Button" + + anchored = 1 + + var/master_tag + var/frequency = 1449 + var/command = "cycle" + + var/datum/radio_frequency/radio_connection + + var/on = 1 + + proc/update_icon() + if(on) + icon_state = "access_button_standby" + else + icon_state = "access_button_off" + + attack_hand(mob/user) + if(radio_connection) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = master_tag + signal.data["command"] = command + + radio_connection.post_signal(src, signal, AIRLOCK_CONTROL_RANGE) + flick("access_button_cycle", src) + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + radio_connection = radio_controller.add_object(src, "[frequency]") + + initialize() + set_frequency(frequency) + + New() + ..() + + if(radio_controller) + set_frequency(frequency) diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm new file mode 100644 index 0000000000000..fd2bcceed54ae --- /dev/null +++ b/code/game/machinery/alarm.dm @@ -0,0 +1,407 @@ +/obj/machinery/alarm/New() + ..() + + if(!alarm_zone) + var/area/A = get_area(loc) + if(A.name) + alarm_zone = A.name + else + alarm_zone = "Unregistered" + +/obj/machinery/alarm/process() + if (src.skipprocess) + src.skipprocess-- + return + + var/turf/location = src.loc + var/safe = 2 + + if(stat & (NOPOWER|BROKEN)) + icon_state = "alarmp" + return + + use_power(5, ENVIRON) + + if (!( istype(location, /turf) )) + return 0 + + var/datum/gas_mixture/environment = location.return_air() + + var/environment_pressure = environment.return_pressure() + + if((environment_pressure < ONE_ATMOSPHERE*0.90) || (environment_pressure > ONE_ATMOSPHERE*1.10)) + //Pressure sensor + if((environment_pressure < ONE_ATMOSPHERE*0.80) || (environment_pressure > ONE_ATMOSPHERE*1.20)) + safe = 0 + else safe = 1 + + if(safe && ((environment.oxygen < MOLES_O2STANDARD*0.90) || (environment.oxygen > MOLES_O2STANDARD*1.10))) + //Oxygen Levels Sensor + if(environment.oxygen < MOLES_O2STANDARD*0.80) + safe = 0 + else safe = 1 + + if(safe && ((environment.temperature < (T20C-10)) || (environment.temperature > (T20C+10)))) + //Oxygen Levels Sensor + if((environment.temperature < (T20C-20)) || (environment.temperature > (T20C+10))) + safe = 0 + else safe = 1 + + if(safe && (environment.carbon_dioxide > 0.05)) + //CO2 Levels Sensor + if(environment.carbon_dioxide > 0.1) + safe = 0 + else safe = 1 + + if(safe && (environment.toxins > 1)) + //Plasma Levels Sensor + if(environment.toxins > 2) + safe = 0 + else safe = 1 + + src.icon_state = "alarm[!safe]" + + if(safe == 2) src.skipprocess = 1 + else if(alarm_frequency) + post_alert(safe) + + return + +/obj/machinery/alarm/proc/post_alert(alert_level) + + var/datum/radio_frequency/frequency = radio_controller.return_frequency(alarm_frequency) + + if(!frequency) return + + var/datum/signal/alert_signal = new + alert_signal.source = src + alert_signal.transmission_method = 1 + alert_signal.data["zone"] = alarm_zone + alert_signal.data["type"] = "Atmospheric" + + if(alert_level==0) + alert_signal.data["alert"] = "severe" + else + alert_signal.data["alert"] = "minor" + + frequency.post_signal(src, alert_signal) + +/obj/machinery/alarm/attackby(W as obj, user as mob) + if (istype(W, /obj/item/weapon/wirecutters)) + stat ^= BROKEN + src.add_fingerprint(user) + for(var/mob/O in viewers(user, null)) + O.show_message(text("\red [] has []activated []!", user, (stat&BROKEN) ? "de" : "re", src), 1) + return + return ..() + +/obj/machinery/alarm/power_change() + if(powered(ENVIRON)) + stat &= ~NOPOWER + else + stat |= NOPOWER + +/obj/machinery/alarm/Click() + if(istype(usr, /mob/living/silicon/ai)) + return examine() + return ..() + +/obj/machinery/alarm/examine() + set src in oview(1) + /* + if(usr.stat) + return + if(stat & (NOPOWER|BROKEN)) + return + if(!(istype(usr, /mob/living/carbon/human) || ticker)) + if (!istype(usr, /mob/living/silicon/ai)) + usr << "\red You don't have the dexterity to do this!" + return + if (get_dist(usr, src) <= 3 || istype(usr, /mob/living/silicon/ai)) + var/turf/T = src.loc + if (!( istype(T, /turf) )) + return + + var/turf_total = T.co2 + T.oxygen + T.poison + T.sl_gas + T.n2 + turf_total = max(turf_total, 1) + usr.show_message("\blue Results:", 1) + var/t = "" + var/t1 = turf_total / CELLSTANDARD * 100 + if ((90 < t1 && t1 < 110)) + usr.show_message(text("\blue Air Pressure: []%", t1), 1) + else + usr.show_message(text("\blue Air Pressure:\red []%", t1), 1) + t1 = T.n2 / turf_total * 100 + t1 = round(t1, 0.0010) + if ((60 < t1 && t1 < 80)) + t += text("Nitrogen: [] ", t1) + else + t += text("Nitrogen: [] ", t1) + t1 = T.oxygen / turf_total * 100 + t1 = round(t1, 0.0010) + if ((20 < t1 && t1 < 24)) + t += text("Oxygen: [] ", t1) + else + t += text("Oxygen: [] ", t1) + t1 = T.poison / turf_total * 100 + t1 = round(t1, 0.0010) + if (t1 < 0.5) + t += text("Plasma: [] ", t1) + else + t += text("Plasma: [] ", t1) + t1 = T.co2 / turf_total * 100 + t1 = round(t1, 0.0010) + if (t1 < 1) + t += text("CO2: [] ", t1) + else + t += text("CO2: [] ", t1) + t1 = T.sl_gas / turf_total * 100 + t1 = round(t1, 0.0010) + if (t1 < 5) + t += text("NO2: []", t1) + else + t += text("NO2: []", t1) + t1 = T.temp - T0C + if (T.temp > 326.444 || T.temp < 282.591) + t += text("
      Temperature: []", t1) + else + t += text("
      Temperature: []", t1) + usr.show_message(t, 1) + return + else + usr << "\blue You are too far away." + */ + + +/obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume) + if(src.detecting) + if(temperature > T0C+200) + src.alarm() // added check of detector status here + return + +/obj/machinery/firealarm/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/firealarm/bullet_act(BLAH) + return src.alarm() + +/obj/machinery/firealarm/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/firealarm/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/wirecutters)) + src.detecting = !( src.detecting ) + if (src.detecting) + user.visible_message("\red [user] has reconnected [src]'s detecting unit!", "You have reconnected [src]'s detecting unit.") + else + user.visible_message("\red [user] has disconnected [src]'s detecting unit!", "You have disconnected [src]'s detecting unit.") + else + src.alarm() + src.add_fingerprint(user) + return + +/obj/machinery/firealarm/process() + if(stat & (NOPOWER|BROKEN)) + return + + use_power(10, ENVIRON) + + if (src.timing) + if (src.time > 0) + src.time = round(src.time) - 1 + else + alarm() + src.time = 0 + src.timing = 0 + src.updateDialog() + return + +/obj/machinery/firealarm/power_change() + if(powered(ENVIRON)) + stat &= ~NOPOWER + icon_state = "fire0" + else + spawn(rand(0,15)) + stat |= NOPOWER + icon_state = "firep" + +/obj/machinery/firealarm/attack_hand(mob/user as mob) + if(user.stat || stat & (NOPOWER|BROKEN)) + return + + user.machine = src + var/area/A = src.loc + var/d1 + var/d2 + if (istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon/ai)) + A = A.loc + + if (A.fire) + d1 = text("Reset - Lockdown", src) + else + d1 = text("Alarm - Lockdown", src) + if (src.timing) + d2 = text("Stop Time Lock", src) + else + d2 = text("Initiate Time Lock", src) + var/second = src.time % 60 + var/minute = (src.time - second) / 60 + var/dat = text("Fire alarm []\n
      \nTimer System: []
      \nTime Left: [][] - - + +\n
      ", d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=firealarm") + onclose(user, "firealarm") + else + A = A.loc + if (A.fire) + d1 = text("[]", src, stars("Reset - Lockdown")) + else + d1 = text("[]", src, stars("Alarm - Lockdown")) + if (src.timing) + d2 = text("[]", src, stars("Stop Time Lock")) + else + d2 = text("[]", src, stars("Initiate Time Lock")) + var/second = src.time % 60 + var/minute = (src.time - second) / 60 + var/dat = text("[] []\n
      \nTimer System: []
      \nTime Left: [][] - - + +\n
      ", stars("Fire alarm"), d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=firealarm") + onclose(user, "firealarm") + return + +/obj/machinery/firealarm/Topic(href, href_list) + ..() + if (usr.stat || stat & (BROKEN|NOPOWER)) + return + if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) + usr.machine = src + if (href_list["reset"]) + src.reset() + else + if (href_list["alarm"]) + src.alarm() + else + if (href_list["time"]) + src.timing = text2num(href_list["time"]) + else + if (href_list["tp"]) + var/tp = text2num(href_list["tp"]) + src.time += tp + src.time = min(max(round(src.time), 0), 120) + src.updateUsrDialog() + + src.add_fingerprint(usr) + else + usr << browse(null, "window=firealarm") + return + return + +/obj/machinery/firealarm/proc/reset() + if (!( src.working )) + return + var/area/A = src.loc + A = A.loc + if (!( istype(A, /area) )) + return + for(var/area/RA in A.related) + RA.firereset() + return + +/obj/machinery/firealarm/proc/alarm() + if (!( src.working )) + return + var/area/A = src.loc + A = A.loc + if (!( istype(A, /area) )) + return + for(var/area/RA in A.related) + RA.firealert() + //playsound(src.loc, 'signal.ogg', 75, 0) + return + +/obj/machinery/partyalarm/attack_paw(mob/user as mob) + return src.attack_hand(user) +/obj/machinery/partyalarm/attack_hand(mob/user as mob) + if(user.stat || stat & (NOPOWER|BROKEN)) + return + + user.machine = src + var/area/A = src.loc + var/d1 + var/d2 + if (istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon/ai)) + A = A.loc + + if (A.party) + d1 = text("No Party :(", src) + else + d1 = text("PARTY!!!", src) + if (src.timing) + d2 = text("Stop Time Lock", src) + else + d2 = text("Initiate Time Lock", src) + var/second = src.time % 60 + var/minute = (src.time - second) / 60 + var/dat = text("Party Button []\n
      \nTimer System: []
      \nTime Left: [][] - - + +\n
      ", d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=partyalarm") + onclose(user, "partyalarm") + else + A = A.loc + if (A.fire) + d1 = text("[]", src, stars("No Party :(")) + else + d1 = text("[]", src, stars("PARTY!!!")) + if (src.timing) + d2 = text("[]", src, stars("Stop Time Lock")) + else + d2 = text("[]", src, stars("Initiate Time Lock")) + var/second = src.time % 60 + var/minute = (src.time - second) / 60 + var/dat = text("[] []\n
      \nTimer System: []
      \nTime Left: [][] - - + +\n
      ", stars("Party Button"), d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=partyalarm") + onclose(user, "partyalarm") + return + +/obj/machinery/partyalarm/proc/reset() + if (!( src.working )) + return + var/area/A = src.loc + A = A.loc + if (!( istype(A, /area) )) + return + A.partyreset() + return + +/obj/machinery/partyalarm/proc/alarm() + if (!( src.working )) + return + var/area/A = src.loc + A = A.loc + if (!( istype(A, /area) )) + return + A.partyalert() + return + +/obj/machinery/partyalarm/Topic(href, href_list) + ..() + if (usr.stat || stat & (BROKEN|NOPOWER)) + return + if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) + usr.machine = src + if (href_list["reset"]) + src.reset() + else + if (href_list["alarm"]) + src.alarm() + else + if (href_list["time"]) + src.timing = text2num(href_list["time"]) + else + if (href_list["tp"]) + var/tp = text2num(href_list["tp"]) + src.time += tp + src.time = min(max(round(src.time), 0), 120) + src.updateUsrDialog() + + src.add_fingerprint(usr) + else + usr << browse(null, "window=partyalarm") + return + return \ No newline at end of file diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm new file mode 100644 index 0000000000000..322c117b672bc --- /dev/null +++ b/code/game/machinery/atmo_control.dm @@ -0,0 +1,558 @@ +obj/machinery/air_sensor + icon = 'stationobjs.dmi' + icon_state = "gsensor1" + name = "Gas Sensor" + + anchored = 1 + + var/id_tag + var/frequency = 1439 + + var/on = 1 + var/output = 3 + //Flags: + // 1 for pressure + // 2 for temperature + // 4 for oxygen concentration + // 8 for toxins concentration + + var/datum/radio_frequency/radio_connection + + proc/update_icon() + icon_state = "gsensor[on]" + + process() + if(on) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = id_tag + signal.data["timestamp"] = air_master.current_cycle + + var/datum/gas_mixture/air_sample = return_air() + + if(output&1) + signal.data["pressure"] = num2text(round(air_sample.return_pressure(),0.1),) + if(output&2) + signal.data["temperature"] = round(air_sample.temperature,0.1) + + if(output&12) + var/total_moles = air_sample.total_moles() + if(output&4) + signal.data["oxygen"] = round(100*air_sample.oxygen/total_moles) + if(output&8) + signal.data["toxins"] = round(100*air_sample.toxins/total_moles) + + radio_connection.post_signal(src, signal) + + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + radio_connection = radio_controller.add_object(src, "[frequency]") + + initialize() + set_frequency(frequency) + + New() + ..() + + if(radio_controller) + set_frequency(frequency) + +obj/machinery/computer/general_air_control + icon = 'computer.dmi' + icon_state = "computer_generic" + + name = "Computer" + + var/frequency = 1439 + var/list/sensors = list() + + var/list/sensor_information = list() + var/datum/radio_frequency/radio_connection + + attack_hand(mob/user) + user << browse(return_text(),"window=computer") + user.machine = src + onclose(user, "computer") + + process() + ..() + + src.updateDialog() + + attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/air_management/M = new /obj/item/weapon/circuitboard/air_management( A ) + for (var/obj/C in src) + C.loc = src.loc + M.frequency = src.frequency + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/air_management/M = new /obj/item/weapon/circuitboard/air_management( A ) + for (var/obj/C in src) + C.loc = src.loc + M.frequency = src.frequency + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + + receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + var/id_tag = signal.data["tag"] + if(!id_tag || !sensors.Find(id_tag)) return + + sensor_information[id_tag] = signal.data + + proc/return_text() + var/sensor_data + if(sensors.len) + for(var/id_tag in sensors) + var/long_name = sensors[id_tag] + var/list/data = sensor_information[id_tag] + var/sensor_part = "[long_name]: " + + if(data) + if(data["pressure"]) + sensor_part += "[data["pressure"]] kPa" + if(data["temperature"]) + sensor_part += ", [data["temperature"]] K" + sensor_part += "
      " + else if(data["temperature"]) + sensor_part += "[data["temperature"]] K
      " + + if(data["oxygen"]||data["toxins"]) + sensor_part += "[long_name] Composition: " + if(data["oxygen"]) + sensor_part += "[data["oxygen"]] %O2" + if(data["toxins"]) + sensor_part += ", [data["toxins"]] %TX" + sensor_part += "
      " + else if(data["toxins"]) + sensor_part += "[data["toxins"]] %TX
      " + + else + sensor_part = "[long_name] can not be found!
      " + + sensor_data += sensor_part + + else + sensor_data = "No sensors connected." + + var/output = {"[name]
      +Sensor Data:
      +[sensor_data]
      "} + + return output + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + radio_connection = radio_controller.add_object(src, "[frequency]") + + initialize() + set_frequency(frequency) + + large_tank_control + icon = 'computer.dmi' + icon_state = "tank" + + var/input_tag + var/output_tag + + var/list/input_info + var/list/output_info + + var/pressure_setting = ONE_ATMOSPHERE * 45 + + + return_text() + var/output = ..() + //if(signal.data) + // input_info = signal.data // Attempting to fix intake control -- TLE + + output += "Tank Control System
      " + if(input_info) + var/power = (input_info["power"] == "on") + var/volume_rate = input_info["volume_rate"] + output += {"Input: [power?("Injecting"):("On Hold")] Refresh
      +Rate: [volume_rate] L/sec
      "} + output += "Command: Toggle Power
      " + + else + output += "ERROR: Can not find input port Search
      " + + output += "
      " + + if(output_info) + var/power = (output_info["power"] == "on") + var/output_pressure = output_info["internal"] + output += {"Output: [power?("Open"):("On Hold")] Refresh
      +Max Output Pressure: [output_pressure] kPa
      "} + output += "Command: Toggle Power Set Pressure
      " + + else + output += "ERROR: Can not find output port Search
      " + + output += "Max Output Pressure Set: - - [pressure_setting] kPa + +
      " + + return output + + receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + var/id_tag = signal.data["tag"] + + if(input_tag == id_tag) + input_info = signal.data + else if(output_tag == id_tag) + output_info = signal.data + else + ..(signal) + + Topic(href, href_list) + if(..()) + return + + if(href_list["in_refresh_status"]) + input_info = null + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = input_tag + signal.data["status"] = 1 + + radio_connection.post_signal(src, signal) + + if(href_list["in_toggle_injector"]) + input_info = null + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = input_tag + signal.data["command"] = "power_toggle" + + radio_connection.post_signal(src, signal) + + if(href_list["out_refresh_status"]) + output_info = null + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = output_tag + signal.data["status"] = 1 + + radio_connection.post_signal(src, signal) + + if(href_list["out_toggle_power"]) + output_info = null + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = output_tag + signal.data["command"] = "power_toggle" + + radio_connection.post_signal(src, signal) + + if(href_list["out_set_pressure"]) + output_info = null + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = output_tag + signal.data["command"] = "set_internal_pressure" + signal.data["parameter"] = "[pressure_setting]" + + radio_connection.post_signal(src, signal) + + if(href_list["adj_pressure"]) + var/change = text2num(href_list["adj_pressure"]) + pressure_setting = min(max(0, pressure_setting + change), 50*ONE_ATMOSPHERE) + + spawn(7) + attack_hand(usr) + + fuel_injection + icon = 'computer.dmi' + icon_state = "atmos" + + var/device_tag + var/list/device_info + + var/automation = 0 + + var/cutoff_temperature = 2000 + var/on_temperature = 1200 + + attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/injector_control/M = new /obj/item/weapon/circuitboard/injector_control( A ) + for (var/obj/C in src) + C.loc = src.loc + M.frequency = src.frequency + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/injector_control/M = new /obj/item/weapon/circuitboard/injector_control( A ) + for (var/obj/C in src) + C.loc = src.loc + M.frequency = src.frequency + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + + process() + if(automation) + if(!radio_connection) + return 0 + + var/injecting = 0 + for(var/id_tag in sensor_information) + var/list/data = sensor_information[id_tag] + if(data["temperature"]) + if(data["temperature"] >= cutoff_temperature) + injecting = 0 + break + if(data["temperature"] <= on_temperature) + injecting = 1 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = device_tag + + if(injecting) + signal.data["command"] = "power_on" + else + signal.data["command"] = "power_off" + + radio_connection.post_signal(src, signal) + + ..() + + return_text() + var/output = ..() + + output += "Fuel Injection System
      " + if(device_info) + var/power = device_info["power"] + var/volume_rate = device_info["volume_rate"] + output += {"Status: [power?("Injecting"):("On Hold")] Refresh
      +Rate: [volume_rate] L/sec
      "} + + if(automation) + output += "Automated Fuel Injection: Engaged
      " + output += "Injector Controls Locked Out
      " + else + output += "Automated Fuel Injection: Disengaged
      " + output += "Injector: Toggle Power Inject (1 Cycle)
      " + + else + output += "ERROR: Can not find device Search
      " + + return output + + receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + var/id_tag = signal.data["tag"] + + if(device_tag == id_tag) + device_info = signal.data + else + ..(signal) + + Topic(href, href_list) + if(..()) + return + + if(href_list["refresh_status"]) + device_info = null + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = device_tag + signal.data["status"] = 1 + + radio_connection.post_signal(src, signal) + + if(href_list["toggle_automation"]) + automation = !automation + + if(href_list["toggle_injector"]) + device_info = null + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = device_tag + signal.data["command"] = "power_toggle" + + radio_connection.post_signal(src, signal) + + if(href_list["injection"]) + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data["tag"] = device_tag + signal.data["command"] = "inject" + + radio_connection.post_signal(src, signal) + +/obj/machinery/computer/general_alert + var/datum/radio_frequency/radio_connection + + initialize() + set_frequency(receive_frequency) + + receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + var/zone = signal.data["zone"] + var/severity = signal.data["alert"] + + if(!zone || !severity) return + + if(severity=="severe") + priority_alarms -= zone + priority_alarms += zone + else + minor_alarms -= zone + minor_alarms += zone + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[receive_frequency]") + receive_frequency = new_frequency + radio_connection = radio_controller.add_object(src, "[receive_frequency]") + + + attack_hand(mob/user) + user << browse(return_text(),"window=computer") + user.machine = src + onclose(user, "computer") + + process() + if(priority_alarms.len) + icon_state = "alert:2" + + else if(minor_alarms.len) + icon_state = "alert:1" + + else + icon_state = "alert:0" + + ..() + + src.updateDialog() + + proc/return_text() + var/priority_text + var/minor_text + + if(priority_alarms.len) + for(var/zone in priority_alarms) + priority_text += "[zone] X
      " + else + priority_text = "No priority alerts detected.
      " + + if(minor_alarms.len) + for(var/zone in minor_alarms) + minor_text += "[zone] X
      " + else + minor_text = "No minor alerts detected.
      " + + var/output = {"[name]
      +Priority Alerts:
      +[priority_text] +
      +
      +Minor Alerts:
      +[minor_text] +
      "} + + return output + + Topic(href, href_list) + if(..()) + return + + if(href_list["priority_clear"]) + var/removing_zone = href_list["priority_clear"] + for(var/zone in priority_alarms) + if(ckey(zone) == removing_zone) + priority_alarms -= zone + + if(href_list["minor_clear"]) + var/removing_zone = href_list["minor_clear"] + for(var/zone in minor_alarms) + if(ckey(zone) == removing_zone) + minor_alarms -= zone \ No newline at end of file diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm new file mode 100644 index 0000000000000..083d43569f1c3 --- /dev/null +++ b/code/game/machinery/atmoalter/canister.dm @@ -0,0 +1,270 @@ +/obj/machinery/portable_atmospherics/canister + name = "canister" + icon = 'atmos.dmi' + density = 1 + var/health = 100.0 + flags = FPRINT | CONDUCT + + var/valve_open = 0 + var/release_pressure = ONE_ATMOSPHERE + + var/color = "blue" + var/filled = 0.5 + pressure_resistance = 7*ONE_ATMOSPHERE + var/temperature_resistance = 1000 + T0C + volume = 1000 + +/obj/machinery/portable_atmospherics/canister/sleeping_agent + name = "Canister: \[N2O\]" + icon_state = "redws" + color = "redws" +/obj/machinery/portable_atmospherics/canister/nitrogen + name = "Canister: \[N2\]" + icon_state = "red" + color = "red" +/obj/machinery/portable_atmospherics/canister/oxygen + name = "Canister: \[O2\]" + icon_state = "blue" +/obj/machinery/portable_atmospherics/canister/toxins + name = "Canister \[Toxin (Bio)\]" + icon_state = "orange" + color = "orange" +/obj/machinery/portable_atmospherics/canister/carbon_dioxide + name = "Canister \[CO2\]" + icon_state = "black" + color = "black" +/obj/machinery/portable_atmospherics/canister/air + name = "Canister \[Air\]" + icon_state = "grey" + color = "grey" + +/obj/machinery/portable_atmospherics/canister/update_icon() + src.overlays = 0 + + if (src.destroyed) + src.icon_state = text("[]-1", src.color) + + else + icon_state = "[color]" + if(holding) + overlays += image('atmos.dmi', "can-oT") + + var/tank_pressure = air_contents.return_pressure() + + if (tank_pressure < 10) + overlays += image('atmos.dmi', "can-o0") + else if (tank_pressure < ONE_ATMOSPHERE) + overlays += image('atmos.dmi', "can-o1") + else if (tank_pressure < 15*ONE_ATMOSPHERE) + overlays += image('atmos.dmi', "can-o2") + else + overlays += image('atmos.dmi', "can-o3") + return + +/obj/machinery/portable_atmospherics/canister/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > temperature_resistance) + health -= 5 + healthcheck() + +/obj/machinery/portable_atmospherics/canister/proc/healthcheck() + if(destroyed) + return 1 + + if (src.health <= 10) + var/atom/location = src.loc + location.assume_air(air_contents) + + src.destroyed = 1 + playsound(src.loc, 'spray.ogg', 10, 1, -3) + src.density = 0 + update_icon() + + if (src.holding) + src.holding.loc = src.loc + src.holding = null + + return 1 + else + return 1 + +/obj/machinery/portable_atmospherics/canister/process() + if (destroyed) + return + + ..() + + var/datum/gas_mixture/environment + + if(holding) + environment = holding.air_contents + else + environment = loc.return_air() + + var/env_pressure = environment.return_pressure() + + if(valve_open) + var/pressure_delta = min(release_pressure - env_pressure, (air_contents.return_pressure() - env_pressure)/2) + //Can not have a pressure delta that would cause environment pressure > tank pressure + + var/transfer_moles = 0 + if((air_contents.temperature > 0) && (pressure_delta > 0)) + transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) + + if(holding) + environment.merge(removed) + else + loc.assume_air(removed) + + src.updateDialog() + src.update_icon() + return + +/obj/machinery/portable_atmospherics/canister/return_air() + return air_contents + +/obj/machinery/portable_atmospherics/canister/blob_act() + src.health -= 1 + healthcheck() + return + + +/obj/machinery/portable_atmospherics/canister/meteorhit(var/obj/O as obj) + src.health = 0 + healthcheck() + return + +/obj/machinery/portable_atmospherics/canister/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(!istype(W, /obj/item/weapon/wrench) && !istype(W, /obj/item/weapon/tank) && !istype(W, /obj/item/device/analyzer) && !istype(W, /obj/item/device/pda)) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\red [user] hits the [src] with a [W]!")) + src.health -= W.force + healthcheck() + ..() + +/obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/canister/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user as mob) + if (src.destroyed) + return + + user.machine = src + var/holding_text + if(holding) + holding_text = {"
      Tank Pressure: [holding.air_contents.return_pressure()] KPa
      +Remove Tank
      +"} + var/output_text = {"[name]
      +Pressure: [air_contents.return_pressure()] KPa
      +Port Status: [(connected_port)?("Connected"):("Disconnected")] +[holding_text] +
      +Release Valve: [valve_open?("Open"):("Closed")]
      +Release Pressure: - - [release_pressure] + +
      +
      +Close
      +"} + + user << browse(output_text, "window=canister;size=600x300") + onclose(user, "canister") + return + +/obj/machinery/portable_atmospherics/canister/Topic(href, href_list) + ..() + if (usr.stat || usr.restrained()) + return + if (((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) + usr.machine = src + + if(href_list["toggle"]) + valve_open = !valve_open + + if (href_list["remove_tank"]) + if(holding) + holding.loc = loc + holding = null + + if (href_list["pressure_adj"]) + var/diff = text2num(href_list["pressure_adj"]) + if(diff > 0) + release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff) + else + release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff) + + src.updateUsrDialog() + src.add_fingerprint(usr) + update_icon() + else + usr << browse(null, "window=canister") + return + return + +/obj/machinery/portable_atmospherics/canister/bullet_act(flag) + if (flag == PROJECTILE_BULLET) + src.health = 0 + spawn( 0 ) + healthcheck() + return + return + +/obj/machinery/portable_atmospherics/canister/toxins/New() + + ..() + + src.air_contents.toxins = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature) + + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/oxygen/New() + + ..() + + src.air_contents.oxygen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature) + + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/sleeping_agent/New() + + ..() + + var/datum/gas/sleeping_agent/trace_gas = new + air_contents.trace_gases += trace_gas + trace_gas.moles = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature) + + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/nitrogen/New() + + ..() + + src.air_contents.nitrogen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature) + + src.update_icon() + return 1 + +/obj/machinery/portable_atmospherics/canister/carbon_dioxide/New() + + ..() + src.air_contents.carbon_dioxide = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature) + + src.update_icon() + return 1 + + +/obj/machinery/portable_atmospherics/canister/air/New() + + ..() + src.air_contents.oxygen = (O2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature) + src.air_contents.nitrogen = (N2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature) + + src.update_icon() + return 1 \ No newline at end of file diff --git a/code/game/machinery/atmoalter/meter.dm b/code/game/machinery/atmoalter/meter.dm new file mode 100644 index 0000000000000..2b9e069c8f924 --- /dev/null +++ b/code/game/machinery/atmoalter/meter.dm @@ -0,0 +1,90 @@ +/obj/machinery/meter/New() + ..() + + src.target = locate(/obj/machinery/atmospherics/pipe) in loc + + return 1 + +/obj/machinery/meter/process() + if(!target) + icon_state = "meterX" + return 0 + + if(stat & (BROKEN|NOPOWER)) + icon_state = "meter0" + return 0 + + use_power(5) + + var/datum/gas_mixture/environment = target.return_air() + if(!environment) + icon_state = "meterX" + return 0 + + var/env_pressure = environment.return_pressure() + if(env_pressure <= 0.15*ONE_ATMOSPHERE) + icon_state = "meter0" + else if(env_pressure <= 1.8*ONE_ATMOSPHERE) + var/val = round(env_pressure/(ONE_ATMOSPHERE*0.3) + 0.5) + icon_state = "meter1_[val]" + else if(env_pressure <= 30*ONE_ATMOSPHERE) + var/val = round(env_pressure/(ONE_ATMOSPHERE*5)-0.35) + 1 + icon_state = "meter2_[val]" + else if(env_pressure <= 59*ONE_ATMOSPHERE) + var/val = round(env_pressure/(ONE_ATMOSPHERE*5) - 6) + 1 + icon_state = "meter3_[val]" + else + icon_state = "meter4" + + if(frequency) + var/datum/radio_frequency/radio_connection = radio_controller.return_frequency("[frequency]") + + if(!radio_connection) return + + var/datum/signal/signal = new + signal.source = src + signal.transmission_method = 1 + + signal.data["tag"] = id + signal.data["device"] = "AM" + signal.data["pressure"] = round(env_pressure) + + radio_connection.post_signal(src, signal) + +/obj/machinery/meter/examine() + set src in oview(1) + + var/t = "A gas flow meter. " + if (src.target) + var/datum/gas_mixture/environment = target.return_air() + if(environment) + t += text("The pressure gauge reads [] kPa", round(environment.return_pressure(), 0.1)) + else + t += "The sensor error light is blinking." + else + t += "The connect error light is blinking." + + usr << t + + + +/obj/machinery/meter/Click() + + if(stat & (NOPOWER|BROKEN)) + return + + var/t = null + if (get_dist(usr, src) <= 3 || istype(usr, /mob/living/silicon/ai)) + if (src.target) + var/datum/gas_mixture/environment = target.return_air() + if(environment) + t = text("Pressure: [] kPa", round(environment.return_pressure(), 0.1)) + else + t = "\red Results: Sensor Error!" + else + t = "\red Results: Connection Error!" + else + usr << "\blue You are too far away." + + usr << t + return diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm new file mode 100644 index 0000000000000..a5979bea6bcad --- /dev/null +++ b/code/game/machinery/atmoalter/portable_atmospherics.dm @@ -0,0 +1,130 @@ +/obj/machinery/portable_atmospherics + name = "atmoalter" + var/datum/gas_mixture/air_contents = new + + var/obj/machinery/atmospherics/portables_connector/connected_port + var/obj/item/weapon/tank/holding + + var/volume = 0 + var/destroyed = 0 + + var/maximum_pressure = 90*ONE_ATMOSPHERE + + New() + ..() + + air_contents.volume = volume + air_contents.temperature = T20C + + return 1 + + process() + if(!connected_port) //only react when pipe_network will ont it do it for you + //Allow for reactions + air_contents.react() + + Del() + del(air_contents) + + ..() + + proc + update_icon() + return null + + connect(obj/machinery/atmospherics/portables_connector/new_port) + //Make sure not already connected to something else + if(connected_port || !new_port || new_port.connected_device) + return 0 + + //Make sure are close enough for a valid connection + if(new_port.loc != loc) + return 0 + + //Perform the connection + connected_port = new_port + connected_port.connected_device = src + + anchored = 1 //Prevent movement + + //Actually enforce the air sharing + var/datum/pipe_network/network = connected_port.return_network(src) + if(network && !network.gases.Find(air_contents)) + network.gases += air_contents + + return 1 + + disconnect() + if(!connected_port) + return 0 + + var/datum/pipe_network/network = connected_port.return_network(src) + if(network) + network.gases -= air_contents + + anchored = 0 + + connected_port.connected_device = null + connected_port = null + + return 1 + +/obj/machinery/portable_atmospherics/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + var/obj/icon = src + if ((istype(W, /obj/item/weapon/tank) && !( src.destroyed ))) + if (src.holding) + return + var/obj/item/weapon/tank/T = W + user.drop_item() + T.loc = src + src.holding = T + update_icon() + return + + else if (istype(W, /obj/item/weapon/wrench)) + if(connected_port) + disconnect() + user << "\blue You disconnect [name] from the port." + return + else + var/obj/machinery/atmospherics/portables_connector/possible_port = locate(/obj/machinery/atmospherics/portables_connector/) in loc + if(possible_port) + if(connect(possible_port)) + user << "\blue You connect [name] to the port." + return + else + user << "\blue [name] failed to connect to the port." + return + else + user << "\blue Nothing happens." + return + + else if ((istype(W, /obj/item/device/analyzer) || (istype(W, /obj/item/device/pda))) && get_dist(user, src) <= 1) + for (var/mob/O in viewers(user, null)) + O << "\red [user] has used [W] on \icon[icon]" + + var/pressure = air_contents.return_pressure() + var/total_moles = air_contents.total_moles() + + user << "\blue Results of analysis of \icon[icon]" + if (total_moles>0) + var/o2_concentration = air_contents.oxygen/total_moles + var/n2_concentration = air_contents.nitrogen/total_moles + var/co2_concentration = air_contents.carbon_dioxide/total_moles + var/plasma_concentration = air_contents.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(air_contents.temperature-T0C)]°C" + else + user << "\blue Tank is empty!" + return + + return \ No newline at end of file diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm new file mode 100644 index 0000000000000..c0f14b1a35825 --- /dev/null +++ b/code/game/machinery/atmoalter/pump.dm @@ -0,0 +1,135 @@ +/obj/machinery/portable_atmospherics/pump + name = "Portable Air Pump" + + icon = 'atmos.dmi' + icon_state = "psiphon:0" + density = 1 + + var/on = 0 + var/direction_out = 0 //0 = siphoning, 1 = releasing + var/target_pressure = 100 + + volume = 750 + +/obj/machinery/portable_atmospherics/pump/update_icon() + src.overlays = 0 + + if(on) + icon_state = "psiphon:1" + else + icon_state = "psiphon:0" + + return + +/obj/machinery/portable_atmospherics/pump/process() + ..() + + var/datum/gas_mixture/environment + if(holding) + environment = holding.air_contents + else + environment = loc.return_air() + + + if(on) + if(direction_out) + var/pressure_delta = target_pressure - environment.return_pressure() + //Can not have a pressure delta that would cause environment pressure > tank pressure + + var/transfer_moles = 0 + if(air_contents.temperature > 0) + transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) + + if(holding) + environment.merge(removed) + else + loc.assume_air(removed) + else + var/pressure_delta = target_pressure - air_contents.return_pressure() + //Can not have a pressure delta that would cause environment pressure > tank pressure + + var/transfer_moles = 0 + if(environment.temperature > 0) + transfer_moles = pressure_delta*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + var/datum/gas_mixture/removed + if(holding) + removed = environment.remove(transfer_moles) + else + removed = loc.remove_air(transfer_moles) + + air_contents.merge(removed) + + src.updateDialog() + src.update_icon() + return + +/obj/machinery/portable_atmospherics/pump/return_air() + return air_contents + +/obj/machinery/portable_atmospherics/pump/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/pump/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/pump/attack_hand(var/mob/user as mob) + + user.machine = src + var/holding_text + + if(holding) + holding_text = {"
      Tank Pressure: [holding.air_contents.return_pressure()] KPa
      +Remove Tank
      +"} + var/output_text = {"[name]
      +Pressure: [air_contents.return_pressure()] KPa
      +Port Status: [(connected_port)?("Connected"):("Disconnected")] +[holding_text] +
      +Power Switch: [on?("On"):("Off")]
      +Pump Direction: [direction_out?("Out"):("In")]
      +Target Pressure: - - [target_pressure] + +
      +
      +Close
      +"} + + user << browse(output_text, "window=pump;size=600x300") + onclose(user, "pump") + + return + +/obj/machinery/portable_atmospherics/pump/Topic(href, href_list) + ..() + if (usr.stat || usr.restrained()) + return + + if (((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) + usr.machine = src + + if(href_list["power"]) + on = !on + + if(href_list["direction"]) + direction_out = !direction_out + + if (href_list["remove_tank"]) + if(holding) + holding.loc = loc + holding = null + + if (href_list["pressure_adj"]) + var/diff = text2num(href_list["pressure_adj"]) + target_pressure = min(10*ONE_ATMOSPHERE, max(0, target_pressure+diff)) + + src.updateUsrDialog() + src.add_fingerprint(usr) + update_icon() + else + usr << browse(null, "window=pump") + return + return \ No newline at end of file diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm new file mode 100644 index 0000000000000..7012473d256b3 --- /dev/null +++ b/code/game/machinery/atmoalter/scrubber.dm @@ -0,0 +1,131 @@ +/obj/machinery/portable_atmospherics/scrubber + name = "Portable Air Scrubber" + + icon = 'atmos.dmi' + icon_state = "pscrubber:0" + density = 1 + + var/on = 0 + var/volume_rate = 800 + + volume = 750 + +/obj/machinery/portable_atmospherics/scrubber/update_icon() + src.overlays = 0 + + if(on) + icon_state = "pscrubber:1" + else + icon_state = "pscrubber:0" + + return + +/obj/machinery/portable_atmospherics/scrubber/process() + ..() + + var/datum/gas_mixture/environment + if(holding) + environment = holding.air_contents + else + environment = loc.return_air() + + + if(on) + var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles() + + //Take a gas sample + var/datum/gas_mixture/removed + if(holding) + removed = environment.remove(transfer_moles) + else + removed = loc.remove_air(transfer_moles) + + //Filter it + var/datum/gas_mixture/filtered_out = new + filtered_out.temperature = removed.temperature + + + filtered_out.toxins = removed.toxins + removed.toxins = 0 + + filtered_out.carbon_dioxide = removed.carbon_dioxide + removed.carbon_dioxide = 0 + + if(removed.trace_gases.len>0) + for(var/datum/gas/trace_gas in removed.trace_gases) + if(istype(trace_gas, /datum/gas/oxygen_agent_b)) + removed.trace_gases -= trace_gas + filtered_out.trace_gases += trace_gas + + //Remix the resulting gases + air_contents.merge(filtered_out) + + if(holding) + environment.merge(removed) + else + loc.assume_air(removed) + + src.updateDialog() + src.update_icon() + return + +/obj/machinery/portable_atmospherics/scrubber/return_air() + return air_contents + +/obj/machinery/portable_atmospherics/scrubber/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/scrubber/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/portable_atmospherics/scrubber/attack_hand(var/mob/user as mob) + + user.machine = src + var/holding_text + + if(holding) + holding_text = {"
      Tank Pressure: [holding.air_contents.return_pressure()] KPa
      +Remove Tank
      +"} + var/output_text = {"[name]
      +Pressure: [air_contents.return_pressure()] KPa
      +Port Status: [(connected_port)?("Connected"):("Disconnected")] +[holding_text] +
      +Power Switch: [on?("On"):("Off")]
      +Target Pressure: - - [volume_rate] + +
      +
      +Close
      +"} + + user << browse(output_text, "window=scrubber;size=600x300") + onclose(user, "scrubber") + return + +/obj/machinery/portable_atmospherics/scrubber/Topic(href, href_list) + ..() + if (usr.stat || usr.restrained()) + return + + if (((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) + usr.machine = src + + if(href_list["power"]) + on = !on + + if (href_list["remove_tank"]) + if(holding) + holding.loc = loc + holding = null + + if (href_list["volume_adj"]) + var/diff = text2num(href_list["volume_adj"]) + volume_rate = min(10*ONE_ATMOSPHERE, max(0, volume_rate+diff)) + + src.updateUsrDialog() + src.add_fingerprint(usr) + update_icon() + else + usr << browse(null, "window=scrubber") + return + return \ No newline at end of file diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm new file mode 100644 index 0000000000000..7ae01b3150cde --- /dev/null +++ b/code/game/machinery/autolathe.dm @@ -0,0 +1,214 @@ +/obj/machinery/autolathe/attackby(var/obj/item/weapon/O as obj, var/mob/user as mob) + if (istype(O, /obj/item/weapon/screwdriver)) + if (!opened) + src.opened = 1 + src.icon_state = "autolathef" + else + src.opened = 0 + src.icon_state = "autolathe" + return + if (opened) + user << "You can't load the autolathe while it's opened." + return +/* + if (istype(O, /obj/item/weapon/grab) && src.hacked) + var/obj/item/weapon/grab/G = O + if (prob(25) && G.affecting) + G.affecting.gib() + m_amount += 50000 + return +*/ + if (istype(O, /obj/item/weapon/sheet/metal)) + if (src.m_amount < 150000.0) + spawn(16) { + flick("autolathe_c",src) + src.m_amount += O:height * O:width * O:length * 100000.0 + O:amount-- + if (O:amount < 1) + del(O) + } + else + user << "The autolathe is full. Please remove metal from the autolathe in order to insert more." + else if (istype(O, /obj/item/weapon/sheet/glass) || istype(O, /obj/item/weapon/sheet/rglass)) + if (src.g_amount < 75000.0) + spawn(16) { + flick("autolathe_c",src) + src.g_amount += O:height * O:width * O:length * 100000.0 + O:amount-- + if (O:amount < 1) + del(O) + } + else + user << "The autolathe is full. Please remove glass from the autolathe in order to insert more." + + else if (O.g_amt || O.m_amt) + spawn(16) { + flick("autolathe_c",src) + if(O.g_amt) // Added null checks to avoid runtime errors when an item doesn't have an expected variable -- TLE + src.g_amount += O.g_amt + if(O.m_amt) + src.m_amount += O.m_amt + del O + } + else + user << "This object does not contain significant amounts of metal or glass, or cannot be accepted by the autolathe due to size or hazardous materials." + +/obj/machinery/autolathe/attack_paw(user as mob) + return src.attack_hand(user) + +/obj/machinery/autolathe/attack_hand(user as mob) + var/dat + if(..()) + return + if (src.shocked) + src.shock(user) + if (src.opened) + dat += "Autolathe Wires:
      " + var/wire + for(wire in src.wires) + dat += text("[wire] Wire: [src.wires[wire] ? "Mend" : "Cut"] Pulse
      ") + + dat += text("The red light is [src.disabled ? "off" : "on"].
      ") + dat += text("The green light is [src.shocked ? "off" : "on"].
      ") + dat += text("The blue light is [src.hacked ? "off" : "on"].
      ") + user << browse("Autolathe Hacking[dat]","window=autolathe_hack") + onclose(user, "autolathe_hack") + return + if (src.disabled) + user << "You press the button, but nothing happens." + return + if (src.temp) + dat = text("[]

      Clear Screen", src.temp, src) + else + dat = text("Metal Amount: [src.m_amount] cm3 (MAX: 150,000)
      \nGlass Amount: [src.g_amount] cm3 (MAX: 75,000)
      ") + var/list/objs = list() + objs += src.L + if (src.hacked) + objs += src.LL + for(var/obj/t in objs) + dat += text("[t.name] ([t.m_amt] cc metal/[t.g_amt] cc glass)
      ") + user << browse("Autolathe Control Panel[dat]", "window=autolathe_regular") + onclose(user, "autolathe_regular") + return + +/obj/machinery/autolathe/Topic(href, href_list) + if(..()) + return + usr.machine = src + src.add_fingerprint(usr) + if(href_list["make"]) + var/obj/template = locate(href_list["make"]) + if(src.m_amount >= template.m_amt && src.g_amount >= template.g_amt) + spawn(16) + flick("autolathe_c",src) + spawn(16) + flick("autolathe_o",src) + spawn(16) + src.m_amount -= template.m_amt + src.g_amount -= template.g_amt + if(src.m_amount < 0) + src.m_amount = 0 + if(src.g_amount < 0) + src.g_amount = 0 + new template.type(usr.loc) + if(href_list["act"]) + if(href_list["act"] == "pulse") + if (!istype(usr.equipped(), /obj/item/device/multitool)) + usr << "You need a multitool!" + else + if(src.wires[href_list["wire"]]) + usr << "You can't pulse a cut wire." + else + if(src.hack_wire == href_list["wire"]) + src.hacked = !src.hacked + spawn(100) src.hacked = !src.hacked + if(src.disable_wire == href_list["wire"]) + src.disabled = !src.disabled + src.shock(usr) + spawn(100) src.disabled = !src.disabled + if(src.shock_wire == href_list["wire"]) + src.shocked = !src.shocked + src.shock(usr) + spawn(100) src.shocked = !src.shocked + if(href_list["act"] == "wire") + if (!istype(usr.equipped(), /obj/item/weapon/wirecutters)) + usr << "You need wirecutters!" + else + if(src.hack_wire == href_list["wire"]) + src.hacked = !src.hacked + if(src.disable_wire == href_list["wire"]) + src.disabled = !src.disabled + src.shock(usr) + if(src.shock_wire == href_list["wire"]) + src.shocked = !src.shocked + src.shock(usr) + + if (href_list["temp"]) + src.temp = null + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + src.updateUsrDialog() + return + +/obj/machinery/autolathe/New() + ..() + // screwdriver removed + src.L += new /obj/item/weapon/wirecutters(src) + src.L += new /obj/item/weapon/wrench(src) + src.L += new /obj/item/weapon/crowbar(src) + src.L += new /obj/item/weapon/weldingtool(src) + src.L += new /obj/item/clothing/head/helmet/welding(src) + src.L += new /obj/item/device/multitool(src) + src.L += new /obj/item/device/flashlight(src) + src.L += new /obj/item/weapon/extinguisher(src) + src.L += new /obj/item/weapon/sheet/metal(src) + src.L += new /obj/item/weapon/sheet/glass(src) + src.L += new /obj/item/weapon/sheet/r_metal(src) + src.L += new /obj/item/weapon/sheet/rglass(src) + src.L += new /obj/item/weapon/rods(src) + src.L += new /obj/item/weapon/rcd_ammo(src) + src.L += new /obj/item/weapon/scalpel(src) + src.L += new /obj/item/weapon/circular_saw(src) + src.L += new /obj/item/device/t_scanner(src) + src.LL += new /obj/item/weapon/flamethrower(src) + src.LL += new /obj/item/device/igniter(src) + src.LL += new /obj/item/device/timer(src) + src.LL += new /obj/item/weapon/rcd(src) + src.LL += new /obj/item/device/infra(src) + src.LL += new /obj/item/device/infra_sensor(src) + src.LL += new /obj/item/weapon/handcuffs(src) + src.LL += new /obj/item/weapon/ammo/a357(src) + src.LL += new /obj/item/weapon/ammo/a38(src) + src.wires["Light Red"] = 0 + src.wires["Dark Red"] = 0 + src.wires["Blue"] = 0 + src.wires["Green"] = 0 + src.wires["Yellow"] = 0 + src.wires["Black"] = 0 + src.wires["White"] = 0 + src.wires["Gray"] = 0 + src.wires["Orange"] = 0 + src.wires["Pink"] = 0 + var/list/w = list("Light Red","Dark Red","Blue","Green","Yellow","Black","White","Gray","Orange","Pink") + src.hack_wire = pick(w) + w -= src.hack_wire + src.shock_wire = pick(w) + w -= src.shock_wire + src.disable_wire = pick(w) + w -= src.disable_wire + +/obj/machinery/autolathe/proc/get_connection() + var/turf/T = src.loc + if(!istype(T, /turf/simulated/floor)) + return + + for(var/obj/cable/C in T) + if(C.d1 == 0) + return C.netnum + + return 0 + +/obj/machinery/autolathe/proc/shock(M as mob) + return src.electrocute(M, 50, get_connection()) \ No newline at end of file diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm new file mode 100644 index 0000000000000..c2da21c167071 --- /dev/null +++ b/code/game/machinery/bots/bots.dm @@ -0,0 +1,75 @@ +// AI (i.e. game AI, not the AI player) controlled bots + +/obj/machinery/bot + icon = 'aibots.dmi' + layer = MOB_LAYER + var/obj/item/weapon/card/id/botcard // the ID card that the bot "holds" + + + +/******************************************************************/ +// Navigation procs +// Used for A-star pathfinding + + +// Returns the surrounding cardinal turfs with open links +// Including through doors openable with the ID +/turf/proc/CardinalTurfsWithAccess(var/obj/item/weapon/card/id/ID) + var/L[] = new() + + // for(var/turf/simulated/t in oview(src,1)) + + for(var/d in cardinal) + var/turf/simulated/T = get_step(src, d) + if(istype(T) && !T.density) + if(!LinkBlockedWithAccess(src, T, ID)) + L.Add(T) + return L + + +// Returns true if a link between A and B is blocked +// Movement through doors allowed if ID has access +/proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/weapon/card/id/ID) + + if(A == null || B == null) return 1 + var/adir = get_dir(A,B) + var/rdir = get_dir(B,A) + if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal + var/iStep = get_step(A,adir&(NORTH|SOUTH)) + if(!LinkBlockedWithAccess(A,iStep, ID) && !LinkBlockedWithAccess(iStep,B,ID)) + return 0 + + var/pStep = get_step(A,adir&(EAST|WEST)) + if(!LinkBlockedWithAccess(A,pStep,ID) && !LinkBlockedWithAccess(pStep,B,ID)) + return 0 + return 1 + + if(DirBlockedWithAccess(A,adir, ID)) + return 1 + + if(DirBlockedWithAccess(B,rdir, ID)) + return 1 + + for(var/obj/O in B) + if(O.density && !istype(O, /obj/machinery/door) && !(O.flags & ON_BORDER)) + return 1 + + return 0 + +// Returns true if direction is blocked from loc +// Checks doors against access with given ID +/proc/DirBlockedWithAccess(turf/loc,var/dir,var/obj/item/weapon/card/id/ID) + for(var/obj/window/D in loc) + if(!D.density) continue + if(D.dir == SOUTHWEST) return 1 + if(D.dir == dir) return 1 + + for(var/obj/machinery/door/D in loc) + if(!D.density) continue + if(istype(D, /obj/machinery/door/window)) + if( dir & D.dir ) return !D.check_access(ID) + + //if((dir & SOUTH) && (D.dir & (EAST|WEST))) return !D.check_access(ID) + //if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID) + else return !D.check_access(ID) // it's a real, air blocking door + return 0 diff --git a/code/game/machinery/bots/cleanbot.dm b/code/game/machinery/bots/cleanbot.dm new file mode 100644 index 0000000000000..6bf847b607239 --- /dev/null +++ b/code/game/machinery/bots/cleanbot.dm @@ -0,0 +1,223 @@ +//Cleanbot assembly +/obj/item/weapon/bucket_sensor + desc = "It's a bucket. With a sensor attached." + name = "proxy bucket" + icon = 'aibots.dmi' + icon_state = "bucket_proxy" + force = 3.0 + throwforce = 10.0 + throw_speed = 2 + throw_range = 5 + w_class = 3.0 + flags = TABLEPASS + + +//Cleanbot +/obj/machinery/bot/cleanbot + name = "Cleanbot" + desc = "A little cleaning robot, he looks so excited!" + icon = 'aibots.dmi' + icon_state = "cleanbot0" + layer = 5.0 + density = 0 + anchored = 0 + //weight = 1.0E7 + var/on = 1 + var/cleaning = 0 + var/locked = 1 + var/screwloose = 0 + var/oddbutton = 0 + var/blood = 1 + var/panelopen = 0 + var/list/target_types = list() + var/obj/decal/cleanable/target + var/obj/decal/cleanable/oldtarget + var/oldloc = null + req_access = list(access_janitor) + var/path[] = new() + + +/obj/machinery/bot/cleanbot/New() + ..() + src.get_targets() + src.icon_state = "cleanbot[src.on]" + + +/obj/machinery/bot/cleanbot/attack_hand(user as mob) + var/dat + dat += text({" +Automatic Station Cleaner v1.0

      +Status: []
      +Behaviour controls are [src.locked ? "locked" : "unlocked"]""}, +text("
      [src.on ? "On" : "Off"]")) + if(!src.locked) + dat += text({"
      +Cleans Blood: []
      "}, +text("[src.blood ? "Yes" : "No"]")) + if(src.panelopen && !src.locked) + dat += text({" +Odd looking screw twiddled: []
      +Weird button pressed: []"}, +text("[src.screwloose ? "Yes" : "No"]"), +text("[src.oddbutton ? "Yes" : "No"]")) + + user << browse("Cleaner v1.0 controls[dat]", "window=autocleaner") + onclose(user, "autocleaner") + return + +/obj/machinery/bot/cleanbot/Topic(href, href_list) + if(..()) + return + usr.machine = src + src.add_fingerprint(usr) + switch(href_list["operation"]) + if("start") + src.on = !src.on + src.target = null + src.oldtarget = null + src.oldloc = null + src.icon_state = "cleanbot[src.on]" + src.path = new() + src.updateUsrDialog() + if("blood") + src.blood =!src.blood + src.get_targets() + src.updateUsrDialog() + if("screw") + src.screwloose = !src.screwloose + usr << "You twiddle the screw." + src.updateUsrDialog() + if("oddbutton") + src.oddbutton = !src.oddbutton + usr << "You press the weird button." + src.updateUsrDialog() + +/obj/machinery/bot/cleanbot/attack_ai() + src.on = !src.on + src.target = null + src.oldtarget = null + src.oldloc = null + src.icon_state = "cleanbot[src.on]" + src.path = new() + +/obj/machinery/bot/cleanbot/attackby(obj/item/weapon/W, mob/user as mob) + if (istype(W, /obj/item/weapon/card/id)) + if(src.allowed(usr)) + src.locked = !src.locked + user << "You [ src.locked ? "lock" : "unlock"] the [src] behaviour controls." + else + user << "\red This [src] doesn't seem to accept your authority." + if (istype(W, /obj/item/weapon/screwdriver)) + if(!src.locked) + src.panelopen = !src.panelopen + user << "You [ src.panelopen ? "open" : "close"] the hidden panel on [src]." + /*if (istype(W, /obj/item/weapon/card/cryptographic_sequencer)) + user << "The [src] buzzes and beeps." + src.oddbutton = 1 + src.screwloose = 1 + src.panelopen = 0 + src.locked = 1*/ + +/obj/machinery/bot/cleanbot/process() + set background = 1 + + if(!src.on) + return + if(src.cleaning) + return + var/list/cleanbottargets = list() + if(!src.target || src.target == null) + for(var/obj/machinery/bot/cleanbot/bot in world) + if(bot != src) + cleanbottargets += bot.target + + if(prob(5) && !src.screwloose && !src.oddbutton) + for(var/mob/O in viewers(src, null)) + O.show_message(text("[src] makes an excited beeping booping sound!"), 1) + + if(src.screwloose && prob(5)) + for(var/mob/O in viewers(src, null)) + O.show_message(text("[src] leaks a drop of water. How strange."), 1) + var/turf/U = src.loc + U:wet = 1 + //U.overlays += /obj/effects/wet_floor + spawn(800) + U:wet = 0 + U.overlays = null + if(src.oddbutton && prob(5)) + for(var/mob/O in viewers(src, null)) + O.show_message(text("Something flies out of [src]. He seems to be acting oddly."), 1) + var/obj/decal/cleanable/blood/gibs/gib = new /obj/decal/cleanable/blood/gibs(src.loc) + //gib.streak(list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)) + src.oldtarget = gib + if(!src.target || src.target == null) + for (var/obj/decal/cleanable/D in view(7,src)) + for(var/T in src.target_types) + if(!(D in cleanbottargets) && (D.type == T || D.parent_type == T) && D != src.oldtarget) + src.oldtarget = D + src.target = D + return + + if(!src.target || src.target == null) + if(src.loc != src.oldloc) + src.oldtarget = null + return + + if(src.target && (src.target != null) && src.path.len == 0) + spawn(0) + src.path = AStar(src.loc, src.target.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, 0, 30) + src.path = reverselist(src.path) + if(src.path.len == 0) + src.oldtarget = src.target + src.target = null + return + if(src.path.len > 0 && src.target && (src.target != null)) + step_to(src, src.path[1]) + src.path -= src.path[1] + else if(src.path.len == 1) + step_to(src, target) + + if(src.target && (src.target != null)) + if(src.loc == src.target.loc) + clean(src.target) + src.path = new() + src.target = null + return + + src.oldloc = src.loc + +/obj/machinery/bot/cleanbot/proc/get_targets() + src.target_types = new/list() + if(src.blood) + target_types += /obj/decal/cleanable/blood/ + target_types += /obj/decal/cleanable/blood/gibs/ + +/obj/machinery/bot/cleanbot/proc/clean(var/obj/decal/cleanable/target) + src.anchored = 1 + src.icon_state = "cleanbot-c" + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [src] begins to clean up the [target]"), 1) + src.cleaning = 1 + spawn(50) + src.cleaning = 0 + del(target) + src.icon_state = "cleanbot[src.on]" + src.anchored = 0 + src.target = null + +/obj/item/weapon/bucket_sensor/attackby(var/obj/item/robot_parts/P, mob/user as mob) + if(!istype(P, /obj/item/robot_parts/l_arm) && !istype(P, /obj/item/robot_parts/r_arm)) + return + var/obj/machinery/bot/cleanbot/A = new /obj/machinery/bot/cleanbot + if(user.r_hand == src || user.l_hand == src) + A.loc = user.loc + else + A.loc = src.loc + user << "You add the robot arm to the bucket and sensor assembly! Beep boop!" + del(P) + del(src) + + + + + diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm new file mode 100644 index 0000000000000..aeb6798ab36d3 --- /dev/null +++ b/code/game/machinery/bots/floorbot.dm @@ -0,0 +1,385 @@ +//Floorbot assemblies +/obj/item/weapon/toolbox_tiles + desc = "It's a toolbox with tiles sticking out the top" + name = "tiles and toolbox" + icon = 'aibots.dmi' + icon_state = "toolbox_tiles" + force = 3.0 + throwforce = 10.0 + throw_speed = 2 + throw_range = 5 + w_class = 3.0 + flags = TABLEPASS + +/obj/item/weapon/toolbox_tiles_sensor + desc = "It's a toolbox with tiles sticking out the top and a sensor attached" + name = "tiles, toolbox and sensor arrangement" + icon = 'aibots.dmi' + icon_state = "toolbox_tiles_sensor" + force = 3.0 + throwforce = 10.0 + throw_speed = 2 + throw_range = 5 + w_class = 3.0 + flags = TABLEPASS + +//Floorbot +/obj/machinery/bot/floorbot + name = "Floorbot" + desc = "A little floor repairing robot, he looks so excited!" + icon = 'aibots.dmi' + icon_state = "floorbot0" + layer = 5.0 + density = 0 + anchored = 0 + //weight = 1.0E7 + var/amount = 10 + var/on = 1 + var/repairing = 0 + var/improvefloors = 0 + var/eattiles = 0 + var/maketiles = 0 + var/locked = 1 + var/turf/target + var/turf/oldtarget + var/oldloc = null + req_access = list(access_atmospherics) + var/path[] = new() + var/targetdirection + + +/obj/machinery/bot/floorbot/New() + ..() + src.updateicon() + +/obj/machinery/bot/floorbot/attack_hand(user as mob) + var/dat + dat += "Automatic Station Floor Repairer v1.0

      " + dat += "Status: [src.on ? "On" : "Off"]
      " + dat += "Tiles left: [src.amount]
      " + dat += "Behvaiour controls are [src.locked ? "locked" : "unlocked"]
      " + if(!src.locked) + dat += "Improves floors: [src.improvefloors ? "Yes" : "No"]
      " + dat += "Finds tiles: [src.eattiles ? "Yes" : "No"]
      " + dat += "Make singles pieces of metal into tiles when empty: [src.maketiles ? "Yes" : "No"]
      " + var/bmode + if (src.targetdirection) + bmode = dir2text(src.targetdirection) + else + bmode = "Disabled" + dat += "

      Bridge Mode : [bmode]
      " + + user << browse("Repairbot v1.0 controls[dat]", "window=autorepair") + onclose(user, "autorepair") + return + + +/obj/machinery/bot/floorbot/attackby(var/obj/item/weapon/W , mob/user as mob) + if(istype(W, /obj/item/weapon/tile)) + var/obj/item/weapon/tile/T = W + if(src.amount >= 50) + return + var/loaded = 0 + if(src.amount + T.amount > 50) + var/i = 50 - src.amount + src.amount += i + T.amount -= i + loaded = i + else + src.amount += T.amount + loaded = T.amount + del(T) + user << "\red You load [loaded] tiles into the floorbot. He now contains [src.amount] tiles!" + src.updateicon() + if(istype(W, /obj/item/weapon/card/id)) + if(src.allowed(usr)) + src.locked = !src.locked + user << "You [src.locked ? "lock" : "unlock"] the [src] behaviour controls." + else + user << "The [src] doesn't seem to accept your authority." + src.updateUsrDialog() + + +/obj/machinery/bot/floorbot/Topic(href, href_list) + if(..()) + return + usr.machine = src + src.add_fingerprint(usr) + switch(href_list["operation"]) + if("start") + src.on = !src.on + src.target = null + src.oldtarget = null + src.oldloc = null + src.updateicon() + src.path = new() + src.updateUsrDialog() + if("improve") + src.improvefloors = !src.improvefloors + src.updateUsrDialog() + if("tiles") + src.eattiles = !src.eattiles + src.updateUsrDialog() + if("make") + src.maketiles = !src.maketiles + src.updateUsrDialog() + if("bridgemode") + switch(src.targetdirection) + if(null) + targetdirection = 1 + if(1) + targetdirection = 2 + if(2) + targetdirection = 4 + if(4) + targetdirection = 8 + if(8) + targetdirection = null + else + targetdirection = null + src.updateUsrDialog() + + +/obj/machinery/bot/floorbot/attack_ai() + src.on = !src.on + src.target = null + src.oldtarget = null + src.oldloc = null + src.updateicon() + src.path = new() + +/obj/machinery/bot/floorbot/process() + set background = 1 + + if(!src.on) + return + if(src.repairing) + return + var/list/floorbottargets = list() + if(!src.target || src.target == null) + for(var/obj/machinery/bot/floorbot/bot in world) + if(bot != src) + floorbottargets += bot.target + if(src.amount <= 0 && ((src.target == null) || !src.target)) + if(src.eattiles) + for(var/obj/item/weapon/tile/T in view(7, src)) + if(T != src.oldtarget && !(target in floorbottargets)) + src.oldtarget = T + src.target = T + break + if(src.target == null || !src.target) + if(src.maketiles) + if(src.target == null || !src.target) + for(var/obj/item/weapon/sheet/metal/M in view(7, src)) + if(!(M in floorbottargets) && M != src.oldtarget && M.amount == 1 && !(istype(M.loc, /turf/simulated/wall))) + src.oldtarget = M + src.target = M + break + else + return + if(prob(5)) + for(var/mob/O in viewers(src, null)) + O.show_message(text("[src] makes an excited booping beeping sound!"), 1) + + if(!src.target || src.target == null) + if(targetdirection != null) + /* + for (var/turf/space/D in view(7,src)) + if(!(D in floorbottargets) && D != src.oldtarget) // Added for bridging mode -- TLE + if(get_dir(src, D) == targetdirection) + src.oldtarget = D + src.target = D + break + */ + var/turf/T = get_step(src, targetdirection) + if(istype(T, /turf/space)) + src.oldtarget = T + src.target = T + if(!src.target || src.target == null) + for (var/turf/space/D in view(7,src)) + if(!(D in floorbottargets) && D != src.oldtarget && (D.loc.name != "Space")) + src.oldtarget = D + src.target = D + break + if((!src.target || src.target == null ) && src.improvefloors) + for (var/turf/simulated/floor/F in view(7,src)) + if(!(F in floorbottargets) && F != src.oldtarget && F.icon_state == "Floor1" && !(istype(F, /turf/simulated/floor/plating))) + src.oldtarget = F + src.target = F + break + if((!src.target || src.target == null) && src.eattiles) + for(var/obj/item/weapon/tile/T in view(7, src)) + if(!(T in floorbottargets) && T != src.oldtarget) + src.oldtarget = T + src.target = T + break + + if(!src.target || src.target == null) + if(src.loc != src.oldloc) + src.oldtarget = null + return + + if(src.target && (src.target != null) && src.path.len == 0) + spawn(0) + if(!istype(src.target, /turf/)) + src.path = AStar(src.loc, src.target.loc, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30) + else + src.path = AStar(src.loc, src.target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30) + src.path = reverselist(src.path) + if(src.path.len == 0) + src.oldtarget = src.target + src.target = null + return + if(src.path.len > 0 && src.target && (src.target != null)) + step_to(src, src.path[1]) + src.path -= src.path[1] + else if(src.path.len == 1) + step_to(src, target) + src.path = new() + + if(src.loc == src.target || src.loc == src.target.loc) + if(istype(src.target, /obj/item/weapon/tile)) + src.eattile(src.target) + else if(istype(src.target, /obj/item/weapon/sheet/metal)) + src.maketile(src.target) + else if(istype(src.target, /turf/)) + repair(src.target) + src.path = new() + return + + src.oldloc = src.loc + + +/obj/machinery/bot/floorbot/proc/repair(var/turf/target) + if(istype(target, /turf/space/)) + if(target.loc.name == "Space") + return + else if(!istype(target, /turf/simulated/floor)) + return + if(src.amount <= 0) + return + src.anchored = 1 + src.icon_state = "floorbot-c" + if(istype(target, /turf/space/)) + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [src] begins to repair the hole"), 1) + var/obj/item/weapon/tile/T = new /obj/item/weapon/tile + src.repairing = 1 + spawn(50) + T.build(src.loc) + src.repairing = 0 + src.amount -= 1 + src.updateicon() + src.anchored = 0 + src.target = null + else + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [src] begins to improve the floor."), 1) + src.repairing = 1 + spawn(50) + src.loc.icon_state = "floor" + src.repairing = 0 + src.amount -= 1 + src.updateicon() + src.anchored = 0 + src.target = null + +/obj/machinery/bot/floorbot/proc/eattile(var/obj/item/weapon/tile/T) + if(!istype(T, /obj/item/weapon/tile)) + return + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [src] begins to collect tiles."), 1) + src.repairing = 1 + spawn(20) + if(isnull(T)) + src.target = null + src.repairing = 0 + return + if(src.amount + T.amount > 50) + var/i = 50 - src.amount + src.amount += i + T.amount -= i + else + src.amount += T.amount + del(T) + src.updateicon() + src.target = null + src.repairing = 0 + +/obj/machinery/bot/floorbot/proc/maketile(var/obj/item/weapon/sheet/metal/M) + if(!istype(M, /obj/item/weapon/sheet/metal)) + return + if(M.amount > 1) + return + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [src] begins to create tiles."), 1) + src.repairing = 1 + spawn(20) + if(isnull(M)) + src.target = null + src.repairing = 0 + return + var/obj/item/weapon/tile/T = new /obj/item/weapon/tile + T.amount = 4 + T.loc = M.loc + del(M) + src.target = null + src.repairing = 0 + +/obj/machinery/bot/floorbot/proc/updateicon() + if(src.amount > 0) + src.icon_state = "floorbot[src.on]" + else + src.icon_state = "floorbot[src.on]e" + + + +/obj/item/weapon/storage/toolbox/mechanical/attackby(var/obj/item/weapon/tile/T, mob/user as mob) + if(!istype(T, /obj/item/weapon/tile)) + ..() + return + if(src.contents.len >= 1) + user << "They wont fit in as there is already stuff inside!" + return + if (user.s_active) + user.s_active.close(user) + var/obj/item/weapon/toolbox_tiles/B = new /obj/item/weapon/toolbox_tiles + B.loc = user + if (user.r_hand == T) + user.u_equip(T) + user.r_hand = B + else + user.u_equip(T) + user.l_hand = B + B.layer = 20 + user << "You add the tiles into the empty toolbox. They stick oddly out the top." + del(T) + del(src) + +/obj/item/weapon/toolbox_tiles/attackby(var/obj/item/device/prox_sensor/D, mob/user as mob) + if(!istype(D, /obj/item/device/prox_sensor)) + return + var/obj/item/weapon/toolbox_tiles_sensor/B = new /obj/item/weapon/toolbox_tiles_sensor + B.loc = user + if (user.r_hand == D) + user.u_equip(D) + user.r_hand = B + else + user.u_equip(D) + user.l_hand = B + B.layer = 20 + user << "You add the sensor to the toolbox and tiles!" + del(D) + del(src) + +/obj/item/weapon/toolbox_tiles_sensor/attackby(var/obj/item/robot_parts/P, mob/user as mob) + if(!istype(P, /obj/item/robot_parts/l_arm) && !istype(P, /obj/item/robot_parts/r_arm)) + return + var/obj/machinery/bot/floorbot/A = new /obj/machinery/bot/floorbot + if(user.r_hand == src || user.l_hand == src) + A.loc = user.loc + else + A.loc = src.loc + user << "You add the robot arm to the odd looking toolbox assembly! Boop beep!" + del(P) + del(src) diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm new file mode 100644 index 0000000000000..a301988d426fd --- /dev/null +++ b/code/game/machinery/bots/medbot.dm @@ -0,0 +1,632 @@ +//MEDBOT +//MEDBOT PATHFINDING +//MEDBOT ASSEMBLY + + +/obj/machinery/bot/medbot + name = "Medibot" + desc = "A little medical robot. He looks somewhat underwhelmed." + icon = 'aibots.dmi' + icon_state = "medibot0" + layer = 5.0 + density = 1 + anchored = 0 + req_access =list(access_medical) + var/on = 1 + var/health = 20 + var/stunned = 0 //It can be stunned by tasers. Delicate circuits. + var/locked = 1 + var/emagged = 0 + var/obj/machinery/camera/cam = null + var/list/botcard_access = list(access_medical, access_morgue, access_medlab, access_robotics) + var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents. + var/skin = null //Set to "tox" or "ointment" for the other two firstaid kits. + var/frustration = 0 + var/path[] = new() + var/mob/living/carbon/patient = null + var/mob/living/carbon/oldpatient = null + var/oldloc = null + var/last_found = 0 + var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages + var/currently_healing = 0 + var/injection_amount = 15 //How much reagent do we inject at a time? + var/heal_threshold = 15 //Start healing when they have this much damage in a category + var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents. + //Setting which reagents to use to treat what by default. By id. + var/treatment_brute = "bicaridine" + var/treatment_oxy = "dexalin" + var/treatment_fire = "kelotane" + var/treatment_tox = "anti_toxin" + var/treatment_virus = "spaceacillin" + +/obj/machinery/bot/medbot/mysterious + name = "Mysterious Medibot" + desc = "International Medibot of mystery." + skin = "bezerk" + treatment_oxy = "dexalinp" + +/obj/item/weapon/firstaid_arm_assembly + name = "first aid/robot arm assembly" + desc = "A first aid kit with a robot arm permanently grafted to it." + icon = 'aibots.dmi' + icon_state = "firstaid_arm" + var/build_step = 0 + var/created_name = "Medibot" //To preserve the name if it's a unique medbot I guess + var/skin = null //Same as medbot, set to tox or ointment for the respective kits. + w_class = 3.0 + + New() + ..() + spawn(5) + if(src.skin) + src.overlays += image('aibots.dmi', "kit_skin_[src.skin]") + + +/obj/machinery/bot/medbot/New() + ..() + src.icon_state = "medibot[src.on]" + + spawn(4) + if(src.skin) + src.overlays += image('aibots.dmi', "medskin_[src.skin]") + + src.botcard = new /obj/item/weapon/card/id(src) + if(isnull(src.botcard_access) || (src.botcard_access.len < 1)) + src.botcard.access = get_access("Medical Doctor") + else + src.botcard.access = src.botcard_access + src.cam = new /obj/machinery/camera(src) + src.cam.c_tag = src.name + src.cam.network = "SS13" + +/obj/machinery/bot/medbot/examine() + set src in view() + ..() + + if (src.health < 20) + if (src.health > 15) + usr << text("\red [src]'s parts look loose.") + else + usr << text("\red [src]'s parts look very loose!") + return + +/obj/machinery/bot/medbot/attack_ai(mob/user as mob) + return toggle_power() + +/obj/machinery/bot/medbot/attack_paw(mob/user as mob) + return attack_hand(user) + +/obj/machinery/bot/medbot/attack_hand(mob/user as mob) + var/dat + dat += "Automatic Medical Unit v1.0

      " + dat += "Status: [src.on ? "On" : "Off"]
      " + dat += "Beaker: " + if (src.reagent_glass) + dat += "Loaded \[[src.reagent_glass.reagents.total_volume]/[src.reagent_glass.reagents.maximum_volume]\]" + else + dat += "None Loaded" + dat += "
      Behaviour controls are [src.locked ? "locked" : "unlocked"]
      " + if(!src.locked) + dat += "Healing Threshold: " + dat += "-- " + dat += "- " + dat += "[src.heal_threshold] " + dat += "+ " + dat += "++" + dat += "
      " + + dat += "Injection Level: " + dat += "- " + dat += "[src.injection_amount] " + dat += "+ " + dat += "
      " + + dat += "Reagent Source: " + dat += "[src.use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]
      " + + user << browse("Medibot v1.0 controls[dat]", "window=automed") + onclose(user, "automed") + return + +/obj/machinery/bot/medbot/Topic(href, href_list) + if(..()) + return + usr.machine = src + src.add_fingerprint(usr) + if ((href_list["power"]) && (src.allowed(usr))) + src.toggle_power() + + else if((href_list["adj_threshold"]) && (!src.locked)) + var/adjust_num = text2num(href_list["adj_threshold"]) + src.heal_threshold += adjust_num + if(src.heal_threshold < 5) + src.heal_threshold = 5 + if(src.heal_threshold > 75) + src.heal_threshold = 75 + + else if((href_list["adj_inject"]) && (!src.locked)) + var/adjust_num = text2num(href_list["adj_inject"]) + src.injection_amount += adjust_num + if(src.injection_amount < 5) + src.injection_amount = 5 + if(src.injection_amount > 15) + src.injection_amount = 15 + + else if((href_list["use_beaker"]) && (!src.locked)) + src.use_beaker = !src.use_beaker + + else if (href_list["eject"] && (!isnull(src.reagent_glass))) + if(!src.locked) + src.reagent_glass.loc = get_turf(src) + src.reagent_glass = null + else + usr << "You cannot eject the beaker because the panel is locked!" + + src.updateUsrDialog() + return + +/obj/machinery/bot/medbot/attackby(obj/item/weapon/W as obj, mob/user as mob) + if ((istype(W, /obj/item/weapon/card/emag)) && (!src.emagged)) + + user << "\red You short out [src]'s reagent synthesis circuits." + spawn(0) + for(var/mob/O in hearers(src, null)) + O.show_message("\red [src] buzzes oddly!", 1) + flick("medibot_spark", src) + src.patient = null + src.oldpatient = user + src.currently_healing = 0 + src.last_found = world.time + src.anchored = 0 + src.emagged = 1 + src.on = 1 + src.icon_state = "medibot[src.on]" + + else if (istype(W, /obj/item/weapon/card/id)) + if (src.allowed(user)) + src.locked = !src.locked + user << "Controls are now [src.locked ? "locked." : "unlocked."]" + src.updateUsrDialog() + else + user << "\red Access denied." + + else if (istype(W, /obj/item/weapon/screwdriver)) + if (src.health < initial(src.health)) + src.health = initial(src.health) + for(var/mob/O in viewers(src, null)) + O << "\red [user] repairs [src]!" + + else if (istype(W, /obj/item/weapon/reagent_containers/glass)) + if(src.locked) + user << "You cannot insert a beaker because the panel is locked!" + return + if(!isnull(src.reagent_glass)) + user << "There is already a beaker loaded!" + return + + user.drop_item() + W.loc = src + src.reagent_glass = W + user << "You insert [W]." + src.updateUsrDialog() + return + + else + switch(W.damtype) + if("fire") + src.health -= W.force * 0.75 + if("brute") + src.health -= W.force * 0.5 + else + if (src.health <= 0) + src.explode() + else if (W.force) + step_to(src, (get_step_away(src,user))) + ..() + + +/obj/machinery/bot/medbot/process() + set background = 1 + + if(!src.on) + src.stunned = 0 + return + + if(src.stunned) + src.icon_state = "medibota" + src.stunned-- + + src.oldpatient = src.patient + src.patient = null + src.currently_healing = 0 + + if(src.stunned <= 0) + src.icon_state = "medibot[src.on]" + src.stunned = 0 + return + + if(src.frustration > 8) + src.oldpatient = src.patient + src.patient = null + src.currently_healing = 0 + src.last_found = world.time + src.path = new() + + if(!src.patient) + if(prob(1)) + var/message = pick("Radar, put a mask on!","There's always a catch, and it's the best there is.","I knew it, I should've been a plastic surgeon.","What kind of medbay is this? Everyone's dropping like dead flies.","Delicious!") + src.speak(message) + + for (var/mob/living/carbon/C in view(7,src)) //Time to find a patient! + if ((C.stat == 2) || !istype(C, /mob/living/carbon/human)) + continue + + if ((C == src.oldpatient) && (world.time < src.last_found + 100)) + continue + + if(src.assess_patient(C)) + src.patient = C + src.oldpatient = C + src.last_found = world.time + spawn(0) + if((src.last_newpatient_speak + 100) < world.time) //Don't spam these messages! + var/message = pick("Hey, you! Hold on, I'm coming.","Wait! I want to help!","You appear to be injured!") + src.speak(message) + src.last_newpatient_speak = world.time + src.visible_message("[src] points at [C.name]!") + break + else + continue + + + if(src.patient && (get_dist(src,src.patient) <= 1)) + if(!src.currently_healing) + src.currently_healing = 1 + src.frustration = 0 + src.medicate_patient(src.patient) + return + + else if(src.patient && (src.path.len) && (get_dist(src.patient,src.path[src.path.len]) > 2)) + src.path = new() + src.currently_healing = 0 + src.last_found = world.time + + if(src.patient && src.path.len == 0 && (get_dist(src,src.patient) > 1)) + spawn(0) + src.path = AStar(src.loc, get_turf(src.patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30,id=botcard) + src.path = reverselist(src.path) + if(src.path.len == 0) + src.oldpatient = src.patient + src.patient = null + src.currently_healing = 0 + src.last_found = world.time + return + + if(src.path.len > 0 && src.patient) + step_to(src, src.path[1]) + src.path -= src.path[1] + spawn(3) + if(src.path.len) + step_to(src, src.path[1]) + src.path -= src.path[1] + + if(src.path.len > 8 && src.patient) + src.frustration++ + + return + + +/obj/machinery/bot/medbot/proc/toggle_power() + src.on = !src.on + src.patient = null + src.oldpatient = null + src.oldloc = null + src.path = new() + src.currently_healing = 0 + src.last_found = world.time + src.icon_state = "medibot[src.on]" + src.updateUsrDialog() + return + +/obj/machinery/bot/medbot/proc/assess_patient(mob/living/carbon/C as mob) + //Time to see if they need medical help! + if(C.stat == 2) + return 0 //welp too late for them! + + if(C.suiciding) + return 0 //Kevorkian school of robotic medical assistants. + + if(src.emagged) //Everyone needs our medicine. (Our medicine is toxins) + return 1 + + //If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS. + if((src.reagent_glass) && (src.use_beaker) && ((C.bruteloss >= heal_threshold) || (C.toxloss >= heal_threshold) || (C.toxloss >= heal_threshold) || (C.oxyloss >= (heal_threshold + 15)))) + for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list) + if(!C.reagents.has_reagent(R)) + return 1 + continue + + //They're injured enough for it! + if((C.bruteloss >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_brute))) + return 1 //If they're already medicated don't bother! + + if((C.oxyloss >= (15 + heal_threshold)) && (!C.reagents.has_reagent(src.treatment_oxy))) + return 1 + + if((C.fireloss >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_fire))) + return 1 + + if((C.toxloss >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_tox))) + return 1 + + if(C.virus && ((C.virus.stage > 1) || (C.virus.spread == "Airborne"))) + if (!C.reagents.has_reagent(src.treatment_virus)) + return 1 //STOP DISEASE FOREVER + + return 0 + +/obj/machinery/bot/medbot/proc/medicate_patient(mob/living/carbon/C as mob) + if(!src.on) + return + + if(!istype(C)) + src.oldpatient = src.patient + src.patient = null + src.currently_healing = 0 + src.last_found = world.time + return + + if(C.stat == 2) + var/death_message = pick("No! NO!","Live, damnit! LIVE!","I...I've never lost a patient before. Not today, I mean.") + src.speak(death_message) + src.oldpatient = src.patient + src.patient = null + src.currently_healing = 0 + src.last_found = world.time + return + + var/reagent_id = null + + //Use whatever is inside the loaded beaker. If there is one. + if((src.use_beaker) && (src.reagent_glass) && (src.reagent_glass.reagents.total_volume)) + reagent_id = "internal_beaker" + + if(src.emagged) //Emagged! Time to poison everybody. + reagent_id = "toxin" + + if (!reagent_id && (C.virus)) + if(!C.reagents.has_reagent(src.treatment_virus)) + reagent_id = src.treatment_virus + + if (!reagent_id && (C.bruteloss >= heal_threshold)) + if(!C.reagents.has_reagent(src.treatment_brute)) + reagent_id = src.treatment_brute + + if (!reagent_id && (C.oxyloss >= (15 + heal_threshold))) + if(!C.reagents.has_reagent(src.treatment_oxy)) + reagent_id = src.treatment_oxy + + if (!reagent_id && (C.fireloss >= heal_threshold)) + if(!C.reagents.has_reagent(src.treatment_fire)) + reagent_id = src.treatment_fire + + if (!reagent_id && (C.toxloss >= heal_threshold)) + if(!C.reagents.has_reagent(src.treatment_tox)) + reagent_id = src.treatment_tox + + if(!reagent_id) //If they don't need any of that they're probably cured! + src.oldpatient = src.patient + src.patient = null + src.currently_healing = 0 + src.last_found = world.time + var/message = pick("All patched up!","An apple a day keeps me away.","Feel better soon!") + src.speak(message) + return + else + src.icon_state = "medibots" + for(var/mob/O in viewers(src, null)) + O.show_message("\red [src] is trying to inject [src.patient]!", 1) + spawn(30) + if ((get_dist(src, src.patient) <= 1) && (src.on)) + if((reagent_id == "internal_beaker") && (src.reagent_glass) && (src.reagent_glass.reagents.total_volume)) + src.reagent_glass.reagents.trans_to(src.patient,src.injection_amount) //Inject from beaker instead. + src.reagent_glass.reagents.reaction(src.patient, 2) + else + src.patient.reagents.add_reagent(reagent_id,src.injection_amount) + for(var/mob/O in viewers(src, null)) + O.show_message("\red [src] injects [src.patient] with the syringe!", 1) + + src.icon_state = "medibot[src.on]" + src.currently_healing = 0 + return + +// src.speak(reagent_id) + reagent_id = null + return + + +/obj/machinery/bot/medbot/proc/speak(var/message) + if((!src.on) || (!message)) + return + for(var/mob/O in hearers(src, null)) + O.show_message("[src] beeps, \"[message]\"",2) + return + +/obj/machinery/bot/medbot/bullet_act(flag, A as obj) + if (flag == PROJECTILE_BULLET) + src.health -= 18 + + else if (flag == PROJECTILE_TASER) + src.stunned += 10 + if(src.stunned > 20) + src.stunned = 20 + + else if (flag == PROJECTILE_LASER) + src.health -= 8 + + + if (src.health <= 0) + src.explode() + +/obj/machinery/bot/medbot/ex_act(severity) + switch(severity) + if(1.0) + src.explode() + return + if(2.0) + src.health -= 15 + if (src.health <= 0) + src.explode() + return + return + +/obj/machinery/bot/medbot/meteorhit() + src.explode() + return + +/obj/machinery/bot/medbot/blob_act() + if(prob(25)) + src.explode() + return + +/obj/machinery/bot/medbot/proc/explode() + src.on = 0 + for(var/mob/O in hearers(src, null)) + O.show_message("\red [src] blows apart!", 1) + var/turf/Tsec = get_turf(src) + + new /obj/item/weapon/storage/firstaid(Tsec) + + new /obj/item/device/prox_sensor(Tsec) + + new /obj/item/device/healthanalyzer(Tsec) + + if(src.reagent_glass) + src.reagent_glass.loc = Tsec + src.reagent_glass = null + + if (prob(50)) + new /obj/item/robot_parts/l_arm(Tsec) + + var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread + s.set_up(3, 1, src) + s.start() + del(src) + return + +/obj/machinery/bot/medbot/Bump(M as mob|obj) //Leave no door unopened! + spawn(0) + if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard))) + var/obj/machinery/door/D = M + if (D.check_access(src.botcard)) + D.open() + src.frustration = 0 + else if ((istype(M, /mob/living/)) && (!src.anchored)) + src.loc = M:loc + src.frustration = 0 + + return + return + +/obj/machinery/bot/medbot/Bumped(M as mob|obj) + spawn(0) + var/turf/T = get_turf(src) + M:loc = T + + +/* + * Pathfinding procs, allow the medibot to path through doors it has access to. + */ + +//Pretty ugh +/* +/turf/proc/AdjacentTurfsAllowMedAccess() + var/L[] = new() + for(var/turf/t in oview(src,1)) + if(!t.density) + if(!LinkBlocked(src, t) && !TurfBlockedNonWindowNonDoor(t,get_access("Medical Doctor"))) + L.Add(t) + return L + + +//It isn't blocked if we can open it, man. +/proc/TurfBlockedNonWindowNonDoor(turf/loc, var/list/access) + for(var/obj/O in loc) + if(O.density && !istype(O, /obj/window) && !istype(O, /obj/machinery/door)) + return 1 + + if (O.density && (istype(O, /obj/machinery/door)) && (access.len)) + var/obj/machinery/door/D = O + for(var/req in D.req_access) + if(!(req in access)) //doesn't have this access + return 1 + + return 0 +*/ + +/* + * Medbot Assembly -- Can be made out of all three medkits. + */ + +/obj/item/weapon/storage/firstaid/attackby(var/obj/item/robot_parts/S, mob/user as mob) + if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm))) + if (src.contents.len >= 7) + return + if ((S.w_class >= 2 || istype(S, /obj/item/weapon/storage))) + return + ..() + return + + //Syringekit doesn't count EVER. + if(src.type == /obj/item/weapon/storage/firstaid/syringes) + return + + if(src.contents.len >= 1) + user << "\red You need to empty [src] out first!" + return + else + var/obj/item/weapon/firstaid_arm_assembly/A = new /obj/item/weapon/firstaid_arm_assembly + if(istype(src,/obj/item/weapon/storage/firstaid/fire)) + A.skin = "ointment" + else if(istype(src,/obj/item/weapon/storage/firstaid/toxin)) + A.skin = "tox" + + A.loc = user + if (user.r_hand == S) + user.u_equip(S) + user.r_hand = A + else + user.u_equip(S) + user.l_hand = A + A.layer = 20 + user << "You add the robot arm to the first aid kit" + del(S) + del(src) + +/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob) + if ((istype(W, /obj/item/device/healthanalyzer)) && (!src.build_step)) + src.build_step++ + user << "You add the health sensor to [src]!" + src.name = "First aid/robot arm/health analyzer assembly" + src.overlays += image('aibots.dmi', "na_scanner") + del(W) + + else if ((istype(W, /obj/item/device/prox_sensor)) && (src.build_step == 1)) + src.build_step++ + user << "You complete the Medibot! Beep boop." + var/obj/machinery/bot/medbot/S = new /obj/machinery/bot/medbot + S.skin = src.skin + S.loc = get_turf(src) + S.name = src.created_name + del(W) + del(src) + + else if (istype(W, /obj/item/weapon/pen)) + var/t = input(user, "Enter new robot name", src.name, src.created_name) as text + t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN) + if (!t) + return + if (!in_range(src, usr) && src.loc != usr) + return + + src.created_name = t \ No newline at end of file diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm new file mode 100644 index 0000000000000..e7b0d8c05e45c --- /dev/null +++ b/code/game/machinery/bots/mulebot.dm @@ -0,0 +1,914 @@ +// Mulebot - carries crates around for Quartermaster +// Navigates via floor navbeacons +// Remote Controlled from QM's PDA + + +/obj/machinery/bot/mulebot + name = "Mulebot" + desc = "A Multiple Utility Load Effector bot." + icon_state = "mulebot0" + layer = MOB_LAYER + density = 1 + anchored = 1 + animate_movement=1 + var/on = 1 + var/locked = 1 + var/atom/movable/load = null // the loaded crate (usually) + + var/beacon_freq = 1445 + var/control_freq = 1447 + + suffix = "" + + var/turf/target // this is turf to navigate to (location of beacon) + var/loaddir = 0 // this the direction to unload onto/load from + var/new_destination = "" // pending new destination (waiting for beacon response) + var/destination = "" // destination description + var/home_destination = "" // tag of home beacon + req_access = list(access_cargo, access_cargo_bot) + var/path[] = new() + + var/mode = 0 //0 = idle/ready + //1 = loading/unloading + //2 = moving to deliver + //3 = returning to home + //4 = blocked + //5 = computing navigation + //6 = waiting for nav computation + //7 = no destination beacon found (or no route) + + var/blockcount = 0 //number of times retried a blocked path + var/reached_target = 1 //true if already reached the target + + var/refresh = 1 // true to refresh dialogue + var/auto_return = 1 // true if auto return to home beacon after unload + var/auto_pickup = 1 // true if auto-pickup at beacon + + var/open = 0 // true if maint hatch is open + var/obj/item/weapon/cell/cell + // the installed power cell + + // constants for internal wiring bitflags + var/const + wire_power1 = 1 // power connections + wire_power2 = 2 + wire_mobavoid = 4 // mob avoidance + wire_loadcheck = 8 // load checking (non-crate) + wire_motor1 = 16 // motor wires + wire_motor2 = 32 // + wire_remote_rx = 64 // remote recv functions + wire_remote_tx = 128 // remote trans status + wire_beacon_rx = 256 // beacon ping recv + wire_beacon_tx = 512 // beacon ping trans + + var/wires = 1023 // all flags on + + var/list/wire_text // list of wire colours + var/list/wire_order // order of wire indices + + + var/bloodiness = 0 // count of bloodiness + + New() + ..() + botcard = new(src) + botcard.access = get_access("Quartermaster") + cell = new(src) + cell.charge = 2000 + cell.maxcharge = 2000 + setup_wires() + + spawn(5) // must wait for map loading to finish + if(radio_controller) + radio_controller.add_object(src, "[control_freq]") + radio_controller.add_object(src, "[beacon_freq]") + + var/count = 0 + for(var/obj/machinery/bot/mulebot/other in world) + count++ + if(!suffix) + suffix = "#[count]" + name = "Mulebot ([suffix])" + + verbs -= /atom/movable/verb/pull + + + // set up the wire colours in random order + // and the random wire display order + // needs 10 wire colours + proc/setup_wires() + var/list/colours = list("Red", "Green", "Blue", "Magenta", "Cyan", "Yellow", "Black", "White", "Orange", "Grey") + var/list/orders = list("0","1","2","3","4","5","6","7","8","9") + wire_text = list() + wire_order = list() + while(colours.len > 0) + var/colour = colours[ rand(1,colours.len) ] + wire_text += colour + colours -= colour + + var/order = orders[ rand(1,orders.len) ] + wire_order += text2num(order) + orders -= order + + + + // attack by item + // emag : lock/unlock, + // screwdriver: open/close hatch + // cell: insert it + // other: chance to knock rider off bot + attackby(var/obj/item/I, var/mob/user) + if(istype(I,/obj/item/weapon/card/emag)) + locked = !locked + user << "\blue You [locked ? "lock" : "unlock"] the mulebot's controls!" + flick("mulebot-emagged", src) + playsound(src.loc, 'sparks1.ogg', 100, 0) + else if(istype(I,/obj/item/weapon/cell) && open && !cell) + var/obj/item/weapon/cell/C = I + user.drop_item() + C.loc = src + cell = C + updateDialog() + else if(istype(I,/obj/item/weapon/screwdriver)) + if(locked) + user << "\blue The maintenance hatch cannot be opened or closed while the controls are locked." + return + + open = !open + if(open) + src.visible_message("[user] opens the maintenance hatch of [src]", "\blue You open [src]'s maintenance hatch.") + on = 0 + icon_state="mulebot-hatch" + else + src.visible_message("[user] closes the maintenance hatch of [src]", "\blue You close [src]'s maintenance hatch.") + icon_state = "mulebot0" + + updateDialog() + else if(load && ismob(load)) // chance to knock off rider + if(prob(1+I.force * 2)) + unload(0) + user.visible_message("\red [user] knocks [load] off [src] with \the [I]!", "\red You knock [load] off [src] with \the [I]!") + else + user << "You hit [src] with \the [I] but to no effect." + else + ..() + return + + + ex_act(var/severity) + unload(0) + switch(severity) + if(1) + del(src) + if(2) + wires &= ~(1 << rand(0,9)) + wires &= ~(1 << rand(0,9)) + wires &= ~(1 << rand(0,9)) + if(3) + wires &= ~(1 << rand(0,9)) + + return + + bullet_act() + if(prob(50)) + load.bullet_act() + unload(0) + if(prob(25)) + src.visible_message("Something shorts out inside [src]!") + var/index = 1<< (rand(0,9)) + if(wires & index) + wires &= ~index + else + wires |= index + + + attack_ai(var/mob/user) + interact(user, 1) + + attack_hand(var/mob/user) + interact(user, 0) + + proc/interact(var/mob/user, var/ai=0) + var/dat + dat += "Multiple Utility Load Effector Mk. III

      " + dat += "ID: [suffix]
      " + dat += "Power: [on ? "On" : "Off"]
      " + + if(!open) + + dat += "Status: " + switch(mode) + if(0) + dat += "Ready" + if(1) + dat += "Loading/Unloading" + if(2) + dat += "Navigating to Delivery Location" + if(3) + dat += "Navigating to Home" + if(4) + dat += "Waiting for clear path" + if(5,6) + dat += "Calculating navigation path" + if(7) + dat += "Unable to locate destination" + + + dat += "
      Current Load: [load ? load.name : "none"]
      " + dat += "Destination: [!destination ? "none" : destination]
      " + dat += "Power level: [cell ? cell.percent() : 0]%
      " + + if(locked && !ai) + dat += "
      Controls are locked (unlock)" + else + dat += "
      Controls are unlocked (lock)

      " + + dat += "Toggle Power
      " + dat += "Stop
      " + dat += "Proceed
      " + dat += "Return to Home
      " + dat += "Set Destination
      " + dat += "Set Bot ID
      " + dat += "Set Home
      " + dat += "Toggle Auto Return Home ([auto_return ? "On":"Off"])
      " + dat += "Toggle Auto Pickup Crate ([auto_pickup ? "On":"Off"])
      " + + if(load) + dat += "Unload Now
      " + dat += "
      The maintenance hatch is closed.
      " + + else + if(!ai) + dat += "The maintenance hatch is open.

      " + dat += "Power cell: " + if(cell) + dat += "Installed
      " + else + dat += "Removed
      " + + dat += wires() + else + dat += "The bot is in maintenance mode and cannot be controlled.
      " + + user << browse("Mulebot [suffix ? "([suffix])" : ""][dat]", "window=mulebot;size=350x500") + onclose(user, "mulebot") + return + + // returns the wire panel text + proc/wires() + var/t = "" + for(var/i = 0 to 9) + var/index = 1<=2) + mode = 0 + updateDialog() + + if("go") + if(mode == 0) + start() + updateDialog() + + if("home") + if(mode == 0 || mode == 2) + start_home() + updateDialog() + + if("destination") + refresh=0 + var/new_dest = input("Enter new destination tag", "Mulebot [suffix ? "([suffix])" : ""]", destination) as text|null + refresh=1 + if(new_dest) + set_destination(new_dest) + + + if("setid") + refresh=0 + var/new_id = input("Enter new bot ID", "Mulebot [suffix ? "([suffix])" : ""]", suffix) as text|null + refresh=1 + if(new_id) + suffix = new_id + name = "Mulebot ([suffix])" + updateDialog() + + if("sethome") + refresh=0 + var/new_home = input("Enter new home tag", "Mulebot [suffix ? "([suffix])" : ""]", home_destination) as text|null + refresh=1 + if(new_home) + home_destination = new_home + updateDialog() + + if("unload") + if(load && mode !=1) + if(loc == target) + unload(loaddir) + else + unload(0) + + if("autoret") + auto_return = !auto_return + + if("autopick") + auto_pickup = !auto_pickup + + if("close") + usr.machine = null + usr << browse(null,"window=mulebot") + + + if("wirecut") + if(istype(usr.equipped(), /obj/item/weapon/wirecutters)) + var/wirebit = text2num(href_list["wire"]) + wires &= ~wirebit + else + usr << "\blue You need wirecutters!" + if("wiremend") + if(istype(usr.equipped(), /obj/item/weapon/wirecutters)) + var/wirebit = text2num(href_list["wire"]) + wires |= wirebit + else + usr << "\blue You need wirecutters!" + + if("wirepulse") + if(istype(usr.equipped(), /obj/item/device/multitool)) + switch(href_list["wire"]) + if("1","2") + usr << "\blue \icon[src] The charge light flickers." + if("4") + usr << "\blue \icon[src] The external warning lights flash briefly." + if("8") + usr << "\blue \icon[src] The load platform clunks." + if("16", "32") + usr << "\blue \icon[src] The drive motor whines briefly." + else + usr << "\blue \icon[src] You hear a radio crackle." + else + usr << "\blue You need a multitool!" + + + + updateDialog() + //src.updateUsrDialog() + else + usr << browse(null, "window=mulebot") + usr.machine = null + return + + + + // returns true if the bot has power + proc/has_power() + return !open && cell && cell.charge>0 && (wires & wire_power1) && (wires & wire_power2) + + // mousedrop a crate to load the bot + // can load anything if emagged + + MouseDrop_T(var/atom/movable/C, mob/user) + + if(user.stat) + return + + if (!on || !istype(C)|| C.anchored || get_dist(user, src) > 1 || get_dist(src,C) > 1 ) + return + + if(load) + return + + load(C) + + + // called to load a crate + proc/load(var/atom/movable/C) + if((wires & wire_loadcheck) && !istype(C,/obj/crate)) + src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.") + playsound(src.loc, 'buzz-sigh.ogg', 50, 0) + return // if not emagged, only allow crates to be loaded + + if(get_dist(C, src) > 1 || load || !on) + return + mode = 1 + + // if a create, close before loading + var/obj/crate/crate = C + if(istype(crate)) + crate.close() + + C.loc = src.loc + sleep(2) + C.loc = src + load = C + + C.pixel_y += 9 + if(C.layer < layer) + C.layer = layer + 0.1 + overlays += C + + if(ismob(C)) + var/mob/M = C + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + + mode = 0 + send_status() + + // called to unload the bot + // argument is optional direction to unload + // if zero, unload at bot's location + proc/unload(var/dirn = 0) + if(!load) + return + + mode = 1 + overlays = null + + load.loc = src.loc + load.pixel_y -= 9 + load.layer = initial(load.layer) + if(ismob(load)) + var/mob/M = load + if(M.client) + M.client.perspective = MOB_PERSPECTIVE + M.client.eye = src + + + if(dirn) + step(load, dirn) + + load = null + + // in case non-load items end up in contents, dump every else too + // this seems to happen sometimes due to race conditions + // with items dropping as mobs are loaded + + for(var/atom/movable/AM in src) + if(AM == cell || AM == botcard) continue + + AM.loc = src.loc + AM.layer = initial(AM.layer) + AM.pixel_y = initial(AM.pixel_y) + if(ismob(AM)) + var/mob/M = AM + if(M.client) + M.client.perspective = MOB_PERSPECTIVE + M.client.eye = src + mode = 0 + + + process() + if(!has_power()) + on = 0 + return + if(on) + var/speed = ((wires & wire_motor1) ? 1:0) + ((wires & wire_motor2) ? 2:0) + //world << "speed: [speed]" + switch(speed) + if(0) + // do nothing + if(1) + process_bot() + spawn(3) + process_bot() + sleep(3) + process_bot() + if(2) + process_bot() + spawn(5) + process_bot() + if(3) + process_bot() + + if(refresh) updateDialog() + + proc/process_bot() + //if(mode) world << "Mode: [mode]" + switch(mode) + if(0) // idle + icon_state = "mulebot0" + return + if(1) // loading/unloading + return + if(2,3,4) // navigating to deliver,home, or blocked + + if(loc == target) // reached target + at_target() + return + + else if(path.len > 0 && target) // valid path + + var/turf/next = path[1] + reached_target = 0 + if(next == loc) + path -= next + return + + + if(istype( next, /turf/simulated)) + //world << "at ([x],[y]) moving to ([next.x],[next.y])" + + + if(bloodiness) + var/obj/decal/cleanable/blood/tracks/B = new(loc) + var/newdir = get_dir(next, loc) + if(newdir == dir) + B.dir = newdir + else + newdir = newdir | dir + if(newdir == 3) + newdir = 1 + else if(newdir == 12) + newdir = 4 + B.dir = newdir + bloodiness-- + + + + var/moved = step_towards(src, next) // attempt to move + if(cell) cell.use(1) + if(moved) // successful move + //world << "Successful move." + blockcount = 0 + path -= loc + + + if(mode==4) + spawn(1) + send_status() + + if(destination == home_destination) + mode = 3 + else + mode = 2 + + else // failed to move + + //world << "Unable to move." + + + + blockcount++ + mode = 4 + if(blockcount == 3) + src.visible_message("[src] makes an annoyed buzzing sound", "You hear an electronic buzzing sound.") + playsound(src.loc, 'buzz-two.ogg', 50, 0) + + if(blockcount > 5) // attempt 5 times before recomputing + // find new path excluding blocked turf + src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.") + playsound(src.loc, 'buzz-sigh.ogg', 50, 0) + + spawn(2) + calc_path(next) + if(path.len > 0) + src.visible_message("[src] makes a delighted ping!", "You hear a ping.") + playsound(src.loc, 'ping.ogg', 50, 0) + mode = 4 + mode =6 + return + return + else + src.visible_message("[src] makes an annoyed buzzing sound", "You hear an electronic buzzing sound.") + playsound(src.loc, 'buzz-two.ogg', 50, 0) + //world << "Bad turf." + mode = 5 + return + else + //world << "No path." + mode = 5 + return + + if(5) // calculate new path + //world << "Calc new path." + mode = 6 + spawn(0) + + calc_path() + + if(path.len > 0) + blockcount = 0 + mode = 4 + src.visible_message("[src] makes a delighted ping!", "You hear a ping.") + playsound(src.loc, 'ping.ogg', 50, 0) + + else + src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.") + playsound(src.loc, 'buzz-sigh.ogg', 50, 0) + + mode = 7 + //if(6) + //world << "Pending path calc." + //if(7) + //world << "No dest / no route." + return + + + // calculates a path to the current destination + // given an optional turf to avoid + proc/calc_path(var/turf/avoid = null) + src.path = AStar(src.loc, src.target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 250, id=botcard, exclude=avoid) + src.path = reverselist(src.path) + + + // sets the current destination + // signals all beacons matching the delivery code + // beacons will return a signal giving their locations + proc/set_destination(var/new_dest) + spawn(0) + new_destination = new_dest + post_signal(beacon_freq, "findbeacon", "delivery") + updateDialog() + + // starts bot moving to current destination + proc/start() + if(destination == home_destination) + mode = 3 + else + mode = 2 + icon_state = "mulebot[(wires & wire_mobavoid) == wire_mobavoid]" + + // starts bot moving to home + // sends a beacon query to find + proc/start_home() + spawn(0) + set_destination(home_destination) + mode = 4 + icon_state = "mulebot[(wires & wire_mobavoid) == wire_mobavoid]" + + // called when bot reaches current target + proc/at_target() + if(!reached_target) + src.visible_message("[src] makes a chiming sound!", "You hear a chime.") + playsound(src.loc, 'chime.ogg', 50, 0) + reached_target = 1 + + if(load) // if loaded, unload at target + unload(loaddir) + else + // not loaded + if(auto_pickup) // find a crate + var/atom/movable/AM + if(!(wires & wire_loadcheck)) // if emagged, load first unanchored thing we find + for(var/atom/movable/A in get_step(loc, loaddir)) + if(!A.anchored) + AM = A + break + else // otherwise, look for crates only + AM = locate(/obj/crate) in get_step(loc,loaddir) + if(AM) + load(AM) + // whatever happened, check to see if we return home + + if(auto_return && destination != home_destination) + // auto return set and not at home already + start_home() + mode = 4 + else + mode = 0 // otherwise go idle + + send_status() // report status to anyone listening + + return + + // called when bot bumps into anything + Bump(var/atom/obs) + if(!(wires & wire_mobavoid)) //usually just bumps, but if avoidance disabled knock over mobs + var/mob/M = obs + if(ismob(M)) + if(istype(M,/mob/living/silicon/robot)) + src.visible_message("\red [src] bumps into [M]!") + else + src.visible_message("\red [src] knocks over [M]!") + M.pulling = null + M.stunned = 8 + M.weakened = 5 + M.lying = 1 + ..() + + alter_health() + return get_turf(src) + + + // called from mob/living/carbon/human/HasEntered() + // when mulebot is in the same loc + proc/RunOver(var/mob/living/carbon/human/H) + src.visible_message("\red [src] drives over [H]!") + playsound(src.loc, 'splat.ogg', 50, 1) + + /* + if(ismob(load)) + var/mob/M = load + if(M.reagents.has_reagent("beer")) + M.unlock_medal("DUI", 1) + if(M.reagents.has_reagent("space_drugs") && istype(H) && H.wear_id.assignment == "Security Officer") + M.unlock_medel("Ridin' Dirty",1) + */ + + var/damage = rand(5,15) + + H.TakeDamage("head", 2*damage, 0) + H.TakeDamage("chest",2*damage, 0) + H.TakeDamage("l_leg",0.5*damage, 0) + H.TakeDamage("r_leg",0.5*damage, 0) + H.TakeDamage("l_arm",0.5*damage, 0) + H.TakeDamage("r_arm",0.5*damage, 0) + + var/obj/decal/cleanable/blood/B = new(src.loc) + B.blood_DNA = H.dna.unique_enzymes + B.blood_type = H.b_type + + bloodiness += 4 + + // player on mulebot attempted to move + relaymove(var/mob/user) + if(user.stat) + return + if(load == user) + unload(0) + return + + // receive a radio signal + // used for control and beacon reception + + receive_signal(datum/signal/signal) + + if(!on) + return + + /* + world << "rec signal: [signal.source]" + for(var/x in signal.data) + world << "* [x] = [signal.data[x]]" + */ + var/recv = signal.data["command"] + // process all-bot input + if(recv=="bot_status" && (wires & wire_remote_rx)) + send_status() + + + recv = signal.data["command [suffix]"] + if(wires & wire_remote_rx) + // process control input + switch(recv) + if("stop") + mode = 0 + return + + if("go") + start() + return + + if("target") + set_destination(signal.data["destination"] ) + return + + if("unload") + if(loc == target) + unload(loaddir) + else + unload(0) + return + + if("home") + start_home() + return + + if("bot_status") + send_status() + return + + if("autoret") + auto_return = text2num(signal.data["value"]) + return + + if("autopick") + auto_pickup = text2num(signal.data["value"]) + return + + // receive response from beacon + recv = signal.data["beacon"] + if(wires & wire_beacon_rx) + if(recv == new_destination) // if the recvd beacon location matches the set destination + // the we will navigate there + destination = new_destination + target = signal.source.loc + var/direction = signal.data["dir"] // this will be the load/unload dir + if(direction) + loaddir = text2num(direction) + else + loaddir = 0 + icon_state = "mulebot[(wires & wire_mobavoid) == wire_mobavoid]" + calc_path() + updateDialog() + + // send a radio signal with a single data key/value pair + proc/post_signal(var/freq, var/key, var/value) + post_signal_multiple(freq, list("[key]" = value) ) + + // send a radio signal with multiple data key/values + proc/post_signal_multiple(var/freq, var/list/keyval) + + if(freq == beacon_freq && !(wires & wire_beacon_tx)) + return + if(freq == control_freq && !(wires & wire_remote_tx)) + return + + var/datum/radio_frequency/frequency = radio_controller.return_frequency("[freq]") + + if(!frequency) return + + + + var/datum/signal/signal = new() + signal.source = src + signal.transmission_method = 1 + for(var/key in keyval) + signal.data[key] = keyval[key] + //world << "sent [key],[keyval[key]] on [freq]" + frequency.post_signal(src, signal) + + // signals bot status etc. to controller + proc/send_status() + var/list/kv = new() + kv["type"] = "mulebot" + kv["name"] = suffix + kv["loca"] = loc.loc // area + kv["mode"] = mode + kv["powr"] = cell ? cell.percent() : 0 + kv["dest"] = destination + kv["home"] = home_destination + kv["load"] = load + kv["retn"] = auto_return + kv["pick"] = auto_pickup + post_signal_multiple(control_freq, kv) + + + diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm new file mode 100644 index 0000000000000..34927390d3dcc --- /dev/null +++ b/code/game/machinery/bots/secbot.dm @@ -0,0 +1,789 @@ +/obj/machinery/bot/secbot + name = "Securitron" + desc = "A little security robot. He looks less than thrilled." + icon = 'aibots.dmi' + icon_state = "secbot0" + layer = 5.0 + density = 1 + anchored = 0 +// weight = 1.0E7 + req_access = list(access_security) + var/on = 1 + var/locked = 1 //Behavior Controls lock + var/mob/living/carbon/target + var/oldtarget_name + var/threatlevel = 0 + var/target_lastloc //Loc of target when arrested. + var/last_found //There's a delay + var/frustration = 0 + var/emagged = 0 //Emagged Secbots view everyone as a criminal + var/health = 25 + var/idcheck = 1 //If false, all station IDs are authorized for weapons. + var/check_records = 1 //Does it check security records? + var/arrest_type = 0 //If true, don't handcuff + + var/mode = 0 +#define SECBOT_IDLE 0 // idle +#define SECBOT_HUNT 1 // found target, hunting +#define SECBOT_PREP_ARREST 2 // at target, preparing to arrest +#define SECBOT_ARREST 3 // arresting target +#define SECBOT_START_PATROL 4 // start patrol +#define SECBOT_PATROL 5 // patrolling +#define SECBOT_SUMMON 6 // summoned by PDA + + var/auto_patrol = 0 // set to make bot automatically patrol + + var/obj/machinery/camera/cam //Camera for the AI to find them I guess + + var/beacon_freq = 1445 // navigation beacon frequency + var/control_freq = 1447 // bot control frequency + + + var/turf/patrol_target // this is turf to navigate to (location of beacon) + var/new_destination // pending new destination (waiting for beacon response) + var/destination // destination description tag + var/next_destination // the next destination in the patrol route + var/list/path = new // list of path turfs + + var/blockcount = 0 //number of times retried a blocked path + var/awaiting_beacon = 0 // count of pticks awaiting a beacon response + + var/nearest_beacon // the nearest beacon's tag + var/turf/nearest_beacon_loc // the nearest beacon's location + + +/obj/machinery/bot/secbot/beepsky + name = "Officer Beepsky" + desc = "It's Officer Beepsky! He's a loose cannon but he gets the job done." + idcheck = 0 + auto_patrol = 1 + +/obj/item/weapon/secbot_assembly + name = "helmet/signaler assembly" + desc = "Some sort of bizarre assembly." + icon = 'aibots.dmi' + icon_state = "helmet_signaler" + item_state = "helmet" + var/build_step = 0 + var/created_name = "Securitron" //To preserve the name if it's a unique securitron I guess + + + +/obj/machinery/bot/secbot + New() + ..() + src.icon_state = "secbot[src.on]" + spawn(3) + src.botcard = new /obj/item/weapon/card/id(src) + src.botcard.access = get_access("Detective") + src.cam = new /obj/machinery/camera(src) + src.cam.c_tag = src.name + src.cam.network = "SS13" + if(radio_controller) + radio_controller.add_object(src, "[control_freq]") + radio_controller.add_object(src, "[beacon_freq]") + + examine() + set src in view() + ..() + + if (src.health < 25) + if (src.health > 15) + usr << text("\red [src]'s parts look loose.") + else + usr << text("\red [src]'s parts look very loose!") + return + + attack_hand(user as mob) + var/dat + + dat += text({" +Automatic Security Unit v1.3

      +Status: []
      +Behaviour controls are [src.locked ? "locked" : "unlocked"]"}, + +"[src.on ? "On" : "Off"]" ) + + if(!src.locked) + dat += text({"
      +Check for Weapon Authorization: []
      +Check Security Records: []
      +Operating Mode: []
      +Auto Patrol: []"}, + +"[src.idcheck ? "Yes" : "No"]", +"[src.check_records ? "Yes" : "No"]", +"[src.arrest_type ? "Detain" : "Arrest"]", +"[auto_patrol ? "On" : "Off"]" ) + + + user << browse("Securitron v1.3 controls[dat]", "window=autosec") + onclose(user, "autosec") + return + + Topic(href, href_list) + usr.machine = src + src.add_fingerprint(usr) + if ((href_list["power"]) && (src.allowed(usr))) + src.on = !src.on + src.target = null + src.oldtarget_name = null + src.anchored = 0 + src.mode = SECBOT_IDLE + walk_to(src,0) + src.icon_state = "secbot[src.on]" + src.updateUsrDialog() + + switch(href_list["operation"]) + if ("idcheck") + src.idcheck = !src.idcheck + src.updateUsrDialog() + if ("ignorerec") + src.check_records = !src.check_records + src.updateUsrDialog() + if ("switchmode") + src.arrest_type = !src.arrest_type + src.updateUsrDialog() + if("patrol") + auto_patrol = !auto_patrol + mode = SECBOT_IDLE + updateUsrDialog() + + attack_ai(mob/user as mob) + src.on = !src.on + src.target = null + src.oldtarget_name = null + mode = SECBOT_IDLE + src.anchored = 0 + src.icon_state = "secbot[src.on]" + walk_to(src,0) + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if ((istype(W, /obj/item/weapon/card/emag)) && (!src.emagged)) + user << "\red You short out [src]'s target assessment circuits." + spawn(0) + for(var/mob/O in hearers(src, null)) + O.show_message("\red [src] buzzes oddly!", 1) + src.target = null + src.oldtarget_name = user.name + src.last_found = world.time + src.anchored = 0 + src.emagged = 1 + src.on = 1 + src.icon_state = "secbot[src.on]" + mode = SECBOT_IDLE + else if (istype(W, /obj/item/weapon/card/id)) + if (src.allowed(user)) + src.locked = !src.locked + user << "Controls are now [src.locked ? "locked." : "unlocked."]" + else + user << "\red Access denied." + + else if (istype(W, /obj/item/weapon/screwdriver)) + if (src.health < 25) + src.health = 25 + for(var/mob/O in viewers(src, null)) + O << "\red [user] repairs [src]!" + else + switch(W.damtype) + if("fire") + src.health -= W.force * 0.75 + if("brute") + src.health -= W.force * 0.5 + else + if (src.health <= 0) + src.explode() + else if ((W.force) && (!src.target)) + src.target = user + src.mode = SECBOT_HUNT + ..() + + + + process() + set background = 1 + + if (!src.on) + return + + switch(mode) + + if(SECBOT_IDLE) // idle + + walk_to(src,0) + look_for_perp() // see if any criminals are in range + if(!mode && auto_patrol) // still idle, and set to patrol + mode = SECBOT_START_PATROL // switch to patrol mode + + if(SECBOT_HUNT) // hunting for perp + + // if can't reach perp for long enough, go idle + if (src.frustration >= 8) + // for(var/mob/O in hearers(src, null)) + // O << "[src] beeps, \"Backup requested! Suspect has evaded arrest.\"" + src.target = null + src.last_found = world.time + src.frustration = 0 + src.mode = 0 + walk_to(src,0) + + if (target) // make sure target exists + if (get_dist(src, src.target) <= 1) // if right next to perp + playsound(src.loc, 'Egloves.ogg', 50, 1, -1) + src.icon_state = "secbot-c" + spawn(2) + src.icon_state = "secbot[src.on]" + var/mob/living/carbon/M = src.target + var/maxstuns = 4 + if (istype(M, /mob/living/carbon/human)) + if (M.weakened < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/) + M.weakened = 10 + if (M.stuttering < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/) + M.stuttering = 10 + if (M.stunned < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/) + M.stunned = 10 + else + M.weakened = 10 + M.stuttering = 10 + M.stunned = 10 + maxstuns-- + if (maxstuns <= 0) + target = null + for(var/mob/O in viewers(src, null)) + O.show_message("\red [src.target] has been stunned by [src]!", 1, "\red You hear someone fall", 2) + + mode = SECBOT_PREP_ARREST + src.anchored = 1 + src.target_lastloc = M.loc + return + + else // not next to perp + var/turf/olddist = get_dist(src, src.target) + walk_to(src, src.target,1,4) + if ((get_dist(src, src.target)) >= (olddist)) + src.frustration++ + else + src.frustration = 0 + + if(SECBOT_PREP_ARREST) // preparing to arrest target + + // see if he got away + if ((get_dist(src, src.target) > 1) || ((src.target:loc != src.target_lastloc) && src.target:weakened < 2)) + src.anchored = 0 + mode = SECBOT_HUNT + return + + if (!src.target.handcuffed && !src.arrest_type) + playsound(src.loc, 'handcuffs.ogg', 30, 1, -2) + mode = SECBOT_ARREST + for(var/mob/O in viewers(src, null)) + O.show_message("\red [src] is trying to put handcuffs on [src.target]!", 1) + + spawn(60) + if (get_dist(src, src.target) <= 1) + if (src.target.handcuffed) + return + + if(istype(src.target,/mob/living/carbon)) + src.target.handcuffed = new /obj/item/weapon/handcuffs(src.target) + + mode = SECBOT_IDLE + src.target = null + src.anchored = 0 + src.last_found = world.time + src.frustration = 0 + + playsound(src.loc, pick('bgod.ogg', 'biamthelaw.ogg', 'bsecureday.ogg', 'bradio.ogg', 'binsult.ogg', 'bcreep.ogg'), 50, 0) + // var/arrest_message = pick("Have a secure day!","I AM THE LAW.", "God made tomorrow for the crooks we don't catch today.","You can't outrun a radio.") + // src.speak(arrest_message) + + if(SECBOT_ARREST) // arresting + + if (src.target.handcuffed) + src.anchored = 0 + mode = SECBOT_IDLE + return + + + if(SECBOT_START_PATROL) // start a patrol + + if(path.len > 0 && patrol_target) // have a valid path, so just resume + mode = SECBOT_PATROL + return + + else if(patrol_target) // has patrol target already + spawn(0) + calc_path() // so just find a route to it + if(path.len == 0) + patrol_target = 0 + return + mode = SECBOT_PATROL + + + else // no patrol target, so need a new one + find_patrol_target() + speak("Engaging patrol mode.") + + + if(SECBOT_PATROL) // patrol mode + + patrol_step() + spawn(5) + if(mode == SECBOT_PATROL) + patrol_step() + + if(SECBOT_SUMMON) // summoned to PDA + patrol_step() + spawn(4) + if(mode == SECBOT_SUMMON) + patrol_step() + sleep(4) + patrol_step() + + return + + + // perform a single patrol step + + proc/patrol_step() + + if(loc == patrol_target) // reached target + at_patrol_target() + return + + else if(path.len > 0 && patrol_target) // valid path + + var/turf/next = path[1] + if(next == loc) + path -= next + return + + + if(istype( next, /turf/simulated)) + + var/moved = step_towards(src, next) // attempt to move + if(moved) // successful move + blockcount = 0 + path -= loc + + look_for_perp() + else // failed to move + + blockcount++ + + if(blockcount > 5) // attempt 5 times before recomputing + // find new path excluding blocked turf + + spawn(2) + calc_path(next) + if(path.len == 0) + find_patrol_target() + else + blockcount = 0 + + return + + return + + else // not a valid turf + mode = SECBOT_IDLE + return + + else // no path, so calculate new one + mode = SECBOT_START_PATROL + + + // finds a new patrol target + proc/find_patrol_target() + send_status() + if(awaiting_beacon) // awaiting beacon response + awaiting_beacon++ + if(awaiting_beacon > 5) // wait 5 secs for beacon response + find_nearest_beacon() // then go to nearest instead + return + + if(next_destination) + set_destination(next_destination) + else + find_nearest_beacon() + return + + + // finds the nearest beacon to self + // signals all beacons matching the patrol code + proc/find_nearest_beacon() + nearest_beacon = null + new_destination = "__nearest__" + post_signal(beacon_freq, "findbeacon", "patrol") + awaiting_beacon = 1 + spawn(10) + awaiting_beacon = 0 + if(nearest_beacon) + set_destination(nearest_beacon) + else + auto_patrol = 0 + mode = SECBOT_IDLE + speak("Disengaging patrol mode.") + send_status() + + + proc/at_patrol_target() + find_patrol_target() + return + + + // sets the current destination + // signals all beacons matching the patrol code + // beacons will return a signal giving their locations + proc/set_destination(var/new_dest) + new_destination = new_dest + post_signal(beacon_freq, "findbeacon", "patrol") + awaiting_beacon = 1 + + + // receive a radio signal + // used for beacon reception + + receive_signal(datum/signal/signal) + + if(!on) + return + + /* + world << "rec signal: [signal.source]" + for(var/x in signal.data) + world << "* [x] = [signal.data[x]]" + */ + + var/recv = signal.data["command"] + // process all-bot input + if(recv=="bot_status") + send_status() + + // check to see if we are the commanded bot + if(signal.data["active"] == src) + // process control input + switch(recv) + if("stop") + mode = SECBOT_IDLE + auto_patrol = 0 + return + + if("go") + mode = SECBOT_IDLE + auto_patrol = 1 + return + + if("summon") + patrol_target = signal.data["target"] + next_destination = destination + destination = null + awaiting_beacon = 0 + mode = SECBOT_SUMMON + calc_path() + speak("Responding.") + + return + + + + // receive response from beacon + recv = signal.data["beacon"] + var/valid = signal.data["patrol"] + if(!recv || !valid) + return + + if(recv == new_destination) // if the recvd beacon location matches the set destination + // the we will navigate there + destination = new_destination + patrol_target = signal.source.loc + next_destination = signal.data["next_patrol"] + awaiting_beacon = 0 + + // if looking for nearest beacon + else if(new_destination == "__nearest__") + var/dist = get_dist(src,signal.source.loc) + if(nearest_beacon) + + // note we ignore the beacon we are located at + if(dist>1 && dist 1) + nearest_beacon = recv + nearest_beacon_loc = signal.source.loc + return + + + // send a radio signal with a single data key/value pair + proc/post_signal(var/freq, var/key, var/value) + post_signal_multiple(freq, list("[key]" = value) ) + + // send a radio signal with multiple data key/values + proc/post_signal_multiple(var/freq, var/list/keyval) + + var/datum/radio_frequency/frequency = radio_controller.return_frequency("[freq]") + + if(!frequency) return + + var/datum/signal/signal = new() + signal.source = src + signal.transmission_method = 1 + for(var/key in keyval) + signal.data[key] = keyval[key] + //world << "sent [key],[keyval[key]] on [freq]" + frequency.post_signal(src, signal) + + // signals bot status etc. to controller + proc/send_status() + var/list/kv = new() + kv["type"] = "secbot" + kv["name"] = name + kv["loca"] = loc.loc // area + kv["mode"] = mode + post_signal_multiple(control_freq, kv) + + + +// calculates a path to the current destination +// given an optional turf to avoid + proc/calc_path(var/turf/avoid = null) + src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=avoid) + src.path = reverselist(src.path) + + +// look for a criminal in view of the bot + + proc/look_for_perp() + src.anchored = 0 + for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal + if ((C.stat) || (C.handcuffed)) + continue + + if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 100)) + continue + + if (istype(C, /mob/living/carbon/human)) + src.threatlevel = src.assess_perp(C) + else if ((istype(C, /mob/living/carbon/monkey)) && (C.client) && (ticker.mode.name == "monkey")) + src.threatlevel = 4 + + if (!src.threatlevel) + continue + + else if (src.threatlevel >= 4) + src.target = C + src.oldtarget_name = C.name + src.speak("Level [src.threatlevel] infraction alert!") + playsound(src.loc, pick('bcriminal.ogg', 'bjustice.ogg', 'bfreeze.ogg'), 50, 0) + src.visible_message("[src] points at [C.name]!") + mode = SECBOT_HUNT + spawn(0) + process() // ensure bot quickly responds to a perp + break + else + continue + + +//If the security records say to arrest them, arrest them +//Or if they have weapons and aren't security, arrest them. + proc/assess_perp(mob/living/carbon/human/perp as mob) + var/threatcount = 0 + + if(src.emagged) return 10 //Everyone is a criminal! + + if((src.idcheck) || (isnull(perp:wear_id)) || (istype(perp:wear_id, /obj/item/weapon/card/id/syndicate))) + if(src.allowed(perp)) //Corrupt cops cannot exist beep boop + return 0 + + if(istype(perp.l_hand, /obj/item/weapon/gun) || istype(perp.l_hand, /obj/item/weapon/baton)) + threatcount += 4 + + if(istype(perp.r_hand, /obj/item/weapon/gun) || istype(perp.r_hand, /obj/item/weapon/baton)) + threatcount += 4 + + if(istype(perp:belt, /obj/item/weapon/gun) || istype(perp:belt, /obj/item/weapon/baton)) + threatcount += 2 + + if(istype(perp:wear_suit, /obj/item/clothing/suit/wizrobe)) + threatcount += 2 + + if(perp.mutantrace != "none") + threatcount += 2 + + //Agent cards lower threatlevel when normal idchecking is off. + if((istype(perp:wear_id, /obj/item/weapon/card/id/syndicate)) && src.idcheck) + threatcount -= 2 + + if (src.check_records) + for (var/datum/data/record/E in data_core.general) + var/perpname = perp.name + if (perp:wear_id && perp:wear_id.registered) + perpname = perp.wear_id.registered + if (E.fields["name"] == perpname) + for (var/datum/data/record/R in data_core.security) + if ((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "*Arrest*")) + threatcount = 4 + break + + return threatcount + + Bump(M as mob|obj) //Leave no door unopened! + spawn(0) + if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard))) + var/obj/machinery/door/D = M + if (D.check_access(src.botcard)) + D.open() + src.frustration = 0 + else if ((istype(M, /mob/living/)) && (!src.anchored)) + src.loc = M:loc + src.frustration = 0 + + return + return + + Bumped(M as mob|obj) + spawn(0) + var/turf/T = get_turf(src) + M:loc = T + + bullet_act(flag, A as obj) + if (flag == PROJECTILE_BULLET) + src.health -= 20 + + // else if (flag == PROJECTILE_WEAKBULLET || PROJECTILE_BEANBAG) //Detective's revolver fires marshmallows + // src.health -= 2 + + else if (flag == PROJECTILE_LASER) + src.health -= 10 + + + if (src.health <= 0) + src.explode() + + proc/speak(var/message) + for(var/mob/O in hearers(src, null)) + O << "[src] beeps, \"[message]\"" + return + + //Generally we want to explode() instead of just deleting the securitron. + ex_act(severity) + switch(severity) + if(1.0) + src.explode() + return + if(2.0) + src.health -= 15 + if (src.health <= 0) + src.explode() + return + return + + meteorhit() + src.explode() + return + + blob_act() + if(prob(25)) + src.explode() + return + + proc/explode() + + walk_to(src,0) + for(var/mob/O in hearers(src, null)) + O.show_message("\red [src] blows apart!", 1) + var/turf/Tsec = get_turf(src) + + var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec) + Sa.build_step = 1 + Sa.overlays += image('aibots.dmi', "hs_hole") + Sa.created_name = src.name + new /obj/item/device/prox_sensor(Tsec) + + var/obj/item/weapon/baton/B = new /obj/item/weapon/baton(Tsec) + B.charges = 0 + + if (prob(50)) + new /obj/item/robot_parts/l_arm(Tsec) + + var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread + s.set_up(3, 1, src) + s.start() + del(src) + + + + + + +//Secbot Construction + +/obj/item/clothing/head/helmet/attackby(var/obj/item/device/radio/signaler/S, mob/user as mob) + if (!istype(S, /obj/item/device/radio/signaler)) + ..() + return + + if (src.type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets. + return + + if (!S.b_stat) + return + else + var/obj/item/weapon/secbot_assembly/A = new /obj/item/weapon/secbot_assembly + A.loc = user + if (user.r_hand == S) + user.u_equip(S) + user.r_hand = A + else + user.u_equip(S) + user.l_hand = A + A.layer = 20 + user << "You add the signaler to the helmet." + del(S) + del(src) + + +/obj/item/weapon/secbot_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob) + if ((istype(W, /obj/item/weapon/weldingtool)) && (!src.build_step)) + if ((W:welding) && (W:get_fuel() >= 1)) + W:use_fuel(1) + src.build_step++ + src.overlays += image('aibots.dmi', "hs_hole") + user << "You weld a hole in [src]!" + + else if ((istype(W, /obj/item/device/prox_sensor)) && (src.build_step == 1)) + src.build_step++ + user << "You add the prox sensor to [src]!" + src.overlays += image('aibots.dmi', "hs_eye") + src.name = "helmet/signaler/prox sensor assembly" + del(W) + + else if (((istype(W, /obj/item/robot_parts/l_arm)) || (istype(W, /obj/item/robot_parts/r_arm))) && (src.build_step == 2)) + src.build_step++ + user << "You add the robot arm to [src]!" + src.name = "helmet/signaler/prox sensor/robot arm assembly" + src.overlays += image('aibots.dmi', "hs_arm") + del(W) + + else if ((istype(W, /obj/item/weapon/baton)) && (src.build_step >= 3)) + src.build_step++ + user << "You complete the Securitron! Beep boop." + var/obj/machinery/bot/secbot/S = new /obj/machinery/bot/secbot + S.loc = get_turf(src) + S.name = src.created_name + del(W) + del(src) + + else if (istype(W, /obj/item/weapon/pen)) + var/t = input(user, "Enter new robot name", src.name, src.created_name) as text + t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN) + if (!t) + return + if (!in_range(src, usr) && src.loc != usr) + return + + src.created_name = t \ No newline at end of file diff --git a/code/game/machinery/camera.dm b/code/game/machinery/camera.dm new file mode 100644 index 0000000000000..23361f1868ca4 --- /dev/null +++ b/code/game/machinery/camera.dm @@ -0,0 +1,309 @@ +// Double clicking turfs to move to nearest camera + +/turf/proc/move_camera_by_click() + if (usr.stat) + return ..() + if (world.time <= usr:lastDblClick+2) + return ..() + + //try to find the closest working camera in the same area, switch to it + var/area/A = get_area(src) + var/best_dist = INFINITY //infinity + var/best_cam = null + for(var/obj/machinery/camera/C in A) + if(usr:network != C.network) + continue // different network (syndicate) + if(C.z != usr.z) + continue // different viewing plane + if(!C.status) + continue // ignore disabled cameras + var/dist = get_dist(src, C) + if(dist < best_dist) + best_dist = dist + best_cam = C + + if(!best_cam) + return ..() + usr:lastDblClick = world.time + usr:switchCamera(best_cam) + +/mob/living/silicon/ai/proc/ai_camera_list() + set category = "AI Commands" + set name = "Show Camera List" + + if(usr.stat == 2) + usr << "You can't track with camera because you are dead!" + return + + attack_ai(src) + +/mob/living/silicon/ai/proc/ai_camera_track() + set category = "AI Commands" + set name = "Track With Camera" + if(usr.stat == 2) + usr << "You can't track with camera because you are dead!" + return + + var/list/names = list() + var/list/namecounts = list() + var/list/creatures = list() + for (var/mob/M in world) + if (istype(M, /mob/new_player)) + continue //cameras can't follow people who haven't started yet DUH OR DIDN'T YOU KNOW THAT + if (istype(M, /mob/living/carbon/human) && istype(M:wear_id, /obj/item/weapon/card/id/syndicate)) + continue + if(!istype(M.loc, /turf)) //in a closet or something, AI can't see him anyways + continue + if(M.invisibility) //cloaked + continue + if(istype(M.loc,/obj/dummy)) + continue + else if (M == usr) + continue + + var/name = M.name + if (name in names) + namecounts[name]++ + name = text("[] ([])", name, namecounts[name]) + else + names.Add(name) + namecounts[name] = 1 + + creatures[name] = M + + var/target_name = input(usr, "Which creature should you track?") as null|anything in creatures + + if (!target_name) + usr:cameraFollow = null + return + + var/mob/target = creatures[target_name] + + ai_actual_track(target) + +/mob/living/silicon/ai/proc/ai_actual_track(mob/target as mob) + + usr:cameraFollow = target + usr << text("Now tracking [] on camera.", target.name) + if (usr.machine == null) + usr.machine = usr + + spawn (0) + while (usr:cameraFollow == target) + if (usr:cameraFollow == null) + return + else if (istype(target, /mob/living/carbon/human) && istype(target:wear_id, /obj/item/weapon/card/id/syndicate)) + usr << "Follow camera mode ended." + usr:cameraFollow = null + return + else if(istype(target.loc,/obj/dummy)) + usr << "Follow camera mode ended." + usr:cameraFollow = null + return + else if (!target || !istype(target.loc, /turf)) //in a closet + usr << "Target is not on or near any active cameras on the station. We'll check again in 5 seconds (unless you use the cancel-camera verb)." + sleep(40) //because we're sleeping another second after this (a few lines down) + continue + + var/obj/machinery/camera/C = usr:current + if ((C && istype(C, /obj/machinery/camera)) || C==null) + + var/closestDist = -1 + if (C!=null) + if (C.status) + closestDist = get_dist(C, target) + //usr << text("Dist = [] for camera []", closestDist, C.name) + var/zmatched = 0 + if (closestDist > 7 || closestDist == -1) + //check other cameras + var/obj/machinery/camera/closest = C + for(var/obj/machinery/camera/C2 in world) + if (C2.network == src.network) + if (C2.z == target.z) + zmatched = 1 + if (C2.status) + var/dist = get_dist(C2, target) + if ((dist < closestDist) || (closestDist == -1)) + closestDist = dist + closest = C2 + //usr << text("Closest camera dist = [], for camera []", closestDist, closest.area.name) + + if (closest != C) + usr:current = closest + usr.reset_view(closest) + //use_power(50) + if (zmatched == 0) + usr << "Target is not on or near any active cameras on the station. We'll check again in 5 seconds (unless you use the cancel-camera verb)." + sleep(40) //because we're sleeping another second after this (a few lines down) + else + usr << "Follow camera mode ended." + usr:cameraFollow = null + + sleep(10) + +/proc/camera_sort(list/L) + var/obj/machinery/camera/a + var/obj/machinery/camera/b + + for (var/i = L.len, i > 0, i--) + for (var/j = 1 to i - 1) + a = L[j] + b = L[j + 1] + if (a.c_tag_order != b.c_tag_order) + if (a.c_tag_order > b.c_tag_order) + L.Swap(j, j + 1) + else + if (sorttext(a.c_tag, b.c_tag) < 0) + L.Swap(j, j + 1) + return L + +/obj/machinery/computer/security/attack_hand(var/mob/user as mob) + if (stat & (NOPOWER|BROKEN)) + return + + user.machine = src + + var/list/L = list() + for (var/obj/machinery/camera/C in world) + L.Add(C) + + camera_sort(L) + + var/list/D = list() + D["Cancel"] = "Cancel" + for (var/obj/machinery/camera/C in L) + if (C.network == src.network) + D[text("[][]", C.c_tag, (C.status ? null : " (Deactivated)"))] = C + + var/t = input(user, "Which camera should you change to?") as null|anything in D + + if(!t) + user.machine = null + return 0 + + var/obj/machinery/camera/C = D[t] + + if (t == "Cancel") + user.machine = null + return 0 + + if ((get_dist(user, src) > 1 || user.machine != src || user.blinded || !( user.canmove ) || !( C.status )) && (!istype(user, /mob/living/silicon/ai))) + return 0 + else + src.current = C + use_power(50) + + spawn( 5 ) + attack_hand(user) + +/mob/living/silicon/ai/attack_ai(var/mob/user as mob) + if (user != src) + return + + if (stat == 2) + return + + user.machine = src + + var/list/L = list() + for (var/obj/machinery/camera/C in world) + L.Add(C) + + camera_sort(L) + + var/list/D = list() + D["Cancel"] = "Cancel" + for (var/obj/machinery/camera/C in L) + if (C.network == src.network) + D[text("[][]", C.c_tag, (C.status ? null : " (Deactivated)"))] = C + + var/t = input(user, "Which camera should you change to?") as null|anything in D + + if (!t || t == "Cancel") + switchCamera(null) + return 0 + + var/obj/machinery/camera/C = D[t] + + switchCamera(C) + + return + +/obj/machinery/camera/ex_act(severity) + if(src.invuln) + return + else + ..(severity) + return + +/obj/machinery/camera/blob_act() + return + +/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user as mob) + if (src.network != user.network || !(src.status)) + return + user.current = src + user.reset_view(src) + +/obj/machinery/camera/attackby(W as obj, user as mob) + if (istype(W, /obj/item/weapon/wirecutters)) + src.status = !( src.status ) + if (!( src.status )) + for(var/mob/O in viewers(user, null)) + O.show_message(text("\red [] has deactivated []!", user, src), 1) + playsound(src.loc, 'Wirecutter.ogg', 100, 1) + src.icon_state = "camera1" + else + for(var/mob/O in viewers(user, null)) + O.show_message(text("\red [] has reactivated []!", user, src), 1) + playsound(src.loc, 'Wirecutter.ogg', 100, 1) + src.icon_state = "camera" + // now disconnect anyone using the camera + for(var/mob/living/silicon/ai/O in world) + if (O.current == src) + O.cancel_camera() + O << "Your connection to the camera has been lost." + for(var/mob/O in world) + if (istype(O.machine, /obj/machinery/computer/security)) + var/obj/machinery/computer/security/S = O.machine + if (S.current == src) + O.machine = null + S.current = null + O.reset_view(null) + O << "The screen bursts into static." + else if (istype(W, /obj/item/weapon/paper)) + var/obj/item/weapon/paper/X = W + user << "You hold a paper up to the camera ..." + for(var/mob/living/silicon/ai/O in world) + //if (O.current == src) + O << "[user] holds a paper up to one of your cameras ..." + O << browse(text("[][]", X.name, X.info), text("window=[]", X.name)) + for(var/mob/O in world) + if (istype(O.machine, /obj/machinery/computer/security)) + var/obj/machinery/computer/security/S = O.machine + if (S.current == src) + O << "[user] holds a paper up to one of the cameras ..." + O << browse(text("[][]", X.name, X.info), text("window=[]", X.name)) + else if (istype(W, /obj/item/weapon/camera_bug)) + if (!src.status) + user << "\blue Camera non-functional" + return + if (src.bugged) + user << "\blue Camera bug removed." + src.bugged = 0 + else + user << "\blue Camera bugged." + src.bugged = 1 + return + + +//Return a working camera that can see a given mob +//or null if none +/proc/seen_by_camera(var/mob/M) + + for(var/obj/machinery/camera/C in oview(M)) + if(C.status) // check if camera disabled + return C + break + + return null diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm new file mode 100644 index 0000000000000..921b9c3ec7a5b --- /dev/null +++ b/code/game/machinery/cell_charger.dm @@ -0,0 +1,64 @@ +/obj/machinery/cell_charger/attackby(obj/item/weapon/W, mob/user) + if(stat & BROKEN) + return + + if(istype(W, /obj/item/weapon/cell)) + if(charging) + user << "There is already a cell in the charger." + return + else + user.drop_item() + W.loc = src + charging = W + user.visible_message("[user] inserts a cell into the charger.", "You insert a cell into the charger.") + chargelevel = -1 + updateicon() + +/obj/machinery/cell_charger/proc/updateicon() + icon_state = "ccharger[charging ? 1 : 0]" + + if(charging && !(stat & (BROKEN|NOPOWER)) ) + + var/newlevel = round( charging.percent() * 4.0 / 99 ) + //world << "nl: [newlevel]" + + if(chargelevel != newlevel) + + overlays = null + overlays += image('power.dmi', "ccharger-o[newlevel]") + + chargelevel = newlevel + else + overlays = null + +/obj/machinery/cell_charger/attack_hand(mob/user) + add_fingerprint(user) + + if(stat & BROKEN) + return + + if(charging) + charging.loc = usr + charging.layer = 20 + if (user.hand ) + user.l_hand = charging + else + user.r_hand = charging + + charging.add_fingerprint(user) + charging.updateicon() + + src.charging = null + user.visible_message("[user] removes the cell from the charger.", "You remove the cell from the charger.") + chargelevel = -1 + updateicon() + +/obj/machinery/cell_charger/process() + //world << "ccpt [charging] [stat]" + if(!charging || (stat & (BROKEN|NOPOWER)) ) + return + + var/added = charging.give(50) + use_power(added / CELLRATE) + + updateicon() \ No newline at end of file diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm new file mode 100644 index 0000000000000..4651bb264be65 --- /dev/null +++ b/code/game/machinery/computer/Operating.dm @@ -0,0 +1,69 @@ +/obj/machinery/computer/operating/New() + ..() + for(var/obj/machinery/optable/O in world) + if(src.id == O.id) + src.table = O + +/obj/machinery/computer/operating/attack_ai(mob/user) + add_fingerprint(user) + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + +/obj/machinery/computer/operating/attack_hand(mob/user) + add_fingerprint(user) + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + + +/obj/machinery/computer/operating/proc/interact(mob/user) + if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) + if (!istype(user, /mob/living/silicon)) + user.machine = null + user << browse(null, "window=op") + return + + user.machine = src + var/dat = "Operating Computer\n" + dat += "Close

      " //| Update" + if(src.table && (src.table.check_victim())) + src.victim = src.table.victim + dat += {" +Patient Information:
      +
      +Name: [src.victim.real_name]
      +Age: [src.victim.age]
      +Blood Type: [src.victim.b_type]
      +
      +Health: [src.victim.health]
      +Brute Damage: [src.victim.bruteloss]
      +Toxins Damage: [src.victim.toxloss]
      +Fire Damage: [src.victim.fireloss]
      +Suffocation Damage: [src.victim.oxyloss]
      +Patient Status: [src.victim.stat ? "Non-responsive" : "Stable"]
      +"} + else + src.victim = null + dat += {" +Patient Information:
      +
      +No Patient Detected +"} + user << browse(dat, "window=op") + onclose(user, "op") + +/obj/machinery/computer/operating/Topic(href, href_list) + if(..()) + return + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.machine = src +// if (href_list["update"]) +// src.interact(usr) + return + +/obj/machinery/computer/operating/process() + if(!(stat & (NOPOWER|BROKEN)) ) + use_power(500) + + src.updateDialog() \ No newline at end of file diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm new file mode 100644 index 0000000000000..461036e4fb95f --- /dev/null +++ b/code/game/machinery/computer/arcade.dm @@ -0,0 +1,196 @@ +/obj/machinery/computer/arcade/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/arcade/M = new /obj/item/weapon/circuitboard/arcade( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/arcade/M = new /obj/item/weapon/circuitboard/arcade( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + +/obj/machinery/computer/arcade/New() + ..() + var/name_action + var/name_part1 + var/name_part2 + + name_action = pick("Defeat ", "Annihilate ", "Save ", "Strike ", "Stop ", "Destroy ", "Robust ", "Romance ") + + name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Evil ", "the Dread King ", "the Space ", "Lord ") + name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon") + + src.enemy_name = dd_replacetext((name_part1 + name_part2), "the ", "") + src.name = (name_action + name_part1 + name_part2) + + +/obj/machinery/computer/arcade/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/arcade/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/arcade/attack_hand(mob/user as mob) + if(..()) + return + user.machine = src + var/dat = "Close" + dat += "

      [src.enemy_name]

      " + + dat += "

      [src.temp]

      " + dat += "
      Health: [src.player_hp] | Magic: [src.player_mp] | Enemy Health: [src.enemy_hp]
      " + + if (src.gameover) + dat += "
      New Game" + else + dat += "
      Attack | " + dat += "Heal | " + dat += "Recharge Power" + + dat += "
      " + + user << browse(dat, "window=arcade") + onclose(user, "arcade") + return + +/obj/machinery/computer/arcade/Topic(href, href_list) + if(..()) + return + + if (!src.blocked) + if (href_list["attack"]) + src.blocked = 1 + var/attackamt = rand(2,6) + src.temp = "You attack for [attackamt] damage!" + src.updateUsrDialog() + + sleep(10) + src.enemy_hp -= attackamt + src.arcade_action() + + else if (href_list["heal"]) + src.blocked = 1 + var/pointamt = rand(1,3) + var/healamt = rand(6,8) + src.temp = "You use [pointamt] magic to heal for [healamt] damage!" + src.updateUsrDialog() + + sleep(10) + src.player_mp -= pointamt + src.player_hp += healamt + src.blocked = 1 + src.updateUsrDialog() + src.arcade_action() + + else if (href_list["charge"]) + src.blocked = 1 + var/chargeamt = rand(4,7) + src.temp = "You regain [chargeamt] points" + src.player_mp += chargeamt + + src.updateUsrDialog() + sleep(10) + src.arcade_action() + + if (href_list["close"]) + usr.machine = null + usr << browse(null, "window=arcade") + + else if (href_list["newgame"]) //Reset everything + temp = "New Round" + player_hp = 30 + player_mp = 10 + enemy_hp = 45 + enemy_mp = 20 + gameover = 0 + + src.add_fingerprint(usr) + src.updateUsrDialog() + return + +/obj/machinery/computer/arcade/proc/arcade_action() + if ((src.enemy_mp <= 0) || (src.enemy_hp <= 0)) + src.gameover = 1 + src.temp = "[src.enemy_name] has fallen! Rejoice!" + var/obj/item/prize + var/prizeselect = pick(1,2,4) + switch(prizeselect) + if(1) + prize = new /obj/item/weapon/spacecash(src.loc) + prize.name = "space ticket" + prize.desc = "It's almost like actual currency!" + if(2) + prize = new /obj/item/device/radio/beacon(src.loc) + prize.name = "electronic blink toy game" + prize.desc = "Blink. Blink. Blink." +// if(3) +// prize = new /obj/item/weapon/zippo(src.loc) +// prize.name = "Burno Lighter" +// prize.desc = "Almost like a decent lighter!" + if(4) + prize = new /obj/item/weapon/c_tube(src.loc) + prize.name = "toy sword" + prize.icon = 'weapons.dmi' + prize.icon_state = "sword1" + prize.desc = "A sword made of cheap plastic." + + else if ((src.enemy_mp <= 5) && (prob(70))) + var/stealamt = rand(2,3) + src.temp = "[src.enemy_name] steals [stealamt] of your power!" + src.player_mp -= stealamt + src.updateUsrDialog() + + if (src.player_mp <= 0) + src.gameover = 1 + sleep(10) + src.temp = "You have been drained! GAME OVER" + + else if ((src.enemy_hp <= 10) && (src.enemy_mp > 4)) + src.temp = "[src.enemy_name] heals for 4 health!" + src.enemy_hp += 4 + src.enemy_mp -= 4 + + else + var/attackamt = rand(3,6) + src.temp = "[src.enemy_name] attacks for [attackamt] damage!" + src.player_hp -= attackamt + + if ((src.player_mp <= 0) || (src.player_hp <= 0)) + src.gameover = 1 + src.temp = "You have been crushed! GAME OVER" + + src.blocked = 0 + return + +/obj/machinery/computer/arcade/power_change() + + if(stat & BROKEN) + icon_state = "arcadeb" + else + if( powered() ) + icon_state = initial(icon_state) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + src.icon_state = "arcade0" + stat |= NOPOWER \ No newline at end of file diff --git a/code/game/machinery/computer/atmos.dm b/code/game/machinery/computer/atmos.dm new file mode 100644 index 0000000000000..f5953acbdd0a4 --- /dev/null +++ b/code/game/machinery/computer/atmos.dm @@ -0,0 +1,119 @@ +/*CONTENTS +Gas Sensor +Siphon computer +Atmos alert computer +*/ + + + +//the atmos alerts computer +/obj/machinery/computer/atmosphere/alerts/attack_ai(mob/user) + add_fingerprint(user) + + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + +/obj/machinery/computer/atmosphere/alerts/attack_hand(mob/user) + add_fingerprint(user) + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + +/obj/machinery/computer/atmosphere/alerts/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/atmospherealerts/M = new /obj/item/weapon/circuitboard/atmospherealerts( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/atmospherealerts/M = new /obj/item/weapon/circuitboard/atmospherealerts( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + + +/obj/machinery/computer/atmosphere/alerts/proc/interact(mob/user) + usr.machine = src + var/dat = "Current Station Alerts\n" + dat += "Close

      " + for (var/cat in src.alarms) + dat += text("[]
      \n", cat) + var/list/L = src.alarms[cat] + if (L.len) + for (var/alarm in L) + var/list/alm = L[alarm] + var/area/A = alm[1] + var/list/sources = alm[3] + dat += "" + dat += "[A.name]" + if (sources.len > 1) + dat += text("- [] sources", sources.len) + dat += "
      \n" + else + dat += "-- All Systems Nominal
      \n" + dat += "
      \n" + user << browse(dat, "window=alerts") + onclose(user, "alerts") + +/obj/machinery/computer/atmosphere/alerts/Topic(href, href_list) + if(..()) + return + return + +/obj/machinery/computer/atmosphere/alerts/proc/triggerAlarm(var/class, area/A, var/O, var/alarmsource) + if(stat & (BROKEN|NOPOWER)) + return + var/list/L = src.alarms[class] + for (var/I in L) + if (I == A.name) + var/list/alarm = L[I] + var/list/sources = alarm[3] + if (!(alarmsource in sources)) + sources += alarmsource + return 1 + var/obj/machinery/camera/C = null + var/list/CL = null + if (O && istype(O, /list)) + CL = O + if (CL.len == 1) + C = CL[1] + else if (O && istype(O, /obj/machinery/camera)) + C = O + L[A.name] = list(A, (C) ? C : O, list(alarmsource)) + return 1 + +/obj/machinery/computer/atmosphere/alerts/proc/cancelAlarm(var/class, area/A as area, obj/origin) + if(stat & (BROKEN|NOPOWER)) + return + var/list/L = src.alarms[class] + var/cleared = 0 + for (var/I in L) + if (I == A.name) + var/list/alarm = L[I] + var/list/srcs = alarm[3] + if (origin in srcs) + srcs -= origin + if (srcs.len == 0) + cleared = 1 + L -= I + return !cleared \ No newline at end of file diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm new file mode 100644 index 0000000000000..31cde6b4c43ff --- /dev/null +++ b/code/game/machinery/computer/buildandrepair.dm @@ -0,0 +1,191 @@ +/obj/computerframe + density = 1 + anchored = 0 + name = "Computer-frame" + icon = 'computer_frame.dmi' + icon_state = "0" + var/state = 0 + var/obj/item/weapon/circuitboard/circuit = null +// weight = 1.0E8 + +/obj/item/weapon/circuitboard + density = 0 + anchored = 0 + w_class = 2.0 + name = "Circuit board" + icon = 'module.dmi' + icon_state = "id_mod" + item_state = "electronic" + var/id = null + var/frequency = null + var/computertype = null + var/powernet = null + var/list/records = null + +/obj/item/weapon/circuitboard/security + name = "Circuit board (Security)" + computertype = "/obj/machinery/computer/security" +/obj/item/weapon/circuitboard/aiupload + name = "Circuit board (AI Upload)" + computertype = "/obj/machinery/computer/aiupload" +/obj/item/weapon/circuitboard/med_data + name = "Circuit board (Medical)" + computertype = "/obj/machinery/computer/med_data" +/obj/item/weapon/circuitboard/scan_consolenew + name = "Circuit board (DNA Machine)" + computertype = "/obj/machinery/scan_consolenew" +/obj/item/weapon/circuitboard/communications + name = "Circuit board (Communications)" + computertype = "/obj/machinery/computer/communications" +/obj/item/weapon/circuitboard/card + name = "Circuit board (ID Computer)" + computertype = "/obj/machinery/computer/card" +//obj/item/weapon/circuitboard/shield +// name = "Circuit board (Shield Control)" +// computertype = "/obj/machinery/computer/stationshield" +/obj/item/weapon/circuitboard/teleporter + name = "Circuit board (Teleporter)" + computertype = "/obj/machinery/computer/teleporter" +/obj/item/weapon/circuitboard/secure_data + name = "Circuit board (Secure Data)" + computertype = "/obj/machinery/computer/secure_data" +/obj/item/weapon/circuitboard/atmospherealerts + name = "Circuit board (Atmosphere alerts)" + computertype = "/obj/machinery/computer/atmosphere/alerts" +/obj/item/weapon/circuitboard/atmospheresiphonswitch + name = "Circuit board (Atmosphere siphon control)" + computertype = "/obj/machinery/computer/atmosphere/siphonswitch" +/obj/item/weapon/circuitboard/air_management + name = "Circuit board (Atmospheric monitor)" + computertype = "/obj/machinery/computer/general_air_control" +/obj/item/weapon/circuitboard/injector_control + name = "Circuit board (Injector control)" + computertype = "/obj/machinery/computer/general_air_control/fuel_injection" +/obj/item/weapon/circuitboard/general_alert + name = "Circuit board (General Alert)" + computertype = "/obj/machinery/computer/general_alert" +/obj/item/weapon/circuitboard/pod + name = "Circuit board (Massdriver control)" + computertype = "/obj/machinery/computer/pod" +/obj/item/weapon/circuitboard/robotics + name = "Circuit board (Robotics Control)" + computertype = "/obj/machinery/computer/robotics" +/obj/item/weapon/circuitboard/cloning + name = "Circuit board (Cloning)" + computertype = "/obj/machinery/computer/cloning" +/obj/item/weapon/circuitboard/arcade + name = "Circuit board (Arcade)" + computertype = "/obj/machinery/computer/arcade" +/obj/item/weapon/circuitboard/turbine_control + name = "Circuit board (Turbine control)" + computertype = "/obj/machinery/computer/turbine_computer" +/obj/item/weapon/circuitboard/solar_control + name = "Circuit board (Door control)" + computertype = "/obj/machinery/power/solar_control" +/obj/item/weapon/circuitboard/powermonitor + name = "Circuit board (Massdriver control)" + computertype = "/obj/machinery/power/monitor" +/obj/item/weapon/circuitboard/olddoor + name = "Circuit board (DoorMex)" + computertype = "/obj/machinery/computer/pod/old" +/obj/item/weapon/circuitboard/syndicatedoor + name = "Circuit board (ProComp Executive)" + computertype = "/obj/machinery/computer/pod/old/syndicate" +/obj/item/weapon/circuitboard/swfdoor + name = "Circuit board (Magix)" + computertype = "/obj/machinery/computer/pod/old/swf" + + + +/obj/computerframe/attackby(obj/item/weapon/P as obj, mob/user as mob) + switch(state) + if(0) + if(istype(P, /obj/item/weapon/wrench)) + playsound(src.loc, 'Ratchet.ogg', 50, 1) + if(do_after(user, 20)) + user << "\blue You wrench the frame into place." + src.anchored = 1 + src.state = 1 + if(istype(P, /obj/item/weapon/weldingtool)) + playsound(src.loc, 'Welder.ogg', 50, 1) + if(do_after(user, 20)) + user << "\blue You deconstruct the frame." + var/obj/item/weapon/sheet/metal/A = new /obj/item/weapon/sheet/metal( src.loc ) + A.amount = 5 + del(src) + if(1) + if(istype(P, /obj/item/weapon/wrench)) + playsound(src.loc, 'Ratchet.ogg', 50, 1) + if(do_after(user, 20)) + user << "\blue You unfasten the frame." + src.anchored = 0 + src.state = 0 + if(istype(P, /obj/item/weapon/circuitboard) && !circuit) + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + user << "\blue You place the circuit board inside the frame." + src.icon_state = "1" + src.circuit = P + user.drop_item() + P.loc = src + if(istype(P, /obj/item/weapon/screwdriver) && circuit) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + user << "\blue You screw the circuit board into place." + src.state = 2 + src.icon_state = "2" + if(istype(P, /obj/item/weapon/crowbar) && circuit) + playsound(src.loc, 'Crowbar.ogg', 50, 1) + user << "\blue You remove the circuit board." + src.state = 1 + src.icon_state = "0" + circuit.loc = src.loc + src.circuit = null + if(2) + if(istype(P, /obj/item/weapon/screwdriver) && circuit) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + user << "\blue You unfasten the circuit board." + src.state = 1 + src.icon_state = "1" + if(istype(P, /obj/item/weapon/cable_coil)) + if(P:amount >= 5) + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + if(do_after(user, 20)) + P:amount -= 5 + if(!P:amount) del(P) + user << "\blue You add cables to the frame." + src.state = 3 + src.icon_state = "3" + if(3) + if(istype(P, /obj/item/weapon/wirecutters)) + playsound(src.loc, 'wirecutter.ogg', 50, 1) + user << "\blue You remove the cables." + src.state = 2 + src.icon_state = "2" + var/obj/item/weapon/cable_coil/A = new /obj/item/weapon/cable_coil( src.loc ) + A.amount = 5 + + if(istype(P, /obj/item/weapon/sheet/glass)) + if(P:amount >= 2) + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + if(do_after(user, 20)) + P:amount -= 2 + if(!P:amount) del(P) + user << "\blue You put in the glass panel." + src.state = 4 + src.icon_state = "4" + if(4) + if(istype(P, /obj/item/weapon/crowbar)) + playsound(src.loc, 'Crowbar.ogg', 50, 1) + user << "\blue You remove the glass panel." + src.state = 3 + src.icon_state = "3" + var/obj/item/weapon/sheet/glass/A = new /obj/item/weapon/sheet/glass( src.loc ) + A.amount = 2 + if(istype(P, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + user << "\blue You connect the monitor." + var/B = new src.circuit.computertype ( src.loc ) + if(circuit.powernet) B:powernet = circuit.powernet + if(circuit.id) B:id = circuit.id + if(circuit.records) B:records = circuit.records + if(circuit.frequency) B:frequency = circuit.frequency + del(src) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm new file mode 100644 index 0000000000000..889f33a6c568b --- /dev/null +++ b/code/game/machinery/computer/communications.dm @@ -0,0 +1,447 @@ +// The communications computer + +/obj/machinery/computer/communications/process() + ..() + if(state != STATE_STATUSDISPLAY) + src.updateDialog() + +/obj/machinery/computer/communications/Topic(href, href_list) + if(..()) + return + usr.machine = src + + if(!href_list["operation"]) + return + switch(href_list["operation"]) + // main interface + if("main") + src.state = STATE_DEFAULT + if("login") + var/mob/M = usr + var/obj/item/weapon/card/id/I = M.equipped() + if (I && istype(I)) + if(src.check_access(I)) + authenticated = 1 + if("logout") + authenticated = 0 + if("nolockdown") + disablelockdown(usr) + post_status("alert", "default") + if("call-prison") + call_prison_shuttle(usr) + if("callshuttle") + src.state = STATE_DEFAULT + if(src.authenticated) + src.state = STATE_CALLSHUTTLE + if("callshuttle2") + if(src.authenticated) + call_shuttle_proc(usr) + + if(emergency_shuttle.online) + post_status("shuttle") + + src.state = STATE_DEFAULT + if("cancelshuttle") + src.state = STATE_DEFAULT + if(src.authenticated) + src.state = STATE_CANCELSHUTTLE + if("cancelshuttle2") + if(src.authenticated) + cancel_call_proc(usr) + src.state = STATE_DEFAULT + if("messagelist") + src.currmsg = 0 + src.state = STATE_MESSAGELIST + if("viewmessage") + src.state = STATE_VIEWMESSAGE + if (!src.currmsg) + if(href_list["message-num"]) + src.currmsg = text2num(href_list["message-num"]) + else + src.state = STATE_MESSAGELIST + if("delmessage") + src.state = (src.currmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST + if("delmessage2") + if(src.authenticated) + if(src.currmsg) + var/title = src.messagetitle[src.currmsg] + var/text = src.messagetext[src.currmsg] + src.messagetitle.Remove(title) + src.messagetext.Remove(text) + if(src.currmsg == src.aicurrmsg) + src.aicurrmsg = 0 + src.currmsg = 0 + src.state = STATE_MESSAGELIST + else + src.state = STATE_VIEWMESSAGE + if("status") + src.state = STATE_STATUSDISPLAY + + // Status display stuff + if("setstat") + switch(href_list["statdisp"]) + if("message") + post_status("message", stat_msg1, stat_msg2) + if("alert") + post_status("alert", href_list["alert"]) + else + post_status(href_list["statdisp"]) + + if("setmsg1") + stat_msg1 = input("Line 1", "Enter Message Text", stat_msg1) as text|null + src.updateDialog() + if("setmsg2") + stat_msg2 = input("Line 2", "Enter Message Text", stat_msg2) as text|null + src.updateDialog() + + // AI interface + if("ai-main") + src.aicurrmsg = 0 + src.aistate = STATE_DEFAULT + if("ai-callshuttle") + src.aistate = STATE_CALLSHUTTLE + if("ai-callshuttle2") + call_shuttle_proc(usr) + src.aistate = STATE_DEFAULT + if("ai-messagelist") + src.aicurrmsg = 0 + src.aistate = STATE_MESSAGELIST + if("ai-viewmessage") + src.aistate = STATE_VIEWMESSAGE + if (!src.aicurrmsg) + if(href_list["message-num"]) + src.aicurrmsg = text2num(href_list["message-num"]) + else + src.aistate = STATE_MESSAGELIST + if("ai-delmessage") + src.aistate = (src.aicurrmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST + if("ai-delmessage2") + if(src.aicurrmsg) + var/title = src.messagetitle[src.aicurrmsg] + var/text = src.messagetext[src.aicurrmsg] + src.messagetitle.Remove(title) + src.messagetext.Remove(text) + if(src.currmsg == src.aicurrmsg) + src.currmsg = 0 + src.aicurrmsg = 0 + src.aistate = STATE_MESSAGELIST + if("ai-status") + src.aistate = STATE_STATUSDISPLAY + src.updateUsrDialog() + +/proc/disablelockdown(var/mob/usr) + world << "\red Lockdown cancelled by [usr.name]!" + + for(var/obj/machinery/firealarm/FA in world) //deactivate firealarms + spawn( 0 ) + if(FA.lockdownbyai == 1) + FA.lockdownbyai = 0 + FA.reset() + for(var/obj/machinery/door/airlock/AL in world) //open airlocks + spawn ( 0 ) + if(AL.canAIControl() && AL.lockdownbyai == 1) + AL.open() + AL.lockdownbyai = 0 + +/obj/machinery/computer/communications/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/communications/M = new /obj/item/weapon/circuitboard/communications( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/communications/M = new /obj/item/weapon/circuitboard/communications( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + +/obj/machinery/computer/communications/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/communications/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/communications/attack_hand(var/mob/user as mob) + if(..()) + return + + user.machine = src + var/dat = "Communications Console " + if (emergency_shuttle.online && emergency_shuttle.location==0) + var/timeleft = emergency_shuttle.timeleft() + dat += "Emergency shuttle\n
      \nETA: [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]
      " + + if (istype(user, /mob/living/silicon)) + var/dat2 = src.interact_ai(user) // give the AI a different interact proc to limit its access + if(dat2) + dat += dat2 + user << browse(dat, "window=communications;size=400x500") + onclose(user, "communications") + return + + switch(src.state) + if(STATE_DEFAULT) + if (src.authenticated) + dat += "
      \[ Log Out \]" + dat += "
      \[ Send Prison Shutle \]" + dat += "
      \[ Disable Lockdown \]" + if(emergency_shuttle.location==0) + if (emergency_shuttle.online) + dat += "
      \[ Cancel Shuttle Call \]" + else + dat += "
      \[ Call Emergency Shuttle \]" + + dat += "
      \[ Set Status Display \]" + else + dat += "
      \[ Log In \]" + dat += "
      \[ Message List \]" + if(STATE_CALLSHUTTLE) + dat += "Are you sure you want to call the shuttle? \[ OK | Cancel \]" + if(STATE_CANCELSHUTTLE) + dat += "Are you sure you want to cancel the shuttle? \[ OK | Cancel \]" + if(STATE_MESSAGELIST) + dat += "Messages:" + for(var/i = 1; i<=src.messagetitle.len; i++) + dat += "
      [src.messagetitle[i]]" + if(STATE_VIEWMESSAGE) + if (src.currmsg) + dat += "[src.messagetitle[src.currmsg]]

      [src.messagetext[src.currmsg]]" + if (src.authenticated) + dat += "

      \[ Delete \]" + else + src.state = STATE_MESSAGELIST + src.attack_hand(user) + return + if(STATE_DELMESSAGE) + if (src.currmsg) + dat += "Are you sure you want to delete this message? \[ OK | Cancel \]" + else + src.state = STATE_MESSAGELIST + src.attack_hand(user) + return + if(STATE_STATUSDISPLAY) + dat += "Set Status Displays
      " + dat += "\[ Clear \]
      " + dat += "\[ Shuttle ETA \]
      " + dat += "\[ Message \]" + dat += "
      " + dat += "\[ Alert: None |" + dat += " Red Alert |" + dat += " Lockdown |" + dat += " Biohazard \]

      " + + + dat += "
      \[ [(src.state != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]" + user << browse(dat, "window=communications;size=400x500") + onclose(user, "communications") + +/obj/machinery/computer/communications/proc/interact_ai(var/mob/living/silicon/ai/user as mob) + var/dat = "" + switch(src.aistate) + if(STATE_DEFAULT) + if(emergency_shuttle.location==0 && !emergency_shuttle.online) + dat += "
      \[ Call Emergency Shuttle \]" + dat += "
      \[ Send Prison Shutle \]" + dat += "
      \[ Message List \]" + dat += "
      \[ Disable Lockdown \]" + dat += "
      \[ Set Status Display \]" + if(STATE_CALLSHUTTLE) + dat += "Are you sure you want to call the shuttle? \[ OK | Cancel \]" + if(STATE_MESSAGELIST) + dat += "Messages:" + for(var/i = 1; i<=src.messagetitle.len; i++) + dat += "
      [src.messagetitle[i]]" + if(STATE_VIEWMESSAGE) + if (src.aicurrmsg) + dat += "[src.messagetitle[src.aicurrmsg]]

      [src.messagetext[src.aicurrmsg]]" + dat += "

      \[ Delete \]" + else + src.aistate = STATE_MESSAGELIST + src.attack_hand(user) + return null + if(STATE_DELMESSAGE) + if(src.aicurrmsg) + dat += "Are you sure you want to delete this message? \[ OK | Cancel \]" + else + src.aistate = STATE_MESSAGELIST + src.attack_hand(user) + return + + if(STATE_STATUSDISPLAY) + dat += "Set Status Displays
      " + dat += "\[ Clear \]
      " + dat += "\[ Shuttle ETA \]
      " + dat += "\[ Message \]" + dat += "
      " + dat += "\[ Alert: None |" + dat += " Red Alert |" + dat += " Lockdown |" + dat += " Biohazard \]

      " + + + dat += "
      \[ [(src.aistate != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]" + return dat + +/mob/living/silicon/ai/proc/ai_call_shuttle() + set category = "AI Commands" + set name = "Call Emergency Shuttle" + if(usr.stat == 2) + usr << "You can't call the shuttle because you are dead!" + return + call_shuttle_proc(src) + + // hack to display shuttle timer + if(emergency_shuttle.online) + var/obj/machinery/computer/communications/C = locate() in world + if(C) + C.post_status("shuttle") + + return + +/proc/call_prison_shuttle(var/mob/usr) + if ((!( ticker ) || emergency_shuttle.location == 1)) + return + if(ticker.mode.name == "blob" || ticker.mode.name == "Corporate Restructuring" || ticker.mode.name == "sandbox") + usr << "Under directive 7-10, [station_name()] is quarantined until further notice." + return + if(ticker.mode.name == "revolution") + usr << "Centcom will not allow the shuttle to be called, due to the possibility of sabotage by revolutionaries." + return + if(ticker.mode.name == "AI malfunction") + usr << "Centcom will not allow the shuttle to be called." + return + for(var/obj/machinery/computer/prison_shuttle/PS in world) + if(!PS.allowedtocall) + usr << "\red Centcom will not allow the shuttle to be called" + return + if(PS.z == 3) + usr << "\red Already in transit! Please wait!" + return + var/A = locate(/area/shuttle/prison/) + for(var/mob/M in A) + M.show_message("\red Launch sequence initiated!") + spawn(0) shake_camera(M, 10, 1) + sleep(10) + + if(PS.z == 2) //This is the laziest proc ever + for(var/atom/movable/AM as mob|obj in A) + AM.z = 3 + AM.Move() + sleep(rand(600,1800)) + for(var/atom/movable/AM as mob|obj in A) + AM.z = 1 + AM.Move() + else + for(var/atom/movable/AM as mob|obj in A) + AM.z = 3 + AM.Move() + sleep(rand(600,1800)) + for(var/atom/movable/AM as mob|obj in A) + AM.z = 2 + AM.Move() + for(var/mob/M in A) + M.show_message("\red Prison shuttle has arrived at destination!") + return + return + + +/proc/enable_prison_shuttle(var/mob/user) + for(var/obj/machinery/computer/prison_shuttle/PS in world) + PS.allowedtocall = !(PS.allowedtocall) + +/proc/call_shuttle_proc(var/mob/user) + if ((!( ticker ) || emergency_shuttle.location)) + return + + if(world.time < 6000) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE + user << "Centcomm will not allow the shuttle to be called." + if(ticker.mode.name == "blob" || ticker.mode.name == "Corporate Restructuring" || ticker.mode.name == "sandbox") + user << "Under directive 7-10, [station_name()] is quarantined until further notice." + return + if(ticker.mode.name == "revolution" || ticker.mode.name == "AI malfunction" || ticker.mode.name == "confliction") + user << "Centcom will not allow the shuttle to be called." + return + /* + if(ticker.mode.name == "nuclear emergency" && world.time < 6000) + user << "Centcom will not allow the shuttle to be called." + return + */ + + emergency_shuttle.incall() + world << "\blue Alert: The emergency shuttle has been called. It will arrive in [round(emergency_shuttle.timeleft()/60)] minutes." + + return + +/proc/cancel_call_proc(var/mob/user) + if ((!( ticker ) || emergency_shuttle.location || emergency_shuttle.direction == 0 || emergency_shuttle.timeleft() < 300)) + return + if( ticker.mode.name == "blob" ) + return + + world << "\blue Alert: The shuttle is going back!" //marker4 + + emergency_shuttle.recall() + + return + +/obj/machinery/computer/communications/proc/post_status(var/command, var/data1, var/data2) + + var/datum/radio_frequency/frequency = radio_controller.return_frequency(status_display_freq) + + if(!frequency) return + + + + var/datum/signal/status_signal = new + status_signal.source = src + status_signal.transmission_method = 1 + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + if("alert") + status_signal.data["picture_state"] = data1 + + frequency.post_signal(src, status_signal) + + + + /* + receive_signal(datum/signal/signal) + + switch(signal.data["command"]) + if("blank") + mode = 0 + + if("shuttle") + mode = 1 + + if("message") + set_message(signal.data["msg1"], signal.data["msg2"]) + + if("alert") + set_picture(signal.data["picture_state"]) +*/ \ No newline at end of file diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm new file mode 100644 index 0000000000000..2d3637430ff14 --- /dev/null +++ b/code/game/machinery/computer/computer.dm @@ -0,0 +1,586 @@ +/*CONTENTS +General Computer +Security Computer +Comm Computer +ID Computer +Pod/Blast Doors computer +*/ + +/obj/machinery/Topic(href, href_list) + ..() + if(stat & (NOPOWER|BROKEN)) + return 1 + if(usr.restrained() || usr.lying || usr.stat) + return 1 + if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") + if (!istype(usr, /mob/living/silicon)) + usr << "\red You don't have the dexterity to do this!" + return 1 + if ((!in_range(src, usr) || !istype(src.loc, /turf)) && !istype(usr, /mob/living/silicon)) + return 1 + src.add_fingerprint(usr) + return 0 + +/obj/machinery/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/attack_hand(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) + return 1 + if(user.lying || user.stat) + return 1 + if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") + if (!istype(user, /mob/living/silicon)) + usr << "\red You don't have the dexterity to do this!" + return 1 + if ((get_dist(src, user) > 1 || !istype(src.loc, /turf)) && !istype(user, /mob/living/silicon)) + return 1 + if (ishuman(user)) + if(user.brainloss >= 60) + for(var/mob/M in viewers(src, null)) + M << "\red [user] stares cluelessly at [src] and drools." + return 1 + else if(prob(user.brainloss)) + user << "\red You momentarily forget how to use [src]." + return 1 + + src.add_fingerprint(user) + return 0 + +/obj/machinery/computer/meteorhit(var/obj/O as obj) + for(var/x in src.verbs) + src.verbs -= x + set_broken() + var/datum/effects/system/harmless_smoke_spread/smoke = new /datum/effects/system/harmless_smoke_spread() + smoke.set_up(5, 0, src) + smoke.start() + return + +/obj/machinery/computer/ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(50)) + for(var/x in src.verbs) + src.verbs -= x + set_broken() + if(3.0) + if (prob(25)) + for(var/x in src.verbs) + src.verbs -= x + set_broken() + else + return + +/obj/machinery/computer/blob_act() + if (prob(50)) + for(var/x in src.verbs) + src.verbs -= x + set_broken() + src.density = 0 + +/obj/machinery/computer/power_change() + if(!istype(src,/obj/machinery/computer/security/telescreen)) + if(stat & BROKEN) + icon_state = initial(icon_state) + src.icon_state += "b" + + else if(powered()) + icon_state = initial(icon_state) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + //src.icon_state = "c_unpowered" + icon_state = initial(icon_state) + src.icon_state += "0" + stat |= NOPOWER + +/obj/machinery/computer/process() + if(stat & (NOPOWER|BROKEN)) + return + use_power(250) + +/obj/machinery/computer/proc/set_broken() + icon_state = initial(icon_state) + icon_state += "b" + stat |= BROKEN + +/obj/machinery/computer/security/New() + ..() + src.verbs -= /obj/machinery/computer/security/verb/station_map + +/obj/machinery/computer/security/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/security/M = new /obj/item/weapon/circuitboard/security( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/security/M = new /obj/item/weapon/circuitboard/security( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + +/obj/machinery/computer/security/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/security/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/security/check_eye(var/mob/user as mob) + if ((get_dist(user, src) > 1 || !( user.canmove ) || user.blinded || !( src.current ) || !( src.current.status )) && (!istype(user, /mob/living/silicon))) + return null + user.reset_view(src.current) + return 1 + + + +/obj/machinery/computer/card/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/card/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/card/attack_hand(var/mob/user as mob) + if(..()) + return + + user.machine = src + var/dat + if (!( ticker )) + return + if (src.mode) // accessing crew manifest + var/crew = "" + for(var/datum/data/record/t in data_core.general) + crew += "[t.fields["name"]] - [t.fields["rank"]]
      " + dat = "Crew Manifest:
      Please use security record computer to modify entries.
      [crew]Print

      Access ID modification console.
      " + else + var/header = "Identification Card Modifier
      Please insert the cards into the slots
      " + + var/target_name + var/target_owner + var/target_rank + if(src.modify) + target_name = src.modify.name + else + target_name = "--------" + if(src.modify && src.modify.registered) + target_owner = src.modify.registered + else + target_owner = "--------" + if(src.modify && src.modify.assignment) + target_rank = src.modify.assignment + else + target_rank = "Unassigned" + header += "Target: [target_name]
      " + + var/scan_name + if(src.scan) + scan_name = src.scan.name + else + scan_name = "--------" + header += "Confirm Identity: [scan_name]
      " + header += "
      " + var/body + if (src.authenticated && src.modify) + var/carddesc = "Registered: [target_owner]
      Assignment: [target_rank]" + var/list/alljobs = get_all_jobs() + "Custom" + var/jobs = "" + for(var/job in alljobs) + jobs += "[dd_replacetext(job, " ", " ")] " //make sure there isn't a line break in the middle of a job + var/accesses = "" + for(var/A in get_all_accesses()) + if(A in src.modify.access) + accesses += "[dd_replacetext(get_access_desc(A), " ", " ")] " + else + accesses += "[dd_replacetext(get_access_desc(A), " ", " ")] " + body = "[carddesc]
      [jobs]

      [accesses]" + else + body = "{Log in}" + dat = "[header][body]
      Access Crew Manifest
      " + user << browse(dat, "window=id_com;size=700x375") + onclose(user, "id_com") + return + +/obj/machinery/computer/card/Topic(href, href_list) + if(..()) + return + usr.machine = src + if (href_list["modify"]) + if (src.modify) + src.modify.name = text("[]'s ID Card ([])", src.modify.registered, src.modify.assignment) + src.modify.loc = src.loc + src.modify = null + else + var/obj/item/I = usr.equipped() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + src.modify = I + src.authenticated = 0 + if (href_list["scan"]) + if (src.scan) + src.scan.loc = src.loc + src.scan = null + else + var/obj/item/I = usr.equipped() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + src.scan = I + src.authenticated = 0 + if (href_list["auth"]) + if ((!( src.authenticated ) && (src.scan || (istype(usr, /mob/living/silicon))) && (src.modify || src.mode))) + if (src.check_access(src.scan)) + src.authenticated = 1 + else if ((!( src.authenticated ) && (istype(usr, /mob/living/silicon))) && (!src.modify)) + usr << "You can't modify an ID without an ID inserted to modify. Once one is in the modify slot on the computer, you can log in." + if(href_list["access"] && href_list["allowed"]) + if(src.authenticated) + var/access_type = text2num(href_list["access"]) + var/access_allowed = text2num(href_list["allowed"]) + if(access_type in get_all_accesses()) + src.modify.access -= access_type + if(access_allowed == 1) + src.modify.access += access_type + if (href_list["assign"]) + if (src.authenticated) + var/t1 = href_list["assign"] + if(t1 == "Custom") + t1 = input("Enter a custom job assignment.","Assignment") + else + src.modify.access = get_access(t1) + src.modify.assignment = t1 + if (href_list["reg"]) + if (src.authenticated) + var/t2 = src.modify + var/t1 = input(usr, "What name?", "ID computer", null) as text + if ((src.authenticated && src.modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(src.loc, /turf))) + src.modify.registered = t1 + if (href_list["mode"]) + src.mode = text2num(href_list["mode"]) + if (href_list["print"]) + if (!( src.printing )) + src.printing = 1 + sleep(50) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( src.loc ) + var/t1 = "Crew Manifest:
      " + for(var/datum/data/record/t in data_core.general) + t1 += "[t.fields["name"]] - [t.fields["rank"]]
      " + P.info = t1 + P.name = "paper- 'Crew Manifest'" + src.printing = null + if (href_list["mode"]) + src.authenticated = 0 + src.mode = text2num(href_list["mode"]) + if (src.modify) + src.modify.name = text("[]'s ID Card ([])", src.modify.registered, src.modify.assignment) + src.updateUsrDialog() + return + +/obj/machinery/computer/card/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/card/M = new /obj/item/weapon/circuitboard/card( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/card/M = new /obj/item/weapon/circuitboard/card( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + +/obj/datacore/proc/manifest() + for(var/mob/living/carbon/human/H in world) + if (!isnull(H.mind) && (H.mind.assigned_role != "MODE")) + var/datum/data/record/G = new /datum/data/record( ) + var/datum/data/record/M = new /datum/data/record( ) + var/datum/data/record/S = new /datum/data/record( ) + var/obj/item/weapon/card/id/C = H.wear_id + if (C) + G.fields["rank"] = C.assignment + else + G.fields["rank"] = "Unassigned" + G.fields["name"] = H.real_name + G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6)) + M.fields["name"] = G.fields["name"] + M.fields["id"] = G.fields["id"] + S.fields["name"] = G.fields["name"] + S.fields["id"] = G.fields["id"] + if (H.gender == FEMALE) + G.fields["sex"] = "Female" + else + G.fields["sex"] = "Male" + G.fields["age"] = text("[]", H.age) + G.fields["fingerprint"] = text("[]", md5(H.dna.uni_identity)) + G.fields["p_stat"] = "Active" + G.fields["m_stat"] = "Stable" + M.fields["b_type"] = text("[]", H.b_type) + M.fields["mi_dis"] = "None" + M.fields["mi_dis_d"] = "No minor disabilities have been declared." + M.fields["ma_dis"] = "None" + M.fields["ma_dis_d"] = "No major disabilities have been diagnosed." + M.fields["alg"] = "None" + M.fields["alg_d"] = "No allergies have been detected in this patient." + M.fields["cdi"] = "None" + M.fields["cdi_d"] = "No diseases have been diagnosed at the moment." + M.fields["notes"] = "No notes." + S.fields["criminal"] = "None" + S.fields["mi_crim"] = "None" + S.fields["mi_crim_d"] = "No minor crime convictions." + S.fields["ma_crim"] = "None" + S.fields["ma_crim_d"] = "No major crime convictions." + S.fields["notes"] = "No notes." + src.general += G + src.medical += M + src.security += S + //Foreach goto(15) + return + +/obj/machinery/computer/pod/proc/alarm() + if(stat & (NOPOWER|BROKEN)) + return + + if (!( src.connected )) + viewers(null, null) << "Cannot locate mass driver connector. Cancelling firing sequence!" + return + for(var/obj/machinery/door/poddoor/M in machines) + if (M.id == src.id) + spawn( 0 ) + M.open() + return + sleep(20) + + //src.connected.drive() *****RM from 40.93.3S + for(var/obj/machinery/mass_driver/M in machines) + if(M.id == src.id) + M.power = src.connected.power + M.drive() + + sleep(50) + for(var/obj/machinery/door/poddoor/M in machines) + if (M.id == src.id) + spawn( 0 ) + M.close() + return + return + +/obj/machinery/computer/pod/New() + ..() + spawn( 5 ) + for(var/obj/machinery/mass_driver/M in machines) + if (M.id == src.id) + src.connected = M + else + return + return + +/obj/machinery/computer/pod/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + + //generate appropriate circuitboard. Accounts for /pod/old computer types + var/obj/item/weapon/circuitboard/pod/M = null + if(istype(src, /obj/machinery/computer/pod/old)) + M = new /obj/item/weapon/circuitboard/olddoor( A ) + if(istype(src, /obj/machinery/computer/pod/old/syndicate)) + M = new /obj/item/weapon/circuitboard/syndicatedoor( A ) + if(istype(src, /obj/machinery/computer/pod/old/swf)) + M = new /obj/item/weapon/circuitboard/swfdoor( A ) + else //it's not an old computer. Generate standard pod circuitboard. + M = new /obj/item/weapon/circuitboard/pod( A ) + + for (var/obj/C in src) + C.loc = src.loc + M.id = src.id + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + + //generate appropriate circuitboard. Accounts for /pod/old computer types + var/obj/item/weapon/circuitboard/pod/M = null + if(istype(src, /obj/machinery/computer/pod/old)) + M = new /obj/item/weapon/circuitboard/olddoor( A ) + if(istype(src, /obj/machinery/computer/pod/old/syndicate)) + M = new /obj/item/weapon/circuitboard/syndicatedoor( A ) + if(istype(src, /obj/machinery/computer/pod/old/swf)) + M = new /obj/item/weapon/circuitboard/swfdoor( A ) + else //it's not an old computer. Generate standard pod circuitboard. + M = new /obj/item/weapon/circuitboard/pod( A ) + + for (var/obj/C in src) + C.loc = src.loc + M.id = src.id + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + +/obj/machinery/computer/pod/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/pod/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/pod/attack_hand(var/mob/user as mob) + if(..()) + return + + var/dat = "Mass Driver Controls" + user.machine = src + var/d2 + if (src.timing) + d2 = text("Stop Time Launch", src) + else + d2 = text("Initiate Time Launch", src) + var/second = src.time % 60 + var/minute = (src.time - second) / 60 + dat += text("
      \nTimer System: []\nTime Left: [][] - - + +", d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + if (src.connected) + var/temp = "" + var/list/L = list( 0.25, 0.5, 1, 2, 4, 8, 16 ) + for(var/t in L) + if (t == src.connected.power) + temp += text("[] ", t) + else + temp += text("[] ", src, t, t) + //Foreach goto(172) + dat += text("
      \nPower Level: []
      \nFiring Sequence
      \nTest Fire Driver
      \nToggle Outer Door
      ", temp, src, src, src) + //*****RM from 40.93.3S + else + dat += text("
      \nToggle Outer Door
      ", src) + //***** + dat += text("

      Close
      ", user) + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + +/obj/machinery/computer/pod/process() + ..() + if (src.timing) + if (src.time > 0) + src.time = round(src.time) - 1 + else + alarm() + src.time = 0 + src.timing = 0 + src.updateDialog() + return + +/obj/machinery/computer/pod/Topic(href, href_list) + if(..()) + return + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.machine = src + if (href_list["power"]) + var/t = text2num(href_list["power"]) + t = min(max(0.25, t), 16) + if (src.connected) + src.connected.power = t + else + if (href_list["alarm"]) + src.alarm() + else + if (href_list["time"]) + src.timing = text2num(href_list["time"]) + else + if (href_list["tp"]) + var/tp = text2num(href_list["tp"]) + src.time += tp + src.time = min(max(round(src.time), 0), 120) + else + if (href_list["door"]) + for(var/obj/machinery/door/poddoor/M in machines) + if (M.id == src.id) + if (M.density) + spawn( 0 ) + M.open() + return + else + spawn( 0 ) + M.close() + return + //Foreach goto(298) + src.add_fingerprint(usr) + src.updateUsrDialog() + + return + +/obj/machinery/mass_driver/proc/drive(amount) + if(stat & (BROKEN|NOPOWER)) + return + use_power(500) + var/O_limit + var/atom/target = get_edge_target_turf(src, src.dir) + for(var/atom/movable/O in src.loc) + if(!O.anchored) + O_limit++ + if(O_limit >= 20) + for(var/mob/M in hearers(src, null)) + M << "\blue The mass driver lets out a screech, it mustn't be able to handle any more items." + break + use_power(500) + spawn( 0 ) + O.throw_at(target, drive_range * src.power, src.power) + flick("mass_driver1", src) + return + + + diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm new file mode 100644 index 0000000000000..386fdecb1c576 --- /dev/null +++ b/code/game/machinery/computer/crew.dm @@ -0,0 +1,92 @@ +/obj/machinery/computer/crew + name = "crew monitoring computer" + icon_state = "comm" + + +/obj/machinery/computer/crew/attack_ai(mob/user) + add_fingerprint(user) + + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + +/obj/machinery/computer/crew/attack_hand(mob/user) + add_fingerprint(user) + + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + + +/obj/machinery/computer/crew/proc/interact(mob/user) + + if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) + if (!istype(user, /mob/living/silicon)) + user.machine = null + user << browse(null, "window=powcomp") + return + + + user.machine = src + var/t = "Crew Monitoring
      " + t += "" + var/list/tracked = list() + + for(var/obj/item/clothing/under/C in world) + if(istype(C.loc, /mob/living/carbon/human)) + tracked.Add(C.loc) + + for(var/mob/living/carbon/human/H in tracked) + for(var/obj/item/clothing/under/C in H) + if(H.z != 1 || istype(H.loc, /turf/space)) + if(C.mode > 0) + t += "" + break + switch(C.mode) + //if(0) + //t += "" + if(1) + t += "" + if(2) + t += "" + if(3) + var/turf/mob_loc = get_turf_loc(H) + t += "" + break + + t += "
      NameVitalsPosition
      [H.name]Not Available
      Not AvailableNot AvailableNot Available
      [H.name][H.stat > 1 ? "Deceased" : "Living"]Not Available
      [H.name][H.stat > 1 ? "Deceased" : "Living"], [H.oxyloss] - [H.toxloss] - [H.fireloss] - [H.bruteloss]Not Available
      [H.name][H.stat > 1 ? "Deceased" : "Living"], [H.oxyloss] - [H.toxloss] - [H.fireloss] - [H.bruteloss][mob_loc.loc] ([H.x], [H.y])
      " + t += "
      " + + t += "

      Close
      " + + user << browse(t, "window=crewcomp;size=420x700") + onclose(user, "crewcomp") + + +/obj/machinery/computer/crew/Topic(href, href_list) + ..() + if( href_list["close"] ) + usr << browse(null, "window=crewcomp") + usr.machine = null + return + +/obj/machinery/computer/crew/process() + if(!(stat & (NOPOWER|BROKEN)) ) + use_power(250) + + src.updateDialog() + + +/obj/machinery/computer/crew/power_change() + + if(stat & BROKEN) + icon_state = "broken" + else + if( powered() ) + icon_state = initial(icon_state) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + src.icon_state = "c_unpowered" + stat |= NOPOWER + diff --git a/code/game/machinery/computer/engine.dm b/code/game/machinery/computer/engine.dm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/code/game/machinery/computer/hologram.dm b/code/game/machinery/computer/hologram.dm new file mode 100644 index 0000000000000..a48c68394741f --- /dev/null +++ b/code/game/machinery/computer/hologram.dm @@ -0,0 +1,94 @@ +/obj/machinery/computer/hologram_comp/New() + ..() + spawn( 10 ) + src.projector = locate(/obj/machinery/hologram_proj, get_step(src.loc, NORTH)) + return + return + +/obj/machinery/computer/hologram_comp/DblClick() + if (!in_range(src, usr)) + return 0 + src.show_console(usr) + return + +/obj/machinery/computer/hologram_comp/proc/render() + var/icon/I = new /icon('human.dmi', "body_m_s") + + if (src.lumens >= 0) + I.Blend(rgb(src.lumens, src.lumens, src.lumens), ICON_ADD) + else + I.Blend(rgb(- src.lumens, -src.lumens, -src.lumens), ICON_SUBTRACT) + + I.Blend(new /icon('human.dmi', "mouth_m_s"), ICON_OVERLAY) + I.Blend(new /icon('human.dmi', "underwear1_m_s"), ICON_OVERLAY) + + var/icon/U = new /icon('human_face.dmi', "hair_a_s") + U.Blend(rgb(src.h_r, src.h_g, src.h_b), ICON_ADD) + + I.Blend(U, ICON_OVERLAY) + + src.projector.projection.icon = I + +/obj/machinery/computer/hologram_comp/proc/show_console(var/mob/user as mob) + var/dat + user.machine = src + if (src.temp) + dat = text("[]

      Clear", src.temp, src) + else + dat = text("Hologram Status:
      \nPower: []
      \nHologram Control:
      \nColor Luminosity: []/220 \[Reset\]
      \nLighten: 1 10
      \nDarken: 1 10
      \n
      \nHair Color: ([],[],[]) \[Reset\]
      \nRed (0-255): \[0\] -10 -1 [] 1 10 \[255\]
      \nGreen (0-255): \[0\] -10 -1 [] 1 10 \[255\]
      \nBlue (0-255): \[0\] -10 -1 [] 1 10 \[255\]
      ", src, (src.projector.projection ? "On" : "Off"), -src.lumens + 35, src, src, src, src, src, src.h_r, src.h_g, src.h_b, src, src, src, src, src.h_r, src, src, src, src, src, src, src.h_g, src, src, src, src, src, src, src.h_b, src, src, src) + user << browse(dat, "window=hologram_console") + onclose(user, "hologram_console") + return + +/obj/machinery/computer/hologram_comp/Topic(href, href_list) + if(..()) + return + if (in_range(src, usr)) + flick("holo_console1", src) + if (href_list["power"]) + if (src.projector.projection) + src.projector.icon_state = "hologram0" + //src.projector.projection = null + del(src.projector.projection) + else + src.projector.projection = new /obj/projection(src.projector.loc) + src.projector.projection.icon = 'human.dmi' + src.projector.projection.icon_state = "body_m_s" + src.projector.icon_state = "hologram1" + src.render() + else + if (href_list["h_r"]) + if (src.projector.projection) + src.h_r += text2num(href_list["h_r"]) + src.h_r = min(max(src.h_r, 0), 255) + render() + else + if (href_list["h_g"]) + if (src.projector.projection) + src.h_g += text2num(href_list["h_g"]) + src.h_g = min(max(src.h_g, 0), 255) + render() + else + if (href_list["h_b"]) + if (src.projector.projection) + src.h_b += text2num(href_list["h_b"]) + src.h_b = min(max(src.h_b, 0), 255) + render() + else + if (href_list["light"]) + if (src.projector.projection) + src.lumens += text2num(href_list["light"]) + src.lumens = min(max(src.lumens, -185.0), 35) + render() + else + if (href_list["reset"]) + if (src.projector.projection) + src.lumens = 0 + render() + else + if (href_list["temp"]) + src.temp = null + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.show_console(M) + return \ No newline at end of file diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm new file mode 100644 index 0000000000000..dd2acb3a344f3 --- /dev/null +++ b/code/game/machinery/computer/medical.dm @@ -0,0 +1,504 @@ +/obj/machinery/computer/med_data/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/med_data/M = new /obj/item/weapon/circuitboard/med_data( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/med_data/M = new /obj/item/weapon/circuitboard/med_data( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + +/obj/machinery/computer/med_data/attack_ai(user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/med_data/attack_paw(user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/med_data/attack_hand(mob/user as mob) + if(..()) + return + var/dat + if (src.temp) + dat = text("[src.temp]

      Clear Screen") + else + dat = text("Confirm Identity: []
      ", src, (src.scan ? text("[]", src.scan.name) : "----------")) + if (src.authenticated) + switch(src.screen) + if(1.0) + dat += {" +Search Records +
      List Records +
      +
      Virus Database +
      Medbot Tracking +
      +
      Record Maintenance +
      {Log Out}
      +"} + if(2.0) + dat += "Record List:
      " + for(var/datum/data/record/R in data_core.general) + dat += text("[]: []
      ", src, R, R.fields["id"], R.fields["name"]) + //Foreach goto(132) + dat += text("
      Back", src) + if(3.0) + dat += text("Records Maintenance
      \nBackup To Disk
      \nUpload From disk
      \nDelete All Records
      \n
      \nBack", src, src, src, src) + if(4.0) + dat += "
      Medical Record

      " + if ((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))) + dat += text("Name: [] ID: []
      \nSex: []
      \nAge: []
      \nFingerprint: []
      \nPhysical Status: []
      \nMental Status: []
      ", src.active1.fields["name"], src.active1.fields["id"], src, src.active1.fields["sex"], src, src.active1.fields["age"], src, src.active1.fields["fingerprint"], src, src.active1.fields["p_stat"], src, src.active1.fields["m_stat"]) + else + dat += "General Record Lost!
      " + if ((istype(src.active2, /datum/data/record) && data_core.medical.Find(src.active2))) + dat += text("
      \n
      Medical Data

      \nBlood Type: []
      \n
      \nMinor Disabilities: []
      \nDetails: []
      \n
      \nMajor Disabilities: []
      \nDetails: []
      \n
      \nAllergies: []
      \nDetails: []
      \n
      \nCurrent Diseases: [] (per disease info placed in log/comment section)
      \nDetails: []
      \n
      \nImportant Notes:
      \n\t[]
      \n
      \n
      Comments/Log

      ", src, src.active2.fields["b_type"], src, src.active2.fields["mi_dis"], src, src.active2.fields["mi_dis_d"], src, src.active2.fields["ma_dis"], src, src.active2.fields["ma_dis_d"], src, src.active2.fields["alg"], src, src.active2.fields["alg_d"], src, src.active2.fields["cdi"], src, src.active2.fields["cdi_d"], src, src.active2.fields["notes"]) + var/counter = 1 + while(src.active2.fields[text("com_[]", counter)]) + dat += text("[]
      Delete Entry

      ", src.active2.fields[text("com_[]", counter)], src, counter) + counter++ + dat += text("Add Entry

      ", src) + dat += text("Delete Record (Medical Only)

      ", src) + else + dat += "Medical Record Lost!
      " + dat += text("New Record

      ") + dat += text("\nPrint Record
      \nBack
      ", src, src) + if(5.0) + dat += {"
      Virus Database
      +
      GBS +
      Common Cold +
      Flu +
      Jungle Fever +
      Clowning Around +
      Plasmatoid +
      Space Rhinovirus +
      Robot Transformation +
      Back"} + if(6.0) + dat += "
      Medical Robot Monitor
      " + dat += "Back" + dat += "
      Medical Robots:" + var/bdat = null + for(var/obj/machinery/bot/medbot/M in world) + var/turf/bl = get_turf(M) + bdat += "[M.name] - \[[bl.x],[bl.y]\] - [M.on ? "Online" : "Offline"]
      " + if((!isnull(M.reagent_glass)) && M.use_beaker) + bdat += "Reservoir: \[[M.reagent_glass.reagents.total_volume]/[M.reagent_glass.reagents.maximum_volume]\]
      " + else + bdat += "Using Internal Synthesizer.
      " + + if(!bdat) + dat += "
      None detected
      " + else + dat += "
      [bdat]" + + else + else + dat += text("{Log In}", src) + user << browse(text("Medical Records[]", dat), "window=med_rec") + onclose(user, "med_rec") + return + +/obj/machinery/computer/med_data/Topic(href, href_list) + if(..()) + return + if (!( data_core.general.Find(src.active1) )) + src.active1 = null + if (!( data_core.medical.Find(src.active2) )) + src.active2 = null + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.machine = src + if (href_list["temp"]) + src.temp = null + if (href_list["scan"]) + if (src.scan) + src.scan.loc = src.loc + src.scan = null + else + var/obj/item/I = usr.equipped() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + src.scan = I + else if (href_list["logout"]) + src.authenticated = null + src.screen = null + src.active1 = null + src.active2 = null + else if (href_list["login"]) + if (istype(usr, /mob/living/silicon)) + src.active1 = null + src.active2 = null + src.authenticated = 1 + src.rank = "AI" + src.screen = 1 + else if (istype(src.scan, /obj/item/weapon/card/id)) + src.active1 = null + src.active2 = null + if (src.check_access(src.scan)) + src.authenticated = src.scan.registered + src.rank = src.scan.assignment + src.screen = 1 + if (src.authenticated) + + if(href_list["screen"]) + src.screen = text2num(href_list["screen"]) + if(src.screen < 1) + src.screen = 1 + + src.active1 = null + src.active2 = null + + if(href_list["vir"]) + switch(href_list["vir"]) + if("gbs") + src.temp = {"Name: GBS +
      Number of stages: 5 +
      Spread: Airborne Transmission +
      Possible Cure: Spaceacillin +
      Affected Species: Human +
      +
      Notes: If left untreated death will occur. +
      +
      Severity: Major"} + if("cc") + src.temp = {"Name: Common Cold +
      Number of stages: 3 +
      Spread: Airborne Transmission +
      Possible Cure: Rest +
      Affected Species: Human +
      +
      Notes: If left untreated the subject will contract the flu. +
      +
      Severity: Minor"} + if("f") + src.temp = {"Name: The Flu +
      Number of stages: 3 +
      Spread: Airborne Transmission +
      Possible Cure: Rest +
      Affected Species: Human +
      +
      Notes: If left untreated the subject will feel quite unwell. +
      +
      Severity: Medium"} + if("jf") + src.temp = {"Name: Jungle Fever +
      Number of stages: 1 +
      Spread: Airborne Transmission +
      Possible Cure: None +
      Affected Species: Monkey +
      +
      Notes: Monkies with this disease will bite humans, causing humans to spontaneously to mutate into a monkey. +
      +
      Severity: Medium"} + if("ca") + src.temp = {"Name: Clowning Around +
      Number of stages: 4 +
      Spread: Airborne Transmission +
      Possible Cure: Spaceacillin +
      Affected Species: Human +
      +
      Notes: Subjects are affected by rampant honking and a fondness for shenanigans. They may also spontaneously phase through closed airlocks. +
      +
      Severity: Laughable"} + if("p") + src.temp = {"Name: Plasmatoid +
      Number of stages: 3 +
      Spread: Airborne Transmission +
      Possible Cure: Inaprovaline +
      Affected Species: Human and Monkey +
      +
      Notes: With this disease the victim will need plasma to breathe. +
      +
      Severity: Major"} + if("dna") + src.temp = {"Name: Space Rhinovirus +
      Number of stages: 4 +
      Spread: Airborne Transmission +
      Possible Cure: Spaceacillin +
      Affected Species: Human +
      +
      Notes: This disease transplants the genetic code of the intial vector into new hosts. +
      +
      Severity: Medium"} + if("bot") + src.temp = {"Name: Robot Transformation +
      Number of stages: 5 +
      Spread: Infected food +
      Possible Cure: None +
      Affected Species: Human +
      +
      Notes: This disease, actually acute nanomachine infection, converts the victim into a cyborg. +
      +
      Severity: Major"} + + if (href_list["del_all"]) + src.temp = text("Are you sure you wish to delete all records?
      \n\tYes
      \n\tNo
      ", src, src) + + if (href_list["del_all2"]) + for(var/datum/data/record/R in data_core.medical) + //R = null + del(R) + //Foreach goto(494) + src.temp = "All records deleted." + + if (href_list["field"]) + var/a1 = src.active1 + var/a2 = src.active2 + switch(href_list["field"]) + if("fingerprint") + if (istype(src.active1, /datum/data/record)) + var/t1 = input("Please input fingerprint hash:", "Med. records", src.active1.fields["id"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) + return + src.active1.fields["fingerprint"] = t1 + if("sex") + if (istype(src.active1, /datum/data/record)) + if (src.active1.fields["sex"] == "Male") + src.active1.fields["sex"] = "Female" + else + src.active1.fields["sex"] = "Male" + if("age") + if (istype(src.active1, /datum/data/record)) + var/t1 = input("Please input age:", "Med. records", src.active1.fields["age"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) + return + src.active1.fields["age"] = t1 + if("mi_dis") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please input minor disabilities list:", "Med. records", src.active2.fields["mi_dis"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["mi_dis"] = t1 + if("mi_dis_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize minor dis.:", "Med. records", src.active2.fields["mi_dis_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["mi_dis_d"] = t1 + if("ma_dis") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please input major diabilities list:", "Med. records", src.active2.fields["ma_dis"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["ma_dis"] = t1 + if("ma_dis_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize major dis.:", "Med. records", src.active2.fields["ma_dis_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["ma_dis_d"] = t1 + if("alg") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please state allergies:", "Med. records", src.active2.fields["alg"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["alg"] = t1 + if("alg_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize allergies:", "Med. records", src.active2.fields["alg_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["alg_d"] = t1 + if("cdi") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please state diseases:", "Med. records", src.active2.fields["cdi"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["cdi"] = t1 + if("cdi_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize diseases:", "Med. records", src.active2.fields["cdi_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["cdi_d"] = t1 + if("notes") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize notes:", "Med. records", src.active2.fields["notes"], null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["notes"] = t1 + if("p_stat") + if (istype(src.active1, /datum/data/record)) + src.temp = text("Physical Condition:
      \n\t*Deceased*
      \n\t*Unconscious*
      \n\tActive
      \n\tPhysically Unfit
      ", src, src, src, src) + if("m_stat") + if (istype(src.active1, /datum/data/record)) + src.temp = text("Mental Condition:
      \n\t*Insane*
      \n\t*Unstable*
      \n\t*Watch*
      \n\tStable
      ", src, src, src, src) + if("b_type") + if (istype(src.active2, /datum/data/record)) + src.temp = text("Blood Type:
      \n\tA- A+
      \n\tB- B+
      \n\tAB- AB+
      \n\tO- O+
      ", src, src, src, src, src, src, src, src) + else + + if (href_list["p_stat"]) + if (src.active1) + switch(href_list["p_stat"]) + if("deceased") + src.active1.fields["p_stat"] = "*Deceased*" + if("unconscious") + src.active1.fields["p_stat"] = "*Unconscious*" + if("active") + src.active1.fields["p_stat"] = "Active" + if("unfit") + src.active1.fields["p_stat"] = "Physically Unfit" + + if (href_list["m_stat"]) + if (src.active1) + switch(href_list["m_stat"]) + if("insane") + src.active1.fields["m_stat"] = "*Insane*" + if("unstable") + src.active1.fields["m_stat"] = "*Unstable*" + if("watch") + src.active1.fields["m_stat"] = "*Watch*" + if("stable") + src.active2.fields["m_stat"] = "Stable" + + + if (href_list["b_type"]) + if (src.active2) + switch(href_list["b_type"]) + if("an") + src.active2.fields["b_type"] = "A-" + if("bn") + src.active2.fields["b_type"] = "B-" + if("abn") + src.active2.fields["b_type"] = "AB-" + if("on") + src.active2.fields["b_type"] = "O-" + if("ap") + src.active2.fields["b_type"] = "A+" + if("bp") + src.active2.fields["b_type"] = "B+" + if("abp") + src.active2.fields["b_type"] = "AB+" + if("op") + src.active2.fields["b_type"] = "O+" + + + if (href_list["del_r"]) + if (src.active2) + src.temp = text("Are you sure you wish to delete the record (Medical Portion Only)?
      \n\tYes
      \n\tNo
      ", src, src) + + if (href_list["del_r2"]) + if (src.active2) + //src.active2 = null + del(src.active2) + + if (href_list["d_rec"]) + var/datum/data/record/R = locate(href_list["d_rec"]) + var/datum/data/record/M = locate(href_list["d_rec"]) + if (!( data_core.general.Find(R) )) + src.temp = "Record Not Found!" + return + for(var/datum/data/record/E in data_core.medical) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + M = E + else + //Foreach continue //goto(2540) + src.active1 = R + src.active2 = M + src.screen = 4 + + if (href_list["new"]) + if ((istype(src.active1, /datum/data/record) && !( istype(src.active2, /datum/data/record) ))) + var/datum/data/record/R = new /datum/data/record( ) + R.fields["name"] = src.active1.fields["name"] + R.fields["id"] = src.active1.fields["id"] + R.name = text("Medical Record #[]", R.fields["id"]) + R.fields["b_type"] = "Unknown" + R.fields["mi_dis"] = "None" + R.fields["mi_dis_d"] = "No minor disabilities have been declared." + R.fields["ma_dis"] = "None" + R.fields["ma_dis_d"] = "No major disabilities have been diagnosed." + R.fields["alg"] = "None" + R.fields["alg_d"] = "No allergies have been detected in this patient." + R.fields["cdi"] = "None" + R.fields["cdi_d"] = "No diseases have been diagnosed at the moment." + R.fields["notes"] = "No notes." + data_core.medical += R + src.active2 = R + src.screen = 4 + + if (href_list["add_c"]) + if (!( istype(src.active2, /datum/data/record) )) + return + var/a2 = src.active2 + var/t1 = input("Add Comment:", "Med. records", null, null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + var/counter = 1 + while(src.active2.fields[text("com_[]", counter)]) + counter++ + src.active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [], 2053
      []", src.authenticated, src.rank, time2text(world.realtime, "DDD MMM DD hh:mm:ss"), t1) + + if (href_list["del_c"]) + if ((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])])) + src.active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" + + if (href_list["search"]) + var/t1 = input("Search String: (Name or ID)", "Med. records", null, null) as text + if ((!( t1 ) || usr.stat || !( src.authenticated ) || usr.restrained() || ((!in_range(src, usr)) && (!istype(usr, /mob/living/silicon))))) + return + src.active1 = null + src.active2 = null + t1 = lowertext(t1) + for(var/datum/data/record/R in data_core.general) + if ((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"]))) + src.active1 = R + else + //Foreach continue //goto(3229) + if (!( src.active1 )) + src.temp = text("Could not locate record [].", t1) + else + for(var/datum/data/record/E in data_core.medical) + if ((E.fields["name"] == src.active1.fields["name"] || E.fields["id"] == src.active1.fields["id"])) + src.active2 = E + else + //Foreach continue //goto(3334) + src.screen = 4 + + if (href_list["print_p"]) + if (!( src.printing )) + src.printing = 1 + sleep(50) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( src.loc ) + P.info = "
      Medical Record

      " + if ((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))) + P.info += text("Name: [] ID: []
      \nSex: []
      \nAge: []
      \nFingerprint: []
      \nPhysical Status: []
      \nMental Status: []
      ", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"], src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"]) + else + P.info += "General Record Lost!
      " + if ((istype(src.active2, /datum/data/record) && data_core.medical.Find(src.active2))) + P.info += text("
      \n
      Medical Data

      \nBlood Type: []
      \n
      \nMinor Disabilities: []
      \nDetails: []
      \n
      \nMajor Disabilities: []
      \nDetails: []
      \n
      \nAllergies: []
      \nDetails: []
      \n
      \nCurrent Diseases: [] (per disease info placed in log/comment section)
      \nDetails: []
      \n
      \nImportant Notes:
      \n\t[]
      \n
      \n
      Comments/Log

      ", src.active2.fields["b_type"], src.active2.fields["mi_dis"], src.active2.fields["mi_dis_d"], src.active2.fields["ma_dis"], src.active2.fields["ma_dis_d"], src.active2.fields["alg"], src.active2.fields["alg_d"], src.active2.fields["cdi"], src.active2.fields["cdi_d"], src.active2.fields["notes"]) + var/counter = 1 + while(src.active2.fields[text("com_[]", counter)]) + P.info += text("[]
      ", src.active2.fields[text("com_[]", counter)]) + counter++ + else + P.info += "Medical Record Lost!
      " + P.info += "" + P.name = "paper- 'Medical Record'" + src.printing = null + + src.add_fingerprint(usr) + src.updateUsrDialog() + return + diff --git a/code/game/machinery/computer/power.dm b/code/game/machinery/computer/power.dm new file mode 100644 index 0000000000000..d9e5e8791c710 --- /dev/null +++ b/code/game/machinery/computer/power.dm @@ -0,0 +1,92 @@ +// the power monitoring computer +// for the moment, just report the status of all APCs in the same powernet + +/obj/machinery/power/monitor/attack_ai(mob/user) + add_fingerprint(user) + + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + +/obj/machinery/power/monitor/attack_hand(mob/user) + add_fingerprint(user) + + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + + +/obj/machinery/power/monitor/proc/interact(mob/user) + + if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) + if (!istype(user, /mob/living/silicon)) + user.machine = null + user << browse(null, "window=powcomp") + return + + + user.machine = src + var/t = "Power Monitoring
      " + + + if(!powernet) + t += "\red No connection" + else + + var/list/L = list() + for(var/obj/machinery/power/terminal/term in powernet.nodes) + if(istype(term.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = term.master + L += A + + t += "
      Total power: [powernet.avail] W
      Total load: [num2text(powernet.viewload,10)] W
      " + + t += "" + + if(L.len > 0) + + t += "Area Eqp./Lgt./Env. Load Cell
      " + + var/list/S = list(" Off","AOff"," On", " AOn") + var/list/chg = list("N","C","F") + + for(var/obj/machinery/power/apc/A in L) + + t += copytext(add_tspace(A.area.name, 30), 1, 30) + t += " [S[A.equipment+1]] [S[A.lighting+1]] [S[A.environ+1]] [add_lspace(A.lastused_total, 6)] [A.cell ? "[add_lspace(round(A.cell.percent()), 3)]% [chg[A.charging+1]]" : " N/C"]
      " + + t += "
      " + + t += "

      Close
      " + + user << browse(t, "window=powcomp;size=420x700") + onclose(user, "powcomp") + + +/obj/machinery/power/monitor/Topic(href, href_list) + ..() + if( href_list["close"] ) + usr << browse(null, "window=powcomp") + usr.machine = null + return + +/obj/machinery/power/monitor/process() + if(!(stat & (NOPOWER|BROKEN)) ) + use_power(250) + + src.updateDialog() + + +/obj/machinery/power/monitor/power_change() + + if(stat & BROKEN) + icon_state = "broken" + else + if( powered() ) + icon_state = initial(icon_state) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + src.icon_state = "c_unpowered" + stat |= NOPOWER + diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm new file mode 100644 index 0000000000000..581ea0f7e1d9e --- /dev/null +++ b/code/game/machinery/computer/robot.dm @@ -0,0 +1,185 @@ +/obj/machinery/computer/robotics + name = "Robotics Control" + icon = 'computer.dmi' + icon_state = "id" + req_access = list(access_captain, access_robotics) + + var/id = 0.0 + var/temp = null + var/status = 0 + var/timeleft = 60 + var/stop = 0.0 + var/screen = 0 // 0 - Main Menu, 1 - Cyborg Status, 2 - Kill 'em All! -- In text + +/obj/machinery/computer/robotics/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/robotics/M = new /obj/item/weapon/circuitboard/robotics( A ) + for (var/obj/C in src) + C.loc = src.loc + M.id = src.id + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/robotics/M = new /obj/item/weapon/circuitboard/robotics( A ) + for (var/obj/C in src) + C.loc = src.loc + M.id = src.id + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + + //else + src.attack_hand(user) + return + +/obj/machinery/computer/robotics/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/robotics/attack_paw(var/mob/user as mob) + + return src.attack_hand(user) + return + +/obj/machinery/computer/robotics/attack_hand(var/mob/user as mob) + if(..()) + return + user.machine = src + var/dat + if (src.temp) + dat = "[src.temp]

      Clear Screen" + else + if(screen == 0) + dat += "

      Cyborg Control Console


      " + dat += "1. Cyborg Status
      " + dat += "2. Emergency Full Destruct
      " + if(screen == 1) + for(var/mob/living/silicon/robot/R in world) + dat += "[R.name] |" + if(R.stat) + dat += " Not Responding |" + else + dat += " Operating Normally |" + if(R.cell) + dat += " Battery Installed ([R.cell.charge]/[R.cell.maxcharge]) |" + else + dat += " No Cell Installed |" + if(R.module) + dat += " Module Installed ([R.module.name]) |" + else + dat += " No Module Installed |" + dat += "(Destroy)" + dat += "
      " + dat += "(Return to Main Menu)
      " + if(screen == 2) + if(!src.status) + dat += {"
      Emergency Robot Self-Destruct
      \nStatus: Off
      + \n
      + \nCountdown: [src.timeleft]/60 \[Reset\]
      + \n
      + \nStart Sequence
      + \n
      + \nClose"} + else + dat = {"Emergency Robot Self-Destruct
      \nStatus: Activated
      + \n
      + \nCountdown: [src.timeleft]/60 \[Reset\]
      + \n
      \nStop Sequence
      + \n
      + \nClose"} + dat += "(Return to Main Menu)
      " + + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + +/obj/machinery/computer/engine/process() + if(stat & (NOPOWER|BROKEN)) + return + use_power(500) + src.updateDialog() + return + +/obj/machinery/computer/robotics/Topic(href, href_list) + if(..()) + return + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.machine = src + + if (href_list["eject"]) + src.temp = {"Destroy Robots?
      +
      \[Swipe ID to initiate destruction sequence\]
      + Cancel"} + + else if (href_list["eject2"]) + var/obj/item/weapon/card/id/I = usr.equipped() + if (istype(I)) + if(src.check_access(I)) + if (!status) + src.status = 1 + src.start_sequence() + src.temp = null + else + usr << "\red Access Denied." + + else if (href_list["stop"]) + src.temp = {" + Stop Robot Destruction Sequence?
      +
      Yes
      + No"} + + else if (href_list["stop2"]) + src.stop = 1 + src.temp = null + + else if (href_list["reset"]) + src.timeleft = 60 + + else if (href_list["temp"]) + src.temp = null + else if (href_list["screen"]) + switch(href_list["screen"]) + if("0") + screen = 0 + if("1") + screen = 1 + if("2") + screen = 2 + else if (href_list["killbot"]) + var/mob/living/silicon/robot/R = locate(href_list["killbot"]) + if(R) + var/choice = input("Are you certain you wish to detonate [R.name]?") in list("Confirm", "Abort") + if(choice == "Confirm") + R.self_destruct() + + src.add_fingerprint(usr) + src.updateUsrDialog() + return + +/obj/machinery/computer/robotics/proc/start_sequence() + + do + if(src.stop) + src.stop = 0 + return + src.timeleft-- + sleep(10) + while(src.timeleft) + + for(var/mob/living/silicon/robot/R in world) + R.self_destruct() + + return + diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm new file mode 100644 index 0000000000000..4696bfa8d9ecd --- /dev/null +++ b/code/game/machinery/computer/security.dm @@ -0,0 +1,432 @@ +/obj/machinery/computer/secure_data/attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (src.stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + new /obj/item/weapon/shard( src.loc ) + var/obj/item/weapon/circuitboard/secure_data/M = new /obj/item/weapon/circuitboard/secure_data( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 3 + A.icon_state = "3" + A.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/computerframe/A = new /obj/computerframe( src.loc ) + var/obj/item/weapon/circuitboard/secure_data/M = new /obj/item/weapon/circuitboard/secure_data( A ) + for (var/obj/C in src) + C.loc = src.loc + A.circuit = M + A.state = 4 + A.icon_state = "4" + A.anchored = 1 + del(src) + else + src.attack_hand(user) + return + +/obj/machinery/computer/secure_data/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/secure_data/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/secure_data/attack_hand(mob/user as mob) + if(..()) + return + var/dat + if (src.temp) + dat = text("[]

      Clear Screen", src.temp, src) + else + dat = text("Confirm Identity: []
      ", src, (src.scan ? text("[]", src.scan.name) : "----------")) + if (src.authenticated) + switch(src.screen) + if(1.0) + dat += text("Search Records
      \nList Records
      \nSearch Fingerprints
      \nNew Record
      \n
      \nRecord Maintenance
      \n{Log Out}
      \n", src, src, src, src, src, src) + if(2.0) + dat += "Record List:
      " + for(var/datum/data/record/R in data_core.general) + dat += text("[]: []
      ", src, R, R.fields["id"], R.fields["name"]) + //Foreach goto(136) + dat += text("
      Back", src) + if(3.0) + dat += text("Records Maintenance
      \nBackup To Disk
      \nUpload From disk
      \nDelete All Records
      \n
      \nBack", src, src, src, src) + if(4.0) + dat += "
      Security Record

      " + if ((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))) + dat += text("Name: [] ID: []
      \nSex: []
      \nAge: []
      \nRank: []
      \nFingerprint: []
      \nPhysical Status: []
      \nMental Status: []
      ", src, src.active1.fields["name"], src, src.active1.fields["id"], src, src.active1.fields["sex"], src, src.active1.fields["age"], src, src.active1.fields["rank"], src, src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"]) + else + dat += "General Record Lost!
      " + if ((istype(src.active2, /datum/data/record) && data_core.security.Find(src.active2))) + dat += text("
      \n
      Security Data

      \nCriminal Status: []
      \n
      \nMinor Crimes: []
      \nDetails: []
      \n
      \nMajor Crimes: []
      \nDetails: []
      \n
      \nImportant Notes:
      \n\t[]
      \n
      \n
      Comments/Log

      ", src, src.active2.fields["criminal"], src, src.active2.fields["mi_crim"], src, src.active2.fields["mi_crim_d"], src, src.active2.fields["ma_crim"], src, src.active2.fields["ma_crim_d"], src, src.active2.fields["notes"]) + var/counter = 1 + while(src.active2.fields[text("com_[]", counter)]) + dat += text("[]
      Delete Entry

      ", src.active2.fields[text("com_[]", counter)], src, counter) + counter++ + dat += text("Add Entry

      ", src) + dat += text("Delete Record (Security Only)

      ", src) + else + dat += "Security Record Lost!
      " + dat += text("New Record

      ", src) + dat += text("\nDelete Record (ALL)

      \nPrint Record
      \nBack
      ", src, src, src) + else + else + dat += text("{Log In}", src) + user << browse(text("Security Records[]", dat), "window=secure_rec") + onclose(user, "secure_rec") + return + +/obj/machinery/computer/secure_data/Topic(href, href_list) + if(..()) + return + if (!( data_core.general.Find(src.active1) )) + src.active1 = null + if (!( data_core.security.Find(src.active2) )) + src.active2 = null + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.machine = src + if (href_list["temp"]) + src.temp = null + if (href_list["scan"]) + if (src.scan) + src.scan.loc = src.loc + src.scan = null + else + var/obj/item/I = usr.equipped() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + src.scan = I + else + if (href_list["logout"]) + src.authenticated = null + src.screen = null + src.active1 = null + src.active2 = null + else + if (href_list["login"]) + if (istype(usr, /mob/living/silicon)) + src.active1 = null + src.active2 = null + src.authenticated = 1 + src.rank = "AI" + src.screen = 1 + if (istype(src.scan, /obj/item/weapon/card/id)) + src.active1 = null + src.active2 = null + if(check_access(src.scan)) + src.authenticated = src.scan.registered + src.rank = src.scan.assignment + src.screen = 1 + if (src.authenticated) + if (href_list["list"]) + src.screen = 2 + src.active1 = null + src.active2 = null + else + if (href_list["rec_m"]) + src.screen = 3 + src.active1 = null + src.active2 = null + else + if (href_list["del_all"]) + src.temp = text("Are you sure you wish to delete all records?
      \n\tYes
      \n\tNo
      ", src, src) + else + if (href_list["del_all2"]) + for(var/datum/data/record/R in data_core.security) + //R = null + del(R) + //Foreach goto(497) + src.temp = "All records deleted." + else + if (href_list["main"]) + src.screen = 1 + src.active1 = null + src.active2 = null + else + if (href_list["field"]) + var/a1 = src.active1 + var/a2 = src.active2 + switch(href_list["field"]) + if("name") + if (istype(src.active1, /datum/data/record)) + var/t1 = input("Please input name:", "Secure. records", src.active1.fields["name"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon)))) || src.active1 != a1) + return + src.active1.fields["name"] = t1 + if("id") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please input id:", "Secure. records", src.active1.fields["id"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) + return + src.active1.fields["id"] = t1 + if("fingerprint") + if (istype(src.active1, /datum/data/record)) + var/t1 = input("Please input fingerprint hash:", "Secure. records", src.active1.fields["fingerprint"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) + return + src.active1.fields["fingerprint"] = t1 + if("sex") + if (istype(src.active1, /datum/data/record)) + if (src.active1.fields["sex"] == "Male") + src.active1.fields["sex"] = "Female" + else + src.active1.fields["sex"] = "Male" + if("age") + if (istype(src.active1, /datum/data/record)) + var/t1 = input("Please input age:", "Secure. records", src.active1.fields["age"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) + return + src.active1.fields["age"] = t1 + if("mi_crim") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please input minor disabilities list:", "Secure. records", src.active2.fields["mi_crim"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["mi_crim"] = t1 + if("mi_crim_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize minor dis.:", "Secure. records", src.active2.fields["mi_crim_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["mi_crim_d"] = t1 + if("ma_crim") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please input major diabilities list:", "Secure. records", src.active2.fields["ma_crim"], null) as text + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["ma_crim"] = t1 + if("ma_crim_d") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize major dis.:", "Secure. records", src.active2.fields["ma_crim_d"], null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["ma_crim_d"] = t1 + if("notes") + if (istype(src.active2, /datum/data/record)) + var/t1 = input("Please summarize notes:", "Secure. records", src.active2.fields["notes"], null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + src.active2.fields["notes"] = t1 + if("criminal") + if (istype(src.active2, /datum/data/record)) + src.temp = text("Criminal Status:
      \n\tNone
      \n\t*Arrest*
      \n\tIncarcerated
      \n\tParolled
      \n\tReleased
      ", src, src, src, src, src) + if("rank") + var/list/L = list( "Head of Personnel", "Captain", "AI" ) + if ((istype(src.active1, /datum/data/record) && L.Find(src.rank))) + src.temp = text("Rank:
      \nAssistants:
      \nAssistant
      \nTechnicians:
      \nDetective
      \nAtmospheric Technician
      \nStation Engineer
      \nResearchers:
      \nGeneticist
      \nScientist
      \nOfficers:
      \nMedical Doctor
      \nSecurity Officer
      \nHigher Officers:
      \nHead of Security
      \nHead of Personnel
      \nCaptain
      ", src, src, src, src, src, src, src, src, src, src, src) + else + alert(usr, "You do not have the required rank to do this!") + else + else + if (href_list["rank"]) + if (src.active1) + switch(href_list["rank"]) + if("res_assist") + src.active1.fields["rank"] = "Assistant" + if("foren_tech") + src.active1.fields["rank"] = "Detective" + if("atmo_tech") + src.active1.fields["rank"] = "Atmospheric Technician" + if("engineer") + src.active1.fields["rank"] = "Station Engineer" + if("med_res") + src.active1.fields["rank"] = "Geneticist" + if("tox_res") + src.active1.fields["rank"] = "Scientist" + if("med_doc") + src.active1.fields["rank"] = "Medical Doctor" + if("secure_off") + src.active1.fields["rank"] = "Security Officer" + if("hoperson") + src.active1.fields["rank"] = "Head of Security" + if("hosecurity") + src.active1.fields["rank"] = "Head of Personnel" + if("captain") + src.active1.fields["rank"] = "Captain" + if("barman") + src.active1.fields["rank"] = "Barman" + if("chemist") + src.active1.fields["rank"] = "Chemist" + if("janitor") + src.active1.fields["rank"] = "Janitor" + if("clown") + src.active1.fields["rank"] = "Clown" + + else + if (href_list["criminal2"]) + if (src.active2) + switch(href_list["criminal2"]) + if("none") + src.active2.fields["criminal"] = "None" + if("arrest") + src.active2.fields["criminal"] = "*Arrest*" + if("incarcerated") + src.active2.fields["criminal"] = "Incarcerated" + if("parolled") + src.active2.fields["criminal"] = "Parolled" + if("released") + src.active2.fields["criminal"] = "Released" + + else + if (href_list["del_r"]) + if (src.active2) + src.temp = text("Are you sure you wish to delete the record (Security Portion Only)?
      \n\tYes
      \n\tNo
      ", src, src) + else + if (href_list["del_r2"]) + if (src.active2) + //src.active2 = null + del(src.active2) + else + if (href_list["dela_r"]) + if (src.active1) + src.temp = text("Are you sure you wish to delete the record (ALL)?
      \n\tYes
      \n\tNo
      ", src, src) + else + if (href_list["dela_r2"]) + for(var/datum/data/record/R in data_core.medical) + if ((R.fields["name"] == src.active1.fields["name"] || R.fields["id"] == src.active1.fields["id"])) + //R = null + del(R) + else + if (src.active2) + //src.active2 = null + del(src.active2) + if (src.active1) + //src.active1 = null + del(src.active1) + else + if (href_list["d_rec"]) + var/datum/data/record/R = locate(href_list["d_rec"]) + var/S = locate(href_list["d_rec"]) + if (!( data_core.general.Find(R) )) + src.temp = "Record Not Found!" + return + for(var/datum/data/record/E in data_core.security) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + S = E + else + //Foreach continue //goto(2614) + src.active1 = R + src.active2 = S + src.screen = 4 + else + if (href_list["new_r"]) + var/datum/data/record/G = new /datum/data/record( ) + G.fields["name"] = "New Record" + G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6)) + G.fields["rank"] = "Unassigned" + G.fields["sex"] = "Male" + G.fields["age"] = "Unknown" + G.fields["fingerprint"] = "Unknown" + G.fields["p_stat"] = "Active" + G.fields["m_stat"] = "Stable" + data_core.general += G + src.active1 = G + src.active2 = null + else + if (href_list["new"]) + if ((istype(src.active1, /datum/data/record) && !( istype(src.active2, /datum/data/record) ))) + var/datum/data/record/R = new /datum/data/record( ) + R.fields["name"] = src.active1.fields["name"] + R.fields["id"] = src.active1.fields["id"] + R.name = text("Security Record #[]", R.fields["id"]) + R.fields["criminal"] = "None" + R.fields["mi_crim"] = "None" + R.fields["mi_crim_d"] = "No minor crime convictions." + R.fields["ma_crim"] = "None" + R.fields["ma_crim_d"] = "No major crime convictions." + R.fields["notes"] = "No notes." + data_core.security += R + src.active2 = R + src.screen = 4 + else + if (href_list["add_c"]) + if (!( istype(src.active2, /datum/data/record) )) + return + var/a2 = src.active2 + var/t1 = input("Add Comment:", "Secure. records", null, null) as message + if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) + return + var/counter = 1 + while(src.active2.fields[text("com_[]", counter)]) + counter++ + src.active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [], 2053
      []", src.authenticated, src.rank, time2text(world.realtime, "DDD MMM DD hh:mm:ss"), t1) + else + if (href_list["del_c"]) + if ((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])])) + src.active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" + else + if (href_list["search_f"]) + var/t1 = input("Search String: (Fingerprint)", "Secure. records", null, null) as text + if ((!( t1 ) || usr.stat || !( src.authenticated ) || usr.restrained() || (!in_range(src, usr)) && (!istype(usr, /mob/living/silicon)))) + return + src.active1 = null + src.active2 = null + t1 = lowertext(t1) + for(var/datum/data/record/R in data_core.general) + if (lowertext(R.fields["fingerprint"]) == t1) + src.active1 = R + else + //Foreach continue //goto(3414) + if (!( src.active1 )) + src.temp = text("Could not locate record [].", t1) + else + for(var/datum/data/record/E in data_core.security) + if ((E.fields["name"] == src.active1.fields["name"] || E.fields["id"] == src.active1.fields["id"])) + src.active2 = E + else + //Foreach continue //goto(3502) + src.screen = 4 + else + if (href_list["search"]) + var/t1 = input("Search String: (Name or ID)", "Secure. records", null, null) as text + if ((!( t1 ) || usr.stat || !( src.authenticated ) || usr.restrained() || !in_range(src, usr))) + return + src.active1 = null + src.active2 = null + t1 = lowertext(t1) + for(var/datum/data/record/R in data_core.general) + if ((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"]))) + src.active1 = R + else + //Foreach continue //goto(3708) + if (!( src.active1 )) + src.temp = text("Could not locate record [].", t1) + else + for(var/datum/data/record/E in data_core.security) + if ((E.fields["name"] == src.active1.fields["name"] || E.fields["id"] == src.active1.fields["id"])) + src.active2 = E + else + //Foreach continue //goto(3813) + src.screen = 4 + else + if (href_list["print_p"]) + if (!( src.printing )) + src.printing = 1 + sleep(50) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( src.loc ) + P.info = "
      Security Record

      " + if ((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))) + P.info += text("Name: [] ID: []
      \nSex: []
      \nAge: []
      \nFingerprint: []
      \nPhysical Status: []
      \nMental Status: []
      ", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"], src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"]) + else + P.info += "General Record Lost!
      " + if ((istype(src.active2, /datum/data/record) && data_core.security.Find(src.active2))) + P.info += text("
      \n
      Security Data

      \nCriminal Status: []
      \n
      \nMinor Crimes: []
      \nDetails: []
      \n
      \nMajor Crimes: []
      \nDetails: []
      \n
      \nImportant Notes:
      \n\t[]
      \n
      \n
      Comments/Log

      ", src.active2.fields["criminal"], src.active2.fields["mi_crim"], src.active2.fields["mi_crim_d"], src.active2.fields["ma_crim"], src.active2.fields["ma_crim_d"], src.active2.fields["notes"]) + var/counter = 1 + while(src.active2.fields[text("com_[]", counter)]) + P.info += text("[]
      ", src.active2.fields[text("com_[]", counter)]) + counter++ + else + P.info += "Security Record Lost!
      " + P.info += "" + P.name = "paper- 'Security Record'" + src.printing = null + src.add_fingerprint(usr) + src.updateUsrDialog() + + return + diff --git a/code/game/machinery/computer/shuttle.dm b/code/game/machinery/computer/shuttle.dm new file mode 100644 index 0000000000000..c7eb4bc5e8841 --- /dev/null +++ b/code/game/machinery/computer/shuttle.dm @@ -0,0 +1,181 @@ +/obj/machinery/computer/shuttle/attackby(var/obj/item/weapon/card/W as obj, var/mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + if ((!( istype(W, /obj/item/weapon/card) ) || !( ticker ) || emergency_shuttle.location != 1 || !( user ))) + return + + + if (istype(W, /obj/item/weapon/card/id)) + + if (!W:access) //no access + user << "The access level of [W:registered]\'s card is not high enough. " + return + + var/list/cardaccess = W:access + if(!istype(cardaccess, /list) || !cardaccess.len) //no access + user << "The access level of [W:registered]\'s card is not high enough. " + return + + if(!(access_heads in W:access)) //doesn't have this access + user << "The access level of [W:registered]\'s card is not high enough. " + return 0 + + var/choice = alert(user, text("Would you like to (un)authorize a shortened launch time? [] authorization\s are still needed. Use abort to cancel all authorizations.", src.auth_need - src.authorized.len), "Shuttle Launch", "Authorize", "Repeal", "Abort") + switch(choice) + if("Authorize") + src.authorized -= W:registered + src.authorized += W:registered + if (src.auth_need - src.authorized.len > 0) + world << text("\blue Alert: [] authorizations needed until shuttle is launched early", src.auth_need - src.authorized.len) + else + world << "\blue Alert: Shuttle launch time shortened to 10 seconds!" + emergency_shuttle.settimeleft(10) + //src.authorized = null + del(src.authorized) + src.authorized = list( ) + + if("Repeal") + src.authorized -= W:registered + world << text("\blue Alert: [] authorizations needed until shuttle is launched early", src.auth_need - src.authorized.len) + + if("Abort") + world << "\blue All authorizations to shorting time for shuttle launch have been revoked!" + src.authorized.len = 0 + src.authorized = list( ) + + else if (istype(W, /obj/item/weapon/card/emag)) + var/choice = alert(user, "Would you like to launch the shuttle?","Shuttle control", "Launch", "Cancel") + switch(choice) + if("Launch") + world << "\blue Alert: Shuttle launch time shortened to 10 seconds!" + emergency_shuttle.settimeleft( 10 ) + if("Cancel") + return + + return + +/* +/obj/shut_controller/proc/rotate(direct) + + var/SE_X = 1 + var/SE_Y = 1 + var/SW_X = 1 + var/SW_Y = 1 + var/NE_X = 1 + var/NE_Y = 1 + var/NW_X = 1 + var/NW_Y = 1 + for(var/obj/move/M in src.parts) + if (M.x < SW_X) + SW_X = M.x + if (M.x > SE_X) + SE_X = M.x + if (M.y < SW_Y) + SW_Y = M.y + if (M.y > NW_Y) + NW_Y = M.y + if (M.y > NE_Y) + NE_Y = M.y + if (M.y < SE_Y) + SE_Y = M.y + if (M.x > NE_X) + NE_X = M.x + if (M.x < NW_X) + NW_X = M.y + var/length = abs(NE_X - NW_X) + var/width = abs(NE_Y - SE_Y) + var/obj/random = pick(src.parts) + var/s_direct = null + switch(s_direct) + if(1.0) + switch(direct) + if(90.0) + var/tx = SE_X + var/ty = SE_Y + var/t_z = random.z + for(var/obj/move/M in src.parts) + M.ty = -M.x - tx + M.tx = -M.y - ty + var/T = locate(M.x, M.y, 11) + M.relocate(T) + M.ty = -M.ty + M.tx += length + //Foreach goto(374) + for(var/obj/move/M in src.parts) + M.tx += tx + M.ty += ty + var/T = locate(M.tx, M.ty, t_z) + M.relocate(T, 90) + //Foreach goto(468) + if(-90.0) + var/tx = SE_X + var/ty = SE_Y + var/t_z = random.z + for(var/obj/move/M in src.parts) + M.ty = M.x - tx + M.tx = M.y - ty + var/T = locate(M.x, M.y, 11) + M.relocate(T) + M.ty = -M.ty + M.ty += width + //Foreach goto(571) + for(var/obj/move/M in src.parts) + M.tx += tx + M.ty += ty + var/T = locate(M.tx, M.ty, t_z) + M.relocate(T, -90.0) + //Foreach goto(663) + else + else + return +*/ + +/obj/machinery/computer/prison_shuttle/verb/take_off() + set src in oview(1) + + if (usr.stat || usr.restrained()) + return + + src.add_fingerprint(usr) + if(!src.allowedtocall) + usr << "\red The console seems irreparably damaged!" + return + if(src.z == 3) + usr << "\red Already in transit! Please wait!" + return + + var/A = locate(/area/shuttle/prison/) + for(var/mob/M in A) + M.show_message("\red Launch sequence initiated!") + spawn(0) shake_camera(M, 10, 1) + sleep(10) + + if(src.z == 2) //This is the laziest proc ever + for(var/atom/movable/AM as mob|obj in A) + AM.z = 3 + AM.Move() + sleep(rand(600,1800)) + for(var/atom/movable/AM as mob|obj in A) + AM.z = 1 + AM.Move() + else + for(var/atom/movable/AM as mob|obj in A) + AM.z = 3 + AM.Move() + sleep(rand(600,1800)) + for(var/atom/movable/AM as mob|obj in A) + AM.z = 2 + AM.Move() + for(var/mob/M in A) + M.show_message("\red Prison shuttle has arrived at destination!") + spawn(0) shake_camera(M, 2, 1) + return + +/obj/machinery/computer/prison_shuttle/verb/restabalize() + set src in oview(1) + + src.add_fingerprint(usr) + + var/A = locate(/area/shuttle/prison/) + for(var/mob/M in A) + M.show_message("\red Restabilizing prison shuttle atmosphere!") \ No newline at end of file diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm new file mode 100644 index 0000000000000..0aafa47e743e2 --- /dev/null +++ b/code/game/machinery/cryo.dm @@ -0,0 +1,284 @@ +/obj/machinery/atmospherics/unary/cryo_cell + name = "cryo cell" + icon = 'Cryogenic2.dmi' + icon_state = "celltop-P" + density = 1 + anchored = 1.0 + layer = 5 + + var/on = 0 + var/temperature_archived + var/obj/overlay/O1 = null + var/mob/occupant = null + var/beaker = null + var/next_trans = 0 + + var/current_heat_capacity = 50 + + + + New() + ..() + build_icon() + initialize_directions = SOUTH + + initialize() + if(node) return + var/node_connect = SOUTH + for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) + if(target.initialize_directions & get_dir(target,src)) + node = target + break + + process() + ..() + if(!node) + return + if(!on) + src.updateUsrDialog() + return + + if(src.occupant) + if(occupant.stat != 2) + process_occupant() + + if(air_contents) + temperature_archived = air_contents.temperature + heat_gas_contents() + expel_gas() + + if(abs(temperature_archived-air_contents.temperature) > 1) + network.update = 1 + + src.updateUsrDialog() + return 1 + + + allow_drop() + return 0 + + + relaymove(mob/user as mob) + if(user.stat) + return + src.go_out() + return + + attack_hand(mob/user as mob) + user.machine = src + var/beaker_text = "" + var/health_text = "" + var/temp_text = "" + if(src.occupant) + if(src.occupant.health <= -100) + health_text = "Dead" + else if(src.occupant.health < 0) + health_text = "[src.occupant.health]" + else + health_text = "[src.occupant.health]" + if(air_contents.temperature > T0C) + temp_text = "[air_contents.temperature]" + else if(air_contents.temperature > 225) + temp_text = "[air_contents.temperature]" + else + temp_text = "[air_contents.temperature]" + if(src.beaker) + beaker_text = "Beaker: Eject" + else + beaker_text = "Beaker: No beaker loaded" + var/dat = {"Cryo cell control system
      + Current cell temperature: [temp_text]K
      + Cryo status: [ src.on ? "Off On" : "Off On"]
      + [beaker_text]

      + Current occupant: [src.occupant ? "
      Name: [src.occupant]
      Health: [health_text]
      Oxygen deprivation: [src.occupant.oxyloss]
      Brute damage: [src.occupant.bruteloss]
      Fire damage: [src.occupant.fireloss]
      Toxin damage: [src.occupant.toxloss]
      Body temperature: [src.occupant.bodytemperature]" : "None"]
      + + "} + + user << browse(dat, "window=cryo") + onclose(user, "cryo") + + Topic(href, href_list) + if (( usr.machine==src && ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) + if(href_list["start"]) + src.on = !src.on + build_icon() + if(href_list["eject"]) + beaker:loc = src.loc + beaker = null + + src.updateUsrDialog() + src.add_fingerprint(usr) + return + + attackby(var/obj/item/weapon/G as obj, var/mob/user as mob) + if(istype(G, /obj/item/weapon/reagent_containers/glass)) + if(src.beaker) + user << "A beaker is already loaded into the machine." + return + + src.beaker = G + user.drop_item() + G.loc = src + user.visible_message("[user] adds a beaker to \the [src]!", "You add a beaker to the [src]!") + else if(istype(G, /obj/item/weapon/grab)) + if(!ismob(G:affecting)) + return + if (src.occupant) + user << "\blue The sleeper is already occupied!" + return + if (G:affecting.abiotic()) + user << "Subject may not have abiotic items on." + return + var/mob/M = G:affecting + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + src.occupant = M + for(var/obj/O in src) + O.loc = src.loc + src.add_fingerprint(user) + build_icon() + del(G) + src.updateUsrDialog() + return + + proc + add_overlays() + src.overlays = list(O1) + + build_icon() + if(on) + if(src.occupant) + icon_state = "celltop_1" + else + icon_state = "celltop" + else + icon_state = "celltop-p" + O1 = new /obj/overlay( ) + O1.icon = 'Cryogenic2.dmi' + if(src.node) + O1.icon_state = "cryo_bottom_[src.on]" + else + O1.icon_state = "cryo_bottom" + O1.pixel_y = -32.0 + src.pixel_y = 32 + add_overlays() + + process_occupant() + if(air_contents.total_moles() < 10) + return + if(occupant) + if(occupant.stat == 2) + return + occupant.bodytemperature += 2*(air_contents.temperature - occupant.bodytemperature)*current_heat_capacity/(current_heat_capacity + air_contents.heat_capacity()) + occupant.bodytemperature = max(occupant.bodytemperature, air_contents.temperature) // this is so ugly i'm sorry for doing it i'll fix it later i promise + occupant.stat = 1 + if(occupant.bodytemperature < T0C) + occupant.sleeping = max(5, (1/occupant.bodytemperature)*2000) + occupant.paralysis = max(5, (1/occupant.bodytemperature)*3000) + if(air_contents.oxygen > 2) + if(occupant.oxyloss) occupant.oxyloss = max(0, occupant.oxyloss - 1) + else + occupant.oxyloss -= 1 + if(occupant.bodytemperature < 225) + if(occupant.bruteloss) occupant.bruteloss = max(0, occupant.bruteloss - 1) + if(occupant.fireloss) occupant.fireloss = max(0, occupant.fireloss - 1) + if(occupant.toxloss) occupant.toxloss = max(0, occupant.toxloss - 1) + if(beaker && (next_trans == 0)) + beaker:reagents.trans_to(occupant, 1, 10) + beaker:reagents.reaction(occupant) + next_trans++ + if(next_trans == 10) + next_trans = 0 + + heat_gas_contents() + if(air_contents.total_moles() < 1) + return + var/air_heat_capacity = air_contents.heat_capacity() + var/combined_heat_capacity = current_heat_capacity + air_heat_capacity + if(combined_heat_capacity > 0) + var/combined_energy = T20C*current_heat_capacity + air_heat_capacity*air_contents.temperature + air_contents.temperature = combined_energy/combined_heat_capacity + + expel_gas() + if(air_contents.total_moles() < 1) + return + var/datum/gas_mixture/expel_gas = new + var/remove_amount = air_contents.total_moles()/100 + expel_gas = air_contents.remove(remove_amount) + expel_gas.temperature = T20C // Lets expel hot gas and see if that helps people not die as they are removed + loc.assume_air(expel_gas) + + go_out() + if(!( src.occupant )) + return + //for(var/obj/O in src) + // O.loc = src.loc + if (src.occupant.client) + src.occupant.client.eye = src.occupant.client.mob + src.occupant.client.perspective = MOB_PERSPECTIVE + src.occupant.loc = src.loc + src.occupant = null + build_icon() + return + + verb + move_eject() + set src in oview(1) + if (usr.stat != 0) + return + src.go_out() + add_fingerprint(usr) + return + + move_inside() + set src in oview(1) + if (usr.stat != 0 || stat & (NOPOWER|BROKEN)) + return + if (src.occupant) + usr << "\blue The cell is already occupied!" + return + if (usr.abiotic()) + usr << "Subject may not have abiotic items on." + return + if(!src.node) + usr << "The cell is not corrrectly connected to its pipe network!" + return + usr.pulling = null + usr.client.perspective = EYE_PERSPECTIVE + usr.client.eye = src + usr.loc = src + src.occupant = usr + /*for(var/obj/O in src) + O.loc = src.loc*/ + src.add_fingerprint(usr) + build_icon() + return + + + + + +/mob/living/carbon/human/abiotic() + if ((src.l_hand && !( src.l_hand.abstract )) || (src.r_hand && !( src.r_hand.abstract )) || (src.back || src.wear_mask || src.head || src.shoes || src.w_uniform || src.wear_suit || src.glasses || src.ears || src.gloves)) + return 1 + else + return 0 + return + +/mob/proc/abiotic() + if ((src.l_hand && !( src.l_hand.abstract )) || (src.r_hand && !( src.r_hand.abstract )) || src.back || src.wear_mask) + return 1 + else + return 0 + return + +/datum/data/function/proc/reset() + return + +/datum/data/function/proc/r_input(href, href_list, mob/user as mob) + return + +/datum/data/function/proc/display() + return \ No newline at end of file diff --git a/code/game/machinery/dispenser.dm b/code/game/machinery/dispenser.dm new file mode 100644 index 0000000000000..de309396dd737 --- /dev/null +++ b/code/game/machinery/dispenser.dm @@ -0,0 +1,100 @@ +/obj/machinery/dispenser/ex_act(severity) + switch(severity) + if(1.0) + //SN src = null + del(src) + return + if(2.0) + if (prob(50)) + //SN src = null + del(src) + return + if(3.0) + if (prob(25)) + while(src.o2tanks > 0) + new /obj/item/weapon/tank/oxygen( src.loc ) + src.o2tanks-- + while(src.pltanks > 0) + new /obj/item/weapon/tank/plasma( src.loc ) + src.pltanks-- + else + return + +/obj/machinery/dispenser/blob_act() + if (prob(25)) + while(src.o2tanks > 0) + new /obj/item/weapon/tank/oxygen( src.loc ) + src.o2tanks-- + while(src.pltanks > 0) + new /obj/item/weapon/tank/plasma( src.loc ) + src.pltanks-- + del(src) + +/obj/machinery/dispenser/meteorhit() + while(src.o2tanks > 0) + new /obj/item/weapon/tank/oxygen( src.loc ) + src.o2tanks-- + while(src.pltanks > 0) + new /obj/item/weapon/tank/plasma( src.loc ) + src.pltanks-- + del(src) + return + +/obj/machinery/dispenser/process() + return + +/obj/machinery/dispenser/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/dispenser/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/dispenser/attack_hand(mob/user as mob) + if(stat & BROKEN) + return + user.machine = src + var/dat = text("Loaded Tank Dispensing Unit
      \nOxygen: [] []
      \nPlasma: [] []
      \n
      ", src.o2tanks, (src.o2tanks ? text("Dispense", src) : "empty"), src.pltanks, (src.pltanks ? text("Dispense", src) : "empty")) + user << browse(dat, "window=dispenser") + onclose(user, "dispenser") + return + +/obj/machinery/dispenser/Topic(href, href_list) + if(stat & BROKEN) + return + if(usr.stat || usr.restrained()) + return + if (!(istype(usr, /mob/living/carbon/human) || ticker)) + if (!istype(usr, /mob/living/silicon/ai)) + usr << "\red You don't have the dexterity to do this!" + else + usr << "\red You are unable to dispense anything, since the controls are physical levers which don't go through any other kind of input." + return + + if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf)))) + usr.machine = src + if (href_list["oxygen"]) + if (text2num(href_list["oxygen"])) + if (src.o2tanks > 0) + use_power(5) + new /obj/item/weapon/tank/oxygen( src.loc ) + src.o2tanks-- + if (istype(src.loc, /mob)) + attack_hand(src.loc) + else + if (href_list["plasma"]) + if (text2num(href_list["plasma"])) + if (src.pltanks > 0) + use_power(5) + new /obj/item/weapon/tank/plasma( src.loc ) + src.pltanks-- + if (istype(src.loc, /mob)) + attack_hand(src.loc) + src.add_fingerprint(usr) + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + else + usr << browse(null, "window=dispenser") + return + return + diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm new file mode 100644 index 0000000000000..50ca2b0e378d5 --- /dev/null +++ b/code/game/machinery/door_control.dm @@ -0,0 +1,88 @@ +/obj/machinery/door_control/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door_control/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door_control/attackby(obj/item/weapon/W, mob/user as mob) + if(istype(W, /obj/item/device/detective_scanner)) + return + return src.attack_hand(user) + +/obj/machinery/door_control/attack_hand(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) + return + use_power(5) + icon_state = "doorctrl1" + + for(var/obj/machinery/door/poddoor/M in machines) + if (M.id == src.id) + if (M.density) + spawn( 0 ) + M.open() + return + else + spawn( 0 ) + M.close() + return + + spawn(15) + if(!(stat & NOPOWER)) + icon_state = "doorctrl0" + src.add_fingerprint(usr) + +/obj/machinery/door_control/power_change() + ..() + if(stat & NOPOWER) + icon_state = "doorctrl-p" + else + icon_state = "doorctrl0" + +/obj/machinery/driver_button/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/driver_button/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/driver_button/attackby(obj/item/weapon/W, mob/user as mob) + + if(istype(W, /obj/item/device/detective_scanner)) + return + return src.attack_hand(user) + +/obj/machinery/driver_button/attack_hand(mob/user as mob) + + if(stat & (NOPOWER|BROKEN)) + return + if(active) + return + + use_power(5) + + active = 1 + icon_state = "launcheract" + + for(var/obj/machinery/door/poddoor/M in machines) + if (M.id == src.id) + spawn( 0 ) + M.open() + return + + sleep(20) + + for(var/obj/machinery/mass_driver/M in machines) + if(M.id == src.id) + M.drive() + + sleep(50) + + for(var/obj/machinery/door/poddoor/M in machines) + if (M.id == src.id) + spawn( 0 ) + M.close() + return + + icon_state = "launcherbtt" + active = 0 + + return \ No newline at end of file diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm new file mode 100644 index 0000000000000..610756e8a659f --- /dev/null +++ b/code/game/machinery/doors/airlock.dm @@ -0,0 +1,924 @@ +#define AIRLOCK_WIRE_IDSCAN 1 +#define AIRLOCK_WIRE_MAIN_POWER1 2 +#define AIRLOCK_WIRE_MAIN_POWER2 3 +#define AIRLOCK_WIRE_DOOR_BOLTS 4 +#define AIRLOCK_WIRE_BACKUP_POWER1 5 +#define AIRLOCK_WIRE_BACKUP_POWER2 6 +#define AIRLOCK_WIRE_OPEN_DOOR 7 +#define AIRLOCK_WIRE_AI_CONTROL 8 +#define AIRLOCK_WIRE_ELECTRIFY 9 + +/* + New methods: + pulse - sends a pulse into a wire for hacking purposes + cut - cuts a wire and makes any necessary state changes + mend - mends a wire and makes any necessary state changes + isWireColorCut - returns 1 if that color wire is cut, or 0 if not + isWireCut - returns 1 if that wire (e.g. AIRLOCK_WIRE_DOOR_BOLTS) is cut, or 0 if not + canAIControl - 1 if the AI can control the airlock, 0 if not (then check canAIHack to see if it can hack in) + canAIHack - 1 if the AI can hack into the airlock to recover control, 0 if not. Also returns 0 if the AI does not *need* to hack it. + arePowerSystemsOn - 1 if the main or backup power are functioning, 0 if not. Does not check whether the power grid is charged or an APC has equipment on or anything like that. (Check (stat & NOPOWER) for that) + requiresIDs - 1 if the airlock is requiring IDs, 0 if not + isAllPowerCut - 1 if the main and backup power both have cut wires. + regainMainPower - handles the effects of main power coming back on. + loseMainPower - handles the effects of main power going offline. Usually (if one isn't already running) spawn a thread to count down how long it will be offline - counting down won't happen if main power was completely cut along with backup power, though, the thread will just sleep. + loseBackupPower - handles the effects of backup power going offline. + regainBackupPower - handles the effects of main power coming back on. + shock - has a chance of electrocuting its target. +*/ + +//This generates the randomized airlock wire assignments for the game. +/proc/RandomAirlockWires() + //to make this not randomize the wires, just set index to 1 and increment it in the flag for loop (after doing everything else). + var/list/wires = list(0, 0, 0, 0, 0, 0, 0, 0, 0) + airlockIndexToFlag = list(0, 0, 0, 0, 0, 0, 0, 0, 0) + airlockIndexToWireColor = list(0, 0, 0, 0, 0, 0, 0, 0, 0) + airlockWireColorToIndex = list(0, 0, 0, 0, 0, 0, 0, 0, 0) + var/flagIndex = 1 + for (var/flag=1, flag<512, flag+=flag) + var/valid = 0 + while (!valid) + var/colorIndex = rand(1, 9) + if (wires[colorIndex]==0) + valid = 1 + wires[colorIndex] = flag + airlockIndexToFlag[flagIndex] = flag + airlockIndexToWireColor[flagIndex] = colorIndex + airlockWireColorToIndex[colorIndex] = flagIndex + flagIndex+=1 + return wires + +/* Example: +Airlock wires color -> flag are { 64, 128, 256, 2, 16, 4, 8, 32, 1 }. +Airlock wires color -> index are { 7, 8, 9, 2, 5, 3, 4, 6, 1 }. +Airlock index -> flag are { 1, 2, 4, 8, 16, 32, 64, 128, 256 }. +Airlock index -> wire color are { 9, 4, 6, 7, 5, 8, 1, 2, 3 }. +*/ + +/obj/machinery/door/airlock + name = "Airlock" + icon = 'doorint.dmi' + icon_state = "door_closed" + + var/aiControlDisabled = 0 //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in. + var/secondsMainPowerLost = 0 //The number of seconds until power is restored. + var/secondsBackupPowerLost = 0 //The number of seconds until power is restored. + var/spawnPowerRestoreRunning = 0 + var/welded = null + var/locked = 0 + var/wires = 511 + secondsElectrified = 0 //How many seconds remain until the door is no longer electrified. -1 if it is permanently electrified until someone fixes it. + var/aiDisabledIdScanner = 0 + var/aiHacking = 0 + var/obj/machinery/door/airlock/closeOther = null + var/closeOtherId = null + var/list/signalers[9] + var/lockdownbyai = 0 + autoclose = 1 + +/obj/machinery/door/airlock/command + name = "Airlock" + icon = 'Doorcom.dmi' + req_access = list(access_heads) + +/obj/machinery/door/airlock/security + name = "Airlock" + icon = 'Doorsec.dmi' + req_access = list(access_security) + + +/obj/machinery/door/airlock/engineering + name = "Airlock" + icon = 'Dooreng.dmi' + req_access = list(access_engine) + +/obj/machinery/door/airlock/medical + name = "Airlock" + icon = 'Doormed.dmi' + req_access = list(access_medical) + +/obj/machinery/door/airlock/maintenance + name = "Maintenance Access" + icon = 'Doormaint.dmi' + req_access = list(access_maint_tunnels) + +/obj/machinery/door/airlock/external + name = "External Airlock" + icon = 'Doorext.dmi' + +/obj/machinery/door/airlock/glass + name = "Glass Airlock" + icon = 'Doorglass.dmi' + opacity = 0 + +/* +About the new airlock wires panel: +* An airlock wire dialog can be accessed by the normal way or by using wirecutters or a multitool on the door while the wire-panel is open. This would show the following wires, which you can either wirecut/mend or send a multitool pulse through. There are 9 wires. +* one wire from the ID scanner. Sending a pulse through this flashes the red light on the door (if the door has power). If you cut this wire, the door will stop recognizing valid IDs. (If the door has 0000 access, it still opens and closes, though) +* two wires for power. Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter). Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be \red open, but bolts-raising will not work. Cutting these wires may electrocute the user. +* one wire for door bolts. Sending a pulse through this drops door bolts (whether the door is powered or not) or raises them (if it is). Cutting this wire also drops the door bolts, and mending it does not raise them. If the wire is cut, trying to raise the door bolts will not work. +* two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter). Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user. +* one wire for opening the door. Sending a pulse through this while the door has power makes it open the door if no access is required. +* one wire for AI control. Sending a pulse through this blocks AI control for a second or so (which is enough to see the AI control light on the panel dialog go off and back on again). Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all. +* one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds. Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted. (Currently it is also STAYING electrified until someone mends the wire) +*/ + + +/obj/machinery/door/airlock/proc/pulse(var/wireColor) + //var/wireFlag = airlockWireColorToFlag[wireColor] //not used in this function + var/wireIndex = airlockWireColorToIndex[wireColor] + switch(wireIndex) + if(AIRLOCK_WIRE_IDSCAN) + //Sending a pulse through this flashes the red light on the door (if the door has power). + if ((src.arePowerSystemsOn()) && (!(stat & NOPOWER))) + animate("deny") + if (AIRLOCK_WIRE_MAIN_POWER1 || AIRLOCK_WIRE_MAIN_POWER2) + //Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter). + src.loseMainPower() + if (AIRLOCK_WIRE_DOOR_BOLTS) + //one wire for door bolts. Sending a pulse through this drops door bolts if they're not down (whether power's on or not), + //raises them if they are down (only if power's on) + if (!src.locked) + src.locked = 1 + usr << "You hear a click from the bottom of the door." + src.updateUsrDialog() + else + if(src.arePowerSystemsOn()) //only can raise bolts if power's on + src.locked = 0 + src.updateUsrDialog() + usr << "You hear a click from inside the door." + update_icon() + + if (AIRLOCK_WIRE_BACKUP_POWER1 || AIRLOCK_WIRE_BACKUP_POWER2) + //two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter). + src.loseBackupPower() + if (AIRLOCK_WIRE_AI_CONTROL) + if (src.aiControlDisabled == 0) + src.aiControlDisabled = 1 + else if (src.aiControlDisabled == -1) + src.aiControlDisabled = 2 + src.updateDialog() + spawn(10) + if (src.aiControlDisabled == 1) + src.aiControlDisabled = 0 + else if (src.aiControlDisabled == 2) + src.aiControlDisabled = -1 + src.updateDialog() + if (AIRLOCK_WIRE_ELECTRIFY) + //one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds. + if (src.secondsElectrified==0) + src.secondsElectrified = 30 + spawn(10) + //TODO: Move this into process() and make pulsing reset secondsElectrified to 30 + while (src.secondsElectrified>0) + src.secondsElectrified-=1 + if (src.secondsElectrified<0) + src.secondsElectrified = 0 + src.updateUsrDialog() + sleep(10) + if(AIRLOCK_WIRE_OPEN_DOOR) + //tries to open the door without ID + //will succeed only if the ID wire is cut or the door requires no access + if (!src.requiresID() || src.check_access(null)) + if (src.density) + open() + else + close() + + + +/obj/machinery/door/airlock/proc/cut(var/wireColor) + var/wireFlag = airlockWireColorToFlag[wireColor] + var/wireIndex = airlockWireColorToIndex[wireColor] + wires &= ~wireFlag + switch(wireIndex) + if(AIRLOCK_WIRE_MAIN_POWER1 || AIRLOCK_WIRE_MAIN_POWER2) + //Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be crowbarred open, but bolts-raising will not work. Cutting these wires may electocute the user. + src.loseMainPower() + src.shock(usr, 50) + src.updateUsrDialog() + if (AIRLOCK_WIRE_DOOR_BOLTS) + //Cutting this wire also drops the door bolts, and mending it does not raise them. (This is what happens now, except there are a lot more wires going to door bolts at present) + if (src.locked!=1) + src.locked = 1 + update_icon() + src.updateUsrDialog() + if (AIRLOCK_WIRE_BACKUP_POWER1 || AIRLOCK_WIRE_BACKUP_POWER2) + //Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user. + src.loseBackupPower() + src.shock(usr, 50) + src.updateUsrDialog() + if (AIRLOCK_WIRE_AI_CONTROL) + //one wire for AI control. Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all. + //aiControlDisabled: If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in. + if (src.aiControlDisabled == 0) + src.aiControlDisabled = 1 + else if (src.aiControlDisabled == -1) + src.aiControlDisabled = 2 + src.updateUsrDialog() + if (AIRLOCK_WIRE_ELECTRIFY) + //Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted. + if (src.secondsElectrified != -1) + src.secondsElectrified = -1 + + +/obj/machinery/door/airlock/proc/mend(var/wireColor) + var/wireFlag = airlockWireColorToFlag[wireColor] + var/wireIndex = airlockWireColorToIndex[wireColor] //not used in this function + wires |= wireFlag + switch(wireIndex) + if(AIRLOCK_WIRE_MAIN_POWER1 || AIRLOCK_WIRE_MAIN_POWER2) + if ((!src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1)) && (!src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2))) + src.regainMainPower() + src.shock(usr, 50) + src.updateUsrDialog() + if (AIRLOCK_WIRE_BACKUP_POWER1 || AIRLOCK_WIRE_BACKUP_POWER2) + if ((!src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1)) && (!src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2))) + src.regainBackupPower() + src.shock(usr, 50) + src.updateUsrDialog() + if (AIRLOCK_WIRE_AI_CONTROL) + //one wire for AI control. Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all. + //aiControlDisabled: If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in. + if (src.aiControlDisabled == 1) + src.aiControlDisabled = 0 + else if (src.aiControlDisabled == 2) + src.aiControlDisabled = -1 + src.updateUsrDialog() + if (AIRLOCK_WIRE_ELECTRIFY) + if (src.secondsElectrified == -1) + src.secondsElectrified = 0 + +/obj/machinery/door/airlock/proc/isElectrified() + if(src.secondsElectrified > 0) + return 1 + else return 0 + +/obj/machinery/door/airlock/proc/isWireColorCut(var/wireColor) + var/wireFlag = airlockWireColorToFlag[wireColor] + return ((src.wires & wireFlag) == 0) + +/obj/machinery/door/airlock/proc/isWireCut(var/wireIndex) + var/wireFlag = airlockIndexToFlag[wireIndex] + return ((src.wires & wireFlag) == 0) + +/obj/machinery/door/airlock/proc/canAIControl() + return ((src.aiControlDisabled!=1) && (!src.isAllPowerCut())); + +/obj/machinery/door/airlock/proc/canAIHack() + return ((src.aiControlDisabled==1) && (!src.isAllPowerCut())); + +/obj/machinery/door/airlock/proc/arePowerSystemsOn() + return (src.secondsMainPowerLost==0 || src.secondsBackupPowerLost==0) + +/obj/machinery/door/airlock/requiresID() + return !(src.isWireCut(AIRLOCK_WIRE_IDSCAN) || aiDisabledIdScanner) + +/obj/machinery/door/airlock/proc/isAllPowerCut() + var/retval=0 + if (src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1) || src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2)) + if (src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1) || src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2)) + retval=1 + return retval + +/obj/machinery/door/airlock/proc/regainMainPower() + if (src.secondsMainPowerLost > 0) + src.secondsMainPowerLost = 0 + +/obj/machinery/door/airlock/proc/loseMainPower() + if (src.secondsMainPowerLost <= 0) + src.secondsMainPowerLost = 60 + if (src.secondsBackupPowerLost < 10) + src.secondsBackupPowerLost = 10 + if (!src.spawnPowerRestoreRunning) + src.spawnPowerRestoreRunning = 1 + spawn(0) + var/cont = 1 + while (cont) + sleep(10) + cont = 0 + if (src.secondsMainPowerLost>0) + if ((!src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1)) && (!src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2))) + src.secondsMainPowerLost -= 1 + src.updateDialog() + cont = 1 + + if (src.secondsBackupPowerLost>0) + if ((!src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1)) && (!src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2))) + src.secondsBackupPowerLost -= 1 + src.updateDialog() + cont = 1 + src.spawnPowerRestoreRunning = 0 + src.updateDialog() + +/obj/machinery/door/airlock/proc/loseBackupPower() + if (src.secondsBackupPowerLost < 60) + src.secondsBackupPowerLost = 60 + +/obj/machinery/door/airlock/proc/regainBackupPower() + if (src.secondsBackupPowerLost > 0) + src.secondsBackupPowerLost = 0 + +//borrowed from the grille's get_connection +/obj/machinery/door/airlock/proc/get_connection() + if(stat & NOPOWER) return 0 + return 1 + +// shock user with probability prb (if all connections & power are working) +// returns 1 if shocked, 0 otherwise +// The preceding comment was borrowed from the grille's shock script +/obj/machinery/door/airlock/proc/shock(mob/user, prb) + + + if(!prob(prb)) + return 0 //you lucked out, no shock for you + + var/net = get_connection() // find the powernet of the connected cable + + if(!net) // cable is unpowered + return 0 + + + if (src.airlockelectrocute(user, prb, net)) + return 1 + else + return 0 + +/obj/machinery/door/airlock/proc/airlockelectrocute(mob/user, netnum) + //You're probably getting shocked deal w/ it + + if(!netnum) // unconnected cable is unpowered + return 0 + + var/prot = 1 + + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + + if(H.gloves) + var/obj/item/clothing/gloves/G = H.gloves + + prot = G.siemens_coefficient + else if (istype(user, /mob/living/silicon)) + return 0 + + if(prot == 0) // elec insulted gloves protect completely + return 0 + + //ok you're getting shocked now + var/datum/powernet/PN // find the powernet + if(powernets && powernets.len >= netnum) + PN = powernets[netnum] + + var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread + s.set_up(5, 1, src) + s.start() + + var/shock_damage = 0 + if(PN.avail > 750000) //someone juiced up the grid enough, people going to die! + shock_damage = min(rand(70,145),rand(70,145))*prot + else if(PN.avail > 100000) + shock_damage = min(rand(35,110),rand(35,110))*prot + else if(PN.avail > 75000) + shock_damage = min(rand(30,100),rand(30,100))*prot + else if(PN.avail > 50000) + shock_damage = min(rand(25,90),rand(25,90))*prot + else if(PN.avail > 25000) + shock_damage = min(rand(20,80),rand(20,80))*prot + else if(PN.avail > 10000) + shock_damage = min(rand(20,65),rand(20,65))*prot + else + shock_damage = min(rand(20,45),rand(20,45))*prot + +// message_admins("\blue ADMIN: DEBUG: shock_damage = [shock_damage] PN.avail = [PN.avail] user = [user] netnum = [netnum]") + + user.burn_skin(shock_damage) + user.fireloss += shock_damage + user.updatehealth() + user << "\red You feel a powerful shock course through your body!" + sleep(1) + + if(user.stunned < shock_damage) user.stunned = shock_damage + if(user.weakened < 20*prot) user.weakened = 20*prot + for(var/mob/M in viewers(src)) + if(M == user) continue + M.show_message("\red [user.name] was shocked by the [src.name]!", 3, "\red You hear a heavy electrical crack", 2) + return 1 + + +/obj/machinery/door/airlock/update_icon() + if(overlays) overlays = null + if(density) + if(locked) + icon_state = "door_locked" + else + icon_state = "door_closed" + if(p_open || welded) + overlays = list() + if(p_open) + overlays += image(icon, "panel_open") + if(welded) + overlays += image(icon, "welded") + else + icon_state = "door_open" + + return + +/obj/machinery/door/airlock/animate(animation) + switch(animation) + if("opening") + if(overlays) overlays = null + if(p_open) + icon_state = "o_door_opening" //can not use flick due to BYOND bug updating overlays right before flicking + else + flick("door_opening", src) + if("closing") + if(overlays) overlays = null + if(p_open) + flick("o_door_closing", src) + else + flick("door_closing", src) + if("spark") + flick("door_spark", src) + if("deny") + flick("door_deny", src) + return + +/obj/machinery/door/airlock/attack_ai(mob/user as mob) + if (!src.canAIControl()) + if (src.canAIHack()) + src.hack(user) + return + + //Separate interface for the AI. + user.machine = src + var/t1 = text("Airlock Control
      \n") + if (src.secondsMainPowerLost > 0) + if ((!src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1)) && (!src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2))) + t1 += text("Main power is offline for [] seconds.
      \n", src.secondsMainPowerLost) + else + t1 += text("Main power is offline indefinitely.
      \n") + else + t1 += text("Main power is online.") + + if (src.secondsBackupPowerLost > 0) + if ((!src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1)) && (!src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2))) + t1 += text("Backup power is offline for [] seconds.
      \n", src.secondsBackupPowerLost) + else + t1 += text("Backup power is offline indefinitely.
      \n") + else if (src.secondsMainPowerLost > 0) + t1 += text("Backup power is online.") + else + t1 += text("Backup power is offline, but will turn on if main power fails.") + t1 += "
      \n" + + if (src.isWireCut(AIRLOCK_WIRE_IDSCAN)) + t1 += text("IdScan wire is cut.
      \n") + else if (src.aiDisabledIdScanner) + t1 += text("IdScan disabled. Enable?
      \n", src) + else + t1 += text("IdScan enabled. Disable?
      \n", src) + + if (src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1)) + t1 += text("Main Power Input wire is cut.
      \n") + if (src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2)) + t1 += text("Main Power Output wire is cut.
      \n") + if (src.secondsMainPowerLost == 0) + t1 += text("Temporarily disrupt main power?.
      \n", src) + if (src.secondsBackupPowerLost == 0) + t1 += text("Temporarily disrupt backup power?.
      \n", src) + + if (src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1)) + t1 += text("Backup Power Input wire is cut.
      \n") + if (src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2)) + t1 += text("Backup Power Output wire is cut.
      \n") + + if (src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + t1 += text("Door bolt drop wire is cut.
      \n") + else if (!src.locked) + t1 += text("Door bolts are up. Drop them?
      \n", src) + else + t1 += text("Door bolts are down.") + if (src.arePowerSystemsOn()) + t1 += text(" Raise?
      \n", src) + else + t1 += text(" Cannot raise door bolts due to power failure.
      \n") + if (src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) + t1 += text("Electrification wire is cut.
      \n") + if (src.secondsElectrified==-1) + t1 += text("Door is electrified indefinitely. Un-electrify it?
      \n", src) + else if (src.secondsElectrified>0) + t1 += text("Door is electrified temporarily ([] seconds). Un-electrify it?
      \n", src.secondsElectrified, src) + else + t1 += text("Door is not electrified. Electrify it for 30 seconds? Or, Electrify it indefinitely until someone cancels the electrification?
      \n", src, src) + + if (src.welded) + t1 += text("Door appears to have been welded shut.
      \n") + else if (!src.locked) + if (src.density) + t1 += text("Open door
      \n", src) + else + t1 += text("Close door
      \n", src) + + t1 += text("

      Close

      \n", src) + user << browse(t1, "window=airlock") + onclose(user, "airlock") + +//aiDisable - 1 idscan, 2 disrupt main power, 3 disrupt backup power, 4 drop door bolts, 5 un-electrify door, 7 close door +//aiEnable - 1 idscan, 4 raise door bolts, 5 electrify door for 30 seconds, 6 electrify door indefinitely, 7 open door + + +/obj/machinery/door/airlock/proc/hack(mob/user as mob) + if (src.aiHacking==0) + src.aiHacking=1 + spawn(20) + //TODO: Make this take a minute + user << "Airlock AI control has been blocked. Beginning fault-detection." + sleep(50) + if (src.canAIControl()) + user << "Alert cancelled. Airlock control has been restored without our assistance." + src.aiHacking=0 + return + else if (!src.canAIHack()) + user << "We've lost our connection! Unable to hack airlock." + src.aiHacking=0 + return + user << "Fault confirmed: airlock control wire disabled or cut." + sleep(20) + user << "Attempting to hack into airlock. This may take some time." + sleep(200) + if (src.canAIControl()) + user << "Alert cancelled. Airlock control has been restored without our assistance." + src.aiHacking=0 + return + else if (!src.canAIHack()) + user << "We've lost our connection! Unable to hack airlock." + src.aiHacking=0 + return + user << "Upload access confirmed. Loading control program into airlock software." + sleep(170) + if (src.canAIControl()) + user << "Alert cancelled. Airlock control has been restored without our assistance." + src.aiHacking=0 + return + else if (!src.canAIHack()) + user << "We've lost our connection! Unable to hack airlock." + src.aiHacking=0 + return + user << "Transfer complete. Forcing airlock to execute program." + sleep(50) + //disable blocked control + src.aiControlDisabled = 2 + user << "Receiving control information from airlock." + sleep(10) + //bring up airlock dialog + src.aiHacking = 0 + src.attack_ai(user) + + +/obj/machinery/door/airlock/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door/airlock/attack_hand(mob/user as mob) + if (!istype(usr, /mob/living/silicon)) + if (src.isElectrified()) + if(src.shock(user, 100)) + return + + if (ishuman(user) && prob(40) && src.density) + var/mob/living/carbon/human/H = user + if(H.brainloss >= 60) + playsound(src.loc, 'bang.ogg', 25, 1) + if(!istype(H.head, /obj/item/clothing/head/helmet)) + for(var/mob/M in viewers(src, null)) + M << "\red [user] headbutts the airlock." + var/datum/organ/external/affecting = H.organs["head"] + affecting.take_damage(10, 0) + H.stunned = 8 + H.weakened = 5 + H.UpdateDamage() + H.UpdateDamageIcon() + else + for(var/mob/M in viewers(src, null)) + M << "\red [user] headbutts the airlock. Good thing they're wearing a helmet." + return + + if (src.p_open) + user.machine = src + var/t1 = text("Access Panel
      \n") + + //t1 += text("[]: ", airlockFeatureNames[airlockWireColorToIndex[9]]) + var/list/wires = list( + "Orange" = 1, + "Dark red" = 2, + "White" = 3, + "Yellow" = 4, + "Red" = 5, + "Blue" = 6, + "Green" = 7, + "Grey" = 8, + "Black" = 9 + ) + for(var/wiredesc in wires) + var/is_uncut = src.wires & airlockWireColorToFlag[wires[wiredesc]] + t1 += "[wiredesc] wire: " + if(!is_uncut) + t1 += "Mend" + else + t1 += "Cut " + t1 += "Pulse " + if(src.signalers[wires[wiredesc]]) + t1 += "Detach signaler" + else + t1 += "Attach signaler" + t1 += "
      " + + t1 += text("
      \n[]
      \n[]
      \n[]", (src.locked ? "The door bolts have fallen!" : "The door bolts look up."), ((src.arePowerSystemsOn() && !(stat & NOPOWER)) ? "The test light is on." : "The test light is off!"), (src.aiControlDisabled==0 ? "The 'AI control allowed' light is on." : "The 'AI control allowed' light is off.")) + + t1 += text("

      Close

      \n", src) + + user << browse(t1, "window=airlock") + onclose(user, "airlock") + + else + ..(user) + return + + +/obj/machinery/door/airlock/Topic(href, href_list) + ..() + if (usr.stat || usr.restrained() ) + return + if (href_list["close"]) + usr << browse(null, "window=airlock") + if (usr.machine==src) + usr.machine = null + return + if (!istype(usr, /mob/living/silicon)) + if(!src.p_open) + return + if ((in_range(src, usr) && istype(src.loc, /turf))) + usr.machine = src + if (href_list["wires"]) + var/t1 = text2num(href_list["wires"]) + if (!( istype(usr.equipped(), /obj/item/weapon/wirecutters) )) + usr << "You need wirecutters!" + return + if (src.isWireColorCut(t1)) + src.mend(t1) + else + src.cut(t1) + else if (href_list["pulse"]) + var/t1 = text2num(href_list["pulse"]) + if (!istype(usr.equipped(), /obj/item/device/multitool)) + usr << "You need a multitool!" + return + if (src.isWireColorCut(t1)) + usr << "You can't pulse a cut wire." + return + else + src.pulse(t1) + else if(href_list["signaler"]) + var/wirenum = text2num(href_list["signaler"]) + if(!istype(usr.equipped(), /obj/item/device/radio/signaler)) + usr << "You need a signaller!" + return + if(src.isWireColorCut(wirenum)) + usr << "You can't attach a signaller to a cut wire." + return + var/obj/item/device/radio/signaler/R = usr.equipped() + if(!R.b_stat) + usr << "This radio can't be attached!" + return + var/mob/M = usr + M.drop_item() + R.loc = src + R.airlock_wire = wirenum + src.signalers[wirenum] = R + else if(href_list["remove-signaler"]) + var/wirenum = text2num(href_list["remove-signaler"]) + if(!(src.signalers[wirenum])) + usr << "There's no signaller attached to that wire!" + return + var/obj/item/device/radio/signaler/R = src.signalers[wirenum] + R.loc = usr.loc + R.airlock_wire = null + src.signalers[wirenum] = null + + src.update_icon() + add_fingerprint(usr) + src.updateUsrDialog() + else + //AI + if (!src.canAIControl()) + usr << "Airlock control connection lost!" + return + //aiDisable - 1 idscan, 2 disrupt main power, 3 disrupt backup power, 4 drop door bolts, 5 un-electrify door, 7 close door + //aiEnable - 1 idscan, 4 raise door bolts, 5 electrify door for 30 seconds, 6 electrify door indefinitely, 7 open door + if (href_list["aiDisable"]) + var/code = text2num(href_list["aiDisable"]) + switch (code) + if (1) + //disable idscan + if (src.isWireCut(AIRLOCK_WIRE_IDSCAN)) + usr << "The IdScan wire has been cut - So, you can't disable it, but it is already disabled anyways." + else if (src.aiDisabledIdScanner) + usr << "You've already disabled the IdScan feature." + else + src.aiDisabledIdScanner = 1 + if (2) + //disrupt main power + if (src.secondsMainPowerLost == 0) + src.loseMainPower() + else + usr << "Main power is already offline." + if (3) + //disrupt backup power + if (src.secondsBackupPowerLost == 0) + src.loseBackupPower() + else + usr << "Backup power is already offline." + if (4) + //drop door bolts + if (src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + usr << "You can't drop the door bolts - The door bolt dropping wire has been cut." + else if (src.locked!=1) + src.locked = 1 + update_icon() + if (5) + //un-electrify door + if (src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) + usr << text("Can't un-electrify the airlock - The electrification wire is cut.
      \n") + else if (src.secondsElectrified==-1) + src.secondsElectrified = 0 + else if (src.secondsElectrified>0) + src.secondsElectrified = 0 + if (7) + //close door + if (src.welded) + usr << text("The airlock has been welded shut!
      \n") + else if (src.locked) + usr << text("The door bolts are down!
      \n") + else if (!src.density) + close() + else + usr << text("The airlock is already closed.
      \n") + + else if (href_list["aiEnable"]) + var/code = text2num(href_list["aiEnable"]) + switch (code) + if (1) + //enable idscan + if (src.isWireCut(AIRLOCK_WIRE_IDSCAN)) + usr << "You can't enable IdScan - The IdScan wire has been cut." + else if (src.aiDisabledIdScanner) + src.aiDisabledIdScanner = 0 + else + usr << "The IdScan feature is not disabled." + if (4) + //raise door bolts + if (src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + usr << text("The door bolt drop wire is cut - you can't raise the door bolts.
      \n") + else if (!src.locked) + usr << text("The door bolts are already up.
      \n") + else + if (src.arePowerSystemsOn()) + src.locked = 0 + update_icon() + else + usr << text("Cannot raise door bolts due to power failure.
      \n") + + if (5) + //electrify door for 30 seconds + if (src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) + usr << text("The electrification wire has been cut.
      \n") + else if (src.secondsElectrified==-1) + usr << text("The door is already indefinitely electrified. You'd have to un-electrify it before you can re-electrify it with a non-forever duration.
      \n") + else if (src.secondsElectrified!=0) + usr << text("The door is already electrified. You can't re-electrify it while it's already electrified.
      \n") + else + src.secondsElectrified = 30 + spawn(10) + while (src.secondsElectrified>0) + src.secondsElectrified-=1 + if (src.secondsElectrified<0) + src.secondsElectrified = 0 + src.updateUsrDialog() + sleep(10) + if (6) + //electrify door indefinitely + if (src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) + usr << text("The electrification wire has been cut.
      \n") + else if (src.secondsElectrified==-1) + usr << text("The door is already indefinitely electrified.
      \n") + else if (src.secondsElectrified!=0) + usr << text("The door is already electrified. You can't re-electrify it while it's already electrified.
      \n") + else + src.secondsElectrified = -1 + if (7) + //open door + if (src.welded) + usr << text("The airlock has been welded shut!
      \n") + else if (src.locked) + usr << text("The door bolts are down!
      \n") + else if (src.density) + open() + // close() + else + usr << text("The airlock is already opened.
      \n") + + src.update_icon() + src.updateUsrDialog() + + return + +/obj/machinery/door/airlock/attackby(C as obj, mob/user as mob) + //world << text("airlock attackby src [] obj [] mob []", src, C, user) + if (!istype(usr, /mob/living/silicon)) + if (src.isElectrified()) + if(src.shock(user, 75)) + return + + src.add_fingerprint(user) + if ((istype(C, /obj/item/weapon/weldingtool) && !( src.operating ) && src.density)) + var/obj/item/weapon/weldingtool/W = C + if(W.welding) + if (W.get_fuel() > 2) + W.use_fuel(2) + W.eyecheck(user) + else + user << "Need more welding fuel!" + return + if (!src.welded) + src.welded = 1 + else + src.welded = null + src.update_icon() + return + else if (istype(C, /obj/item/weapon/screwdriver)) + src.p_open = !( src.p_open ) + src.update_icon() + else if (istype(C, /obj/item/weapon/wirecutters)) + return src.attack_hand(user) + else if (istype(C, /obj/item/device/multitool)) + return src.attack_hand(user) + else if (istype(C, /obj/item/device/radio/signaler)) + return src.attack_hand(user) + else if (istype(C, /obj/item/weapon/crowbar)) + if ((src.density) && (!( src.welded ) && !( src.operating ) && ((!src.arePowerSystemsOn()) || (stat & NOPOWER)) && !( src.locked ))) + spawn( 0 ) + src.operating = 1 + animate("opening") + + sleep(15) + + src.density = 0 + update_icon() + + if (!istype(src, /obj/machinery/door/airlock/glass)) + src.sd_SetOpacity(0) + src.operating = 0 + return + else + if ((!src.density) && (!( src.welded ) && !( src.operating ) && !( src.locked ))) + spawn( 0 ) + src.operating = 1 + animate("closing") + + src.density = 1 + sleep(15) + update_icon() + + if ((src.visible) && (!istype(src, /obj/machinery/door/airlock/glass))) + src.sd_SetOpacity(1) + src.operating = 0 + + else + ..() + return + +/obj/machinery/door/airlock/open() + if (src.welded || src.locked || (!src.arePowerSystemsOn()) || (stat & NOPOWER) || src.isWireCut(AIRLOCK_WIRE_OPEN_DOOR)) + return 0 + use_power(50) + playsound(src.loc, 'airlock.ogg', 30, 1) + if (src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density) + src.closeOther.close() + return ..() + +/obj/machinery/door/airlock/close() + if (src.welded || src.locked || (!src.arePowerSystemsOn()) || (stat & NOPOWER) || src.isWireCut(AIRLOCK_WIRE_OPEN_DOOR)) + return + use_power(50) + playsound(src.loc, 'airlock.ogg', 30, 1) + ..() + return + +/obj/machinery/door/airlock/New() + ..() + if (src.closeOtherId != null) + spawn (5) + for (var/obj/machinery/door/airlock/A in machines) + if (A.closeOtherId == src.closeOtherId && A != src) + src.closeOther = A + break \ No newline at end of file diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm new file mode 100644 index 0000000000000..482826623a0d6 --- /dev/null +++ b/code/game/machinery/doors/brigdoors.dm @@ -0,0 +1,203 @@ +/obj/machinery/computer/door_control + name = "Door Control" + icon = 'stationobjs.dmi' + icon_state = "sec_computer" + req_access = list(access_brig) +// var/authenticated = 0.0 if anyone wants to make it so you need to log in in future go ahead. + var/id = 1.0 + +/obj/machinery/computer/door_control/proc/alarm() + if(stat & (NOPOWER|BROKEN)) + return + for(var/obj/machinery/door/window/brigdoor/M in world) + if (M.id == src.id) + if(M.density) + spawn( 0 ) + M.open() + else + spawn( 0 ) + M.close() + src.updateUsrDialog() + return + +/obj/machinery/computer/door_control/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/door_control/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/computer/door_control/attack_hand(var/mob/user as mob) + if(..()) + return + var/dat = "Brig Computer

      " + user.machine = src + for(var/obj/machinery/door/window/brigdoor/M in world) + if(M.id == 1) + dat += text("Door 1: [(M.density ? "Closed" : "Opened")]
      ") + else if(M.id == 2) + dat += text("Door 2: [(M.density ? "Closed" : "Opened")]
      ") + else if(M.id == 3) + dat += text("Door 3: [(M.density ? "Closed" : "Opened")]
      ") + else if(M.id == 4) + dat += text("Door 4: [(M.density ? "Closed" : "Opened")]
      ") + else if(M.id == 5) + dat += text("Door 5: [(M.density ? "Closed" : "Opened")]
      ") + else + world << "Invalid ID detected on brigdoor ([M.x],[M.y],[M.z]) with id [M.id]" + dat += text("
      Open All
      ") + dat += text("Close All
      ") + dat += text("

      Close
      ") + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + +/obj/machinery/computer/door_control/Topic(href, href_list) + if(..()) + return + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.machine = src + if (href_list["setid"]) + if(src.allowed(usr)) + src.id = text2num(href_list["setid"]) + src.alarm() + if (href_list["openall"]) + if(src.allowed(usr)) + for(var/obj/machinery/door/window/brigdoor/M in world) + if(M.density) + M.open() + if (href_list["closeall"]) + if(src.allowed(usr)) + for(var/obj/machinery/door/window/brigdoor/M in world) + if(!M.density) + M.close() + src.add_fingerprint(usr) + src.updateUsrDialog() + return + + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + +/obj/machinery/door_timer + name = "Door Timer" + icon = 'stationobjs.dmi' + icon_state = "doortimer0" + desc = "A remote control switch for a door." + req_access = list(access_brig) + anchored = 1.0 + var/id = null + var/time = 30.0 + var/timing = 0.0 + +/obj/machinery/door_timer/process() + ..() + if (src.timing) + if (src.time > 0) + src.time = round(src.time) - 1 + else + alarm() + src.time = 0 + src.timing = 0 + src.updateDialog() + src.update_icon() + return + +/obj/machinery/door_timer/power_change() + update_icon() + + +/obj/machinery/door_timer/proc/alarm() + if(stat & (NOPOWER|BROKEN)) + return + for(var/obj/machinery/door/window/brigdoor/M in world) + if (M.id == src.id) + if(M.density) + spawn( 0 ) + M.open() + else + spawn( 0 ) + M.close() + for(var/obj/secure_closet/brig/B in world) + if (B.id == src.id) + if(B.locked) + B.locked = 0 + B.icon_state = text("[(B.locked ? "1" : null)]secloset0") + src.updateUsrDialog() + src.update_icon() + return + +/obj/machinery/door_timer/attack_ai(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door_timer/attack_paw(var/mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door_timer/attack_hand(var/mob/user as mob) + if(..()) + return + + var/dat = "Door [src.id] controls" + user.machine = src + var/d2 + if (src.timing) + d2 = text("Stop Timed
      ", src) + else + d2 = text("Initiate Time
      ", src) + var/second = src.time % 60 + var/minute = (src.time - second) / 60 + dat += text("

      \nTimer System: [d2]\nTime Left: [(minute ? text("[minute]:") : null)][second] - - + +") + for(var/obj/machinery/flasher/F in world) + if(F.id == src.id) + if(F.last_flash && world.time < F.last_flash + 150) + dat += text("

      Flash Cell (Charging)", src) + else + dat += text("

      Flash Cell", src) + dat += text("

      Close
      ", user) + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + +/obj/machinery/door_timer/Topic(href, href_list) + if(..()) + return + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.machine = src + if (href_list["time"]) + if(src.allowed(usr)) + src.timing = text2num(href_list["time"]) + else + if (href_list["tp"]) + if(src.allowed(usr)) + var/tp = text2num(href_list["tp"]) + src.time += tp + src.time = min(max(round(src.time), 0), 600) + if (href_list["fc"]) + if(src.allowed(usr)) + for (var/obj/machinery/flasher/F in world) + if (F.id == src.id) + F.flash() + src.add_fingerprint(usr) + src.updateUsrDialog() + src.update_icon() + return + +/obj/machinery/door_timer/proc/update_icon() + if(stat & (NOPOWER)) + icon_state = "doortimer-p" + return + else if(stat & (BROKEN)) + icon_state = "doortimer-b" + return + else + if(src.timing) + icon_state = "doortimer1" + else if(src.time > 0) + icon_state = "doortimer0" + else + spawn( 50 ) + icon_state = "doortimer0" + icon_state = "doortimer2" \ No newline at end of file diff --git a/code/game/machinery/doors/checkForMultipleDoors.dm b/code/game/machinery/doors/checkForMultipleDoors.dm new file mode 100644 index 0000000000000..9005a7fda49d0 --- /dev/null +++ b/code/game/machinery/doors/checkForMultipleDoors.dm @@ -0,0 +1,16 @@ +/obj/machinery/door/proc/checkForMultipleDoors() + if(!src.loc) + return 0 + for(var/obj/machinery/door/D in src.loc) + if(!istype(D, /obj/machinery/door/window) && D.density) + return 0 + return 1 + +/turf/simulated/wall/proc/checkForMultipleDoors() + if(!src.loc) + return 0 + for(var/obj/machinery/door/D in locate(src.x,src.y,src.z)) + if(!istype(D, /obj/machinery/door/window) && D.density) + return 0 + //There are no false wall checks because that would be fucking retarded + return 1 \ No newline at end of file diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm new file mode 100644 index 0000000000000..d92d7a7a2df70 --- /dev/null +++ b/code/game/machinery/doors/door.dm @@ -0,0 +1,257 @@ +/obj/machinery/door/Bumped(atom/AM) + if(p_open || operating) return + if(ismob(AM)) + var/mob/M = AM + if(world.timeofday - AM.last_bumped <= 60) return + if(M.client && !M:handcuffed) + bumpopen(M) + else if(istype(AM, /obj/machinery/bot)) + var/obj/machinery/bot/bot = AM + if(src.check_access(bot.botcard)) + if(density) + open() + else if(istype(AM, /obj/alien/facehugger)) + if(src.check_access(null)) + if(density) + open() + +/obj/machinery/door/proc/bumpopen(mob/user as mob) + if (src.operating) + return + //if(world.timeofday-last_used <= 10) + // return + src.add_fingerprint(user) + if (!src.requiresID()) + //don't care who they are or what they have, act as if they're NOTHING + user = null + + if (src.allowed(user)) + if (src.density) + //last_used = world.timeofday + open() + else if (src.density) + flick("door_deny", src) + return + + +/obj/machinery/door/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group) return 0 + if(istype(mover, /obj/beam)) + return !opacity + return !density + +/obj/machinery/door/proc/update_nearby_tiles(need_rebuild) + if(!air_master) return 0 + + var/turf/simulated/source = loc + var/turf/simulated/north = get_step(source,NORTH) + var/turf/simulated/south = get_step(source,SOUTH) + var/turf/simulated/east = get_step(source,EAST) + var/turf/simulated/west = get_step(source,WEST) + + if(need_rebuild) + if(istype(source)) //Rebuild/update nearby group geometry + if(source.parent) + air_master.groups_to_rebuild += source.parent + else + air_master.tiles_to_update += source + if(istype(north)) + if(north.parent) + air_master.groups_to_rebuild += north.parent + else + air_master.tiles_to_update += north + if(istype(south)) + if(south.parent) + air_master.groups_to_rebuild += south.parent + else + air_master.tiles_to_update += south + if(istype(east)) + if(east.parent) + air_master.groups_to_rebuild += east.parent + else + air_master.tiles_to_update += east + if(istype(west)) + if(west.parent) + air_master.groups_to_rebuild += west.parent + else + air_master.tiles_to_update += west + else + if(istype(source)) air_master.tiles_to_update += source + if(istype(north)) air_master.tiles_to_update += north + if(istype(south)) air_master.tiles_to_update += south + if(istype(east)) air_master.tiles_to_update += east + if(istype(west)) air_master.tiles_to_update += west + + return 1 + +/obj/machinery/door + New() + ..() + + update_nearby_tiles(need_rebuild=1) + + Del() + update_nearby_tiles() + + ..() + + +/obj/machinery/door/meteorhit(obj/M as obj) + src.open() + return + +/obj/machinery/door/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door/attack_hand(mob/user as mob) + return src.attackby(user, user) + +/obj/machinery/door/proc/requiresID() + return 1 + +/obj/machinery/door/attackby(obj/item/I as obj, mob/user as mob) + if (src.operating) + return + src.add_fingerprint(user) + if (!src.requiresID()) + //don't care who they are or what they have, act as if they're NOTHING + user = null + if (src.density && istype(I, /obj/item/weapon/card/emag)) + src.operating = -1 + flick("door_spark", src) + sleep(6) + open() + return 1 + if (src.allowed(user)) + if (src.density) + open() + else + close() + else if (src.density) + flick("door_deny", src) + return + +/obj/machinery/door/blob_act() + if(prob(20)) + del(src) + +/obj/machinery/door/ex_act(severity) + switch(severity) + if(1.0) + del(src) + if(2.0) + if(prob(25)) + del(src) + if(3.0) + if(prob(80)) + var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread + s.set_up(2, 1, src) + s.start() + +/obj/machinery/door/proc/update_icon() + if(density) + icon_state = "door1" + else + icon_state = "door0" + return + +/obj/machinery/door/proc/animate(animation) + switch(animation) + if("opening") + if(p_open) + flick("o_doorc0", src) + else + flick("doorc0", src) + if("closing") + if(p_open) + flick("o_doorc1", src) + else + flick("doorc1", src) + if("deny") + flick("door_deny", src) + return + +/obj/machinery/door/proc/open() + if(!density) + return 1 + if (src.operating == 1) //doors can still open when emag-disabled + return + if (!ticker) + return 0 + if(!src.operating) //in case of emag + src.operating = 1 + + animate("opening") + sleep(10) + src.density = 0 + update_icon() + + src.sd_SetOpacity(0) + update_nearby_tiles() + + if(operating == 1) //emag again + src.operating = 0 + + if(autoclose) + spawn(150) + autoclose() + return 1 + +/obj/machinery/door/proc/close() + if(density) + return 1 + if (src.operating) + return + src.operating = 1 + + animate("closing") + src.density = 1 + sleep(10) + update_icon() + + if (src.visible && (!istype(src, /obj/machinery/door/airlock/glass))) + src.sd_SetOpacity(1) + if(operating == 1) + operating = 0 + update_nearby_tiles() + +/obj/machinery/door/proc/autoclose() + var/obj/machinery/door/airlock/A = src + if ((!A.density) && !( A.operating ) && !(A.locked) && !( A.welded )) + close() + else return + +/////////////////////////////////////////////////// Unpowered doors + +/obj/machinery/door/unpowered + autoclose = 0 + +/obj/machinery/door/unpowered/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door/unpowered/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/door/unpowered/attack_hand(mob/user as mob) + return src.attackby(null, user) + +/obj/machinery/door/unpowered/attackby(obj/item/I as obj, mob/user as mob) + if (src.operating) + return + src.add_fingerprint(user) + if (src.allowed(user)) + if (src.density) + open() + else + close() + return + +/obj/machinery/door/unpowered/shuttle + icon = 'shuttle.dmi' + name = "door" + icon_state = "door1" + opacity = 1 + density = 1 \ No newline at end of file diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm new file mode 100644 index 0000000000000..6c4c72b257196 --- /dev/null +++ b/code/game/machinery/doors/firedoor.dm @@ -0,0 +1,111 @@ +/var/const/OPEN = 1 +/var/const/CLOSED = 2 + +/obj/machinery/door/firedoor/Bumped(atom/AM) + if(p_open || operating) + return + if(!density) + return ..() + else + return 0 + + +/obj/machinery/door/firedoor/power_change() + if( powered(ENVIRON) ) + stat &= ~NOPOWER + else + stat |= NOPOWER + +/obj/machinery/door/firedoor/attackby(obj/item/weapon/C as obj, mob/user as mob) + src.add_fingerprint(user) + if ((istype(C, /obj/item/weapon/weldingtool) && !( src.operating ) && src.density)) + var/obj/item/weapon/weldingtool/W = C + if(W.welding) + if (W.get_fuel() > 2) + W.use_fuel(2) + if (!( src.blocked )) + src.blocked = 1 + else + src.blocked = 0 + update_icon() + + return + if (!( istype(C, /obj/item/weapon/crowbar) )) + return + + if (!src.blocked && !src.operating) + if(src.density) + spawn( 0 ) + src.operating = 1 + + animate("opening") + sleep(15) + src.density = 0 + update_icon() + + src.sd_SetOpacity(0) + src.operating = 0 + return + else //close it up again + spawn( 0 ) + src.operating = 1 + + animate("closing") + src.density = 1 + sleep(15) + update_icon() + + src.sd_SetOpacity(1) + src.operating = 0 + return + return + +/obj/machinery/door/firedoor/process() + if(src.operating) + return + if(src.nextstate) + if(src.nextstate == OPEN && src.density) + spawn() + src.open() + else if(src.nextstate == CLOSED && !src.density) + spawn() + src.close() + src.nextstate = null + +/obj/machinery/door/firedoor/border_only + CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group) + var/direction = get_dir(src,target) + return (dir != direction) + else if(density) + if(!height) + var/direction = get_dir(src,target) + return (dir != direction) + else + return 0 + + return 1 + + update_nearby_tiles(need_rebuild) + if(!air_master) return 0 + + var/turf/simulated/source = loc + var/turf/simulated/destination = get_step(source,dir) + + if(need_rebuild) + if(istype(source)) //Rebuild/update nearby group geometry + if(source.parent) + air_master.groups_to_rebuild += source.parent + else + air_master.tiles_to_update += source + if(istype(destination)) + if(destination.parent) + air_master.groups_to_rebuild += destination.parent + else + air_master.tiles_to_update += destination + + else + if(istype(source)) air_master.tiles_to_update += source + if(istype(destination)) air_master.tiles_to_update += destination + + return 1 \ No newline at end of file diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm new file mode 100644 index 0000000000000..75f723b51aeac --- /dev/null +++ b/code/game/machinery/doors/poddoor.dm @@ -0,0 +1,57 @@ +/obj/machinery/door/poddoor/Bumped(atom/AM) + if(!density) + return ..() + else + return 0 + +/obj/machinery/door/poddoor/attackby(obj/item/weapon/C as obj, mob/user as mob) + src.add_fingerprint(user) + if (!( istype(C, /obj/item/weapon/crowbar) )) + return + if ((src.density && (stat & NOPOWER) && !( src.operating ))) + spawn( 0 ) + src.operating = 1 + flick("pdoorc0", src) + src.icon_state = "pdoor0" + sleep(15) + src.density = 0 + src.sd_SetOpacity(0) + src.operating = 0 + return + return + +/obj/machinery/door/poddoor/open() + if (src.operating == 1) //doors can still open when emag-disabled + return + if (!ticker) + return 0 + if(!src.operating) //in case of emag + src.operating = 1 + flick("pdoorc0", src) + src.icon_state = "pdoor0" + sleep(10) + src.density = 0 + src.sd_SetOpacity(0) + update_nearby_tiles() + + if(operating == 1) //emag again + src.operating = 0 + if(autoclose) + spawn(150) + autoclose() + return 1 + +/obj/machinery/door/poddoor/close() + if (src.operating) + return + src.operating = 1 + flick("pdoorc1", src) + src.icon_state = "pdoor1" + src.density = 1 + if (src.visible) + src.sd_SetOpacity(1) + update_nearby_tiles() + + sleep(10) + src.operating = 0 + return \ No newline at end of file diff --git a/code/game/machinery/doors/shuttledoor.dm b/code/game/machinery/doors/shuttledoor.dm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm new file mode 100644 index 0000000000000..7cbafa11302c4 --- /dev/null +++ b/code/game/machinery/doors/windowdoor.dm @@ -0,0 +1,129 @@ +/obj/machinery/door/window/update_nearby_tiles(need_rebuild) + if(!air_master) return 0 + + var/turf/simulated/source = loc + var/turf/simulated/target = get_step(source,dir) + + if(need_rebuild) + if(istype(source)) //Rebuild/update nearby group geometry + if(source.parent) + air_master.groups_to_rebuild += source.parent + else + air_master.tiles_to_update += source + if(istype(target)) + if(target.parent) + air_master.groups_to_rebuild += target.parent + else + air_master.tiles_to_update += target + else + if(istype(source)) air_master.tiles_to_update += source + if(istype(target)) air_master.tiles_to_update += target + + return 1 + +/obj/machinery/door/window/New() + ..() + + if (src.req_access && src.req_access.len) + src.icon_state = "[src.icon_state]" + src.base_state = src.icon_state + return + +/obj/machinery/door/window/Bumped(atom/movable/AM as mob|obj) + if (!( ismob(AM) )) + var/obj/machinery/bot/bot = AM + if(istype(bot)) + if(density && src.check_access(bot.botcard)) + open() + sleep(50) + close() + return + if (!( ticker )) + return + if (src.operating) + return + if (src.density && src.allowed(AM)) + open() + if(src.check_access(null)) + sleep(50) + else //secure doors close faster + sleep(20) + close() + return + +/obj/machinery/door/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover, /obj/beam)) + return 1 + if(get_dir(loc, target) == dir) //Make sure looking at appropriate border + if(air_group) return 0 + return !density + else + return 1 + +/obj/machinery/door/window/CheckExit(atom/movable/mover as mob|obj, turf/target as turf) + if(istype(mover, /obj/beam)) + return 1 + if(get_dir(loc, target) == dir) + return !density + else + return 1 + +/obj/machinery/door/window/open() + if (src.operating == 1) //doors can still open when emag-disabled + return 0 + if (!ticker) + return 0 + if(!src.operating) //in case of emag + src.operating = 1 + flick(text("[]opening", src.base_state), src) + playsound(src.loc, 'windowdoor.ogg', 100, 1) + src.icon_state = text("[]open", src.base_state) + sleep(10) + + src.density = 0 + src.sd_SetOpacity(0) + update_nearby_tiles() + + if(operating == 1) //emag again + src.operating = 0 + return 1 + +/obj/machinery/door/window/close() + if (src.operating) + return 0 + src.operating = 1 + flick(text("[]closing", src.base_state), src) + playsound(src.loc, 'windowdoor.ogg', 100, 1) + src.icon_state = text("[]", src.base_state) + + src.density = 1 + if (src.visible) + src.sd_SetOpacity(1) + update_nearby_tiles() + + sleep(10) + + src.operating = 0 + return 1 + +/obj/machinery/door/window/attackby(obj/item/I as obj, mob/user as mob) + if (src.operating) + return + src.add_fingerprint(user) + if (!src.requiresID()) + //don't care who they are or what they have, act as if they're NOTHING + user = null + if (src.density && istype(I, /obj/item/weapon/card/emag)) + src.operating = -1 + flick(text("[]spark", src.base_state), src) + sleep(6) + open() + return 1 + if (src.allowed(user)) + if (src.density) + open() + else + close() + else if (src.density) + flick(text("[]deny", src.base_state), src) + return \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm new file mode 100644 index 0000000000000..f86992cac606a --- /dev/null +++ b/code/game/machinery/embedded_controller/access_controller.dm @@ -0,0 +1,205 @@ +//States for airlock_control +#define ACCESS_STATE_INTERNAL -1 +#define ACCESS_STATE_LOCKED 0 +#define ACCESS_STATE_EXTERNAL 1 + +datum/computer/file/embedded_program/access_controller + var/id_tag + var/exterior_door_tag + var/interior_door_tag + + state = ACCESS_STATE_LOCKED + var/target_state = ACCESS_STATE_LOCKED + + receive_signal(datum/signal/signal, receive_method, receive_param) + var/receive_tag = signal.data["tag"] + if(!receive_tag) return + + if(receive_tag==exterior_door_tag) + if(signal.data["door_status"] == "closed") + if(signal.data["lock_status"] == "locked") + memory["exterior_status"] = "locked" + else + memory["exterior_status"] = "closed" + else + memory["exterior_status"] = "open" + + else if(receive_tag==interior_door_tag) + if(signal.data["door_status"] == "closed") + if(signal.data["lock_status"] == "locked") + memory["interior_status"] = "locked" + else + memory["interior_status"] = "closed" + else + memory["interior_status"] = "open" + + else if(receive_tag==id_tag) + switch(signal.data["command"]) + if("cycle_interior") + target_state = ACCESS_STATE_INTERNAL + if("cycle_exterior") + target_state = ACCESS_STATE_EXTERNAL + if("cycle") + if(state < ACCESS_STATE_LOCKED) + target_state = ACCESS_STATE_EXTERNAL + else + target_state = ACCESS_STATE_INTERNAL + + receive_user_command(command) + switch(command) + if("cycle_closed") + target_state = ACCESS_STATE_LOCKED + if("cycle_exterior") + target_state = ACCESS_STATE_EXTERNAL + if("cycle_interior") + target_state = ACCESS_STATE_INTERNAL + + process() + switch(state) + if(ACCESS_STATE_INTERNAL) // state -1 + if(target_state > state) + if(memory["interior_status"] == "locked") + state = ACCESS_STATE_LOCKED + else + var/datum/signal/signal = new + signal.data["tag"] = interior_door_tag + if(memory["interior_status"] == "closed") + signal.data["command"] = "lock" + else + signal.data["command"] = "secure_close" + post_signal(signal) + + if(ACCESS_STATE_LOCKED) + if(target_state < state) + if(memory["exterior_status"] != "locked") + var/datum/signal/signal = new + signal.data["tag"] = exterior_door_tag + if(memory["exterior_status"] == "closed") + signal.data["command"] = "lock" + else + signal.data["command"] = "secure_close" + post_signal(signal) + else + if(memory["interior_status"] == "closed" || memory["interior_status"] == "open") + state = ACCESS_STATE_INTERNAL + else + var/datum/signal/signal = new + signal.data["tag"] = interior_door_tag + signal.data["command"] = "unlock" + post_signal(signal) + else if(target_state > state) + if(memory["interior_status"] != "locked") + var/datum/signal/signal = new + signal.data["tag"] = interior_door_tag + if(memory["interior_status"] == "closed") + signal.data["command"] = "lock" + else + signal.data["command"] = "secure_close" + post_signal(signal) + else + if(memory["exterior_status"] == "closed" || memory["exterior_status"] == "open") + state = ACCESS_STATE_EXTERNAL + else + var/datum/signal/signal = new + signal.data["tag"] = exterior_door_tag + signal.data["command"] = "unlock" + post_signal(signal) + else + if(memory["interior_status"] != "locked") + var/datum/signal/signal = new + signal.data["tag"] = interior_door_tag + if(memory["interior_status"] == "closed") + signal.data["command"] = "lock" + else + signal.data["command"] = "secure_close" + post_signal(signal) + else if(memory["exterior_status"] != "locked") + var/datum/signal/signal = new + signal.data["tag"] = exterior_door_tag + if(memory["exterior_status"] == "closed") + signal.data["command"] = "lock" + else + signal.data["command"] = "secure_close" + post_signal(signal) + + if(ACCESS_STATE_EXTERNAL) //state 1 + if(target_state < state) + if(memory["exterior_status"] == "locked") + state = ACCESS_STATE_LOCKED + else + var/datum/signal/signal = new + signal.data["tag"] = exterior_door_tag + if(memory["exterior_status"] == "closed") + signal.data["command"] = "lock" + else + signal.data["command"] = "secure_close" + post_signal(signal) + + + return 1 + + +obj/machinery/embedded_controller/radio/access_controller + icon = 'airlock_machines.dmi' + icon_state = "access_control_standby" + + name = "Access Console" + density = 0 + + frequency = 1449 + + // Setup parameters only + var/id_tag + var/exterior_door_tag + var/interior_door_tag + + initialize() + ..() + + var/datum/computer/file/embedded_program/access_controller/new_prog = new + + new_prog.id_tag = id_tag + new_prog.exterior_door_tag = exterior_door_tag + new_prog.interior_door_tag = interior_door_tag + + new_prog.master = src + program = new_prog + + update_icon() + if(on && program) + if(program.memory["processing"]) + icon_state = "access_control_process" + else + icon_state = "access_control_standby" + else + icon_state = "access_control_off" + + + return_text() + var/state_options = null + + var/state = 0 + var/exterior_status = "----" + var/interior_status = "----" + if(program) + state = program.state + exterior_status = program.memory["exterior_status"] + interior_status = program.memory["interior_status"] + + switch(state) + if(ACCESS_STATE_INTERNAL) + state_options = {"Lock Interior Airlock
      +Cycle to Exterior Airlock
      "} + if(ACCESS_STATE_LOCKED) + state_options = {"Unlock Interior Airlock
      +Unlock Exterior Airlock
      "} + if(ACCESS_STATE_EXTERNAL) + state_options = {"Cycle to Interior Airlock
      +Lock Exterior Airlock
      "} + + var/output = {"Access Control Console
      +[state_options]
      +Exterior Door: [exterior_status]
      +Interior Door: [interior_status]
      "} + + return output \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/airlock_controller.dm b/code/game/machinery/embedded_controller/airlock_controller.dm new file mode 100644 index 0000000000000..4a1025b2c494c --- /dev/null +++ b/code/game/machinery/embedded_controller/airlock_controller.dm @@ -0,0 +1,256 @@ +//States for airlock_control +#define AIRLOCK_STATE_INOPEN -2 +#define AIRLOCK_STATE_PRESSURIZE -1 +#define AIRLOCK_STATE_CLOSED 0 +#define AIRLOCK_STATE_DEPRESSURIZE 1 +#define AIRLOCK_STATE_OUTOPEN 2 + +datum/computer/file/embedded_program/airlock_controller + var/id_tag + var/exterior_door_tag + var/interior_door_tag + var/airpump_tag + var/sensor_tag + var/sanitize_external + + state = AIRLOCK_STATE_CLOSED + var/target_state = AIRLOCK_STATE_CLOSED + var/sensor_pressure = null + + receive_signal(datum/signal/signal, receive_method, receive_param) + var/receive_tag = signal.data["tag"] + if(!receive_tag) return + + if(receive_tag==sensor_tag) + if(signal.data["pressure"]) + sensor_pressure = text2num(signal.data["pressure"]) + + else if(receive_tag==exterior_door_tag) + memory["exterior_status"] = signal.data["door_status"] + + else if(receive_tag==interior_door_tag) + memory["interior_status"] = signal.data["door_status"] + + else if(receive_tag==airpump_tag) + if(signal.data["power"]=="on") + memory["pump_status"] = signal.data["direction"] + else + memory["pump_status"] = "off" + + else if(receive_tag==id_tag) + switch(signal.data["command"]) + if("cycle") + if(state < AIRLOCK_STATE_CLOSED) + target_state = AIRLOCK_STATE_OUTOPEN + else + target_state = AIRLOCK_STATE_INOPEN + + receive_user_command(command) + switch(command) + if("cycle_closed") + target_state = AIRLOCK_STATE_CLOSED + if("cycle_exterior") + target_state = AIRLOCK_STATE_OUTOPEN + if("cycle_interior") + target_state = AIRLOCK_STATE_INOPEN + if("abort") + target_state = AIRLOCK_STATE_CLOSED + + process() + switch(state) + if(AIRLOCK_STATE_INOPEN) // state -2 + if(target_state > state) + if(memory["interior_status"] == "closed") + state = AIRLOCK_STATE_CLOSED + else + var/datum/signal/signal = new + signal.data["tag"] = interior_door_tag + signal.data["command"] = "secure_close" + post_signal(signal) + else + if(memory["pump_status"] != "off") + var/datum/signal/signal = new + signal.data["tag"] = airpump_tag + signal.data["command"] = "power_off" + post_signal(signal) + + if(AIRLOCK_STATE_PRESSURIZE) + if(target_state < state) + if(sensor_pressure >= ONE_ATMOSPHERE*0.95) + if(memory["interior_status"] == "open") + state = AIRLOCK_STATE_INOPEN + else + var/datum/signal/signal = new + signal.data["tag"] = interior_door_tag + signal.data["command"] = "secure_open" + post_signal(signal) + else + var/datum/signal/signal = new + signal.data["tag"] = airpump_tag + if(memory["pump_status"] == "siphon") + signal.data["command"] = "stabalize" + else if(memory["pump_status"] != "release") + signal.data["command"] = "power_on" + post_signal(signal) + else if(target_state > state) + state = AIRLOCK_STATE_CLOSED + + if(AIRLOCK_STATE_CLOSED) + if(target_state > state) + if(memory["interior_status"] == "closed") + state = AIRLOCK_STATE_DEPRESSURIZE + else + var/datum/signal/signal = new + signal.data["tag"] = interior_door_tag + signal.data["command"] = "secure_close" + post_signal(signal) + else if(target_state < state) + if(memory["exterior_status"] == "closed") + state = AIRLOCK_STATE_PRESSURIZE + else + var/datum/signal/signal = new + signal.data["tag"] = exterior_door_tag + signal.data["command"] = "secure_close" + post_signal(signal) + + else + if(memory["pump_status"] != "off") + var/datum/signal/signal = new + signal.data["tag"] = airpump_tag + signal.data["command"] = "power_off" + post_signal(signal) + + if(AIRLOCK_STATE_DEPRESSURIZE) + var/target_pressure = ONE_ATMOSPHERE*0.05 + if(sanitize_external) + target_pressure = ONE_ATMOSPHERE*0.01 + + if(sensor_pressure <= target_pressure) + if(target_state > state) + if(memory["exterior_status"] == "open") + state = AIRLOCK_STATE_OUTOPEN + else + var/datum/signal/signal = new + signal.data["tag"] = exterior_door_tag + signal.data["command"] = "secure_open" + post_signal(signal) + else if(target_state < state) + state = AIRLOCK_STATE_CLOSED + else if((target_state < state) && !sanitize_external) + state = AIRLOCK_STATE_CLOSED + else + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = airpump_tag + if(memory["pump_status"] == "release") + signal.data["command"] = "purge" + else if(memory["pump_status"] != "siphon") + signal.data["command"] = "power_on" + post_signal(signal) + + if(AIRLOCK_STATE_OUTOPEN) //state 2 + if(target_state < state) + if(memory["exterior_status"] == "closed") + if(sanitize_external) + state = AIRLOCK_STATE_DEPRESSURIZE + else + state = AIRLOCK_STATE_CLOSED + else + var/datum/signal/signal = new + signal.data["tag"] = exterior_door_tag + signal.data["command"] = "secure_close" + post_signal(signal) + else + if(memory["pump_status"] != "off") + var/datum/signal/signal = new + signal.data["tag"] = airpump_tag + signal.data["command"] = "power_off" + post_signal(signal) + + memory["sensor_pressure"] = sensor_pressure + memory["processing"] = state != target_state + sensor_pressure = null + + return 1 + + +obj/machinery/embedded_controller/radio/airlock_controller + icon = 'airlock_machines.dmi' + icon_state = "airlock_control_standby" + + name = "Airlock Console" + density = 0 + + frequency = 1449 + + // Setup parameters only + var/id_tag + var/exterior_door_tag + var/interior_door_tag + var/airpump_tag + var/sensor_tag + var/sanitize_external + + initialize() + ..() + + var/datum/computer/file/embedded_program/airlock_controller/new_prog = new + + new_prog.id_tag = id_tag + new_prog.exterior_door_tag = exterior_door_tag + new_prog.interior_door_tag = interior_door_tag + new_prog.airpump_tag = airpump_tag + new_prog.sensor_tag = sensor_tag + new_prog.sanitize_external = sanitize_external + + new_prog.master = src + program = new_prog + + update_icon() + if(on && program) + if(program.memory["processing"]) + icon_state = "airlock_control_process" + else + icon_state = "airlock_control_standby" + else + icon_state = "airlock_control_off" + + + return_text() + var/state_options = null + + var/state = 0 + var/sensor_pressure = "----" + var/exterior_status = "----" + var/interior_status = "----" + var/pump_status = "----" + if(program) + state = program.state + sensor_pressure = program.memory["sensor_pressure"] + exterior_status = program.memory["exterior_status"] + interior_status = program.memory["interior_status"] + pump_status = program.memory["pump_status"] + + switch(state) + if(AIRLOCK_STATE_INOPEN) + state_options = {"Close Interior Airlock
      +Cycle to Exterior Airlock
      "} + if(AIRLOCK_STATE_PRESSURIZE) + state_options = "Abort Cycling
      " + if(AIRLOCK_STATE_CLOSED) + state_options = {"Open Interior Airlock
      +Open Exterior Airlock
      "} + if(AIRLOCK_STATE_DEPRESSURIZE) + state_options = "Abort Cycling
      " + if(AIRLOCK_STATE_OUTOPEN) + state_options = {"Cycle to Interior Airlock
      +Close Exterior Airlock
      "} + + var/output = {"Airlock Control Console
      +[state_options]
      +Chamber Pressure: [sensor_pressure] kPa
      +Exterior Door: [exterior_status]
      +Interior Door: [interior_status]
      +Control Pump: [pump_status]
      "} + + return output \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm new file mode 100644 index 0000000000000..6542f39a725a7 --- /dev/null +++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm @@ -0,0 +1,82 @@ +datum/computer/file/embedded_program + var/list/memory = list() + var/state + var/obj/machinery/embedded_controller/master + + proc + post_signal(datum/signal/signal, comm_line) + if(master) + master.post_signal(signal, comm_line) + else + del(signal) + + receive_user_command(command) + + receive_signal(datum/signal/signal, receive_method, receive_param) + return null + + process() + return 0 + +obj/machinery/embedded_controller + var/datum/computer/file/embedded_program/program + + name = "Embedded Controller" + density = 0 + anchored = 1 + + var/on = 1 + + attack_hand(mob/user) + user << browse(return_text(), "window=computer") + user.machine = src + onclose(user, "computer") + + proc/update_icon() + proc/return_text() + + proc/post_signal(datum/signal/signal, comm_line) + return 0 + + receive_signal(datum/signal/signal, receive_method, receive_param) + if(!signal || signal.encryption) return + + if(program) + return program.receive_signal(signal, receive_method, receive_param) + + Topic(href, href_list) + if(..()) + return 0 + + if(program) + program.receive_user_command(href_list["command"]) + + usr.machine = src + + process() + if(program) + program.process() + + update_icon() + src.updateDialog() + ..() + + radio + var/frequency + var/datum/radio_frequency/radio_connection + + initialize() + set_frequency(frequency) + + post_signal(datum/signal/signal) + signal.transmission_method = TRANSMISSION_RADIO + if(radio_connection) + return radio_connection.post_signal(src, signal) + else + del(signal) + + proc + set_frequency(new_frequency) + radio_controller.remove_object(src, "[frequency]") + frequency = new_frequency + radio_connection = radio_controller.add_object(src, "[frequency]") \ No newline at end of file diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm new file mode 100644 index 0000000000000..47f6936754e6c --- /dev/null +++ b/code/game/machinery/flasher.dm @@ -0,0 +1,103 @@ +// It is a gizmo that flashes a small area + +/obj/machinery/flasher + name = "Mounted flash" + desc = "A wall-mounted flashbulb device." + icon = 'stationobjs.dmi' + icon_state = "mflash1" + var/id = null + var/range = 2 //this is roughly the size of brig cell + var/disable = 0 + var/last_flash = 0 //Don't want it getting spammed like regular flashes + var/strength = 10 //How weakened targets are when flashed. + var/base_state = "mflash" + anchored = 1 + +/obj/machinery/flasher/portable //Portable version of the flasher. Only flashes when anchored + name = "portable flasher" + desc = "A portable flashing device. Wrench to activate and deactivate. Cannot detect slow movements." + icon_state = "pflash1" + strength = 8 + anchored = 0 + base_state = "pflash" + density = 1 + +/obj/machinery/flasher/New() + sleep(4) + src.sd_SetLuminosity(2) + +/obj/machinery/flasher/power_change() + if ( powered() ) + stat &= ~NOPOWER + icon_state = "[base_state]1" + src.sd_SetLuminosity(2) + else + stat |= ~NOPOWER + icon_state = "[base_state]1-p" + src.sd_SetLuminosity(0) + +//Don't want to render prison breaks impossible +/obj/machinery/flasher/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/wirecutters)) + add_fingerprint(user) + src.disable = !src.disable + if (src.disable) + user.visible_message("\red [user] has disconnected the [src]'s flashbulb!", "\red You disconnect the [src]'s flashbulb!") + if (!src.disable) + user.visible_message("\red [user] has connected the [src]'s flashbulb!", "\red You connect the [src]'s flashbulb!") + +//Let the AI trigger them directly. +/obj/machinery/flasher/attack_ai() + if (src.anchored) + return src.flash() + else + return + +/obj/machinery/flasher/proc/flash() + if (!(powered())) + return + + if ((src.disable) || (src.last_flash && world.time < src.last_flash + 150)) + return + + playsound(src.loc, 'flash.ogg', 100, 1) + flick("[base_state]_flash", src) + src.last_flash = world.time + use_power(1000) + + for (var/mob/O in viewers(src, null)) + if (get_dist(src, O) > src.range) + continue + if ((istype(O, /mob/living/carbon/human) && (istype(O:glasses, /obj/item/clothing/glasses/sunglasses)))) + continue + + O.weakened = src.strength + if ((O.eye_stat > 15 && prob(O.eye_stat + 50))) + flick("e_flash", O:flash) + O.eye_stat += rand(1, 2) + else + flick("flash", O:flash) + O.eye_stat += rand(0, 2) + + +/obj/machinery/flasher/portable/HasProximity(atom/movable/AM as mob|obj) + if ((src.disable) || (src.last_flash && world.time < src.last_flash + 150)) + return + + if(istype(AM, /mob/living/carbon)) + var/mob/living/carbon/M = AM + if ((M.m_intent != "walk") && (src.anchored)) + src.flash() + +/obj/machinery/flasher/portable/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/wrench)) + add_fingerprint(user) + src.anchored = !src.anchored + + if (!src.anchored) + user.show_message(text("\red [src] can now be moved.")) + src.overlays = null + + else if (src.anchored) + user.show_message(text("\red [src] is now secured.")) + src.overlays += "[base_state]-s" \ No newline at end of file diff --git a/code/game/machinery/gibber.dm b/code/game/machinery/gibber.dm new file mode 100644 index 0000000000000..571238bbbc531 --- /dev/null +++ b/code/game/machinery/gibber.dm @@ -0,0 +1,120 @@ + + +/obj/machinery/gibber/New() + ..() + src.overlays += image('kitchen.dmi', "grindnotinuse") + +/obj/machinery/gibber/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/gibber/relaymove(mob/user as mob) + src.go_out() + return + +/obj/machinery/gibber/attack_hand(mob/user as mob) + if(operating) + user << "\red It's locked and running" + return + else + src.startgibbing(user) + +/obj/machinery/gibber/attackby(obj/item/weapon/grab/G as obj, mob/user as mob) + if(src.occupant) + user << "\red The gibber is full, empty it first!" + return + if(G.affecting.abiotic()) + user << "\red Subject may not have abiotic items on." + return + if (!( istype(G, /obj/item/weapon/grab)) || !(istype(G.affecting, /mob/living/carbon/human))) + user << "\red This item is not suitable for the gibber!" + return + + user.visible_message("\red [user] starts to put [G.affecting] into the gibber!") + src.add_fingerprint(user) + sleep(30) + if(G.affecting) + user.visible_message("\red [user] stuffs [G.affecting] into the gibber!") + var/mob/M = G.affecting + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + src.occupant = M + del(G) + +/obj/machinery/gibber/verb/eject() + set src in oview(1) + + if (usr.stat != 0) + return + src.go_out() + add_fingerprint(usr) + return + +/obj/machinery/gibber/proc/go_out() + if (!src.occupant) + return + for(var/obj/O in src) + O.loc = src.loc + if (src.occupant.client) + src.occupant.client.eye = src.occupant.client.mob + src.occupant.client.perspective = MOB_PERSPECTIVE + src.occupant.loc = src.loc + src.occupant = null + return + + +/obj/machinery/gibber/proc/startgibbing(mob/user as mob) + if(src.operating) + return + if(!src.occupant) + for(var/mob/M in viewers(src, null)) + M.show_message("\red You hear a loud metallic grinding sound.", 1) + return + else + for(var/mob/M in viewers(src, null)) + M.show_message("\red You hear a loud squelchy grinding sound.", 1) + src.operating = 1 + src.dirty += 1 + var/sourcename = src.occupant.real_name + var/sourcejob = src.occupant.job + var/obj/item/weapon/reagent_containers/food/snacks/humanmeat/newmeat1 = new /obj/item/weapon/reagent_containers/food/snacks/humanmeat + var/obj/item/weapon/reagent_containers/food/snacks/humanmeat/newmeat2 = new /obj/item/weapon/reagent_containers/food/snacks/humanmeat + var/obj/item/weapon/reagent_containers/food/snacks/humanmeat/newmeat3 = new /obj/item/weapon/reagent_containers/food/snacks/humanmeat + newmeat1.name = sourcename + newmeat1.name + newmeat1.subjectname = sourcename + newmeat1.subjectjob = sourcejob + newmeat2.name = sourcename + newmeat2.name + newmeat2.subjectname = sourcename + newmeat2.subjectjob = sourcejob + newmeat3.name = sourcename + newmeat3.name + newmeat3.subjectname = sourcename + newmeat3.subjectjob = sourcejob + if(src.occupant.client) + var/mob/dead/observer/newmob + newmob = new/mob/dead/observer(src.occupant) + src.occupant:client:mob = newmob + newmob:client:eye = newmob + del(src.occupant) + else + del(src.occupant) + spawn(src.gibtime) + playsound(src.loc, 'splat.ogg', 50, 1) + operating = 0 + var/turf/Tx1 = locate(src.x - 1, src.y, src.z) + var/turf/Tx2 = locate(src.x - 2, src.y, src.z) + var/turf/Tx3 = locate(src.x - 3, src.y, src.z) + if(istype(Tx1, /turf/simulated/floor/)) // Make it so the blood that flies out only appears on the freezer floor + new /obj/decal/cleanable/blood/gibs(Tx1) + newmeat1.loc = get_turf(Tx1) + if(istype(Tx2, /turf/simulated/floor/)) + new /obj/decal/cleanable/blood/gibs(Tx2) + newmeat2.loc = get_turf(Tx2) + if(istype(Tx3, /turf/simulated/floor/)) + new /obj/decal/cleanable/blood/gibs(Tx3) + newmeat3.loc = get_turf(Tx3) + if(src.dirty == 1) + src.overlays += image('kitchen.dmi', "grindbloody") + src.operating = 0 + + diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm new file mode 100644 index 0000000000000..534abd77eb7f7 --- /dev/null +++ b/code/game/machinery/hologram.dm @@ -0,0 +1,79 @@ +/obj/machinery/hologram_ai/New() + ..() + +/obj/machinery/hologram_ai/attack_ai(user as mob) + src.show_console(user) + return + +/obj/machinery/hologram_ai/proc/render() + var/icon/I = new /icon('human.dmi', "body_m_s") + + if (src.lumens >= 0) + I.Blend(rgb(src.lumens, src.lumens, src.lumens), ICON_ADD) + else + I.Blend(rgb(- src.lumens, -src.lumens, -src.lumens), ICON_SUBTRACT) + + I.Blend(new /icon('human.dmi', "mouth_m_s"), ICON_OVERLAY) + I.Blend(new /icon('human.dmi', "underwear1_m_s"), ICON_OVERLAY) + + var/icon/U = new /icon('human_face.dmi', "hair_a_s") + U.Blend(rgb(src.h_r, src.h_g, src.h_b), ICON_ADD) + + I.Blend(U, ICON_OVERLAY) + + src.projection.icon = I + +/obj/machinery/hologram_ai/proc/show_console(var/mob/user as mob) + var/dat + user.machine = src + if (src.temp) + dat = text("[]

      Clear", src.temp, src) + else + dat = text("Hologram Status:
      \nPower: []
      \nHologram Control:
      \nColor Luminosity: []/220 \[Reset\]
      \nLighten: 1 10
      \nDarken: 1 10
      \n
      \nHair Color: ([],[],[]) \[Reset\]
      \nRed (0-255): \[0\] -10 -1 [] 1 10 \[255\]
      \nGreen (0-255): \[0\] -10 -1 [] 1 10 \[255\]
      \nBlue (0-255): \[0\] -10 -1 [] 1 10 \[255\]
      ", src, (src.projection ? "On" : "Off"), -src.lumens + 35, src, src, src, src, src, src.h_r, src.h_g, src.h_b, src, src, src, src, src.h_r, src, src, src, src, src, src, src.h_g, src, src, src, src, src, src, src.h_b, src, src, src) + user << browse(dat, "window=hologram_console") + onclose(user, "hologram_console") + return + +/obj/machinery/hologram_ai/Topic(href, href_list) + ..() + if (!istype(usr, /mob/living/silicon/ai)) + return + + if (href_list["power"]) + if (src.projection) + src.icon_state = "hologram0" + //src.projector.projection = null + del(src.projection) + else + src.projection = new /obj/projection( src.loc ) + src.projection.icon = 'human.dmi' + src.projection.icon_state = "male" + src.icon_state = "hologram1" + src.render() + else if (href_list["h_r"]) + if (src.projection) + src.h_r += text2num(href_list["h_r"]) + src.h_r = min(max(src.h_r, 0), 255) + render() + else if (href_list["h_g"]) + if (src.projection) + src.h_g += text2num(href_list["h_g"]) + src.h_g = min(max(src.h_g, 0), 255) + render() + else if (href_list["h_b"]) + if (src.projection) + src.h_b += text2num(href_list["h_b"]) + src.h_b = min(max(src.h_b, 0), 255) + render() + else if (href_list["light"]) + if (src.projection) + src.lumens += text2num(href_list["light"]) + src.lumens = min(max(src.lumens, -185.0), 35) + render() + else if (href_list["reset"]) + if (src.projection) + src.lumens = 0 + render() + else if (href_list["temp"]) + src.temp = null + src.show_console(usr) \ No newline at end of file diff --git a/code/game/machinery/hydroponics.dm b/code/game/machinery/hydroponics.dm new file mode 100644 index 0000000000000..e61c4bb47ad2c --- /dev/null +++ b/code/game/machinery/hydroponics.dm @@ -0,0 +1,331 @@ +/obj/machinery/hydroponics + name = "Hydroponics Tray" + icon = 'hydroponics.dmi' + icon_state = "hydrotray" + density = 1 + anchored = 1 + var/waterlevel = 100 // The amount of water in the tray (max 100) + var/nutrilevel = 10 // The amount of nutrient in the tray (max 10) + var/yieldmod = 1 //Modifier to yield + var/mutmod = 1 //Modifier to mutation chance + var/age = 0 // Current age + var/dead = 0 // Is it dead? + var/health = 0 // It's health. + var/lastproduce = 0 // Last time it was harvested + var/lastcycle = 0 //Used for timing of cycles. + var/cycledelay = 200 // About 10 seconds / cycle + var/planted = 0 // Is it occupied? + var/harvest = 0; //Ready to harvest? + var/obj/item/seeds/myseed = null // The currently planted seed + +obj/machinery/hydroponics/process() + + if(world.time > (src.lastcycle + src.cycledelay)) + src.lastcycle = world.time + if(src.planted & !src.dead) + src.age++ + src.waterlevel -= rand(1,6) + if(src.nutrilevel > 0) + src.nutrilevel -= 1 + if(src.waterlevel < 0) + src.waterlevel = 0 + if(src.waterlevel <= 0) + src.health -= 3 + else if(src.waterlevel <= 5) + src.health -= 1 + if(src.waterlevel > 10 & src.nutrilevel > 0) + src.health += 1 + if(src.health > src.myseed.endurance) + src.health = src.myseed.endurance + if(src.age > src.myseed.lifespan) + src.health -= 5 + if(src.health <= 0) + src.dead = 1 + src.harvest = 0 + if(src.age > src.myseed.production && (src.age - src.lastproduce) > src.myseed.production && (!src.harvest && !src.dead)) + var/m_count = 0 + while(m_count < src.mutmod) + src.mutate() + m_count++; + if(src.yieldmod > 0) + src.harvest = 1 + else + src.lastproduce = src.age + src.updateicon() + return + +obj/machinery/hydroponics/proc/updateicon() + //Refreshes the icon + overlays = null + if(src.planted) + if(dead) + overlays += image('hydroponics.dmi', icon_state="[src.myseed.species]-dead") + else if(src.harvest) + overlays += image('hydroponics.dmi', icon_state="[src.myseed.species]-harvest") + else if(src.age < src.myseed.maturation) + var/t_growthstate = ((src.age / src.myseed.maturation) * 6) + overlays += image('hydroponics.dmi', icon_state="[src.myseed.species]-grow[round(t_growthstate)]") + src.lastproduce = src.age //Cheating by putting this here, it means that it isn't instantly ready to harvest + else + overlays += image('hydroponics.dmi', icon_state="[src.myseed.species]-grow6") + + if(src.waterlevel <= 10) + overlays += image('hydroponics.dmi', icon_state="over_lowwater") + if(src.nutrilevel <= 2) + overlays += image('hydroponics.dmi', icon_state="over_lownutri") + if(src.health <= (src.myseed.endurance / 2)) + overlays += image('hydroponics.dmi', icon_state="over_lowhealth") + if(src.harvest) + overlays += image('hydroponics.dmi', icon_state="over_harvest") + return + +obj/machinery/hydroponics/proc/mutate() // Mutates the current seed + + src.myseed.lifespan += rand(-2,2) + if(src.myseed.lifespan < 10) + src.myseed.lifespan = 10 + if(src.myseed.lifespan > 30) + src.myseed.lifespan = 30 + + src.myseed.endurance += rand(-5,5) + if(src.myseed.endurance < 10) + src.myseed.endurance = 10 + if(src.myseed.endurance > 100) + src.myseed.endurance = 100 + + src.myseed.production += rand(-1,1) + if(src.myseed.production < 2) + src.myseed.production = 2 + if(src.myseed.production > 10) + src.myseed.production = 10 + + src.myseed.yield += rand(-2,2) + if(src.myseed.yield < 0) + src.myseed.yield = 0 + if(src.myseed.yield > 10) + src.myseed.yield = 10 + + if(src.myseed.potency != -1) //Not all plants have a potency + src.myseed.potency += rand(-10,10) + if(src.myseed.potency < 0) + src.myseed.potency = 0 + if(src.myseed.potency > 100) + src.myseed.potency = 100 + +obj/machinery/hydroponics/attackby(var/obj/item/O as obj, var/mob/user as mob) + + //Called when mob user "attacks" it with object O + if (istype(O, /obj/item/weapon/reagent_containers/glass/bucket)) + var/b_amount = O.reagents.get_reagent_amount("water") + if(b_amount > 0 && src.waterlevel < 100) + if(b_amount + src.waterlevel > 100) + b_amount = 100 - src.waterlevel + O.reagents.remove_reagent("water", b_amount) + src.waterlevel += b_amount + playsound(src.loc, 'slosh.ogg', 25, 1) + user << "You fill the tray with [b_amount] units of water." + else if(src.waterlevel >= 100) + user << "\red The hydroponics tray is already full." + else + user << "\red The bucket is not filled with water." + src.updateicon() + else if ( istype(O, /obj/item/nutrient/) ) + var/obj/item/nutrient/myNut = O + user.u_equip(O) + src.nutrilevel = 10 + src.yieldmod = myNut.yieldmod + src.mutmod = myNut.mutmod + user << "You replace the nutrient solution in the tray" + del(O) + src.updateicon() + else if (istype(O, /obj/item/seeds/)) + if(!src.planted) + user.u_equip(O) + user << "You plant the [O.name]" + src.dead = 0 + src.myseed = O + src.planted = 1 + src.age = 1 + src.health = src.myseed.endurance + src.lastcycle = world.time + O.loc = src + if((user.client && user.s_active != src)) + user.client.screen -= O + O.dropped(user) + src.updateicon() + else + user << "\red The tray already has a seed in it!" + else if (istype(O, /obj/item/device/analyzer/plant_analyzer)) + if(src.planted && src.myseed) + user << "[src.myseed.name]" + user << "-Plant Age: [src.age]" + user << "--Plant Endurance: [src.myseed.endurance]" + user << "--Plant Lifespan: [src.myseed.lifespan]" + user << "--Plant Yield: [src.myseed.yield]" + user << "--Plant Production: [src.myseed.production]" + if(src.myseed.potency != -1) + user << "--Plant Potency: [src.myseed.potency]" + else + user << "No plant found." + + return + +/obj/machinery/hydroponics/attack_hand(mob/user as mob) + if(src.harvest) + if(!user in range(1,src)) + return + var/item = text2path(src.myseed.productname) + var/t_amount = 0 + + while ( t_amount < (src.myseed.yield * src.yieldmod )) + var/obj/item/weapon/reagent_containers/food/snacks/grown/t_prod = new item(user.loc) + t_prod.seed = src.myseed.mypath + t_prod.species = src.myseed.species + t_prod.lifespan = src.myseed.lifespan + t_prod.endurance = src.myseed.endurance + t_prod.maturation = src.myseed.maturation + t_prod.production = src.myseed.production + t_prod.yield = src.myseed.yield + t_prod.potency = src.myseed.potency + t_amount++ + src.harvest = 0 + src.lastproduce = src.age + if((src.yieldmod * src.myseed.yield) <= 0) + usr << text("\red You fail to harvest anything useful") + else + usr << text("You harvest from the [src.myseed.plantname]") + if(src.myseed.oneharvest) + src.planted = 0 + src.dead = 0 + src.updateicon() + else if(src.dead) + src.planted = 0 + src.dead = 0 + usr << text("You remove the dead plant from the tray") + del(src.myseed) + src.updateicon() + else + if(src.planted && !src.dead) + usr << text("The hydroponics tray has a [src.myseed.plantname] planted") + if(src.health <= (src.myseed.endurance / 2)) + usr << text("The plant looks unhealthy") + else + usr << text("The hydroponics tray is empty") + usr << text("Water: [src.waterlevel]/100") + usr << text("Nutrient: [src.nutrilevel]/10") + +/obj/item/device/analyzer/plant_analyzer + name = "Plant Analyzer" + icon_state = "hydro" + + attack_self(mob/user as mob) + return 0 + +/datum/vinetracker + var/list/vines = list() + + proc/process() + set background = 1 + while(vines.len > 0) + for(var/obj/plant/vine/V in vines) + sleep(-1) + switch(V.stage) + if(1) + for(var/turf/T in orange(1, V)) + var/plantfound = 0 + if(istype(T, /turf/space)) // Vines don't grow in space + break + for(var/obj/O in T) // Vines don't grow on other plants, either + if(istype(O, /obj/plant)) + plantfound = 1 + break + if(plantfound) + continue + var/chance = rand(1,100) + if(chance < 50) + spawn() new /obj/plant/vine(T) + continue + V.health += 5 + if(V.health >= 30) + V.stage = 2 + V.icon_state = "spacevine2" + V.density = 1 + else if(2) + /* + for(var/turf/T in orange(1, V)) + var/plantfound = 0 + if(istype(T, /turf/space)) + break + for(var/obj/O in T) + if(istype(O, /obj/plant)) + plantfound = 1 + break + if(plantfound) + continue + if(prob(15)) + spawn() new /obj/plant/vine(T) + */ + V.health += 5 + if(V.health >= 40) + V.stage = 3 + V.icon_state = "spacevine3" + else if(3) + V.health += 10 + if(V.health >= 60) + V.stage = 4 + V.icon_state = "spacevine4" + else if(4) + V.health += 20 + spawn(3000) del(V) + sleep(600) + + + +obj/plant + anchored = 1 + var + stage = 1 + health = 10 + +obj/plant/vine + name = "space vine" + icon = 'hydroponics.dmi' + icon_state = "spacevine1" + anchored = 1 + health = 20 + var + datum/vinetracker/tracker + + New() + ..() + for(var/datum/vinetracker/V in world) + if(V) + tracker = V + V.vines.Add(src) + return + var/datum/vinetracker/V = new /datum/vinetracker + tracker = V + V.vines.Add(src) + spawn () V.process() + + attackby(var/obj/item/weapon/W, var/mob/user) + if(health <= 0) + del(src) + return + src.visible_message("\red \The [src] has been attacked with \the [W][(user ? " by [user]." : ".")]") + var/damage = W.force * 2 + + if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + + if(WT.welding) + damage = 15 + playsound(src.loc, 'Welder.ogg', 100, 1) + + src.health -= damage + +/obj/plant/vine/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 350) + health -= 15 + if(health <= 0) + del(src) \ No newline at end of file diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm new file mode 100644 index 0000000000000..c5474ef97c554 --- /dev/null +++ b/code/game/machinery/igniter.dm @@ -0,0 +1,142 @@ +/obj/machinery/igniter/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/igniter/attack_paw(mob/user as mob) + if ((ticker && ticker.mode.name == "monkey")) + return src.attack_hand(user) + return + +/obj/machinery/igniter/attack_hand(mob/user as mob) + if(..()) + return + add_fingerprint(user) + + use_power(50) + src.on = !( src.on ) + src.icon_state = text("igniter[]", src.on) + return + +/obj/machinery/igniter/process() + if (src.on && !(stat & NOPOWER) ) + var/turf/location = src.loc + if (isturf(location)) + location.hotspot_expose(1000,500,1) + return 1 + +/obj/machinery/igniter/New() + ..() + icon_state = "igniter[on]" + +/obj/machinery/igniter/power_change() + if(!( stat & NOPOWER) ) + icon_state = "igniter[src.on]" + else + icon_state = "igniter0" + +// Wall mounted remote-control igniter. + +/obj/machinery/sparker + name = "Mounted igniter" + desc = "A wall-mounted ignition device." + icon = 'stationobjs.dmi' + icon_state = "migniter" + var/id = null + var/disable = 0 + var/last_spark = 0 + var/base_state = "migniter" + anchored = 1 + +/obj/machinery/sparker/New() + ..() + +/obj/machinery/sparker/power_change() + if ( powered() && disable == 0 ) + stat &= ~NOPOWER + icon_state = "[base_state]" + src.sd_SetLuminosity(2) + else + stat |= ~NOPOWER + icon_state = "[base_state]-p" + src.sd_SetLuminosity(0) + +/obj/machinery/sparker/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/screwdriver)) + add_fingerprint(user) + src.disable = !src.disable + if (src.disable) + user.visible_message("\red [user] has disabled the [src]!", "\red You disable the connection to the [src].") + icon_state = "[base_state]-d" + if (!src.disable) + user.visible_message("\red [user] has reconnected the [src]!", "\red You fix the connection to the [src].") + if(src.powered()) + icon_state = "[base_state]" + else + icon_state = "[base_state]-p" + +/obj/machinery/sparker/attack_ai() + if (src.anchored) + return src.ignite() + else + return + +/obj/machinery/sparker/proc/ignite() + if (!(powered())) + return + + if ((src.disable) || (src.last_spark && world.time < src.last_spark + 50)) + return + + + flick("[base_state]-spark", src) + var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread + s.set_up(2, 1, src) + s.start() + src.last_spark = world.time + use_power(1000) + var/turf/location = src.loc + if (isturf(location)) + location.hotspot_expose(1000,500,1) + return 1 + + +/obj/machinery/ignition_switch/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/ignition_switch/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/ignition_switch/attackby(obj/item/weapon/W, mob/user as mob) + + if(istype(W, /obj/item/device/detective_scanner)) + return + return src.attack_hand(user) + +/obj/machinery/ignition_switch/attack_hand(mob/user as mob) + + if(stat & (NOPOWER|BROKEN)) + return + if(active) + return + + use_power(5) + + active = 1 + icon_state = "launcheract" + + for(var/obj/machinery/sparker/M in machines) + if (M.id == src.id) + spawn( 0 ) + M.ignite() + + for(var/obj/machinery/igniter/M in machines) + if(M.id == src.id) + use_power(50) + M.on = !( M.on ) + M.icon_state = text("igniter[]", M.on) + + sleep(50) + + icon_state = "launcherbtt" + active = 0 + + return \ No newline at end of file diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm new file mode 100644 index 0000000000000..75a307e478128 --- /dev/null +++ b/code/game/machinery/lightswitch.dm @@ -0,0 +1,62 @@ +// the light switch +// can have multiple per area +// can also operate on non-loc area through "otherarea" var + +/obj/machinery/light_switch/New() + ..() + spawn(5) + src.area = src.loc.loc + + if(otherarea) + src.area = locate(text2path("/area/[otherarea]")) + + if(!name) + name = "light switch ([area.name])" + + src.on = src.area.lightswitch + updateicon() + + + +/obj/machinery/light_switch/proc/updateicon() + if(stat & NOPOWER) + icon_state = "light-p" + else + if(on) + icon_state = "light1" + else + icon_state = "light0" + +/obj/machinery/light_switch/examine() + set src in oview(1) + if(usr && !usr.stat) + usr << "A light switch. It is [on? "on" : "off"]." + + +/obj/machinery/light_switch/attack_paw(mob/user) + src.attack_hand(user) + +/obj/machinery/light_switch/attack_hand(mob/user) + + on = !on + + for(var/area/A in area.master.related) + A.lightswitch = on + A.updateicon() + + for(var/obj/machinery/light_switch/L in A) + L.on = on + L.updateicon() + + area.master.power_change() + +/obj/machinery/light_switch/power_change() + + if(!otherarea) + if(powered(LIGHT)) + stat &= ~NOPOWER + else + stat |= NOPOWER + + updateicon() + diff --git a/code/game/machinery/main.dm b/code/game/machinery/main.dm new file mode 100644 index 0000000000000..ed764cc7a2d6d --- /dev/null +++ b/code/game/machinery/main.dm @@ -0,0 +1,30 @@ +/obj/machinery/New() + ..() + machines.Add(src) + +/obj/machinery/Del() + machines.Remove(src) + ..() + +/obj/machinery/proc/process() + return + +/obj/machinery/ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(50)) + del(src) + return + if(3.0) + if (prob(25)) + del(src) + return + else + return + +/obj/machinery/blob_act() + if(prob(25)) + del(src) \ No newline at end of file diff --git a/code/game/machinery/microwave.dm b/code/game/machinery/microwave.dm new file mode 100644 index 0000000000000..1cd96362b54cb --- /dev/null +++ b/code/game/machinery/microwave.dm @@ -0,0 +1,341 @@ +/datum/recipe + var/egg_amount = 0 + var/flour_amount = 0 + var/water_amount = 0 + var/monkeymeat_amount = 0 + var/xenomeat_amount = 0 + var/humanmeat_amount = 0 + var/donkpocket_amount = 0 + var/obj/extra_item = null // This is if an extra item is needed, eg a butte for an assburger + var/creates = "" // The item that is spawned when the recipe is made + +/datum/recipe/donut + egg_amount = 1 + flour_amount = 1 + creates = "/obj/item/weapon/reagent_containers/food/snacks/donut" + +/datum/recipe/monkeyburger + egg_amount = 0 + flour_amount = 1 + monkeymeat_amount = 1 + creates = "/obj/item/weapon/reagent_containers/food/snacks/monkeyburger" + +/datum/recipe/humanburger + flour_amount = 1 + humanmeat_amount = 1 + creates = "/obj/item/weapon/reagent_containers/food/snacks/humanburger" + +/datum/recipe/brainburger + flour_amount = 1 + extra_item = /obj/item/brain + creates = "/obj/item/weapon/reagent_containers/food/snacks/brainburger" + +/datum/recipe/roburger/ + flour_amount = 1 + extra_item = /obj/item/robot_parts/head + creates = "/obj/item/weapon/reagent_containers/food/snacks/roburger" + +/datum/recipe/waffles + egg_amount = 2 + flour_amount = 2 + creates = "/obj/item/weapon/reagent_containers/food/snacks/waffles" + +/datum/recipe/faggot + monkeymeat_amount = 1 + humanmeat_amount = 1 + creates = "/obj/item/weapon/reagent_containers/food/snacks/faggot" + +/datum/recipe/pie + flour_amount = 2 + extra_item = /obj/item/weapon/banana + creates = "/obj/item/weapon/reagent_containers/food/snacks/pie" + +/datum/recipe/donkpocket + flour_amount = 1 + extra_item = /obj/item/weapon/reagent_containers/food/snacks/faggot + creates = "/obj/item/weapon/reagent_containers/food/snacks/donkpocket" + +/datum/recipe/donkpocket_warm + donkpocket_amount = 1 + creates = "/obj/item/weapon/reagent_containers/food/snacks/donkpocket" + +/datum/recipe/xenoburger + egg_amount = 0 + flour_amount = 1 + xenomeat_amount = 1 + creates = "/obj/item/weapon/reagent_containers/food/snacks/xenoburger" + +/obj/machinery/microwave/New() // *** After making the recipe in defines\obj\food.dmi, add it in here! *** + ..() + src.available_recipes += new /datum/recipe/donut(src) + src.available_recipes += new /datum/recipe/monkeyburger(src) + src.available_recipes += new /datum/recipe/humanburger(src) + src.available_recipes += new /datum/recipe/waffles(src) + src.available_recipes += new /datum/recipe/brainburger(src) + src.available_recipes += new /datum/recipe/faggot(src) + src.available_recipes += new /datum/recipe/roburger(src) + src.available_recipes += new /datum/recipe/donkpocket(src) + src.available_recipes += new /datum/recipe/donkpocket_warm(src) + src.available_recipes += new /datum/recipe/pie(src) + src.available_recipes += new /datum/recipe/xenoburger(src) + + +/******************* +* Item Adding +********************/ + +obj/machinery/microwave/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(src.broken > 0) + if(src.broken == 2 && istype(O, /obj/item/weapon/screwdriver)) // If it's broken and they're using a screwdriver + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] starts to fix part of the microwave.")) + sleep(20) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] fixes part of the microwave.")) + src.broken = 1 // Fix it a bit + else if(src.broken == 1 && istype(O, /obj/item/weapon/wrench)) // If it's broken and they're doing the wrench + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] starts to fix part of the microwave.")) + sleep(20) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] fixes the microwave!")) + src.icon_state = "mw" + src.broken = 0 // Fix it! + else + user << "It's broken!" + else if(src.dirty) // The microwave is all dirty so can't be used! + if(istype(O, /obj/item/weapon/cleaner)) // If they're trying to clean it then let them + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] starts to clean the microwave.")) + sleep(20) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] has cleaned the microwave!")) + src.dirty = 0 // It's cleaned! + src.icon_state = "mw" + else //Otherwise bad luck!! + return + else if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/egg)) // If an egg is used, add it + if(src.egg_amount < 5) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] adds an egg to the microwave.")) + src.egg_amount++ + del(O) + else if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/flour)) // If flour is used, add it + if(src.flour_amount < 5) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] adds some flour to the microwave.")) + src.flour_amount++ + del(O) + else if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/monkeymeat)) + if(src.monkeymeat_amount < 5) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] adds some meat to the microwave.")) + src.monkeymeat_amount++ + del(O) + else if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/xenomeat)) + if(src.xenomeat_amount < 5) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] adds some meat to the microwave.")) + src.xenomeat_amount++ + del(O) + else if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/humanmeat)) + if(src.humanmeat_amount < 5) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] adds some meat to the microwave.")) + src.humanmeat_name = O:subjectname + src.humanmeat_job = O:subjectjob + src.humanmeat_amount++ + del(O) + else if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/donkpocket)) + if(src.donkpocket_amount < 2) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] adds a donk-pocket to the microwave.")) + src.donkpocket_amount++ + del(O) + else + if(!istype(extra_item, /obj/item)) //Allow one non food item to be added! + user.u_equip(O) + extra_item = O + O.loc = src + if((user.client && user.s_active != src)) + user.client.screen -= O + O.dropped(user) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue [user] adds [O] to the microwave.")) + else + user << "There already seems to be an unusual item inside, so you don't add this one too." //Let them know it failed for a reason though + +obj/machinery/microwave/attack_paw(user as mob) + return src.attack_hand(user) + + +/******************* +* Microwave Menu +********************/ + +/obj/machinery/microwave/attack_hand(user as mob) // The microwave Menu + var/dat + var/xenodisplay + if(src.xenomeat_amount) xenodisplay = "Alien Meat: [src.xenomeat_amount]
      " + if(src.broken > 0) + dat = {" +Bzzzzttttt + "} + else if(src.operating) + dat = {" +Microwaving in progress!
      +Please wait...!

      +
      +"} + else if(src.dirty) + dat = {" +This microwave is dirty!
      +Please clean it before use!

      +
      +"} + else + dat = {" +Eggs:[src.egg_amount] eggs
      +Flour:[src.flour_amount] cups of flour
      +Monkey Meat:[src.monkeymeat_amount] slabs of meat
      +Meat Turnovers:[src.donkpocket_amount] turnovers
      +Other Meat:[src.humanmeat_amount] slabs of meat
      +[xenodisplay] +
      +
      +Turn on!
      +
      Dispose contents!
      +"} + + user << browse("Microwave Controls[dat]", "window=microwave") + onclose(user, "microwave") + return + + + +/*********************************** +* Microwave Menu Handling/Cooking +************************************/ + +/obj/machinery/microwave/Topic(href, href_list) + if(..()) + return + + usr.machine = src + src.add_fingerprint(usr) + + if(href_list["cook"]) + if(!src.operating) + var/operation = text2num(href_list["cook"]) + + var/cook_time = 200 // The time to wait before spawning the item + var/cooked_item = "" + + if(operation == 1) // If cook was pressed + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue The microwave turns on.")) + for(var/datum/recipe/R in src.available_recipes) //Look through the recipe list we made above + if(src.egg_amount == R.egg_amount && src.flour_amount == R.flour_amount && src.monkeymeat_amount == R.monkeymeat_amount && src.humanmeat_amount == R.humanmeat_amount && src.donkpocket_amount == R.donkpocket_amount && src.xenomeat_amount == R.xenomeat_amount) // Check if it's an accepted recipe + if(R.extra_item == null || src.extra_item.type == R.extra_item) // Just in case the recipe doesn't have an extra item in it + src.egg_amount = 0 // If so remove all the eggs + src.flour_amount = 0 // And the flour + src.water_amount = 0 //And the water + src.monkeymeat_amount = 0 + src.humanmeat_amount = 0 + src.donkpocket_amount = 0 + src.extra_item = null // And the extra item + cooked_item = R.creates // Store the item that will be created + + if(cooked_item == "") //Oops that wasn't a recipe dummy!!! + if(src.egg_amount > 0 || src.flour_amount > 0 || src.water_amount > 0 || src.monkeymeat_amount > 0 || src.humanmeat_amount > 0 || src.donkpocket_amount > 0 && src.extra_item == null) //Make sure there's something inside though to dirty it + src.operating = 1 // Turn it on + src.icon_state = "mw1" + src.updateUsrDialog() + src.egg_amount = 0 //Clear all the values as this crap is what makes the mess inside!! + src.flour_amount = 0 + src.water_amount = 0 + src.humanmeat_amount = 0 + src.monkeymeat_amount = 0 + src.donkpocket_amount = 0 + sleep(40) // Half way through + playsound(src.loc, 'splat.ogg', 50, 1) // Play a splat sound + icon_state = "mwbloody1" // Make it look dirty!! + sleep(40) // Then at the end let it finish normally + playsound(src.loc, 'ding.ogg', 50, 1) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\red The microwave gets covered in muck!")) + src.dirty = 1 // Make it dirty so it can't be used util cleaned + src.icon_state = "mwbloody" // Make it look dirty too + src.operating = 0 // Turn it off again aferwards + // Don't clear the extra item though so important stuff can't be deleted this way and + // it prolly wouldn't make a mess anyway + + else if(src.extra_item != null) // However if there's a weird item inside we want to break it, not dirty it + src.operating = 1 // Turn it on + src.icon_state = "mw1" + src.updateUsrDialog() + src.egg_amount = 0 //Clear all the values as this crap is gone when it breaks!! + src.flour_amount = 0 + src.water_amount = 0 + src.humanmeat_amount = 0 + src.monkeymeat_amount = 0 + src.donkpocket_amount = 0 + sleep(60) // Wait a while + var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread + s.set_up(2, 1, src) + s.start() + icon_state = "mwb" // Make it look all busted up and shit + for(var/mob/V in viewers(src, null)) + V.show_message(text("\red The microwave breaks!")) //Let them know they're stupid + src.broken = 2 // Make it broken so it can't be used util fixed + src.operating = 0 // Turn it off again aferwards + src.extra_item.loc = get_turf(src) // Eject the extra item so important shit like the disk can't be destroyed in there + src.extra_item = null + + else //Otherwise it was empty, so just turn it on then off again with nothing happening + src.operating = 1 + src.icon_state = "mw1" + src.updateUsrDialog() + sleep(80) + src.icon_state = "mw" + playsound(src.loc, 'ding.ogg', 50, 1) + src.operating = 0 + + if(operation == 2) // If dispose was pressed, empty the microwave + src.egg_amount = 0 + src.flour_amount = 0 + src.water_amount = 0 + src.humanmeat_amount = 0 + src.monkeymeat_amount = 0 + src.donkpocket_amount = 0 + if(src.extra_item != null) + src.extra_item.loc = get_turf(src) // Eject the extra item so important shit like the disk can't be destroyed in there + src.extra_item = null + usr << "You dispose of the microwave contents." + + var/cooking = text2path(cooked_item) // Get the item that needs to be spanwed + if(!isnull(cooking)) + for(var/mob/V in viewers(src, null)) + V.show_message(text("\blue The microwave begins cooking something!")) + src.operating = 1 // Turn it on so it can't be used again while it's cooking + src.icon_state = "mw1" //Make it look on too + src.updateUsrDialog() + src.being_cooked = new cooking(src) + + spawn(cook_time) //After the cooking time + if(!isnull(src.being_cooked)) + playsound(src.loc, 'ding.ogg', 50, 1) + if(istype(src.being_cooked, /obj/item/weapon/reagent_containers/food/snacks/humanburger)) + src.being_cooked.name = humanmeat_name + src.being_cooked.name + src.being_cooked:job = humanmeat_job + if(istype(src.being_cooked, /obj/item/weapon/reagent_containers/food/snacks/donkpocket)) + src.being_cooked:warm = 1 + src.being_cooked.name = "warm " + src.being_cooked.name + src.being_cooked:cooltime() + src.being_cooked.loc = get_turf(src) // Create the new item + src.being_cooked = null // We're done! + + src.operating = 0 // Turn the microwave back off + src.icon_state = "mw" + else + return \ No newline at end of file diff --git a/code/game/machinery/morgue.dm b/code/game/machinery/morgue.dm new file mode 100644 index 0000000000000..5906754bcd415 --- /dev/null +++ b/code/game/machinery/morgue.dm @@ -0,0 +1,345 @@ +/obj/morgue/proc/update() + if (src.connected) + src.icon_state = "morgue0" + else + if (src.contents.len) + src.icon_state = "morgue2" + else + src.icon_state = "morgue1" + return + +/obj/morgue/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + if(3.0) + if (prob(5)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + return + +/obj/morgue/alter_health() + return src.loc + +/obj/morgue/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/morgue/attack_hand(mob/user as mob) + if (src.connected) + for(var/atom/movable/A as mob|obj in src.connected.loc) + if (!( A.anchored )) + A.loc = src + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + //src.connected = null + del(src.connected) + else + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + src.connected = new /obj/m_tray( src.loc ) + step(src.connected, EAST) + src.connected.layer = OBJ_LAYER + var/turf/T = get_step(src, EAST) + if (T.contents.Find(src.connected)) + src.connected.connected = src + src.icon_state = "morgue0" + for(var/atom/movable/A as mob|obj in src) + A.loc = src.connected.loc + src.connected.icon_state = "morguet" + else + //src.connected = null + del(src.connected) + src.add_fingerprint(user) + update() + return + +/obj/morgue/attackby(P as obj, mob/user as mob) + if (istype(P, /obj/item/weapon/pen)) + var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text + if (user.equipped() != P) + return + if ((!in_range(src, usr) && src.loc != user)) + return + t = copytext(sanitize(t),1,MAX_MESSAGE_LEN) + if (t) + src.name = text("Morgue- '[]'", t) + else + src.name = "Morgue" + src.add_fingerprint(user) + return + +/obj/morgue/relaymove(mob/user as mob) + if (user.stat) + return + src.connected = new /obj/m_tray( src.loc ) + step(src.connected, EAST) + src.connected.layer = OBJ_LAYER + var/turf/T = get_step(src, EAST) + if (T.contents.Find(src.connected)) + src.connected.connected = src + src.icon_state = "morgue0" + for(var/atom/movable/A as mob|obj in src) + A.loc = src.connected.loc + //Foreach goto(106) + src.connected.icon_state = "morguet" + else + //src.connected = null + del(src.connected) + return + +/obj/m_tray/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if (istype(mover, /obj/item/weapon/dummy)) + return 1 + else + return ..() + +/obj/m_tray/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/m_tray/attack_hand(mob/user as mob) + if (src.connected) + for(var/atom/movable/A as mob|obj in src.loc) + if (!( A.anchored )) + A.loc = src.connected + //Foreach goto(26) + src.connected.connected = null + src.connected.update() + add_fingerprint(user) + //SN src = null + del(src) + return + return + +/obj/m_tray/MouseDrop_T(atom/movable/O as mob|obj, mob/user as mob) + if ((!( istype(O, /atom/movable) ) || O.anchored || get_dist(user, src) > 1 || get_dist(user, O) > 1 || user.contents.Find(src))) + return + O.loc = src.loc + if (user != O) + for(var/mob/B in viewers(user, 3)) + if ((B.client && !( B.blinded ))) + B << text("\red [] stuffs [] into []!", user, O, src) + //Foreach goto(99) + return + +/obj/crematorium/proc/update() + if (src.connected) + src.icon_state = "crema0" + else + if (src.contents.len) + src.icon_state = "crema2" + else + src.icon_state = "crema1" + return + +/obj/crematorium/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + if(3.0) + if (prob(5)) + for(var/atom/movable/A as mob|obj in src) + A.loc = src.loc + ex_act(severity) + del(src) + return + return + +/obj/crematorium/alter_health() + return src.loc + +/obj/crematorium/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/crematorium/attack_hand(mob/user as mob) +// if (cremating) AWW MAN! THIS WOULD BE SO MUCH MORE FUN ... TO WATCH +// user.show_message("\red Uh-oh, that was a bad idea.", 1) +// //usr << "Uh-oh, that was a bad idea." +// src:loc:poison += 20000000 +// src:loc:firelevel = src:loc:poison +// return + if (cremating) + usr << "\red It's locked." + return + if ((src.connected) && (src.locked == 0)) + for(var/atom/movable/A as mob|obj in src.connected.loc) + if (!( A.anchored )) + A.loc = src + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + //src.connected = null + del(src.connected) + else if (src.locked == 0) + playsound(src.loc, 'Deconstruct.ogg', 50, 1) + src.connected = new /obj/c_tray( src.loc ) + step(src.connected, SOUTH) + src.connected.layer = OBJ_LAYER + var/turf/T = get_step(src, SOUTH) + if (T.contents.Find(src.connected)) + src.connected.connected = src + src.icon_state = "crema0" + for(var/atom/movable/A as mob|obj in src) + A.loc = src.connected.loc + src.connected.icon_state = "cremat" + else + //src.connected = null + del(src.connected) + src.add_fingerprint(user) + update() + +/obj/crematorium/attackby(P as obj, mob/user as mob) + if (istype(P, /obj/item/weapon/pen)) + var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text + if (user.equipped() != P) + return + if ((!in_range(src, usr) > 1 && src.loc != user)) + return + t = copytext(sanitize(t),1,MAX_MESSAGE_LEN) + if (t) + src.name = text("Crematorium- '[]'", t) + else + src.name = "Crematorium" + src.add_fingerprint(user) + return + +/obj/crematorium/relaymove(mob/user as mob) + if (user.stat || locked) + return + src.connected = new /obj/c_tray( src.loc ) + step(src.connected, SOUTH) + src.connected.layer = OBJ_LAYER + var/turf/T = get_step(src, SOUTH) + if (T.contents.Find(src.connected)) + src.connected.connected = src + src.icon_state = "crema0" + for(var/atom/movable/A as mob|obj in src) + A.loc = src.connected.loc + //Foreach goto(106) + src.connected.icon_state = "cremat" + else + //src.connected = null + del(src.connected) + return + +/obj/crematorium/proc/cremate(atom/A, mob/user as mob) +// for(var/obj/machinery/crema_switch/O in src) //trying to figure a way to call the switch, too drunk to sort it out atm +// if(var/on == 1) +// return + if(cremating) + return //don't let you cremate something twice or w/e + + if(length(contents) == 0) + for (var/mob/M in viewers(user)) + M.show_message("\red You hear a hollow crackle.", 1) + return + else if(contents) + cremating = 1 + locked = 1 + var/mob/dead/observer/newmob + for (var/M in contents) + if (istype(M,/mob/living) && M:client) + spawn(1) + var/i + M:stunned = 100 //You really dont want to place this inside the loop. + + newmob = new/mob/dead/observer(M) + M:client:mob = newmob + + for(i=0, i<10, i++) + sleep(10) + M:fireloss += 30 + new /obj/decal/ash(M:loc) + + //newmob.loc = src.loc + + newmob:client:eye = newmob // Hrm + for (var/obj/item/weapon/W in M) + if (prob(10)) + W.loc = M:loc + del(M) + else if (istype(M,/mob/living) && !(M:client)) // + spawn(0) + var/i + M:stunned = 100 + for(i=0, i<10, i++) + sleep(10) + M:fireloss += 50 + new /obj/decal/ash(M:loc) + for (var/obj/item/weapon/W in M) + if (prob(10)) + W.loc = M:loc + del(M) + for (var/mob/M in viewers(user)) + M.show_message("\red You hear a roar as the crematorium activates.", 1) + spawn(100) + cremating = 0 + locked = 0 + playsound(src.loc, 'ding.ogg', 50, 1) + + return + +/obj/c_tray/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if (istype(mover, /obj/item/weapon/dummy)) + return 1 + else + return ..() + +/obj/c_tray/attack_paw(mob/user as mob) + return src.attack_hand(user) + +/obj/c_tray/attack_hand(mob/user as mob) + if (src.connected) + for(var/atom/movable/A as mob|obj in src.loc) + if (!( A.anchored )) + A.loc = src.connected + //Foreach goto(26) + src.connected.connected = null + src.connected.update() + add_fingerprint(user) + //SN src = null + del(src) + return + return + +/obj/c_tray/MouseDrop_T(atom/movable/O as mob|obj, mob/user as mob) + if ((!( istype(O, /atom/movable) ) || O.anchored || get_dist(user, src) > 1 || get_dist(user, O) > 1 || user.contents.Find(src))) + return + O.loc = src.loc + if (user != O) + for(var/mob/B in viewers(user, 3)) + if ((B.client && !( B.blinded ))) + B << text("\red [] stuffs [] into []!", user, O, src) + //Foreach goto(99) + return + +/obj/machinery/crema_switch/attack_hand(mob/user as mob) + if(src.allowed(usr)) + for (var/obj/crematorium/C in world) + if (C.id == id) + if (!C.cremating) + C.cremate(user) + else + usr << "\red Access denied." + return + diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm new file mode 100644 index 0000000000000..b694823af3ca7 --- /dev/null +++ b/code/game/machinery/navbeacon.dm @@ -0,0 +1,244 @@ +// Navigation beacon for AI robots +// Functions as a transponder: looks for incoming signal matching + +/obj/machinery/navbeacon + + icon = 'objects.dmi' + icon_state = "navbeacon0-f" + name = "navigation beacon" + desc = "A radio beacon used for bot navigation." + level = 1 // underfloor + layer = 2.5 + anchored = 1 + + var/open = 0 // true if cover is open + var/locked = 1 // true if controls are locked + var/freq = 1445 // radio frequency + var/location = "" // location response text + var/list/codes // assoc. list of transponder codes + var/codes_txt = "" // codes as set on map: "tag1;tag2" or "tag1=value;tag2=value" + + req_access = list(access_engine) + + New() + ..() + + set_codes() + + var/turf/T = loc + hide(T.intact) + + spawn(5) // must wait for map loading to finish + if(radio_controller) + radio_controller.add_object(src, "[freq]") + + // set the transponder codes assoc list from codes_txt + proc/set_codes() + if(!codes_txt) + return + + codes = new() + + var/list/entries = dd_text2List(codes_txt, ";") // entries are separated by semicolons + + for(var/e in entries) + var/index = findtext(e, "=") // format is "key=value" + if(index) + var/key = copytext(e, 1, index) + var/val = copytext(e, index+1) + codes[key] = val + else + codes[e] = "1" + + + // called when turf state changes + // hide the object if turf is intact + hide(var/intact) + invisibility = intact ? 101 : 0 + updateicon() + + // update the icon_state + proc/updateicon() + var/state="navbeacon[open]" + + if(invisibility) + icon_state = "[state]-f" // if invisible, set icon to faded version + // in case revealed by T-scanner + else + icon_state = "[state]" + + + // look for a signal of the form "findbeacon=X" + // where X is any + // or the location + // or one of the set transponder keys + // if found, return a signal + receive_signal(datum/signal/signal) + + var/request = signal.data["findbeacon"] + if(request && ((request in codes) || request == "any" || request == location)) + spawn(1) + post_signal() + + // return a signal giving location and transponder codes + + proc/post_signal() + + var/datum/radio_frequency/frequency = radio_controller.return_frequency("[freq]") + + if(!frequency) return + + var/datum/signal/signal = new() + signal.source = src + signal.transmission_method = 1 + signal.data["beacon"] = location + + for(var/key in codes) + signal.data[key] = codes[key] + + frequency.post_signal(src, signal) + + + attackby(var/obj/item/I, var/mob/user) + var/turf/T = loc + if(T.intact) + return // prevent intraction when T-scanner revealed + + if(istype(I, /obj/item/weapon/screwdriver)) + open = !open + + user.visible_message("[user] [open ? "opens" : "closes"] the beacon's cover.", "You [open ? "open" : "close"] the beacon's cover.") + + updateicon() + + else if (istype(I, /obj/item/weapon/card/id)) + if(open) + if (src.allowed(user)) + src.locked = !src.locked + user << "Controls are now [src.locked ? "locked." : "unlocked."]" + else + user << "\red Access denied." + updateDialog() + else + user << "You must open the cover first!" + return + + attack_ai(var/mob/user) + interact(user, 1) + + attack_paw() + return + + attack_hand(var/mob/user) + interact(user, 0) + + proc/interact(var/mob/user, var/ai = 0) + var/turf/T = loc + if(T.intact) + return // prevent intraction when T-scanner revealed + + if(!open && !ai) // can't alter controls if not open, unless you're an AI + user << "The beacon's control cover is closed." + return + + + var/t + + if(locked && !ai) + t = {"Navigation Beacon

      +(swipe card to unlock controls)
      +Frequency: [format_frequency(freq)]

      +Location: [location ? location : "(none)"]

      +Transponder Codes: