diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 82633fdc70..f67f095a4f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,3 @@ -[Feature Freeze!]: # We are currently not considering any balance or antagonist oriented pull requests. Full details, as well as ways to bypass this freeze, are available here https://github.com/tgstation/tgstation/pull/28223 - - [Changelogs]: # (Please make a changelog if you're adding, removing or changing content that'll affect players. This includes, but is not limited to, new features, sprites, sounds; balance changes; map edits and important fixes) []: # (See here for how to easily make a changelog: https://github.com/tgstation/tgstation/wiki/Changelogs. An example changelog has been provided below. Please edit or remove) diff --git a/.travis.yml b/.travis.yml index c0a45df72d..ba11b40c97 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: generic sudo: false +dist: precise env: global: diff --git a/SQL/database_changelog.txt.rej b/SQL/database_changelog.txt.rej new file mode 100644 index 0000000000..1b201ec4aa --- /dev/null +++ b/SQL/database_changelog.txt.rej @@ -0,0 +1,15 @@ +diff a/SQL/database_changelog.txt b/SQL/database_changelog.txt (rejected hunks) +@@ -1,10 +1,10 @@ + Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255. + +-The latest database version is 3.1; The query to update the schema revision table is: ++The latest database version is 3.0; The query to update the schema revision table is: + +-UPDATE `schema_revision` SET major = 3, minor = 1 LIMIT 1; ++INSERT INTO `schema_revision` (`major`, `minor`) VALUES (3, 0); + or +-UPDATE `SS13_schema_revision` SET major = 3, minor = 1 LIMIT 1; ++INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (3, 0); + + ---------------------------------------------------- + diff --git a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm index f0f2d8a6c5..c47534925f 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm @@ -460,7 +460,7 @@ /area/ruin/powered/beach) "cz" = ( /obj/effect/turf_decal/sand, -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/plating/beach/sand, /area/ruin/powered/beach) "cR" = ( diff --git a/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm b/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm index 408fe6ff1d..87137f7d14 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm @@ -896,7 +896,7 @@ /area/ruin/powered/clownplanet) "dR" = ( /obj/effect/decal/cleanable/dirt, -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/indestructible/sound{ icon_state = "bananium"; name = "bananium floor"; diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_animal_hospital.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_animal_hospital.dmm index de78fed108..ec1ce79bd8 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_animal_hospital.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_animal_hospital.dmm @@ -809,7 +809,7 @@ /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "cF" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/closed/wall/mineral/titanium/nodiagonal, /area/ruin/powered/animal_hospital) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm index aed9b30686..3cae12bfe1 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm @@ -1071,7 +1071,7 @@ /area/ruin/unpowered/ash_walkers) "cE" = ( /obj/structure/stone_tile/surrounding/cracked, -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/ash_walkers) "cF" = ( diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_biodome_winter.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_biodome_winter.dmm index 49ae2cb4f5..722cc92d78 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_biodome_winter.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_biodome_winter.dmm @@ -275,7 +275,7 @@ }, /area/ruin/powered/snow_biodome) "bS" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/plating/asteroid/snow{ initial_gas_mix = "o2=22;n2=82;TEMP=180" }, diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_cultaltar.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_cultaltar.dmm index ed4aee469d..875cfdc35d 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_cultaltar.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_cultaltar.dmm @@ -163,7 +163,7 @@ /turf/open/floor/plasteel/cult{ initial_gas_mix = "o2=14;n2=23;TEMP=300" }, -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/closed/wall/mineral/cult, /area/ruin/unpowered) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_envy.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_envy.dmm index 66d7173097..773fc01f51 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_envy.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_envy.dmm @@ -104,7 +104,7 @@ /turf/open/floor/plating, /area/ruin/unpowered) "r" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/closed/wall/rust, /area/ruin/unpowered) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_fountain_hall.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_fountain_hall.dmm index 0c40aa2881..ab1d5764e1 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_fountain_hall.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_fountain_hall.dmm @@ -29,7 +29,7 @@ /turf/open/floor/engine/cult, /area/ruin/unpowered) "i" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/engine/cult, /area/ruin/unpowered) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_gluttony.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_gluttony.dmm index 97b44df094..3b1c555805 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_gluttony.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_gluttony.dmm @@ -85,7 +85,7 @@ /turf/open/floor/plasteel/freezer, /area/ruin/powered/gluttony) "D" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/plasteel/freezer, /area/ruin/powered/gluttony) "R" = ( diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm index fa1e394751..c993ecbb63 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm @@ -285,7 +285,7 @@ /turf/open/floor/plating, /area/ruin/powered/golem_ship) "Y" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/mineral/titanium/purple, /area/ruin/powered/golem_ship) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_greed.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_greed.dmm index 3d67d7b474..c81c510b9e 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_greed.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_greed.dmm @@ -123,7 +123,7 @@ /turf/open/floor/engine/cult, /area/ruin/powered/greed) "z" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/engine/cult, /area/ruin/powered/greed) "J" = ( diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm index 896f13b1bb..2749e39f1f 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm @@ -180,7 +180,7 @@ }, /area/ruin/powered) "L" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/plating/asteroid/basalt, /area/ruin/powered) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm index 44c41f5b85..f14495c95c 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm @@ -342,7 +342,7 @@ /area/ruin/unpowered) "S" = ( /obj/effect/decal/cleanable/dirt, -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/wood{ baseturf = /turf/open/floor/plating/asteroid/basalt/lava_land_surface; initial_gas_mix = "o2=14;n2=23;TEMP=300" diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_pride.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_pride.dmm index b1dedc0cb3..38b5f5f64d 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_pride.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_pride.dmm @@ -65,7 +65,7 @@ /turf/open/floor/mineral/silver, /area/ruin/powered/pride) "u" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/mineral/silver, /area/ruin/powered/pride) "G" = ( diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm index cb2686fe89..01ac536230 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm @@ -262,7 +262,7 @@ /turf/open/floor/plasteel/freezer, /area/ruin/powered/seedvault) "Z" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/closed/wall/r_wall, /area/ruin/powered/seedvault) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm index 89a8b50c39..5ae4227813 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm @@ -42,7 +42,7 @@ }, /area/ruin/unpowered) "h" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/sepia{ blocks_air = 0; slowdown = 10 diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm index 3392d60307..8d40c16d58 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm @@ -169,7 +169,7 @@ /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "B" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/closed/wall/mineral/titanium/survival/pod, /area/ruin/powered) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_swarmer_crash.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_swarmer_crash.dmm index a794b58db8..3962947551 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_swarmer_crash.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_swarmer_crash.dmm @@ -22,7 +22,7 @@ /turf/open/floor/mineral/plastitanium, /area/ruin/unpowered) "g" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/closed/wall/mineral/plastitanium, /area/ruin/unpowered) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm index be96830ca4..2893f3481f 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm @@ -1285,7 +1285,7 @@ }, /area/ruin/powered/syndicate_lava_base) "dd" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/plasteel/vault{ dir = 5 }, diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm index 22d341c7df..0c4dd60fb8 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm @@ -105,7 +105,7 @@ "s" = ( /obj/structure/table/optable/abductor, /obj/item/weapon/cautery/alien, -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/plating/abductor{ initial_gas_mix = "o2=16;n2=23;TEMP=300" }, diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm index d139ee641b..fed94448d0 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm @@ -269,7 +269,7 @@ "W" = ( /obj/structure/alien/weeds, /obj/structure/alien/resin/wall, -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/xenonest) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm.rej b/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm.rej new file mode 100644 index 0000000000..365cc7fdda --- /dev/null +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm.rej @@ -0,0 +1,10 @@ +diff a/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm (rejected hunks) +@@ -269,7 +269,7 @@ + "W" = ( + /obj/structure/alien/weeds, + /obj/structure/alien/resin/wall, +-/obj/effect/baseturf_helper, ++/obj/effect/baseturf_helper/lava_land/surface, + /turf/open/floor/plating/asteroid/basalt/lava_land_surface, + /area/ruin/unpowered/xenonest) + diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index bf4263ffe6..c89e4e0422 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -60788,9 +60788,6 @@ /turf/open/floor/plasteel, /area/science/robotics/lab) "cHY" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 3e19f173a4..781a872633 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -7457,9 +7457,6 @@ /turf/open/floor/plating, /area/maintenance/port/fore) "aqr" = ( -/turf/open/floor/plating{ - icon_state = "panelscorched" - }, /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -25015,6 +25012,10 @@ dir = 1; icon_state = "pipe-c" }, +/obj/structure/fireaxecabinet{ + pixel_x = -32; + pixel_y = 0 + }, /turf/open/floor/plasteel/caution{ icon_state = "caution"; dir = 8 @@ -29570,10 +29571,10 @@ "bgT" = ( /obj/machinery/computer/atmos_control/tank{ frequency = 1441; - input_tag = "co2_in"; - name = "Carbon Dioxide Supply Control"; - output_tag = "co2_out"; - sensors = list("co2_sensor" = "Tank") + input_tag = "n2o_in"; + name = "Nitrous Oxide Supply Control"; + output_tag = "n2o_out"; + sensors = list("n2o_sensor" = "Tank") }, /obj/structure/window/reinforced{ dir = 8 @@ -112682,9 +112683,6 @@ /turf/open/floor/plating, /area/engine/atmospherics_engine) "ept" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, /obj/effect/turf_decal/stripes/line{ dir = 9 }, @@ -138464,7 +138462,7 @@ aRf aSV aUs aIU -aIU +aSV aIU aSV aSV diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm index 4c00524717..9b97eef1d5 100644 --- a/_maps/map_files/Mining/Lavaland.dmm +++ b/_maps/map_files/Mining/Lavaland.dmm @@ -1,4 +1,4 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "aa" = ( /turf/closed/indestructible/riveted/boss, /area/lavaland/surface/outdoors) @@ -1241,6 +1241,7 @@ d2 = 4; icon_state = "1-4" }, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/circuit, /area/mine/maintenance) "dy" = ( @@ -3399,17 +3400,27 @@ /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "Wt" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/closed/wall, /area/mine/laborcamp/security) "Wu" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/closed/wall, /area/mine/laborcamp) "Ww" = ( -/obj/effect/baseturf_helper, +/obj/effect/baseturf_helper/lava_land/surface, /turf/open/floor/plasteel, /area/mine/living_quarters) +"Wx" = ( +/obj/effect/baseturf_helper/lava_land/surface, +/turf/open/floor/plasteel/brown{ + dir = 4 + }, +/area/mine/eva) +"Wy" = ( +/obj/effect/baseturf_helper/lava_land/surface, +/turf/open/floor/plasteel, +/area/mine/production) (1,1,1) = {" aa @@ -19057,7 +19068,7 @@ cI cP cn bP -bP +Wy bP bP eD @@ -19570,7 +19581,7 @@ bf cK bq bq -dt +br bq dV el @@ -20335,7 +20346,7 @@ bf bp bu bI -bW +Wx cr bf ad diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index 60495dcf55..020a963662 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -5039,7 +5039,6 @@ name = "Detective Privacy Blast door" }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plating, /area/security/detectives_office) "aix" = ( @@ -32004,7 +32003,6 @@ "bcM" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel/vault{ dir = 5 }, diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 4cc0b5c158..b4b78673a1 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -49675,7 +49675,7 @@ /turf/open/floor/plating, /area/maintenance/department/engine) "cdF" = ( -/obj/structure/closet/secure_closet/miner, +/obj/structure/closet/secure_closet/miner/unlocked, /turf/open/floor/plating, /area/shuttle/auxillary_base) "cdG" = ( diff --git a/apc_repair.dmi b/apc_repair.dmi new file mode 100644 index 0000000000..6e861eef61 Binary files /dev/null and b/apc_repair.dmi differ diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm index 82d030bf08..24e10a24d1 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -1,15 +1,16 @@ //Investigate logging defines -#define INVESTIGATE_ATMOS "atmos" -#define INVESTIGATE_BOTANY "botany" -#define INVESTIGATE_CARGO "cargo" -#define INVESTIGATE_EXPERIMENTOR "experimentor" -#define INVESTIGATE_GRAVITY "gravity" -#define INVESTIGATE_RECORDS "records" -#define INVESTIGATE_SINGULO "singulo" -#define INVESTIGATE_SUPERMATTER "supermatter" -#define INVESTIGATE_TELESCI "telesci" -#define INVESTIGATE_WIRES "wires" +#define INVESTIGATE_ATMOS "atmos" +#define INVESTIGATE_BOTANY "botany" +#define INVESTIGATE_CARGO "cargo" +#define INVESTIGATE_EXPERIMENTOR "experimentor" +#define INVESTIGATE_GRAVITY "gravity" +#define INVESTIGATE_RECORDS "records" +#define INVESTIGATE_SINGULO "singulo" +#define INVESTIGATE_SUPERMATTER "supermatter" +#define INVESTIGATE_TELESCI "telesci" +#define INVESTIGATE_WIRES "wires" #define INVESTIGATE_PORTAL "portals" +#define INVESTIGATE_HALLUCINATIONS "hallucinations" //Individual logging defines #define INDIVIDUAL_ATTACK_LOG "Attack log" diff --git a/code/__DEFINES/logging.dm.rej b/code/__DEFINES/logging.dm.rej new file mode 100644 index 0000000000..6a7a358a9c --- /dev/null +++ b/code/__DEFINES/logging.dm.rej @@ -0,0 +1,9 @@ +diff a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm (rejected hunks) +@@ -9,6 +9,7 @@ + #define INVESTIGATE_SUPERMATTER "supermatter" + #define INVESTIGATE_TELESCI "telesci" + #define INVESTIGATE_WIRES "wires" ++#define INVESTIGATE_HALLUCINATIONS "hallucinations" + + //Individual logging defines + #define INDIVIDUAL_ATTACK_LOG "Attack log" diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index e0ab84f832..4342766be7 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -8,7 +8,7 @@ //You can use these defines to get the typepath of the currently running proc/verb (yes procs + verbs are objects) /* eg: /mob/living/carbon/human/death() - world << THIS_PROC_TYPE_STR //You can only output the string versions + to_chat(world, THIS_PROC_TYPE_STR) //You can only output the string versions Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a string with () (eg: the _WITH_ARGS defines) to make it look nicer) */ #define THIS_PROC_TYPE ..... @@ -46,8 +46,8 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s //Human Overlays Indexes///////// //citadel code #define MUTATIONS_LAYER 30 //mutations. Tk headglows, cold resistance glow, etc -#define BODY_BEHIND_LAYER 29 //certain mutantrace features (tail when looking south) that must appear behind the body parts -#define GENITALS_BEHIND_LAYER 28 +#define GENITALS_BEHIND_LAYER 29 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer +#define BODY_BEHIND_LAYER 28 //certain mutantrace features (tail when looking south) that must appear behind the body parts #define BODYPARTS_LAYER 27 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag #define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts #define GENITALS_ADJ_LAYER 25 @@ -350,6 +350,7 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE //debug printing macros #define debug_world(msg) if (GLOB.Debug2) to_chat(world, "DEBUG: [msg]") +#define debug_usr(msg) if (GLOB.Debug2&&usr) to_chat(usr, "DEBUG: [msg]") #define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.admins, "DEBUG: [msg]") #define debug_world_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]") diff --git a/code/__DEFINES/server_tools.dm b/code/__DEFINES/server_tools.dm index 4624c5914f..a4afa58a87 100644 --- a/code/__DEFINES/server_tools.dm +++ b/code/__DEFINES/server_tools.dm @@ -4,6 +4,9 @@ #define IRC_STATUS_THROTTLE 5 +#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round + //This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored + //keep these in sync with TGS3 #define SERVICE_WORLD_PARAM "server_service" #define SERVICE_PR_TEST_JSON "..\\..\\prtestjob.json" @@ -17,7 +20,7 @@ #define SERVICE_CMD_NAME_CHECK "namecheck" #define SERVICE_CMD_ADMIN_WHO "adminwho" -//#define SERVICE_CMD_PARAM_KEY //defined in __compile_options.dm +#define SERVICE_CMD_PARAM_KEY "serviceCommsKey" #define SERVICE_CMD_PARAM_COMMAND "command" #define SERVICE_CMD_PARAM_MESSAGE "message" #define SERVICE_CMD_PARAM_TARGET "target" diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 9c64fb8b74..9646f03252 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -320,7 +320,7 @@ return r // Returns the key based on the index -#define KEYBYINDEX(L, index) (((index <= L:len) && (index > 0)) ? L[index] : null) +#define KEYBYINDEX(L, index) (((index <= length(L)) && (index > 0)) ? L[index] : null) /proc/count_by_type(list/L, type) var/i = 0 @@ -468,7 +468,7 @@ . |= key_list[key] //Picks from the list, with some safeties, and returns the "default" arg if it fails -#define DEFAULTPICK(L, default) ((islist(L) && L:len) ? pick(L) : default) +#define DEFAULTPICK(L, default) ((islist(L) && length(L)) ? pick(L) : default) #define LAZYINITLIST(L) if (!L) L = list() #define UNSETEMPTY(L) if (L && !L.len) L = null #define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } } diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 2dd2e42129..05b6aa1a15 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -1,3 +1,10 @@ +//wrapper macros for easier grepping +#define DIRECT_OUTPUT(A, B) A << B +#define SEND_IMAGE(target, image) DIRECT_OUTPUT(target, image) +#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound) +#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text) +#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text) + //print a warning message to world.log #define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].") /proc/warning(msg) @@ -20,13 +27,13 @@ /proc/log_admin(text) GLOB.admin_log.Add(text) if (config.log_admin) - GLOB.world_game_log << "\[[time_stamp()]]ADMIN: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMIN: [text]") //Items using this proc are stripped from public logs - use with caution /proc/log_admin_private(text) GLOB.admin_log.Add(text) if (config.log_admin) - GLOB.world_game_log << "\[[time_stamp()]]ADMINPRIVATE: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMINPRIVATE: [text]") /proc/log_adminsay(text) if (config.log_adminchat) @@ -38,65 +45,65 @@ /proc/log_game(text) if (config.log_game) - GLOB.world_game_log << "\[[time_stamp()]]GAME: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]GAME: [text]") /proc/log_vote(text) if (config.log_vote) - GLOB.world_game_log << "\[[time_stamp()]]VOTE: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]VOTE: [text]") /proc/log_access(text) if (config.log_access) - GLOB.world_game_log << "\[[time_stamp()]]ACCESS: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ACCESS: [text]") /proc/log_say(text) if (config.log_say) - GLOB.world_game_log << "\[[time_stamp()]]SAY: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]SAY: [text]") /proc/log_prayer(text) if (config.log_prayer) - GLOB.world_game_log << "\[[time_stamp()]]PRAY: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]PRAY: [text]") /proc/log_law(text) if (config.log_law) - GLOB.world_game_log << "\[[time_stamp()]]LAW: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]LAW: [text]") /proc/log_ooc(text) if (config.log_ooc) - GLOB.world_game_log << "\[[time_stamp()]]OOC: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]OOC: [text]") /proc/log_whisper(text) if (config.log_whisper) - GLOB.world_game_log << "\[[time_stamp()]]WHISPER: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]WHISPER: [text]") /proc/log_emote(text) if (config.log_emote) - GLOB.world_game_log << "\[[time_stamp()]]EMOTE: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]EMOTE: [text]") /proc/log_attack(text) if (config.log_attack) - GLOB.world_attack_log << "\[[time_stamp()]]ATTACK: [text]" + WRITE_FILE(GLOB.world_attack_log, "\[[time_stamp()]]ATTACK: [text]") /proc/log_pda(text) if (config.log_pda) - GLOB.world_game_log << "\[[time_stamp()]]PDA: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]PDA: [text]") /proc/log_comment(text) if (config.log_pda) //reusing the PDA option because I really don't think news comments are worth a config option - GLOB.world_game_log << "\[[time_stamp()]]COMMENT: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]COMMENT: [text]") /proc/log_chat(text) if (config.log_pda) - GLOB.world_game_log << "\[[time_stamp()]]CHAT: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]CHAT: [text]") /proc/log_sql(text) if(config.sql_enabled) - GLOB.world_game_log << "\[[time_stamp()]]SQL: [text]" + WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]SQL: [text]") //This replaces world.log so it displays both in DD and the file /proc/log_world(text) - GLOB.world_runtime_log << text - world.log << text + WRITE_FILE(GLOB.world_runtime_log, text) + SEND_TEXT(world.log, text) // Helper procs for building detailed log lines diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index d150e86f45..9b1507771a 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -418,7 +418,7 @@ /proc/showCandidatePollWindow(mob/M, poll_time, Question, list/candidates, ignore_category, time_passed, flashwindow = TRUE) set waitfor = 0 - M << 'sound/misc/notice2.ogg' //Alerting them to their consideration + SEND_SOUND(M, 'sound/misc/notice2.ogg') //Alerting them to their consideration if(flashwindow) window_flash(M.client) switch(ignore_category ? askuser(M,Question,"Please answer in [poll_time/10] seconds!","Yes","No","Never for this round", StealFocus=0, Timeout=poll_time) : askuser(M,Question,"Please answer in [poll_time/10] seconds!","Yes","No", StealFocus=0, Timeout=poll_time)) @@ -426,7 +426,7 @@ to_chat(M, "Choice registered: Yes.") if(time_passed + poll_time <= world.time) to_chat(M, "Sorry, you answered too late to be considered!") - M << 'sound/machines/buzz-sigh.ogg' + SEND_SOUND(M, 'sound/machines/buzz-sigh.ogg') candidates -= M else candidates += M diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 92d5dcbd80..1af231f893 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -48,6 +48,11 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list) //genitals init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list) + + for(var/K in GLOB.cock_shapes_list) + var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K] + GLOB.cock_shapes_icons[K] = value.icon_state + init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list) GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing. diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 04ea69a43f..b245b1f146 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -167,7 +167,7 @@ mob Output_Icon() set name = "2. Output Icon" - to_chat(src, "Icon is: [bicon(getFlatIcon(src))]") + to_chat(src, "Icon is: [icon2base64html(getFlatIcon(src))]") Label_Icon() set name = "3. Label Icon" @@ -712,7 +712,8 @@ The _flatIcons list is a cache for generated icon files. if(!current) curIndex++ //Try the next layer continue - currentLayer = current:layer + var/image/I = current + currentLayer = I.layer if(currentLayer<0) // Special case for FLY_LAYER if(currentLayer <= -1000) return flat if(pSet == 0) // Underlay @@ -747,22 +748,22 @@ The _flatIcons list is a cache for generated icon files. // Dimensions of overlay being added var/{addX1;addX2;addY1;addY2} - for(var/I in layers) - - if(I:alpha == 0) + for(var/V in layers) + var/image/I = V + if(I.alpha == 0) continue if(I == copy) // 'I' is an /image based on the object being flattened. curblend = BLEND_OVERLAY - add = icon(I:icon, I:icon_state, I:dir) + add = icon(I.icon, I.icon_state, I.dir) else // 'I' is an appearance object. add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend) // Find the new dimensions of the flat icon to fit the added overlay - addX1 = min(flatX1, I:pixel_x+1) - addX2 = max(flatX2, I:pixel_x+add.Width()) - addY1 = min(flatY1, I:pixel_y+1) - addY2 = max(flatY2, I:pixel_y+add.Height()) + addX1 = min(flatX1, I.pixel_x+1) + addX2 = max(flatX2, I.pixel_x+add.Width()) + addY1 = min(flatY1, I.pixel_y+1) + addY2 = max(flatY2, I.pixel_y+add.Height()) if(addX1!=flatX1 || addX2!=flatX2 || addY1!=flatY1 || addY2!=flatY2) // Resize the flattened icon so the new icon fits @@ -771,7 +772,7 @@ The _flatIcons list is a cache for generated icon files. flatY1=addY1;flatY2=addY2 // Blend the overlay into the flattened icon - flat.Blend(add, blendMode2iconMode(curblend), I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1) + flat.Blend(add, blendMode2iconMode(curblend), I.pixel_x + 2 - flatX1, I.pixel_y + 2 - flatY1) if(A.color) flat.Blend(A.color, ICON_MULTIPLY) @@ -782,10 +783,11 @@ The _flatIcons list is a cache for generated icon files. /proc/getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A. - for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it. - if(I:layer>A.layer) + for(var/V in A.overlays)//For every image in overlays. var/image/I will not work, don't try it. + var/image/I = V + if(I.layer>A.layer) continue//If layer is greater than what we need, skip it. - var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects. + var/icon/image_overlay = new(I.icon,I.icon_state)//Blend only works with icon objects. //Also, icons cannot directly set icon_state. Slower than changing variables but whatever. alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay. return alpha_mask//And now return the mask. @@ -993,3 +995,110 @@ GLOBAL_LIST_EMPTY(friendly_animal_types) #undef FROZEN_RED_COLOR #undef FROZEN_GREEN_COLOR #undef FROZEN_BLUE_COLOR + + +//Converts an icon to base64. Operates by putting the icon in the iconCache savefile, +// exporting it as text, and then parsing the base64 from that. +// (This relies on byond automatically storing icons in savefiles as base64) +/proc/icon2base64(icon/icon, iconKey = "misc") + if (!isicon(icon)) + return FALSE + WRITE_FILE(GLOB.iconCache[iconKey], icon) + var/iconData = GLOB.iconCache.ExportText(iconKey) + var/list/partial = splittext(iconData, "{") + return replacetext(copytext(partial[2], 3, -5), "\n", "") + +/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving = FALSE) + if (!thing) + return + + var/key + var/icon/I = thing + if (!target) + return + if (target == world) + target = GLOB.clients + + var/list/targets + if (!islist(target)) + targets = list(target) + else + targets = target + if (!targets.len) + return + if (!isicon(I)) + if (isfile(thing)) //special snowflake + var/name = sanitize_filename("[generate_asset_name(thing)].png") + register_asset(name, thing) + for (var/thing2 in targets) + send_asset(thing2, key, FALSE) + return "" + var/atom/A = thing + if (isnull(dir)) + dir = A.dir + if (isnull(icon_state)) + icon_state = A.icon_state + I = A.icon + if (ishuman(thing)) // Shitty workaround for a BYOND issue. + var/icon/temp = I + I = icon() + I.Insert(temp, dir = SOUTH) + dir = SOUTH + else + if (isnull(dir)) + dir = SOUTH + if (isnull(icon_state)) + icon_state = "" + + I = icon(I, icon_state, dir, frame, moving) + + key = "[generate_asset_name(I)].png" + register_asset(key, I) + for (var/thing2 in targets) + send_asset(thing2, key, FALSE) + + return "" + +/proc/icon2base64html(thing) + if (!thing) + return + var/static/list/bicon_cache = list() + if (isicon(thing)) + var/icon/I = thing + var/icon_base64 = icon2base64(I) + + if (I.Height() > world.icon_size || I.Width() > world.icon_size) + var/icon_md5 = md5(icon_base64) + icon_base64 = bicon_cache[icon_md5] + if (!icon_base64) // Doesn't exist yet, make it. + bicon_cache[icon_md5] = icon_base64 = icon2base64(I) + + + return "" + + // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with. + var/atom/A = thing + var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]" + + + if (!bicon_cache[key]) // Doesn't exist, make it. + var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1) + if (ishuman(thing)) // Shitty workaround for a BYOND issue. + var/icon/temp = I + I = icon() + I.Insert(temp, dir = SOUTH) + + bicon_cache[key] = icon2base64(I, key) + + return "" + +//Costlier version of icon2html() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. +/proc/costly_icon2html(thing, target) + if (!thing) + return + + if (isicon(thing)) + return icon2html(thing, target) + + var/icon/I = getFlatIcon(thing) + return icon2html(I, target) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 7c6746f477..cb64f3fb22 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -1,6 +1,3 @@ -//wrapper macro for sending images that makes grepping easy -#define SEND_IMAGE(target, image) target << image - /proc/random_blood_type() return pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") @@ -116,6 +113,7 @@ "xenohead" = "None", "xenotail" = "None", "exhibitionist" = FALSE, + "genitals_use_skintone" = FALSE, "has_cock" = FALSE, "cock_shape" = pick(GLOB.cock_shapes_list), "cock_length" = 6, @@ -158,8 +156,9 @@ "womb_cum_rate" = CUM_RATE, "womb_cum_mult" = CUM_RATE_MULT, "womb_efficiency" = CUM_EFFICIENCY, - "womb_fluid" = "femcum")) - + "womb_fluid" = "femcum", + "flavor_text" = "")) + /proc/random_hair_style(gender) switch(gender) if(MALE) diff --git a/code/__HELPERS/priority_announce.dm b/code/__HELPERS/priority_announce.dm index 70bb8b2db6..a617437ac3 100644 --- a/code/__HELPERS/priority_announce.dm +++ b/code/__HELPERS/priority_announce.dm @@ -24,11 +24,12 @@ announcement += "
[html_encode(text)]
" announcement += "
" + var/s = sound(sound) for(var/mob/M in GLOB.player_list) if(!isnewplayer(M) && M.can_hear()) to_chat(M, announcement) if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS) - M << sound(sound) + SEND_SOUND(M, s) /proc/print_command_report(text = "", title = null, announce=TRUE) if(!title) @@ -55,6 +56,6 @@ to_chat(M, "[title]
[message]

") if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS) if(alert) - M << sound('sound/misc/notice1.ogg') + SEND_SOUND(M, sound('sound/misc/notice1.ogg')) else - M << sound('sound/misc/notice2.ogg') + SEND_SOUND(M, sound('sound/misc/notice2.ogg')) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index cd5d0c6af5..53691d122e 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -45,6 +45,9 @@ index = findtext(t, char, index+1) return t +/proc/sanitize_filename(t) + return sanitize_simple(t, list("\n"="", "\t"="", "/"="", "\\"="", "?"="", "%"="", "*"="", ":"="", "|"="", "\""="", "<"="", ">"="")) + //Runs byond's sanitization proc along-side sanitize_simple /proc/sanitize(t,list/repl_chars = null) return html_encode(sanitize_simple(t,repl_chars)) @@ -553,14 +556,14 @@ GLOBAL_LIST_INIT(binary, list("0","1")) var/list/tosend = list() tosend["data"] = finalized - log << json_encode(tosend) + WRITE_FILE(log, json_encode(tosend)) //Used for applying byonds text macros to strings that are loaded at runtime /proc/apply_text_macros(string) var/next_backslash = findtext(string, "\\") if(!next_backslash) return string - + var/leng = length(string) var/next_space = findtext(string, " ", next_backslash + 1) diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 36a81e90e2..7df96c3da2 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -537,3 +537,18 @@ if(!istype(the_matrix) || the_matrix.len != 20) return "#ffffffff" return rgb(the_matrix[1]*255, the_matrix[6]*255, the_matrix[11]*255, the_matrix[16]*255) + +/proc/type2parent(child) + var/string_type = "[child]" + var/last_slash = findlasttext(string_type, "/") + if(last_slash == 1) + switch(child) + if(/datum) + return null + if(/obj || /mob) + return /atom/movable + if(/area || /turf) + return /atom + else + return /datum + return text2path(copytext(string_type, 1, last_slash)) \ No newline at end of file diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index aab766f9e4..8cb34e23b5 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -289,7 +289,7 @@ Turf and target are separate in case you want to teleport some distance from a t var/list/pois = list() for(var/mob/M in mobs) if(skip_mindless && (!M.mind && !M.ckey)) - if(!isbot(M) && !istype(M, /mob/camera/)) + if(!isbot(M) && !istype(M, /mob/camera) && !ismegafauna(M)) continue if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins continue @@ -845,11 +845,11 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list( /obj/proc/atmosanalyzer_scan(datum/gas_mixture/air_contents, mob/user, obj/target = src) var/obj/icon = target - user.visible_message("[user] has used the analyzer on [bicon(icon)] [target].", "You use the analyzer on [bicon(icon)] [target].") + user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(src))] [target].", "You use the analyzer on [icon2html(icon, user)] [target].") var/pressure = air_contents.return_pressure() var/total_moles = air_contents.total_moles() - to_chat(user, "Results of analysis of [bicon(icon)] [target].") + to_chat(user, "Results of analysis of [icon2html(icon, user)] [target].") if(total_moles>0) to_chat(user, "Pressure: [round(pressure,0.1)] kPa") diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 964c956eca..a669f1b4f5 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -69,8 +69,6 @@ #error You need version 511 or higher #endif - #define SERVICE_CMD_PARAM_KEY "serviceCommsKey" - //Update this whenever the db schema changes //make sure you add an update to the schema_version stable in the db changelog #define DB_MAJOR_VERSION 3 diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index b944f32754..e1f1410837 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -205,7 +205,7 @@ or something covering your eyes." /obj/screen/alert/embeddedobject name = "Embedded Object" desc = "Something got lodged into your flesh and is causing major bleeding. It might fall out with time, but surgery is the safest way. \ -If you're feeling frisky, click yourself in help intent to pull the object out." +If you're feeling frisky, examine yourself and click the underlined item to pull the object out." icon_state = "embeddedobject" /obj/screen/alert/embeddedobject/Click() diff --git a/code/citadel/_cit_helpers.dm b/code/citadel/_cit_helpers.dm index db0626fa9c..e6dca1e369 100644 --- a/code/citadel/_cit_helpers.dm +++ b/code/citadel/_cit_helpers.dm @@ -53,6 +53,7 @@ GLOBAL_LIST_EMPTY(xeno_dorsal_list) //Genitals and Arousal Lists GLOBAL_LIST_EMPTY(cock_shapes_list)//global_lists.dm for the list initializations //Now also _DATASTRUCTURES globals.dm +GLOBAL_LIST_EMPTY(cock_shapes_icons) //Associated list for names->icon_states for cockshapes. GLOBAL_LIST_EMPTY(breasts_size_list) GLOBAL_LIST_EMPTY(breasts_shapes_list) GLOBAL_LIST_EMPTY(vagina_shapes_list) diff --git a/code/citadel/cit_arousal.dm b/code/citadel/cit_arousal.dm index cf47dab1da..6005758144 100644 --- a/code/citadel/cit_arousal.dm +++ b/code/citadel/cit_arousal.dm @@ -181,224 +181,364 @@ else to_chat(src, "You aren't aroused enough for that.") + +//These are various procs that we'll use later, split up for readability instead of having one, huge proc. +//For all of these, we assume the arguments given are proper and have been checked beforehand. +/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/G, mb_time = 30) //Masturbation, keep it gender-neutral + var/total_fluids = 0 + var/datum/reagents/fluid_source = null + + if(G.producing) //Can it produce its own fluids, such as breasts? + fluid_source = G.reagents + else + if(!G.linked_organ) + to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") + return + fluid_source = G.linked_organ.reagents + total_fluids = fluid_source.total_volume + if(mb_time) + src.visible_message("[src] starts to [G.masturbation_verb] [p_their()] [G.name].", \ + "You start to [G.masturbation_verb] your [G.name].", \ + "You start to [G.masturbation_verb] your [G.name].") + + if(do_after(src, mb_time, target = src)) + if(total_fluids > 5) + fluid_source.reaction(src.loc, TOUCH, 1, 0) + fluid_source.clear_reagents() + src.visible_message("[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!", \ + "You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].", \ + "You have relieved yourself.") + if(G.can_climax) + setArousalLoss(min_arousal) + + +/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes + var/total_fluids = 0 + var/datum/reagents/fluid_source = null + var/unable_to_come = FALSE + + if(G.producing) //Can it produce its own fluids, such as breasts? + fluid_source = G.reagents + total_fluids = fluid_source.total_volume + else + if(!G.linked_organ) + unable_to_come = TRUE + else + fluid_source = G.linked_organ.reagents + total_fluids = fluid_source.total_volume + + if(unable_to_come) + src.visible_message("[src] shudders, their [G.name] unable to cum.", \ + "Your [G.name] cannot cum, giving no relief.", \ + "Your [G.name] cannot cum, giving no relief.") + else + total_fluids = fluid_source.total_volume + if(mb_time) //as long as it's not instant, give a warning + src.visible_message("[src] looks like they're about to cum.", \ + "You feel yourself about to orgasm.", \ + "You feel yourself about to orgasm.") + if(do_after(src, mb_time, target = src)) + if(total_fluids > 5) + fluid_source.reaction(src.loc, TOUCH, 1, 0) + fluid_source.clear_reagents() + src.visible_message("[src] orgasms[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""], using [p_their()] [G.name]!", \ + "You climax[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""] with your [G.name].", \ + "You climax using your [G.name].") + if(G.can_climax) + setArousalLoss(min_arousal) + + +/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, mb_time = 30) //Used for climaxing with any living thing + var/total_fluids = 0 + var/datum/reagents/fluid_source = null + + if(G.producing) //Can it produce its own fluids, such as breasts? + fluid_source = G.reagents + else + if(!G.linked_organ) + to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") + return + fluid_source = G.linked_organ.reagents + total_fluids = fluid_source.total_volume + if(mb_time) //Skip warning if this is an instant climax. + src.visible_message("[src] is about to climax with [L]!", \ + "You're about to climax with [L]!", \ + "You're preparing to climax with someone!") + if(spillage) + if(do_after(src, mb_time, target = src) && in_range(src, L)) + fluid_source.trans_to(L, total_fluids*G.fluid_transfer_factor) + total_fluids -= total_fluids*G.fluid_transfer_factor + if(total_fluids > 5) + fluid_source.reaction(L.loc, TOUCH, 1, 0) + fluid_source.clear_reagents() + src.visible_message("[src] climaxes with [L][spillage ? ", overflowing and spilling":""], using [p_their()] [G.name]!", \ + "You orgasm with [L][spillage ? ", spilling out of them":""], using your [G.name].", \ + "You have climaxed with someone[spillage ? ", spilling out of them":""], using your [G.name].") + if(G.can_climax) + setArousalLoss(min_arousal) + else //knots and other non-spilling orgasms + if(do_after(src, mb_time, target = src) && in_range(src, L)) + fluid_source.trans_to(L, total_fluids) + total_fluids = 0 + src.visible_message("[src] climaxes with [L], [p_their()] [G.name] spilling nothing!", \ + "You ejaculate with [L], your [G.name] spilling nothing.", \ + "You have climaxed inside someone, your [G.name] spilling nothing.") + if(G.can_climax) + setArousalLoss(min_arousal) + + +/mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/G, obj/item/weapon/reagent_containers/container, mb_time = 30) //For beaker-filling, beware the bartender + var/total_fluids = 0 + var/datum/reagents/fluid_source = null + + if(G.producing) //Can it produce its own fluids, such as breasts? + fluid_source = G.reagents + else + if(!G.linked_organ) + to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") + return + fluid_source = G.linked_organ.reagents + total_fluids = fluid_source.total_volume + + //if(!container) //Something weird happened + // to_chat(src, "You need a container to do this!") + // return + + src.visible_message("[src] starts to [G.masturbation_verb] their [G.name] over [container].", \ + "You start to [G.masturbation_verb] your [G.name] over [container].", \ + "You start to [G.masturbation_verb] your [G.name] over something.") + if(do_after(src, mb_time, target = src) && in_range(src, container)) + fluid_source.trans_to(container, total_fluids) + src.visible_message("[src] uses [p_their()] [G.name] to fill [container]!", \ + "You used your [G.name] to fill [container].", \ + "You have relieved some pressure.") + if(G.can_climax) + setArousalLoss(min_arousal) + +/mob/living/carbon/human/proc/pick_masturbate_genitals() + var/obj/item/organ/genital/ret_organ + var/list/genitals_list = list() + var/list/worn_stuff = get_equipped_items() + + for(var/obj/item/organ/genital/G in internal_organs) + if(G.can_masturbate_with) //filter out what you can't masturbate with + if(G.is_exposed(worn_stuff)) //Nude or through_clothing + genitals_list += G + if(genitals_list.len) + ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list + return ret_organ + return null //error stuff + + +/mob/living/carbon/human/proc/pick_climax_genitals() + var/obj/item/organ/genital/ret_organ + var/list/genitals_list = list() + var/list/worn_stuff = get_equipped_items() + + for(var/obj/item/organ/genital/G in internal_organs) + if(G.can_climax) //filter out what you can't masturbate with + if(G.is_exposed(worn_stuff)) //Nude or through_clothing + genitals_list += G + if(genitals_list.len) + ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list + return ret_organ + return null //error stuff + + +/mob/living/carbon/human/proc/pick_partner() + var/list/partners = list() + if(src.pulling) + partners += src.pulling //Yes, even objects for now + if(src.pulledby) + partners += src.pulledby + //Now we got both of them, let's check if they're proper + for(var/I in partners) + if(isliving(I)) + if(iscarbon(I)) + var/mob/living/carbon/C = I + if(!C.exposed_genitals.len) //Nothing through_clothing + if(!C.is_groin_exposed()) //No pants undone + if(!C.is_chest_exposed()) //No chest exposed + partners -= I //Then not proper, remove them + else + partners -= I //No fucking objects + //NOW the list should only contain correct partners + if(!partners.len) + return null //No one left. + return input(src, "With whom?", "Sexual partner", null) in partners //pick one, default to null + +/mob/living/carbon/human/proc/pick_climax_container() + var/obj/item/weapon/reagent_containers/SC = null + var/list/containers_list = list() + + for(var/obj/item/weapon/reagent_containers/container in held_items) + if(container.is_open_container() || istype(container, /obj/item/weapon/reagent_containers/food/snacks)) + containers_list += container + + if(containers_list.len) + SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list + if(SC) + if(in_range(src, SC)) + return SC + return null //If nothing correct, give null. + + +//Here's the main proc itself /mob/living/carbon/human/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints if(mb_cd_timer > world.time) if(!forced_climax) //Don't spam the message to the victim if forced to come too fast to_chat(src, "You need to wait [round((mb_cd_timer - world.time)/(20))] seconds before you can do that again!") return mb_cd_timer = (world.time + mb_cd_length) - var/list/genitals_list = list() - var/obj/item/organ/genital/SG = null//originally selected_genital - var/list/containers_list = list() - var/obj/item/weapon/reagent_containers/SC = null - var/datum/reagents/fluid_source = null - var/into_container = 0 - var/free_hands = get_num_arms() //arms was only used to know if we had ANY at all - var/total_cum = 0 - var/finished = 0 - var/mb_time = 30 + + if(canbearoused && has_dna()) if(stat==2) to_chat(src, "You can't do that while dead!") return if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks - for(var/obj/item/organ/genital/G in internal_organs) - if(G.can_masturbate_with) //All capable genitals will orgasm with this - var/unable_to_come = FALSE - switch(G.type) - if(/obj/item/organ/genital/penis) - var/obj/item/organ/genital/penis/P = G - if(!P.linked_balls) - unable_to_come = TRUE - else - fluid_source = P.linked_balls.reagents + for(var/obj/item/organ/O in internal_organs) + if(istype(O, /obj/item/organ/genital)) + var/obj/item/organ/genital/G = O + if(!G.can_climax) //Skip things like wombs and testicles + continue + var/mob/living/partner + var/check_target + var/list/worn_stuff = get_equipped_items() + if(G.is_exposed(worn_stuff)) + if(src.pulling) //Are we pulling someone? Priority target, we can't be making option menus for this, has to be quick + if(isliving(src.pulling)) //Don't fuck objects + check_target = src.pulling + if(src.pulledby && !check_target) //prioritise pulled over pulledby + if(isliving(src.pulledby)) + check_target = src.pulledby + //Now we should have a partner, or else we have to come alone + if(check_target) + if(iscarbon(check_target)) //carbons can have clothes + var/mob/living/carbon/C = check_target + if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) //Are they naked enough? + partner = C + else //A cat is fine too + partner = check_target + if(partner) //Did they pass the clothing checks? + mob_climax_partner(G, partner, mb_time = 0) //Instant climax due to forced + continue //You've climaxed once with this organ, continue on + //not exposed OR if no partner was found while exposed, climax alone + mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms + //Now all genitals that could climax, have. + //Since this was a forced climax, we do not need to continue with the other stuff + return + //If we get here, then this is not a forced climax and we gotta check a few things. - if(/obj/item/organ/genital/vagina) - var/obj/item/organ/genital/vagina/V = G - if(!V.linked_womb) - unable_to_come = TRUE - else - fluid_source = V.linked_womb.reagents - else //Weird, undefined genitalia behaviour - unable_to_come = TRUE - - if(unable_to_come) - src.visible_message("[src] shudders, their [G.name] unable to cum.", \ - "Your [G.name] cannot cum, giving no relief.", \ - "Your [G.name] cannot cum, giving no relief.") - else - if(fluid_source) - total_cum = fluid_source.total_volume - src.visible_message("[src] looks like they're about to cum.", \ - "You feel yourself about to orgasm.", \ - "You feel yourself about to orgasm.") - if(do_after(src, mb_time, target = src)) - if(total_cum > 5) - fluid_source.reaction(src.loc, TOUCH, 1, 0) - fluid_source.clear_reagents() - fluid_source = null //cleanup so this can be used for the next genitalia - - src.visible_message("[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!", \ - "You're forced to cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""] with your [G].", \ - "Your [G] have been forced to climax.") - finished = 1 - if(finished) - setArousalLoss(min_arousal) - return //Do not proceed to masturbating if all genitals have been forced to orgasm. - if(stat==1) //Sleeping people can be forced chemically or with electrical stimulants, for example. + if(stat==1) //No sleep-masturbation, you're unconscious. to_chat(src, "You must be conscious to do that!") return - if(restrained()) - to_chat(src, "You can't do that while restrained!") - return - if(getArousalLoss() < 33)//flat number instead of percentage + if(getArousalLoss() < 33) //flat number instead of percentage to_chat(src, "You aren't aroused enough for that!") return - if(!is_groin_exposed()) - to_chat(src, "You need to undress, first!") - return - if(!free_hands) - to_chat(src, "You need at least one free arm.") - return - for(var/helditem in held_items)//how many hands are free - if(isobj(helditem)) - free_hands-- - if(free_hands <= 0) - to_chat(src, "You need at least one free hand.") - return - for(var/obj/item/organ/genital/G in internal_organs) - if(G.can_masturbate_with)//filter out what you can't masturbate with - genitals_list += G - if(genitals_list.len) - SG = input(src, "with what?", "Masturbate") as null|obj in genitals_list - if(SG) - for(var/obj/item/weapon/reagent_containers/container in held_items) - if(container.is_open_container() || istype(container, /obj/item/weapon/reagent_containers/food/snacks/pie)) - containers_list += container - if(containers_list.len) - SC = input(src, "Into or onto what?(Cancel for nowhere)", "Masturbate") as null|obj in containers_list - if(SC) - if(in_range(src, SC)) - into_container = 1 - SG.update() - switch(SG.type) - //Penis - if(/obj/item/organ/genital/penis) - var/obj/item/organ/genital/penis/P = SG - if(!P.linked_balls) - to_chat(src, "You need a pair of testicles to do this.") - return - fluid_source = P.linked_balls.reagents - total_cum = fluid_source.total_volume - if(into_container)//into a glass or beaker or whatever - src.visible_message("[src] starts [pick("jerking off","stroking")] their [SG.name] over [SC].", \ - "You start jerking off over [SC.name].", \ - "You start masturbating.") - if(do_after(src, mb_time, target = src) && in_range(src, SC)) - fluid_source.trans_to(SC, total_cum) - src.visible_message("[src] orgasms, [pick("cumming into", "emptying themself into")] [SC]!", \ - "You cum into [SC].", \ - "You have relieved yourself.") - finished = 1 - else //Not in a container - if(src.pulling) - if(iscarbon(src.pulling)) - var/mob/living/carbon/C = src.pulling - if(!C.is_groin_exposed()) - to_chat(src, "You must undress someone to climax inside them.") - return - if(isliving(src.pulling)) //Gotta be alive to fuck it, don't wanna have to code fucking objects that ain't containers... - var/mob/living/partner = src.pulling - src.visible_message("[src] is about to climax inside [partner]!", \ - "You're about to climax inside [partner]!", \ - "You're preparing to climax inside someone!") - switch(grab_state) - if(GRAB_PASSIVE) - if(do_after(src, mb_time, target = src) && in_range(src, partner)) - var/spillage = 0.5 //Leaks a bit on passive grab - var/did_spill = FALSE - fluid_source.trans_to(partner, total_cum*(1-spillage)) - total_cum = total_cum*spillage - if(total_cum > 5) - fluid_source.reaction(partner.loc, TOUCH, 1, 0) - did_spill = TRUE - fluid_source.clear_reagents() + //Ok, now we check what they want to do. + var/choice = input(src, "Select sexual activity", "Sexual activity:") in list("Masturbate", "Climax alone", "Climax with partner", "Fill container") - src.visible_message("[src] ejaculates inside [partner][did_spill ? ", overflowing and spilling":""]!", \ - "You ejaculate inside [partner][did_spill ? ", spilling out of them":""].", \ - "You have climaxed inside someone[did_spill ? ", spilling out of them":""].") - finished = 1 - else //Aggressive or higher - if(do_after(src, mb_time, target = src) && in_range(src, partner)) - var/spillage = 0.0 //Leakproofing seals - fluid_source.trans_to(partner, total_cum*(1-spillage)) - total_cum = total_cum*spillage - if(total_cum > 5) - fluid_source.reaction(partner.loc, TOUCH, 1, 0) - fluid_source.clear_reagents() + switch(choice) + if("Masturbate") + if(restrained(TRUE)) //TRUE ignores grabs + to_chat(src, "You can't do that while restrained!") + return + var/free_hands = get_num_arms() + if(!free_hands) + to_chat(src, "You need at least one free arm.") + return + for(var/helditem in held_items)//how many hands are free + if(isobj(helditem)) + free_hands-- + if(free_hands <= 0) + to_chat(src, "You're holding too many things.") + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_masturbate_genitals() + if(picked_organ) + mob_masturbate(picked_organ) + return + else //They either lack organs that can masturbate, or they didn't pick one. + to_chat(src, "You cannot masturbate without choosing genitals.") + return - src.visible_message("[src] ejaculates inside [partner], spilling nothing!", \ - "You ejaculate inside [partner], spilling nothing.", \ - "You have climaxed inside someone, spilling nothing.") - finished = 1 - //Don't care, not coding you fucking a unanchored girder - else //No pulling, or pulling non-living things - src.visible_message("[src] starts [pick("jerking off","stroking")] their [SG].", \ - "You start masturbating.", \ - "You start masturbating.") - if(do_after(src, mb_time, target = src)) - if(total_cum > 5) - fluid_source.reaction(src.loc, TOUCH, 1, 0) - fluid_source.clear_reagents() + if("Climax alone") + if(restrained(TRUE)) //TRUE ignores grabs + to_chat(src, "You can't do that while restrained!") + return + var/free_hands = get_num_arms() + if(!free_hands) + to_chat(src, "You need at least one free arm.") + return + for(var/helditem in held_items)//how many hands are free + if(isobj(helditem)) + free_hands-- + if(free_hands <= 0) + to_chat(src, "You're holding too many things.") + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() + if(picked_organ) + mob_climax_outside(picked_organ) + return + else //They either lack organs that can masturbate, or they didn't pick one. + to_chat(src, "You cannot climax without choosing genitals.") + return - src.visible_message("[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!", \ - "You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].", \ - "You have relieved yourself.") - finished = 1 + if("Climax with partner") + //We need no hands, we can be restrained and so on, so let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() + if(picked_organ) + var/mob/living/partner = pick_partner() //Get someone + if(partner) + var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No") + if(spillage == "Yes") + mob_climax_partner(picked_organ, partner, TRUE) + else + mob_climax_partner(picked_organ, partner, FALSE) + return + else + to_chat(src, "You cannot do this alone.") + return + else //They either lack organs that can masturbate, or they didn't pick one. + to_chat(src, "You cannot climax without choosing genitals.") + return - if(/obj/item/organ/genital/vagina) - var/obj/item/organ/genital/vagina/V = SG - if(!V.linked_womb) - to_chat(src, "You need a womb to do this.") - return - fluid_source = V.linked_womb.reagents - total_cum = fluid_source.total_volume - if(into_container)//into a glass or beaker or whatever - src.visible_message("[src] starts fingering their [SG.name] over [SC].", \ - "You start fingering over [SC.name].", \ - "You start masturbating.") - if(do_after(src, mb_time, target = src) && in_range(src, SC)) - fluid_source.trans_to(SC, total_cum) - src.visible_message("[src] orgasms, [pick("cumming into", "emptying themself into")] [SC]!", \ - "You cum into [SC].", \ - "You have relieved yourself.") - finished = 1 - - else//not into a container - src.visible_message("[src] starts fingering their vagina.", \ - "You start fingering your vagina.", \ - "You start masturbating.") - if(do_after(src, mb_time, target = src)) - if(total_cum > 5) - fluid_source.reaction(src.loc, TOUCH, 1, 0) - fluid_source.clear_reagents() - src.visible_message("[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!", \ - "You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].", \ - "You have relieved yourself.") - finished = 1 - - else//backup message, just in case - src.visible_message("[src] starts masturbating!", \ - "You start masturbating.") - if(do_after(src, mb_time, target = src)) - src.visible_message("[src] [pick("relieves themself!", "shudders and moans in orgasm!")]", \ - "You have relieved yourself.") - finished = 1 - if(finished) - setArousalLoss(min_arousal) - - else - to_chat(src, "You have no genitals!") - return + if("Fill container") + //We'll need hands and no restraints. + if(restrained(TRUE)) //TRUE ignores grabs + to_chat(src, "You can't do that while restrained!") + return + var/free_hands = get_num_arms() + if(!free_hands) + to_chat(src, "You need at least one free arm.") + return + for(var/helditem in held_items)//how many hands are free + if(isobj(helditem)) + free_hands-- + if(free_hands <= 0) + to_chat(src, "You're holding too many things.") + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids. + if(picked_organ) + //Good, got an organ, time to pick a container + var/obj/item/weapon/reagent_containers/fluid_container = pick_climax_container() + if(fluid_container) + mob_fill_container(picked_organ, fluid_container) + return + else + to_chat(src, "You cannot do this without anything to fill.") + return + else //They either lack organs that can climax, or they didn't pick one. + to_chat(src, "You cannot fill anything without choosing genitals.") + return + else //Somehow another option was taken, maybe something interrupted the selection or it was cancelled + return //Just end it in that case. diff --git a/code/citadel/cit_reagents.dm b/code/citadel/cit_reagents.dm index 428729d30f..4a0e91479b 100644 --- a/code/citadel/cit_reagents.dm +++ b/code/citadel/cit_reagents.dm @@ -153,14 +153,13 @@ if(prob(33)) if(M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna()) var/mob/living/carbon/human/H = M - to_chat(H, "Your libido is going haywire!") - H.mob_climax(forced_climax=TRUE) + if(prob(50)) //Less spam + to_chat(H, "Your libido is going haywire!") + H.mob_climax(forced_climax=TRUE) if(M.min_arousal < 50) M.min_arousal += 1 - to_chat(M, "You're having a hard time thinkin about things other than sex!") if(M.min_arousal < M.max_arousal) M.min_arousal += 1 - to_chat(M, "You feel your libido permanently increasing.") M.adjustArousalLoss(2) ..() @@ -197,10 +196,8 @@ if(prob(33)) if(M.min_arousal > 0) M.min_arousal -= 1 - to_chat(M, "You feel your libido returning to more normal levels.") if(M.min_arousal > 50) M.min_arousal -= 1 - to_chat(M, "You feel like your overactive libido is calming down.") M.adjustArousalLoss(-2) ..() diff --git a/code/citadel/icons/taur_penis_onmob.dmi b/code/citadel/icons/taur_penis_onmob.dmi new file mode 100644 index 0000000000..3debbd0047 Binary files /dev/null and b/code/citadel/icons/taur_penis_onmob.dmi differ diff --git a/code/citadel/organs/breasts.dm b/code/citadel/organs/breasts.dm index ce45b88cfb..dda5e248ee 100644 --- a/code/citadel/organs/breasts.dm +++ b/code/citadel/organs/breasts.dm @@ -1,5 +1,5 @@ /obj/item/organ/genital/breasts - name = "Breasts" + name = "breasts" desc = "Female milk producing organs." icon_state = "breasts" icon = 'code/citadel/icons/breasts.dmi' @@ -11,6 +11,10 @@ var/amount = 2 producing = TRUE shape = "pair" + can_masturbate_with = TRUE + masturbation_verb = "massage" + can_climax = TRUE + fluid_transfer_factor =0.5 /obj/item/organ/genital/breasts/Initialize() . = ..() @@ -54,4 +58,10 @@ var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need. color = "#[skintone2hex(H.skin_tone)]" else - color = "#[owner.dna.features["breasts_color"]]" \ No newline at end of file + color = "#[owner.dna.features["breasts_color"]]" + +/obj/item/organ/genital/breasts/is_exposed() + . = ..() + if(.) + return TRUE + return owner.is_chest_exposed() \ No newline at end of file diff --git a/code/citadel/organs/eggsack.dm b/code/citadel/organs/eggsack.dm index 718a353b87..1486310d61 100644 --- a/code/citadel/organs/eggsack.dm +++ b/code/citadel/organs/eggsack.dm @@ -7,7 +7,7 @@ slot = "testicles" color = null //don't use the /genital color since it already is colored w_class = 3 - var/internal = TRUE + internal = TRUE var/egg_girth = EGG_GIRTH_DEF var/cum_mult = CUM_RATE_MULT var/cum_rate = CUM_RATE diff --git a/code/citadel/organs/genitals.dm b/code/citadel/organs/genitals.dm index c129d8e8fa..1f46778aaf 100644 --- a/code/citadel/organs/genitals.dm +++ b/code/citadel/organs/genitals.dm @@ -3,7 +3,10 @@ var/shape = "human" var/sensitivity = 1 var/list/genital_flags = list() - var/can_masturbate_with = 0 + var/can_masturbate_with = FALSE + var/masturbation_verb = "masturbate" + var/can_climax = FALSE + var/fluid_transfer_factor = 0.0 //How much would a partner get in them if they climax using this? var/size = 2 //can vary between num or text, just used in icon_state strings var/fluid_id = null var/fluid_max_volume = 50 @@ -13,6 +16,9 @@ var/producing = FALSE var/aroused_state = FALSE //Boolean used in icon_state strings var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons. + var/obj/item/organ/genital/linked_organ + var/through_clothes = FALSE + var/internal = FALSE /obj/item/organ/genital/Initialize() . = ..() @@ -34,6 +40,52 @@ update_appearance() update_link() +//exposure and through-clothing code +/mob/living/carbon + var/list/exposed_genitals = list() //Keeping track of them so we don't have to iterate through every genitalia and see if exposed + +/obj/item/organ/genital/proc/is_exposed() + if(!owner) + return FALSE + if(internal) + return FALSE + if(through_clothes) + return TRUE + +/obj/item/organ/genital/proc/toggle_through_clothes() + if(through_clothes) + through_clothes = FALSE + owner.exposed_genitals -= src + else + through_clothes = TRUE + owner.exposed_genitals += src + if(ishuman(owner)) //recast to use update genitals proc + var/mob/living/carbon/human/H = owner + H.update_genitals() + +/mob/living/carbon/verb/toggle_genitals() + set category = "IC" + set name = "Expose/Hide genitals" + set desc = "Allows you to toggle which genitals should show through clothes or not." + + var/list/genital_list = list() + for(var/obj/item/organ/O in internal_organs) + if(istype(O, /obj/item/organ/genital)) + var/obj/item/organ/genital/G = O + if(!G.internal) + genital_list += G + if(!genital_list.len) //There is nothing to expose + return + //Full list of exposable genitals created + var/obj/item/organ/genital/picked_organ + picked_organ = input(src, "Expose/Hide genitals", "Choose which genitalia to expose/hide", null) in genital_list + if(picked_organ) + picked_organ.toggle_through_clothes() + return + + + + /obj/item/organ/genital/proc/update_size() /obj/item/organ/genital/proc/update_appearance() @@ -41,6 +93,9 @@ /obj/item/organ/genital/proc/update_link() /obj/item/organ/genital/proc/remove_ref() + if(linked_organ) + linked_organ.linked_organ = null + linked_organ = null /obj/item/organ/genital/Insert(mob/living/carbon/M, special = 0) ..() @@ -58,21 +113,21 @@ var/obj/item/organ/genital/GtoClean for(GtoClean in internal_organs) qdel(GtoClean) - - if(dna.features["has_cock"]) - give_penis() - if(dna.features["has_balls"]) - give_balls() - else if(dna.features["has_ovi"]) - give_ovipositor() - if(dna.features["has_eggsack"]) - give_eggsack() + //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in. if(dna.features["has_breasts"]) give_breasts() if(dna.features["has_vag"]) give_vagina() - if(dna.features["has_womb"]) - give_womb() + if(dna.features["has_womb"]) + give_womb() + if(dna.features["has_balls"]) + give_balls() + if(dna.features["has_cock"]) + give_penis() + if(dna.features["has_ovi"]) + give_ovipositor() + if(dna.features["has_eggsack"]) + give_eggsack() /mob/living/carbon/human/proc/give_penis() if(!dna) @@ -208,17 +263,15 @@ if(H.disabilities & HUSK) return //start scanning for genitals - var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again - if(H.is_groin_exposed(worn_stuff)) - //ORDER is important here. Vaginas first, theoretical testes after, and penis LAST. - //The latter is always drawn on top of the former. - if(H.has_vagina()) - genitals_to_add += H.getorganslot("vagina") - if(H.has_penis()) - genitals_to_add += H.getorganslot("penis") - if(H.is_chest_exposed(worn_stuff)) - if(H.has_breasts()) - genitals_to_add += H.getorganslot("breasts") + //var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again + + for(var/obj/item/organ/O in H.internal_organs) + if(istype(O, /obj/item/organ/genital)) + var/obj/item/organ/genital/G = O + if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes + genitals_to_add += H.getorganslot(G.slot) + //Now we added all genitals that aren't internal and should be rendered + var/image/I //start applying overlays for(var/layer in relevant_layers) @@ -243,8 +296,10 @@ G.aroused_state = FALSE icon_string = "[G.slot]_[S.icon_state]_[size]_[G.aroused_state]_[layertext]" I = image("icon" = S.icon, "icon_state" = icon_string, "layer" =- layer) + if(S.center) I = center_image(I,S.dimension_x,S.dimension_y) + if(use_skintones && H.dna.features["genitals_use_skintone"]) I.color = "#[skintone2hex(H.skin_tone)]" else diff --git a/code/citadel/organs/genitals_sprite_accessories.dm b/code/citadel/organs/genitals_sprite_accessories.dm index 586be3a095..710bab787c 100644 --- a/code/citadel/organs/genitals_sprite_accessories.dm +++ b/code/citadel/organs/genitals_sprite_accessories.dm @@ -31,6 +31,33 @@ icon_state = "tapered" name = "Tapered" +//////////////////////// +// Taur cocks go here // +//////////////////////// +/datum/sprite_accessory/penis/taur_flared + icon = 'code/citadel/icons/taur_penis_onmob.dmi' //Needed larger width + icon_state = "flared" + name = "Taur, Flared" + center = TRUE //Center the image 'cause 2-tile wide. + dimension_x = 64 + +/datum/sprite_accessory/penis/taur_knotted + icon = 'code/citadel/icons/taur_penis_onmob.dmi' //Needed larger width + icon_state = "knotted" + name = "Taur, Knotted" + center = TRUE //Center the image 'cause 2-tile wide. + dimension_x = 64 + +/datum/sprite_accessory/penis/taur_tapered + icon = 'code/citadel/icons/taur_penis_onmob.dmi' //Needed larger width + icon_state = "tapered" + name = "Taur, Tapered" + center = TRUE //Center the image 'cause 2-tile wide. + dimension_x = 64 + + + + //Vaginas /datum/sprite_accessory/vagina icon = 'code/citadel/icons/vagina_onmob.dmi' diff --git a/code/citadel/organs/penis.dm b/code/citadel/organs/penis.dm index d687b3e76a..7348e8c969 100644 --- a/code/citadel/organs/penis.dm +++ b/code/citadel/organs/penis.dm @@ -1,21 +1,23 @@ /obj/item/organ/genital/penis - name = "Penis" - desc = "A male reproductive organ." - icon_state = "penis" - icon = 'code/citadel/icons/penis.dmi' - zone = "groin" - slot = "penis" - w_class = 3 - can_masturbate_with = 1 - size = 2 //arbitrary value derived from length and girth for sprites. - var/length = 6 //inches + name = "penis" + desc = "A male reproductive organ." + icon_state = "penis" + icon = 'code/citadel/icons/penis.dmi' + zone = "groin" + slot = "penis" + w_class = 3 + can_masturbate_with = TRUE + masturbation_verb = "stroke" + can_climax = TRUE + fluid_transfer_factor = 0.5 + size = 2 //arbitrary value derived from length and girth for sprites. + var/length = 6 //inches var/cached_length //used to detect a change in length - var/girth = 0 - var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm - var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF - var/list/dickflags = list() - var/list/knotted_types = list("knotted", "barbknot") - var/obj/item/organ/genital/testicles/linked_balls + var/girth = 0 + var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm + var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF + var/list/dickflags = list() + var/list/knotted_types = list("knotted", "barbknot") /obj/item/organ/genital/penis/update_size() if(length == cached_length) @@ -35,7 +37,7 @@ cached_length = length /obj/item/organ/genital/penis/update_appearance() - var/string = "penis_[lowertext(shape)]_[size]" + var/string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]" icon_state = sanitize_text(string) var/lowershape = lowertext(shape) if(lowershape in knotted_types) @@ -55,15 +57,16 @@ /obj/item/organ/genital/penis/update_link() if(owner) - linked_balls = (owner.getorganslot("testicles")) - if(linked_balls) - linked_balls.linked_penis = src + linked_organ = (owner.getorganslot("testicles")) + if(linked_organ) + linked_organ.linked_organ = src else - if(linked_balls) - linked_balls.linked_penis = null - linked_balls = null + if(linked_organ) + linked_organ.linked_organ = null + linked_organ = null -/obj/item/organ/genital/penis/remove_ref() - if(linked_balls) - linked_balls.linked_penis = null - linked_balls = null +/obj/item/organ/genital/penis/is_exposed() + . = ..() + if(.) + return TRUE + return owner.is_groin_exposed() \ No newline at end of file diff --git a/code/citadel/organs/testicles.dm b/code/citadel/organs/testicles.dm index a759aeab52..bb3ade6048 100644 --- a/code/citadel/organs/testicles.dm +++ b/code/citadel/organs/testicles.dm @@ -1,18 +1,17 @@ /obj/item/organ/genital/testicles - name = "Testicles" + name = "testicles" desc = "A male reproductive organ." icon_state = "testicles" icon = 'code/citadel/icons/penis.dmi' zone = "groin" slot = "testicles" w_class = 3 - var/internal = FALSE + internal = TRUE size = BALLS_SIZE_DEF var/sack_size = BALLS_SACK_SIZE_DEF fluid_id = "semen" producing = TRUE var/sent_full_message = 1 //defaults to 1 since they're full to start - var/obj/item/organ/genital/penis/linked_penis /obj/item/organ/genital/testicles/Initialize() . = ..() @@ -33,20 +32,20 @@ return FALSE sent_full_message = 0 update_link() - if(!linked_penis) + if(!linked_organ) return FALSE reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate))//generate the cum /obj/item/organ/genital/testicles/update_link() if(owner && !QDELETED(src)) - linked_penis = (owner.getorganslot("penis")) - if(linked_penis) - linked_penis.linked_balls = src + linked_organ = (owner.getorganslot("penis")) + if(linked_organ) + linked_organ.linked_organ = src else - if(linked_penis) - linked_penis.linked_balls = null - linked_penis = null + if(linked_organ) + linked_organ.linked_organ = null + linked_organ = null /obj/item/organ/genital/testicles/proc/send_full_message(msg = "Your balls finally feel full, again.") if(owner && istext(msg)) diff --git a/code/citadel/organs/vagina.dm b/code/citadel/organs/vagina.dm index fa1f00bda2..f170ced9b6 100644 --- a/code/citadel/organs/vagina.dm +++ b/code/citadel/organs/vagina.dm @@ -1,12 +1,15 @@ /obj/item/organ/genital/vagina - name = "Vagina" + name = "vagina" desc = "A female reproductive organ." icon = 'code/citadel/icons/vagina.dmi' icon_state = "vagina" zone = "groin" slot = "vagina" size = 1 //There is only 1 size right now - can_masturbate_with = 1 + can_masturbate_with = TRUE + masturbation_verb = "finger" + can_climax = TRUE + fluid_transfer_factor = 0.1 //Yes, some amount is exposed to you, go get your AIDS w_class = 3 var/cap_length = 8//D E P T H (cap = capacity) var/cap_girth = 12 @@ -15,7 +18,6 @@ var/clit_diam = 0.25 var/clit_len = 0.25 var/list/vag_types = list("tentacle", "dentata", "hairy") - var/obj/item/organ/genital/womb/linked_womb /obj/item/organ/genital/vagina/update_appearance() @@ -56,15 +58,16 @@ /obj/item/organ/genital/vagina/update_link() if(owner) - linked_womb = (owner.getorganslot("womb")) - if(linked_womb) - linked_womb.linked_vag = src + linked_organ = (owner.getorganslot("womb")) + if(linked_organ) + linked_organ.linked_organ = src else - if(linked_womb) - linked_womb.linked_vag = null - linked_womb = null + if(linked_organ) + linked_organ.linked_organ = null + linked_organ = null -/obj/item/organ/genital/vagina/remove_ref() - if(linked_womb) - linked_womb.linked_vag = null - linked_womb = null +/obj/item/organ/genital/vagina/is_exposed() + . = ..() + if(.) + return TRUE + return owner.is_groin_exposed() \ No newline at end of file diff --git a/code/citadel/organs/womb.dm b/code/citadel/organs/womb.dm index 3ebe5c2f98..433f005623 100644 --- a/code/citadel/organs/womb.dm +++ b/code/citadel/organs/womb.dm @@ -1,15 +1,15 @@ /obj/item/organ/genital/womb - name = "Womb" + name = "womb" desc = "A female reproductive organ." icon = 'code/citadel/icons/vagina.dmi' icon_state = "womb" zone = "groin" slot = "womb" w_class = 3 - var/internal = FALSE + internal = TRUE fluid_id = "femcum" producing = TRUE - var/obj/item/organ/genital/vagina/linked_vag + /obj/item/organ/genital/womb/Initialize() . = ..() @@ -24,25 +24,20 @@ /obj/item/organ/genital/womb/proc/generate_femcum() reagents.maximum_volume = fluid_max_volume update_link() - if(!linked_vag) + if(!linked_organ) return FALSE reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate))//generate the cum /obj/item/organ/genital/womb/update_link() if(owner) - linked_vag = (owner.getorganslot("vagina")) - if(linked_vag) - linked_vag.linked_womb = src + linked_organ = (owner.getorganslot("vagina")) + if(linked_organ) + linked_organ.linked_organ = src else - if(linked_vag) - linked_vag.linked_womb = null - linked_vag = null - -/obj/item/organ/genital/womb/remove_ref() - if(linked_vag) - linked_vag.linked_womb = null - linked_vag = null + if(linked_organ) + linked_organ.linked_organ = null + linked_organ = null /obj/item/organ/genital/womb/Destroy() return ..() diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index c32c481291..abf2c1f937 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -275,7 +275,7 @@ if(M.config_tag) if(!(M.config_tag in modes)) // ensure each mode is added only once - GLOB.config_error_log << "Adding game mode [M.name] ([M.config_tag]) to configuration." + WRITE_FILE(GLOB.config_error_log, "Adding game mode [M.name] ([M.config_tag]) to configuration.") modes += M.config_tag mode_names[M.config_tag] = M.name probabilities[M.config_tag] = M.probability @@ -548,7 +548,7 @@ if("irc_announce_new_game") irc_announce_new_game = TRUE else - GLOB.config_error_log << "Unknown setting in configuration: '[name]'" + WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'") else if(type == "game_options") switch(name) @@ -611,13 +611,13 @@ if(mode_name in modes) continuous[mode_name] = 1 else - GLOB.config_error_log << "Unknown continuous configuration definition: [mode_name]." + WRITE_FILE(GLOB.config_error_log, "Unknown continuous configuration definition: [mode_name].") if("midround_antag") var/mode_name = lowertext(value) if(mode_name in modes) midround_antag[mode_name] = 1 else - GLOB.config_error_log << "Unknown midround antagonist configuration definition: [mode_name]." + WRITE_FILE(GLOB.config_error_log, "Unknown midround antagonist configuration definition: [mode_name].") if("midround_antag_time_check") midround_antag_time_check = text2num(value) if("midround_antag_life_check") @@ -633,9 +633,9 @@ if(mode_name in modes) min_pop[mode_name] = text2num(mode_value) else - GLOB.config_error_log << "Unknown minimum population configuration definition: [mode_name]." + WRITE_FILE(GLOB.config_error_log, "Unknown minimum population configuration definition: [mode_name].") else - GLOB.config_error_log << "Incorrect minimum population configuration definition: [mode_name] [mode_value]." + WRITE_FILE(GLOB.config_error_log, "Incorrect minimum population configuration definition: [mode_name] [mode_value].") if("max_pop") var/pop_pos = findtext(value, " ") var/mode_name = null @@ -647,9 +647,9 @@ if(mode_name in modes) max_pop[mode_name] = text2num(mode_value) else - GLOB.config_error_log << "Unknown maximum population configuration definition: [mode_name]." + WRITE_FILE(GLOB.config_error_log, "Unknown maximum population configuration definition: [mode_name].") else - GLOB.config_error_log << "Incorrect maximum population configuration definition: [mode_name] [mode_value]." + WRITE_FILE(GLOB.config_error_log, "Incorrect maximum population configuration definition: [mode_name] [mode_value].") if("shuttle_refuel_delay") shuttle_refuel_delay = text2num(value) if("show_game_type_odds") @@ -677,9 +677,9 @@ if(prob_name in modes) probabilities[prob_name] = text2num(prob_value) else - GLOB.config_error_log << "Unknown game mode probability configuration definition: [prob_name]." + WRITE_FILE(GLOB.config_error_log, "Unknown game mode probability configuration definition: [prob_name].") else - GLOB.config_error_log << "Incorrect probability configuration definition: [prob_name] [prob_value]." + WRITE_FILE(GLOB.config_error_log, "Incorrect probability configuration definition: [prob_name] [prob_value].") if("protect_roles_from_antagonist") protect_roles_from_antagonist = 1 @@ -726,7 +726,7 @@ // Value is in the form "LAWID,NUMBER" var/list/L = splittext(value, ",") if(L.len != 2) - GLOB.config_error_log << "Invalid LAW_WEIGHT: " + t + WRITE_FILE(GLOB.config_error_log, "Invalid LAW_WEIGHT: " + t) continue var/lawid = L[1] var/weight = text2num(L[2]) @@ -781,7 +781,7 @@ if("mice_roundstart") mice_roundstart = text2num(value) else - GLOB.config_error_log << "Unknown setting in configuration: '[name]'" + WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'") else if(type == "policies") policies[name] = value @@ -839,7 +839,7 @@ if ("disabled") currentmap = null else - GLOB.config_error_log << "Unknown command in map vote config: '[command]'" + WRITE_FILE(GLOB.config_error_log, "Unknown command in map vote config: '[command]'") /datum/configuration/proc/loadsql(filename) @@ -883,7 +883,7 @@ if("feedback_tableprefix") global.sqlfdbktableprefix = value else - GLOB.config_error_log << "Unknown setting in configuration: '[name]'" + WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'") /datum/configuration/proc/pick_mode(mode_name) // I wish I didn't have to instance the game modes in order to look up diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 607b142c59..fd27c9424f 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -3,12 +3,15 @@ SUBSYSTEM_DEF(assets) init_order = INIT_ORDER_ASSETS flags = SS_NO_FIRE var/list/cache = list() + var/list/preload = list() /datum/controller/subsystem/assets/Initialize(timeofday) for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple)) var/datum/asset/A = new type() A.register() + preload = cache.Copy() //don't preload assets generated during the round + for(var/client/C in GLOB.clients) - addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, cache, FALSE), 10) + addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, preload, FALSE), 10) ..() diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index afa77b0207..3344afcaaa 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -250,7 +250,7 @@ SUBSYSTEM_DEF(blackbox) return 0 return value -/datum/feedback_variable/proc/get_variable() +/datum/feedback_variable/proc/get_variable() return variable /datum/feedback_variable/proc/set_details(text) @@ -260,12 +260,12 @@ SUBSYSTEM_DEF(blackbox) /datum/feedback_variable/proc/add_details(text) if (istext(text)) if (!details) - details = text + details = "\"[text]\"" else - details += " [text]" + details += " | \"[text]\"" -/datum/feedback_variable/proc/get_details() +/datum/feedback_variable/proc/get_details() return details /datum/feedback_variable/proc/get_parsed() - return list(variable,value,details) + return list(variable,value,details) \ No newline at end of file diff --git a/code/controllers/subsystem/pai.dm b/code/controllers/subsystem/pai.dm index e5e83c85fc..2a1a04e21d 100644 --- a/code/controllers/subsystem/pai.dm +++ b/code/controllers/subsystem/pai.dm @@ -149,7 +149,6 @@ SUBSYSTEM_DEF(pai) continue if(!(ROLE_PAI in G.client.prefs.be_special)) continue - //G << 'sound/misc/server-ready.ogg' //Alerting them to their consideration to_chat(G, "[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.") addtimer(CALLBACK(src, .proc/spam_again), spam_delay) var/list/available = list() diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm index f4eebe95be..a0dc7c526d 100644 --- a/code/controllers/subsystem/persistence.dm +++ b/code/controllers/subsystem/persistence.dm @@ -49,7 +49,7 @@ SUBSYSTEM_DEF(persistence) satchel_string = pick_n_take(expanded_old_satchels) old_secret_satchels = jointext(expanded_old_satchels,"#") - secret_satchels[SSmapping.config.map_name] << old_secret_satchels + WRITE_FILE(secret_satchels[SSmapping.config.map_name], old_secret_satchels) var/list/chosen_satchel = splittext(satchel_string,"|") if(!chosen_satchel || isemptylist(chosen_satchel) || chosen_satchel.len != 3) //Malformed @@ -171,7 +171,7 @@ SUBSYSTEM_DEF(persistence) if(isemptylist(savable_obj)) continue old_secret_satchels += "[F.x]|[F.y]|[pick(savable_obj)]#" - secret_satchels[SSmapping.config.map_name] << old_secret_satchels + WRITE_FILE(secret_satchels[SSmapping.config.map_name], old_secret_satchels) /datum/controller/subsystem/persistence/proc/CollectChiselMessages() var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav") @@ -181,14 +181,14 @@ SUBSYSTEM_DEF(persistence) log_world("Saved [saved_messages.len] engraved messages on map [SSmapping.config.map_name]") - chisel_messages_sav[SSmapping.config.map_name] << json_encode(saved_messages) + WRITE_FILE(chisel_messages_sav[SSmapping.config.map_name], json_encode(saved_messages)) /datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M) saved_messages += list(M.pack()) // dm eats one list /datum/controller/subsystem/persistence/proc/CollectTrophies() - trophy_sav << json_encode(saved_trophies) + WRITE_FILE(trophy_sav, json_encode(saved_trophies)) /datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T) if(!T.added_roundstart && T.showpiece) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 8aff552076..d88d788d37 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -101,8 +101,6 @@ SUBSYSTEM_DEF(shuttle) T.color = "#00ffff" #endif - //world.log << "[transit_turfs.len] transit turfs registered" - /datum/controller/subsystem/shuttle/fire() for(var/thing in mobile) if(!thing) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index d897b290d4..e07d2db001 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -225,7 +225,7 @@ SUBSYSTEM_DEF(ticker) round_start_time = world.time to_chat(world, "Welcome to [station_name()], enjoy your stay!") - world << sound('sound/ai/welcome.ogg') + SEND_SOUND(world, sound('sound/ai/welcome.ogg')) current_state = GAME_STATE_PLAYING Master.SetRunLevel(RUNLEVEL_GAME) @@ -300,7 +300,7 @@ SUBSYSTEM_DEF(ticker) if("nuclear emergency") //Nuke wasn't on station when it blew up flick("intro_nuke",cinematic) sleep(35) - world << sound('sound/effects/explosionfar.ogg') + SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg')) station_explosion_detonation(bomb) flick("station_intact_fade_red",cinematic) cinematic.icon_state = "summary_nukefail" @@ -308,12 +308,12 @@ SUBSYSTEM_DEF(ticker) cinematic.icon_state = null flick("intro_cult",cinematic) sleep(25) - world << sound('sound/magic/enter_blood.ogg') + SEND_SOUND(world, sound('sound/magic/enter_blood.ogg')) sleep(28) - world << sound('sound/machines/terminal_off.ogg') + SEND_SOUND(world, sound('sound/machines/terminal_off.ogg')) sleep(20) flick("station_corrupted",cinematic) - world << sound('sound/effects/ghost.ogg') + SEND_SOUND(world, sound('sound/effects/ghost.ogg')) actually_blew_up = FALSE if("gang war") //Gang Domination (just show the override screen) cinematic.icon_state = "intro_malf_still" @@ -323,19 +323,19 @@ SUBSYSTEM_DEF(ticker) if("fake") //The round isn't over, we're just freaking people out for fun flick("intro_nuke",cinematic) sleep(35) - world << sound('sound/items/bikehorn.ogg') + SEND_SOUND(world, sound('sound/items/bikehorn.ogg')) flick("summary_selfdes",cinematic) actually_blew_up = FALSE else flick("intro_nuke",cinematic) sleep(35) - world << sound('sound/effects/explosionfar.ogg') + SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg')) station_explosion_detonation(bomb) if(NUKE_MISS_STATION || NUKE_SYNDICATE_BASE) //nuke was nowhere nearby //TODO: a really distant explosion animation sleep(50) - world << sound('sound/effects/explosionfar.ogg') + SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg')) station_explosion_detonation(bomb) actually_blew_up = station_missed == NUKE_SYNDICATE_BASE //don't kill everyone on station if it detonated off station else //station was destroyed @@ -346,42 +346,42 @@ SUBSYSTEM_DEF(ticker) flick("intro_nuke",cinematic) sleep(35) flick("station_explode_fade_red",cinematic) - world << sound('sound/effects/explosionfar.ogg') + SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg')) station_explosion_detonation(bomb) cinematic.icon_state = "summary_nukewin" if("AI malfunction") //Malf (screen,explosion,summary) flick("intro_malf",cinematic) sleep(76) flick("station_explode_fade_red",cinematic) - world << sound('sound/effects/explosionfar.ogg') + SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg')) station_explosion_detonation(bomb) //TODO: If we ever decide to actually detonate the vault bomb cinematic.icon_state = "summary_malf" if("blob") //Station nuked (nuke,explosion,summary) flick("intro_nuke",cinematic) sleep(35) flick("station_explode_fade_red",cinematic) - world << sound('sound/effects/explosionfar.ogg') + SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg')) station_explosion_detonation(bomb) //TODO: no idea what this case could be cinematic.icon_state = "summary_selfdes" if("cult") //Station nuked (nuke,explosion,summary) flick("intro_nuke",cinematic) sleep(35) flick("station_explode_fade_red",cinematic) - world << sound('sound/effects/explosionfar.ogg') + SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg')) station_explosion_detonation(bomb) //TODO: no idea what this case could be cinematic.icon_state = "summary_cult" if("no_core") //Nuke failed to detonate as it had no core flick("intro_nuke",cinematic) sleep(35) flick("station_intact",cinematic) - world << sound('sound/ambience/signal.ogg') + SEND_SOUND(world, sound('sound/ambience/signal.ogg')) addtimer(CALLBACK(src, .proc/finish_cinematic, null, FALSE), 100) return //Faster exit, since nothing happened else //Station nuked (nuke,explosion,summary) flick("intro_nuke",cinematic) sleep(35) flick("station_explode_fade_red", cinematic) - world << sound('sound/effects/explosionfar.ogg') + SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg')) station_explosion_detonation(bomb) cinematic.icon_state = "summary_selfdes" //If its actually the end of the round, wait for it to end. @@ -636,7 +636,7 @@ SUBSYSTEM_DEF(ticker) if(living_player_count() < config.hard_popcap) if(next_in_line && next_in_line.client) to_chat(next_in_line, "A slot has opened! You have approximately 20 seconds to join. \>\>Join Game\<\<") - next_in_line << sound('sound/misc/notice1.ogg') + SEND_SOUND(next_in_line, sound('sound/misc/notice1.ogg')) next_in_line.LateChoices() return queued_players -= next_in_line //Client disconnected, remove he @@ -804,7 +804,7 @@ SUBSYSTEM_DEF(ticker) /datum/controller/subsystem/ticker/proc/save_mode(the_mode) var/F = file("data/mode.txt") fdel(F) - F << the_mode + WRITE_FILE(F, the_mode) /datum/controller/subsystem/ticker/proc/SetRoundEndSound(the_sound) set waitfor = FALSE @@ -858,4 +858,4 @@ SUBSYSTEM_DEF(ticker) 'sound/roundend/disappointed.ogg'\ ) - world << sound(round_end_sound) + SEND_SOUND(world, sound(round_end_sound)) diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index 6c5466d8d9..a0bcb5feec 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -53,7 +53,7 @@ SUBSYSTEM_DEF(title) /datum/controller/subsystem/title/Shutdown() if(file_path) var/F = file("data/previous_title.dat") - F << file_path + WRITE_FILE(F, file_path) for(var/thing in GLOB.clients) if(!thing) diff --git a/code/datums/action.dm b/code/datums/action.dm index 16fbeb8462..ecaa70387b 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -169,7 +169,7 @@ /datum/action/item_action/toggle_firemode name = "Toggle Firemode" - + /datum/action/item_action/rcl name = "Change Cable Color" button_icon_state = "rcl_rainbow" @@ -490,7 +490,8 @@ var/obj/effect/proc_holder/spell/S = target S.action = src name = S.name - icon_icon = S.action_icon + desc = S.desc + button_icon = S.action_icon button_icon_state = S.action_icon_state background_icon_state = S.action_background_icon_state button.name = name diff --git a/code/datums/antagonists/devil.dm b/code/datums/antagonists/devil.dm index c8f00d1995..077fb94e52 100644 --- a/code/datums/antagonists/devil.dm +++ b/code/datums/antagonists/devil.dm @@ -280,7 +280,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", if(!D) return to_chat(world, "\"SLOTH, WRATH, GLUTTONY, ACEDIA, ENVY, GREED, PRIDE! FIRES OF HELL AWAKEN!!\"") - world << 'sound/hallucinations/veryfar_noise.ogg' + SEND_SOUND(world, sound('sound/hallucinations/veryfar_noise.ogg')) give_appropriate_spells() D.convert_to_archdevil() if(istype(D.loc, /obj/effect/dummy/slaughter/)) diff --git a/code/datums/antagonists/ninja.dm b/code/datums/antagonists/ninja.dm index 6948740687..4efb17f154 100644 --- a/code/datums/antagonists/ninja.dm +++ b/code/datums/antagonists/ninja.dm @@ -141,7 +141,7 @@ /datum/antagonist/ninja/greet() - owner.current << sound('sound/effects/ninja_greeting.ogg') + SEND_SOUND(owner.current, sound('sound/effects/ninja_greeting.ogg')) to_chat(owner.current, "I am an elite mercenary assassin of the mighty Spider Clan. A SPACE NINJA!") to_chat(owner.current, "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!") to_chat(owner.current, "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.") diff --git a/code/datums/callback.dm b/code/datums/callback.dm index 1b5c25fe18..624fed58a6 100644 --- a/code/datums/callback.dm +++ b/code/datums/callback.dm @@ -100,3 +100,57 @@ if (object == GLOBAL_PROC) return call(delegate)(arglist(calling_arguments)) return call(object, delegate)(arglist(calling_arguments)) + + +/datum/callback_select + var/list/finished + var/pendingcount + var/total + +/datum/callback_select/New(count, savereturns) + total = count + if (savereturns) + finished = new(count) + + +/datum/callback_select/proc/invoke_callback(index, datum/callback/callback, list/callback_args, savereturn = TRUE) + set waitfor = FALSE + if (!callback || !istype(callback)) + //This check only exists because the alternative is callback_select would block forever if given invalid data + CRASH("invalid callback passed to invoke_callback") + if (!length(callback_args)) + callback_args = list() + pendingcount++ + var/rtn = callback.Invoke(arglist(callback_args)) + pendingcount-- + if (savereturn) + finished[index] = rtn + + + + +//runs a list of callbacks asynchronously, returning once all of them return. +//callbacks can be repeated. +//callbacks-args is a optional list of argument lists, in the same order as the callbacks, +// the inner lists will be sent to the callbacks when invoked() as additional args. +//can optionly save and return a list of return values, in the same order as the original list of callbacks +//resolution is the number of byond ticks between checks. +/proc/callback_select(list/callbacks, list/callback_args, savereturns = TRUE, resolution = 1) + if (!callbacks) + return + var/count = length(callbacks) + if (!count) + return + if (!callback_args) + callback_args = list() + + callback_args.len = count + + var/datum/callback_select/CS = new(count, savereturns) + for (var/i in 1 to count) + CS.invoke_callback(i, callbacks[i], callback_args[i], savereturns) + + while(CS.pendingcount) + sleep(resolution*world.tick_lag) + return CS.finished + diff --git a/code/datums/callback.dm.rej b/code/datums/callback.dm.rej new file mode 100644 index 0000000000..14faac8412 --- /dev/null +++ b/code/datums/callback.dm.rej @@ -0,0 +1,62 @@ +diff a/code/datums/callback.dm b/code/datums/callback.dm (rejected hunks) +@@ -100,60 +100,3 @@ + if (object == GLOBAL_PROC) + return call(delegate)(arglist(calling_arguments)) + return call(object, delegate)(arglist(calling_arguments)) +- +- +-/datum/callback_select +- var/list/finished +- var/pendingcount +- var/total +- +-/datum/callback_select/New(count, savereturns) +- total = count +- if (savereturns) +- finished = new(count) +- +- +-/datum/callback_select/proc/invoke_callback(index, datum/callback/callback, list/callback_args, savereturn = TRUE) +- set waitfor = FALSE +- if (!callback || !istype(callback)) +- //This check only exists because the alternative is callback_select would block forever if given invalid data +- CRASH("invalid callback passed to invoke_callback") +- if (!length(callback_args)) +- callback_args = list() +- pendingcount++ +- debug_usr("calling callback") +- var/rtn = callback.Invoke(arglist(callback_args)) +- debug_usr("callback returned") +- pendingcount-- +- if (savereturn) +- finished[index] = rtn +- +- +- +- +-//runs a list of callbacks asynchronously, returning once all of them return. +-//callbacks can be repeated. +-//callbacks-args is a optional list of argument lists, in the same order as the callbacks, +-// the inner lists will be sent to the callbacks when invoked() as additional args. +-//can optionly save and return a list of return values, in the same order as the original list of callbacks +-//resolution is the number of byond ticks between checks. +-/proc/callback_select(list/callbacks, list/callback_args, savereturns = TRUE, resolution = 1) +- if (!callbacks) +- return +- var/count = length(callbacks) +- if (!count) +- return +- if (!callback_args) +- callback_args = list() +- +- callback_args.len = count +- +- var/datum/callback_select/CS = new(count, savereturns) +- for (var/i in 1 to count) +- CS.invoke_callback(i, callbacks[i], callback_args[i], savereturns) +- debug_usr("starting callbacks: [CS.pendingcount]") +- while(CS.pendingcount) +- debug_usr("callbacks: [CS.pendingcount]") +- sleep(resolution*world.tick_lag) +- return CS.finished +- diff --git a/code/datums/components/component.dm b/code/datums/components/component.dm index 20e2a6e9ac..4d5fae2115 100644 --- a/code/datums/components/component.dm +++ b/code/datums/components/component.dm @@ -18,7 +18,38 @@ qdel(src) return P.SendSignal(COMSIG_COMPONENT_ADDED, src) - LAZYADD(P.datum_components, src) + + //lazy init the parent's dc list + var/list/dc = P.datum_components + if(!dc) + P.datum_components = dc = list() + + //set up the typecache + var/our_type = type + for(var/I in _GetInverseTypeListExceptRoot(our_type)) + var/test = dc[I] + if(test) //already another component of this type here + var/list/components_of_type + if(!islist(test)) + components_of_type = list(test) + dc[I] = components_of_type + else + components_of_type = test + if(I == our_type) //exact match, take priority + var/inserted = FALSE + for(var/J in 1 to components_of_type.len) + var/datum/component/C = components_of_type[J] + if(C.type != our_type) //but not over other exact matches + components_of_type.Insert(J, I) + inserted = TRUE + break + if(!inserted) + components_of_type += src + else //indirect match, back of the line with ya + components_of_type += src + else //only component of this type, no list + dc[I] = src + parent = P /datum/component/Destroy() @@ -33,7 +64,20 @@ /datum/component/proc/_RemoveNoSignal() var/datum/P = parent if(P) - LAZYREMOVE(P.datum_components, src) + var/list/dc = P.datum_components + var/our_type = type + for(var/I in _GetInverseTypeListExceptRoot(our_type)) + var/list/components_of_type = dc[I] + if(islist(components_of_type)) // + var/list/subtracted = components_of_type - src + if(subtracted.len == 1) //only 1 guy left + dc[I] = subtracted[1] //make him special + else + dc[I] = subtracted + else //just us + dc -= I + if(!dc.len) + P.datum_components = null parent = null /datum/component/proc/RegisterSignal(sig_type, proc_on_self, override = FALSE) @@ -66,6 +110,13 @@ /datum/component/proc/OnTransfer(datum/new_parent) return +/datum/component/proc/_GetInverseTypeListExceptRoot(our_type_cached) + var/datum/component/current_type = our_type_cached + . = list() + while (current_type != /datum/component) + . += current_type + current_type = type2parent(current_type) + /datum/proc/SendSignal(sigtype, ...) var/list/comps = datum_components . = FALSE @@ -81,21 +132,32 @@ return /datum/proc/GetComponent(c_type) - for(var/I in datum_components) - if(istype(I, c_type)) - return I + var/list/dc = datum_components + if(!dc) + return null + . = dc[c_type] + if(islist(.)) + return .[1] /datum/proc/GetExactComponent(c_type) - for(var/I in datum_components) - var/datum/component/C = I + var/list/dc = datum_components + if(!dc) + return null + var/datum/component/C = dc[c_type] + if(C) + if(islist(C)) + C = C[1] if(C.type == c_type) - return I + return C + return null /datum/proc/GetComponents(c_type) - . = list() - for(var/I in datum_components) - if(istype(I, c_type)) - . += I + var/list/dc = datum_components + if(!dc) + return null + . = dc[c_type] + if(!islist(.)) + return list(.) /datum/proc/AddComponent(new_type, ...) var/nt = new_type diff --git a/code/datums/components/component.dm.rej b/code/datums/components/component.dm.rej new file mode 100644 index 0000000000..7d216a39c5 --- /dev/null +++ b/code/datums/components/component.dm.rej @@ -0,0 +1,18 @@ +diff a/code/datums/components/component.dm b/code/datums/components/component.dm (rejected hunks) +@@ -22,8 +22,7 @@ + //lazy init the parent's dc list + var/list/dc = P.datum_components + if(!dc) +- dc = list() +- P.datum_components = dc ++ P.datum_components = dc = list() + + //set up the typecache + var/our_type = type +@@ -179,4 +178,4 @@ + helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C) + C.OnTransfer(src) + C.parent = src +- SendSignal(COMSIG_COMPONENT_ADDED, C) +\ No newline at end of file ++ SendSignal(COMSIG_COMPONENT_ADDED, C) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index e519cf6af3..87c6ad7334 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -929,6 +929,26 @@ manipulate_organs(C) href_list["datumrefresh"] = href_list["editorgans"] + else if(href_list["hallucinate"]) + if(!check_rights(0)) + return + + var/mob/living/carbon/C = locate(href_list["hallucinate"]) in GLOB.mob_list + if(!istype(C)) + to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + return + + var/list/hallucinations = subtypesof(/datum/hallucination) + var/result = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in hallucinations + if(!usr) + return + if(QDELETED(C)) + to_chat(usr, "Mob doesn't exist anymore") + return + + if(result) + new result(C, TRUE) + else if(href_list["makehuman"]) if(!check_rights(R_SPAWN)) return diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index 84d177a390..6d26246c38 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -43,7 +43,7 @@ SSdisease.active_diseases += DD //Add it to the active diseases list, now that it's actually in a mob and being processed. //Copy properties over. This is so edited diseases persist. - var/list/skipped = list("affected_mob","holder","carrier","stage","type","parent_type","vars","transformed") + var/list/skipped = list("affected_mob","holder","carrier","stage","type","parent_type","vars","transformed","symptoms") for(var/V in DD.vars) if(V in skipped) continue diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index e8ddfdc3d7..7f09ffa48c 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -57,9 +57,7 @@ symptoms = GenerateSymptoms(0, 2) else for(var/datum/symptom/S in D.symptoms) - var/datum/symptom/new_symp = new S.type - new_symp.name = S.name - new_symp.neutered = S.neutered + var/datum/symptom/new_symp = S.Copy() symptoms += new_symp Refresh() diff --git a/code/datums/diseases/advance/symptoms/hallucigen.dm b/code/datums/diseases/advance/symptoms/hallucigen.dm index f913d49573..9bfd5b0baf 100644 --- a/code/datums/diseases/advance/symptoms/hallucigen.dm +++ b/code/datums/diseases/advance/symptoms/hallucigen.dm @@ -59,4 +59,4 @@ Bonus else if(prob(base_message_chance)) to_chat(M, "[pick("Oh, your head...", "Your head pounds.", "They're everywhere! Run!", "Something in the shadows...")]") - M.hallucination += (15 * power) + M.hallucination += (45 * power) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 550ea590bf..4bacf2d9e8 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -32,6 +32,7 @@ if(ishuman(destination)) var/mob/living/carbon/human/H = destination H.give_genitals(TRUE)//This gives the body the genitals of this DNA. Used for any transformations based on DNA + destination.flavor_text = destination.dna.features["flavor_text"] //Update the flavor_text to use new dna text /datum/dna/proc/copy_dna(datum/dna/new_dna) new_dna.unique_enzymes = unique_enzymes @@ -231,6 +232,7 @@ if(newfeatures) dna.features = newfeatures + flavor_text = dna.features["flavor_text"] //Update the flavor_text to use new dna text if(mrace) set_species(mrace, icon_update=0) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 7017149d53..a31aab8607 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -400,7 +400,15 @@ if (assigned_role in GLOB.command_positions) text += "HEAD|loyal|employee|headrev|rev" else if (src in SSticker.mode.head_revolutionaries) - text += "head|loyal|employee|HEADREV|rev" + var/last_healthy_headrev = TRUE + for(var/I in SSticker.mode.head_revolutionaries) + if(I == src) + continue + var/mob/M = I + if(M.z == ZLEVEL_STATION && !M.stat) + last_healthy_headrev = FALSE + break + text += "head|loyal|employee|[last_healthy_headrev ? "LAST " : ""]HEADREV|rev" text += "
Flash: give" var/list/L = current.get_contents() @@ -805,11 +813,11 @@ possible_targets += possible_target.current var/mob/def_target = null - var/objective_list[] = list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain, /datum/objective/maroon) - if (objective&&(objective.type in objective_list) && objective:target) - def_target = objective:target.current + var/list/objective_list = typecacheof(list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain, /datum/objective/maroon)) + if (is_type_in_typecache(objective, objective_list) && objective.target) + def_target = objective.target.current - var/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets + var/mob/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets if (!new_target) return @@ -817,12 +825,12 @@ if (new_target == "Free objective") new_objective = new objective_path new_objective.owner = src - new_objective:target = null + new_objective.target = null new_objective.explanation_text = "Free objective" else new_objective = new objective_path new_objective.owner = src - new_objective:target = new_target:mind + new_objective.target = new_target.mind //Will display as special role if the target is set as MODE. Ninjas/commandos/nuke ops. new_objective.update_explanation_text() diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 485ca00515..c15ede7b3e 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -37,7 +37,7 @@ icon_state = "shadow_mend" /datum/status_effect/void_price/tick() - owner << sound('sound/magic/summon_karp.ogg', volume = 25) + SEND_SOUND(owner, sound('sound/magic/summon_karp.ogg', volume = 25)) owner.adjustBruteLoss(3) @@ -247,7 +247,7 @@ for(var/datum/mind/B in SSticker.mode.cult) if(isliving(B.current)) var/mob/living/M = B.current - M << 'sound/hallucinations/veryfar_noise.ogg' + SEND_SOUND(M, sound('sound/hallucinations/veryfar_noise.ogg')) to_chat(M, "The Cult's Master, [owner], has fallen in \the [A]!") /datum/status_effect/cult_master/tick() diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm index 7b43bf6396..f4f2fc089c 100644 --- a/code/datums/weather/weather.dm +++ b/code/datums/weather/weather.dm @@ -69,7 +69,7 @@ if(telegraph_message) to_chat(M, telegraph_message) if(telegraph_sound) - M << sound(telegraph_sound) + SEND_SOUND(M, sound(telegraph_sound)) addtimer(CALLBACK(src, .proc/start), telegraph_duration) /datum/weather/proc/start() @@ -83,7 +83,7 @@ if(weather_message) to_chat(M, weather_message) if(weather_sound) - M << sound(weather_sound) + SEND_SOUND(M, sound(weather_sound)) START_PROCESSING(SSweather, src) addtimer(CALLBACK(src, .proc/wind_down), weather_duration) @@ -98,7 +98,7 @@ if(end_message) to_chat(M, end_message) if(end_sound) - M << sound(end_sound) + SEND_SOUND(M, sound(end_sound)) STOP_PROCESSING(SSweather, src) addtimer(CALLBACK(src, .proc/end), end_duration) diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm index 00b2dd10b8..9aa2ca81e8 100644 --- a/code/datums/wires/mulebot.dm +++ b/code/datums/wires/mulebot.dm @@ -20,12 +20,12 @@ var/mob/living/simple_animal/bot/mulebot/M = holder switch(wire) if(WIRE_POWER1, WIRE_POWER2) - holder.visible_message("[bicon(M)] The charge light flickers.") + holder.visible_message("[icon2html(M, viewers(holder))] The charge light flickers.") if(WIRE_AVOIDANCE) - holder.visible_message("[bicon(M)] The external warning lights flash briefly.") + holder.visible_message("[icon2html(M, viewers(holder))] The external warning lights flash briefly.") if(WIRE_LOADCHECK) - holder.visible_message("[bicon(M)] The load platform clunks.") + holder.visible_message("[icon2html(M, viewers(holder))] The load platform clunks.") if(WIRE_MOTOR1, WIRE_MOTOR2) - holder.visible_message("[bicon(M)] The drive motor whines briefly.") + holder.visible_message("[icon2html(M, viewers(holder))] The drive motor whines briefly.") else - holder.visible_message("[bicon(M)] You hear a radio crackle.") \ No newline at end of file + holder.visible_message("[icon2html(M, viewers(holder))] You hear a radio crackle.") \ No newline at end of file diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm index 436b8be3ec..d38147f1ec 100644 --- a/code/datums/wires/particle_accelerator.dm +++ b/code/datums/wires/particle_accelerator.dm @@ -25,7 +25,7 @@ if(WIRE_INTERFACE) C.interface_control = !C.interface_control if(WIRE_LIMIT) - C.visible_message("[bicon(C)][C] makes a large whirring noise.") + C.visible_message("[icon2html(C, viewers(holder))][C] makes a large whirring noise.") /datum/wires/particle_accelerator/control_box/on_cut(wire, mend) var/obj/machinery/particle_accelerator/control_box/C = holder diff --git a/code/datums/wires/syndicatebomb.dm b/code/datums/wires/syndicatebomb.dm index 78acc42eb0..043110f5d3 100644 --- a/code/datums/wires/syndicatebomb.dm +++ b/code/datums/wires/syndicatebomb.dm @@ -19,21 +19,21 @@ switch(wire) if(WIRE_BOOM) if(B.active) - holder.visible_message("[bicon(B)] An alarm sounds! It's go-") + holder.visible_message("[icon2html(B, viewers(holder))] An alarm sounds! It's go-") B.explode_now = TRUE tell_admins(B) if(WIRE_UNBOLT) - holder.visible_message("[bicon(B)] The bolts spin in place for a moment.") + holder.visible_message("[icon2html(B, viewers(holder))] The bolts spin in place for a moment.") if(WIRE_DELAY) if(B.delayedbig) - holder.visible_message("[bicon(B)] The bomb has already been delayed.") + holder.visible_message("[icon2html(B, viewers(holder))] The bomb has already been delayed.") else - holder.visible_message("[bicon(B)] The bomb chirps.") + holder.visible_message("[icon2html(B, viewers(holder))] The bomb chirps.") playsound(B, 'sound/machines/chime.ogg', 30, 1) B.detonation_timer += 300 B.delayedbig = TRUE if(WIRE_PROCEED) - holder.visible_message("[bicon(B)] The bomb buzzes ominously!") + holder.visible_message("[icon2html(B, viewers(holder))] The bomb buzzes ominously!") playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1) var/seconds = B.seconds_remaining() if(seconds >= 61) // Long fuse bombs can suddenly become more dangerous if you tinker with them. @@ -44,13 +44,13 @@ B.detonation_timer = world.time + 100 if(WIRE_ACTIVATE) if(!B.active && !B.defused) - holder.visible_message("[bicon(B)] You hear the bomb start ticking!") + holder.visible_message("[icon2html(B, viewers(holder))] You hear the bomb start ticking!") B.activate() B.update_icon() else if(B.delayedlittle) - holder.visible_message("[bicon(B)] Nothing happens.") + holder.visible_message("[icon2html(B, viewers(holder))] Nothing happens.") else - holder.visible_message("[bicon(B)] The bomb seems to hesitate for a moment.") + holder.visible_message("[icon2html(B, viewers(holder))] The bomb seems to hesitate for a moment.") B.detonation_timer += 100 B.delayedlittle = TRUE @@ -62,24 +62,24 @@ B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage. else if(B.active) - holder.visible_message("[bicon(B)] An alarm sounds! It's go-") + holder.visible_message("[icon2html(B, viewers(holder))] An alarm sounds! It's go-") B.explode_now = TRUE tell_admins(B) else B.defused = TRUE if(WIRE_UNBOLT) if(!mend && B.anchored) - holder.visible_message("[bicon(B)] The bolts lift out of the ground!") + holder.visible_message("[icon2html(B, viewers(holder))] The bolts lift out of the ground!") playsound(B, 'sound/effects/stealthoff.ogg', 30, 1) B.anchored = FALSE if(WIRE_PROCEED) if(!mend && B.active) - holder.visible_message("[bicon(B)] An alarm sounds! It's go-") + holder.visible_message("[icon2html(B, viewers(holder))] An alarm sounds! It's go-") B.explode_now = TRUE tell_admins(B) if(WIRE_ACTIVATE) if(!mend && B.active) - holder.visible_message("[bicon(B)] The timer stops! The bomb has been defused!") + holder.visible_message("[icon2html(B, viewers(holder))] The timer stops! The bomb has been defused!") B.active = FALSE B.defused = TRUE B.update_icon() diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 1b8d25aa51..218cb59f41 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -439,7 +439,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) // Ambience goes down here -- make sure to list each area separately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch if(L.client && !L.client.ambience_playing && L.client.prefs.toggles & SOUND_SHIP_AMBIENCE) L.client.ambience_playing = 1 - L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ) + SEND_SOUND(L, sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ)) if(!(L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))) return //General ambience check is below the ship ambience so one can play without the other @@ -448,7 +448,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) var/sound = pick(ambientsounds) if(!L.client.played) - L << sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE) + SEND_SOUND(L, sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE)) L.client.played = 1 sleep(600) //ewww - this is very very bad if(L.&& L.client) diff --git a/code/game/area/areas.dm.rej b/code/game/area/areas.dm.rej new file mode 100644 index 0000000000..3c097d1229 --- /dev/null +++ b/code/game/area/areas.dm.rej @@ -0,0 +1,10 @@ +diff a/code/game/area/areas.dm b/code/game/area/areas.dm (rejected hunks) +@@ -432,7 +432,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) + // Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch + if(L.client && !L.client.ambience_playing && L.client.prefs.toggles & SOUND_SHIP_AMBIENCE) + L.client.ambience_playing = 1 +- L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ) ++ SEND_SOUND(L, sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ)) + + if(!(L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))) + return //General ambience check is below the ship ambience so one can play without the other diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 6a00f26ffc..d931f808b8 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -270,7 +270,7 @@ f_name = "a " f_name += "blood-stained [name]!" - to_chat(user, "[bicon(src)] That's [f_name]") + to_chat(user, "[icon2html(src, user)] That's [f_name]") if(desc) to_chat(user, desc) diff --git a/code/game/communications.dm b/code/game/communications.dm index 66bb91ef59..19c3f87460 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -292,7 +292,7 @@ GLOBAL_VAR_INIT(RADIO_MAGNETS, "9") /datum/signal/proc/debug_print() if (source) - . = "signal = {source = '[source]' ([source:x],[source:y],[source:z])\n" + . = "signal = {source = '[source]' [COORD(source)]\n" else . = "signal = {source = '[source]' ()\n" for (var/i in data) diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm index 8da7cb3169..8a6d0063b9 100644 --- a/code/game/gamemodes/antag_spawner.dm +++ b/code/game/gamemodes/antag_spawner.dm @@ -110,7 +110,7 @@ SSticker.mode.apprentices += M.mind M.mind.special_role = "apprentice" SSticker.mode.update_wiz_icons_added(M.mind) - M << sound('sound/effects/magic.ogg') + SEND_SOUND(M, sound('sound/effects/magic.ogg')) var/newname = copytext(sanitize(input(M, "You are [wizard_name]'s apprentice. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN) if (!newname) newname = randomname diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm index deef4367e0..389888ac28 100644 --- a/code/game/gamemodes/blob/powers.dm +++ b/code/game/gamemodes/blob/powers.dm @@ -171,11 +171,11 @@ if(candidates.len) //if we got at least one candidate, they're a blobbernaut now. var/client/C = pick(candidates) blobber.key = C.key - blobber << 'sound/effects/blobattack.ogg' - blobber << 'sound/effects/attackblob.ogg' + SEND_SOUND(blobber, sound('sound/effects/blobattack.ogg')) + SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg')) to_chat(blobber, "You are a blobbernaut!") to_chat(blobber, "You are powerful, hard to kill, and slowly regenerate near nodes and cores, but will slowly die if not near the blob or if the factory that made you is killed.") - to_chat(blobber, "You can communicate with other blobbernauts and GLOB.overminds via :b") + to_chat(blobber, "You can communicate with other blobbernauts and overminds via :b") to_chat(blobber, "Your overmind's blob reagent is: [blob_reagent_datum.name]!") to_chat(blobber, "The [blob_reagent_datum.name] reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]") if(blobber) diff --git a/code/game/gamemodes/blob/powers.dm.rej b/code/game/gamemodes/blob/powers.dm.rej new file mode 100644 index 0000000000..27dc764a75 --- /dev/null +++ b/code/game/gamemodes/blob/powers.dm.rej @@ -0,0 +1,10 @@ +diff a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm (rejected hunks) +@@ -175,7 +175,7 @@ + SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg')) + to_chat(blobber, "You are a blobbernaut!") + to_chat(blobber, "You are powerful, hard to kill, and slowly regenerate near nodes and cores, but will slowly die if not near the blob or if the factory that made you is killed.") +- to_chat(blobber, "You can communicate with other blobbernauts and GLOB.overminds via :b") ++ to_chat(blobber, "You can communicate with other blobbernauts and overminds via :b") + to_chat(blobber, "Your overmind's blob reagent is: [blob_reagent_datum.name]!") + to_chat(blobber, "The [blob_reagent_datum.name] reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]") + if(blobber) diff --git a/code/game/gamemodes/blob/theblob.dm b/code/game/gamemodes/blob/theblob.dm index 0c216f1c38..f6cdd64bb6 100644 --- a/code/game/gamemodes/blob/theblob.dm +++ b/code/game/gamemodes/blob/theblob.dm @@ -24,6 +24,7 @@ M.changeNext_move(CLICK_CD_MELEE) var/a = pick("gently stroke", "nuzzle", "affectionatly pet", "cuddle") M.visible_message("[M] [a]s [src]!", "You [a] [src]!") + to_chat(overmind, "[M] [a]s you!") playsound(src, 'sound/effects/blobattack.ogg', 50, 1) //SQUISH SQUISH @@ -235,7 +236,7 @@ if(istype(I, /obj/item/device/analyzer)) user.changeNext_move(CLICK_CD_MELEE) to_chat(user, "The analyzer beeps once, then reports:
") - user << 'sound/machines/ping.ogg' + SEND_SOUND(user, sound('sound/machines/ping.ogg')) chemeffectreport(user) typereport(user) else diff --git a/code/game/gamemodes/changeling/powers/shriek.dm b/code/game/gamemodes/changeling/powers/shriek.dm index 099d991062..7afce8aa27 100644 --- a/code/game/gamemodes/changeling/powers/shriek.dm +++ b/code/game/gamemodes/changeling/powers/shriek.dm @@ -16,10 +16,10 @@ C.confused += 25 C.Jitter(50) else - C << sound('sound/effects/screech.ogg') + SEND_SOUND(C, sound('sound/effects/screech.ogg')) if(issilicon(M)) - M << sound('sound/weapons/flash.ogg') + SEND_SOUND(M, sound('sound/weapons/flash.ogg')) M.Knockdown(rand(100,200)) for(var/obj/machinery/light/L in range(4, user)) diff --git a/code/game/gamemodes/clock_cult/clock_mobs.dm b/code/game/gamemodes/clock_cult/clock_mobs.dm index 97a68fd321..abeb183ab0 100644 --- a/code/game/gamemodes/clock_cult/clock_mobs.dm +++ b/code/game/gamemodes/clock_cult/clock_mobs.dm @@ -38,7 +38,7 @@ /mob/living/simple_animal/hostile/clockwork/examine(mob/user) var/t_He = p_they(TRUE) var/t_s = p_s() - var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src]!\n" msg += "[desc]\n" if(health < maxHealth) msg += "" diff --git a/code/game/gamemodes/clock_cult/clock_scripture.dm b/code/game/gamemodes/clock_cult/clock_scripture.dm index 4a1ca367ce..382aaec10d 100644 --- a/code/game/gamemodes/clock_cult/clock_scripture.dm +++ b/code/game/gamemodes/clock_cult/clock_scripture.dm @@ -150,7 +150,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or if(prob(ratvarian_prob)) message = text2ratvar(message) to_chat(invoker, "\"[message]\"") - invoker << 'sound/magic/clockwork/invoke_general.ogg' + SEND_SOUND(invoker, sound('sound/magic/clockwork/invoke_general.ogg')) return TRUE /datum/clockwork_scripture/proc/check_offstation_penalty() diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm index a7fb90d253..647b47e7fa 100644 --- a/code/game/gamemodes/cult/cult_comms.dm +++ b/code/game/gamemodes/cult/cult_comms.dm @@ -103,13 +103,13 @@ if(B.current) B.current.update_action_buttons_icon() if(!B.current.incapacitated()) - B.current << 'sound/hallucinations/im_here1.ogg' + SEND_SOUND(B.current, 'sound/hallucinations/im_here1.ogg') to_chat(B.current, "Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.") sleep(100) var/list/asked_cultists = list() for(var/datum/mind/B in SSticker.mode.cult) if(B.current && B.current != Nominee && !B.current.incapacitated()) - B.current << 'sound/magic/exit_blood.ogg' + SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg') asked_cultists += B.current var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists) if(QDELETED(Nominee) || Nominee.incapacitated()) @@ -280,7 +280,7 @@ for(var/datum/mind/B in SSticker.mode.cult) if(B.current && B.current.stat != DEAD && B.current.client) to_chat(B.current, "Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!") - B.current << pick(sound('sound/hallucinations/over_here2.ogg',0,1,75), sound('sound/hallucinations/over_here3.ogg',0,1,75)) + SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75)) B.current.client.images += GLOB.blood_target_image attached_action.owner.update_action_buttons_icon() remove_ranged_ability("The marking rite is complete! It will last for 90 seconds.") @@ -324,7 +324,7 @@ return FALSE if(cooldown > world.time) if(!PM.active) - owner << "You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can pulse again!" + to_chat(owner, "You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can pulse again!") return FALSE return ..() @@ -367,7 +367,7 @@ if(!attached_action.throwing) attached_action.throwing = TRUE attached_action.throwee = target - ranged_ability_user << 'sound/weapons/thudswoosh.ogg' + SEND_SOUND(ranged_ability_user, sound('sound/weapons/thudswoosh.ogg')) to_chat(ranged_ability_user,"You reach through the veil with your mind's eye and seize [target]!") return else diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 918398154c..d472bb7d5a 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -161,11 +161,15 @@ /obj/item/weapon/sharpener/cult name = "eldritch whetstone" desc = "A block, empowered by dark magic. Sharp weapons will be enhanced when used on the stone." + icon_state = "cult_sharpener" used = 0 increment = 5 max = 40 prefix = "darkened" +/obj/item/weapon/sharpener/cult/update_icon() + icon_state = "cult_sharpener[used ? "_used" : ""]" + /obj/item/clothing/suit/hooded/cultrobes/cult_shield name = "empowered cultist armor" desc = "Empowered garb which creates a powerful shield around the user." @@ -391,7 +395,7 @@ if(!iscultist(user)) to_chat(user, "That doesn't seem to do anything useful.") return - + if(istype(A, /obj/item)) var/list/cultists = list() diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 69b730d574..4c80f53b94 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -538,7 +538,7 @@ structure_check() searches for nearby cultist structures required for the invoca mob_to_revive = input(user, "Choose a cultist to revive.", "Cultist to Revive") as null|anything in potential_revive_mobs else mob_to_revive = potential_revive_mobs[1] - if(!src || QDELETED(src) || rune_in_use || !validness_checks(mob_to_revive, user)) + if(QDELETED(src) || !validness_checks(mob_to_revive, user)) rune_in_use = FALSE return if(user.name == "Herbert West") diff --git a/code/game/gamemodes/cult/supply.dm b/code/game/gamemodes/cult/supply.dm index 71b8c941b1..23270c3d6c 100644 --- a/code/game/gamemodes/cult/supply.dm +++ b/code/game/gamemodes/cult/supply.dm @@ -29,7 +29,6 @@ return 0 /obj/item/weapon/paper/talisman/supply/Topic(href, href_list) - world.log << "[usr], [href], [href_list]" if(QDELETED(src) || usr.incapacitated() || !in_range(src, usr)) return diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm index e8b77c1172..c5b94d983f 100644 --- a/code/game/gamemodes/cult/talisman.dm +++ b/code/game/gamemodes/cult/talisman.dm @@ -270,7 +270,7 @@ if(target.use(25)) new /obj/structure/constructshell(T) to_chat(user, "The talisman clings to the metal and twists it into a construct shell!") - user << sound('sound/effects/magic.ogg',0,1,25) + SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) invoke(user, 1) qdel(src) else @@ -281,7 +281,7 @@ new /obj/item/stack/sheet/runed_metal(T,quantity) target.use(quantity) to_chat(user, "The talisman clings to the plasteel, transforming it into runed metal!") - user << sound('sound/effects/magic.ogg',0,1,25) + SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) invoke(user, 1) if(uses <= 0) qdel(src) diff --git a/code/game/gamemodes/devil/true_devil/_true_devil.dm b/code/game/gamemodes/devil/true_devil/_true_devil.dm index 1a0cfcd231..090b926dbf 100644 --- a/code/game/gamemodes/devil/true_devil/_true_devil.dm +++ b/code/game/gamemodes/devil/true_devil/_true_devil.dm @@ -61,15 +61,15 @@ /mob/living/carbon/true_devil/examine(mob/user) - var/msg = "*---------*\nThis is [bicon(src)] [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] [src]!\n" //Left hand items for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "It is holding [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "It is holding [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "It is holding [bicon(I)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "It is holding [icon2html(I, user)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" //Braindead if(!client && stat != DEAD) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index f6fef13305..790319e362 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -111,7 +111,7 @@ var/list/living_crew = list() for(var/mob/Player in GLOB.mob_list) - if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player)) + if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) && !isbrain(Player) && Player.client) living_crew += Player if(living_crew.len / GLOB.joined_player_list.len <= config.midround_antag_life_check) //If a lot of the player base died, we start fresh message_admins("Convert_roundtype failed due to too many dead people. Limit is [config.midround_antag_life_check * 100]% living crew") @@ -120,7 +120,7 @@ var/list/datum/game_mode/runnable_modes = config.get_runnable_midround_modes(living_crew.len) var/list/datum/game_mode/usable_modes = list() for(var/datum/game_mode/G in runnable_modes) - if(G.reroll_friendly) + if(G.reroll_friendly && living_crew >= G.required_players) usable_modes += G else qdel(G) @@ -208,7 +208,7 @@ return 0 //A resource saver: once we find someone who has to die for all antags to be dead, we can just keep checking them, cycling over everyone only when we lose our mark. for(var/mob/Player in GLOB.living_mob_list) - if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player)) + if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player) && Player.client) if(Player.mind.special_role) //Someone's still antaging! living_antag_player = Player return 0 diff --git a/code/game/gamemodes/gang/gang_datum.dm b/code/game/gamemodes/gang/gang_datum.dm index ba18ad7578..b7b20a7311 100644 --- a/code/game/gamemodes/gang/gang_datum.dm +++ b/code/game/gamemodes/gang/gang_datum.dm @@ -191,7 +191,7 @@ var/mob/living/mob = get(tool.loc, /mob/living) if(mob && mob.mind && mob.stat == CONSCIOUS) if(mob.mind.gang_datum == src) - to_chat(mob, "[bicon(tool)] [message]") + to_chat(mob, "[icon2html(tool, mob)] [message]") return diff --git a/code/game/gamemodes/gang/gang_pen.dm b/code/game/gamemodes/gang/gang_pen.dm index 4357f31e83..e52db2ec5f 100644 --- a/code/game/gamemodes/gang/gang_pen.dm +++ b/code/game/gamemodes/gang/gang_pen.dm @@ -66,4 +66,4 @@ cooldown = 0 icon_state = "pen" var/mob/M = get(src, /mob) - to_chat(M, "[bicon(src)] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly. It is ready to be used again.") + to_chat(M, "[icon2html(src, M)] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly. It is ready to be used again.") diff --git a/code/game/gamemodes/gang/recaller.dm b/code/game/gamemodes/gang/recaller.dm index 601a1f1c0d..0be52e6033 100644 --- a/code/game/gamemodes/gang/recaller.dm +++ b/code/game/gamemodes/gang/recaller.dm @@ -110,7 +110,7 @@ if(!message || !can_use(user)) return if(user.z > 2) - to_chat(user, "[bicon(src)]Error: Station out of range.") + to_chat(user, "[icon2html(src, user)]Error: Station out of range.") return var/list/members = list() members += gang.gangsters @@ -179,35 +179,35 @@ gang.message_gangtools("[usr] is attempting to recall the emergency shuttle.") recalling = 1 - to_chat(loc, "[bicon(src)]Generating shuttle recall order with codes retrieved from last call signal...") + to_chat(loc, "[icon2html(src, loc)]Generating shuttle recall order with codes retrieved from last call signal...") sleep(rand(100,300)) if(SSshuttle.emergency.mode != SHUTTLE_CALL) //Shuttle can only be recalled when it's moving to the station - to_chat(user, "[bicon(src)]Emergency shuttle cannot be recalled at this time.") + to_chat(user, "[icon2html(src, user)]Emergency shuttle cannot be recalled at this time.") recalling = 0 return 0 - to_chat(loc, "[bicon(src)]Shuttle recall order generated. Accessing station long-range communication arrays...") + to_chat(loc, "[icon2html(src, loc)]Shuttle recall order generated. Accessing station long-range communication arrays...") sleep(rand(100,300)) if(!gang.dom_attempts) - to_chat(user, "[bicon(src)]Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts.") + to_chat(user, "[icon2html(src, user)]Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts.") recalling = 0 return 0 var/turf/userturf = get_turf(user) if(userturf.z != ZLEVEL_STATION) //Shuttle can only be recalled while on station - to_chat(user, "[\bicon(src)]Error: Device out of range of station communication arrays.") + to_chat(user, "[icon2html(src, user)]Error: Device out of range of station communication arrays.") recalling = 0 return 0 var/datum/station_state/end_state = new /datum/station_state() end_state.count() if((100 * GLOB.start_state.score(end_state)) < 80) //Shuttle cannot be recalled if the station is too damaged - to_chat(user, "[bicon(src)]Error: Station communication systems compromised. Unable to establish connection.") + to_chat(user, "[icon2html(src, user)]Error: Station communication systems compromised. Unable to establish connection.") recalling = 0 return 0 - to_chat(loc, "[bicon(src)]Comm arrays accessed. Broadcasting recall signal...") + to_chat(loc, "[icon2html(src, loc)]Comm arrays accessed. Broadcasting recall signal...") sleep(rand(100,300)) @@ -220,7 +220,7 @@ gang.recalls -= 1 return 1 - to_chat(loc, "[bicon(src)]No response recieved. Emergency shuttle cannot be recalled at this time.") + to_chat(loc, "[icon2html(src, loc)]No response recieved. Emergency shuttle cannot be recalled at this time.") return 0 /obj/item/device/gangtool/proc/can_use(mob/living/carbon/human/user) diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index 8c8108962e..5bc162ee8f 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -375,8 +375,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( minor_announce("[key] SECONDS UNTIL DOOMSDAY DEVICE ACTIVATION!", "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4", TRUE) /obj/machinery/doomsday_device/proc/detonate(z_level = ZLEVEL_STATION) - for(var/mob/M in GLOB.player_list) - M << 'sound/machines/alarm.ogg' + sound_to_playing_players('sound/machines/alarm.ogg') sleep(100) for(var/mob/living/L in GLOB.mob_list) var/turf/T = get_turf(L) diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm index 68ed9abd35..c24ab53ef5 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm @@ -654,7 +654,7 @@ to_chat(M, "[link] [rendered]") /mob/living/simple_animal/hostile/swarmer/proc/ContactSwarmers() - var/message = input(src, "Announce to other swarmers", "Swarmer contact") + var/message = stripped_input(src, "Announce to other swarmers", "Swarmer contact") // TODO get swarmers their own colour rather than just boldtext if(message) swarmer_chat(message) diff --git a/code/game/gamemodes/miniantags/morph/morph.dm b/code/game/gamemodes/miniantags/morph/morph.dm index dcd2ef2673..af27833d15 100644 --- a/code/game/gamemodes/miniantags/morph/morph.dm +++ b/code/game/gamemodes/miniantags/morph/morph.dm @@ -224,7 +224,7 @@ player_mind.special_role = "Morph" SSticker.mode.traitors |= player_mind to_chat(S, S.playstyle_string) - S << 'sound/magic/mutate.ogg' + SEND_SOUND(S, sound('sound/magic/mutate.ogg')) message_admins("[key_name_admin(S)] has been made into a morph by an event.") log_game("[key_name(S)] was spawned as a morph by an event.") spawned_mobs += S diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm index afbc597c29..e16c21e2e2 100644 --- a/code/game/gamemodes/miniantags/revenant/revenant.dm +++ b/code/game/gamemodes/miniantags/revenant/revenant.dm @@ -74,7 +74,7 @@ generated_objectives_and_spells = TRUE mind.remove_all_antag() mind.wipe_memory() - src << 'sound/effects/ghost.ogg' + SEND_SOUND(src, sound('sound/effects/ghost.ogg')) var/datum/objective/revenant/objective = new objective.owner = mind mind.objectives += objective diff --git a/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm b/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm index e9b417de1a..bcb2218fe6 100644 --- a/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm +++ b/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm @@ -42,7 +42,7 @@ SSticker.mode.traitors |= player_mind to_chat(S, S.playstyle_string) to_chat(S, "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.") - S << 'sound/magic/demon_dies.ogg' + SEND_SOUND(S, 'sound/magic/demon_dies.ogg') message_admins("[key_name_admin(S)] has been made into a slaughter demon by an event.") log_game("[key_name(S)] was spawned as a slaughter demon by an event.") spawned_mobs += S diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 759c5f4454..16fb1f601d 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -288,7 +288,7 @@ text += "
" text += "(Syndicates used [TC_uses] TC) [purchases]" if(TC_uses == 0 && station_was_nuked && !are_operatives_dead()) - text += "[bicon(icon('icons/badass.dmi', "badass"))]" + text += "[icon2html('icons/badass.dmi', world, "badass")]" to_chat(world, text) return 1 diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 793313edfd..941e0bf081 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -420,8 +420,7 @@ yes_code = FALSE safety = TRUE update_icon() - for(var/mob/M in GLOB.player_list) - M << 'sound/machines/alarm.ogg' + sound_to_playing_players('sound/machines/alarm.ogg') if(SSticker && SSticker.mode) SSticker.mode.explosion_in_progress = 1 sleep(100) diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 3e6cca1ac5..3b91816ee9 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -124,7 +124,7 @@ text += " (used [TC_uses] TC) [purchases]" if(TC_uses==0 && traitorwin) var/static/icon/badass = icon('icons/badass.dmi', "badass") - text += "[bicon(badass)]" + text += "[icon2html(badass, world)]" text += objectives diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 5f65c2a96d..6f1ae8e1dd 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -476,7 +476,7 @@ GiveHint(target) else if(istype(I, /obj/item/weapon/bikehorn)) to_chat(target, "HONK") - target << 'sound/items/airhorn.ogg' + SEND_SOUND(target, 'sound/items/airhorn.ogg') target.adjustEarDamage(0,3) GiveHint(target) cooldown = world.time +cooldown_time diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index 1e72707e86..2fe15a99d8 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -2,7 +2,7 @@ name = "cell charger" desc = "It charges power cells." icon = 'icons/obj/power.dmi' - icon_state = "ccharger0" + icon_state = "ccharger" anchored = TRUE use_power = IDLE_POWER_USE idle_power_usage = 5 @@ -12,19 +12,16 @@ var/chargelevel = -1 /obj/machinery/cell_charger/proc/updateicon() - icon_state = "ccharger[charging ? 1 : 0]" + cut_overlays() - if(charging && !(stat & (BROKEN|NOPOWER))) - var/newlevel = round(charging.percent() * 4 / 100) - - if(chargelevel != newlevel) - chargelevel = newlevel - - cut_overlays() - add_overlay("ccharger-o[newlevel]") - - else - cut_overlays() + if(charging) + add_overlay(image(charging.icon, charging.icon_state)) + add_overlay("ccharger-on") + if(!(stat & (BROKEN|NOPOWER))) + var/newlevel = round(charging.percent() * 4 / 100) + if(chargelevel != newlevel) + chargelevel = newlevel + add_overlay("ccharger-o[newlevel]") /obj/machinery/cell_charger/examine(mob/user) ..() diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index df64aeb832..8e5c83183d 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -388,7 +388,7 @@ flash_color(mob_occupant, flash_color="#960000", flash_time=100) to_chat(mob_occupant, "Agony blazes across your consciousness as your body is torn apart.
Is this what dying is like? Yes it is.
") playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 50, 0) - mob_occupant << sound('sound/hallucinations/veryfar_noise.ogg',0,1,50) + SEND_SOUND(mob_occupant, sound('sound/hallucinations/veryfar_noise.ogg',0,1,50)) QDEL_IN(mob_occupant, 40) /obj/machinery/clonepod/relaymove(mob/user) diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm index a288c9d51c..45c4142f09 100644 --- a/code/game/machinery/computer/apc_control.dm +++ b/code/game/machinery/computer/apc_control.dm @@ -116,24 +116,24 @@ authenticated = FALSE auth_id = "\[NULL\]" if(href_list["restore_logging"]) - to_chat(usr, "[bicon(src)] Logging functionality restored from backup data.") + to_chat(usr, "[icon2html(src, usr)] Logging functionality restored from backup data.") emagged = FALSE LAZYADD(logs, "-=- Logging restored to full functionality at this point -=-") if(href_list["access_apc"]) playsound(src, "terminal_type", 50, 0) var/obj/machinery/power/apc/APC = locate(href_list["access_apc"]) in GLOB.apcs_list if(!APC || APC.aidisabled || APC.panel_open || QDELETED(APC)) - to_chat(usr, "[bicon(src)] APC does not return interface request. Remote access may be disabled.") + to_chat(usr, "[icon2html(src, usr)] APC does not return interface request. Remote access may be disabled.") return if(active_apc) - to_chat(usr, "[bicon(src)] Disconnected from [active_apc].") + to_chat(usr, "[icon2html(src, usr)] Disconnected from [active_apc].") active_apc.say("Remote access canceled. Interface locked.") playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, 0) playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, 0) active_apc.locked = TRUE active_apc.update_icon() active_apc = null - to_chat(usr, "[bicon(src)] Connected to APC in [APC.area]. Interface request sent.") + to_chat(usr, "[icon2html(src, usr)] Connected to APC in [APC.area]. Interface request sent.") log_activity("remotely accessed APC in [APC.area]") APC.interact(usr, GLOB.not_incapacitated_state) playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index da8c7c43ca..480d446830 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -473,7 +473,6 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) if ("reg") if (authenticated) var/t2 = modify - //var/t1 = input(usr, "What name?", "ID computer", null) as text if ((authenticated && modify == t2 && (in_range(src, usr) || issilicon(usr)) && isturf(loc))) var/newName = reject_bad_name(href_list["reg"]) if(newName) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 47f38f0d87..eef44384d2 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -89,7 +89,7 @@ playsound(src, 'sound/machines/terminal_alert.ogg', 25, 0) if(prob(25)) for(var/mob/living/silicon/ai/AI in active_ais()) - AI << sound('sound/machines/terminal_alert.ogg', volume = 10) //Very quiet for balance reasons + SEND_SOUND(AI, sound('sound/machines/terminal_alert.ogg', volume = 10)) //Very quiet for balance reasons if("logout") authenticated = 0 playsound(src, 'sound/machines/terminal_off.ogg', 50, 0) diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm index 26a7d3b729..f71066f8dd 100644 --- a/code/game/machinery/computer/message.dm +++ b/code/game/machinery/computer/message.dm @@ -309,7 +309,7 @@ message = noserver else if(auth) - var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null) + var/dkey = trim(stripped_input(usr, "Please enter the decryption key.")) if(dkey && dkey != "") if(src.linkedServer.decryptkey == dkey) var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):")) @@ -414,10 +414,10 @@ customrecepient.tnote += "← From [customsender] ([customjob]):
[custommessage]
" if (!customrecepient.silent) playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1) - customrecepient.audible_message("[bicon(customrecepient)] *[customrecepient.ttone]*", null, 3) + customrecepient.audible_message("[icon2html(customrecepient, viewers(customrecepient))] *[customrecepient.ttone]*", null, 3) if( customrecepient.loc && ishuman(customrecepient.loc) ) var/mob/living/carbon/human/H = customrecepient.loc - to_chat(H, "[bicon(customrecepient)] Message from [customsender] ([customjob]), \"[custommessage]\" (Reply)") + to_chat(H, "[icon2html(customrecepient, viewers(H))] Message from [customsender] ([customjob]), \"[custommessage]\" (Reply)") log_talk(usr,"[key_name(usr)] (PDA: [customsender]) sent \"[custommessage]\" to [customrecepient.owner]",LOGPDA) customrecepient.cut_overlays() customrecepient.add_overlay(mutable_appearance('icons/obj/pda.dmi', "pda-r")) @@ -427,10 +427,10 @@ customrecepient.tnote += "← From [PDARec.owner] ([customjob]):
[custommessage]
" if (!customrecepient.silent) playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1) - customrecepient.audible_message("[bicon(customrecepient)] *[customrecepient.ttone]*", null, 3) + customrecepient.audible_message("[icon2html(customrecepient, viewers(customrecepient))] *[customrecepient.ttone]*", null, 3) if( customrecepient.loc && ishuman(customrecepient.loc) ) var/mob/living/carbon/human/H = customrecepient.loc - to_chat(H, "[bicon(customrecepient)] Message from [PDARec.owner] ([customjob]), \"[custommessage]\" (Reply)") + to_chat(H, "[icon2html(customrecepient, H)] Message from [PDARec.owner] ([customjob]), \"[custommessage]\" (Reply)") log_talk(usr,"[key_name(usr)] (PDA: [PDARec.owner]) sent \"[custommessage]\" to [customrecepient.owner]",LOGPDA) customrecepient.cut_overlays() customrecepient.add_overlay(mutable_appearance('icons/obj/pda.dmi', "pda-r")) diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm index 60ac43cb41..3f18cc29e9 100644 --- a/code/game/machinery/computer/pod.dm +++ b/code/game/machinery/computer/pod.dm @@ -21,7 +21,7 @@ return if(!connected) - viewers(null, null) << "Cannot locate mass driver connector. Cancelling firing sequence!" + say("Cannot locate mass driver connector. Cancelling firing sequence!") return for(var/obj/machinery/door/poddoor/M in range(range, src)) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 624d853808..94047727bc 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -233,9 +233,13 @@ return else /*if(src.justzap)*/ return - else if(user.hallucination > 50 && ishuman(user) && prob(10) && src.operating == FALSE) - hallucinate_shock(user) - return + else if(user.hallucinating() && ishuman(user) && prob(4) && !operating) + var/mob/living/carbon/human/H = user + if(H.gloves) + var/obj/item/clothing/gloves/G = H.gloves + if(G.siemens_coefficient)//not insulated + hallucinate_shock(H) + return if (cyclelinkedairlock) if (!shuttledocked && !emergency && !cyclelinkedairlock.shuttledocked && !cyclelinkedairlock.emergency && allowed(user)) if(cyclelinkedairlock.operating) diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index a3f2424a9a..a0086b7258 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -390,7 +390,7 @@ new /obj/effect/temp_visual/cult/sac(loc) var/atom/throwtarget throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(L, src))) - L << pick(sound('sound/hallucinations/turn_around1.ogg',0,1,50), sound('sound/hallucinations/turn_around2.ogg',0,1,50)) + SEND_SOUND(L, sound(pick('sound/hallucinations/turn_around1.ogg','sound/hallucinations/turn_around2.ogg'),0,1,50)) flash_color(L, flash_color="#960000", flash_time=20) L.Knockdown(40) L.throw_at(throwtarget, 5, 1,src) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 32e0e60fca..f9d530feac 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -445,7 +445,7 @@ Class Procs: /obj/machinery/proc/display_parts(mob/user) to_chat(user, "Following parts detected in the machine:") for(var/obj/item/C in component_parts) - to_chat(user, "[bicon(C)] [C.name]") + to_chat(user, "[icon2html(C, user)] [C.name]") /obj/machinery/examine(mob/user) ..() diff --git a/code/game/machinery/overview.dm b/code/game/machinery/overview.dm index ffcb36678a..545414577e 100644 --- a/code/game/machinery/overview.dm +++ b/code/game/machinery/overview.dm @@ -96,7 +96,8 @@ colour2 = rgb(255,128,0) if(ismob(AM)) - if(AM:client) + var/mob/M = AM + if(M.client) colour = rgb(255,0,0) else colour = rgb(255,128,128) @@ -146,7 +147,7 @@ var/icon/I2 = imap[2+(ix + icx*iy)*2] - //to_chat(world, "icon: [bicon(I)]") + //to_chat(world, "icon: [icon2html(I, world)]") I.DrawBox(colour, rx, ry, rx+1, ry+1) @@ -163,7 +164,7 @@ H.screen_loc = "[5 + i%icx],[6+ round(i/icx)]" - //to_chat(world, "[bicon(I)] at [H.screen_loc]") + //to_chat(world, "[icon2html(I, world)] at [H.screen_loc]") H.name = (i==0)?"maprefresh":"map" @@ -242,7 +243,8 @@ colour = rgb(255,255,0) if(ismob(AM)) - if(AM:client) + var/mob/M = AM + if(M.client) colour = rgb(255,0,0) else colour = rgb(255,128,128) @@ -274,7 +276,7 @@ var/icon/I = imap[1+(ix + icx*iy)] - //to_chat(world, "icon: [bicon(I)]") + //to_chat(world, "icon: [icon2html(I, world)]") I.DrawBox(colour, rx, ry, rx, ry) @@ -289,7 +291,7 @@ H.screen_loc = "[5 + i%icx],[6+ round(i/icx)]" - //to_chat(world, "[bicon(I)] at [H.screen_loc]") + //to_chat(world, "[icon2html(I, world)] at [H.screen_loc]") H.name = (i==0)?"maprefresh":"map" diff --git a/code/game/machinery/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm index 2183ec6448..20fd729304 100644 --- a/code/game/machinery/robot_fabricator.dm +++ b/code/game/machinery/robot_fabricator.dm @@ -11,31 +11,29 @@ idle_power_usage = 20 active_power_usage = 5000 -/obj/machinery/robotic_fabricator/attackby(obj/item/O, mob/user, params) +/obj/machinery/robotic_fabricator/attackby(obj/item/O, mob/living/user, params) if (istype(O, /obj/item/stack/sheet/metal)) - if (src.metal_amount < 150000) - var/count = 0 - src.add_overlay("fab-load-metal") - spawn(15) - if(O) - if(!O:amount) - return - while(metal_amount < 150000 && O:amount) - src.metal_amount += O:materials[MAT_METAL] /*O:height * O:width * O:length * 100000*/ - O:amount-- - count++ - - if (O:amount < 1) - qdel(O) - - to_chat(user, "You insert [count] metal sheet\s into \the [src].") - cut_overlay("fab-load-metal") - updateDialog() + if (metal_amount < 150000) + add_overlay("fab-load-metal") + addtimer(CALLBACK(src, .proc/FinishLoadingMetal, O, user), 15) else to_chat(user, "\The [src] is full.") else return ..() +/obj/machinery/robotic_fabricator/proc/FinishLoadingMetal(obj/item/stack/sheet/metal/M, mob/living/user) + cut_overlay("fab-load-metal") + if(QDELETED(M) || QDELETED(user)) + return + var/count = 0 + while(metal_amount < 150000 && !QDELETED(M)) + metal_amount += M.materials[MAT_METAL] + M.use(1) + count++ + + to_chat(user, "You insert [count] metal sheet\s into \the [src].") + updateDialog() + /obj/machinery/robotic_fabricator/power_change() if (powered()) stat &= ~NOPOWER diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 23ba93992c..c857ddaf16 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -12,7 +12,7 @@ /obj/structure/emergency_shield/Initialize() . = ..() - setDir(pick(1,2,3,4)) + setDir(pick(GLOB.cardinals)) air_update_turf(1) /obj/structure/emergency_shield/Destroy() diff --git a/code/game/machinery/shieldgen.dm.rej b/code/game/machinery/shieldgen.dm.rej new file mode 100644 index 0000000000..12ce2d21dc --- /dev/null +++ b/code/game/machinery/shieldgen.dm.rej @@ -0,0 +1,10 @@ +diff a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm (rejected hunks) +@@ -12,7 +12,7 @@ + + /obj/structure/emergency_shield/Initialize() + . = ..() +- setDir(pick(1,2,3,4)) ++ setDir(pick(GLOB.cardinals)) + air_update_turf(1) + + /obj/structure/emergency_shield/Destroy() diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index a2f97c3d54..4e96eb661d 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -207,14 +207,14 @@ var/new_timer = input(user, "Please set the timer.", "Timer", "[timer_set]") as num if(in_range(src, user) && isliving(user)) //No running off and setting bombs from across the station timer_set = Clamp(new_timer, minimum_timer, maximum_timer) - src.loc.visible_message("[bicon(src)] timer set for [timer_set] seconds.") + src.loc.visible_message("[icon2html(src, viewers(src))] timer set for [timer_set] seconds.") if(alert(user,"Would you like to start the countdown now?",,"Yes","No") == "Yes" && in_range(src, user) && isliving(user)) if(defused || active) if(defused) - src.loc.visible_message("[bicon(src)] Device error: User intervention required.") + src.loc.visible_message("[icon2html(src, viewers(src))] Device error: User intervention required.") return else - src.loc.visible_message("[bicon(src)] [timer_set] seconds until detonation, please clear the area.") + src.loc.visible_message("[icon2html(src, viewers(loc))] [timer_set] seconds until detonation, please clear the area.") activate() update_icon() add_fingerprint(user) @@ -330,7 +330,7 @@ var/obj/machinery/syndicatebomb/holder = loc if(istype(holder)) attempts++ - holder.loc.visible_message("[bicon(holder)] Alert: Bomb has detonated. Your score is now [defusals] for [attempts]. Resetting wires...") + holder.loc.visible_message("[icon2html(holder, viewers(holder))] Alert: Bomb has detonated. Your score is now [defusals] for [attempts]. Resetting wires...") reset() else qdel(src) @@ -340,7 +340,7 @@ if(istype(holder)) attempts++ defusals++ - holder.loc.visible_message("[bicon(holder)] Alert: Bomb has been defused. Your score is now [defusals] for [attempts]! Resetting wires in 5 seconds...") + holder.loc.visible_message("[icon2html(holder, viewers(holder))] Alert: Bomb has been defused. Your score is now [defusals] for [attempts]! Resetting wires in 5 seconds...") sleep(50) //Just in case someone is trying to remove the bomb core this gives them a little window to crowbar it out if(istype(holder)) reset() diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm index 4fdf06b530..1e7c2b9f20 100644 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -37,10 +37,7 @@ src.update_chassis_page() chassis.occupant_message("The [src] is destroyed!") chassis.log_append_to_last("[src] is destroyed.",1) - if(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon)) - chassis.occupant << sound('sound/mecha/weapdestr.ogg',volume=50) - else - chassis.occupant << sound('sound/mecha/critdestr.ogg',volume=50) + SEND_SOUND(chassis.occupant, sound(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon) ? 'sound/mecha/weapdestr.ogg' : 'sound/mecha/critdestr.ogg', volume=50)) chassis = null return ..() @@ -139,7 +136,7 @@ /obj/item/mecha_parts/mecha_equipment/proc/occupant_message(message) if(chassis) - chassis.occupant_message("[bicon(src)] [message]") + chassis.occupant_message("[icon2html(src, chassis.occupant)] [message]") return /obj/item/mecha_parts/mecha_equipment/proc/log_message(message) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 5564cd2c0a..28f2b0fb18 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -262,7 +262,7 @@ if(equipment && equipment.len) to_chat(user, "It's equipped with:") for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) - to_chat(user, "[bicon(ME)] [ME]") + to_chat(user, "[icon2html(ME, user)] [ME]") //processing internal damage, temperature, air regulation, alert updates, lights power use. /obj/mecha/process() @@ -596,7 +596,7 @@ /obj/mecha/proc/setInternalDamage(int_dam_flag) internal_damage |= int_dam_flag log_append_to_last("Internal damage of type [int_dam_flag].",1) - occupant << sound('sound/machines/warning-buzzer.ogg',wait=0) + SEND_SOUND(occupant, sound('sound/machines/warning-buzzer.ogg',wait=0)) diag_hud_set_mechstat() return @@ -636,7 +636,7 @@ var/can_control_mech = 0 for(var/obj/item/mecha_parts/mecha_tracking/ai_control/A in trackers) can_control_mech = 1 - to_chat(user, "[bicon(src)] Status of [name]:\n[A.get_mecha_info()]") + to_chat(user, "[icon2html(src, user)] Status of [name]:\n[A.get_mecha_info()]") break if(!can_control_mech) to_chat(user, "You cannot control exosuits without AI control beacons installed.") @@ -707,14 +707,14 @@ icon_state = initial(icon_state) playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) if(!internal_damage) - occupant << sound('sound/mecha/nominal.ogg',volume=50) + SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50)) AI.cancel_camera() AI.controlled_mech = src AI.remote_control = src AI.canmove = 1 //Much easier than adding AI checks! Be sure to set this back to 0 if you decide to allow an AI to leave a mech somehow. AI.can_shunt = 0 //ONE AI ENTERS. NO AI LEAVES. - to_chat(AI, "[AI.can_dominate_mechs ? "Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!" \ - : "You have been uploaded to a mech's onboard computer."]") + to_chat(AI, AI.can_dominate_mechs ? "Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!" :\ + "You have been uploaded to a mech's onboard computer.") to_chat(AI, "Use Middle-Mouse to activate mech functions and equipment. Click normally for AI interactions.") if(interaction == AI_TRANS_FROM_CARD) GrantActions(AI, FALSE) //No eject/return to core action for AI uploaded by card @@ -860,7 +860,7 @@ setDir(dir_in) playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) if(!internal_damage) - occupant << sound('sound/mecha/nominal.ogg',volume=50) + SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50)) return 1 else return 0 @@ -914,7 +914,7 @@ setDir(dir_in) log_message("[mmi_as_oc] moved in as pilot.") if(!internal_damage) - occupant << sound('sound/mecha/nominal.ogg',volume=50) + SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50)) GrantActions(brainmob) return TRUE @@ -1004,7 +1004,7 @@ /obj/mecha/proc/occupant_message(message as text) if(message) if(occupant && occupant.client) - to_chat(occupant, "[bicon(src)] [message]") + to_chat(occupant, "[icon2html(src, occupant)] [message]") return /obj/mecha/proc/log_message(message as text,red=null) diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm index 050498d8f1..4102ba914b 100644 --- a/code/game/mecha/mecha_actions.dm +++ b/code/game/mecha/mecha_actions.dm @@ -242,7 +242,7 @@ chassis.occupant_message("Zoom mode [chassis.zoom_mode?"en":"dis"]abled.") if(chassis.zoom_mode) owner.client.change_view(12) - owner << sound('sound/mecha/imag_enh.ogg',volume=50) + SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg',volume=50)) else owner.client.change_view(world.view) //world.view - default mob view size UpdateButtonIcon() diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index 5127aa2285..72a721911f 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -169,7 +169,7 @@ . += "You recognise the footprints as belonging to:\n" for(var/shoe in shoe_types) var/obj/item/clothing/shoes/S = shoe - . += "some [initial(S.name)] [bicon(initial(S.icon))]\n" + . += "some [initial(S.name)] [icon2html(initial(S.icon), user)]\n" to_chat(user, .) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index c9b524836f..80b291e571 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -22,7 +22,7 @@ /obj/effect/mine/proc/triggermine(mob/victim) if(triggered) return - visible_message("[victim] sets off [bicon(src)] [src]!") + visible_message("[victim] sets off [icon2html(src, viewers(src))] [src]!") var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread s.set_up(3, 1, src) s.start() @@ -121,13 +121,13 @@ if(!victim.client || !istype(victim)) return to_chat(victim, "RIP AND TEAR") - victim << 'sound/misc/e1m1.ogg' + SEND_SOUND(victim, sound('sound/misc/e1m1.ogg')) var/old_color = victim.client.color var/red_splash = list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0) var/pure_red = list(0,0,0,0,0,0,0,0,0,1,0,0) spawn(0) - new /obj/effect/hallucination/delusion(victim.loc,victim,"demon",duration,0) + new /datum/hallucination/delusion(victim, TRUE, "demon",duration,0) var/obj/item/weapon/twohanded/required/chainsaw/doomslayer/chainsaw = new(victim.loc) chainsaw.flags |= NODROP diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index bca1ccce81..9097d8add4 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -558,7 +558,7 @@ GLOBAL_LIST_EMPTY(PDAs) if (!silent) playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) - audible_message("[bicon(src)] *[ttone]*", null, 3) + audible_message("[icon2html(src, hearers(src))] *[ttone]*", null, 3) //Search for holder of the PDA. var/mob/living/L = null if(loc && isliving(loc)) @@ -575,7 +575,7 @@ GLOBAL_LIST_EMPTY(PDAs) hrefstart = "" hrefend = "" - to_chat(L, "[\bicon(src)] Message from [hrefstart][source.owner] ([source.ownjob])[hrefend], \"[msg.message]\"[msg.get_photo_ref()] (Reply)") + to_chat(L, "[icon2html(src)] Message from [hrefstart][source.owner] ([source.ownjob])[hrefend], \"[msg.message]\"[msg.get_photo_ref()] (Reply)") update_icon() add_overlay(icon_alert) diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index e5bca7eeac..f32f707204 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -88,27 +88,27 @@ if(isliving(loc)) var/mob/living/M = loc if(!emagged) - to_chat(M, "[bicon(src)] RADIATION PULSE DETECTED.") - to_chat(M, "[bicon(src)] Severity: [amount]") + to_chat(M, "[icon2html(src, M)] RADIATION PULSE DETECTED.") + to_chat(M, "[icon2html(src, M)] Severity: [amount]") else - to_chat(M, "[bicon(src)] !@%$AT!(N P!LS! D/TEC?ED.") - to_chat(M, "[bicon(src)] &!F2rity: <=[amount]#1") + to_chat(M, "[icon2html(src, M)] !@%$AT!(N P!LS! D/TEC?ED.") + to_chat(M, "[icon2html(src, M)] &!F2rity: <=[amount]#1") update_icon() /obj/item/device/geiger_counter/attack_self(mob/user) scanning = !scanning update_icon() - to_chat(user, "[bicon(src)] You switch [scanning ? "on" : "off"] [src].") + to_chat(user, "[icon2html(src, user)] You switch [scanning ? "on" : "off"] [src].") /obj/item/device/geiger_counter/attack(mob/living/M, mob/user) if(user.a_intent == INTENT_HELP) if(!emagged) user.visible_message("[user] scans [M] with [src].", "You scan [M]'s radiation levels with [src]...") if(!M.radiation) - to_chat(user, "[bicon(src)] Radiation levels within normal boundaries.") + to_chat(user, "[icon2html(src, user)] Radiation levels within normal boundaries.") return 1 else - to_chat(user, "[bicon(src)] Subject is irradiated. Radiation levels: [M.radiation].") + to_chat(user, "[icon2html(src, user)] Subject is irradiated. Radiation levels: [M.radiation].") return 1 else user.visible_message("[user] scans [M] with [src].", "You project [src]'s stored radiation into [M]'s body!") diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 3d7e575215..ae84bd2f2c 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -147,7 +147,7 @@ MASS SPECTROMETER if (M.getCloneLoss()) to_chat(user, "\tSubject appears to have [M.getCloneLoss() > 30 ? "severe" : "minor"] cellular damage.") if (M.reagents && M.reagents.get_reagent_amount("epinephrine")) - to_chat(user, "\tBloodstream analysis located [M.reagents:get_reagent_amount("epinephrine")] units of rejuvenation chemicals.") + to_chat(user, "\tBloodstream analysis located [M.reagents.get_reagent_amount("epinephrine")] units of rejuvenation chemicals.") if (M.getBrainLoss() >= 100 || !M.getorgan(/obj/item/organ/brain)) to_chat(user, "\tSubject brain function is non-existent.") else if (M.getBrainLoss() >= 60) diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index c21ff386bd..4663e2142a 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -8,7 +8,7 @@ desc = "Regulates the transfer of air between two tanks" var/obj/item/weapon/tank/tank_one var/obj/item/weapon/tank/tank_two - var/obj/item/device/attached_device + var/obj/item/device/assembly/attached_device var/mob/attacher = null var/valve_open = FALSE var/toggle = 1 @@ -99,8 +99,8 @@ toggle_valve() else if(attached_device) if(href_list["rem_device"]) - attached_device.loc = get_turf(src) - attached_device:holder = null + attached_device.forceMove(get_turf(src)) + attached_device.holder = null attached_device = null update_icon() if(href_list["device"]) diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index 285225d6f1..1bd66b6a38 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -12,7 +12,7 @@ novariants = FALSE GLOBAL_LIST_INIT(human_recipes, list( \ - new/datum/stack_recipe("bloated human costume", /obj/item/clothing/suit/hooded/bloated_human, 5, on_floor = 1), \ + new/datum/stack_recipe("bloated human costume", /obj/item/clothing/suit/hooded/bloated_human, 5), \ )) /obj/item/stack/sheet/animalhide/human/Initialize(mapload, new_amount, merge = TRUE) @@ -33,7 +33,7 @@ GLOBAL_LIST_INIT(human_recipes, list( \ icon_state = "sheet-corgi" GLOBAL_LIST_INIT(corgi_recipes, list ( \ - new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3, on_floor = 1), \ + new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3), \ )) /obj/item/stack/sheet/animalhide/corgi/Initialize(mapload, new_amount, merge = TRUE) @@ -53,8 +53,8 @@ GLOBAL_LIST_INIT(corgi_recipes, list ( \ icon_state = "sheet-monkey" GLOBAL_LIST_INIT(monkey_recipes, list ( \ - new/datum/stack_recipe("monkey mask", /obj/item/clothing/mask/gas/monkeymask, 1, on_floor = 1), \ - new/datum/stack_recipe("monkey suit", /obj/item/clothing/suit/monkeysuit, 2, on_floor = 1), \ + new/datum/stack_recipe("monkey mask", /obj/item/clothing/mask/gas/monkeymask, 1), \ + new/datum/stack_recipe("monkey suit", /obj/item/clothing/suit/monkeysuit, 2), \ )) /obj/item/stack/sheet/animalhide/monkey/Initialize(mapload, new_amount, merge = TRUE) @@ -74,8 +74,8 @@ GLOBAL_LIST_INIT(monkey_recipes, list ( \ icon_state = "sheet-xeno" GLOBAL_LIST_INIT(xeno_recipes, list ( \ - new/datum/stack_recipe("alien helmet", /obj/item/clothing/head/xenos, 1, on_floor = 1), \ - new/datum/stack_recipe("alien suit", /obj/item/clothing/suit/xenos, 2, on_floor = 1), \ + new/datum/stack_recipe("alien helmet", /obj/item/clothing/head/xenos, 1), \ + new/datum/stack_recipe("alien suit", /obj/item/clothing/suit/xenos, 2), \ )) /obj/item/stack/sheet/animalhide/xeno/Initialize(mapload, new_amount, merge = TRUE) @@ -161,7 +161,7 @@ GLOBAL_LIST_INIT(leather_recipes, list ( \ GLOBAL_LIST_INIT(sinew_recipes, list ( \ - new/datum/stack_recipe("sinew restraints", /obj/item/weapon/restraints/handcuffs/sinew, 1, on_floor = 1), \ + new/datum/stack_recipe("sinew restraints", /obj/item/weapon/restraints/handcuffs/sinew, 1), \ )) /obj/item/stack/sheet/sinew/Initialize(mapload, new_amount, merge = TRUE) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 348c6620cd..daaadeb797 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -527,7 +527,7 @@ return list(pick(messages)) /obj/item/toy/talking/proc/toy_talk(mob/user, message) - user.loc.visible_message("[bicon(src)] [message]") + user.loc.visible_message("[icon2html(src, viewers(user.loc))] [message]") if(chattering) chatter(message, phomeme, user) @@ -1082,7 +1082,7 @@ user.visible_message("[user] pulls back the string on [src].") icon_state = "[initial(icon_state)]_used" sleep(5) - audible_message("[bicon(src)] Hiss!") + audible_message("[icon2html(src, viewers(src))] Hiss!") var/list/possible_sounds = list('sound/voice/hiss1.ogg', 'sound/voice/hiss2.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss4.ogg') var/chosen_sound = pick(possible_sounds) playsound(get_turf(src), chosen_sound, 50, 1) diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index 6f2310303b..66e3e0317f 100644 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -525,7 +525,7 @@ AI MODULES laws[1] = generate_ion_law() to_chat(user, "You press the button on [src].") playsound(user, 'sound/machines/click.ogg', 20, 1) - src.loc.visible_message("[bicon(src)] [laws[1]]") + src.loc.visible_message("[icon2html(src, viewers(loc))] [laws[1]]") /******************** Mother Drone ******************/ diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 3f89e593d5..e4a69dfab7 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -106,7 +106,7 @@ update_label() /obj/item/weapon/card/id/attack_self(mob/user) - user.visible_message("[user] shows you: [bicon(src)] [src.name].", \ + user.visible_message("[user] shows you: [icon2html(src, viewers(user))] [src.name].", \ "You show \the [src.name].") src.add_fingerprint(user) return diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm index 0e6d6cc66f..1829538a01 100755 --- a/code/game/objects/items/weapons/flamethrower.dm +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -26,6 +26,7 @@ var/create_full = FALSE var/create_with_tank = FALSE var/igniter_type = /obj/item/device/assembly/igniter + trigger_guard = TRIGGER_GUARD_NORMAL /obj/item/weapon/flamethrower/Destroy() if(weldtool) @@ -69,12 +70,7 @@ if(flag) return // too close if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.dna.check_mutation(HULK)) - to_chat(user, "Your meaty finger is much too large for the trigger guard!") - return - if(NOGUNS in H.dna.species.species_traits) - to_chat(user, "Your fingers don't fit in the trigger guard!") + if(!can_trigger_gun(user)) return if(user && user.get_active_held_item() == src) // Make sure our user is still holding us var/turf/target_turf = get_turf(target) diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index 802c2d499a..40fa7d2520 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -90,8 +90,8 @@ desc = "Looks like some cables tied together. Could be used to tie something up." icon_state = "cuff_red" item_state = "coil_red" - lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' - righthand_file = 'icons/mob/inhands/items_righthand.dmi' + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' materials = list(MAT_METAL=150, MAT_GLASS=75) origin_tech = "engineering=2" breakouttime = 300 //Deciseconds = 30s @@ -145,9 +145,7 @@ /obj/item/weapon/restraints/handcuffs/cable/white icon_state = "cuff_white" - item_state = "cuff_white" - lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' + item_state = "coil_white" /obj/item/weapon/restraints/handcuffs/alien icon_state = "handcuffAlien" @@ -212,7 +210,6 @@ name = "zipties" desc = "Plastic, disposable zipties that can be used to restrain temporarily but are destroyed after use." icon_state = "cuff_white" - item_state = "cuff_white" lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' materials = list() @@ -222,6 +219,7 @@ /obj/item/weapon/restraints/handcuffs/cable/zipties/used desc = "A pair of broken zipties." icon_state = "cuff_white_used" + item_state = "cuff_white" /obj/item/weapon/restraints/handcuffs/cable/zipties/used/attack() return diff --git a/code/game/objects/items/weapons/his_grace.dm b/code/game/objects/items/weapons/his_grace.dm index c43e1600b6..5b57fab800 100644 --- a/code/game/objects/items/weapons/his_grace.dm +++ b/code/game/objects/items/weapons/his_grace.dm @@ -20,12 +20,14 @@ var/prev_bloodthirst = HIS_GRACE_SATIATED var/force_bonus = 0 -/obj/item/weapon/his_grace/New() - ..() +/obj/item/weapon/his_grace/Initialize() + . = ..() START_PROCESSING(SSprocessing, src) + GLOB.poi_list += src /obj/item/weapon/his_grace/Destroy() STOP_PROCESSING(SSprocessing, src) + GLOB.poi_list -= src for(var/mob/living/L in src) L.forceMove(get_turf(src)) return ..() diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm index 238022d209..8e1cf3301e 100644 --- a/code/game/objects/items/weapons/holy_weapons.dm +++ b/code/game/objects/items/weapons/holy_weapons.dm @@ -320,6 +320,8 @@ desc = "Particularly twisted dieties grant gifts of dubious value." icon_state = "arm_blade" item_state = "arm_blade" + lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi' + righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi' flags = ABSTRACT | NODROP w_class = WEIGHT_CLASS_HUGE sharpness = IS_SHARP diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm index 2ded74b536..5d32856bc9 100644 --- a/code/game/objects/items/weapons/melee/misc.dm +++ b/code/game/objects/items/weapons/melee/misc.dm @@ -209,8 +209,8 @@ origin_tech = "combat=7;materials=6" force_string = "INFINITE" -/obj/item/weapon/melee/supermatter_sword/New() - ..() +/obj/item/weapon/melee/supermatter_sword/Initialize() + . = ..() shard = new /obj/machinery/power/supermatter_shard(src) qdel(shard.countdown) shard.countdown = null diff --git a/code/game/objects/items/weapons/pneumaticCannon.dm b/code/game/objects/items/weapons/pneumaticCannon.dm index d2f5714d5e..ab61e7b916 100644 --- a/code/game/objects/items/weapons/pneumaticCannon.dm +++ b/code/game/objects/items/weapons/pneumaticCannon.dm @@ -26,6 +26,7 @@ var/fire_mode = PCANNON_FIREALL var/automatic = FALSE var/clumsyCheck = TRUE + trigger_guard = TRIGGER_GUARD_NORMAL /obj/item/weapon/pneumatic_cannon/CanItemAutoclick() return automatic @@ -37,10 +38,10 @@ out += "You'll need to get closer to see any more." return for(var/obj/item/I in loadedItems) - out += "[bicon(I)] It has \the [I] loaded." + out += "[icon2html(I, user)] It has \the [I] loaded." CHECK_TICK if(tank) - out += "[bicon(tank)] It has \the [tank] mounted onto it." + out += "[icon2html(tank, user)] It has \the [tank] mounted onto it." to_chat(user, out.Join("
")) /obj/item/weapon/pneumatic_cannon/attackby(obj/item/weapon/W, mob/user, params) @@ -108,11 +109,7 @@ if(!istype(user) && !target) return var/discharge = 0 - if(user.dna.check_mutation(HULK)) - to_chat(user, "Your meaty finger is much too large for the trigger guard!") - return - if(NOGUNS in user.dna.species.species_traits) - to_chat(user, "Your fingers don't fit in the trigger guard!") + if(!can_trigger_gun(user)) return if(!loadedItems || !loadedWeightClass) to_chat(user, "\The [src] has nothing loaded.") diff --git a/code/game/objects/items/weapons/powerfist.dm b/code/game/objects/items/weapons/powerfist.dm index 256cdc0433..77d7784852 100644 --- a/code/game/objects/items/weapons/powerfist.dm +++ b/code/game/objects/items/weapons/powerfist.dm @@ -26,7 +26,7 @@ to_chat(user, "You'll need to get closer to see any more.") return if(tank) - to_chat(user, "[bicon(tank)] It has \the [tank] mounted onto it.") + to_chat(user, "[icon2html(tank, user)] It has \the [tank] mounted onto it.") /obj/item/weapon/melee/powerfist/attackby(obj/item/weapon/W, mob/user, params) diff --git a/code/game/objects/items/weapons/sharpener.dm b/code/game/objects/items/weapons/sharpener.dm index ace66060af..881832b5bb 100644 --- a/code/game/objects/items/weapons/sharpener.dm +++ b/code/game/objects/items/weapons/sharpener.dm @@ -12,31 +12,31 @@ /obj/item/weapon/sharpener/attackby(obj/item/I, mob/user, params) if(used) - to_chat(user, "The sharpening block is too worn to use again.") + to_chat(user, "The sharpening block is too worn to use again!") return if(I.force >= max || I.throwforce >= max)//no esword sharpening - to_chat(user, "[I] is much too powerful to sharpen further.") + to_chat(user, "[I] is much too powerful to sharpen further!") return if(requires_sharpness && !I.sharpness) - to_chat(user, "You can only sharpen items that are already sharp, such as knives.") + to_chat(user, "You can only sharpen items that are already sharp, such as knives!") return if(istype(I, /obj/item/weapon/melee/transforming/energy)) - to_chat(user, "You don't think \the [I] will be the thing getting modified if you use it on \the [src].") + to_chat(user, "You don't think \the [I] will be the thing getting modified if you use it on \the [src]!") return if(istype(I, /obj/item/weapon/twohanded))//some twohanded items should still be sharpenable, but handle force differently. therefore i need this stuff var/obj/item/weapon/twohanded/TH = I if(TH.force_wielded >= max) - to_chat(user, "[TH] is much too powerful to sharpen further.") + to_chat(user, "[TH] is much too powerful to sharpen further!") return if(TH.wielded) - to_chat(user, "[TH] must be unwielded before it can be sharpened.") + to_chat(user, "[TH] must be unwielded before it can be sharpened!") return if(TH.force_wielded > initial(TH.force_wielded)) - to_chat(user, "[TH] has already been refined before. It cannot be sharpened further.") + to_chat(user, "[TH] has already been refined before. It cannot be sharpened further!") return TH.force_wielded = Clamp(TH.force_wielded + increment, 0, max)//wieldforce is increased since normal force wont stay if(I.force > initial(I.force)) - to_chat(user, "[I] has already been refined before. It cannot be sharpened further.") + to_chat(user, "[I] has already been refined before. It cannot be sharpened further!") return user.visible_message("[user] sharpens [I] with [src]!", "You sharpen [I], making it much more deadly than before.") I.sharpness = IS_SHARP_ACCURATE @@ -46,6 +46,7 @@ name = "worn out [name]" desc = "[desc] At least, it used to." used = 1 + update_icon() /obj/item/weapon/sharpener/super name = "super whetstone" diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index ee6b2ea2c2..53bfe5d64c 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -1,4 +1,5 @@ /obj/item/weapon + var/trigger_guard = TRIGGER_GUARD_NONE /obj/item/weapon/banhammer desc = "A banhammer" @@ -77,8 +78,8 @@ var/notches = 0 //HOW MANY PEOPLE HAVE BEEN SLAIN WITH THIS BLADE var/obj/item/weapon/disk/nuclear/nuke_disk //OUR STORED NUKE DISK -/obj/item/weapon/claymore/highlander/New() - ..() +/obj/item/weapon/claymore/highlander/Initialize() + . = ..() START_PROCESSING(SSobj, src) /obj/item/weapon/claymore/highlander/Destroy() @@ -540,7 +541,7 @@ return 1 /obj/item/weapon/melee/flyswatter - name = "Flyswatter" + name = "flyswatter" desc = "Useful for killing insects of all sizes." icon = 'icons/obj/weapons.dmi' icon_state = "flyswatter" @@ -555,8 +556,8 @@ //Things in this list will be instantly splatted. Flyman weakness is handled in the flyman species weakness proc. var/list/strong_against -/obj/item/weapon/melee/flyswatter/New() - ..() +/obj/item/weapon/melee/flyswatter/Initialize() + . = ..() strong_against = typecacheof(list( /mob/living/simple_animal/hostile/poison/bees/, /mob/living/simple_animal/butterfly, @@ -584,3 +585,8 @@ throwforce = 0 flags = DROPDEL | ABSTRACT attack_verb = list("bopped") + +/obj/item/weapon/proc/can_trigger_gun(mob/living/user) + if(!user.can_use_guns(src)) + return FALSE + return TRUE \ No newline at end of file diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm index 24e70059af..bfd3dea037 100644 --- a/code/game/objects/structures/fireaxe.dm +++ b/code/game/objects/structures/fireaxe.dm @@ -12,8 +12,8 @@ max_integrity = 150 integrity_failure = 50 -/obj/structure/fireaxecabinet/New() - ..() +/obj/structure/fireaxecabinet/Initialize() + . = ..() update_icon() /obj/structure/fireaxecabinet/Destroy() diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index e478ff5d92..d141f71b7a 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -1,12 +1,13 @@ /obj/structure/flora resistance_flags = FLAMMABLE + obj_integrity = 150 max_integrity = 150 - anchored = TRUE + anchored = 1 //trees /obj/structure/flora/tree name = "tree" - density = TRUE + density = 1 pixel_x = -16 layer = FLY_LAYER var/cut = FALSE @@ -25,7 +26,7 @@ playsound(get_turf(src), 'sound/effects/meteorimpact.ogg', 100 , 0, 0) icon = 'icons/obj/flora/pinetrees.dmi' icon_state = "tree_stump" - density = FALSE + density = 0 pixel_x = -16 name += " stump" cut = TRUE @@ -45,14 +46,14 @@ /obj/structure/flora/tree/pine/Initialize() icon_state = "pine_[rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/tree/pine/xmas name = "xmas tree" icon_state = "pine_c" /obj/structure/flora/tree/pine/xmas/Initialize() - ..() + . = ..() icon_state = "pine_c" /obj/structure/flora/tree/dead @@ -64,7 +65,7 @@ icon_state = "palm1" /obj/structure/flora/tree/palm/Initialize() - ..() + . = ..() icon_state = pick("palm1","palm2") pixel_x = 0 @@ -76,7 +77,7 @@ /obj/structure/flora/tree/dead/Initialize() icon_state = "tree_[rand(1, 6)]" - ..() + . = ..() /obj/structure/flora/tree/jungle name = "tree" @@ -88,12 +89,7 @@ /obj/structure/flora/tree/jungle/Initialize() icon_state = "[icon_state][rand(1, 6)]" - ..() - -/obj/structure/flora/tree/jungle/small - pixel_y = 0 - pixel_x = -32 - icon = 'icons/obj/flora/jungletreesmall.dmi' + . = ..() //grass /obj/structure/flora/grass @@ -106,7 +102,7 @@ /obj/structure/flora/grass/brown/Initialize() icon_state = "snowgrass[rand(1, 3)]bb" - ..() + . = ..() /obj/structure/flora/grass/green @@ -114,14 +110,14 @@ /obj/structure/flora/grass/green/Initialize() icon_state = "snowgrass[rand(1, 3)]gb" - ..() + . = ..() /obj/structure/flora/grass/both icon_state = "snowgrassall1" /obj/structure/flora/grass/both/Initialize() icon_state = "snowgrassall[rand(1, 3)]" - ..() + . = ..() //bushes @@ -129,11 +125,11 @@ name = "bush" icon = 'icons/obj/flora/snowflora.dmi' icon_state = "snowbush1" - anchored = TRUE + anchored = 1 /obj/structure/flora/bush/Initialize() icon_state = "snowbush[rand(1, 6)]" - ..() + . = ..() //newbushes @@ -145,112 +141,112 @@ /obj/structure/flora/ausbushes/Initialize() if(icon_state == "firstbush_1") icon_state = "firstbush_[rand(1, 4)]" - ..() + . = ..() /obj/structure/flora/ausbushes/reedbush icon_state = "reedbush_1" /obj/structure/flora/ausbushes/reedbush/Initialize() icon_state = "reedbush_[rand(1, 4)]" - ..() + . = ..() /obj/structure/flora/ausbushes/leafybush icon_state = "leafybush_1" /obj/structure/flora/ausbushes/leafybush/Initialize() icon_state = "leafybush_[rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/ausbushes/palebush icon_state = "palebush_1" /obj/structure/flora/ausbushes/palebush/Initialize() icon_state = "palebush_[rand(1, 4)]" - ..() + . = ..() /obj/structure/flora/ausbushes/stalkybush icon_state = "stalkybush_1" /obj/structure/flora/ausbushes/stalkybush/Initialize() icon_state = "stalkybush_[rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/ausbushes/grassybush icon_state = "grassybush_1" /obj/structure/flora/ausbushes/grassybush/Initialize() icon_state = "grassybush_[rand(1, 4)]" - ..() + . = ..() /obj/structure/flora/ausbushes/fernybush icon_state = "fernybush_1" /obj/structure/flora/ausbushes/fernybush/Initialize() icon_state = "fernybush_[rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/ausbushes/sunnybush icon_state = "sunnybush_1" /obj/structure/flora/ausbushes/sunnybush/Initialize() icon_state = "sunnybush_[rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/ausbushes/genericbush icon_state = "genericbush_1" /obj/structure/flora/ausbushes/genericbush/Initialize() icon_state = "genericbush_[rand(1, 4)]" - ..() + . = ..() /obj/structure/flora/ausbushes/pointybush icon_state = "pointybush_1" /obj/structure/flora/ausbushes/pointybush/Initialize() icon_state = "pointybush_[rand(1, 4)]" - ..() + . = ..() /obj/structure/flora/ausbushes/lavendergrass icon_state = "lavendergrass_1" /obj/structure/flora/ausbushes/lavendergrass/Initialize() icon_state = "lavendergrass_[rand(1, 4)]" - ..() + . = ..() /obj/structure/flora/ausbushes/ywflowers icon_state = "ywflowers_1" /obj/structure/flora/ausbushes/ywflowers/Initialize() icon_state = "ywflowers_[rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/ausbushes/brflowers icon_state = "brflowers_1" /obj/structure/flora/ausbushes/brflowers/Initialize() icon_state = "brflowers_[rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/ausbushes/ppflowers icon_state = "ppflowers_1" /obj/structure/flora/ausbushes/ppflowers/Initialize() icon_state = "ppflowers_[rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/ausbushes/sparsegrass icon_state = "sparsegrass_1" /obj/structure/flora/ausbushes/sparsegrass/Initialize() icon_state = "sparsegrass_[rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/ausbushes/fullgrass icon_state = "fullgrass_1" /obj/structure/flora/ausbushes/fullgrass/Initialize() icon_state = "fullgrass_[rand(1, 3)]" - ..() + . = ..() /obj/item/weapon/twohanded/required/kirbyplants name = "potted plant" @@ -308,10 +304,10 @@ desc = "A volcanic rock" icon = 'icons/obj/flora/rocks.dmi' resistance_flags = FIRE_PROOF - density = TRUE + density = 1 /obj/structure/flora/rock/Initialize() - ..() + . = ..() icon_state = "[icon_state][rand(1,3)]" /obj/structure/flora/rock/pile @@ -319,7 +315,7 @@ desc = "A pile of rocks" /obj/structure/flora/rock/pile/Initialize() - ..() + . = ..() icon_state = "[icon_state][rand(1,3)]" //Jungle grass @@ -333,7 +329,7 @@ /obj/structure/flora/grass/jungle/Initialize() icon_state = "[icon_state][rand(1, 5)]" - ..() + . = ..() /obj/structure/flora/grass/jungle/b icon_state = "grassb" @@ -348,7 +344,7 @@ density = FALSE /obj/structure/flora/rock/jungle/Initialize() - ..() + . = ..() icon_state = "[initial(icon_state)][rand(1,5)]" @@ -361,7 +357,7 @@ /obj/structure/flora/junglebush/Initialize() icon_state = "[icon_state][rand(1, 3)]" - ..() + . = ..() /obj/structure/flora/junglebush/b icon_state = "bushb" diff --git a/code/game/objects/structures/flora.dm.rej b/code/game/objects/structures/flora.dm.rej new file mode 100644 index 0000000000..8257ec2122 --- /dev/null +++ b/code/game/objects/structures/flora.dm.rej @@ -0,0 +1,28 @@ +diff a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm (rejected hunks) +@@ -89,7 +89,7 @@ + + /obj/structure/flora/tree/jungle/Initialize() + icon_state = "[icon_state][rand(1, 6)]" +- ..() ++ . = ..() + + //grass + /obj/structure/flora/grass +@@ -307,7 +307,7 @@ + density = 1 + + /obj/structure/flora/rock/Initialize() +- ..() ++ . = ..() + icon_state = "[icon_state][rand(1,3)]" + + /obj/structure/flora/rock/pile +@@ -381,5 +381,5 @@ + pixel_y = -16 + + /obj/structure/flora/rock/pile/largejungle/Initialize() +- ..() +- icon_state = "[initial(icon_state)][rand(1,3)]" +\ No newline at end of file ++ . = ..() ++ icon_state = "[initial(icon_state)][rand(1,3)]" diff --git a/code/game/objects/structures/manned_turret.dm b/code/game/objects/structures/manned_turret.dm index 323927af77..7448aa128f 100644 --- a/code/game/objects/structures/manned_turret.dm +++ b/code/game/objects/structures/manned_turret.dm @@ -85,7 +85,7 @@ calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(controller, C.mouseParams) /obj/machinery/manned_turret/proc/direction_track(mob/user, atom/targeted) - if(user.stat != CONSCIOUS) + if(user.incapacitated()) return setDir(get_dir(src,targeted)) user.setDir(dir) @@ -125,7 +125,7 @@ /obj/machinery/manned_turret/proc/checkfire(atom/targeted_atom, mob/user) target = targeted_atom - if(target == user || target == get_turf(src)) + if(target == user || user.incapacitated() || target == get_turf(src)) return if(world.time < cooldown) if(!warned && world.time > (cooldown - cooldown_duration + rate_of_fire*number_of_shots)) // To capture the window where one is done firing @@ -143,6 +143,8 @@ addtimer(CALLBACK(src, /obj/machinery/manned_turret/.proc/fire_helper, user), i*rate_of_fire) /obj/machinery/manned_turret/proc/fire_helper(mob/user) + if(user.incapacitated()) + return update_positioning() //REFRESH MOUSE TRACKING!! var/turf/targets_from = get_turf(src) if(QDELETED(target)) diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm index 9a25da9019..f6b044a0da 100644 --- a/code/game/objects/structures/signs.dm +++ b/code/game/objects/structures/signs.dm @@ -321,6 +321,6 @@ icon_state = "direction_bridge" /obj/structure/sign/logo - name = "station logo" - desc = "A sign: SPACE STATION 13." - icon_state = "ss13sign-1" \ No newline at end of file + name = "nanotrasen logo" + desc = "The Nanotrasen corporate logo." + icon_state = "ss13sign-1" diff --git a/code/game/objects/structures/signs.dm.rej b/code/game/objects/structures/signs.dm.rej new file mode 100644 index 0000000000..51eea8f290 --- /dev/null +++ b/code/game/objects/structures/signs.dm.rej @@ -0,0 +1,11 @@ +diff a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm (rejected hunks) +@@ -326,6 +326,6 @@ + icon_state = "direction_bridge" + + /obj/structure/sign/logo +- name = "station logo" +- desc = "A sign: SPACE STATION 13." ++ name = "nanotrasen logo" ++ desc = "The Nanotrasen corporate logo." + icon_state = "nanotrasen_sign1" +\ No newline at end of file diff --git a/code/game/objects/weapons.dm b/code/game/objects/weapons.dm index 0598d88a59..69c6c89870 100644 --- a/code/game/objects/weapons.dm +++ b/code/game/objects/weapons.dm @@ -2,8 +2,8 @@ name = "weapon" icon = 'icons/obj/weapons.dmi' -/obj/item/weapon/New() - ..() +/obj/item/weapon/Initialize() + . = ..() if(!hitsound) if(damtype == "fire") hitsound = 'sound/items/welder.ogg' diff --git a/code/game/sound.dm b/code/game/sound.dm index c728071e50..ff35915b08 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -78,7 +78,7 @@ S.y = 1 S.falloff = (falloff ? falloff : FALLOFF_SOUNDS) - src << S + SEND_SOUND(src, S) /proc/sound_to_playing_players(sound, volume = 100, vary) sound = get_sfx(sound) @@ -94,13 +94,13 @@ next_channel = 1 /mob/proc/stop_sound_channel(chan) - src << sound(null, repeat = 0, wait = 0, channel = chan) + SEND_SOUND(src, sound(null, repeat = 0, wait = 0, channel = chan)) /client/proc/playtitlemusic() UNTIL(SSticker.login_music) //wait for SSticker init to set the login music if(prefs && (prefs.toggles & SOUND_LOBBY)) - src << sound(SSticker.login_music, repeat = 0, wait = 0, volume = 85, channel = CHANNEL_LOBBYMUSIC) // MAD JAMS + SEND_SOUND(src, sound(SSticker.login_music, repeat = 0, wait = 0, volume = 85, channel = CHANNEL_LOBBYMUSIC) // MAD JAMS) /proc/get_rand_frequency() return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs. @@ -175,7 +175,3 @@ 'sound/vore/prey/death_07.ogg','sound/vore/prey/death_08.ogg','sound/vore/prey/death_09.ogg', 'sound/vore/prey/death_10.ogg') return soundin - -/proc/playsound_global(file, repeat = 0, wait, channel, volume) - for(var/V in GLOB.clients) - V << sound(file, repeat, wait, channel, volume) diff --git a/code/game/sound.dm.rej b/code/game/sound.dm.rej new file mode 100644 index 0000000000..003c8b9975 --- /dev/null +++ b/code/game/sound.dm.rej @@ -0,0 +1,9 @@ +diff a/code/game/sound.dm b/code/game/sound.dm (rejected hunks) +@@ -145,7 +145,3 @@ + if ("can_open") + soundin = pick('sound/effects/can_open1.ogg', 'sound/effects/can_open2.ogg', 'sound/effects/can_open3.ogg') + return soundin +- +-/proc/playsound_global(file, repeat = 0, wait, channel, volume) +- for(var/V in GLOB.clients) +- V << sound(file, repeat, wait, channel, volume) diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 82ff907a04..a990530056 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -18,6 +18,7 @@ var/sound /turf/open/indestructible/sound/Entered(var/mob/AM) + ..() if(istype(AM)) playsound(src,sound,50,1) diff --git a/code/game/turfs/simulated/chasm.dm b/code/game/turfs/simulated/chasm.dm index 968e782984..a51240c969 100644 --- a/code/game/turfs/simulated/chasm.dm +++ b/code/game/turfs/simulated/chasm.dm @@ -22,6 +22,7 @@ return /turf/open/chasm/Entered(atom/movable/AM) + ..() START_PROCESSING(SSobj, src) drop_stuff(AM) diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm index ec84bff35d..9eb5337768 100644 --- a/code/game/turfs/simulated/floor/plating/asteroid.dm +++ b/code/game/turfs/simulated/floor/plating/asteroid.dm @@ -104,7 +104,18 @@ return /turf/open/floor/plating/asteroid/singularity_pull(S, current_size) - return + if(dug) + return + switch(current_size) + if(STAGE_THREE) + if(!prob(30)) + gets_dug() + if(STAGE_FOUR) + if(prob(50)) + gets_dug() + else + if(current_size >= STAGE_FIVE && prob(70)) + gets_dug() /turf/open/floor/plating/asteroid/basalt diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm index c7e6973c4d..b877fa9eac 100644 --- a/code/game/turfs/space/transit.dm +++ b/code/game/turfs/space/transit.dm @@ -25,6 +25,7 @@ dir = EAST /turf/open/space/transit/Entered(atom/movable/AM, atom/OldLoc) + ..() if(!locate(/obj/structure/lattice) in src) throw_atom(AM) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index b204406d05..ed76b7704e 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -160,8 +160,15 @@ return TRUE //Nothing found to block so return success! /turf/Entered(atom/movable/AM) + ..() if(explosion_level && AM.ex_check(explosion_id)) AM.ex_act(explosion_level) + + // If an opaque movable atom moves around we need to potentially update visibility. + if (AM.opacity) + has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. + reconsider_lights() + /turf/open/Entered(atom/movable/AM) ..() diff --git a/code/game/turfs/turf.dm.rej b/code/game/turfs/turf.dm.rej new file mode 100644 index 0000000000..1c4472c18a --- /dev/null +++ b/code/game/turfs/turf.dm.rej @@ -0,0 +1,13 @@ +diff a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm (rejected hunks) +@@ -163,6 +163,11 @@ + if(explosion_level && AM.ex_check(explosion_id)) + AM.ex_act(explosion_level) + ++ // If an opaque movable atom moves around we need to potentially update visibility. ++ if (AM.opacity) ++ has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. ++ reconsider_lights() ++ + /turf/open/Entered(atom/movable/AM) + ..() + //melting diff --git a/code/game/world.dm b/code/game/world.dm new file mode 100644 index 0000000000..f5b45a46ca --- /dev/null +++ b/code/game/world.dm @@ -0,0 +1,292 @@ +/world/New() + log_world("World loaded at [time_stamp()]") + + SetupExternalRSC() + + GLOB.config_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = file("data/logs/config_error.log") //temporary file used to record errors with loading config, moved to log directory once logging is set bl + + make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) + + config = new + + CheckSchemaVersion() + SetRoundID() + + SetupLogs() + + if(!RunningService()) //tgs2 support + GLOB.revdata.DownloadPRDetails() + + load_motd() + load_admins() + LoadVerbs(/datum/verbs/menu) + if(config.usewhitelist) + load_whitelist() + LoadBans() + + GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000 + + Master.Initialize(10, FALSE) + + if(config.irc_announce_new_game) + IRCBroadcast("New round starting on [SSmapping.config.map_name]!") + +/world/proc/SetupExternalRSC() +#if (PRELOAD_RSC == 0) + external_rsc_urls = world.file2list("config/external_rsc_urls.txt","\n") + var/i=1 + while(i<=external_rsc_urls.len) + if(external_rsc_urls[i]) + i++ + else + external_rsc_urls.Cut(i,i+1) +#endif + +/world/proc/CheckSchemaVersion() + if(config.sql_enabled) + if(SSdbcore.Connect()) + log_world("Database connection established.") + var/datum/DBQuery/query_db_version = SSdbcore.NewQuery("SELECT major, minor FROM [format_table_name("schema_revision")] ORDER BY date DESC LIMIT 1") + query_db_version.Execute() + if(query_db_version.NextRow()) + var/db_major = text2num(query_db_version.item[1]) + var/db_minor = text2num(query_db_version.item[2]) + if(db_major < DB_MAJOR_VERSION || db_minor < DB_MINOR_VERSION) + message_admins("Database schema ([db_major].[db_minor]) is behind latest schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors") + log_sql("Database schema ([db_major].[db_minor]) is behind latest schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors") + else + message_admins("Could not get schema version from database") + else + log_world("Your server failed to establish a connection with the database.") + +/world/proc/SetRoundID() + if(config.sql_enabled) + if(SSdbcore.Connect()) + var/datum/DBQuery/query_round_start = SSdbcore.NewQuery("INSERT INTO [format_table_name("round")] (start_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')") + query_round_start.Execute() + var/datum/DBQuery/query_round_last_id = SSdbcore.NewQuery("SELECT LAST_INSERT_ID()") + query_round_last_id.Execute() + if(query_round_last_id.NextRow()) + GLOB.round_id = query_round_last_id.item[1] + +/world/proc/SetupLogs() + GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-" + if(GLOB.round_id) + GLOB.log_directory += "[GLOB.round_id]" + else + GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]" + GLOB.world_game_log = file("[GLOB.log_directory]/game.log") + GLOB.world_attack_log = file("[GLOB.log_directory]/attack.log") + GLOB.world_runtime_log = file("[GLOB.log_directory]/runtime.log") + GLOB.world_href_log = file("[GLOB.log_directory]/hrefs.html") + WRITE_FILE(GLOB.world_game_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------") + WRITE_FILE(GLOB.world_attack_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------") + WRITE_FILE(GLOB.world_runtime_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------") + GLOB.changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently + if(fexists(GLOB.config_error_log)) + fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log") + fdel(GLOB.config_error_log) + + if(GLOB.round_id) + log_game("Round ID: [GLOB.round_id]") + +/world/Topic(T, addr, master, key) + var/list/input = params2list(T) + + var/pinging = ("ping" in input) + var/playing = ("players" in input) + + if(!pinging && !playing && config && config.log_world_topic) + WRITE_FILE(GLOB.world_game_log, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]") + + if(input[SERVICE_CMD_PARAM_KEY]) + return ServiceCommand(input) + var/key_valid = (global.comms_allowed && input["key"] == global.comms_key) + + if(pinging) + var/x = 1 + for (var/client/C in GLOB.clients) + x++ + return x + + else if(playing) + var/n = 0 + for(var/mob/M in GLOB.player_list) + if(M.client) + n++ + return n + + else if("ircstatus" in input) //tgs2 support + var/static/last_irc_status = 0 + if(world.time - last_irc_status < 50) + return + var/list/adm = get_admin_counts() + var/list/allmins = adm["total"] + var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). " + status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode.name]." + send2irc("Status", status) + last_irc_status = world.time + + else if("status" in input) + var/list/s = list() + s["version"] = GLOB.game_version + s["mode"] = GLOB.master_mode + s["respawn"] = config ? GLOB.abandon_allowed : 0 + s["enter"] = GLOB.enter_allowed + s["vote"] = config.allow_vote_mode + s["ai"] = config.allow_ai + s["host"] = host ? host : null + s["active_players"] = get_active_player_count() + s["players"] = GLOB.clients.len + s["revision"] = GLOB.revdata.commit + s["revision_date"] = GLOB.revdata.date + + var/list/adm = get_admin_counts() + var/list/presentmins = adm["present"] + var/list/afkmins = adm["afk"] + s["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho + s["gamestate"] = SSticker.current_state + + s["map_name"] = SSmapping.config.map_name + + if(key_valid && SSticker.HasRoundStarted()) + s["real_mode"] = SSticker.mode.name + // Key-authed callers may know the truth behind the "secret" + + s["security_level"] = get_security_level() + s["round_duration"] = SSticker ? round((world.time-SSticker.round_start_time)/10) : 0 + // Amount of world's ticks in seconds, useful for calculating round duration + + if(SSshuttle && SSshuttle.emergency) + s["shuttle_mode"] = SSshuttle.emergency.mode + // Shuttle status, see /__DEFINES/stat.dm + s["shuttle_timer"] = SSshuttle.emergency.timeLeft() + // Shuttle timer, in seconds + + return list2params(s) + + else if("announce" in input) + if(!key_valid) + return "Bad Key" + else + AnnouncePR(input["announce"], json_decode(input["payload"])) + + else if("crossmessage" in input) + if(!key_valid) + return + else + if(input["crossmessage"] == "Ahelp") + relay_msg_admins("HELP: [input["source"]] [input["message_sender"]]: [input["message"]]") + if(input["crossmessage"] == "Comms_Console") + minor_announce(input["message"], "Incoming message from [input["message_sender"]]") + for(var/obj/machinery/computer/communications/CM in GLOB.machines) + CM.overrideCooldown() + if(input["crossmessage"] == "News_Report") + minor_announce(input["message"], "Breaking Update From [input["message_sender"]]") + + else if("adminmsg" in input) //tgs2 support + if(!key_valid) + return "Bad Key" + else + return IrcPm(input["adminmsg"],input["msg"],input["sender"]) + + else if("namecheck" in input) //tgs2 support + if(!key_valid) + return "Bad Key" + else + log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]") + message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]") + return keywords_lookup(input["namecheck"],1) + else if("adminwho" in input) //tgs2 support + if(!key_valid) + return "Bad Key" + else + return ircadminwho() + else if("server_hop" in input) + show_server_hop_transfer_screen(input["server_hop"]) + +/world/proc/AnnouncePR(announcement, list/payload) + var/static/list/PRcounts = list() //PR id -> number of times announced this round + var/id = "[payload["pull_request"]["id"]]" + if(!PRcounts[id]) + PRcounts[id] = 1 + else + ++PRcounts[id] + if(PRcounts[id] > PR_ANNOUNCEMENTS_PER_ROUND) + return + + var/final_composed = "PR: [announcement]" + for(var/client/C in GLOB.clients) + C.AnnouncePR(final_composed) + +/world/Reboot(reason = 0, fast_track = FALSE) + ServiceReboot() //handles alternative actions if necessary + if (reason || fast_track) //special reboot, do none of the normal stuff + if (usr) + log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools") + message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools") + to_chat(world, "Rebooting World immediately due to host request") + else + to_chat(world, "Rebooting world...") + Master.Shutdown() //run SS shutdowns + log_world("World rebooted at [time_stamp()]") + ..() + +/world/proc/load_motd() + GLOB.join_motd = file2text("config/motd.txt") + "
" + GLOB.revdata.GetTestMergeInfo() + +/world/proc/update_status() + var/s = "" + + if (config && config.server_name) + s += "[config.server_name] — " + + s += "[station_name()]"; + s += " (" + s += "" //Change this to wherever you want the hub to link to. + s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version. + s += "" + s += ")" + + var/list/features = list() + + if(GLOB.master_mode) + features += GLOB.master_mode + + if (!GLOB.enter_allowed) + features += "closed" + + features += GLOB.abandon_allowed ? "respawn" : "no respawn" + + if (config && config.allow_vote_mode) + features += "vote" + + if (config && config.allow_ai) + features += "AI allowed" + + var/n = 0 + for (var/mob/M in GLOB.player_list) + if (M.client) + n++ + + if (n > 1) + features += "~[n] players" + else if (n > 0) + features += "~[n] player" + + if (!host && config && config.hostedby) + features += "hosted by [config.hostedby]" + + if (features) + s += ": [jointext(features, ", ")]" + + status = s + +/world/proc/update_hub_visibility(new_visibility) + if(new_visibility == GLOB.hub_visibility) + return + GLOB.hub_visibility = new_visibility + if(GLOB.hub_visibility) + hub_password = "kMZy3U5jJHSiBQjr" + else + hub_password = "SORRYNOPASSWORD" diff --git a/code/modules/admin/DB_ban/functions.dm b/code/modules/admin/DB_ban/functions.dm index 23bf656b8c..e580b306b3 100644 --- a/code/modules/admin/DB_ban/functions.dm +++ b/code/modules/admin/DB_ban/functions.dm @@ -83,10 +83,10 @@ var/a_computerid var/a_ip - if(src.owner && istype(src.owner, /client)) - a_ckey = src.owner:ckey - a_computerid = src.owner:computer_id - a_ip = src.owner:address + if(istype(owner)) + a_ckey = owner.ckey + a_computerid = owner.computer_id + a_ip = owner.address if(blockselfban) if(a_ckey == ckey) @@ -309,12 +309,12 @@ to_chat(usr, "Database update failed due to multiple bans having the same ID. Contact the database admin.") return - if(!src.owner || !istype(src.owner, /client)) + if(!istype(owner)) return - var/unban_ckey = src.owner:ckey - var/unban_computerid = src.owner:computer_id - var/unban_ip = src.owner:address + var/unban_ckey = owner.ckey + var/unban_computerid = owner.computer_id + var/unban_ip = owner.address var/sql_update = "UPDATE [format_table_name("ban")] SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = '[unban_ckey]', unbanned_computerid = '[unban_computerid]', unbanned_ip = INET_ATON('[unban_ip]') WHERE id = [id]" var/datum/DBQuery/query_unban = SSdbcore.NewQuery(sql_update) diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm index 1ff2360923..5ea980a91d 100644 --- a/code/modules/admin/NewBan.dm +++ b/code/modules/admin/NewBan.dm @@ -109,14 +109,14 @@ GLOBAL_PROTECT(Banlist) else GLOB.Banlist.dir.Add("[ckey][computerid]") GLOB.Banlist.cd = "/base/[ckey][computerid]" - GLOB.Banlist["key"] << ckey - GLOB.Banlist["id"] << computerid - GLOB.Banlist["ip"] << address - GLOB.Banlist["reason"] << reason - GLOB.Banlist["bannedby"] << bannedby - GLOB.Banlist["temp"] << temp + WRITE_FILE(GLOB.Banlist["key"], ckey) + WRITE_FILE(GLOB.Banlist["id"], computerid) + WRITE_FILE(GLOB.Banlist["ip"], address) + WRITE_FILE(GLOB.Banlist["reason"], reason) + WRITE_FILE(GLOB.Banlist["bannedby"], bannedby) + WRITE_FILE(GLOB.Banlist["temp"], temp) if (temp) - GLOB.Banlist["minutes"] << bantimestamp + WRITE_FILE(GLOB.Banlist["minutes"], bantimestamp) if(!temp) create_message("note", ckey, bannedby, "Permanently banned - [reason]", null, null, 0, 0) else @@ -211,17 +211,17 @@ GLOBAL_PROTECT(Banlist) GLOB.Banlist.cd = "/base" GLOB.Banlist.dir.Add("trash[i]trashid[i]") GLOB.Banlist.cd = "/base/trash[i]trashid[i]" - GLOB.Banlist["key"] << "trash[i]" + WRITE_FILE(GLOB.Banlist["key"], "trash[i]") else GLOB.Banlist.cd = "/base" GLOB.Banlist.dir.Add("[last]trashid[i]") GLOB.Banlist.cd = "/base/[last]trashid[i]" - GLOB.Banlist["key"] << last - GLOB.Banlist["id"] << "trashid[i]" - GLOB.Banlist["reason"] << "Trashban[i]." - GLOB.Banlist["temp"] << a - GLOB.Banlist["minutes"] << GLOB.CMinutes + rand(1,2000) - GLOB.Banlist["bannedby"] << "trashmin" + WRITE_FILE(GLOB.Banlist["key"], last) + WRITE_FILE(GLOB.Banlist["id"], "trashid[i]") + WRITE_FILE(GLOB.Banlist["reason"], "Trashban[i].") + WRITE_FILE(GLOB.Banlist["temp"], a) + WRITE_FILE(GLOB.Banlist["minutes"], GLOB.CMinutes + rand(1,2000)) + WRITE_FILE(GLOB.Banlist["bannedby"], "trashmin") last = "trash[i]" GLOB.Banlist.cd = "/base" diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 7c20421d3c..5943e753a0 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -595,7 +595,7 @@ log_admin("[key_name(usr)] delayed the round start.") else to_chat(world, "The game will start in [newtime] seconds.") - world << 'sound/ai/attention.ogg' + SEND_SOUND(world, sound('sound/ai/attention.ogg')) log_admin("[key_name(usr)] set the pre-game delay to [newtime] seconds.") SSblackbox.add_details("admin_verb","Delay Game Start") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index 54feb11532..2ca0593e8d 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -5,7 +5,7 @@ F << "[time_stamp()] \ref[src] ([x],[y],[z]) || [src] [message]
" -/client/proc/investigate_show(subject in list("hrefs","notes, memos, watchlist", INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY) ) +/client/proc/investigate_show(subject in list("hrefs","notes, memos, watchlist", INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS) ) set name = "Investigate" set category = "Admin" if(!holder) diff --git a/code/modules/admin/admin_investigate.dm.rej b/code/modules/admin/admin_investigate.dm.rej new file mode 100644 index 0000000000..d58adb0f78 --- /dev/null +++ b/code/modules/admin/admin_investigate.dm.rej @@ -0,0 +1 @@ +garbage \ No newline at end of file diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index 73c2d8067e..828fbb2e91 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -142,7 +142,7 @@ GLOBAL_PROTECT(admin_ranks) else if(!SSdbcore.Connect()) log_world("Failed to connect to database in load_admin_ranks(). Reverting to legacy system.") - GLOB.world_game_log << "Failed to connect to database in load_admin_ranks(). Reverting to legacy system." + WRITE_FILE(GLOB.world_game_log, "Failed to connect to database in load_admin_ranks(). Reverting to legacy system.") config.admin_legacy_system = 1 load_admin_ranks() return @@ -220,7 +220,7 @@ GLOBAL_PROTECT(admin_ranks) else if(!SSdbcore.Connect()) log_world("Failed to connect to database in load_admins(). Reverting to legacy system.") - GLOB.world_game_log << "Failed to connect to database in load_admins(). Reverting to legacy system." + WRITE_FILE(GLOB.world_game_log, "Failed to connect to database in load_admins(). Reverting to legacy system.") config.admin_legacy_system = 1 load_admins() return diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 68e5430a09..3276a319db 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -12,11 +12,13 @@ GLOBAL_LIST_INIT(admin_verbs_default, world.AVerbsDefault()) /client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/ /client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/ /client/proc/secrets, + /client/proc/toggle_hear_radio, /*allows admins to hide all radio output*/ /client/proc/reload_admins, /client/proc/reestablish_db_connection, /*reattempt a connection to the database*/ /client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/ /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ /client/proc/cmd_admin_ticket_panel, + /client/proc/panicbunker, /client/proc/stop_sounds ) GLOBAL_PROTECT(admin_verbs_admin) @@ -114,7 +116,6 @@ GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer()) /client/proc/toggle_random_events, /client/proc/forcerandomrotate, /client/proc/adminchangemap, - /client/proc/panicbunker, /client/proc/toggle_hub ) GLOBAL_PROTECT(admin_verbs_debug) diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index c3185c7b21..04a4b7877a 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -390,7 +390,7 @@ SSblackbox.add_details("admin_secrets_fun_used","Chinese Cartoons") message_admins("[key_name_admin(usr)] made everything kawaii.") for(var/mob/living/carbon/human/H in GLOB.mob_list) - H << sound('sound/ai/animes.ogg') + SEND_SOUND(H, sound('sound/ai/animes.ogg')) if(H.dna.species.id == "human") if(H.dna.features["tail_human"] == "None" || H.dna.features["ears"] == "None") diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 818b0d6f09..ac047429c8 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -6,7 +6,7 @@ log_admin("[key_name(usr)] tried to use the admin panel without authorization.") return if(href_list["ahelp"]) - if(!check_rights(R_ADMIN)) + if(!check_rights(R_ADMIN, TRUE)) return var/ahelp_ref = href_list["ahelp"] @@ -506,10 +506,10 @@ ban_unban_log_save("[key_name(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") message_admins("[key_name_admin(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") GLOB.Banlist.cd = "/base/[banfolder]" - GLOB.Banlist["reason"] << reason - GLOB.Banlist["temp"] << temp - GLOB.Banlist["minutes"] << minutes - GLOB.Banlist["bannedby"] << usr.ckey + WRITE_FILE(GLOB.Banlist["reason"], reason) + WRITE_FILE(GLOB.Banlist["temp"], temp) + WRITE_FILE(GLOB.Banlist["minutes"], minutes) + WRITE_FILE(GLOB.Banlist["bannedby"], usr.ckey) GLOB.Banlist.cd = "/base" SSblackbox.inc("ban_edit",1) unbanpanel() @@ -1697,7 +1697,7 @@ message_admins("[key_name(H)] got their cookie, spawned by [key_name(src.owner)].") SSblackbox.inc("admin_cookies_spawned",1) to_chat(H, "Your prayers have been answered!! You received the best cookie!") - H << 'sound/effects/pray_chaplain.ogg' + SEND_SOUND(H, sound('sound/effects/pray_chaplain.ogg')) else if(href_list["adminsmite"]) if(!check_rights(R_ADMIN|R_FUN)) diff --git a/code/modules/admin/verbs/BrokenInhands.dm b/code/modules/admin/verbs/BrokenInhands.dm index 89eccf285d..732ae9e91c 100644 --- a/code/modules/admin/verbs/BrokenInhands.dm +++ b/code/modules/admin/verbs/BrokenInhands.dm @@ -28,7 +28,7 @@ if(text) var/F = file("broken_icons.txt") fdel(F) - F << text + WRITE_FILE(F, text) to_chat(world, "Completely successfully and written to [F]") diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 0177798e25..b19c736e14 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -194,7 +194,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) AddInteraction("[key_name_admin(usr)] PM'd [LinkedReplyName()]") message_admins("Ticket [TicketHref("#[id]")] created") else - MessageNoRecipient(parsed_message) + MessageNoRecipient(msg, parsed_message) //send it to irc if nobody is on and tell us how many were on var/admin_number_present = send2irc_adminless_only(initiator_ckey, "Ticket #[id]: [name]") @@ -249,18 +249,19 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) //message from the initiator without a target, all admins will see this //won't bug irc -/datum/admin_help/proc/MessageNoRecipient(msg) +/datum/admin_help/proc/MessageNoRecipient(msg, parsed_msg) var/ref_src = "\ref[src]" - var/chat_msg = "Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]: [msg]" + //Message to be sent to all admins + var/admin_msg = "Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]: [parsed_msg]" AddInteraction("[LinkedReplyName(ref_src)]: [msg]") + //send this msg to all admins - for(var/client/X in GLOB.admins) if(X.prefs.toggles & SOUND_ADMINHELP) - X << 'sound/effects/adminhelp.ogg' + SEND_SOUND(X, sound('sound/effects/adminhelp.ogg')) window_flash(X, ignorepref = TRUE) - to_chat(X, chat_msg) + to_chat(X, admin_msg) //show it to the person adminhelping too to_chat(initiator, "PM to-Admins: [msg]") @@ -346,7 +347,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(initiator) initiator.giveadminhelpverb() - initiator << 'sound/effects/adminhelp.ogg' + SEND_SOUND(initiator, sound('sound/effects/adminhelp.ogg')) to_chat(initiator, "- AdminHelp Rejected! -") to_chat(initiator, "Your admin help was rejected. The adminhelp verb has been returned to you so that you may try again.") diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index 7f4dd3ebb9..ec1091bb3c 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -84,11 +84,11 @@ var/list/keys = list() for(var/mob/M in GLOB.player_list) keys += M.client - var/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys) + var/client/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys) if(!selection) to_chat(src, "No keys found.") return - var/mob/M = selection:mob + var/mob/M = selection.mob log_admin("[key_name(usr)] jumped to [key_name(M)]") message_admins("[key_name_admin(usr)] jumped to [key_name_admin(M)]") diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 31fb08da36..db29021463 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -167,7 +167,7 @@ //play the recieving admin the adminhelp sound (if they have them enabled) if(recipient.prefs.toggles & SOUND_ADMINHELP) - recipient << 'sound/effects/adminhelp.ogg' + SEND_SOUND(recipient, sound('sound/effects/adminhelp.ogg')) else if(holder) //sender is an admin but recipient is not. Do BIG RED TEXT @@ -182,7 +182,7 @@ admin_ticket_log(recipient, "PM From [key_name_admin(src)]: [keywordparsedmsg]") //always play non-admin recipients the adminhelp sound - recipient << 'sound/effects/adminhelp.ogg' + SEND_SOUND(recipient, sound('sound/effects/adminhelp.ogg')) //AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn if(config.popup_admin_pm) @@ -301,7 +301,7 @@ window_flash(C, ignorepref = TRUE) //always play non-admin recipients the adminhelp sound - C << 'sound/effects/adminhelp.ogg' + SEND_SOUND(C, 'sound/effects/adminhelp.ogg') C.ircreplyamount = IRCREPLYCOUNT diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index c69628c625..66438d1fac 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -316,10 +316,8 @@ GLOBAL_PROTECT(AdminProcCallCount) alert("Wait until the game starts") return if(ishuman(M)) - log_admin("[key_name(src)] has alienized [M.key].") - spawn(0) - M:Alienize() - SSblackbox.add_details("admin_verb","Make Alien") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + INVOKE_ASYNC(M, /mob/living/carbon/human/proc/Alienize) + SSblackbox.add_details("admin_verb","Make Alien") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! log_admin("[key_name(usr)] made [key_name(M)] into an alien.") message_admins("[key_name_admin(usr)] made [key_name(M)] into an alien.") else @@ -333,10 +331,8 @@ GLOBAL_PROTECT(AdminProcCallCount) alert("Wait until the game starts") return if(ishuman(M)) - log_admin("[key_name(src)] has slimeized [M.key].") - spawn(0) - M:slimeize() - SSblackbox.add_details("admin_verb","Make Slime") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + INVOKE_ASYNC(M, /mob/living/carbon/human/proc/slimeize) + SSblackbox.add_details("admin_verb","Make Slime") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! log_admin("[key_name(usr)] made [key_name(M)] into a slime.") message_admins("[key_name_admin(usr)] made [key_name(M)] into a slime.") else @@ -461,12 +457,14 @@ GLOBAL_PROTECT(AdminProcCallCount) if(worn) if(istype(worn, /obj/item/device/pda)) - worn:id = id - id.loc = worn + var/obj/item/device/pda/PDA = worn + PDA.id = id + id.forceMove(PDA) else if(istype(worn, /obj/item/weapon/storage/wallet)) - worn:front_id = id - id.loc = worn - worn.update_icon() + var/obj/item/weapon/storage/wallet/W = worn + W.front_id = id + id.forceMove(W) + W.update_icon() else H.equip_to_slot(id,slot_wear_id) diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm index 15b619f653..a4482154d8 100644 --- a/code/modules/admin/verbs/diagnostics.dm +++ b/code/modules/admin/verbs/diagnostics.dm @@ -78,8 +78,9 @@ continue output += "  [filters[filter]]: [f.len]
" for (var/device in f) - if (isobj(device)) - output += "    [device] ([device:x],[device:y],[device:z] in area [get_area(device:loc)])
" + if (istype(device, /atom)) + var/atom/A = device + output += "    [device] ([A.x],[A.y],[A.z] in area [get_area(device)])
" else output += "    [device]
" diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm index fe3fe61b3f..9f08eb5e0e 100644 --- a/code/modules/admin/verbs/getlogs.dm +++ b/code/modules/admin/verbs/getlogs.dm @@ -13,7 +13,17 @@ return message_admins("[key_name_admin(src)] accessed file: [path]") - src << ftp(file(path)) + //this is copypasta because making it a proc would mean locking out adminproccalls, + // and that system is buggy enough with false positives that I don't want to risk locking admins out of legit calls. + switch(alert("View (in game), Open (in your system's text editor), or Download file [path]?", "Log File Opening", "View", "Open", "Download")) + if ("View") + src << browse("
[html_encode(file2text(file(path)))]
", list2params(list("window" = "viewfile.[path]"))) + if ("Open") + src << run(file(path)) + if ("Download") + src << ftp(file(path)) + else + return to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") return @@ -27,7 +37,15 @@ set desc = "Shows server log for this round." if(fexists("[GLOB.world_game_log]")) - src << ftp(GLOB.world_game_log) + switch(alert("View (in game), Open (in your system's text editor), or Download file [GLOB.world_game_log]?", "Log File Opening", "View", "Open", "Download")) + if ("View") + src << browse("
[html_encode(file2text(GLOB.world_game_log))]
", list2params(list("window" = "viewfile.[GLOB.world_game_log]"))) + if ("Open") + src << run(GLOB.world_game_log) + if ("Download") + src << ftp(GLOB.world_game_log) + else + return else to_chat(src, "Server log not found, try using .getserverlog.") return @@ -41,7 +59,15 @@ set desc = "Shows server attack log for this round." if(fexists("[GLOB.world_attack_log]")) - src << ftp(GLOB.world_attack_log) + switch(alert("View (in game), Open (in your system's text editor), or Download file [GLOB.world_attack_log]?", "Log File Opening", "View", "Open", "Download")) + if ("View") + src << browse("
[html_encode(file2text(GLOB.world_attack_log))]
", list2params(list("window" = "viewfile.[GLOB.world_attack_log]"))) + if ("Open") + src << run(GLOB.world_attack_log) + if ("Download") + src << ftp(GLOB.world_attack_log) + else + return else to_chat(src, "Server attack log not found, try using .getserverlog.") return diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index eb4c3a5f10..2bac326710 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -30,7 +30,7 @@ for(var/mob/M in GLOB.player_list) if(M.client.prefs.toggles & SOUND_MIDI) - M << admin_sound + SEND_SOUND(M, admin_sound) SSblackbox.add_details("admin_verb","Play Global Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -68,5 +68,5 @@ message_admins("[key_name_admin(src)] stopped all currently playing sounds.") for(var/mob/M in GLOB.player_list) if(M.client) - M << sound(null) + SEND_SOUND(M, sound(null)) SSblackbox.add_details("admin_verb","Stop All Playing Sounds") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index 1b2fa82e20..bbe1c48b6a 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -33,14 +33,14 @@ prayer_type = "CULTIST PRAYER" deity = "Nar-Sie" - msg = "[bicon(cross)][prayer_type][deity ? " (to [deity])" : ""]: [ADMIN_FULLMONTY(src)] [ADMIN_SC(src)]: [msg]" + msg = "[icon2html(cross, GLOB.admins)][prayer_type][deity ? " (to [deity])" : ""]: [ADMIN_FULLMONTY(src)] [ADMIN_SC(src)]: [msg]" for(var/client/C in GLOB.admins) if(C.prefs.chat_toggles & CHAT_PRAYER) to_chat(C, msg) if(C.prefs.toggles & SOUND_PRAYERS) if(usr.job == "Chaplain") - C << 'sound/effects/pray.ogg' + SEND_SOUND(C, sound('sound/effects/pray.ogg')) to_chat(usr, "Your prayers have been received by the gods.") SSblackbox.add_details("admin_verb","Prayer") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm index 2853fefcbf..6cd8efdd1d 100644 --- a/code/modules/assembly/bomb.dm +++ b/code/modules/assembly/bomb.dm @@ -44,7 +44,8 @@ qdel(src) return - if((istype(W, /obj/item/weapon/weldingtool) && W:welding)) + var/obj/item/weapon/weldingtool/WT = W + if((istype(WT) && WT.welding)) if(!status) status = TRUE GLOB.bombers += "[key_name(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]" @@ -63,7 +64,7 @@ return /obj/item/device/onetankbomb/receive_signal() //This is mainly called by the sensor through sense() to the holder, and from the holder to here. - visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*") + visible_message("[icon2html(src, viewers(src))] *beep* *beep*", "*beep* *beep*") sleep(10) if(!src) return diff --git a/code/modules/assembly/health.dm b/code/modules/assembly/health.dm index b454cbacfb..180cb55db6 100644 --- a/code/modules/assembly/health.dm +++ b/code/modules/assembly/health.dm @@ -59,7 +59,7 @@ health_scan = M.health if(health_scan <= alarm_health) pulse() - audible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*") + audible_message("[icon2html(src, hearers(src))] *beep* *beep*", "*beep* *beep*") toggle_scan() return return diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index be1659546f..c196e984a2 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -99,7 +99,7 @@ if(!secured || !on || next_activate > world.time) return FALSE pulse(0) - audible_message("[bicon(src)] *beep* *beep*", null, 3) + audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 3) next_activate = world.time + 30 /obj/item/device/assembly/infra/interact(mob/user)//TODO: change this this to the wire control panel diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 9cf534f975..556979070d 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -56,7 +56,7 @@ if(!secured || next_activate > world.time) return 0 pulse(0) - audible_message("[bicon(src)] *beep* *beep*", null, 3) + audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 3) next_activate = world.time + 30 diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index b3f25ac8cf..7c8efb14d5 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -143,7 +143,7 @@ Code: if(!(src.wires & WIRE_RADIO_RECEIVE)) return 0 pulse(1) - audible_message("[bicon(src)] *beep* *beep*", null, 1) + audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 1) return diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 8938ecbe9d..9a959bc544 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -45,7 +45,7 @@ if(!secured || next_activate > world.time) return FALSE pulse(0) - audible_message("[bicon(src)] *beep* *beep*", null, 3) + audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 3) if(loop) timing = 1 update_icon() diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index d733dfc3fb..a45536430a 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -189,8 +189,9 @@ #define CONNECTED 2 #define EMPTY 4 #define LOW 8 -#define FULL 16 -#define DANGER 32 +#define MEDIUM 16 +#define FULL 32 +#define DANGER 64 /obj/machinery/portable_atmospherics/canister/update_icon() if(stat & BROKEN) cut_overlays() @@ -207,9 +208,11 @@ var/pressure = air_contents.return_pressure() if(pressure < 10) update |= EMPTY - else if(pressure < ONE_ATMOSPHERE) + else if(pressure < 5 * ONE_ATMOSPHERE) update |= LOW - else if(pressure < 15 * ONE_ATMOSPHERE) + else if(pressure < 10 * ONE_ATMOSPHERE) + update |= MEDIUM + else if(pressure < 40 * ONE_ATMOSPHERE) update |= FULL else update |= DANGER @@ -222,9 +225,9 @@ add_overlay("can-open") if(update & CONNECTED) add_overlay("can-connector") - if(update & EMPTY) + if(update & LOW) add_overlay("can-o0") - else if(update & LOW) + else if(update & MEDIUM) add_overlay("can-o1") else if(update & FULL) add_overlay("can-o2") @@ -234,6 +237,7 @@ #undef CONNECTED #undef EMPTY #undef LOW +#undef MEDIUM #undef FULL #undef DANGER diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm index 33f822ac2b..cd48386d62 100644 --- a/code/modules/cargo/console.dm +++ b/code/modules/cargo/console.dm @@ -145,7 +145,7 @@ var/reason = "" if(requestonly) - reason = input("Reason:", name, "") as text|null + reason = stripped_input("Reason:", name, "") if(isnull(reason) || ..()) return diff --git a/code/modules/cargo/console.dm.rej b/code/modules/cargo/console.dm.rej new file mode 100644 index 0000000000..e8798f179a --- /dev/null +++ b/code/modules/cargo/console.dm.rej @@ -0,0 +1,10 @@ +diff a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm (rejected hunks) +@@ -145,7 +145,7 @@ + + var/reason = "" + if(requestonly) +- reason = stripped_input("Reason:", name, "") as text|null ++ reason = stripped_input("Reason:", name, "") + if(isnull(reason) || ..()) + return + diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index 81fecc6dda..4f576dd3e7 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -138,6 +138,13 @@ You can set verify to TRUE if you want send() to sleep until the client has the /proc/register_asset(var/asset_name, var/asset) SSassets.cache[asset_name] = asset +//Generated names do not include file extention. +//Used mainly for code that deals with assets in a generic way +//The same asset will always lead to the same asset name +/proc/generate_asset_name(var/file) + return "asset.[md5(fcopy_rsc(file))]" + + //These datums are used to populate the asset cache, the proc "register()" does this. //all of our asset datums, used for referring to these later @@ -170,6 +177,33 @@ GLOBAL_LIST_EMPTY(asset_datums) send_asset_list(client,assets,verify) +//Generates assets based on iconstates of a single icon +/datum/asset/simple/icon_states + var/icon + var/direction = SOUTH + var/frame = 1 + var/movement_states = FALSE + + var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png" + var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format + + verify = FALSE + +/datum/asset/simple/icon_states/register() + for(var/icon_state_name in icon_states(icon)) + var/asset = icon(icon, icon_state_name, direction, frame, movement_states) + if (!asset) + continue + asset = fcopy_rsc(asset) //dedupe + var/asset_name = sanitize_filename("[prefix].[icon_state_name].png") + if (generic_icon_names) + asset_name = "[generate_asset_name(asset)].png" + + assets[asset_name] = asset + + ..() + + //DEFINITIONS FOR ASSET DATUMS START HERE. /datum/asset/simple/tgui @@ -306,3 +340,14 @@ GLOBAL_LIST_EMPTY(asset_datums) for(var/path in typesof(/datum/html_interface)) var/datum/html_interface/hi = new path() hi.registerResources() + +//this exists purely to avoid meta by pre-loading all language icons. +/datum/asset/language/register() + for(var/path in typesof(/datum/language)) + set waitfor = FALSE + var/datum/language/L = new path () + L.get_icon() + +/datum/asset/simple/icon_states/emojis + icon = 'icons/emoji.dmi' + generic_icon_names = TRUE diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 4455af7ca9..637c3e2bec 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -72,9 +72,9 @@ to_chat(src, "Your previous action was ignored because you've done too many in a second") return - //Logs all hrefs - GLOB.world_href_log << "[time_stamp(show_ds = TRUE)] [src] (usr:[usr]) || [hsrc ? "[hsrc] " : ""][href]
" - + //Logs all hrefs, except chat pings + if(!(href_list["_src_"] == "chat" && href_list["proc"] == "ping" && LAZYLEN(href_list) == 2)) + WRITE_FILE(GLOB.world_href_log, "[time_stamp(show_ds = TRUE)] [src] (usr:[usr]) || [hsrc ? "[hsrc] " : ""][href]
") // Admin PM if(href_list["priv_msg"]) cmd_admin_pm(href_list["priv_msg"],null) @@ -642,7 +642,7 @@ GLOBAL_LIST(external_rsc_urls) ) spawn (10) //removing this spawn causes all clients to not get verbs. //Precache the client with all other assets slowly, so as to not block other browse() calls - getFilesSlow(src, SSassets.cache, register_asset = FALSE) + getFilesSlow(src, SSassets.preload, register_asset = FALSE) //Hook, override it to run code when dir changes diff --git a/code/modules/client/client_procs.dm.rej b/code/modules/client/client_procs.dm.rej new file mode 100644 index 0000000000..2b656938c4 --- /dev/null +++ b/code/modules/client/client_procs.dm.rej @@ -0,0 +1,10 @@ +diff a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm (rejected hunks) +@@ -73,7 +73,7 @@ + return + + //Logs all hrefs, except chat pings +- if(href_list["proc"] != "ping") ++ if(!(href_list["_src_"] == "chat" && href_list["proc"] == "ping" && LAZYLEN(href_list) == 2)) + WRITE_FILE(GLOB.world_href_log, "[time_stamp(show_ds = TRUE)] [src] (usr:[usr]) || [hsrc ? "[hsrc] " : ""][href]
") + + // Admin PM diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 1e07ee4ce0..4c23db3f86 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -130,7 +130,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) "womb_cum_rate" = CUM_RATE, "womb_cum_mult" = CUM_RATE_MULT, "womb_efficiency" = CUM_EFFICIENCY, - "womb_fluid" = "femcum" + "womb_fluid" = "femcum", + "flavor_text" = "" )//MAKE SURE TO UPDATE THE LIST IN MOBS.DM IF YOU'RE GOING TO ADD TO THIS LIST, OTHERWISE THINGS MIGHT GET FUCKEY var/list/custom_names = list("clown", "mime", "ai", "cyborg", "religion", "deity") @@ -175,7 +176,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) //citadel code var/arousable = TRUE //Allows players to disable arousal from the character creation menu - var/flavor_text = "" /datum/preferences/New(client/C) parent = C @@ -394,13 +394,13 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
" dat += "

" dat += "Set Flavor Text
" - if(lentext(flavor_text) <= 40) - if(!lentext(flavor_text)) + if(lentext(features["flavor_text"]) <= 40) + if(!lentext(features["flavor_text"])) dat += "\[...\]" else - dat += "[flavor_text]" + dat += "[features["flavor_text"]]" else - dat += "[TextPreview(flavor_text)]...
" + dat += "[TextPreview(features["flavor_text"])]...
" if(config.mutant_races)//really don't need this check, but fuck un-tabbing all those lines dat += "

Body

" dat += "Gender: [gender == MALE ? "Male" : "Female"]
" @@ -916,11 +916,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) if("flavor_text") - var/msg = input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(flavor_text)) as message + var/msg = input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(features["flavor_text"])) as message if(msg != null) msg = copytext(msg, 1, MAX_MESSAGE_LEN) msg = html_encode(msg) - flavor_text = msg + features["flavor_text"] = msg if("metadata") var/new_metadata = input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , metadata) as message|null @@ -1628,7 +1628,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.backbag = backbag - character.dna.features = features.Copy() + character.dna.features = features.Copy() //Flavor text is now a DNA feature character.dna.real_name = character.real_name var/datum/species/chosen_species if(pref_species != /datum/species/human && config.mutant_races) @@ -1639,7 +1639,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) //citadel code character.give_genitals() - character.flavor_text = flavor_text + character.flavor_text = features["flavor_text"] //Let's update their flavor_text at least initially character.canbearoused = arousable if(icon_updates) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index c52767f1d9..244afc69f3 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -226,34 +226,34 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car return 0 S.cd = "/" - S["version"] << SAVEFILE_VERSION_MAX //updates (or failing that the sanity checks) will ensure data is not invalid at load. Assume up-to-date + WRITE_FILE(S["version"] , SAVEFILE_VERSION_MAX) //updates (or failing that the sanity checks) will ensure data is not invalid at load. Assume up-to-date //general preferences - S["ooccolor"] << ooccolor - S["lastchangelog"] << lastchangelog - S["UI_style"] << UI_style - S["hotkeys"] << hotkeys - S["tgui_fancy"] << tgui_fancy - S["tgui_lock"] << tgui_lock - S["windowflash"] << windowflashing - S["be_special"] << be_special - S["default_slot"] << default_slot - S["toggles"] << toggles - S["chat_toggles"] << chat_toggles - S["ghost_form"] << ghost_form - S["ghost_orbit"] << ghost_orbit - S["ghost_accs"] << ghost_accs - S["ghost_others"] << ghost_others - S["preferred_map"] << preferred_map - S["ignoring"] << ignoring - S["ghost_hud"] << ghost_hud - S["inquisitive_ghost"] << inquisitive_ghost - S["uses_glasses_colour"]<< uses_glasses_colour - S["clientfps"] << clientfps - S["parallax"] << parallax - S["menuoptions"] << menuoptions - S["enable_tips"] << enable_tips - S["tip_delay"] << tip_delay + WRITE_FILE(S["ooccolor"], ooccolor) + WRITE_FILE(S["lastchangelog"], lastchangelog) + WRITE_FILE(S["UI_style"], UI_style) + WRITE_FILE(S["hotkeys"], hotkeys) + WRITE_FILE(S["tgui_fancy"], tgui_fancy) + WRITE_FILE(S["tgui_lock"], tgui_lock) + WRITE_FILE(S["windowflash"], windowflashing) + WRITE_FILE(S["be_special"], be_special) + WRITE_FILE(S["default_slot"], default_slot) + WRITE_FILE(S["toggles"], toggles) + WRITE_FILE(S["chat_toggles"], chat_toggles) + WRITE_FILE(S["ghost_form"], ghost_form) + WRITE_FILE(S["ghost_orbit"], ghost_orbit) + WRITE_FILE(S["ghost_accs"], ghost_accs) + WRITE_FILE(S["ghost_others"], ghost_others) + WRITE_FILE(S["preferred_map"], preferred_map) + WRITE_FILE(S["ignoring"], ignoring) + WRITE_FILE(S["ghost_hud"], ghost_hud) + WRITE_FILE(S["inquisitive_ghost"], inquisitive_ghost) + WRITE_FILE(S["uses_glasses_colour"], uses_glasses_colour) + WRITE_FILE(S["clientfps"], clientfps) + WRITE_FILE(S["parallax"], parallax) + WRITE_FILE(S["menuoptions"], menuoptions) + WRITE_FILE(S["enable_tips"], enable_tips) + WRITE_FILE(S["tip_delay"], tip_delay) //citadel code S["arousable"] << arousable @@ -273,7 +273,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car slot = sanitize_integer(slot, 1, max_save_slots, initial(default_slot)) if(slot != default_slot) default_slot = slot - S["default_slot"] << slot + WRITE_FILE(S["default_slot"] , slot) S.cd = "/character[slot]" var/needs_update = savefile_needs_update(S) @@ -292,7 +292,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car pref_species = new rando_race() if(!S["features["mcolor"]"] || S["features["mcolor"]"] == "#000") - S["features["mcolor"]"] << "#FFF" + WRITE_FILE(S["features["mcolor"]"] , "#FFF") //Character S["OOC_Notes"] >> metadata @@ -342,9 +342,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["job_engsec_med"] >> job_engsec_med S["job_engsec_low"] >> job_engsec_low - //Citadel code - S["flavor_text"] >> flavor_text S["feature_exhibitionist"] >> features["exhibitionist"] S["feature_mcolor2"] >> features["mcolor2"] S["feature_mcolor3"] >> features["mcolor3"] @@ -382,6 +380,17 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_vag_color"] >> features["vag_color"] //womb features S["feature_has_womb"] >> features["has_womb"] + //flavor text + //Let's make our players NOT cry desperately as we wipe their savefiles of their special snowflake texts: + if((S["flavor_text"] != "") && (S["flavor_text"] != null) && S["flavor_text"]) //If old text isn't null and isn't "" but still exists. + S["flavor_text"] >> features["flavor_text"] //Load old flavortext as current dna-based flavortext + + S["feature_flavor_text"] << features["flavor_text"] //Save it in our new type of flavor-text + S["flavor_text"] << "" //Remove old flavortext, completing the cut-and-paste into the new format. + + else //We have no old flavortext, default to new + S["feature_flavor_text"] >> features["flavor_text"] + //try to fix any outdated data if necessary if(needs_update >= 0) @@ -441,7 +450,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car job_engsec_low = sanitize_integer(job_engsec_low, 0, 65535, initial(job_engsec_low)) //Citadel - flavor_text = sanitize_text(flavor_text, initial(flavor_text)) + features["flavor_text"] = sanitize_text(features["flavor_text"], initial(features["flavor_text"])) if(!features["mcolor2"] || features["mcolor"] == "#000") features["mcolor2"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F") if(!features["mcolor3"] || features["mcolor"] == "#000") @@ -461,56 +470,55 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["version"] << SAVEFILE_VERSION_MAX //load_character will sanitize any bad data, so assume up-to-date. //Character - S["OOC_Notes"] << metadata - S["real_name"] << real_name - S["name_is_always_random"] << be_random_name - S["body_is_always_random"] << be_random_body - S["gender"] << gender - S["age"] << age - S["hair_color"] << hair_color - S["facial_hair_color"] << facial_hair_color - S["eye_color"] << eye_color - S["skin_tone"] << skin_tone - S["hair_style_name"] << hair_style - S["facial_style_name"] << facial_hair_style - S["underwear"] << underwear - S["undershirt"] << undershirt - S["socks"] << socks - S["backbag"] << backbag - S["uplink_loc"] << uplink_spawn_loc - S["species"] << pref_species.id - S["feature_mcolor"] << features["mcolor"] - S["feature_lizard_tail"] << features["tail_lizard"] - S["feature_human_tail"] << features["tail_human"] - S["feature_lizard_snout"] << features["snout"] - S["feature_lizard_horns"] << features["horns"] - S["feature_human_ears"] << features["ears"] - S["feature_lizard_frills"] << features["frills"] - S["feature_lizard_spines"] << features["spines"] - S["feature_lizard_body_markings"] << features["body_markings"] - S["feature_lizard_legs"] << features["legs"] - S["clown_name"] << custom_names["clown"] - S["mime_name"] << custom_names["mime"] - S["ai_name"] << custom_names["ai"] - S["cyborg_name"] << custom_names["cyborg"] - S["religion_name"] << custom_names["religion"] - S["deity_name"] << custom_names["deity"] - S["prefered_security_department"] << prefered_security_department + WRITE_FILE(S["OOC_Notes"] , metadata) + WRITE_FILE(S["real_name"] , real_name) + WRITE_FILE(S["name_is_always_random"] , be_random_name) + WRITE_FILE(S["body_is_always_random"] , be_random_body) + WRITE_FILE(S["gender"] , gender) + WRITE_FILE(S["age"] , age) + WRITE_FILE(S["hair_color"] , hair_color) + WRITE_FILE(S["facial_hair_color"] , facial_hair_color) + WRITE_FILE(S["eye_color"] , eye_color) + WRITE_FILE(S["skin_tone"] , skin_tone) + WRITE_FILE(S["hair_style_name"] , hair_style) + WRITE_FILE(S["facial_style_name"] , facial_hair_style) + WRITE_FILE(S["underwear"] , underwear) + WRITE_FILE(S["undershirt"] , undershirt) + WRITE_FILE(S["socks"] , socks) + WRITE_FILE(S["backbag"] , backbag) + WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc) + WRITE_FILE(S["species"] , pref_species.id) + WRITE_FILE(S["feature_mcolor"] , features["mcolor"]) + WRITE_FILE(S["feature_lizard_tail"] , features["tail_lizard"]) + WRITE_FILE(S["feature_human_tail"] , features["tail_human"]) + WRITE_FILE(S["feature_lizard_snout"] , features["snout"]) + WRITE_FILE(S["feature_lizard_horns"] , features["horns"]) + WRITE_FILE(S["feature_human_ears"] , features["ears"]) + WRITE_FILE(S["feature_lizard_frills"] , features["frills"]) + WRITE_FILE(S["feature_lizard_spines"] , features["spines"]) + WRITE_FILE(S["feature_lizard_body_markings"] , features["body_markings"]) + WRITE_FILE(S["feature_lizard_legs"] , features["legs"]) + WRITE_FILE(S["clown_name"] , custom_names["clown"]) + WRITE_FILE(S["mime_name"] , custom_names["mime"]) + WRITE_FILE(S["ai_name"] , custom_names["ai"]) + WRITE_FILE(S["cyborg_name"] , custom_names["cyborg"]) + WRITE_FILE(S["religion_name"] , custom_names["religion"]) + WRITE_FILE(S["deity_name"] , custom_names["deity"]) + WRITE_FILE(S["prefered_security_department"] , prefered_security_department) //Jobs - S["joblessrole"] << joblessrole - S["job_civilian_high"] << job_civilian_high - S["job_civilian_med"] << job_civilian_med - S["job_civilian_low"] << job_civilian_low - S["job_medsci_high"] << job_medsci_high - S["job_medsci_med"] << job_medsci_med - S["job_medsci_low"] << job_medsci_low - S["job_engsec_high"] << job_engsec_high - S["job_engsec_med"] << job_engsec_med - S["job_engsec_low"] << job_engsec_low + WRITE_FILE(S["joblessrole"] , joblessrole) + WRITE_FILE(S["job_civilian_high"] , job_civilian_high) + WRITE_FILE(S["job_civilian_med"] , job_civilian_med) + WRITE_FILE(S["job_civilian_low"] , job_civilian_low) + WRITE_FILE(S["job_medsci_high"] , job_medsci_high) + WRITE_FILE(S["job_medsci_med"] , job_medsci_med) + WRITE_FILE(S["job_medsci_low"] , job_medsci_low) + WRITE_FILE(S["job_engsec_high"] , job_engsec_high) + WRITE_FILE(S["job_engsec_med"] , job_engsec_med) + WRITE_FILE(S["job_engsec_low"] , job_engsec_low) //Citadel - S["flavor_text"] << flavor_text S["feature_exhibitionist"] << features["exhibitionist"] S["feature_mcolor2"] << features["mcolor2"] S["feature_mcolor3"] << features["mcolor3"] @@ -548,7 +556,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_vag_color"] << features["vag_color"] //womb features S["feature_has_womb"] << features["has_womb"] - + //flavor text + S["feature_flavor_text"] << features["flavor_text"] return 1 #undef SAVEFILE_VERSION_MAX diff --git a/code/modules/client/preferences_savefile.dm.rej b/code/modules/client/preferences_savefile.dm.rej new file mode 100644 index 0000000000..3cdbf2cd44 --- /dev/null +++ b/code/modules/client/preferences_savefile.dm.rej @@ -0,0 +1,10 @@ +diff a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm (rejected hunks) +@@ -193,7 +193,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car + return 0 + S.cd = "/" + +- WRITE_FILE(S["version"] , SAVEFILE_VERSION_MAX //updates (or failing that the sanity checks) will ensure data is not invalid at load. Assume up-to-date) ++ WRITE_FILE(S["version"] , SAVEFILE_VERSION_MAX) //updates (or failing that the sanity checks) will ensure data is not invalid at load. Assume up-to-date + + //general preferences + WRITE_FILE(S["ooccolor"], ooccolor) diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index d56b6e0619..1d04964a8b 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -229,7 +229,7 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggleprayersounds)() set name = "Stop Sounds" set category = "Preferences" set desc = "Stop Current Sounds" - usr << sound(null) + SEND_SOUND(usr, sound(null)) SSblackbox.add_details("preferences_verb","Stop Self Sounds") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index aeb1a7fdcf..cd0f893fa6 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -55,7 +55,7 @@ var/keyname = key if(prefs.unlock_content) if(prefs.toggles & MEMBER_PUBLIC) - keyname = "[bicon(icon('icons/member_content.dmi', "blag"))][keyname]" + keyname = "[icon2html('icons/member_content.dmi', world, "blag")][keyname]" for(var/client/C in GLOB.clients) if(C.prefs.chat_toggles & CHAT_OOC) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index bd6ffe5f67..bf34ee9f18 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -253,6 +253,7 @@ BLIND // can't see anything slot_flags = SLOT_HEAD var/blockTracking = 0 //For AI tracking var/can_toggle = null + dynamic_hair_suffix = "+generic" /obj/item/clothing/head/Initialize() . = ..() diff --git a/code/modules/clothing/head/collectable.dm b/code/modules/clothing/head/collectable.dm index 8ec8d00c77..67ce9ea370 100644 --- a/code/modules/clothing/head/collectable.dm +++ b/code/modules/clothing/head/collectable.dm @@ -14,6 +14,7 @@ name = "collectable slime cap!" desc = "It just latches right in place!" icon_state = "slime" + dynamic_hair_suffix = "" /obj/item/clothing/head/collectable/xenom name = "collectable xenomorph helmet!" @@ -25,6 +26,7 @@ desc = "A rare chef's hat meant for hat collectors!" icon_state = "chef" item_state = "chef" + dynamic_hair_suffix = "" dog_fashion = /datum/dog_fashion/head/chef @@ -53,6 +55,7 @@ name = "collectable police officer's hat" desc = "A collectable police officer's Hat. This hat emphasizes that you are THE LAW." icon_state = "policehelm" + dynamic_hair_suffix = "" dog_fashion = /datum/dog_fashion/head/warden @@ -95,6 +98,7 @@ desc = "The fur feels... a bit too realistic." icon_state = "kitty" item_state = "kitty" + dynamic_hair_suffix = "" dog_fashion = /datum/dog_fashion/head/kitty @@ -103,6 +107,7 @@ desc = "Not as lucky as the feet!" icon_state = "bunny" item_state = "bunny" + dynamic_hair_suffix = "" dog_fashion = /datum/dog_fashion/head/rabbit @@ -125,6 +130,7 @@ name = "collectable HoS hat" desc = "Now you too can beat prisoners, set silly sentences, and arrest for no reason!" icon_state = "hoscap" + dynamic_hair_suffix = "" /obj/item/clothing/head/collectable/HoP name = "collectable HoP hat" @@ -138,6 +144,7 @@ icon_state = "thunderdome" item_state = "thunderdome" resistance_flags = 0 + flags_inv = HIDEHAIR /obj/item/clothing/head/collectable/swat name = "collectable SWAT helmet" @@ -145,3 +152,4 @@ icon_state = "swat" item_state = "swat" resistance_flags = 0 + flags_inv = HIDEHAIR diff --git a/code/modules/clothing/head/collectable.dm.rej b/code/modules/clothing/head/collectable.dm.rej new file mode 100644 index 0000000000..82a9962cb8 --- /dev/null +++ b/code/modules/clothing/head/collectable.dm.rej @@ -0,0 +1,9 @@ +diff a/code/modules/clothing/head/collectable.dm b/code/modules/clothing/head/collectable.dm (rejected hunks) +@@ -4,7 +4,6 @@ + /obj/item/clothing/head/collectable + name = "collectable hat" + desc = "A rare collectable hat." +- dynamic_hair_suffix = "+detective" + + + /obj/item/clothing/head/collectable/petehat diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index 28fe8cacfb..6eefb458ed 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -10,6 +10,7 @@ flags_inv = 0 actions_types = list(/datum/action/item_action/toggle_helmet_light) resistance_flags = FIRE_PROOF + dynamic_hair_suffix = "+generic" dog_fashion = /datum/dog_fashion/head diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index f100df4366..24d8049ac7 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -12,6 +12,7 @@ strip_delay = 60 resistance_flags = 0 flags_cover = HEADCOVERSEYES + flags_inv = HIDEHAIR dog_fashion = /datum/dog_fashion/head/helmet diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index 23b3da72ef..6a127f571b 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -7,6 +7,7 @@ desc = "The commander in chef's head wear." strip_delay = 10 equip_delay_other = 10 + dynamic_hair_suffix = "" dog_fashion = /datum/dog_fashion/head/chef /obj/item/clothing/head/chefhat/suicide_act(mob/user) @@ -62,6 +63,7 @@ item_state = "cage" worn_x_dimension = 64 worn_y_dimension = 64 + dynamic_hair_suffix = "" /obj/item/clothing/head/witchunter_hat @@ -99,6 +101,7 @@ desc = "A beret, a mime's favorite headwear." icon_state = "beret" dog_fashion = /datum/dog_fashion/head/beret + dynamic_hair_suffix = "" /obj/item/clothing/head/beret/black name = "black beret" @@ -118,6 +121,7 @@ icon_state = "hoscap" armor = list(melee = 40, bullet = 30, laser = 25, energy = 10, bomb = 25, bio = 10, rad = 0, fire = 50, acid = 60) strip_delay = 80 + dynamic_hair_suffix = "" /obj/item/clothing/head/HoS/syndicate name = "syndicate cap" diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index 2c972ccc70..959c28d45e 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -1,287 +1,290 @@ - - -/obj/item/clothing/head/centhat - name = "\improper CentCom hat" - icon_state = "centcom" - desc = "It's good to be emperor." - item_state = "that" - flags_inv = 0 - armor = list(melee = 30, bullet = 15, laser = 30, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 50, acid = 50) - strip_delay = 80 - -/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 = "top-hat" - desc = "It's an amish looking hat." - icon_state = "tophat" - item_state = "that" - dog_fashion = /datum/dog_fashion/head - throwforce = 1 - -/obj/item/clothing/head/canada - name = "striped red tophat" - desc = "it smells like fresh donut holes / il sent comme des trous de beignets frais" - icon_state = "canada" - item_state = "canada" - -/obj/item/clothing/head/redcoat - name = "redcoat's hat" - icon_state = "redcoat" - desc = "'I guess it's a redhead.'" - -/obj/item/clothing/head/mailman - name = "mailman's hat" - icon_state = "mailman" - desc = "'Right-on-time' mail service head wear." - -/obj/item/clothing/head/plaguedoctorhat - name = "plague doctor's hat" - desc = "These were once used by plague doctors. They're pretty much useless." - icon_state = "plaguedoctor" - permeability_coefficient = 0.01 - -/obj/item/clothing/head/hasturhood - name = "hastur's hood" - desc = "It's unspeakably stylish." - icon_state = "hasturhood" - flags_inv = HIDEHAIR - flags_cover = HEADCOVERSEYES - -/obj/item/clothing/head/nursehat - name = "nurse's hat" - desc = "It allows quick identification of trained medical personnel." - icon_state = "nursehat" - - dog_fashion = /datum/dog_fashion/head/nurse - -/obj/item/clothing/head/syndicatefake - name = "black space-helmet replica" - icon_state = "syndicate-helm-black-red" - item_state = "syndicate-helm-black-red" - desc = "A plastic replica of a Syndicate agent's space helmet. You'll look just like a real murderous Syndicate agent in this! This is a toy, it is not made for use in space!" - flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR - -/obj/item/clothing/head/cueball - name = "cueball helmet" - desc = "A large, featureless white orb meant to be worn on your head. How do you even see out of this thing?" - icon_state = "cueball" - item_state="cueball" - flags_cover = HEADCOVERSEYES|HEADCOVERSMOUTH - flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR - -/obj/item/clothing/head/snowman - name = "Snowman Head" - desc = "A ball of white styrofoam. So festive." - icon_state = "snowman_h" - item_state = "snowman_h" - flags_cover = HEADCOVERSEYES - flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR - -/obj/item/clothing/head/justice - name = "justice hat" - desc = "Fight for what's righteous!" - icon_state = "justicered" - item_state = "justicered" - flags_inv = HIDEHAIR|HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR - flags_cover = HEADCOVERSEYES - -/obj/item/clothing/head/justice/blue - icon_state = "justiceblue" - item_state = "justiceblue" - -/obj/item/clothing/head/justice/yellow - icon_state = "justiceyellow" - item_state = "justiceyellow" - -/obj/item/clothing/head/justice/green - icon_state = "justicegreen" - item_state = "justicegreen" - -/obj/item/clothing/head/justice/pink - icon_state = "justicepink" - item_state = "justicepink" - -/obj/item/clothing/head/rabbitears - name = "rabbit ears" - desc = "Wearing these makes you look useless, and only good for your sex appeal." - icon_state = "bunny" - - dog_fashion = /datum/dog_fashion/head/rabbit - - -/obj/item/clothing/head/flatcap - name = "flat cap" - desc = "A working man's cap." - icon_state = "flat_cap" - item_state = "detective" - -/obj/item/clothing/head/pirate - name = "pirate hat" - desc = "Yarr." - icon_state = "pirate" - item_state = "pirate" - dog_fashion = /datum/dog_fashion/head/pirate - -/obj/item/clothing/head/pirate/captain - icon_state = "hgpiratecap" - item_state = "hgpiratecap" - -/obj/item/clothing/head/bandana - name = "pirate bandana" - desc = "Yarr." - icon_state = "bandana" - item_state = "bandana" - -/obj/item/clothing/head/bowler - name = "bowler-hat" - desc = "Gentleman, elite aboard!" - icon_state = "bowler" - item_state = "bowler" - -/obj/item/clothing/head/witchwig - name = "witch costume wig" - desc = "Eeeee~heheheheheheh!" - icon_state = "witch" - item_state = "witch" - flags_inv = HIDEHAIR - -/obj/item/clothing/head/chicken - name = "chicken suit head" - desc = "Bkaw!" - icon_state = "chickenhead" - item_state = "chickensuit" - flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR - -/obj/item/clothing/head/griffin - name = "griffon head" - desc = "Why not 'eagle head'? Who knows." - icon_state = "griffinhat" - item_state = "griffinhat" - flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR - -/obj/item/clothing/head/bearpelt - name = "bear pelt hat" - desc = "Fuzzy." - icon_state = "bearpelt" - item_state = "bearpelt" - -/obj/item/clothing/head/xenos - name = "xenos helmet" - icon_state = "xenos" - item_state = "xenos_helm" - desc = "A helmet made out of chitinous alien hide." - flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR - -/obj/item/clothing/head/fedora - name = "fedora" - icon_state = "fedora" - item_state = "fedora" - armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50) - desc = "A really cool hat if you're a mobster. A really lame hat if you're not." - dynamic_hair_suffix = "+detective" - pockets = /obj/item/weapon/storage/internal/pocket/small - -/obj/item/clothing/head/fedora/suicide_act(mob/user) - if(user.gender == FEMALE) - return 0 - var/mob/living/carbon/human/H = user - user.visible_message("[user] is donning [src]! It looks like they're trying to be nice to girls.") - user.say("M'lady.") - sleep(10) - H.facial_hair_style = "Neckbeard" - return(BRUTELOSS) - -/obj/item/clothing/head/sombrero - name = "sombrero" - icon_state = "sombrero" - item_state = "sombrero" - desc = "You can practically taste the fiesta." - flags_inv = HIDEHAIR - - dog_fashion = /datum/dog_fashion/head/sombrero - -/obj/item/clothing/head/sombrero/green - name = "green sombrero" - icon_state = "greensombrero" - item_state = "greensombrero" - desc = "As elegant as a dancing cactus." - flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS - dog_fashion = null - -/obj/item/clothing/head/sombrero/shamebrero - name = "shamebrero" - icon_state = "shamebrero" - item_state = "shamebrero" - desc = "Once it's on, it never comes off." - flags = NODROP - dog_fashion = null - -/obj/item/clothing/head/cone - desc = "This cone is trying to warn you of something!" - name = "warning cone" - icon = 'icons/obj/janitor.dmi' - icon_state = "cone" - item_state = "cone" - force = 1 - throwforce = 3 - throw_speed = 2 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - attack_verb = list("warned", "cautioned", "smashed") - resistance_flags = 0 - -/obj/item/clothing/head/santa - name = "santa hat" - desc = "On the first day of christmas my employer gave to me!" - icon_state = "santahatnorm" - item_state = "that" - cold_protection = HEAD - min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT - dog_fashion = /datum/dog_fashion/head/santa - -/obj/item/clothing/head/jester - name = "jester hat" +/obj/item/clothing/head/centhat + name = "\improper Centcom hat" + icon_state = "centcom" + desc = "It's good to be emperor." + item_state = "that" + flags_inv = 0 + armor = list(melee = 30, bullet = 15, laser = 30, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 50, acid = 50) + strip_delay = 80 + +/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 = "top-hat" + desc = "It's an amish looking hat." + icon_state = "tophat" + item_state = "that" + dog_fashion = /datum/dog_fashion/head + throwforce = 1 + +/obj/item/clothing/head/canada + name = "striped red tophat" + desc = "it smells like fresh donut holes / il sent comme des trous de beignets frais" + icon_state = "canada" + item_state = "canada" + +/obj/item/clothing/head/redcoat + name = "redcoat's hat" + icon_state = "redcoat" + desc = "'I guess it's a redhead.'" + +/obj/item/clothing/head/mailman + name = "mailman's hat" + icon_state = "mailman" + desc = "'Right-on-time' mail service head wear." + +/obj/item/clothing/head/plaguedoctorhat + name = "plague doctor's hat" + desc = "These were once used by plague doctors. They're pretty much useless." + icon_state = "plaguedoctor" + permeability_coefficient = 0.01 + +/obj/item/clothing/head/hasturhood + name = "hastur's hood" + desc = "It's unspeakably stylish." + icon_state = "hasturhood" + flags_inv = HIDEHAIR + flags_cover = HEADCOVERSEYES + +/obj/item/clothing/head/nursehat + name = "nurse's hat" + desc = "It allows quick identification of trained medical personnel." + icon_state = "nursehat" + dynamic_hair_suffix = "" + + dog_fashion = /datum/dog_fashion/head/nurse + +/obj/item/clothing/head/syndicatefake + name = "black space-helmet replica" + icon_state = "syndicate-helm-black-red" + item_state = "syndicate-helm-black-red" + desc = "A plastic replica of a Syndicate agent's space helmet. You'll look just like a real murderous Syndicate agent in this! This is a toy, it is not made for use in space!" + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR + +/obj/item/clothing/head/cueball + name = "cueball helmet" + desc = "A large, featureless white orb meant to be worn on your head. How do you even see out of this thing?" + icon_state = "cueball" + item_state="cueball" + flags_cover = HEADCOVERSEYES|HEADCOVERSMOUTH + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR + +/obj/item/clothing/head/snowman + name = "Snowman Head" + desc = "A ball of white styrofoam. So festive." + icon_state = "snowman_h" + item_state = "snowman_h" + flags_cover = HEADCOVERSEYES + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR + +/obj/item/clothing/head/justice + name = "justice hat" + desc = "Fight for what's righteous!" + icon_state = "justicered" + item_state = "justicered" + flags_inv = HIDEHAIR|HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR + flags_cover = HEADCOVERSEYES + +/obj/item/clothing/head/justice/blue + icon_state = "justiceblue" + item_state = "justiceblue" + +/obj/item/clothing/head/justice/yellow + icon_state = "justiceyellow" + item_state = "justiceyellow" + +/obj/item/clothing/head/justice/green + icon_state = "justicegreen" + item_state = "justicegreen" + +/obj/item/clothing/head/justice/pink + icon_state = "justicepink" + item_state = "justicepink" + +/obj/item/clothing/head/rabbitears + name = "rabbit ears" + desc = "Wearing these makes you look useless, and only good for your sex appeal." + icon_state = "bunny" + dynamic_hair_suffix = "" + + dog_fashion = /datum/dog_fashion/head/rabbit + + +/obj/item/clothing/head/flatcap + name = "flat cap" + desc = "A working man's cap." + icon_state = "flat_cap" + item_state = "detective" + +/obj/item/clothing/head/pirate + name = "pirate hat" + desc = "Yarr." + icon_state = "pirate" + item_state = "pirate" + dog_fashion = /datum/dog_fashion/head/pirate + +/obj/item/clothing/head/pirate/captain + icon_state = "hgpiratecap" + item_state = "hgpiratecap" + +/obj/item/clothing/head/bandana + name = "pirate bandana" + desc = "Yarr." + icon_state = "bandana" + item_state = "bandana" + dynamic_hair_suffix = "" + +/obj/item/clothing/head/bowler + name = "bowler-hat" + desc = "Gentleman, elite aboard!" + icon_state = "bowler" + item_state = "bowler" + dynamic_hair_suffix = "" + +/obj/item/clothing/head/witchwig + name = "witch costume wig" + desc = "Eeeee~heheheheheheh!" + icon_state = "witch" + item_state = "witch" + flags_inv = HIDEHAIR + +/obj/item/clothing/head/chicken + name = "chicken suit head" + desc = "Bkaw!" + icon_state = "chickenhead" + item_state = "chickensuit" + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR + +/obj/item/clothing/head/griffin + name = "griffon head" + desc = "Why not 'eagle head'? Who knows." + icon_state = "griffinhat" + item_state = "griffinhat" + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR + +/obj/item/clothing/head/bearpelt + name = "bear pelt hat" + desc = "Fuzzy." + icon_state = "bearpelt" + item_state = "bearpelt" + +/obj/item/clothing/head/xenos + name = "xenos helmet" + icon_state = "xenos" + item_state = "xenos_helm" + desc = "A helmet made out of chitinous alien hide." + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR + +/obj/item/clothing/head/fedora + name = "fedora" + icon_state = "fedora" + item_state = "fedora" + armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50) + desc = "A really cool hat if you're a mobster. A really lame hat if you're not." + pockets = /obj/item/weapon/storage/internal/pocket/small + +/obj/item/clothing/head/fedora/suicide_act(mob/user) + if(user.gender == FEMALE) + return 0 + var/mob/living/carbon/human/H = user + user.visible_message("[user] is donning [src]! It looks like they're trying to be nice to girls.") + user.say("M'lady.") + sleep(10) + H.facial_hair_style = "Neckbeard" + return(BRUTELOSS) + +/obj/item/clothing/head/sombrero + name = "sombrero" + icon_state = "sombrero" + item_state = "sombrero" + desc = "You can practically taste the fiesta." + flags_inv = HIDEHAIR + + dog_fashion = /datum/dog_fashion/head/sombrero + +/obj/item/clothing/head/sombrero/green + name = "green sombrero" + icon_state = "greensombrero" + item_state = "greensombrero" + desc = "As elegant as a dancing cactus." + flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS + dog_fashion = null + +/obj/item/clothing/head/sombrero/shamebrero + name = "shamebrero" + icon_state = "shamebrero" + item_state = "shamebrero" + desc = "Once it's on, it never comes off." + flags = NODROP + dog_fashion = null + +/obj/item/clothing/head/cone + desc = "This cone is trying to warn you of something!" + name = "warning cone" + icon = 'icons/obj/janitor.dmi' + icon_state = "cone" + item_state = "cone" + force = 1 + throwforce = 3 + throw_speed = 2 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + attack_verb = list("warned", "cautioned", "smashed") + resistance_flags = 0 + +/obj/item/clothing/head/santa + name = "santa hat" + desc = "On the first day of christmas my employer gave to me!" + icon_state = "santahatnorm" + item_state = "that" + cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT + dog_fashion = /datum/dog_fashion/head/santa + +/obj/item/clothing/head/jester + name = "jester hat" desc = "A hat with bells, to add some merriness to the suit." - icon_state = "jester_hat" - -/obj/item/clothing/head/rice_hat - name = "rice hat" - desc = "Welcome to the rice fields, motherfucker." - icon_state = "rice_hat" - -/obj/item/clothing/head/lizard - name = "lizardskin cloche hat" - desc = "How many lizards died to make this hat? Not enough." - icon_state = "lizard" - -/obj/item/clothing/head/papersack - name = "paper sack hat" - desc = "A paper sack with crude holes cut out for eyes. Useful for hiding one's identity or ugliness." - icon_state = "papersack" - flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS - -/obj/item/clothing/head/papersack/smiley - name = "paper sack hat" - desc = "A paper sack with crude holes cut out for eyes and a sketchy smile drawn on the front. Not creepy at all." - icon_state = "papersack_smile" - flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS - -/obj/item/clothing/head/crown - name = "crown" - desc = "A crown fit for a king, a petty king maybe." - icon_state = "crown" - armor = list(melee = 15, bullet = 0, laser = 0,energy = 15, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) - resistance_flags = FIRE_PROOF - -/obj/item/clothing/head/crown/fancy - name = "magnificent crown" - desc = "A crown worn by only the highest emperors of the land." - icon_state = "fancycrown" + icon_state = "jester_hat" + dynamic_hair_suffix = "" + +/obj/item/clothing/head/rice_hat + name = "rice hat" + desc = "Welcome to the rice fields, motherfucker." + icon_state = "rice_hat" + +/obj/item/clothing/head/lizard + name = "lizardskin cloche hat" + desc = "How many lizards died to make this hat? Not enough." + icon_state = "lizard" + +/obj/item/clothing/head/papersack + name = "paper sack hat" + desc = "A paper sack with crude holes cut out for eyes. Useful for hiding one's identity or ugliness." + icon_state = "papersack" + flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS + +/obj/item/clothing/head/papersack/smiley + name = "paper sack hat" + desc = "A paper sack with crude holes cut out for eyes and a sketchy smile drawn on the front. Not creepy at all." + icon_state = "papersack_smile" + flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS + +/obj/item/clothing/head/crown + name = "crown" + desc = "A crown fit for a king, a petty king maybe." + icon_state = "crown" + armor = list(melee = 15, bullet = 0, laser = 0,energy = 15, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) + resistance_flags = FIRE_PROOF + dynamic_hair_suffix = "" + +/obj/item/clothing/head/crown/fancy + name = "magnificent crown" + desc = "A crown worn by only the highest emperors of the land." + icon_state = "fancycrown" /obj/item/clothing/head/scarecrow_hat name = "scarecrow hat" @@ -297,4 +300,5 @@ /obj/item/clothing/head/jester/alt name = "jester hat" desc = "A hat with bells, to add some merriness to the suit." - icon_state = "jester_hat2" \ No newline at end of file + icon_state = "jester_hat2" + dynamic_hair_suffix = "" diff --git a/code/modules/clothing/head/misc.dm.rej b/code/modules/clothing/head/misc.dm.rej new file mode 100644 index 0000000000..df85f74b20 --- /dev/null +++ b/code/modules/clothing/head/misc.dm.rej @@ -0,0 +1,16 @@ +diff a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm (rejected hunks) +@@ -250,7 +250,7 @@ + name = "jester hat" + desc = "A hat with bells, to add some merriness to the suit." + icon_state = "jester_hat" +- dynamic_hair_suffix = "null" ++ dynamic_hair_suffix = "" + + /obj/item/clothing/head/rice_hat + name = "rice hat" +@@ -302,4 +302,4 @@ + name = "jester hat" + desc = "A hat with bells, to add some merriness to the suit." + icon_state = "jester_hat2" +- dynamic_hair_suffix = "null" ++ dynamic_hair_suffix = "" diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 4c14fc0422..d15c7dd5f4 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -125,6 +125,7 @@ desc = "A pair of kitty ears. Meow!" icon_state = "kitty" color = "#999999" + dynamic_hair_suffix = "" dog_fashion = /datum/dog_fashion/head/kitty @@ -150,6 +151,7 @@ flags_inv = 0 armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0) brightness_on = 1 //luminosity when on + dynamic_hair_suffix = "" dog_fashion = /datum/dog_fashion/head/reindeer diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm index 66b62d3a67..abdb42d5b3 100644 --- a/code/modules/clothing/outfits/standard.dm +++ b/code/modules/clothing/outfits/standard.dm @@ -338,7 +338,7 @@ name = "Death Commando" uniform = /obj/item/clothing/under/color/green - suit = /obj/item/clothing/suit/space/hardsuit/shielded/swat + suit = /obj/item/clothing/suit/space/hardsuit/deathsquad shoes = /obj/item/clothing/shoes/combat/swat gloves = /obj/item/clothing/gloves/combat mask = /obj/item/clothing/mask/gas/sechailer/swat diff --git a/code/modules/clothing/spacesuits/flightsuit.dm b/code/modules/clothing/spacesuits/flightsuit.dm index 9888be0494..e0d2907ae8 100644 --- a/code/modules/clothing/spacesuits/flightsuit.dm +++ b/code/modules/clothing/spacesuits/flightsuit.dm @@ -138,7 +138,7 @@ targ = mob_override if(!istype(targ)) return - to_chat(targ, "[bicon(src)]|[message]") + to_chat(targ, "[icon2html(src, targ)]|[message]") /obj/item/device/flightpack/proc/sync_processing(datum/controller/subsystem/processing/flightpacks/FPS) processing_mode = FPS.flightsuit_processing @@ -924,7 +924,7 @@ targ = loc if(!istype(targ)) return - to_chat(targ, "[bicon(src)]|[message]") + to_chat(targ, "[icon2html(src, targ)]|[message]") /obj/item/clothing/suit/space/hardsuit/flightsuit/examine(mob/user) ..() diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 00f622b751..7f8be87a2e 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -47,7 +47,7 @@ /obj/item/clothing/head/helmet/space/hardsuit/proc/display_visor_message(var/msg) var/mob/wearer = loc if(msg && ishuman(wearer)) - wearer.show_message("[bicon(src)][msg]", 1) + wearer.show_message("[icon2html(src, wearer)][msg]", 1) /obj/item/clothing/head/helmet/space/hardsuit/rad_act(severity) ..() @@ -200,7 +200,7 @@ item_color = "mining" max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF - heat_protection = CHEST|GROIN|LEGS|ARMS + heat_protection = HEAD armor = list(melee = 30, bullet = 5, laser = 10, energy = 5, bomb = 50, bio = 100, rad = 50, fire = 50, acid = 75) brightness_on = 7 allowed = list(/obj/item/device/flashlight, /obj/item/weapon/tank/internals, /obj/item/weapon/resonator, /obj/item/device/mining_scanner, /obj/item/device/t_scanner/adv_mining_scanner, /obj/item/weapon/gun/energy/kinetic_accelerator) @@ -216,6 +216,7 @@ armor = list(melee = 30, bullet = 5, laser = 10, energy = 5, bomb = 50, bio = 100, rad = 50, fire = 50, acid = 75) allowed = list(/obj/item/device/flashlight, /obj/item/weapon/tank/internals, /obj/item/weapon/storage/bag/ore, /obj/item/weapon/pickaxe) helmettype = /obj/item/clothing/head/helmet/space/hardsuit/mining + heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS //Syndicate hardsuit /obj/item/clothing/head/helmet/space/hardsuit/syndi diff --git a/code/modules/detectivework/detective_work.dm b/code/modules/detectivework/detective_work.dm index 1ab499fcb5..6c91fee8c5 100644 --- a/code/modules/detectivework/detective_work.dm +++ b/code/modules/detectivework/detective_work.dm @@ -17,19 +17,16 @@ if(M.wear_suit) fibertext = "Material from \a [M.wear_suit]." if(prob(10*item_multiplier) && !(fibertext in suit_fibers)) - //world.log << "Added fibertext: [fibertext]" suit_fibers += fibertext if(!(M.wear_suit.body_parts_covered & CHEST)) if(M.w_uniform) fibertext = "Fibers from \a [M.w_uniform]." if(prob(12*item_multiplier) && !(fibertext in suit_fibers)) //Wearing a suit means less of the uniform exposed. - //world.log << "Added fibertext: [fibertext]" suit_fibers += fibertext if(!(M.wear_suit.body_parts_covered & HANDS)) if(M.gloves) fibertext = "Material from a pair of [M.gloves.name]." if(prob(20*item_multiplier) && !(fibertext in suit_fibers)) - //world.log << "Added fibertext: [fibertext]" suit_fibers += fibertext else if(M.w_uniform) fibertext = "Fibers from \a [M.w_uniform]." @@ -39,12 +36,10 @@ if(M.gloves) fibertext = "Material from a pair of [M.gloves.name]." if(prob(20*item_multiplier) && !(fibertext in suit_fibers)) - //world.log << "Added fibertext: [fibertext]" suit_fibers += "Material from a pair of [M.gloves.name]." else if(M.gloves) fibertext = "Material from a pair of [M.gloves.name]." if(prob(20*item_multiplier) && !(fibertext in suit_fibers)) - //world.log << "Added fibertext: [fibertext]" suit_fibers += "Material from a pair of [M.gloves.name]." diff --git a/code/modules/emoji/emoji_parse.dm b/code/modules/emoji/emoji_parse.dm index 5ecadbe09c..58f261f8cc 100644 --- a/code/modules/emoji/emoji_parse.dm +++ b/code/modules/emoji/emoji_parse.dm @@ -16,7 +16,7 @@ if(search) emoji = lowertext(copytext(text, pos+1, search)) if(emoji in emojis) - parsed += bicon(icon('icons/emoji.dmi', emoji)) + parsed += icon2html('icons/emoji.dmi', world, emoji) pos = search + 1 else parsed += copytext(text, pos, search) diff --git a/code/modules/error_handler/error_handler.dm b/code/modules/error_handler/error_handler.dm index e2cce14db3..93605ea78a 100644 --- a/code/modules/error_handler/error_handler.dm +++ b/code/modules/error_handler/error_handler.dm @@ -55,7 +55,7 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0) var/skipcount = abs(error_cooldown[erroruid]) - 1 error_cooldown[erroruid] = 0 if(skipcount > 0) - world.log << "\[[time_stamp()]] Skipped [skipcount] runtimes in [E.file],[E.line]." + SEND_TEXT(world.log, "\[[time_stamp()]] Skipped [skipcount] runtimes in [E.file],[E.line].") GLOB.error_cache.log_error(E, skip_count = skipcount) error_last_seen[erroruid] = world.time @@ -92,9 +92,9 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0) if(GLOB.error_cache) GLOB.error_cache.log_error(E, desclines) - world.log << "\[[time_stamp()]] Runtime in [E.file],[E.line]: [E]" + SEND_TEXT(world.log, "\[[time_stamp()]] Runtime in [E.file],[E.line]: [E]") for(var/line in desclines) - world.log << line + SEND_TEXT(world.log, line) /* This logs the runtime in the old format */ diff --git a/code/modules/events/holiday/halloween.dm b/code/modules/events/holiday/halloween.dm index 8f634003f5..1386995c28 100644 --- a/code/modules/events/holiday/halloween.dm +++ b/code/modules/events/holiday/halloween.dm @@ -70,7 +70,7 @@ if(!H.client || !istype(H)) return to_chat(H, "Honk...") - H << 'sound/spookoween/scary_clown_appear.ogg' + SEND_SOUND(H, sound('sound/spookoween/scary_clown_appear.ogg')) var/turf/T = get_turf(H) if(T) new /obj/effect/hallucination/simple/clown(T, H, 50) diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm index 888b87cc02..9658d8b144 100644 --- a/code/modules/events/portal_storm.dm +++ b/code/modules/events/portal_storm.dm @@ -68,11 +68,11 @@ /datum/round_event/portal_storm/announce() set waitfor = 0 - playsound_global('sound/magic/lightning_chargeup.ogg', repeat=0, channel=1, volume=100) + sound_to_playing_players('sound/magic/lightning_chargeup.ogg') sleep(80) priority_announce("Massive bluespace anomaly detected en route to [station_name()]. Brace for impact.") sleep(20) - playsound_global('sound/magic/lightningbolt.ogg', repeat=0, channel=1, volume=100) + sound_to_playing_players('sound/magic/lightningbolt.ogg') /datum/round_event/portal_storm/tick() spawn_effects() diff --git a/code/modules/events/wizard/fakeexplosion.dm b/code/modules/events/wizard/fakeexplosion.dm index f6ffab2da8..3dee4a1f49 100644 --- a/code/modules/events/wizard/fakeexplosion.dm +++ b/code/modules/events/wizard/fakeexplosion.dm @@ -6,6 +6,5 @@ earliest_start = 0 /datum/round_event/wizard/fake_explosion/start() - for(var/mob/M in GLOB.player_list) - M << 'sound/machines/alarm.ogg' + sound_to_playing_players('sound/machines/alarm.ogg') addtimer(CALLBACK(SSticker, /datum/controller/subsystem/ticker/.proc/station_explosion_cinematic, 1, "fake"), 100) //:o) \ No newline at end of file diff --git a/code/modules/events/wizard/imposter.dm b/code/modules/events/wizard/imposter.dm index ffec648771..1ba052c4c0 100644 --- a/code/modules/events/wizard/imposter.dm +++ b/code/modules/events/wizard/imposter.dm @@ -55,4 +55,4 @@ I.log_message("Is an imposter!", INDIVIDUAL_ATTACK_LOG) to_chat(I, "You are an imposter! Trick and confuse the crew to misdirect malice from your handsome original!") - I << sound('sound/effects/magic.ogg') + SEND_SOUND(I, sound('sound/effects/magic.ogg')) diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index c1b0a387e4..2b8fe4b064 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -11,51 +11,83 @@ Gunshots/explosions/opening doors/less rare audio (done) */ +#define HAL_LINES_FILE "hallucination.json" + /mob/living/carbon var/image/halimage var/image/halbody var/obj/halitem var/hal_screwyhud = SCREWYHUD_NONE - var/handling_hal = 0 + var/next_hallucination = 0 + +GLOBAL_LIST_INIT(hallucinations_minor, list( + /datum/hallucination/sounds, + /datum/hallucination/bolts, + /datum/hallucination/whispers, + /datum/hallucination/message, + /datum/hallucination/hudscrew)) + +GLOBAL_LIST_INIT(hallucinations_medium, list( + /datum/hallucination/fake_alert, + /datum/hallucination/items, + /datum/hallucination/items_other, + /datum/hallucination/dangerflash, + /datum/hallucination/bolts, + /datum/hallucination/fake_flood, + /datum/hallucination/husks, + /datum/hallucination/battle, + /datum/hallucination/fire, + /datum/hallucination/self_delusion)) + +GLOBAL_LIST_INIT(hallucinations_major, list( + /datum/hallucination/fakeattacker, + /datum/hallucination/death, + /datum/hallucination/xeno_attack, + /datum/hallucination/singularity_scare, + /datum/hallucination/delusion, + /datum/hallucination/oh_yeah)) /mob/living/carbon/proc/handle_hallucinations() - if(handling_hal) + if(world.time < next_hallucination) return - //Least obvious - var/list/minor = list("sounds"=25,"bolts_minor"=5,"whispers"=15,"message"=10,"hudscrew"=15) - //Something's wrong here - var/list/medium = list("fake_alert"=15,"items"=10,"items_other"=10,"dangerflash"=10,"bolts"=5,"flood"=5,"husks"=10,"battle"=15,"self_delusion"=10) - //AAAAH - var/list/major = list("fake"=20,"death"=10,"xeno"=10,"singulo"=10,"borer"=10,"delusion"=20,"koolaid"=10) + if(hallucination) + var/list/current = GLOB.hallucinations_minor + if(prob(25) && hallucination > 100) + current = GLOB.hallucinations_medium + else if(prob(10) && hallucination > 200) + current = GLOB.hallucinations_major + var/halpick = pick(current) + new halpick(src, FALSE) - handling_hal = 1 - while(hallucination > 20) - sleep(rand(200,500)/(hallucination/25)) - if(prob(20)) - continue - var/list/current = list() - switch(rand(100)) - if(1 to 50) - current = minor - if(51 to 85) - current = medium - if(86 to 100) - current = major +/mob/living/carbon/proc/set_screwyhud(hud_type) + hal_screwyhud = hud_type + update_health_hud() - var/halpick = pickweight(current) +/datum/hallucination + var/mob/living/carbon/target + var/cost = 5 //affects the amount of hallucination reduced, and cooldown until the next hallucination + var/feedback_details //extra info for investigate - hallucinate(halpick) - handling_hal = 0 +/datum/hallucination/New(mob/living/carbon/T, forced = TRUE) + set waitfor = 0 + target = T + if(!forced) + target.hallucination = max(0, target.hallucination - cost) + target.next_hallucination = world.time + (rand(cost * 0.5, cost * 3) * 10) + +/datum/hallucination/proc/wake_and_restore() + target.set_screwyhud(SCREWYHUD_NONE) + target.SetSleeping(0) + +/datum/hallucination/Destroy() + target.investigate_log("was afflicted with a hallucination of type [type]. [feedback_details]", INVESTIGATE_HALLUCINATIONS) + return ..() /obj/effect/hallucination invisibility = INVISIBILITY_OBSERVER var/mob/living/carbon/target = null -/obj/effect/hallucination/proc/wake_and_restore() - target.hal_screwyhud = SCREWYHUD_NONE - target.SetSleeping(0) - /obj/effect/hallucination/simple var/image_icon = 'icons/mob/alien.dmi' var/image_state = "alienh_pounce" @@ -64,13 +96,14 @@ Gunshots/explosions/opening doors/less rare audio (done) var/col_mod = null var/image/current_image = null var/image_layer = MOB_LAYER - var/active = 1 //qdelery + var/active = TRUE //qdelery /obj/effect/hallucination/simple/Initialize(mapload, var/mob/living/carbon/T) ..() target = T current_image = GetImage() - if(target.client) target.client.images |= current_image + if(target.client) + target.client.images |= current_image /obj/effect/hallucination/simple/proc/GetImage() var/image/I = image(image_icon,src,image_state,image_layer,dir=src.dir) @@ -82,10 +115,12 @@ Gunshots/explosions/opening doors/less rare audio (done) /obj/effect/hallucination/simple/proc/Show(update=1) if(active) - if(target.client) target.client.images.Remove(current_image) + if(target.client) + target.client.images.Remove(current_image) if(update) current_image = GetImage() - if(target.client) target.client.images |= current_image + if(target.client) + target.client.images |= current_image /obj/effect/hallucination/simple/update_icon(new_state,new_icon,new_px=0,new_py=0) image_state = new_state @@ -101,36 +136,39 @@ Gunshots/explosions/opening doors/less rare audio (done) Show() /obj/effect/hallucination/simple/Destroy() - if(target.client) target.client.images.Remove(current_image) - active = 0 + if(target.client) + target.client.images.Remove(current_image) + active = FALSE return ..() #define FAKE_FLOOD_EXPAND_TIME 20 #define FAKE_FLOOD_MAX_RADIUS 10 -/obj/effect/hallucination/fake_flood +/datum/hallucination/fake_flood //Plasma starts flooding from the nearby vent + var/turf/center var/list/flood_images = list() var/list/turf/flood_turfs = list() var/image_icon = 'icons/effects/tile_effects.dmi' var/image_state = "plasma" var/radius = 0 var/next_expand = 0 + cost = 25 -/obj/effect/hallucination/fake_flood/Initialize(mapload, var/mob/living/carbon/T) +/datum/hallucination/fake_flood/New(mob/living/carbon/T, forced = TRUE) ..() - target = T for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in orange(7,target)) if(!U.welded) - src.loc = U.loc + center = get_turf(U) break - flood_images += image(image_icon,src,image_state,MOB_LAYER) - flood_turfs += get_turf(src.loc) + feedback_details += "Vent Coords: [center.x],[center.y],[center.z]" + flood_images += image(image_icon,center,image_state,MOB_LAYER) + flood_turfs += center if(target.client) target.client.images |= flood_images next_expand = world.time + FAKE_FLOOD_EXPAND_TIME START_PROCESSING(SSobj, src) -/obj/effect/hallucination/fake_flood/process() +/datum/hallucination/fake_flood/process() if(next_expand <= world.time) radius++ if(radius > FAKE_FLOOD_MAX_RADIUS) @@ -138,10 +176,10 @@ Gunshots/explosions/opening doors/less rare audio (done) return Expand() if((get_turf(target) in flood_turfs) && !target.internal) - target.hallucinate("fake_alert", "tox_in_air") + new /datum/hallucination/fake_alert(target, TRUE, "tox_in_air") next_expand = world.time + FAKE_FLOOD_EXPAND_TIME -/obj/effect/hallucination/fake_flood/proc/Expand() +/datum/hallucination/fake_flood/proc/Expand() for(var/turf/FT in flood_turfs) for(var/dir in GLOB.cardinals) var/turf/T = get_step(FT, dir) @@ -152,7 +190,7 @@ Gunshots/explosions/opening doors/less rare audio (done) if(target.client) target.client.images |= flood_images -/obj/effect/hallucination/fake_flood/Destroy() +/datum/hallucination/fake_flood/Destroy() STOP_PROCESSING(SSobj, src) qdel(flood_turfs) flood_turfs = list() @@ -167,7 +205,7 @@ Gunshots/explosions/opening doors/less rare audio (done) image_icon = 'icons/mob/alien.dmi' image_state = "alienh_pounce" -/obj/effect/hallucination/simple/xeno/Initialize(mapload, var/mob/living/carbon/T) +/obj/effect/hallucination/simple/xeno/Initialize(mapload, mob/living/carbon/T) ..() name = "alien hunter ([rand(1, 1000)])" @@ -177,18 +215,19 @@ Gunshots/explosions/opening doors/less rare audio (done) target.Knockdown(100) target.visible_message("[target] flails around wildly.","[name] pounces on you!") -/obj/effect/hallucination/xeno_attack +/datum/hallucination/xeno_attack //Xeno crawls from nearby vent,jumps at you, and goes back in var/obj/machinery/atmospherics/components/unary/vent_pump/pump = null var/obj/effect/hallucination/simple/xeno/xeno = null + cost = 25 -/obj/effect/hallucination/xeno_attack/Initialize(mapload, var/mob/living/carbon/T) +/datum/hallucination/xeno_attack/New(mob/living/carbon/T, forced = TRUE) ..() - target = T for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in orange(7,target)) if(!U.welded) pump = U break + feedback_details += "Vent Coords: [pump.x],[pump.y],[pump.z]" if(pump) xeno = new(pump.loc,target) sleep(10) @@ -200,7 +239,7 @@ Gunshots/explosions/opening doors/less rare audio (done) sleep(10) var/xeno_name = xeno.name to_chat(target, "[xeno_name] begins climbing into the ventilation system...") - sleep(10) + sleep(30) qdel(xeno) to_chat(target, "[xeno_name] scrambles into the ventilation ducts!") qdel(src) @@ -209,7 +248,7 @@ Gunshots/explosions/opening doors/less rare audio (done) image_icon = 'icons/mob/animal.dmi' image_state = "clown" -/obj/effect/hallucination/simple/clown/Initialize(mapload, var/mob/living/carbon/T,duration) +/obj/effect/hallucination/simple/clown/Initialize(mapload, mob/living/carbon/T, duration) ..(loc, T) name = pick(GLOB.clown_names) QDEL_IN(src,duration) @@ -217,59 +256,27 @@ Gunshots/explosions/opening doors/less rare audio (done) /obj/effect/hallucination/simple/clown/scary image_state = "scary_clown" -/obj/effect/hallucination/simple/borer - image_icon = 'icons/mob/borer.dmi' - image_state = "brainslug" - -/obj/effect/hallucination/borer - //A borer unconsciouss you and crawls in your ear - var/obj/machinery/atmospherics/components/unary/vent_pump/pump = null - var/obj/effect/hallucination/simple/borer/borer = null - -/obj/effect/hallucination/borer/Initialize(mapload, var/mob/living/carbon/T) - ..() - target = T - for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in orange(7,target)) - if(!U.welded) - pump = U - break - if(pump) - borer = new(pump.loc,target) - for(var/i=0, i<11, i++) - walk_to(borer, get_step(borer, get_cardinal_dir(borer, T))) - if(borer.Adjacent(T)) - to_chat(T, "You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing.") - T.Stun(80) - sleep(50) - qdel(borer) - sleep(rand(60, 90)) - to_chat(T, "Primary [rand(1000,9999)] states: [pick("Hello","Hi","You're my slave now!","Don't try to get rid of me...")]") - break - sleep(4) - if(!QDELETED(borer)) - qdel(borer) - qdel(src) - /obj/effect/hallucination/simple/bubblegum name = "Bubblegum" image_icon = 'icons/mob/lavaland/96x96megafauna.dmi' image_state = "bubblegum" px = -32 -/obj/effect/hallucination/oh_yeah +/datum/hallucination/oh_yeah var/obj/effect/hallucination/simple/bubblegum/bubblegum var/image/fakebroken var/image/fakerune + cost = 75 -/obj/effect/hallucination/oh_yeah/Initialize(mapload, var/mob/living/carbon/T) +/datum/hallucination/oh_yeah/New(mob/living/carbon/T, forced = TRUE) . = ..() - target = T var/turf/closed/wall/wall for(var/turf/closed/wall/W in range(7,target)) wall = W break if(!wall) return INITIALIZE_HINT_QDEL + feedback_details += "Source: [wall.x],[wall.y],[wall.z]" fakebroken = image('icons/turf/floors.dmi', wall, "plating", layer = TURF_LAYER) var/turf/landing = get_turf(target) @@ -283,7 +290,7 @@ Gunshots/explosions/opening doors/less rare audio (done) bubblegum = new(wall, target) addtimer(CALLBACK(src, .proc/bubble_attack, landing), 10) -/obj/effect/hallucination/oh_yeah/proc/bubble_attack(turf/landing) +/datum/hallucination/oh_yeah/proc/bubble_attack(turf/landing) var/charged = FALSE //only get hit once while(get_turf(bubblegum) != landing && target && target.stat != DEAD) bubblegum.forceMove(get_step_towards(bubblegum, landing)) @@ -301,7 +308,7 @@ Gunshots/explosions/opening doors/less rare audio (done) sleep(30) qdel(src) -/obj/effect/hallucination/oh_yeah/Destroy() +/datum/hallucination/oh_yeah/Destroy() if(target.client) target.client.images.Remove(fakebroken) target.client.images.Remove(fakerune) @@ -310,23 +317,24 @@ Gunshots/explosions/opening doors/less rare audio (done) QDEL_NULL(bubblegum) return ..() -/obj/effect/hallucination/singularity_scare +/datum/hallucination/singularity_scare //Singularity moving towards you. //todo Hide where it moved with fake space images var/obj/effect/hallucination/simple/singularity/s = null + cost = 75 -/obj/effect/hallucination/singularity_scare/Initialize(mapload, var/mob/living/carbon/T) +/datum/hallucination/singularity_scare/New(mob/living/carbon/T, forced = TRUE) ..() - target = T var/turf/start = get_turf(T) var/screen_border = pick(SOUTH,EAST,WEST,NORTH) - for(var/i = 0,i<11,i++) + for(var/i in 1 to 13) start = get_step(start,screen_border) + feedback_details += "Source: [start.x],[start.y],[start.z]" s = new(start,target) s.parent = src - for(var/i = 0,i<11,i++) - sleep(5) - s.loc = get_step(get_turf(s),get_dir(s,target)) + for(var/i in 1 to 13) + sleep(10) + s.forceMove(get_step(get_turf(s),get_dir(s,target))) s.Show() s.Eat() qdel(s) @@ -337,64 +345,72 @@ Gunshots/explosions/opening doors/less rare audio (done) image_layer = MASSIVE_OBJ_LAYER px = -96 py = -96 - var/obj/effect/hallucination/singularity_scare/parent + var/datum/hallucination/singularity_scare/parent /obj/effect/hallucination/simple/singularity/proc/Eat(atom/OldLoc, Dir) var/target_dist = get_dist(src,target) if(target_dist<=3) //"Eaten" - target.hal_screwyhud = SCREWYHUD_CRIT + target.set_screwyhud(SCREWYHUD_DEAD) target.SetUnconscious(160) - addtimer(CALLBACK(parent, .proc/wake_and_restore), rand(30, 50)) + addtimer(CALLBACK(parent, /datum/hallucination/.proc/wake_and_restore), rand(30, 50)) -/obj/effect/hallucination/battle +/datum/hallucination/battle + cost = 15 -/obj/effect/hallucination/battle/Initialize(mapload, var/mob/living/carbon/T) +/datum/hallucination/battle/New(mob/living/carbon/T, forced = TRUE, battle_type) ..() - target = T var/hits = rand(3,6) - switch(rand(1,5)) - if(1) //Laser fight - for(var/i=0,i...wabbajack...wabbajack...") - target.playsound_local(target,'sound/magic/staff_change.ogg', 50, 1, -1) + if(wabbajack) + to_chat(target, "...wabbajack...wabbajack...") + target.playsound_local(target,'sound/magic/staff_change.ogg', 50, 1) delusion = A target.client.images |= A QDEL_IN(src, duration) -/obj/effect/hallucination/self_delusion/Destroy() +/datum/hallucination/self_delusion/Destroy() if(target.client) target.client.images.Remove(delusion) return ..() -/obj/effect/hallucination/fakeattacker/Initialize(mapload, var/mob/living/carbon/T) +/datum/hallucination/fakeattacker/New(mob/living/carbon/T, forced = TRUE) ..() - target = T var/mob/living/carbon/human/clone = null var/clone_weapon = null @@ -523,6 +541,7 @@ Gunshots/explosions/opening doors/less rare audio (done) if(H.stat || H.lying) continue clone = H + feedback_details += "Clone of: [H.real_name]" break if(!clone) @@ -604,7 +623,7 @@ Gunshots/explosions/opening doors/less rare audio (done) for(var/mob/O in oviewers(world.view , my_target)) to_chat(O, "[my_target] stumbles around.") -/obj/effect/fake_attacker/Initialize(mapload, var/mob/living/carbon/T) +/obj/effect/fake_attacker/Initialize(mapload, mob/living/carbon/T) ..() my_target = T QDEL_IN(src, 300) @@ -651,7 +670,7 @@ Gunshots/explosions/opening doors/less rare audio (done) if(!locate(/obj/effect/overlay) in my_target.loc) fake_blood(my_target) else - my_target.playsound_local(my_target, pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg'), 25, 1, -1) + my_target.playsound_local(my_target, pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg'), 25, 1) my_target.show_message("[src.name] has punched [my_target]!", 1) my_target.staminaloss += 30 if(prob(33)) @@ -674,14 +693,15 @@ Gunshots/explosions/opening doors/less rare audio (done) QDEL_IN(O, 300) -/obj/effect/hallucination/bolts +/datum/hallucination/bolts var/list/doors = list() + cost = 25 -/obj/effect/hallucination/bolts/Initialize(mapload, var/mob/living/carbon/T,var/door_number=-1) //-1 for severe, 1-2 for subtle +/datum/hallucination/bolts/New(mob/living/carbon/T, forced, door_number=-1) //-1 for severe, 1-2 for subtle ..() - target = T var/image/I = null var/count = 0 + feedback_details += "Door amount: [door_number]" for(var/obj/machinery/door/airlock/A in range(7, target)) if(count>door_number && door_number>0) break @@ -700,13 +720,30 @@ Gunshots/explosions/opening doors/less rare audio (done) sleep(rand(6,12)) qdel(src) -/obj/effect/hallucination/whispers +/datum/hallucination/whispers + cost = 15 -/obj/effect/hallucination/whispers/Initialize(mapload, var/mob/living/carbon/T) +/datum/hallucination/whispers/New(mob/living/carbon/T, forced = TRUE) ..() - target = T - var/speak_messages = list("I'm watching you...","[target.first_name()]!","Get out!","Kchck-Chkck? Kchchck!","Did you hear that?","What did you do ?","Why?","Give me that!","HELP!!","EI NATH!!", "RUN!!", "Kill me!","O bidai nabora se'sma!", "[text2ratvar("Divinity, grant...")]") - var/radio_messages = list("Xenos!","Singularity loose!","Comms down!","They are arming the nuke!","They butchered Ian!","H-help!","[pick("Cult", "Wizard", "Ling", "Ops", "Revenant", "Murderer", "Harm", "I hear flashing", "Help")] in [pick(GLOB.teleportlocs)][prob(50)?"!":"!!"]","Where's [target.first_name()]?","Call the shuttle!","AI rogue!!") + var/speak_messages = list("[pick_list_replacements(HAL_LINES_FILE, "suspicion")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "greetings")][target.first_name()]!",\ + "[pick_list_replacements(HAL_LINES_FILE, "getout")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "weird")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "didyouhearthat")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "imatraitor")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "doubt")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "aggressive")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "help")]!!",\ + "[pick_list_replacements(HAL_LINES_FILE, "escape")]",\ + "I'm infected, [pick_list_replacements(HAL_LINES_FILE, "infection_advice")]!") + + var/radio_messages = list("Set [target.first_name()] to arrest!",\ + "[pick_list_replacements(HAL_LINES_FILE, "people")] is [pick_list_replacements(HAL_LINES_FILE, "accusations")]!",\ + "Help!",\ + "[pick_list_replacements(HAL_LINES_FILE, "threat")] in [pick_list_replacements(HAL_LINES_FILE, "location")][prob(50)?"!":"!!"]",\ + "Where's [target.first_name()]?"\ + ,"[pick("C","Ai, c","Someone c","Rec")]all the shuttle!"\ + ,"AI [pick("rogue", "is dead")]!!") var/list/mob/living/carbon/people = list() var/list/mob/living/carbon/person = null @@ -722,7 +759,9 @@ Gunshots/explosions/opening doors/less rare audio (done) people += H if(person) //Basic talk var/image/speech_overlay = image('icons/mob/talk.dmi', person, "default0", layer = ABOVE_MOB_LAYER) - to_chat(target, target.compose_message(person,understood_language,pick(speak_messages),null,person.get_spans())) + var/message = target.compose_message(person,understood_language,pick(speak_messages),null,person.get_spans()) + feedback_details += "Type: Talk, Source: [person.real_name], Message: [message]" + to_chat(target, message) if(target.client) target.client.images |= speech_overlay sleep(30) @@ -732,312 +771,381 @@ Gunshots/explosions/opening doors/less rare audio (done) for(var/mob/living/carbon/human/H in GLOB.living_mob_list) humans += H person = pick(humans) - to_chat(target, target.compose_message(person,understood_language,pick(radio_messages),"1459",person.get_spans())) + var/message = target.compose_message(person,understood_language,pick(radio_messages),"1459",person.get_spans()) + feedback_details += "Type: Radio, Source: [person.real_name], Message: [message]" + to_chat(target, message) qdel(src) -/obj/effect/hallucination/message +/datum/hallucination/message + cost = 15 -/obj/effect/hallucination/message/Initialize(mapload, var/mob/living/carbon/T) +/datum/hallucination/message/New(mob/living/carbon/T, forced = TRUE) ..() - target = T var/chosen = pick("The light burns you!", \ "You don't feel like yourself.", \ - "Unknown has punched [target]!", \ "You hear something squeezing through the ducts...", \ "You hear a distant scream.", \ "You feel invincible, nothing can hurt you!", \ "You feel a tiny prick!", \ "[target] sneezes.", \ - "You feel faint.", \ - "You hear a strange, alien voice in your head...[pick("Hiss","Ssss")]", \ - "You can see...everything!") + //The truth, revealed + "You're hallucinating.", \ + //Direct advice + "[pick_list_replacements(HAL_LINES_FILE, "advice")]") + feedback_details += "Message: [chosen]" to_chat(target, chosen) qdel(src) -/mob/living/carbon/proc/hallucinate(hal_type, specific) // specific is used to specify a particular hallucination - set waitfor = 0 - switch(hal_type) - if("xeno") - new /obj/effect/hallucination/xeno_attack(src.loc,src) - if("borer") - new /obj/effect/hallucination/borer(src.loc,src) - if("singulo") - new /obj/effect/hallucination/singularity_scare(src.loc,src) - if("koolaid") - new /obj/effect/hallucination/oh_yeah(src.loc,src) - if("battle") - new /obj/effect/hallucination/battle(src.loc,src) - if("flood") - new /obj/effect/hallucination/fake_flood(src.loc,src) - if("delusion") - new /obj/effect/hallucination/delusion(src.loc,src) - if("self_delusion") - new /obj/effect/hallucination/self_delusion(src.loc,src) - if("fake") - new /obj/effect/hallucination/fakeattacker(src.loc,src) - if("bolts") - new /obj/effect/hallucination/bolts(src.loc,src) - if("bolts_minor") - new /obj/effect/hallucination/bolts(src.loc,src,rand(1,2)) - if("whispers") - new /obj/effect/hallucination/whispers(src.loc,src) - if("message") - new /obj/effect/hallucination/message(src.loc,src) - if("items_other") - new /obj/effect/hallucination/items_other(src.loc,src) - if("sounds") - //Strange audio - switch(rand(1,20)) - if(1) playsound_local(null,'sound/machines/airlock.ogg', 15, 1) - if(2) - if(prob(50)) playsound_local(null,'sound/effects/explosion1.ogg', 50, 1) - else playsound_local(null, 'sound/effects/explosion2.ogg', 50, 1) - if(3) playsound_local(null, 'sound/effects/explosionfar.ogg', 50, 1) - if(4) playsound_local(null, pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg'), 50, 1) - if(5) - playsound_local(null, 'sound/weapons/ring.ogg', 35) - sleep(15) - playsound_local(null, 'sound/weapons/ring.ogg', 35) - sleep(15) - playsound_local(null, 'sound/weapons/ring.ogg', 35) - if(6) playsound_local(null, 'sound/magic/summon_guns.ogg', 50, 1) - if(7) playsound_local(null, 'sound/machines/alarm.ogg', 100, 0) - if(8) playsound_local(null, 'sound/voice/bfreeze.ogg', 35, 0) - if(9) - //To make it more realistic, I added two gunshots (enough to kill) - playsound_local(null, 'sound/weapons/gunshot.ogg', 25, 1) - spawn(rand(10,30)) - playsound_local(null, 'sound/weapons/gunshot.ogg', 25, 1) - sleep(rand(5,10)) - playsound_local(null, sound(get_sfx("bodyfall"), 25), 25, 1) - if(10) playsound_local(null, 'sound/effects/pray_chaplain.ogg', 50) - if(11) - //Same as above, but with tasers. - playsound_local(null, 'sound/weapons/taser.ogg', 25, 1) - spawn(rand(10,30)) - playsound_local(null, 'sound/weapons/taser.ogg', 25, 1) - sleep(rand(5,10)) - playsound_local(null, sound(get_sfx("bodyfall"), 25), 25, 1) - //Rare audio - if(12) - //These sounds are (mostly) taken from Hidden: Source - var/list/creepyasssounds = list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/heart_beat.ogg', 'sound/effects/screech.ogg',\ - 'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\ - 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\ - 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\ - 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg') - playsound_local(null, pick(creepyasssounds), 50, 1) - if(13) - playsound_local(null, 'sound/effects/ratvar_rises.ogg', 100) - sleep(150) - playsound_local(null, 'sound/effects/ratvar_reveal.ogg', 100) - if(14) - to_chat(src, "

Priority Announcement

") - to_chat(src, "

The Emergency Shuttle has docked with the station. You have 3 minutes to board the Emergency Shuttle.

") - playsound_local(null, 'sound/ai/shuttledock.ogg', 100) - //Deconstructing a wall - if(15) - playsound_local(null, 'sound/items/welder.ogg', 15, 1) - sleep(105) - playsound_local(null, 'sound/items/welder2.ogg', 15, 1) - sleep(15) - playsound_local(null, 'sound/items/ratchet.ogg', 15, 1) - //Hacking a door - if(16) - playsound_local(null, 'sound/items/screwdriver.ogg', 15, 1) - sleep(rand(10,30)) - for(var/i = rand(1,3), i>0, i--) - playsound_local(null, 'sound/weapons/empty.ogg', 15, 1) - sleep(rand(10,30)) - playsound_local(null, 'sound/machines/airlockforced.ogg', 15, 1) - if(17) - playsound_local(null, 'sound/weapons/saberon.ogg',35,1) - if(18) - to_chat(src, "

Biohazard Alert

") - to_chat(src, "

Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.

") - playsound_local(null, 'sound/ai/outbreak5.ogg') - if(19) //Tesla loose! - playsound_local(null, 'sound/magic/lightningbolt.ogg', 35, 1) - sleep(20) - playsound_local(null, 'sound/magic/lightningbolt.ogg', 65, 1) - sleep(20) - playsound_local(null, 'sound/magic/lightningbolt.ogg', 100, 1) - if(20) //AI is doomsdaying! - to_chat(src, "

Anomaly Alert

") - to_chat(src, "

Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.

") - playsound_local(null, 'sound/ai/aimalf.ogg', 100) - if("hudscrew") - //Screwy HUD - //to_chat(src, "Screwy HUD") - hal_screwyhud = pick(SCREWYHUD_NONE,SCREWYHUD_CRIT,SCREWYHUD_DEAD,SCREWYHUD_HEALTHY) - sleep(rand(100,250)) - hal_screwyhud = 0 +/datum/hallucination/sounds + cost = 15 - if("fake_alert") - var/alert_type = pick("not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","weightless","fire","locked","hacked","temp","pressure") - if(specific) - alert_type = specific - switch(alert_type) - if("not_enough_oxy") - throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy, override = TRUE) - if("not_enough_tox") - throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox, override = TRUE) - if("not_enough_co2") - throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2, override = TRUE) - if("too_much_oxy") - throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy, override = TRUE) - if("too_much_co2") - throw_alert("too_much_co2", /obj/screen/alert/too_much_co2, override = TRUE) - if("too_much_tox") - throw_alert("too_much_tox", /obj/screen/alert/too_much_tox, override = TRUE) - if("nutrition") - if(prob(50)) - throw_alert("nutrition", /obj/screen/alert/fat, override = TRUE) - else - throw_alert("nutrition", /obj/screen/alert/starving, override = TRUE) - if("weightless") - throw_alert("weightless", /obj/screen/alert/weightless, override = TRUE) - if("fire") - throw_alert("fire", /obj/screen/alert/fire, override = TRUE) - if("temp") - if(prob(50)) - throw_alert("temp", /obj/screen/alert/hot, 3, override = TRUE) - else - throw_alert("temp", /obj/screen/alert/cold, 3, override = TRUE) - if("pressure") - if(prob(50)) - throw_alert("pressure", /obj/screen/alert/highpressure, 2, override = TRUE) - else - throw_alert("pressure", /obj/screen/alert/lowpressure, 2, override = TRUE) - //BEEP BOOP I AM A ROBOT - if("newlaw") - throw_alert("newlaw", /obj/screen/alert/newlaw, override = TRUE) - if("locked") - throw_alert("locked", /obj/screen/alert/locked, override = TRUE) - if("hacked") - throw_alert("hacked", /obj/screen/alert/hacked, override = TRUE) - if("charge") - throw_alert("charge", /obj/screen/alert/emptycell, override = TRUE) - sleep(rand(100,200)) - clear_alert(alert_type, clear_override = TRUE) - - if("items") - //Strange items - //to_chat(src, "Traitor Items") - if(!halitem) - halitem = new - var/obj/item/l_hand = get_item_for_held_index(1) - var/obj/item/r_hand = get_item_for_held_index(2) - var/l = ui_hand_position(get_held_index_of_item(l_hand)) - var/r = ui_hand_position(get_held_index_of_item(r_hand)) - var/list/slots_free = list(l,r) - if(l_hand) slots_free -= l - if(r_hand) slots_free -= r - if(ishuman(src)) - var/mob/living/carbon/human/H = src - if(!H.belt) slots_free += ui_belt - if(!H.l_store) slots_free += ui_storage1 - if(!H.r_store) slots_free += ui_storage2 - if(slots_free.len) - halitem.screen_loc = pick(slots_free) - halitem.layer = ABOVE_HUD_LAYER - halitem.plane = ABOVE_HUD_PLANE - switch(rand(1,6)) - if(1) //revolver - halitem.icon = 'icons/obj/guns/projectile.dmi' - halitem.icon_state = "revolver" - halitem.name = "Revolver" - if(2) //c4 - halitem.icon = 'icons/obj/grenade.dmi' - halitem.icon_state = "plastic-explosive0" - halitem.name = "Mysterious Package" - if(prob(25)) - halitem.icon_state = "c4small_1" - if(3) //sword - halitem.icon = 'icons/obj/weapons.dmi' - halitem.icon_state = "sword1" - halitem.name = "Sword" - if(4) //stun baton - halitem.icon = 'icons/obj/weapons.dmi' - halitem.icon_state = "stunbaton" - halitem.name = "Stun Baton" - if(5) //emag - halitem.icon = 'icons/obj/card.dmi' - halitem.icon_state = "emag" - halitem.name = "Cryptographic Sequencer" - if(6) //flashbang - halitem.icon = 'icons/obj/grenade.dmi' - halitem.icon_state = "flashbang1" - halitem.name = "Flashbang" - if(client) client.screen += halitem - QDEL_IN(halitem, rand(100, 250)) - if("dangerflash") - //Flashes of danger - //to_chat(src, "Danger Flash") - if(!halimage) - var/list/possible_points = list() - for(var/turf/open/floor/F in view(src,world.view)) - possible_points += F - if(possible_points.len) - var/turf/open/floor/target = pick(possible_points) - - switch(rand(1,4)) - if(1) - //to_chat(src, "Space") - halimage = image('icons/turf/space.dmi',target,"[rand(1,25)]",TURF_LAYER) - if(2) - //to_chat(src, "Lava") - halimage = image('icons/turf/floors/lava.dmi',target,"smooth",TURF_LAYER) - if(3) - //to_chat(src, "Chasm") - halimage = image('icons/turf/floors/Chasms.dmi',target,"smooth",TURF_LAYER) - if(4) - //to_chat(src, "C4") - halimage = image('icons/obj/grenade.dmi',target,"plastic-explosive2",OBJ_LAYER+0.01) - - - if(client) client.images += halimage - sleep(rand(40,60)) //Only seen for a brief moment. - if(client) client.images -= halimage - halimage = null - if("death") - //Fake death - hal_screwyhud = SCREWYHUD_DEAD - SetUnconscious(400) - var/area/area = get_area(src) - to_chat(src, "[mind.name] has died at [area.name].") +/datum/hallucination/sounds/New(mob/living/carbon/T, forced = TRUE, sound_type) + ..() + if(!sound_type) + sound_type = pick("airlock","explosion","far_explosion","glass","phone","summon_guns","alarm","beepsky","hallelujah","creepy","ratvar","shuttle_dock", + "wall_decon","door_hack","esword","blob_alert","tesla","malf_ai") + feedback_details += "Type: [sound_type]" + //Strange audio + switch(sound_type) + if("airlock") + target.playsound_local(null,'sound/machines/airlock.ogg', 15, 1) + if("explosion") if(prob(50)) - var/list/dead_people = list() - for(var/mob/dead/observer/G in GLOB.player_list) - dead_people += G - var/mob/dead/observer/fakemob = pick(dead_people) - if(fakemob) - sleep(rand(30, 60)) - to_chat(src, "DEAD: [fakemob.name] says, \"[pick("rip","welcome [first_name()]","you too?","is the AI malf?",\ - "i[prob(50)?" fucking":""] hate [pick("blood cult", "clock cult", "revenants", "abductors","double agents","viruses","badmins","you")]")]\"") - sleep(rand(50,70)) - hal_screwyhud = SCREWYHUD_NONE - SetSleeping(0) - if("husks") - if(!halbody) - var/list/possible_points = list() - for(var/turf/open/floor/F in view(src,world.view)) - possible_points += F - if(possible_points.len) - var/turf/open/floor/target = pick(possible_points) - switch(rand(1,4)) - if(1) - var/image/body = image('icons/mob/human.dmi',target,"husk",TURF_LAYER) - var/matrix/M = matrix() - M.Turn(90) - body.transform = M - halbody = body - if(2,3) - halbody = image('icons/mob/human.dmi',target,"husk",TURF_LAYER) - if(4) - halbody = image('icons/mob/alien.dmi',target,"alienother",TURF_LAYER) + target.playsound_local(null,'sound/effects/explosion1.ogg', 50, 1) + else + target.playsound_local(null, 'sound/effects/explosion2.ogg', 50, 1) + if("far_explosion") + target.playsound_local(null, 'sound/effects/explosionfar.ogg', 50, 1) + if("glass") + target.playsound_local(null, pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg'), 50, 1) + if("phone") + target.playsound_local(null, 'sound/weapons/ring.ogg', 35) + sleep(15) + target.playsound_local(null, 'sound/weapons/ring.ogg', 35) + sleep(15) + target.playsound_local(null, 'sound/weapons/ring.ogg', 35) + if("summon_guns") + target.playsound_local(null, 'sound/magic/summon_guns.ogg', 50, 1) + if("alarm") + target.playsound_local(null, 'sound/machines/alarm.ogg', 100, 0) + if("beepsky") + target.playsound_local(null, 'sound/voice/bfreeze.ogg', 35, 0) + if("hallelujah") + target.playsound_local(null, 'sound/effects/pray_chaplain.ogg', 50) + //Rare audio + if("creepy") + //These sounds are (mostly) taken from Hidden: Source + var/static/list/hallucinations_creepyasssounds = list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/heart_beat.ogg', 'sound/effects/screech.ogg',\ + 'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\ + 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\ + 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\ + 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg') + target.playsound_local(null, pick(hallucinations_creepyasssounds), 50, 1) + if("ratvar") + target.playsound_local(null, 'sound/effects/ratvar_rises.ogg', 100) + sleep(150) + target.playsound_local(null, 'sound/effects/ratvar_reveal.ogg', 100) + if("shuttle_dock") + to_chat(target, "

Priority Announcement

") + to_chat(target, "

The Emergency Shuttle has docked with the station. You have 3 minutes to board the Emergency Shuttle.

") + target.playsound_local(null, 'sound/ai/shuttledock.ogg', 100) + //Deconstructing a wall + if("wall_decon") + target.playsound_local(null, 'sound/items/welder.ogg', 15, 1) + sleep(105) + target.playsound_local(null, 'sound/items/welder2.ogg', 15, 1) + sleep(15) + target.playsound_local(null, 'sound/items/ratchet.ogg', 15, 1) + //Hacking a door + if("door_hack") + target.playsound_local(null, 'sound/items/screwdriver.ogg', 15, 1) + sleep(rand(10,30)) + for(var/i = rand(1,3), i>0, i--) + target.playsound_local(null, 'sound/weapons/empty.ogg', 15, 1) + sleep(rand(10,30)) + target.playsound_local(null, 'sound/machines/airlockforced.ogg', 15, 1) + if("esword") + target.playsound_local(null, 'sound/weapons/saberon.ogg',35,1) + if("blob_alert") + to_chat(target, "

Biohazard Alert

") + to_chat(target, "

Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.

") + target.playsound_local(null, 'sound/ai/outbreak5.ogg', 100, 0) + if("tesla") //Tesla loose! + target.playsound_local(null, 'sound/magic/lightningbolt.ogg', 35, 1) + sleep(20) + target.playsound_local(null, 'sound/magic/lightningbolt.ogg', 65, 1) + sleep(20) + target.playsound_local(null, 'sound/magic/lightningbolt.ogg', 100, 1) + if("malf_ai") //AI is doomsdaying! + to_chat(target, "

Anomaly Alert

") + to_chat(target, "

Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.

") + target.playsound_local(null, 'sound/ai/aimalf.ogg', 100, 0) + qdel(src) + +/datum/hallucination/hudscrew + cost = 10 + +/datum/hallucination/hudscrew/New(mob/living/carbon/T, forced = TRUE) + ..() + //Screwy HUD + target.set_screwyhud(pick(SCREWYHUD_CRIT,SCREWYHUD_DEAD,SCREWYHUD_HEALTHY)) + feedback_details += "Type: [target.hal_screwyhud]" + sleep(rand(100,250)) + target.set_screwyhud(SCREWYHUD_NONE) + qdel(src) + +/datum/hallucination/fake_alert + cost = 15 + +/datum/hallucination/fake_alert/New(mob/living/carbon/T, forced = TRUE, specific, duration = 150) + ..() + var/alert_type = pick("not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","weightless","fire","locked","hacked","temphot","tempcold","pressure") + if(specific) + alert_type = specific + feedback_details += "Type: [alert_type]" + switch(alert_type) + if("oxy") + target.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy, override = TRUE) + if("not_enough_tox") + target.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox, override = TRUE) + if("not_enough_co2") + target.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2, override = TRUE) + if("too_much_oxy") + target.throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy, override = TRUE) + if("too_much_co2") + target.throw_alert("too_much_co2", /obj/screen/alert/too_much_co2, override = TRUE) + if("tox_in_air") + target.throw_alert("too_much_tox", /obj/screen/alert/too_much_tox, override = TRUE) + if("nutrition") + if(prob(50)) + target.throw_alert("nutrition", /obj/screen/alert/fat, override = TRUE) + else + target.throw_alert("nutrition", /obj/screen/alert/starving, override = TRUE) + if("weightless") + target.throw_alert("weightless", /obj/screen/alert/weightless, override = TRUE) + if("fire") + target.throw_alert("fire", /obj/screen/alert/fire, override = TRUE) + if("temphot") + target.throw_alert("temp", /obj/screen/alert/hot, 3, override = TRUE) + if("tempcold") + target.throw_alert("temp", /obj/screen/alert/cold, 3, override = TRUE) + if("pressure") + if(prob(50)) + target.throw_alert("pressure", /obj/screen/alert/highpressure, 2, override = TRUE) + else + target.throw_alert("pressure", /obj/screen/alert/lowpressure, 2, override = TRUE) + //BEEP BOOP I AM A ROBOT + if("newlaw") + target.throw_alert("newlaw", /obj/screen/alert/newlaw, override = TRUE) + if("locked") + target.throw_alert("locked", /obj/screen/alert/locked, override = TRUE) + if("hacked") + target.throw_alert("hacked", /obj/screen/alert/hacked, override = TRUE) + if("charge") + target.throw_alert("charge",/obj/screen/alert/emptycell, override = TRUE) + sleep(duration) + target.clear_alert(alert_type, clear_override = TRUE) + qdel(src) + +/datum/hallucination/items + cost = 15 + +/datum/hallucination/items/New(mob/living/carbon/T, forced = TRUE) + ..() + //Strange items + if(!target.halitem) + target.halitem = new + var/obj/item/l_hand = target.get_item_for_held_index(1) + var/obj/item/r_hand = target.get_item_for_held_index(2) + var/l = ui_hand_position(target.get_held_index_of_item(l_hand)) + var/r = ui_hand_position(target.get_held_index_of_item(r_hand)) + var/list/slots_free = list(l,r) + if(l_hand) slots_free -= l + if(r_hand) slots_free -= r + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(!H.belt) slots_free += ui_belt + if(!H.l_store) slots_free += ui_storage1 + if(!H.r_store) slots_free += ui_storage2 + if(slots_free.len) + target.halitem.screen_loc = pick(slots_free) + target.halitem.layer = ABOVE_HUD_LAYER + target.halitem.plane = ABOVE_HUD_PLANE + switch(rand(1,6)) + if(1) //revolver + target.halitem.icon = 'icons/obj/guns/projectile.dmi' + target.halitem.icon_state = "revolver" + target.halitem.name = "Revolver" + if(2) //c4 + target.halitem.icon = 'icons/obj/grenade.dmi' + target.halitem.icon_state = "plastic-explosive0" + target.halitem.name = "C4" + if(prob(25)) + target.halitem.icon_state = "plasticx40" + if(3) //sword + target.halitem.icon = 'icons/obj/weapons.dmi' + target.halitem.icon_state = "sword0" + target.halitem.name = "Energy Sword" + if(4) //stun baton + target.halitem.icon = 'icons/obj/weapons.dmi' + target.halitem.icon_state = "stunbaton" + target.halitem.name = "Stun Baton" + if(5) //emag + target.halitem.icon = 'icons/obj/card.dmi' + target.halitem.icon_state = "emag" + target.halitem.name = "Cryptographic Sequencer" + if(6) //flashbang + target.halitem.icon = 'icons/obj/grenade.dmi' + target.halitem.icon_state = "flashbang1" + target.halitem.name = "Flashbang" + feedback_details += "Type: [target.halitem.name]" + if(target.client) target.client.screen += target.halitem + QDEL_IN(target.halitem, rand(150, 350)) + qdel(src) + +/datum/hallucination/dangerflash + cost = 15 + +/datum/hallucination/dangerflash/New(mob/living/carbon/T, forced = TRUE) + ..() + //Flashes of danger + if(!target.halimage) + var/list/possible_points = list() + for(var/turf/open/floor/F in view(target,world.view)) + possible_points += F + if(possible_points.len) + var/turf/open/floor/danger_point = pick(possible_points) + + switch(rand(1,5)) + if(1) + target.halimage = image('icons/turf/space.dmi',danger_point,"[rand(1,25)]",TURF_LAYER) + if(2) + target.halimage = image('icons/turf/floors/lava.dmi',danger_point,"smooth",TURF_LAYER) + if(3) + target.halimage = image('icons/turf/floors/Chasms.dmi',danger_point,"smooth",TURF_LAYER) + if(4) + target.halimage = image('icons/effects/effects.dmi',danger_point,"anom",OBJ_LAYER+0.01) + if(5) + target.halimage = image('icons/effects/effects.dmi',danger_point,"electricity2",OBJ_LAYER+0.01) + + + if(target.client) + target.client.images += target.halimage + sleep(rand(200,450)) + if(target.client) + target.client.images -= target.halimage + QDEL_NULL(target.halimage) + qdel(src) + +/datum/hallucination/death + cost = 40 + +/datum/hallucination/death/New(mob/living/carbon/T, forced = TRUE) + set waitfor = 0 + ..() + target.set_screwyhud(SCREWYHUD_DEAD) + target.Knockdown(300) + target.silent += 10 + var/area/area = get_area(target) + to_chat(target, "[target.mind.name] has died at [area.name].") + if(prob(50)) + var/mob/fakemob + var/list/dead_people = list() + for(var/mob/dead/observer/G in GLOB.player_list) + dead_people += G + if(LAZYLEN(dead_people)) + fakemob = pick(dead_people) + else + fakemob = target //ever been so lonely you had to haunt yourself? + if(fakemob) + sleep(rand(20, 50)) + to_chat(target, "DEAD: [fakemob.name] says, \"[pick("rip","hey [target.first_name()]","you too?","is the AI rogue?",\ + "i[prob(50)?" fucking":""] hate [pick("blood cult", "clock cult", "revenants", "abductors","double agents","viruses","badmins","you")]")]\"") + sleep(rand(70,90)) + target.set_screwyhud(SCREWYHUD_NONE) + target.SetKnockdown(0) + target.silent = 0 + qdel(src) + +/datum/hallucination/fire + cost = 25 + +/datum/hallucination/fire/New(mob/living/carbon/T, forced = TRUE) + ..() + var/image/fire_overlay = image('icons/mob/OnFire.dmi', target, "Standing", ABOVE_MOB_LAYER) + if(target.client) + target.client.images += fire_overlay + to_chat(target, "You're set on fire!") + target.throw_alert("fire", /obj/screen/alert/fire, override = TRUE) + sleep(20) + target.throw_alert("temp", /obj/screen/alert/hot, 1, override = TRUE) + sleep(30) + target.clear_alert("temp", clear_override = TRUE) + target.throw_alert("temp", /obj/screen/alert/hot, 2, override = TRUE) + sleep(30) + target.clear_alert("temp", clear_override = TRUE) + target.throw_alert("temp", /obj/screen/alert/hot, 3, override = TRUE) + for(var/i in 1 to rand(5, 10)) + target.adjustStaminaLoss(15) + sleep(25) + target.clear_alert("fire", clear_override = TRUE) + target.clear_alert("temp", clear_override = TRUE) + if(target.client) + target.client.images -= fire_overlay + QDEL_NULL(fire_overlay) + qdel(src) + +/datum/hallucination/husks + cost = 20 + +/datum/hallucination/husks/New(mob/living/carbon/T, forced = TRUE) + ..() + if(!target.halbody) + var/list/possible_points = list() + for(var/turf/open/floor/F in view(target,world.view)) + possible_points += F + if(possible_points.len) + var/turf/open/floor/husk_point = pick(possible_points) + switch(rand(1,4)) + if(1) + var/image/body = image('icons/mob/human.dmi',husk_point,"husk",TURF_LAYER) + var/matrix/M = matrix() + M.Turn(90) + body.transform = M + target.halbody = body + if(2,3) + target.halbody = image('icons/mob/human.dmi',husk_point,"husk",TURF_LAYER) + if(4) + target.halbody = image('icons/mob/alien.dmi',husk_point,"alienother",TURF_LAYER) + + if(target.client) + target.client.images += target.halbody + sleep(rand(30,50)) //Only seen for a brief moment. + if(target.client) + target.client.images -= target.halbody + QDEL_NULL(target.halbody) + qdel(src) + +//hallucination projectile code in code/modules/projectiles/projectile/special.dm +/datum/hallucination/stray_bullet + cost = 15 + +/datum/hallucination/stray_bullet/New(mob/living/carbon/C, forced = TRUE) + ..() + var/list/turf/startlocs = list() + for(var/turf/open/T in view(world.view+1,target)-view(world.view,target)) + startlocs += T + var/turf/start = pick(startlocs) + var/proj_type = pick(subtypesof(/obj/item/projectile/hallucination)) + feedback_details += "Type: [proj_type]" + var/obj/item/projectile/hallucination/H = new proj_type(start) + target.playsound_local(start, H.hal_fire_sound, 60, 1) + H.hal_target = target + H.current = start + H.starting = start + H.yo = target.y - start.y + H.xo = target.x - start.x + H.original = target + H.fire() + qdel(src) - if(client) client.images += halbody - spawn(rand(30,50)) //Only seen for a brief moment. - if(client) client.images -= halbody - halbody = null diff --git a/code/modules/flufftext/Hallucination.dm.rej b/code/modules/flufftext/Hallucination.dm.rej new file mode 100644 index 0000000000..2b8fe4b064 --- /dev/null +++ b/code/modules/flufftext/Hallucination.dm.rej @@ -0,0 +1,1151 @@ +/* +Ideas for the subtle effects of hallucination: + +Light up oxygen/plasma indicators (done) +Cause health to look critical/dead, even when standing (done) +Characters silently watching you +Brief flashes of fire/space/bombs/c4/dangerous shit (done) +Items that are rare/traitorous/don't exist appearing in your inventory slots (done) +Strange audio (should be rare) (done) +Gunshots/explosions/opening doors/less rare audio (done) + +*/ + +#define HAL_LINES_FILE "hallucination.json" + +/mob/living/carbon + var/image/halimage + var/image/halbody + var/obj/halitem + var/hal_screwyhud = SCREWYHUD_NONE + var/next_hallucination = 0 + +GLOBAL_LIST_INIT(hallucinations_minor, list( + /datum/hallucination/sounds, + /datum/hallucination/bolts, + /datum/hallucination/whispers, + /datum/hallucination/message, + /datum/hallucination/hudscrew)) + +GLOBAL_LIST_INIT(hallucinations_medium, list( + /datum/hallucination/fake_alert, + /datum/hallucination/items, + /datum/hallucination/items_other, + /datum/hallucination/dangerflash, + /datum/hallucination/bolts, + /datum/hallucination/fake_flood, + /datum/hallucination/husks, + /datum/hallucination/battle, + /datum/hallucination/fire, + /datum/hallucination/self_delusion)) + +GLOBAL_LIST_INIT(hallucinations_major, list( + /datum/hallucination/fakeattacker, + /datum/hallucination/death, + /datum/hallucination/xeno_attack, + /datum/hallucination/singularity_scare, + /datum/hallucination/delusion, + /datum/hallucination/oh_yeah)) + +/mob/living/carbon/proc/handle_hallucinations() + if(world.time < next_hallucination) + return + + if(hallucination) + var/list/current = GLOB.hallucinations_minor + if(prob(25) && hallucination > 100) + current = GLOB.hallucinations_medium + else if(prob(10) && hallucination > 200) + current = GLOB.hallucinations_major + var/halpick = pick(current) + new halpick(src, FALSE) + +/mob/living/carbon/proc/set_screwyhud(hud_type) + hal_screwyhud = hud_type + update_health_hud() + +/datum/hallucination + var/mob/living/carbon/target + var/cost = 5 //affects the amount of hallucination reduced, and cooldown until the next hallucination + var/feedback_details //extra info for investigate + +/datum/hallucination/New(mob/living/carbon/T, forced = TRUE) + set waitfor = 0 + target = T + if(!forced) + target.hallucination = max(0, target.hallucination - cost) + target.next_hallucination = world.time + (rand(cost * 0.5, cost * 3) * 10) + +/datum/hallucination/proc/wake_and_restore() + target.set_screwyhud(SCREWYHUD_NONE) + target.SetSleeping(0) + +/datum/hallucination/Destroy() + target.investigate_log("was afflicted with a hallucination of type [type]. [feedback_details]", INVESTIGATE_HALLUCINATIONS) + return ..() + +/obj/effect/hallucination + invisibility = INVISIBILITY_OBSERVER + var/mob/living/carbon/target = null + +/obj/effect/hallucination/simple + var/image_icon = 'icons/mob/alien.dmi' + var/image_state = "alienh_pounce" + var/px = 0 + var/py = 0 + var/col_mod = null + var/image/current_image = null + var/image_layer = MOB_LAYER + var/active = TRUE //qdelery + +/obj/effect/hallucination/simple/Initialize(mapload, var/mob/living/carbon/T) + ..() + target = T + current_image = GetImage() + if(target.client) + target.client.images |= current_image + +/obj/effect/hallucination/simple/proc/GetImage() + var/image/I = image(image_icon,src,image_state,image_layer,dir=src.dir) + I.pixel_x = px + I.pixel_y = py + if(col_mod) + I.color = col_mod + return I + +/obj/effect/hallucination/simple/proc/Show(update=1) + if(active) + if(target.client) + target.client.images.Remove(current_image) + if(update) + current_image = GetImage() + if(target.client) + target.client.images |= current_image + +/obj/effect/hallucination/simple/update_icon(new_state,new_icon,new_px=0,new_py=0) + image_state = new_state + if(new_icon) + image_icon = new_icon + else + image_icon = initial(image_icon) + px = new_px + py = new_py + Show() + +/obj/effect/hallucination/simple/Moved(atom/OldLoc, Dir) + Show() + +/obj/effect/hallucination/simple/Destroy() + if(target.client) + target.client.images.Remove(current_image) + active = FALSE + return ..() + +#define FAKE_FLOOD_EXPAND_TIME 20 +#define FAKE_FLOOD_MAX_RADIUS 10 + +/datum/hallucination/fake_flood + //Plasma starts flooding from the nearby vent + var/turf/center + var/list/flood_images = list() + var/list/turf/flood_turfs = list() + var/image_icon = 'icons/effects/tile_effects.dmi' + var/image_state = "plasma" + var/radius = 0 + var/next_expand = 0 + cost = 25 + +/datum/hallucination/fake_flood/New(mob/living/carbon/T, forced = TRUE) + ..() + for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in orange(7,target)) + if(!U.welded) + center = get_turf(U) + break + feedback_details += "Vent Coords: [center.x],[center.y],[center.z]" + flood_images += image(image_icon,center,image_state,MOB_LAYER) + flood_turfs += center + if(target.client) target.client.images |= flood_images + next_expand = world.time + FAKE_FLOOD_EXPAND_TIME + START_PROCESSING(SSobj, src) + +/datum/hallucination/fake_flood/process() + if(next_expand <= world.time) + radius++ + if(radius > FAKE_FLOOD_MAX_RADIUS) + qdel(src) + return + Expand() + if((get_turf(target) in flood_turfs) && !target.internal) + new /datum/hallucination/fake_alert(target, TRUE, "tox_in_air") + next_expand = world.time + FAKE_FLOOD_EXPAND_TIME + +/datum/hallucination/fake_flood/proc/Expand() + for(var/turf/FT in flood_turfs) + for(var/dir in GLOB.cardinals) + var/turf/T = get_step(FT, dir) + if((T in flood_turfs) || !FT.CanAtmosPass(T)) + continue + flood_images += image(image_icon,T,image_state,MOB_LAYER) + flood_turfs += T + if(target.client) + target.client.images |= flood_images + +/datum/hallucination/fake_flood/Destroy() + STOP_PROCESSING(SSobj, src) + qdel(flood_turfs) + flood_turfs = list() + if(target.client) + target.client.images.Remove(flood_images) + target = null + qdel(flood_images) + flood_images = list() + return ..() + +/obj/effect/hallucination/simple/xeno + image_icon = 'icons/mob/alien.dmi' + image_state = "alienh_pounce" + +/obj/effect/hallucination/simple/xeno/Initialize(mapload, mob/living/carbon/T) + ..() + name = "alien hunter ([rand(1, 1000)])" + +/obj/effect/hallucination/simple/xeno/throw_impact(A) + update_icon("alienh_pounce") + if(A == target && target.stat!=DEAD) + target.Knockdown(100) + target.visible_message("[target] flails around wildly.","[name] pounces on you!") + +/datum/hallucination/xeno_attack + //Xeno crawls from nearby vent,jumps at you, and goes back in + var/obj/machinery/atmospherics/components/unary/vent_pump/pump = null + var/obj/effect/hallucination/simple/xeno/xeno = null + cost = 25 + +/datum/hallucination/xeno_attack/New(mob/living/carbon/T, forced = TRUE) + ..() + for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in orange(7,target)) + if(!U.welded) + pump = U + break + feedback_details += "Vent Coords: [pump.x],[pump.y],[pump.z]" + if(pump) + xeno = new(pump.loc,target) + sleep(10) + xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32) + xeno.throw_at(target,7,1, spin = 0, diagonals_first = 1) + sleep(10) + xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32) + xeno.throw_at(pump,7,1, spin = 0, diagonals_first = 1) + sleep(10) + var/xeno_name = xeno.name + to_chat(target, "[xeno_name] begins climbing into the ventilation system...") + sleep(30) + qdel(xeno) + to_chat(target, "[xeno_name] scrambles into the ventilation ducts!") + qdel(src) + +/obj/effect/hallucination/simple/clown + image_icon = 'icons/mob/animal.dmi' + image_state = "clown" + +/obj/effect/hallucination/simple/clown/Initialize(mapload, mob/living/carbon/T, duration) + ..(loc, T) + name = pick(GLOB.clown_names) + QDEL_IN(src,duration) + +/obj/effect/hallucination/simple/clown/scary + image_state = "scary_clown" + +/obj/effect/hallucination/simple/bubblegum + name = "Bubblegum" + image_icon = 'icons/mob/lavaland/96x96megafauna.dmi' + image_state = "bubblegum" + px = -32 + +/datum/hallucination/oh_yeah + var/obj/effect/hallucination/simple/bubblegum/bubblegum + var/image/fakebroken + var/image/fakerune + cost = 75 + +/datum/hallucination/oh_yeah/New(mob/living/carbon/T, forced = TRUE) + . = ..() + var/turf/closed/wall/wall + for(var/turf/closed/wall/W in range(7,target)) + wall = W + break + if(!wall) + return INITIALIZE_HINT_QDEL + feedback_details += "Source: [wall.x],[wall.y],[wall.z]" + + fakebroken = image('icons/turf/floors.dmi', wall, "plating", layer = TURF_LAYER) + var/turf/landing = get_turf(target) + var/turf/landing_image_turf = get_step(landing, SOUTHWEST) //the icon is 3x3 + fakerune = image('icons/effects/96x96.dmi', landing_image_turf, "landing", layer = ABOVE_OPEN_TURF_LAYER) + fakebroken.override = TRUE + if(target.client) + target.client.images |= fakebroken + target.client.images |= fakerune + target.playsound_local(wall,'sound/effects/meteorimpact.ogg', 150, 1) + bubblegum = new(wall, target) + addtimer(CALLBACK(src, .proc/bubble_attack, landing), 10) + +/datum/hallucination/oh_yeah/proc/bubble_attack(turf/landing) + var/charged = FALSE //only get hit once + while(get_turf(bubblegum) != landing && target && target.stat != DEAD) + bubblegum.forceMove(get_step_towards(bubblegum, landing)) + bubblegum.setDir(get_dir(bubblegum, landing)) + target.playsound_local(get_turf(bubblegum), 'sound/effects/meteorimpact.ogg', 150, 1) + shake_camera(target, 2, 1) + if(bubblegum.Adjacent(target) && !charged) + charged = TRUE + target.Knockdown(80) + target.adjustStaminaLoss(40) + step_away(target, bubblegum) + shake_camera(target, 4, 3) + target.visible_message("[target] jumps backwards, falling on the ground!","[bubblegum] slams into you!") + sleep(2) + sleep(30) + qdel(src) + +/datum/hallucination/oh_yeah/Destroy() + if(target.client) + target.client.images.Remove(fakebroken) + target.client.images.Remove(fakerune) + QDEL_NULL(fakebroken) + QDEL_NULL(fakerune) + QDEL_NULL(bubblegum) + return ..() + +/datum/hallucination/singularity_scare + //Singularity moving towards you. + //todo Hide where it moved with fake space images + var/obj/effect/hallucination/simple/singularity/s = null + cost = 75 + +/datum/hallucination/singularity_scare/New(mob/living/carbon/T, forced = TRUE) + ..() + var/turf/start = get_turf(T) + var/screen_border = pick(SOUTH,EAST,WEST,NORTH) + for(var/i in 1 to 13) + start = get_step(start,screen_border) + feedback_details += "Source: [start.x],[start.y],[start.z]" + s = new(start,target) + s.parent = src + for(var/i in 1 to 13) + sleep(10) + s.forceMove(get_step(get_turf(s),get_dir(s,target))) + s.Show() + s.Eat() + qdel(s) + +/obj/effect/hallucination/simple/singularity + image_icon = 'icons/effects/224x224.dmi' + image_state = "singularity_s7" + image_layer = MASSIVE_OBJ_LAYER + px = -96 + py = -96 + var/datum/hallucination/singularity_scare/parent + +/obj/effect/hallucination/simple/singularity/proc/Eat(atom/OldLoc, Dir) + var/target_dist = get_dist(src,target) + if(target_dist<=3) //"Eaten" + target.set_screwyhud(SCREWYHUD_DEAD) + target.SetUnconscious(160) + addtimer(CALLBACK(parent, /datum/hallucination/.proc/wake_and_restore), rand(30, 50)) + +/datum/hallucination/battle + cost = 15 + +/datum/hallucination/battle/New(mob/living/carbon/T, forced = TRUE, battle_type) + ..() + var/hits = rand(3,6) + if(!battle_type) + battle_type = pick("laser","esword","gun","stunprod","bomb") + feedback_details += "Type: [battle_type]" + switch(battle_type) + if("laser") //Laser fight + for(var/i in 1 to hits) + target.playsound_local(null, 'sound/weapons/laser.ogg', 25, 1) + if(prob(50)) + addtimer(CALLBACK(target, /mob/.proc/playsound_local, null, 'sound/weapons/sear.ogg', 25, 1), rand(10,20)) + else + addtimer(CALLBACK(target, /mob/.proc/playsound_local, null, 'sound/weapons/effects/searwall.ogg', 25, 1), rand(10,20)) + sleep(rand(CLICK_CD_RANGE, CLICK_CD_RANGE + 8)) + target.playsound_local(null, get_sfx("bodyfall"), 25, 1) + if("esword") //Esword fight + target.playsound_local(null, 'sound/weapons/saberon.ogg',15, 1) + for(var/i=0,i...wabbajack...wabbajack...") + target.playsound_local(target,'sound/magic/staff_change.ogg', 50, 1) + delusion = A + target.client.images |= A + QDEL_IN(src, duration) + +/datum/hallucination/self_delusion/Destroy() + if(target.client) + target.client.images.Remove(delusion) + return ..() + +/datum/hallucination/fakeattacker/New(mob/living/carbon/T, forced = TRUE) + ..() + var/mob/living/carbon/human/clone = null + var/clone_weapon = null + + for(var/mob/living/carbon/human/H in GLOB.living_mob_list) + if(H.stat || H.lying) + continue + clone = H + feedback_details += "Clone of: [H.real_name]" + break + + if(!clone) + return + + var/static/list/non_fakeattack_weapons = list(/obj/item/weapon/gun/ballistic, /obj/item/ammo_box/a357,\ + /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow, /obj/item/weapon/melee/transforming/energy/sword/saber,\ + /obj/item/weapon/storage/box/syndicate, /obj/item/weapon/storage/box/emps,\ + /obj/item/weapon/cartridge/virus/syndicate, /obj/item/clothing/under/chameleon,\ + /obj/item/clothing/shoes/chameleon, /obj/item/weapon/card/id/syndicate,\ + /obj/item/clothing/mask/chameleon, /obj/item/clothing/glasses/thermal,\ + /obj/item/device/chameleon, /obj/item/weapon/card/emag, /obj/item/weapon/grenade/plastic/x4,\ + /obj/item/weapon/storage/toolbox/syndicate, /obj/item/weapon/aiModule,\ + /obj/item/device/radio/headset/syndicate, /obj/item/weapon/grenade/plastic/c4,\ + /obj/item/device/powersink, /obj/item/weapon/storage/box/syndie_kit,\ + /obj/item/toy/syndicateballoon, /obj/item/weapon/gun/energy/laser/captain,\ + /obj/item/weapon/hand_tele, /obj/item/weapon/construction/rcd, /obj/item/weapon/tank/jetpack,\ + /obj/item/clothing/under/rank/captain, /obj/item/device/aicard,\ + /obj/item/clothing/shoes/magboots, /obj/item/areaeditor/blueprints, /obj/item/weapon/disk/nuclear,\ + /obj/item/clothing/suit/space/nasavoid, /obj/item/weapon/tank) + + var/obj/effect/fake_attacker/F = new/obj/effect/fake_attacker(get_turf(target),target) + + for(var/obj/item/I in clone.held_items) + if(!(locate(I) in non_fakeattack_weapons)) + clone_weapon = I.name + F.weap = I + + F.name = clone.name + F.my_target = target + F.weapon_name = clone_weapon + + F.left = image(clone,dir = WEST) + F.right = image(clone,dir = EAST) + F.up = image(clone,dir = NORTH) + F.down = image(clone,dir = SOUTH) + + F.updateimage() + qdel(src) + +/obj/effect/fake_attacker + icon = null + icon_state = null + name = "" + desc = "" + density = FALSE + anchored = TRUE + opacity = 0 + var/mob/living/carbon/human/my_target = null + var/weapon_name = null + var/obj/item/weap = null + var/image/stand_icon = null + var/image/currentimage = null + var/icon/base = null + var/skin_tone + var/mob/living/clone = null + var/image/left + var/image/right + var/image/up + var/collapse + var/image/down + + max_integrity = 100 + +/obj/effect/fake_attacker/attackby(obj/item/weapon/P, mob/living/user, params) + step_away(src,my_target,2) + user.changeNext_move(CLICK_CD_MELEE) + user.do_attack_animation(src) + my_target.playsound_local(src, P.hitsound, 1) + my_target.visible_message("[my_target] flails around wildly.", \ + "[my_target] has attacked [src]!") + + obj_integrity -= P.force + +/obj/effect/fake_attacker/Crossed(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)) + to_chat(O, "[my_target] stumbles around.") + +/obj/effect/fake_attacker/Initialize(mapload, mob/living/carbon/T) + ..() + my_target = T + QDEL_IN(src, 300) + step_away(src,my_target,2) + INVOKE_ASYNC(src, .proc/attack_loop) + + +/obj/effect/fake_attacker/proc/updateimage() +// del src.currentimage + if(src.dir == NORTH) + del src.currentimage + src.currentimage = new /image(up,src) + else if(src.dir == SOUTH) + del src.currentimage + src.currentimage = new /image(down,src) + else if(src.dir == EAST) + del src.currentimage + src.currentimage = new /image(right,src) + else if(src.dir == WEST) + del src.currentimage + src.currentimage = new /image(left,src) + SEND_IMAGE(my_target, currentimage) + + +/obj/effect/fake_attacker/proc/attack_loop() + while(1) + sleep(rand(5,10)) + if(obj_integrity < 0 || my_target.stat) + collapse() + continue + if(get_dist(src,my_target) > 1) + src.setDir(get_dir(src,my_target)) + step_towards(src,my_target) + updateimage() + else + if(prob(15)) + if(weapon_name) + my_target.playsound_local(my_target, weap.hitsound, weap.get_clamped_volume(), 1) + my_target.show_message("[src.name] has attacked [my_target] with [weapon_name]!", 1) + my_target.staminaloss += 30 + if(prob(20)) + my_target.blur_eyes(3) + if(prob(33)) + if(!locate(/obj/effect/overlay) in my_target.loc) + fake_blood(my_target) + else + my_target.playsound_local(my_target, pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg'), 25, 1) + my_target.show_message("[src.name] has punched [my_target]!", 1) + my_target.staminaloss += 30 + if(prob(33)) + if(!locate(/obj/effect/overlay) in my_target.loc) + fake_blood(my_target) + + if(prob(15)) + step_away(src,my_target,2) + +/obj/effect/fake_attacker/proc/collapse() + collapse = 1 + updateimage() + qdel(src) + +/obj/effect/fake_attacker/proc/fake_blood(mob/target) + var/obj/effect/overlay/O = new/obj/effect/overlay(target.loc) + O.name = "blood" + var/image/I = image('icons/effects/blood.dmi',O,"floor[rand(1,7)]",O.dir,1) + SEND_IMAGE(target, I) + QDEL_IN(O, 300) + + +/datum/hallucination/bolts + var/list/doors = list() + cost = 25 + +/datum/hallucination/bolts/New(mob/living/carbon/T, forced, door_number=-1) //-1 for severe, 1-2 for subtle + ..() + var/image/I = null + var/count = 0 + feedback_details += "Door amount: [door_number]" + for(var/obj/machinery/door/airlock/A in range(7, target)) + if(count>door_number && door_number>0) + break + count++ + I = image(A.overlays_file, get_turf(A), "lights_bolts",layer=A.layer+0.1) + doors += I + if(target.client) + target.client.images |= I + target.playsound_local(get_turf(A), 'sound/machines/boltsdown.ogg',30,0,3) + sleep(rand(6,12)) + sleep(100) + for(var/image/B in doors) + if(target.client) + target.client.images.Remove(B) + target.playsound_local(get_turf(B), 'sound/machines/boltsup.ogg',30,0,3) + sleep(rand(6,12)) + qdel(src) + +/datum/hallucination/whispers + cost = 15 + +/datum/hallucination/whispers/New(mob/living/carbon/T, forced = TRUE) + ..() + var/speak_messages = list("[pick_list_replacements(HAL_LINES_FILE, "suspicion")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "greetings")][target.first_name()]!",\ + "[pick_list_replacements(HAL_LINES_FILE, "getout")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "weird")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "didyouhearthat")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "imatraitor")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "doubt")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "aggressive")]",\ + "[pick_list_replacements(HAL_LINES_FILE, "help")]!!",\ + "[pick_list_replacements(HAL_LINES_FILE, "escape")]",\ + "I'm infected, [pick_list_replacements(HAL_LINES_FILE, "infection_advice")]!") + + var/radio_messages = list("Set [target.first_name()] to arrest!",\ + "[pick_list_replacements(HAL_LINES_FILE, "people")] is [pick_list_replacements(HAL_LINES_FILE, "accusations")]!",\ + "Help!",\ + "[pick_list_replacements(HAL_LINES_FILE, "threat")] in [pick_list_replacements(HAL_LINES_FILE, "location")][prob(50)?"!":"!!"]",\ + "Where's [target.first_name()]?"\ + ,"[pick("C","Ai, c","Someone c","Rec")]all the shuttle!"\ + ,"AI [pick("rogue", "is dead")]!!") + + var/list/mob/living/carbon/people = list() + var/list/mob/living/carbon/person = null + var/datum/language/understood_language = target.get_random_understood_language() + for(var/mob/living/carbon/H in view(target)) + if(H == target) + continue + if(!person) + person = H + else + if(get_dist(target,H)The light burns you!", \ + "You don't feel like yourself.", \ + "You hear something squeezing through the ducts...", \ + "You hear a distant scream.", \ + "You feel invincible, nothing can hurt you!", \ + "You feel a tiny prick!", \ + "[target] sneezes.", \ + //The truth, revealed + "You're hallucinating.", \ + //Direct advice + "[pick_list_replacements(HAL_LINES_FILE, "advice")]") + feedback_details += "Message: [chosen]" + to_chat(target, chosen) + qdel(src) + +/datum/hallucination/sounds + cost = 15 + +/datum/hallucination/sounds/New(mob/living/carbon/T, forced = TRUE, sound_type) + ..() + if(!sound_type) + sound_type = pick("airlock","explosion","far_explosion","glass","phone","summon_guns","alarm","beepsky","hallelujah","creepy","ratvar","shuttle_dock", + "wall_decon","door_hack","esword","blob_alert","tesla","malf_ai") + feedback_details += "Type: [sound_type]" + //Strange audio + switch(sound_type) + if("airlock") + target.playsound_local(null,'sound/machines/airlock.ogg', 15, 1) + if("explosion") + if(prob(50)) + target.playsound_local(null,'sound/effects/explosion1.ogg', 50, 1) + else + target.playsound_local(null, 'sound/effects/explosion2.ogg', 50, 1) + if("far_explosion") + target.playsound_local(null, 'sound/effects/explosionfar.ogg', 50, 1) + if("glass") + target.playsound_local(null, pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg'), 50, 1) + if("phone") + target.playsound_local(null, 'sound/weapons/ring.ogg', 35) + sleep(15) + target.playsound_local(null, 'sound/weapons/ring.ogg', 35) + sleep(15) + target.playsound_local(null, 'sound/weapons/ring.ogg', 35) + if("summon_guns") + target.playsound_local(null, 'sound/magic/summon_guns.ogg', 50, 1) + if("alarm") + target.playsound_local(null, 'sound/machines/alarm.ogg', 100, 0) + if("beepsky") + target.playsound_local(null, 'sound/voice/bfreeze.ogg', 35, 0) + if("hallelujah") + target.playsound_local(null, 'sound/effects/pray_chaplain.ogg', 50) + //Rare audio + if("creepy") + //These sounds are (mostly) taken from Hidden: Source + var/static/list/hallucinations_creepyasssounds = list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/heart_beat.ogg', 'sound/effects/screech.ogg',\ + 'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\ + 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\ + 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\ + 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg') + target.playsound_local(null, pick(hallucinations_creepyasssounds), 50, 1) + if("ratvar") + target.playsound_local(null, 'sound/effects/ratvar_rises.ogg', 100) + sleep(150) + target.playsound_local(null, 'sound/effects/ratvar_reveal.ogg', 100) + if("shuttle_dock") + to_chat(target, "

Priority Announcement

") + to_chat(target, "

The Emergency Shuttle has docked with the station. You have 3 minutes to board the Emergency Shuttle.

") + target.playsound_local(null, 'sound/ai/shuttledock.ogg', 100) + //Deconstructing a wall + if("wall_decon") + target.playsound_local(null, 'sound/items/welder.ogg', 15, 1) + sleep(105) + target.playsound_local(null, 'sound/items/welder2.ogg', 15, 1) + sleep(15) + target.playsound_local(null, 'sound/items/ratchet.ogg', 15, 1) + //Hacking a door + if("door_hack") + target.playsound_local(null, 'sound/items/screwdriver.ogg', 15, 1) + sleep(rand(10,30)) + for(var/i = rand(1,3), i>0, i--) + target.playsound_local(null, 'sound/weapons/empty.ogg', 15, 1) + sleep(rand(10,30)) + target.playsound_local(null, 'sound/machines/airlockforced.ogg', 15, 1) + if("esword") + target.playsound_local(null, 'sound/weapons/saberon.ogg',35,1) + if("blob_alert") + to_chat(target, "

Biohazard Alert

") + to_chat(target, "

Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.

") + target.playsound_local(null, 'sound/ai/outbreak5.ogg', 100, 0) + if("tesla") //Tesla loose! + target.playsound_local(null, 'sound/magic/lightningbolt.ogg', 35, 1) + sleep(20) + target.playsound_local(null, 'sound/magic/lightningbolt.ogg', 65, 1) + sleep(20) + target.playsound_local(null, 'sound/magic/lightningbolt.ogg', 100, 1) + if("malf_ai") //AI is doomsdaying! + to_chat(target, "

Anomaly Alert

") + to_chat(target, "

Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.

") + target.playsound_local(null, 'sound/ai/aimalf.ogg', 100, 0) + qdel(src) + +/datum/hallucination/hudscrew + cost = 10 + +/datum/hallucination/hudscrew/New(mob/living/carbon/T, forced = TRUE) + ..() + //Screwy HUD + target.set_screwyhud(pick(SCREWYHUD_CRIT,SCREWYHUD_DEAD,SCREWYHUD_HEALTHY)) + feedback_details += "Type: [target.hal_screwyhud]" + sleep(rand(100,250)) + target.set_screwyhud(SCREWYHUD_NONE) + qdel(src) + +/datum/hallucination/fake_alert + cost = 15 + +/datum/hallucination/fake_alert/New(mob/living/carbon/T, forced = TRUE, specific, duration = 150) + ..() + var/alert_type = pick("not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","weightless","fire","locked","hacked","temphot","tempcold","pressure") + if(specific) + alert_type = specific + feedback_details += "Type: [alert_type]" + switch(alert_type) + if("oxy") + target.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy, override = TRUE) + if("not_enough_tox") + target.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox, override = TRUE) + if("not_enough_co2") + target.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2, override = TRUE) + if("too_much_oxy") + target.throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy, override = TRUE) + if("too_much_co2") + target.throw_alert("too_much_co2", /obj/screen/alert/too_much_co2, override = TRUE) + if("tox_in_air") + target.throw_alert("too_much_tox", /obj/screen/alert/too_much_tox, override = TRUE) + if("nutrition") + if(prob(50)) + target.throw_alert("nutrition", /obj/screen/alert/fat, override = TRUE) + else + target.throw_alert("nutrition", /obj/screen/alert/starving, override = TRUE) + if("weightless") + target.throw_alert("weightless", /obj/screen/alert/weightless, override = TRUE) + if("fire") + target.throw_alert("fire", /obj/screen/alert/fire, override = TRUE) + if("temphot") + target.throw_alert("temp", /obj/screen/alert/hot, 3, override = TRUE) + if("tempcold") + target.throw_alert("temp", /obj/screen/alert/cold, 3, override = TRUE) + if("pressure") + if(prob(50)) + target.throw_alert("pressure", /obj/screen/alert/highpressure, 2, override = TRUE) + else + target.throw_alert("pressure", /obj/screen/alert/lowpressure, 2, override = TRUE) + //BEEP BOOP I AM A ROBOT + if("newlaw") + target.throw_alert("newlaw", /obj/screen/alert/newlaw, override = TRUE) + if("locked") + target.throw_alert("locked", /obj/screen/alert/locked, override = TRUE) + if("hacked") + target.throw_alert("hacked", /obj/screen/alert/hacked, override = TRUE) + if("charge") + target.throw_alert("charge",/obj/screen/alert/emptycell, override = TRUE) + sleep(duration) + target.clear_alert(alert_type, clear_override = TRUE) + qdel(src) + +/datum/hallucination/items + cost = 15 + +/datum/hallucination/items/New(mob/living/carbon/T, forced = TRUE) + ..() + //Strange items + if(!target.halitem) + target.halitem = new + var/obj/item/l_hand = target.get_item_for_held_index(1) + var/obj/item/r_hand = target.get_item_for_held_index(2) + var/l = ui_hand_position(target.get_held_index_of_item(l_hand)) + var/r = ui_hand_position(target.get_held_index_of_item(r_hand)) + var/list/slots_free = list(l,r) + if(l_hand) slots_free -= l + if(r_hand) slots_free -= r + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(!H.belt) slots_free += ui_belt + if(!H.l_store) slots_free += ui_storage1 + if(!H.r_store) slots_free += ui_storage2 + if(slots_free.len) + target.halitem.screen_loc = pick(slots_free) + target.halitem.layer = ABOVE_HUD_LAYER + target.halitem.plane = ABOVE_HUD_PLANE + switch(rand(1,6)) + if(1) //revolver + target.halitem.icon = 'icons/obj/guns/projectile.dmi' + target.halitem.icon_state = "revolver" + target.halitem.name = "Revolver" + if(2) //c4 + target.halitem.icon = 'icons/obj/grenade.dmi' + target.halitem.icon_state = "plastic-explosive0" + target.halitem.name = "C4" + if(prob(25)) + target.halitem.icon_state = "plasticx40" + if(3) //sword + target.halitem.icon = 'icons/obj/weapons.dmi' + target.halitem.icon_state = "sword0" + target.halitem.name = "Energy Sword" + if(4) //stun baton + target.halitem.icon = 'icons/obj/weapons.dmi' + target.halitem.icon_state = "stunbaton" + target.halitem.name = "Stun Baton" + if(5) //emag + target.halitem.icon = 'icons/obj/card.dmi' + target.halitem.icon_state = "emag" + target.halitem.name = "Cryptographic Sequencer" + if(6) //flashbang + target.halitem.icon = 'icons/obj/grenade.dmi' + target.halitem.icon_state = "flashbang1" + target.halitem.name = "Flashbang" + feedback_details += "Type: [target.halitem.name]" + if(target.client) target.client.screen += target.halitem + QDEL_IN(target.halitem, rand(150, 350)) + qdel(src) + +/datum/hallucination/dangerflash + cost = 15 + +/datum/hallucination/dangerflash/New(mob/living/carbon/T, forced = TRUE) + ..() + //Flashes of danger + if(!target.halimage) + var/list/possible_points = list() + for(var/turf/open/floor/F in view(target,world.view)) + possible_points += F + if(possible_points.len) + var/turf/open/floor/danger_point = pick(possible_points) + + switch(rand(1,5)) + if(1) + target.halimage = image('icons/turf/space.dmi',danger_point,"[rand(1,25)]",TURF_LAYER) + if(2) + target.halimage = image('icons/turf/floors/lava.dmi',danger_point,"smooth",TURF_LAYER) + if(3) + target.halimage = image('icons/turf/floors/Chasms.dmi',danger_point,"smooth",TURF_LAYER) + if(4) + target.halimage = image('icons/effects/effects.dmi',danger_point,"anom",OBJ_LAYER+0.01) + if(5) + target.halimage = image('icons/effects/effects.dmi',danger_point,"electricity2",OBJ_LAYER+0.01) + + + if(target.client) + target.client.images += target.halimage + sleep(rand(200,450)) + if(target.client) + target.client.images -= target.halimage + QDEL_NULL(target.halimage) + qdel(src) + +/datum/hallucination/death + cost = 40 + +/datum/hallucination/death/New(mob/living/carbon/T, forced = TRUE) + set waitfor = 0 + ..() + target.set_screwyhud(SCREWYHUD_DEAD) + target.Knockdown(300) + target.silent += 10 + var/area/area = get_area(target) + to_chat(target, "[target.mind.name] has died at [area.name].") + if(prob(50)) + var/mob/fakemob + var/list/dead_people = list() + for(var/mob/dead/observer/G in GLOB.player_list) + dead_people += G + if(LAZYLEN(dead_people)) + fakemob = pick(dead_people) + else + fakemob = target //ever been so lonely you had to haunt yourself? + if(fakemob) + sleep(rand(20, 50)) + to_chat(target, "DEAD: [fakemob.name] says, \"[pick("rip","hey [target.first_name()]","you too?","is the AI rogue?",\ + "i[prob(50)?" fucking":""] hate [pick("blood cult", "clock cult", "revenants", "abductors","double agents","viruses","badmins","you")]")]\"") + sleep(rand(70,90)) + target.set_screwyhud(SCREWYHUD_NONE) + target.SetKnockdown(0) + target.silent = 0 + qdel(src) + +/datum/hallucination/fire + cost = 25 + +/datum/hallucination/fire/New(mob/living/carbon/T, forced = TRUE) + ..() + var/image/fire_overlay = image('icons/mob/OnFire.dmi', target, "Standing", ABOVE_MOB_LAYER) + if(target.client) + target.client.images += fire_overlay + to_chat(target, "You're set on fire!") + target.throw_alert("fire", /obj/screen/alert/fire, override = TRUE) + sleep(20) + target.throw_alert("temp", /obj/screen/alert/hot, 1, override = TRUE) + sleep(30) + target.clear_alert("temp", clear_override = TRUE) + target.throw_alert("temp", /obj/screen/alert/hot, 2, override = TRUE) + sleep(30) + target.clear_alert("temp", clear_override = TRUE) + target.throw_alert("temp", /obj/screen/alert/hot, 3, override = TRUE) + for(var/i in 1 to rand(5, 10)) + target.adjustStaminaLoss(15) + sleep(25) + target.clear_alert("fire", clear_override = TRUE) + target.clear_alert("temp", clear_override = TRUE) + if(target.client) + target.client.images -= fire_overlay + QDEL_NULL(fire_overlay) + qdel(src) + +/datum/hallucination/husks + cost = 20 + +/datum/hallucination/husks/New(mob/living/carbon/T, forced = TRUE) + ..() + if(!target.halbody) + var/list/possible_points = list() + for(var/turf/open/floor/F in view(target,world.view)) + possible_points += F + if(possible_points.len) + var/turf/open/floor/husk_point = pick(possible_points) + switch(rand(1,4)) + if(1) + var/image/body = image('icons/mob/human.dmi',husk_point,"husk",TURF_LAYER) + var/matrix/M = matrix() + M.Turn(90) + body.transform = M + target.halbody = body + if(2,3) + target.halbody = image('icons/mob/human.dmi',husk_point,"husk",TURF_LAYER) + if(4) + target.halbody = image('icons/mob/alien.dmi',husk_point,"alienother",TURF_LAYER) + + if(target.client) + target.client.images += target.halbody + sleep(rand(30,50)) //Only seen for a brief moment. + if(target.client) + target.client.images -= target.halbody + QDEL_NULL(target.halbody) + qdel(src) + +//hallucination projectile code in code/modules/projectiles/projectile/special.dm +/datum/hallucination/stray_bullet + cost = 15 + +/datum/hallucination/stray_bullet/New(mob/living/carbon/C, forced = TRUE) + ..() + var/list/turf/startlocs = list() + for(var/turf/open/T in view(world.view+1,target)-view(world.view,target)) + startlocs += T + var/turf/start = pick(startlocs) + var/proj_type = pick(subtypesof(/obj/item/projectile/hallucination)) + feedback_details += "Type: [proj_type]" + var/obj/item/projectile/hallucination/H = new proj_type(start) + target.playsound_local(start, H.hal_fire_sound, 60, 1) + H.hal_target = target + H.current = start + H.starting = start + H.yo = target.y - start.y + H.xo = target.x - start.x + H.original = target + H.fire() + qdel(src) + diff --git a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm index aee52412a6..ff8f9d01a1 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm @@ -100,7 +100,7 @@ var/obj/item/weapon/reagent_containers/food/snacks/icecream/I = O if(!I.ice_creamed) if(product_types[dispense_flavour] > 0) - src.visible_message("[bicon(src)] [user] scoops delicious [flavour_name] ice cream into [I].") + visible_message("[icon2html(src, viewers(src))] [user] scoops delicious [flavour_name] ice cream into [I].") product_types[dispense_flavour] -= 1 I.add_ice_cream(flavour_name) // if(beaker) diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm index cde68b86e2..54c2154b42 100644 --- a/code/modules/food_and_drinks/pizzabox.dm +++ b/code/modules/food_and_drinks/pizzabox.dm @@ -101,7 +101,7 @@ return open = !open if(open && !bomb_defused) - audible_message("[bicon(src)] *beep*") + audible_message("[icon2html(src, hearers(src))] *beep*") bomb_active = TRUE START_PROCESSING(SSobj, src) update_icon() diff --git a/code/modules/food_and_drinks/recipes/food_mixtures.dm b/code/modules/food_and_drinks/recipes/food_mixtures.dm index 17662feb6e..bfa8b8bebd 100644 --- a/code/modules/food_and_drinks/recipes/food_mixtures.dm +++ b/code/modules/food_and_drinks/recipes/food_mixtures.dm @@ -13,7 +13,7 @@ id = "tofu" required_reagents = list("soymilk" = 10) required_catalysts = list("enzyme" = 5) - mob_react=1 + mob_react = FALSE /datum/chemical_reaction/tofu/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) @@ -37,7 +37,7 @@ name = "Chocolate Bar" id = "chocolate_bar" required_reagents = list("chocolate_milk" = 4, "sugar" = 2) - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/chocolate_bar2/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) @@ -91,7 +91,7 @@ name = "synthmeat" id = "synthmeat" required_reagents = list("blood" = 5, "cryoxadone" = 1) - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/synthmeat/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 7b236ea56f..85770f618a 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -100,7 +100,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic sendClientData() //do not convert to to_chat() - owner << {"If you can see this, update byond."} + SEND_TEXT(owner, "If you can see this, update byond.") pingLoop() @@ -152,7 +152,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if (found.len > 0) //TODO: add a new evasion ban for the CURRENT client details, using the matched row details message_admins("[key_name(src.owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])") - log_admin_private("[key_name(src.owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])") + log_admin_private("[key_name(owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])") cookieSent = TRUE @@ -165,58 +165,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") //Global chat procs - -//Converts an icon to base64. Operates by putting the icon in the iconCache savefile, -// exporting it as text, and then parsing the base64 from that. -// (This relies on byond automatically storing icons in savefiles as base64) -/proc/icon2base64(icon/icon, iconKey = "misc") - if (!isicon(icon)) - return FALSE - GLOB.iconCache[iconKey] << icon - var/iconData = GLOB.iconCache.ExportText(iconKey) - var/list/partial = splittext(iconData, "{") - return replacetext(copytext(partial[2], 3, -5), "\n", "") - -/proc/bicon(thing) - if (!thing) - return - var/static/list/bicon_cache = list() - if (isicon(thing)) - var/icon/I = thing - var/icon_md5 = md5(I) - if (!bicon_cache[icon_md5]) // Doesn't exist yet, make it. - I = icon(I) //copy it - I.Scale(16,16) //scale it - bicon_cache[icon_md5] = icon2base64(thing) //base64 it - return "" - - // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with. - var/atom/A = thing - var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]" - - - if (!bicon_cache[key]) // Doesn't exist, make it. - var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1) - I.Scale(16,16) - if (ishuman(thing)) // Shitty workaround for a BYOND issue. - var/icon/temp = I - I = icon() - I.Insert(temp, dir = SOUTH) - bicon_cache[key] = icon2base64(I, key) - - return "" - -//Costlier version of bicon() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. -/proc/costly_bicon(thing) - if (!thing) - return - - if (isicon(thing)) - return bicon(thing) - - var/icon/I = getFlatIcon(thing) - return bicon(I) - /proc/to_chat(target, message) if(!target) return @@ -224,7 +172,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic //Ok so I did my best but I accept that some calls to this will be for shit like sound and images //It stands that we PROBABLY don't want to output those to the browser output so just handle them here if (istype(message, /image) || istype(message, /sound) || istype(target, /savefile)) - target << message CRASH("Invalid message! [message]") if(!istext(message)) @@ -255,7 +202,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic continue //Send it to the old style output window. - C << original_message + SEND_TEXT(C, original_message) if(!C.chatOutput || C.chatOutput.broken) // A player who hasn't updated his skin file. continue diff --git a/code/modules/goonchat/browserOutput.dm.rej b/code/modules/goonchat/browserOutput.dm.rej new file mode 100644 index 0000000000..231def1c9a --- /dev/null +++ b/code/modules/goonchat/browserOutput.dm.rej @@ -0,0 +1,137 @@ +diff a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm (rejected hunks) +@@ -166,135 +166,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic + + //Global chat procs + +-//Converts an icon to base64. Operates by putting the icon in the iconCache savefile, +-// exporting it as text, and then parsing the base64 from that. +-// (This relies on byond automatically storing icons in savefiles as base64) +-/proc/icon2base64(icon/icon, iconKey = "misc") +- if (!isicon(icon)) +- return FALSE +- WRITE_FILE(GLOB.iconCache[iconKey], icon) +- var/iconData = GLOB.iconCache.ExportText(iconKey) +- var/list/partial = splittext(iconData, "{") +- return replacetext(copytext(partial[2], 3, -5), "\n", "") +- +-/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving) +- if (!thing) +- return +- var/static/datum/callback/CB = CALLBACK(GLOBAL_PROC, .proc/send_asset) +- +- var/key +- var/icon/I = thing +- if (!target) +- return +- if (target == world) +- target = GLOB.clients +- +- var/list/targets +- if (!islist(target)) +- targets = list(target) +- else +- targets = target +- if (!targets.len) +- return +- debug_usr("start") +- if (!isicon(I)) +- debug_usr("not icon") +- if (isfile(thing)) //special snowflake +- debug_usr("file") +- var/name = sanitize_filename("bicon.[thing]") +- debug_usr("file:[name]") +- register_asset(name, thing) +- var/list/callbacks +- var/list/callback_args = list() +- for (var/thing2 in targets) +- callbacks += CB +- callback_args[++callback_args.len] = list(thing2, name, TRUE) +- callback_select(callbacks, callback_args, savereturns = FALSE) +- return "" +- debug_usr("not file") +- var/atom/A +- if (isnull(dir)) +- dir = A.dir +- if (isnull(icon_state)) +- icon_state = A.icon_state +- I = A.icon +- if (ishuman(thing)) // Shitty workaround for a BYOND issue. +- debug_usr("human") +- var/icon/temp = I +- I = icon() +- I.Insert(temp, dir = SOUTH) +- dir = SOUTH +- else +- debug_usr("icon") +- if (isnull(dir)) +- dir = SOUTH +- if (isnull(icon_state)) +- icon_state = "" +- +- I = icon(I, icon_state, dir, frame) +- +- key = sanitize_filename("bicon.[md5(icon2base64(I))].[icon_state].[dir].png") +- debug_usr("key:[key]") +- register_asset(key, I) +- var/list/callbacks = list() +- var/list/callback_args = list() +- for (var/thing2 in targets) +- callbacks += CB +- callback_args[++callback_args.len] = list(thing2, key, TRUE) +- +- callback_select(callbacks, callback_args, savereturns = FALSE) +- return "" +- +-/proc/icon2base64html(thing) +- if (!thing) +- return +- var/static/list/bicon_cache = list() +- if (isicon(thing)) +- var/icon/I = thing +- var/icon_base64 = icon2base64(I) +- +- if (I.Height() > world.icon_size || I.Width() > world.icon_size) +- var/icon_md5 = md5(icon_base64) +- debug_admins(icon_md5) +- icon_base64 = bicon_cache[icon_md5] +- if (!icon_base64) // Doesn't exist yet, make it. +- I = icon(I) +- I.Scale(world.icon_size, world.icon_size) +- bicon_cache[icon_md5] = icon_base64 = icon2base64(I) +- +- +- return "" +- +- // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with. +- var/atom/A = thing +- var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]" +- +- +- if (!bicon_cache[key]) // Doesn't exist, make it. +- var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1) +- if (ishuman(thing)) // Shitty workaround for a BYOND issue. +- var/icon/temp = I +- I = icon() +- I.Insert(temp, dir = SOUTH) +- +- if (I.Height() > world.icon_size || I.Width() > world.icon_size) +- I.Scale(world.icon_size, world.icon_size) +- +- bicon_cache[key] = icon2base64(I, key) +- +- return "" +- +-//Costlier version of icon2html() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. +-/proc/costly_icon2html(thing, target) +- if (!thing) +- return +- +- if (isicon(thing)) +- return icon2html(thing, target) +- +- var/icon/I = getFlatIcon(thing) +- return icon2html(I, target) +- + /proc/to_chat(target, message) + if(!target) + return diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css index ea4c169f0e..36640db74e 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -28,10 +28,14 @@ img { margin: 0; padding: 0; line-height: 1; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; } img.icon { - width: 16px; - height: 16px; + height: 1em; + min-height: 16px; + width: auto; + vertical-align: bottom; } a {color: #0000ff;} @@ -357,7 +361,6 @@ h1.alert, h2.alert {color: #000000;} .clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} .his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} -BIG IMG.icon {width: 32px; height: 32px;} .memo {color: #638500; text-align: center;} .memoedit {text-align: center; font-size: 16px;} @@ -368,6 +371,9 @@ BIG IMG.icon {width: 32px; height: 32px;} .swarmer {color: #2C75FF;} .resonate {color: #298F85;} +.love {color: #FF69Bf;} +.lovebold {color: #FF69Bf; font-weight: bold;} + .connectionClosed, .fatalError {background: red; color: white; padding: 5px;} .connectionClosed.restored {background: green;} .internal.boldnshit {color: blue; font-weight: bold;} diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js index 59b152ab3b..e6e0c1d6fa 100644 --- a/code/modules/goonchat/browserassets/js/browserOutput.js +++ b/code/modules/goonchat/browserassets/js/browserOutput.js @@ -29,6 +29,8 @@ var opts = { 'messageLimit': 2053, //A limit...for the messages... 'scrollSnapTolerance': 10, //If within x pixels of bottom 'clickTolerance': 10, //Keep focus if outside x pixels of mousedown position on mouseup + 'imageRetryDelay': 50, //how long between attempts to reload images (in ms) + 'imageRetryLimit': 50, //how many attempts should we make? 'popups': 0, //Amount of popups opened ever 'wasd': false, //Is the user in wasd mode? 'chatMode': 'default', //The mode the chat is in @@ -146,6 +148,23 @@ function highlightTerms(el) { el.innerHTML = newText; } } + +function iconError(E) { + var that = this; + setTimeout(function() { + var attempts = $(that).data('reload_attempts'); + if (typeof attempts === 'undefined' || !attempts) { + attempts = 1; + } + if (attempts > opts.imageRetryLimit) + return; + var src = that.src; + that.src = null; + that.src = src+'#'+attempts; + $(that).data('reload_attempts', ++attempts); + }, opts.imageRetryDelay); +} + //Send a message to the client function output(message, flag) { if (typeof message === 'undefined') { @@ -271,7 +290,7 @@ function output(message, flag) { entry.innerHTML = message.trim(); $messages[0].appendChild(entry); - + $(entry).find("img.icon").error(iconError); //Actually do the snap if (!filteredOut && atBottom) { $('body,html').scrollTop($messages.outerHeight()); @@ -861,7 +880,11 @@ $(function() { $messages.empty(); opts.messageCount = 0; }); - + + $('img.icon').error(iconError); + + + /***************************************** * diff --git a/code/modules/goonchat/jsErrorHandler.dm b/code/modules/goonchat/jsErrorHandler.dm index 67ea5faca3..ce257ce660 100644 --- a/code/modules/goonchat/jsErrorHandler.dm +++ b/code/modules/goonchat/jsErrorHandler.dm @@ -32,7 +32,7 @@ CRASH("Debug Error Handling encountered an error! This is highly ironic! File: '[fileName]' has exceeded the filesize limit of: [src.logFileLimit] bytes") message = "\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: \[[C && C.key ? C.key : "Unknown Client"]\] triggered: [message]" - logFile << message + WRITE_FILE(logFile, message) return 1 /datum/debugFileOutput/proc/clear(fileName) diff --git a/code/modules/hydroponics/grown/chili.dm b/code/modules/hydroponics/grown/chili.dm index 7707a4d438..66bd823a89 100644 --- a/code/modules/hydroponics/grown/chili.dm +++ b/code/modules/hydroponics/grown/chili.dm @@ -71,21 +71,21 @@ name = "ghost chili" desc = "It seems to be vibrating gently." icon_state = "ghostchilipepper" - var/mob/held_mob + var/mob/living/carbon/human/held_mob filling_color = "#F8F8FF" bitesize_mod = 4 origin_tech = "biotech=4;magnets=5" /obj/item/weapon/reagent_containers/food/snacks/grown/ghost_chili/attack_hand(mob/user) ..() - if( ismob(src.loc) ) - held_mob = src.loc + if( ismob(loc) ) + held_mob = loc START_PROCESSING(SSobj, src) /obj/item/weapon/reagent_containers/food/snacks/grown/ghost_chili/process() - if(held_mob && src.loc == held_mob) + if(held_mob && loc == held_mob) if(held_mob.is_holding(src)) - if(hasvar(held_mob,"gloves") && held_mob:gloves) + if(istype(held_mob) && held_mob.gloves) return held_mob.bodytemperature += 15 * TEMPERATURE_DAMAGE_COEFFICIENT if(prob(10)) diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm index 2ad7f0549c..8b51429bd3 100644 --- a/code/modules/language/language.dm +++ b/code/modules/language/language.dm @@ -35,7 +35,7 @@ return TRUE /datum/language/proc/get_icon() - return "[bicon(icon(icon, icon_state))]" + return "[icon2html(icon, world, icon_state)]" /datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) if(!syllables || !syllables.len) diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index 3aca57c4bf..fc03cfb8c0 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -95,14 +95,6 @@ has_opaque_atom = TRUE break -// If an opaque movable atom moves around we need to potentially update visibility. -/turf/Entered(var/atom/movable/Obj, var/atom/OldLoc) - . = ..() - - if (Obj && Obj.opacity) - has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. - reconsider_lights() - /turf/Exited(var/atom/movable/Obj, var/atom/newloc) . = ..() diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index a1251381b4..06845ba0cb 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -284,7 +284,7 @@ L.adjustBruteLoss(bonus_value) /obj/item/crusher_trophy/tail_spike/proc/pushback(mob/living/target, mob/living/user) - if(!target.anchored || ismegafauna(target)) //megafauna will always be pushed + if(!QDELETED(target) && !QDELETED(user) && (!target.anchored || ismegafauna(target))) //megafauna will always be pushed step(target, get_dir(user, target)) //bubblegum diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm index 25aa9fb8e8..8029cc1416 100644 --- a/code/modules/mining/minebot.dm +++ b/code/modules/mining/minebot.dm @@ -170,6 +170,7 @@ /datum/action/innate/minedrone check_flags = AB_CHECK_CONSCIOUS + icon_icon = 'icons/mob/actions/actions_mecha.dmi' background_icon_state = "bg_default" /datum/action/innate/minedrone/toggle_light diff --git a/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm b/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm index 8e724f1aa5..ab4b044cb9 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm @@ -31,6 +31,16 @@ color_src = 0 icon = 'icons/mob/mam_bodyparts.dmi' +/datum/sprite_accessory/tails/human/bear + name = "Bear" + icon_state = "bear" + icon = 'icons/mob/mam_bodyparts.dmi' + +/datum/sprite_accessory/ears/human/bear + name = "Bear" + icon_state = "bear" + icon = 'icons/mob/mam_bodyparts.dmi' + /datum/sprite_accessory/tails/human/catbig name = "Cat, Big" icon_state = "catbig" @@ -112,7 +122,7 @@ /datum/sprite_accessory/tails/human/shark name = "Shark" icon_state = "shark" - color_src = 0 + color_src = MUTCOLORS icon = 'icons/mob/mam_bodyparts.dmi' /datum/sprite_accessory/tails/human/shark/datashark @@ -140,8 +150,7 @@ /datum/sprite_accessory/ears/wolf name = "Wolf" icon_state = "wolf" - hasinner = 1 - icon = 'icons/mob/mam_bodyparts.dmi' + extra = 1 /datum/sprite_accessory/tails/human/wolf name = "Wolf" @@ -181,6 +190,7 @@ /datum/sprite_accessory/mam_tails_animated icon = 'icons/mob/mam_bodyparts.dmi' + /datum/sprite_accessory/mam_tails_animated/none name = "None" @@ -234,16 +244,9 @@ extra = 1 extra_color_src = MUTCOLORS2 -/datum/sprite_accessory/mam_ears/catbig - name = "Cat, Big" - icon_state = "cat" - hasinner = 1 - icon = 'icons/mob/mutant_bodyparts.dmi' - /datum/sprite_accessory/mam_tails/bear name = "Bear" icon_state = "bear" - extra_color_src = MUTCOLORS2 icon = 'icons/mob/mam_bodyparts.dmi' /datum/sprite_accessory/mam_ears/bear @@ -251,6 +254,12 @@ icon_state = "bear" icon = 'icons/mob/mam_bodyparts.dmi' +/datum/sprite_accessory/mam_ears/catbig + name = "Cat, Big" + icon_state = "cat" + hasinner = 1 + icon = 'icons/mob/mutant_bodyparts.dmi' + /datum/sprite_accessory/mam_tails/catbig name = "Cat, Big" icon_state = "catbig" @@ -317,7 +326,6 @@ /datum/sprite_accessory/mam_ears/husky name = "Husky" icon_state = "wolf" - hasinner = 1 icon = 'icons/mob/mam_bodyparts.dmi' extra = 1 @@ -381,7 +389,7 @@ /datum/sprite_accessory/mam_tails/shark name = "Shark" icon_state = "shark" - color_src = 0 + color_src = MUTCOLORS /datum/sprite_accessory/mam_tails_animated/shark name = "Shark" @@ -427,7 +435,7 @@ /datum/sprite_accessory/mam_ears/wolf name = "Wolf" icon_state = "wolf" - hasinner = 1 + extra = 1 /datum/sprite_accessory/mam_tails/wolf name = "Wolf" @@ -455,7 +463,6 @@ /datum/sprite_accessory/mam_tails/rabbit name = "Rabbit" icon_state = "rabbit" - color_src = 0 icon = 'icons/mob/mam_bodyparts.dmi' /datum/sprite_accessory/mam_ears/rabbit @@ -586,6 +593,13 @@ extra2 = 1 icon = 'icons/mob/mam_body_markings.dmi' + /datum/sprite_accessory/mam_body_markings/xeno + name = "Xeno" + icon_state = "xeno" + color_src = MUTCOLORS2 + extra_color_src = MUTCOLORS3 + gender_specific = 1 + /****************************************** ************ Taur Bodies ****************** *******************************************/ @@ -664,49 +678,67 @@ //Xeno Dorsal Tubes /datum/sprite_accessory/xeno_dorsal - icon = 'icons/mob/exotic_bodyparts.dmi' - color_src = 0 + icon = 'icons/mob/xeno_parts_greyscale.dmi' /datum/sprite_accessory/xeno_dorsal/none name = "None" -/datum/sprite_accessory/xeno_dorsal/normal - name = "Dorsal Tubes" - icon_state = "dortubes" +/datum/sprite_accessory/xeno_dorsal/standard + name = "Standard" + icon_state = "standard" + icon = 'icons/mob/xeno_parts_greyscale.dmi' + +/datum/sprite_accessory/xeno_dorsal/royal + name = "Royal" + icon_state = "royal" + icon = 'icons/mob/xeno_parts_greyscale.dmi' + +/datum/sprite_accessory/xeno_dorsal/down + name = "Dorsal Down" + icon_state = "down" + icon = 'icons/mob/xeno_parts_greyscale.dmi' //Xeno Tail /datum/sprite_accessory/xeno_tail - icon = 'icons/mob/exotic_bodyparts.dmi' - color_src = 0 + icon = 'icons/mob/xeno_parts_greyscale.dmi' /datum/sprite_accessory/xeno_tail/none name = "None" -/datum/sprite_accessory/xeno_tail/normal +/datum/sprite_accessory/xeno_tail/standard name = "Xenomorph Tail" icon_state = "xeno" + icon = 'icons/mob/xeno_parts_greyscale.dmi' //Xeno Caste Heads //unused as of October 3, 2016 /datum/sprite_accessory/xeno_head - icon = 'icons/mob/exotic_bodyparts.dmi' - color_src = 0 + icon = 'icons/mob/xeno_parts_greyscale.dmi' /datum/sprite_accessory/xeno_head/none name = "None" +/datum/sprite_accessory/xeno_head/standard + name = "Standard" + icon_state = "standard" + icon = 'icons/mob/xeno_parts_greyscale.dmi' -/datum/sprite_accessory/xeno_head/hunter - name = "Hunter" - icon_state = "hunter" -/datum/sprite_accessory/xeno_head/drone - name = "Drone" - icon_state = "drone" +/datum/sprite_accessory/xeno_head/royal + name = "royal" + icon_state = "royal" + icon = 'icons/mob/xeno_parts_greyscale.dmi' + +/datum/sprite_accessory/xeno_head/hollywood + name = "hollywood" + icon_state = "hollywood" + icon = 'icons/mob/xeno_parts_greyscale.dmi' + +/datum/sprite_accessory/xeno_head/warrior + name = "warrior" + icon_state = "warrior" + icon = 'icons/mob/xeno_parts_greyscale.dmi' -/datum/sprite_accessory/xeno_head/sentinel - name = "Sentinel" - icon_state = "sentinel" /* //Slimecoon Parts /datum/sprite_accessory/slimecoon_ears diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 2ede4c360e..da769c23cb 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -351,7 +351,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp source.plane = old_plane to_chat(src, "(Click to re-enter)") if(sound) - src << sound(sound) + SEND_SOUND(src, sound(sound)) /mob/dead/observer/proc/dead_tele() set category = "Ghost" diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm index 86ea3d64e9..01626c5694 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm @@ -87,7 +87,7 @@ var/atom/xeno_loc = get_turf(owner) var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc) new_xeno.key = ghost.key - new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100) //To get the player's attention + SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention new_xeno.canmove = 0 //so we don't move during the bursting animation new_xeno.notransform = 1 new_xeno.invisibility = INVISIBILITY_MAXIMUM diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 91a178ca36..feef638fdc 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -51,9 +51,10 @@ var/obj/item/item_in_hand = src.get_active_held_item() if(item_in_hand) //this segment checks if the item in your hand is twohanded. - if(istype(item_in_hand, /obj/item/weapon/twohanded)) - if(item_in_hand:wielded == 1) - to_chat(usr, "Your other hand is too busy holding the [item_in_hand.name]") + var/obj/item/weapon/twohanded/TH = item_in_hand + if(istype(TH)) + if(TH.wielded == 1) + to_chat(usr, "Your other hand is too busy holding [TH]") return var/oindex = active_hand_index active_hand_index = held_index @@ -170,6 +171,7 @@ if(thrown_thing) visible_message("[src] has thrown [thrown_thing].") + add_logs(src, thrown_thing, "has thrown") newtonian_move(get_dir(target, src)) thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src) @@ -240,6 +242,12 @@ /mob/living/carbon/is_muzzled() return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle)) +/mob/living/carbon/hallucinating() + if(hallucination) + return TRUE + else + return FALSE + /mob/living/carbon/resist_buckle() if(restrained()) changeNext_move(CLICK_CD_BREAKOUT) @@ -812,3 +820,4 @@ .["Make AI"] = "?_src_=vars;makeai=\ref[src]" .["Modify bodypart"] = "?_src_=vars;editbodypart=\ref[src]" .["Modify organs"] = "?_src_=vars;editorgans=\ref[src]" + .["Hallucinate"] = "?_src_=vars;hallucinate=\ref[src]" diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 8bf10c39ba..dcc2655e9a 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -337,7 +337,7 @@ // you need earmuffs, inacusiate, or replacement else if(ears.ear_damage >= 5) to_chat(src, "Your ears start to ring!") - src << sound('sound/weapons/flash_ring.ogg',0,1,0,250) + SEND_SOUND(src, sound('sound/weapons/flash_ring.ogg',0,1,0,250)) return effect_amount //how soundbanged we are diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index ebc349cefc..e30556db30 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -6,26 +6,26 @@ var/t_has = p_have() var/t_is = p_are() - var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src]!\n" if (handcuffed) - msg += "[t_He] [t_is] [bicon(handcuffed)] handcuffed!\n" + msg += "[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!\n" if (head) - msg += "[t_He] [t_is] wearing [bicon(head)] \a [src.head] on [t_his] head. \n" + msg += "[t_He] [t_is] wearing [icon2html(head, user)] \a [src.head] on [t_his] head. \n" if (wear_mask) - msg += "[t_He] [t_is] wearing [bicon(wear_mask)] \a [src.wear_mask] on [t_his] face.\n" + msg += "[t_He] [t_is] wearing [icon2html(wear_mask, user)] \a [src.wear_mask] on [t_his] face.\n" if (wear_neck) - msg += "[t_He] [t_is] wearing [bicon(wear_neck)] \a [src.wear_neck] around [t_his] neck.\n" + msg += "[t_He] [t_is] wearing [icon2html(wear_neck, user)] \a [src.wear_neck] around [t_his] neck.\n" for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "[t_He] [t_is] holding [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "[t_He] [t_is] holding [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "[t_He] [t_is] holding [bicon(I)] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "[t_He] [t_is] holding [icon2html(I, user)] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n" if (back) - msg += "[t_He] [t_has] [bicon(back)] \a [src.back] on [t_his] back.\n" + msg += "[t_He] [t_has] [icon2html(back, user)] \a [src.back] on [t_his] back.\n" var/appears_dead = 0 if (stat == DEAD) appears_dead = 1 diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 94732a349d..c2bec849e2 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -19,55 +19,55 @@ if(istype(w_uniform, /obj/item/clothing/under)) var/obj/item/clothing/under/U = w_uniform if(U.attached_accessory) - accessory_msg += " with [bicon(U.attached_accessory)] \a [U.attached_accessory]" + accessory_msg += " with [icon2html(U.attached_accessory, user)] \a [U.attached_accessory]" if(w_uniform.blood_DNA) - msg += "[t_He] [t_is] wearing \icon[w_uniform] [w_uniform.gender==PLURAL?"some":"a"] blood-stained [w_uniform.name][accessory_msg]!\n" + msg += "[t_He] [t_is] wearing [icon2html(w_uniform, user)] [w_uniform.gender==PLURAL?"some":"a"] blood-stained [w_uniform.name][accessory_msg]!\n" else - msg += "[t_He] [t_is] wearing [bicon(w_uniform)] \a [w_uniform][accessory_msg].\n" + msg += "[t_He] [t_is] wearing [icon2html(w_uniform, user)] \a [w_uniform][accessory_msg].\n" //head if(head) if(head.blood_DNA) - msg += "[t_He] [t_is] wearing [bicon(head)] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on [t_his] head!\n" + msg += "[t_He] [t_is] wearing [icon2html(head, user)] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on [t_his] head!\n" else - msg += "[t_He] [t_is] wearing [bicon(head)] \a [head] on [t_his] head.\n" + msg += "[t_He] [t_is] wearing [icon2html(head, user)] \a [head] on [t_his] head.\n" //suit/armor if(wear_suit) if(wear_suit.blood_DNA) - msg += "[t_He] [t_is] wearing [bicon(wear_suit)] [wear_suit.gender==PLURAL?"some":"a"] blood-stained [wear_suit.name]!\n" + msg += "[t_He] [t_is] wearing [icon2html(wear_suit, user)] [wear_suit.gender==PLURAL?"some":"a"] blood-stained [wear_suit.name]!\n" else - msg += "[t_He] [t_is] wearing [bicon(wear_suit)] \a [wear_suit].\n" + msg += "[t_He] [t_is] wearing [icon2html(wear_suit, user)] \a [wear_suit].\n" //suit/armor storage if(s_store) if(s_store.blood_DNA) - msg += "[t_He] [t_is] carrying [bicon(s_store)] [s_store.gender==PLURAL?"some":"a"] blood-stained [s_store.name] on [t_his] [wear_suit.name]!\n" + msg += "[t_He] [t_is] carrying [icon2html(s_store, user)] [s_store.gender==PLURAL?"some":"a"] blood-stained [s_store.name] on [t_his] [wear_suit.name]!\n" else - msg += "[t_He] [t_is] carrying [bicon(s_store)] \a [s_store] on [t_his] [wear_suit.name].\n" + msg += "[t_He] [t_is] carrying [icon2html(s_store, user)] \a [s_store] on [t_his] [wear_suit.name].\n" //back if(back) if(back.blood_DNA) - msg += "[t_He] [t_has] [bicon(back)] [back.gender==PLURAL?"some":"a"] blood-stained [back] on [t_his] back.\n" + msg += "[t_He] [t_has] [icon2html(back, user)] [back.gender==PLURAL?"some":"a"] blood-stained [back] on [t_his] back.\n" else - msg += "[t_He] [t_has] [bicon(back)] \a [back] on [t_his] back.\n" + msg += "[t_He] [t_has] [icon2html(back, user)] \a [back] on [t_his] back.\n" //Hands for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "[t_He] [t_is] holding [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "[t_He] [t_is] holding [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "[t_He] [t_is] holding [bicon(I)] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "[t_He] [t_is] holding [icon2html(I, user)] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n" //gloves if(gloves && !(slot_gloves in obscured)) if(gloves.blood_DNA) - msg += "[t_He] [t_has] [bicon(gloves)] [gloves.gender==PLURAL?"some":"a"] blood-stained [gloves.name] on [t_his] hands!\n" + msg += "[t_He] [t_has] [icon2html(gloves, user)] [gloves.gender==PLURAL?"some":"a"] blood-stained [gloves.name] on [t_his] hands!\n" else - msg += "[t_He] [t_has] [bicon(gloves)] \a [gloves] on [t_his] hands.\n" + msg += "[t_He] [t_has] [icon2html(gloves, user)] \a [gloves] on [t_his] hands.\n" else if(blood_DNA) var/hand_number = get_num_arms() if(hand_number) @@ -78,48 +78,48 @@ //handcuffed? if(handcuffed) if(istype(handcuffed, /obj/item/weapon/restraints/handcuffs/cable)) - msg += "[t_He] [t_is] [bicon(handcuffed)] restrained with cable!\n" + msg += "[t_He] [t_is] [icon2html(handcuffed, user)] restrained with cable!\n" else - msg += "[t_He] [t_is] [bicon(handcuffed)] handcuffed!\n" + msg += "[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!\n" //belt if(belt) if(belt.blood_DNA) - msg += "[t_He] [t_has] [bicon(belt)] [belt.gender==PLURAL?"some":"a"] blood-stained [belt.name] about [t_his] waist!\n" + msg += "[t_He] [t_has] [icon2html(belt, user)] [belt.gender==PLURAL?"some":"a"] blood-stained [belt.name] about [t_his] waist!\n" else - msg += "[t_He] [t_has] [bicon(belt)] \a [belt] about [t_his] waist.\n" + msg += "[t_He] [t_has] [icon2html(belt, user)] \a [belt] about [t_his] waist.\n" //shoes if(shoes && !(slot_shoes in obscured)) if(shoes.blood_DNA) - msg += "[t_He] [t_is] wearing [bicon(shoes)] [shoes.gender==PLURAL?"some":"a"] blood-stained [shoes.name] on [t_his] feet!\n" + msg += "[t_He] [t_is] wearing [icon2html(shoes, user)] [shoes.gender==PLURAL?"some":"a"] blood-stained [shoes.name] on [t_his] feet!\n" else - msg += "[t_He] [t_is] wearing [bicon(shoes)] \a [shoes] on [t_his] feet.\n" + msg += "[t_He] [t_is] wearing [icon2html(shoes, user)] \a [shoes] on [t_his] feet.\n" //mask if(wear_mask && !(slot_wear_mask in obscured)) if(wear_mask.blood_DNA) - msg += "[t_He] [t_has] [bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] blood-stained [wear_mask.name] on [t_his] face!\n" + msg += "[t_He] [t_has] [icon2html(wear_mask, user)] [wear_mask.gender==PLURAL?"some":"a"] blood-stained [wear_mask.name] on [t_his] face!\n" else - msg += "[t_He] [t_has] [bicon(wear_mask)] \a [wear_mask] on [t_his] face.\n" + msg += "[t_He] [t_has] [icon2html(wear_mask, user)] \a [wear_mask] on [t_his] face.\n" if (wear_neck && !(slot_neck in obscured)) - msg += "[t_He] [t_is] wearing [bicon(wear_neck)] \a [src.wear_neck] around [t_his] neck.\n" + msg += "[t_He] [t_is] wearing [icon2html(wear_neck, user)] \a [src.wear_neck] around [t_his] neck.\n" //eyes if(glasses && !(slot_glasses in obscured)) if(glasses.blood_DNA) - msg += "[t_He] [t_has] [bicon(glasses)] [glasses.gender==PLURAL?"some":"a"] blood-stained [glasses] covering [t_his] eyes!\n" + msg += "[t_He] [t_has] [icon2html(glasses, user)] [glasses.gender==PLURAL?"some":"a"] blood-stained [glasses] covering [t_his] eyes!\n" else - msg += "[t_He] [t_has] [bicon(glasses)] \a [glasses] covering [t_his] eyes.\n" + msg += "[t_He] [t_has] [icon2html(glasses, user)] \a [glasses] covering [t_his] eyes.\n" //ears if(ears && !(slot_ears in obscured)) - msg += "[t_He] [t_has] [bicon(ears)] \a [ears] on [t_his] ears.\n" + msg += "[t_He] [t_has] [icon2html(ears, user)] \a [ears] on [t_his] ears.\n" //ID if(wear_id) - msg += "[t_He] [t_is] wearing [bicon(wear_id)] \a [wear_id].\n" + msg += "[t_He] [t_is] wearing [icon2html(wear_id, user)] \a [wear_id].\n" //Jitters switch(jitteriness) @@ -164,7 +164,7 @@ var/obj/item/bodypart/BP = X missing -= BP.body_zone for(var/obj/item/I in BP.embedded_objects) - msg += "[t_He] [t_has] \a [bicon(I)] [I] embedded in [t_his] [BP.name]!\n" + msg += "[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!\n" //stores missing limbs var/l_limbs_missing = 0 diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 69b581995b..3dacc2f444 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -143,7 +143,7 @@ var/protection = (prot["head"] + prot["arms"] + prot["feet"] + prot["legs"] + prot["groin"] + prot["chest"] + prot["hands"])/7 return protection -/mob/living/carbon/human/can_use_guns(var/obj/item/weapon/gun/G) +/mob/living/carbon/human/can_use_guns(var/obj/item/weapon/G) . = ..() if(G.trigger_guard == TRIGGER_GUARD_NORMAL) diff --git a/code/modules/mob/living/carbon/human/interactive.dm b/code/modules/mob/living/carbon/human/interactive.dm index e439f8ef9e..2ed81b9f88 100644 --- a/code/modules/mob/living/carbon/human/interactive.dm +++ b/code/modules/mob/living/carbon/human/interactive.dm @@ -97,7 +97,7 @@ if(voice_saved) return var/savefile/S = new /savefile("data/npc_saves/snpc.sav") - S["knownStrings"] << knownStrings + WRITE_FILE(S["knownStrings"], knownStrings) //botPool funcs /mob/living/carbon/human/interactive/proc/takeDelegate(mob/living/carbon/human/interactive/from,doReset=TRUE) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index d9f1acf879..da99954f29 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -63,6 +63,7 @@ return list( head, wear_mask, + wear_neck, glasses, ears, ) @@ -171,7 +172,7 @@ dropItemToGround(belt) w_uniform = null update_suit_sensors() - if(!QDELETED(src)) + if(!QDELETED(src)) update_inv_w_uniform() else if(I == gloves) gloves = null diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm index d612a4f061..32d6a89494 100644 --- a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm @@ -79,6 +79,28 @@ datum/species/mammal return TRUE //HERBIVOROUS// +//Alien// +/datum/species/xeno + // A cloning mistake, crossing human and xenomorph DNA + name = "xeno" + id = "xeno" + say_mod = "hisses" + default_color = "00FF00" + species_traits = list(MUTCOLORS,LIPS,DIGITIGRADE,PIERCEIMMUNE) + mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "taur","mam_body_markings") + default_features = list("xenotail"="xeno","xenohead"="standard","xenodorsal"="standard","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None","mam_body_markings" = "xeno") + heatmod = 1.3 + attack_verb = "slash" + attack_sound = 'sound/weapons/slash.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/xeno + skinned_type = /obj/item/stack/sheet/animalhide/xeno + exotic_bloodtype = "L" + damage_overlay_type = "xeno" + roundstart = 1 + +//Praise the Omnissiah, A challange worthy of my skills - HS + //EXOTIC// //These races will likely include lots of downsides and upsides. Keep them relatively balanced.// /* @@ -217,4 +239,4 @@ datum/species/guilmon attack_verb = "claw" attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' - roundstart = 1 \ No newline at end of file + roundstart = 1 diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 72c65ae471..c52d9862ad 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -378,8 +378,7 @@ adjust_drugginess(-1) if(hallucination) - spawn handle_hallucinations() - hallucination = max(hallucination-2,0) + handle_hallucinations() //used in human and monkey handle_environment() /mob/living/carbon/proc/natural_bodytemperature_stabilization() diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index f57a48b5c6..9ed0a74d31 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -140,7 +140,7 @@ return 0 return 1 -/mob/living/carbon/monkey/can_use_guns(var/obj/item/weapon/gun/G) +/mob/living/carbon/monkey/can_use_guns(var/obj/item/weapon/G) return 1 /mob/living/carbon/monkey/angry diff --git a/code/modules/mob/living/carbon/monkey/punpun.dm b/code/modules/mob/living/carbon/monkey/punpun.dm index 901f2ceabc..b56028634f 100644 --- a/code/modules/mob/living/carbon/monkey/punpun.dm +++ b/code/modules/mob/living/carbon/monkey/punpun.dm @@ -51,23 +51,23 @@ /mob/living/carbon/monkey/punpun/proc/Write_Memory(dead, gibbed) var/savefile/S = new /savefile("data/npc_saves/Punpun.sav") if(gibbed) - S["ancestor_name"] << null - S["ancestor_chain"] << 1 - S["relic_hat"] << null - S["relic_mask"] << null + WRITE_FILE(S["ancestor_name"], null) + WRITE_FILE(S["ancestor_chain"], 1) + WRITE_FILE(S["relic_hat"], null) + WRITE_FILE(S["relic_mask"], null) return if(dead) - S["ancestor_name"] << ancestor_name - S["ancestor_chain"] << ancestor_chain + 1 + WRITE_FILE(S["ancestor_name"], ancestor_name) + WRITE_FILE(S["ancestor_chain"], ancestor_chain + 1) if(!ancestor_name) //new monkey name this round - S["ancestor_name"] << name + WRITE_FILE(S["ancestor_name"], name) if(head) - S["relic_hat"] << head.type + WRITE_FILE(S["relic_hat"], head.type) else - S["relic_hat"] << null + WRITE_FILE(S["relic_hat"], null) if(wear_mask) - S["relic_mask"] << wear_mask.type + WRITE_FILE(S["relic_mask"], wear_mask.type) else - S["relic_mask"] << null + WRITE_FILE(S["relic_mask"], null) if(!dead) memory_saved = 1 diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 8bdcf30f66..ff37b85800 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -326,7 +326,7 @@ /datum/emote/living/surrender key = "surrender" key_third_person = "surrenders" - message = "puts their hands on their head and falls to the ground, they surrender%s!" + message = "puts their hands on their head and falls to the ground, they surrender!" emote_type = EMOTE_AUDIBLE /datum/emote/living/surrender/run_emote(mob/user, params) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index b58fb0ec13..9684e44ac9 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -550,6 +550,7 @@ if(!restrained(ignore_grab = 1) && pulledby) visible_message("[src] resists against [pulledby]'s grip!") resist_grab() + add_logs(pulledby, src, "resisted grab") return //unbuckling yourself @@ -587,6 +588,7 @@ if(pulledby.grab_state) if(prob(30/pulledby.grab_state)) visible_message("[src] has broken free of [pulledby]'s grip!") + add_logs(pulledby, src, "broke grab") pulledby.stop_pulling() return 0 if(moving_resist && client) //we resisted by trying to move @@ -795,7 +797,7 @@ else to_chat(src, "You don't have the dexterity to do this!") return -/mob/living/proc/can_use_guns(var/obj/item/weapon/gun/G) +/mob/living/proc/can_use_guns(var/obj/item/weapon/G) if (G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser()) to_chat(src, "You don't have the dexterity to do this!") return 0 diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 0c693b4749..01dca7f00e 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -89,7 +89,7 @@ var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].",I.armour_penetration) apply_damage(I.throwforce, dtype, zone, armor) if(I.thrownby) - add_logs(I.thrownby, src, "hit", I) + add_logs(I.thrownby, src, "threw and hit", I) else return 1 else @@ -150,6 +150,7 @@ var/grab_upgrade_time = 30 visible_message("[user] starts to tighten [user.p_their()] grip on [src]!", \ "[user] starts to tighten [user.p_their()] grip on you!") + add_logs(user, src, "attempted to strangle", addition="grab") if(!do_mob(user, src, grab_upgrade_time)) return 0 if(!user.pulling || user.pulling != src || user.grab_state != old_grab_state || user.a_intent != INTENT_GRAB) @@ -157,18 +158,20 @@ user.grab_state++ switch(user.grab_state) if(GRAB_AGGRESSIVE) - add_logs(user, src, "grabbed", addition="aggressively") + add_logs(user, src, "grabbed", addition="aggressive grab") visible_message("[user] has grabbed [src] aggressively!", \ "[user] has grabbed [src] aggressively!") drop_all_held_items() stop_pulling() if(GRAB_NECK) + add_logs(user, src, "grabbed", addition="neck grab") visible_message("[user] has grabbed [src] by the neck!",\ "[user] has grabbed you by the neck!") update_canmove() //we fall down if(!buckled && !density) Move(user.loc) if(GRAB_KILL) + add_logs(user, src, "strangled", addition="grab") visible_message("[user] is strangling [src]!", \ "[user] is strangling you!") update_canmove() //we fall down @@ -316,7 +319,7 @@ GLOB.cult_narsie.souls += 1 if((GLOB.cult_narsie.souls == GLOB.cult_narsie.soul_goal) && (GLOB.cult_narsie.resolved == FALSE)) GLOB.cult_narsie.resolved = TRUE - world << sound('sound/machines/alarm.ogg') + sound_to_playing_players('sound/machines/alarm.ogg') addtimer(CALLBACK(GLOBAL_PROC, .proc/cult_ending_helper, 1), 120) addtimer(CALLBACK(GLOBAL_PROC, .proc/ending_helper), 270) if(client) diff --git a/code/modules/mob/living/silicon/ai/examine.dm b/code/modules/mob/living/silicon/ai/examine.dm index b19e866378..3af95cec4c 100644 --- a/code/modules/mob/living/silicon/ai/examine.dm +++ b/code/modules/mob/living/silicon/ai/examine.dm @@ -1,5 +1,5 @@ /mob/living/silicon/ai/examine(mob/user) - var/msg = "*---------*\nThis is [bicon(src)] [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] [src]!\n" if (stat == DEAD) msg += "It appears to be powered-down.\n" else diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index 2e800f7de0..f0e079b594 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -163,9 +163,9 @@ if(M.client && M.can_hear() && (M.client.prefs.toggles & SOUND_ANNOUNCEMENTS)) var/turf/T = get_turf(M) if(T.z == z_level) - M << voice + SEND_SOUND(M, voice) else - only_listener << voice + SEND_SOUND(only_listener, voice) return 1 return 0 diff --git a/code/modules/mob/living/silicon/pai/personality.dm b/code/modules/mob/living/silicon/pai/personality.dm index 869009f255..4b2bc45118 100644 --- a/code/modules/mob/living/silicon/pai/personality.dm +++ b/code/modules/mob/living/silicon/pai/personality.dm @@ -17,12 +17,12 @@ var/savefile/F = new /savefile(src.savefile_path(user)) - F["name"] << src.name - F["description"] << src.description - F["role"] << src.role - F["comments"] << src.comments + WRITE_FILE(F["name"], name) + WRITE_FILE(F["description"], description) + WRITE_FILE(F["role"], role) + WRITE_FILE(F["comments"], comments) - F["version"] << 1 + WRITE_FILE(F["version"], 1) return 1 diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index 77874ad403..f0c50e17f1 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -173,7 +173,7 @@ if(href_list["send"]) sradio.send_signal("ACTIVATE") - audible_message("[bicon(src)] *beep* *beep*") + audible_message("[icon2html(src, world)] *beep* *beep*") if(href_list["freq"]) @@ -619,7 +619,8 @@ src.paiInterface() if(hackprogress >= 100) src.hackprogress = 0 - src.cable.machine:open() + var/obj/machinery/door/D = cable.machine + D.open() sleep(50) // Update every 5 seconds // Digital Messenger diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 7f232e20f4..788a8f4255 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -1,11 +1,11 @@ /mob/living/silicon/robot/examine(mob/user) - var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src]!\n" if(desc) msg += "[desc]\n" var/obj/act_module = get_active_held_item() if(act_module) - msg += "It is holding [bicon(act_module)] \a [act_module].\n" + msg += "It is holding [icon2html(act_module, user)] \a [act_module].\n" msg += "" if (src.getBruteLoss()) if (src.getBruteLoss() < maxHealth*0.5) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 59cb793b27..3c963ca820 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -469,7 +469,7 @@ Pass a positive integer as an argument to override a bot's default speed. var/area/end_area = get_area(waypoint) if(client) //Player bots instead get a location command from the AI - to_chat(src, "Priority waypoint set by [bicon(caller)] [caller]. Proceed to [end_area.name]<\b>.") + to_chat(src, "Priority waypoint set by [icon2html(caller, src)] [caller]. Proceed to [end_area.name]<\b>.") //For giving the bot temporary all-access. var/obj/item/weapon/card/id/all_access = new /obj/item/weapon/card/id @@ -485,7 +485,7 @@ Pass a positive integer as an argument to override a bot's default speed. turn_on() //Saves the AI the hassle of having to activate a bot manually. access_card = all_access //Give the bot all-access while under the AI's command. if(message) - to_chat(calling_ai, "[bicon(src)] [name] called to [end_area.name]. [path.len-1] meters to destination.") + to_chat(calling_ai, "[icon2html(src, calling_ai)] [name] called to [end_area.name]. [path.len-1] meters to destination.") pathset = 1 mode = BOT_RESPONDING tries = 0 @@ -500,7 +500,7 @@ Pass a positive integer as an argument to override a bot's default speed. var/success = bot_move(ai_waypoint, 3) if(!success) if(calling_ai) - to_chat(calling_ai, "[bicon(src)] [get_turf(src) == ai_waypoint ? "[src] successfully arrived to waypoint." : "[src] failed to reach waypoint."]") + to_chat(calling_ai, "[icon2html(src, calling_ai)] [get_turf(src) == ai_waypoint ? "[src] successfully arrived to waypoint." : "[src] failed to reach waypoint."]") calling_ai = null bot_reset() diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index e8936a2863..74005e84dd 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -596,7 +596,7 @@ if(pathset) //The AI called us here, so notify it of our arrival. loaddir = dir //The MULE will attempt to load a crate in whatever direction the MULE is "facing". if(calling_ai) - to_chat(calling_ai, "[bicon(src)] [src] wirelessly plays a chiming sound!") + to_chat(calling_ai, "[icon2html(src, calling_ai)] [src] wirelessly plays a chiming sound!") playsound(calling_ai, 'sound/machines/chime.ogg',40, 0) calling_ai = null radio_channel = "AI Private" //Report on AI Private instead if the AI is controlling us. diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 74f855bf8c..e0993c6ce5 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -50,7 +50,7 @@ /mob/living/simple_animal/hostile/construct/examine(mob/user) var/t_He = p_they(TRUE) var/t_s = p_s() - var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src]!\n" msg += "[desc]\n" if(health < maxHealth) msg += "" diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index ef0b35cdc3..62e0fb8fdd 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -130,7 +130,7 @@ family[C.type] += 1 else family[C.type] = 1 - S["family"] << family + WRITE_FILE(S["family"], family) memory_saved = 1 /mob/living/simple_animal/pet/cat/Runtime/proc/Deploy_The_Cats() diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index f80defb32d..58d497293a 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -344,14 +344,14 @@ /mob/living/simple_animal/pet/dog/corgi/Ian/proc/Write_Memory(dead) var/savefile/S = new /savefile("data/npc_saves/Ian.sav") if(!dead) - S["age"] << age + 1 + WRITE_FILE(S["age"], age + 1) if((age + 1) > record_age) - S["record_age"] << record_age + 1 + WRITE_FILE(S["record_age"], record_age + 1) if(inventory_head) - S["saved_head"] << inventory_head.type + WRITE_FILE(S["saved_head"], inventory_head.type) else - S["age"] << 0 - S["saved_head"] << null + WRITE_FILE(S["age"], 0) + WRITE_FILE(S["saved_head"], null) memory_saved = 1 diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index db347cc203..b37d5079d7 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -171,29 +171,29 @@ /mob/living/simple_animal/drone/examine(mob/user) - var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src]!\n" //Hands for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "It has [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "It has [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "It has [bicon(I)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "It has [icon2html(I, user)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" //Internal storage if(internal_storage && !(internal_storage.flags&ABSTRACT)) if(internal_storage.blood_DNA) - msg += "It is holding [bicon(internal_storage)] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n" + msg += "It is holding [icon2html(internal_storage, user)] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n" else - msg += "It is holding [bicon(internal_storage)] \a [internal_storage] in its internal storage.\n" + msg += "It is holding [icon2html(internal_storage, user)] \a [internal_storage] in its internal storage.\n" //Cosmetic hat - provides no function other than looks if(head && !(head.flags&ABSTRACT)) if(head.blood_DNA) - msg += "It is wearing [bicon(head)] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on its head!\n" + msg += "It is wearing [icon2html(head, user)] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on its head!\n" else - msg += "It is wearing [bicon(head)] \a [head] on its head.\n" + msg += "It is wearing [icon2html(head, user)] \a [head] on its head.\n" //Braindead if(!client && stat != DEAD) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index c984194805..51d28df31b 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -176,7 +176,7 @@ else ..() -/mob/living/simple_animal/drone/cogscarab/can_use_guns(obj/item/weapon/gun/G) +/mob/living/simple_animal/drone/cogscarab/can_use_guns(obj/item/weapon/G) return GLOB.ratvar_awakens /mob/living/simple_animal/drone/cogscarab/get_armor_effectiveness() diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 207bda2c2c..75a1759e1d 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -57,7 +57,7 @@ if( ishuman(AM) ) if(!stat) var/mob/M = AM - to_chat(M, "[bicon(src)] Squeek!") + to_chat(M, "[icon2html(src, M)] Squeek!") playsound(src, 'sound/effects/mousesqueek.ogg', 100, 1) ..() diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm index 5fe0ccaade..02754e0121 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm @@ -26,21 +26,21 @@ /mob/living/simple_animal/hostile/guardian/dextrous/examine(mob/user) if(dextrous) - var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src)] \a [src]!\n" msg += "[desc]\n" for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "It has [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "It has [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "It has [bicon(I)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "It has [icon2html(I, user)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" if(internal_storage && !(internal_storage.flags&ABSTRACT)) if(internal_storage.blood_DNA) - msg += "It is holding [bicon(internal_storage)] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n" + msg += "It is holding [icon2html(internal_storage, user)] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n" else - msg += "It is holding [bicon(internal_storage)] \a [internal_storage] in its internal storage.\n" + msg += "It is holding [icon2html(internal_storage, user)] \a [internal_storage] in its internal storage.\n" msg += "*---------*" to_chat(user, msg) else diff --git a/code/modules/mob/living/simple_animal/guardian/types/fire.dm b/code/modules/mob/living/simple_animal/guardian/types/fire.dm index b0a8ba5215..8f456abc53 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/fire.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/fire.dm @@ -21,7 +21,7 @@ /mob/living/simple_animal/hostile/guardian/fire/AttackingTarget() . = ..() if(. && ishuman(target) && target != summoner) - new /obj/effect/hallucination/delusion(target.loc,target,"custom",200,0, icon_state,icon) + new /datum/hallucination/delusion(target,TRUE,"custom",200,0, icon_state,icon) /mob/living/simple_animal/hostile/guardian/fire/Crossed(AM as mob|obj) ..() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 7be59e1322..356c3197b3 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -283,7 +283,7 @@ Difficulty: Very Hard for(var/obj/O in (contents-component_parts)) stored_items += O.type - S["stored_items"] << stored_items + WRITE_FILE(S["stored_items"], stored_items) memory_saved = TRUE /obj/machinery/smartfridge/black_box/proc/ReadMemory() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index 11c59a2d28..0ca966df35 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -57,6 +57,7 @@ Difficulty: Hard ranged_cooldown_time = 40 aggro_vision_range = 21 //so it can see to one side of the arena to the other loot = list(/obj/item/weapon/hierophant_club) + crusher_loot = list(/obj/item/weapon/hierophant_club) wander = FALSE var/burst_range = 3 //range on burst aoe var/beam_range = 5 //range on cross blast beams diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 86bbcfdc45..6be40e0d43 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -936,10 +936,10 @@ /mob/living/simple_animal/parrot/Poly/proc/Write_Memory() var/savefile/S = new /savefile("data/npc_saves/Poly.sav") if(islist(speech_buffer)) - S["phrases"] << speech_buffer - S["roundssurvived"] << rounds_survived - S["longestsurvival"] << longest_survival - S["longestdeathstreak"] << longest_deathstreak + WRITE_FILE(S["phrases"], speech_buffer) + WRITE_FILE(S["roundssurvived"], rounds_survived) + WRITE_FILE(S["longestsurvival"], longest_survival) + WRITE_FILE(S["longestdeathstreak"], longest_deathstreak) memory_saved = 1 /mob/living/simple_animal/parrot/Poly/ghost diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 236b36dafd..0e7d7a157e 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -347,7 +347,7 @@ /mob/living/simple_animal/slime/examine(mob/user) - var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src]!\n" if (src.stat == DEAD) msg += "It is limp and unresponsive.\n" else diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 26b22d964e..d612611ea6 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -327,6 +327,7 @@ if(AM.pulledby) if(!supress_message) visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.") + add_logs(AM, AM.pulledby, "pulled from", src) AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. pulling = AM @@ -337,6 +338,7 @@ if(ismob(AM)) var/mob/M = AM + add_logs(src, M, "grabbed", addition="passive grab") if(!supress_message) visible_message("[src] has grabbed [M] passively!") if(!iscarbon(src)) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index a704c2e43f..999779c7e3 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -325,6 +325,9 @@ It's fairly easy to fix if dealing with single letters but not so much with comp return B.eye_blind return 0 +/mob/proc/hallucinating() + return FALSE + /proc/is_special_character(mob/M) // returns 1 for special characters and 2 for heroes of gamemode //moved out of admins.dm because things other than admin procs were calling this. if(!SSticker.HasRoundStarted()) return 0 @@ -384,7 +387,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp if(O.client) to_chat(O, "[message][(enter_link) ? " [enter_link]" : ""]") if(ghost_sound) - O << sound(ghost_sound) + SEND_SOUND(O, sound(ghost_sound)) if(flashwindow) window_flash(O.client) if(source) diff --git a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm index f200fbf747..10a6deb63d 100644 --- a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm +++ b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm @@ -110,7 +110,7 @@ if(!channel) return var/mob/living/user = usr - var/logname = input(user,"Enter desired logfile name (.log) or leave blank to cancel:") + var/logname = stripped_input(user,"Enter desired logfile name (.log) or leave blank to cancel:") if(!logname || !channel) return 1 var/datum/computer_file/data/logfile = new/datum/computer_file/data/logfile() diff --git a/code/modules/ninja/suit/suit_initialisation.dm b/code/modules/ninja/suit/suit_initialisation.dm index b723ade381..5fb3fe8a62 100644 --- a/code/modules/ninja/suit/suit_initialisation.dm +++ b/code/modules/ninja/suit/suit_initialisation.dm @@ -70,7 +70,7 @@ addtimer(CALLBACK(src, .proc/deinitialize_three, delay, U), delay) /obj/item/clothing/suit/space/space_ninja/proc/deinitialize_three(delay, mob/living/carbon/human/U) - to_chat(U, "Logging off, [U:real_name]. Shutting down SpiderOS.") + to_chat(U, "Logging off, [U.real_name]. Shutting down SpiderOS.") addtimer(CALLBACK(src, .proc/deinitialize_four, delay, U), delay) /obj/item/clothing/suit/space/space_ninja/proc/deinitialize_four(delay, mob/living/carbon/human/U) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index b1896f930a..4755f3d64a 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -222,8 +222,9 @@ var/offX = 32 * (A.x - center.x) + A.pixel_x + 33 var/offY = 32 * (A.y - center.y) + A.pixel_y + 33 if(ismovableatom(A)) - offX += A:step_x - offY += A:step_y + var/atom/movable/AM = A + offX += AM.step_x + offY += AM.step_y res.Blend(img, blendMode2iconMode(A.blend_mode), offX, offY) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index e36c639eb9..d01516e312 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -120,8 +120,8 @@ if(auto_name) name = "\improper [get_area(src)] APC" - pixel_x = (src.tdir & 3)? 0 : (src.tdir == 4 ? 24 : -24) - pixel_y = (src.tdir & 3)? (src.tdir ==1 ? 24 : -24) : 0 + pixel_x = (src.tdir & 3)? 0 : (src.tdir == 4 ? 26 : -27) + pixel_y = (src.tdir & 3)? (src.tdir == 1 ? 25 : -25) : 0 if (building) area = get_area(src) opened = 1 @@ -892,7 +892,7 @@ transfer_in_progress = TRUE user.visible_message("[user] slots [card] into [src]...", "Transfer process initiated. Sending request for AI approval...") playsound(src, 'sound/machines/click.ogg', 50, 1) - occupier << sound('sound/misc/notice2.ogg') //To alert the AI that someone's trying to card them if they're tabbed out + SEND_SOUND(occupier, sound('sound/misc/notice2.ogg')) //To alert the AI that someone's trying to card them if they're tabbed out if(alert(occupier, "[user] is attempting to transfer you to \a [card.name]. Do you consent to this?", "APC Transfer", "Yes - Transfer Me", "No - Keep Me Here") == "No - Keep Me Here") to_chat(user, "AI denied transfer request. Process terminated.") playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 1) @@ -986,9 +986,6 @@ else main_status = 2 - //if(debug) - // world.log << "Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light] - Longterm: [longtermpower]" - if(cell && !shorted) // draw power from cell as before to power the area var/cellused = min(cell.charge, GLOB.CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index b0d07e88d5..f130e7be11 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -216,7 +216,6 @@ //remove the old powernet and replace it with a new one throughout the network. /proc/propagate_network(obj/O, datum/powernet/PN) - //world.log << "propagating new network" var/list/worklist = list() var/list/found_machines = list() var/index = 1 diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 90c33bb6b3..df969d869e 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -71,7 +71,7 @@ sleep(1150) if(resolved == FALSE) resolved = TRUE - world << sound('sound/machines/alarm.ogg') + sound_to_playing_players('sound/machines/alarm.ogg') addtimer(CALLBACK(GLOBAL_PROC, .proc/cult_ending_helper), 120) addtimer(CALLBACK(GLOBAL_PROC, .proc/ending_helper), 220) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 07190b102c..1b65da86ab 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -26,7 +26,7 @@ var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing var/last_warning var/consumedSupermatter = 0 //If the singularity has eaten a supermatter shard and can go to stage six - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF dangerous_possession = TRUE /obj/singularity/Initialize(mapload, starting_energy = 50) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 816cd97874..f635d8e227 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -219,7 +219,7 @@ var/turf/T = get_turf(src) for(var/mob/M in GLOB.mob_list) if(M.z == z) - M << 'sound/magic/charge.ogg' + SEND_SOUND(M, 'sound/magic/charge.ogg') to_chat(M, "You feel reality distort for a moment...") if(combined_gas > MOLE_PENALTY_THRESHOLD) investigate_log("has collapsed into a singularity.", INVESTIGATE_SUPERMATTER) @@ -457,7 +457,7 @@ visible_message("[src] is consumed by the singularity!") for(var/mob/M in GLOB.mob_list) if(M.z == z) - M << 'sound/effects/supermatter.ogg' //everyone goan know bout this + SEND_SOUND(M, 'sound/effects/supermatter.ogg') //everyone goan know bout this to_chat(M, "A horrible screeching fills your ears, and a wave of dread washes over you...") qdel(src) return gain diff --git a/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm b/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm index 24b75a3a9a..6fdcccd43f 100644 --- a/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm +++ b/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm @@ -37,16 +37,12 @@ /datum/mapGeneratorModule/bottomLayer/massdelete/leave_turfs deleteturfs = FALSE -/datum/mapGeneratorModule/bottomLayer/massdelete/leave_turfs/New() - ..() - ignore_typecache = typecacheof(list(/turf)) - /datum/mapGeneratorModule/bottomLayer/massdelete/regeneration_delete deleteturfs = FALSE /datum/mapGeneratorModule/bottomLayer/massdelete/regeneration_delete/New() ..() - ignore_typecache = typecacheof(list(/mob, /turf)) + ignore_typecache = typecacheof(list(/mob)) //Only places atoms/turfs on area borders /datum/mapGeneratorModule/border diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 156a5ee81e..d5109a2c0c 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -27,7 +27,7 @@ var/recoil = 0 //boom boom shake the room var/clumsy_check = 1 var/obj/item/ammo_casing/chambered = null - var/trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers + trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers var/sawn_desc = null //description change if weapon is sawn-off var/sawn_state = SAWN_INTACT var/burst_size = 1 //how large a burst is @@ -188,12 +188,10 @@ -/obj/item/weapon/gun/proc/can_trigger_gun(var/mob/living/user) - - if(!handle_pins(user) || !user.can_use_guns(src)) - return 0 - - return 1 +/obj/item/weapon/gun/can_trigger_gun(mob/living/user) + . = ..() + if(!handle_pins(user)) + return FALSE /obj/item/weapon/gun/proc/handle_pins(mob/living/user) if(pin) diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 54e0ed7e12..f7aedb00fc 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -356,7 +356,7 @@ /obj/item/projectile/bullet/saw/hollow damage = 60 - armour_penetration = -10 + armour_penetration = -60 /obj/item/projectile/bullet/saw/ap damage = 40 diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index 4b1d5af6c4..5a8f49f45a 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -387,3 +387,232 @@ var/obj/effect/ebeam/B = b animate(B, alpha = 0, time = 32) return ..() + +/obj/item/projectile/hallucination + name = "bullet" + icon = null + icon_state = null + hitsound = "" + suppressed = TRUE + ricochets_max = 0 + ricochet_chance = 0 + damage = 0 + nodamage = TRUE + projectile_type = /obj/item/projectile/hallucination + log_override = TRUE + var/hal_icon_state + var/image/fake_icon + var/mob/living/carbon/hal_target + var/hal_fire_sound + var/hal_hitsound + var/hal_hitsound_wall + var/hal_impact_effect + var/hal_impact_effect_wall + var/hit_duration + var/hit_duration_wall + +/obj/item/projectile/hallucination/fire() + ..() + fake_icon = image('icons/obj/projectiles.dmi', src, hal_icon_state, ABOVE_MOB_LAYER) + if(hal_target.client) + hal_target.client.images += fake_icon + +/obj/item/projectile/hallucination/Destroy() + if(hal_target.client) + hal_target.client.images -= fake_icon + QDEL_NULL(fake_icon) + return ..() + +/obj/item/projectile/hallucination/Collide(atom/A) + if(!ismob(A)) + if(hal_hitsound_wall) + hal_target.playsound_local(loc, hal_hitsound_wall, 40, 1) + if(hal_impact_effect_wall) + spawn_hit(A, TRUE) + else if(A == hal_target) + if(hal_hitsound) + hal_target.playsound_local(A, hal_hitsound, 100, 1) + target_on_hit(A) + qdel(src) + return TRUE + +/obj/item/projectile/hallucination/proc/target_on_hit(mob/M) + if(M == hal_target) + to_chat(hal_target, "[M] is hit by \a [src] in the chest!") + hal_apply_effect() + else if(M in view(hal_target)) + to_chat(hal_target, "[M] is hit by \a [src] in the chest!!") + if(damage_type == BRUTE) + var/splatter_dir = dir + if(starting) + splatter_dir = get_dir(starting, get_turf(M)) + spawn_blood(M, splatter_dir) + else if(hal_impact_effect) + spawn_hit(M, FALSE) + +/obj/item/projectile/hallucination/proc/spawn_blood(mob/M, set_dir) + set waitfor = 0 + if(!hal_target.client) + return + + var/splatter_icon_state + if(set_dir in GLOB.diagonals) + splatter_icon_state = "splatter[pick(1, 2, 6)]" + else + splatter_icon_state = "splatter[pick(3, 4, 5)]" + + var/image/blood = image('icons/effects/blood.dmi', M, splatter_icon_state, ABOVE_MOB_LAYER) + var/target_pixel_x = 0 + var/target_pixel_y = 0 + switch(set_dir) + if(NORTH) + target_pixel_y = 16 + if(SOUTH) + target_pixel_y = -16 + layer = ABOVE_MOB_LAYER + if(EAST) + target_pixel_x = 16 + if(WEST) + target_pixel_x = -16 + if(NORTHEAST) + target_pixel_x = 16 + target_pixel_y = 16 + if(NORTHWEST) + target_pixel_x = -16 + target_pixel_y = 16 + if(SOUTHEAST) + target_pixel_x = 16 + target_pixel_y = -16 + layer = ABOVE_MOB_LAYER + if(SOUTHWEST) + target_pixel_x = -16 + target_pixel_y = -16 + layer = ABOVE_MOB_LAYER + hal_target.client.images += blood + animate(blood, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = 5) + sleep(5) + hal_target.client.images -= blood + qdel(blood) + +/obj/item/projectile/hallucination/proc/spawn_hit(atom/A, is_wall) + set waitfor = 0 + if(!hal_target.client) + return + + var/image/hit_effect = image('icons/effects/blood.dmi', A, is_wall ? hal_impact_effect_wall : hal_impact_effect, ABOVE_MOB_LAYER) + hit_effect.pixel_x = A.pixel_x + rand(-4,4) + hit_effect.pixel_y = A.pixel_y + rand(-4,4) + hal_target.client.images += hit_effect + sleep(is_wall ? hit_duration_wall : hit_duration) + hal_target.client.images -= hit_effect + qdel(hit_effect) + + +/obj/item/projectile/hallucination/proc/hal_apply_effect() + return + +/obj/item/projectile/hallucination/bullet + name = "bullet" + hal_icon_state = "bullet" + hal_fire_sound = "gunshot" + hal_hitsound = 'sound/weapons/pierce.ogg' + hal_hitsound_wall = "ricochet" + hal_impact_effect = "impact_bullet" + hal_impact_effect_wall = "impact_bullet" + hit_duration = 5 + hit_duration_wall = 5 + +/obj/item/projectile/hallucination/bullet/hal_apply_effect() + hal_target.adjustStaminaLoss(60) + +/obj/item/projectile/hallucination/laser + name = "laser" + damage_type = BURN + hal_icon_state = "laser" + hal_fire_sound = 'sound/weapons/laser.ogg' + hal_hitsound = 'sound/weapons/sear.ogg' + hal_hitsound_wall = 'sound/weapons/effects/searwall.ogg' + hal_impact_effect = "impact_laser" + hal_impact_effect_wall = "impact_laser_wall" + hit_duration = 4 + hit_duration_wall = 10 + pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE + +/obj/item/projectile/hallucination/laser/hal_apply_effect() + hal_target.adjustStaminaLoss(20) + hal_target.blur_eyes(2) + +/obj/item/projectile/hallucination/taser + name = "electrode" + damage_type = BURN + hal_icon_state = "spark" + color = "#FFFF00" + hal_fire_sound = 'sound/weapons/taser.ogg' + hal_hitsound = 'sound/weapons/taserhit.ogg' + hal_hitsound_wall = null + hal_impact_effect = null + hal_impact_effect_wall = null + +/obj/item/projectile/hallucination/taser/hal_apply_effect() + hal_target.Knockdown(100) + hal_target.stuttering += 20 + if(hal_target.dna && hal_target.dna.check_mutation(HULK)) + hal_target.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) + else if(hal_target.status_flags & CANKNOCKDOWN) + addtimer(CALLBACK(hal_target, /mob/living/carbon.proc/do_jitter_animation, 20), 5) + +/obj/item/projectile/hallucination/disabler + name = "disabler beam" + damage_type = STAMINA + hal_icon_state = "omnilaser" + hal_fire_sound = 'sound/weapons/taser2.ogg' + hal_hitsound = 'sound/weapons/tap.ogg' + hal_hitsound_wall = 'sound/weapons/effects/searwall.ogg' + hal_impact_effect = "impact_laser_blue" + hal_impact_effect_wall = null + hit_duration = 4 + pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE + +/obj/item/projectile/hallucination/disabler/hal_apply_effect() + hal_target.adjustStaminaLoss(25) + +/obj/item/projectile/hallucination/ebow + name = "bolt" + damage_type = TOX + hal_icon_state = "cbbolt" + hal_fire_sound = 'sound/weapons/genhit.ogg' + hal_hitsound = null + hal_hitsound_wall = null + hal_impact_effect = null + hal_impact_effect_wall = null + +/obj/item/projectile/hallucination/ebow/hal_apply_effect() + hal_target.Knockdown(100) + hal_target.stuttering += 5 + hal_target.adjustStaminaLoss(8) + +/obj/item/projectile/hallucination/change + name = "bolt of change" + damage_type = BURN + hal_icon_state = "ice_1" + hal_fire_sound = 'sound/magic/staff_change.ogg' + hal_hitsound = null + hal_hitsound_wall = null + hal_impact_effect = null + hal_impact_effect_wall = null + +/obj/item/projectile/hallucination/change/hal_apply_effect() + new /datum/hallucination/self_delusion(hal_target, TRUE, wabbajack = FALSE) + +/obj/item/projectile/hallucination/death + name = "bolt of death" + damage_type = BURN + hal_icon_state = "pulse1_bl" + hal_fire_sound = 'sound/magic/wandodeath.ogg' + hal_hitsound = null + hal_hitsound_wall = null + hal_impact_effect = null + hal_impact_effect_wall = null + +/obj/item/projectile/hallucination/death/hal_apply_effect() + new /datum/hallucination/death(hal_target, TRUE) diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 8d2bd6002f..54d17497f3 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -370,9 +370,8 @@ else if(cached_my_atom.type == C.required_container) matching_container = 1 - if (isliving(cached_my_atom)) //Makes it so certain chemical reactions don't occur in mobs - if (C.mob_react) - return + if (isliving(cached_my_atom) && !C.mob_react) //Makes it so certain chemical reactions don't occur in mobs + return if(!C.required_other) matching_other = 1 @@ -401,19 +400,21 @@ add_reagent(P, cached_results[P]*multiplier, null, chem_temp) var/list/seen = viewers(4, get_turf(my_atom)) + var/iconhtml = icon2html(cached_my_atom, seen) if(cached_my_atom) if(!ismob(cached_my_atom)) // No bubbling mobs if(C.mix_sound) playsound(get_turf(cached_my_atom), C.mix_sound, 80, 1) + for(var/mob/M in seen) - to_chat(M, "[bicon(my_atom)] [C.mix_message]") + to_chat(M, "[iconhtml] [C.mix_message]") if(istype(cached_my_atom, /obj/item/slime_extract)) var/obj/item/slime_extract/ME2 = my_atom ME2.Uses-- if(ME2.Uses <= 0) // give the notification that the slime core is dead for(var/mob/M in seen) - to_chat(M, "[bicon(my_atom)] \The [my_atom]'s power is consumed in the reaction.") + to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.") ME2.name = "used slime extract" ME2.desc = "This extract has been used up." diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index 8cf7333c6e..716943e7f4 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -101,9 +101,11 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) ui = new(user, src, ui_key, "chem_dispenser", name, 550, 550, master_ui, state) + if(user.hallucinating()) + ui.set_autoupdate(FALSE) //to not ruin the immersion by constantly changing the fake chemicals ui.open() -/obj/machinery/chem_dispenser/ui_data() +/obj/machinery/chem_dispenser/ui_data(mob/user) var/data = list() data["amount"] = amount data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI. @@ -128,10 +130,16 @@ data["beakerTransferAmounts"] = null var chemicals[0] + var/is_hallucinating = FALSE + if(user.hallucinating()) + is_hallucinating = TRUE for(var/re in dispensable_reagents) var/datum/reagent/temp = GLOB.chemical_reagents_list[re] if(temp) - chemicals.Add(list(list("title" = temp.name, "id" = temp.id))) + var/chemname = temp.name + if(is_hallucinating && prob(5)) + chemname = "[pick_list_replacements("hallucination.json", "chemicals")]" + chemicals.Add(list(list("title" = chemname, "id" = temp.id))) data["chemicals"] = chemicals return data diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 1fae98e2f3..72001d5ca9 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -390,7 +390,7 @@ T.MakeSlippery(min_wet_time = 10, wet_time_to_add = reac_volume*2) var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T) if(hotspot) - var/datum/gas_mixture/lowertemp = T.remove_air( T:air:total_moles() ) + 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) diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index c13ff096e4..428c10e24a 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -10,7 +10,7 @@ var/required_other = 0 // an integer required for the reaction to happen var/secondary = 0 // set to nonzero if secondary reaction - var/mob_react = 0 //Determines if a chemical reaction can occur inside a mob + var/mob_react = TRUE //Determines if a chemical reaction can occur inside a mob var/required_temp = 0 var/is_cold_recipe = 0 // Set to 1 if you want the recipe to only react when it's BELOW the required temp. diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 4151a2695e..01195333fb 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -51,7 +51,7 @@ name = "Solid Plasma" id = "solidplasma" required_reagents = list("iron" = 5, "frostoil" = 5, "plasma" = 20) - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/plasmasolidification/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) @@ -62,7 +62,7 @@ name = "Solid Gold" id = "solidgold" required_reagents = list("frostoil" = 5, "gold" = 20, "iron" = 1) - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/goldsolidification/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) @@ -80,7 +80,7 @@ id = "soapification" required_reagents = list("liquidgibs" = 10, "lye" = 10) // requires two scooped gib tiles required_temp = 374 - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/soapification/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) @@ -92,7 +92,7 @@ id = "candlefication" required_reagents = list("liquidgibs" = 5, "oxygen" = 5) // required_temp = 374 - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/candlefication/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) @@ -103,7 +103,7 @@ name = "Meatification" id = "meatification" required_reagents = list("liquidgibs" = 10, "nutriment" = 10, "carbon" = 10) - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/meatification/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) @@ -436,7 +436,7 @@ name = "Foam" id = "foam" required_reagents = list("fluorosurfactant" = 1, "water" = 1) - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/foam/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) @@ -453,7 +453,7 @@ name = "Metal Foam" id = "metalfoam" required_reagents = list("aluminium" = 3, "foaming_agent" = 1, "facid" = 1) - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/metalfoam/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) @@ -470,7 +470,7 @@ name = "Iron Foam" id = "ironlfoam" required_reagents = list("iron" = 3, "foaming_agent" = 1, "facid" = 1) - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/ironfoam/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index dc361467a7..8ca65a6588 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -144,6 +144,7 @@ required_reagents = list("methamphetamine" = 1) strengthdiv = 6 modifier = 1 + mob_react = FALSE /datum/chemical_reaction/reagent_explosion/methsplosion/on_reaction(datum/reagents/holder, created_volume) var/turf/T = get_turf(holder.my_atom) @@ -154,7 +155,7 @@ /datum/chemical_reaction/reagent_explosion/methsplosion/methboom2 required_reagents = list("diethylamine" = 1, "iodine" = 1, "phosphorus" = 1, "hydrogen" = 1) //diethylamine is often left over from mixing the ephedrine. - required_temp = 300 //room temperature, chilling it even a little will prevent the explosion + required_temp = 300 //room temperature, chilling it even a little will prevent the explosion results = list("methboom1" = 4) // this is ugly. Sorry goof. /datum/chemical_reaction/sorium @@ -269,7 +270,7 @@ required_reagents = list("smoke_powder" = 1) required_temp = 374 secondary = 1 - mob_react = 1 + mob_react = FALSE /datum/chemical_reaction/smoke_powder_smoke/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index 0d0a4f7695..4388d6bcbe 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -341,7 +341,7 @@ found = 1 break if(!found) - to_chat(user, "[bicon(src)]The conveyor switch did not detect any linked conveyor belts in range.") + to_chat(user, "[icon2html(src, user)]The conveyor switch did not detect any linked conveyor belts in range.") return var/obj/machinery/conveyor_switch/NC = new/obj/machinery/conveyor_switch(A, id) transfer_fingerprints_to(NC) diff --git a/code/modules/ruins/objects_and_mobs/ruin_mapping_aids.dm b/code/modules/ruins/objects_and_mobs/ruin_mapping_aids.dm index 06fb2b9c04..68a34637b8 100644 --- a/code/modules/ruins/objects_and_mobs/ruin_mapping_aids.dm +++ b/code/modules/ruins/objects_and_mobs/ruin_mapping_aids.dm @@ -1,10 +1,10 @@ //These landmarks can be placed in rooms/ruins to set the baseturfs of every turf in the area. Easier than having potentially unlimited subtypes of every turf or having to manually edit the turfs in the map editor /obj/effect/baseturf_helper - name = "lava baseturf editor" + name = "baseturf editor" icon = 'icons/obj/weapons.dmi' icon_state = "syndballoon" - var/baseturf = /turf/open/lava/smooth/lava_land_surface + var/baseturf = null layer = POINT_LAYER /obj/effect/baseturf_helper/Initialize() @@ -13,4 +13,37 @@ for(var/turf/T in get_area_turfs(thearea, z)) if(T.baseturf != T.type) //Don't break indestructible walls and the like T.baseturf = baseturf - qdel(src) \ No newline at end of file + qdel(src) + + +/obj/effect/baseturf_helper/asteroid + name = "asteroid baseturf editor" + baseturf = /turf/open/floor/plating/asteroid + +/obj/effect/baseturf_helper/asteroid/airless + name = "asteroid airless baseturf editor" + baseturf = /turf/open/floor/plating/asteroid/airless + +/obj/effect/baseturf_helper/asteroid/basalt + name = "asteroid basalt baseturf editor" + baseturf = /turf/open/floor/plating/asteroid/basalt + +/obj/effect/baseturf_helper/asteroid/snow + name = "asteroid snow baseturf editor" + baseturf = /turf/open/floor/plating/asteroid/snow + +/obj/effect/baseturf_helper/beach/sand + name = "beach sand baseturf editor" + baseturf = /turf/open/floor/plating/beach/sand + +/obj/effect/baseturf_helper/beach/water + name = "water baseturf editor" + baseturf = /turf/open/floor/plating/beach/water + +/obj/effect/baseturf_helper/lava + name = "lava baseturf editor" + baseturf = /turf/open/lava/smooth + +/obj/effect/baseturf_helper/lava_land/surface + name = "lavaland baseturf editor" + baseturf = /turf/open/lava/smooth/lava_land_surface diff --git a/code/modules/server_tools/server_tools.dm b/code/modules/server_tools/server_tools.dm index d6a98ad2e5..be8c80ac24 100644 --- a/code/modules/server_tools/server_tools.dm +++ b/code/modules/server_tools/server_tools.dm @@ -73,7 +73,7 @@ GLOBAL_PROTECT(reboot_mode) if(rtod - last_irc_status < IRC_STATUS_THROTTLE) return last_irc_status = rtod - return "[GLOB.clients.len] players on [SSmapping.config.map_name], Mode: [GLOB.master_mode]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [config.server ? config.server : "[world.internet_address]:[world.port]"]" + return "[GLOB.round_id ? "Round #[GLOB.round_id]: " : ""][GLOB.clients.len] players on [SSmapping.config.map_name], Mode: [GLOB.master_mode]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [config.server ? config.server : "[world.internet_address]:[world.port]"]" if(SERVICE_CMD_ADMIN_MSG) return IrcPm(params[SERVICE_CMD_PARAM_TARGET], params[SERVICE_CMD_PARAM_MESSAGE], params[SERVICE_CMD_PARAM_SENDER]) diff --git a/code/modules/spells/spell_types/knock.dm b/code/modules/spells/spell_types/knock.dm index b68491d15d..bbb2b3877f 100644 --- a/code/modules/spells/spell_types/knock.dm +++ b/code/modules/spells/spell_types/knock.dm @@ -13,7 +13,7 @@ action_icon_state = "knock" /obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets,mob/user = usr) - user << sound('sound/magic/knock.ogg') + SEND_SOUND(user, sound('sound/magic/knock.ogg')) for(var/turf/T in targets) for(var/obj/machinery/door/door in T.contents) INVOKE_ASYNC(src, .proc/open_door, door) diff --git a/code/modules/spells/spell_types/mind_transfer.dm b/code/modules/spells/spell_types/mind_transfer.dm index fafb8afde6..023af548d0 100644 --- a/code/modules/spells/spell_types/mind_transfer.dm +++ b/code/modules/spells/spell_types/mind_transfer.dm @@ -75,5 +75,5 @@ Also, you never added distance checking after target is selected. I've went ahea //Here we knock both mobs out for a time. caster.Unconscious(unconscious_amount_caster) victim.Unconscious(unconscious_amount_victim) - caster << sound('sound/magic/mandswap.ogg') - victim << sound('sound/magic/mandswap.ogg')// only the caster and victim hear the sounds, that way no one knows for sure if the swap happened + SEND_SOUND(caster, sound('sound/magic/mandswap.ogg')) + SEND_SOUND(victim, sound('sound/magic/mandswap.ogg'))// only the caster and victim hear the sounds, that way no one knows for sure if the swap happened diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index ff44804e75..0f5f1de91d 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -290,9 +290,8 @@ //HALLUCINATE else if((findtext(message, hallucinate_words))) cooldown = COOLDOWN_MEME - for(var/V in listeners) - var/mob/living/L = V - new /obj/effect/hallucination/delusion(get_turf(L),L,null,150 * power_multiplier,0) + for(var/mob/living/carbon/C in listeners) + new /datum/hallucination/delusion(C, TRUE, null,150 * power_multiplier,0) //WAKE UP else if((findtext(message, wakeup_words))) diff --git a/code/modules/uplink/uplink_item.dm b/code/modules/uplink/uplink_item.dm index 7b455b7d80..b04ebe6643 100644 --- a/code/modules/uplink/uplink_item.dm +++ b/code/modules/uplink/uplink_item.dm @@ -110,10 +110,10 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once. var/obj/item/weapon/storage/box/B = A if(istype(B) && B.contents.len > 0) for(var/obj/item/I in B) - U.purchase_log += "[bicon(I)]" + U.purchase_log += "[icon2base64html(I)]" else if(purchase_log_vis) - U.purchase_log += "[bicon(A)]" + U.purchase_log += "[icon2base64html(A)]" if(limited_stock > 0) limited_stock -= 1 @@ -1394,7 +1394,7 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once. continue crate_value -= I.cost new I.item(C) - U.purchase_log += "[bicon(I.item)]" + U.purchase_log += "[icon2base64html(I.item)]" SSblackbox.add_details("traitor_uplink_items_bought", "[name]|[cost]") return C diff --git a/code/modules/vehicles/bicycle.dm b/code/modules/vehicles/bicycle.dm index 2d9b3c8258..cd93196b69 100644 --- a/code/modules/vehicles/bicycle.dm +++ b/code/modules/vehicles/bicycle.dm @@ -13,7 +13,7 @@ /obj/vehicle/bicycle/buckle_mob(mob/living/M, force = 0, check_loc = 1) if(prob(easter_egg_chance) || (SSevents.holidays && SSevents.holidays[APRIL_FOOLS])) - M << sound(pick(bike_music), repeat = 1, wait = 0, volume = 80, channel = CHANNEL_BICYCLE) + SEND_SOUND(M, sound(pick(bike_music), repeat = 1, wait = 0, volume = 80, channel = CHANNEL_BICYCLE)) . = ..() /obj/vehicle/bicycle/unbuckle_mob(mob/living/buckled_mob,force = 0) diff --git a/code/world.dm b/code/world.dm index 5ef7491f45..955d19c6c4 100644 --- a/code/world.dm +++ b/code/world.dm @@ -1,3 +1,7 @@ + +//This file is just for the necessary /world definition +//Try looking in game/world.dm + /world mob = /mob/dead/new_player turf = /turf/open/space/basic @@ -10,299 +14,3 @@ #ifdef GC_FAILURE_HARD_LOOKUP loop_checks = FALSE #endif - -/world/New() - log_world("World loaded at [time_stamp()]") - - SetupExternalRSC() - - GLOB.config_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = file("data/logs/config_error.log") //temporary file used to record errors with loading config, moved to log directory once logging is set bl - - make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) - - config = new - - CheckSchemaVersion() - SetRoundID() - - SetupLogs() - - if(!RunningService()) //tgs2 support - GLOB.revdata.DownloadPRDetails() - - load_motd() - load_admins() - LoadVerbs(/datum/verbs/menu) - if(config.usewhitelist) - load_whitelist() - LoadBans() - - GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000 - - Master.Initialize(10, FALSE) - - if(config.irc_announce_new_game) - IRCBroadcast("New round starting on [SSmapping.config.map_name]!") - -/world/proc/SetupExternalRSC() -#if (PRELOAD_RSC == 0) - external_rsc_urls = world.file2list("config/external_rsc_urls.txt","\n") - var/i=1 - while(i<=external_rsc_urls.len) - if(external_rsc_urls[i]) - i++ - else - external_rsc_urls.Cut(i,i+1) -#endif - -/world/proc/CheckSchemaVersion() - if(config.sql_enabled) - if(SSdbcore.Connect()) - log_world("Database connection established.") - var/datum/DBQuery/db_version = SSdbcore.NewQuery("SELECT major, minor FROM [format_table_name("schema_version")]") - db_version.Execute() - if(db_version.NextRow()) - var/db_major = db_version.item[1] - var/db_minor = db_version.item[2] - if(db_major < DB_MAJOR_VERSION || db_minor < DB_MINOR_VERSION) - message_admins("db schema ([db_major].[db_minor]) is behind latest tg schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors") - log_sql("db schema ([db_major].[db_minor]) is behind latest tg schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors") - else - message_admins("Could not get schema version from db") - else - log_world("Your server failed to establish a connection with the database.") - -/world/proc/SetRoundID() - if(config.sql_enabled) - if(SSdbcore.Connect()) - var/datum/DBQuery/query_round_start = SSdbcore.NewQuery("INSERT INTO [format_table_name("round")] (start_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')") - query_round_start.Execute() - var/datum/DBQuery/query_round_last_id = SSdbcore.NewQuery("SELECT LAST_INSERT_ID()") - query_round_last_id.Execute() - if(query_round_last_id.NextRow()) - GLOB.round_id = query_round_last_id.item[1] - -/world/proc/SetupLogs() - GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-" - if(GLOB.round_id) - GLOB.log_directory += "[GLOB.round_id]" - else - GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]" - GLOB.world_game_log = file("[GLOB.log_directory]/game.log") - GLOB.world_attack_log = file("[GLOB.log_directory]/attack.log") - GLOB.world_runtime_log = file("[GLOB.log_directory]/runtime.log") - GLOB.world_href_log = file("[GLOB.log_directory]/hrefs.html") - GLOB.world_game_log << "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------" - GLOB.world_attack_log << "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------" - GLOB.world_runtime_log << "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------" - GLOB.changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently - if(fexists(GLOB.config_error_log)) - fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log") - fdel(GLOB.config_error_log) - - if(GLOB.round_id) - log_game("Round ID: [GLOB.round_id]") - -/world/Topic(T, addr, master, key) - var/list/input = params2list(T) - - var/pinging = ("ping" in input) - var/playing = ("players" in input) - - if(!pinging && !playing && config && config.log_world_topic) - GLOB.world_game_log << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]" - - if(input[SERVICE_CMD_PARAM_KEY]) - return ServiceCommand(input) - var/key_valid = (global.comms_allowed && input["key"] == global.comms_key) - - if(pinging) - var/x = 1 - for (var/client/C in GLOB.clients) - x++ - return x - - else if(playing) - var/n = 0 - for(var/mob/M in GLOB.player_list) - if(M.client) - n++ - return n - - else if("ircstatus" in input) //tgs2 support - var/static/last_irc_status = 0 - if(world.time - last_irc_status < 50) - return - var/list/adm = get_admin_counts() - var/list/allmins = adm["total"] - var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). " - status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode.name]." - send2irc("Status", status) - last_irc_status = world.time - - else if("status" in input) - var/list/s = list() - s["version"] = GLOB.game_version - s["mode"] = GLOB.master_mode - s["respawn"] = config ? GLOB.abandon_allowed : 0 - s["enter"] = GLOB.enter_allowed - s["vote"] = config.allow_vote_mode - s["ai"] = config.allow_ai - s["host"] = host ? host : null - s["active_players"] = get_active_player_count() - s["players"] = GLOB.clients.len - s["revision"] = GLOB.revdata.commit - s["revision_date"] = GLOB.revdata.date - - var/list/adm = get_admin_counts() - var/list/presentmins = adm["present"] - var/list/afkmins = adm["afk"] - s["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho - s["gamestate"] = SSticker.current_state - - s["map_name"] = SSmapping.config.map_name - - if(key_valid && SSticker.HasRoundStarted()) - s["real_mode"] = SSticker.mode.name - // Key-authed callers may know the truth behind the "secret" - - s["security_level"] = get_security_level() - s["round_duration"] = SSticker ? round((world.time-SSticker.round_start_time)/10) : 0 - // Amount of world's ticks in seconds, useful for calculating round duration - - if(SSshuttle && SSshuttle.emergency) - s["shuttle_mode"] = SSshuttle.emergency.mode - // Shuttle status, see /__DEFINES/stat.dm - s["shuttle_timer"] = SSshuttle.emergency.timeLeft() - // Shuttle timer, in seconds - - return list2params(s) - - else if("announce" in input) - if(!key_valid) - return "Bad Key" - else - AnnouncePR(input["announce"], json_decode(input["payload"])) - - else if("crossmessage" in input) - if(!key_valid) - return - else - if(input["crossmessage"] == "Ahelp") - relay_msg_admins("HELP: [input["source"]] [input["message_sender"]]: [input["message"]]") - if(input["crossmessage"] == "Comms_Console") - minor_announce(input["message"], "Incoming message from [input["message_sender"]]") - for(var/obj/machinery/computer/communications/CM in GLOB.machines) - CM.overrideCooldown() - if(input["crossmessage"] == "News_Report") - minor_announce(input["message"], "Breaking Update From [input["message_sender"]]") - - else if("adminmsg" in input) //tgs2 support - if(!key_valid) - return "Bad Key" - else - return IrcPm(input["adminmsg"],input["msg"],input["sender"]) - - else if("namecheck" in input) //tgs2 support - if(!key_valid) - return "Bad Key" - else - log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]") - message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]") - return keywords_lookup(input["namecheck"],1) - else if("adminwho" in input) //tgs2 support - if(!key_valid) - return "Bad Key" - else - return ircadminwho() - else if("server_hop" in input) - show_server_hop_transfer_screen(input["server_hop"]) - -#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round - //This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored - -/world/proc/AnnouncePR(announcement, list/payload) - var/static/list/PRcounts = list() //PR id -> number of times announced this round - var/id = "[payload["pull_request"]["id"]]" - if(!PRcounts[id]) - PRcounts[id] = 1 - else - ++PRcounts[id] - if(PRcounts[id] > PR_ANNOUNCEMENTS_PER_ROUND) - return - - var/final_composed = "PR: [announcement]" - for(var/client/C in GLOB.clients) - C.AnnouncePR(final_composed) - -/world/Reboot(reason = 0, fast_track = FALSE) - ServiceReboot() //handles alternative actions if necessary - if (reason || fast_track) //special reboot, do none of the normal stuff - if (usr) - log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools") - message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools") - to_chat(world, "Rebooting World immediately due to host request") - else - to_chat(world, "Rebooting world...") - Master.Shutdown() //run SS shutdowns - log_world("World rebooted at [time_stamp()]") - ..() - -/world/proc/load_motd() - GLOB.join_motd = file2text("config/motd.txt") + "
" + GLOB.revdata.GetTestMergeInfo() - -/world/proc/update_status() - var/s = "" - - if (config && config.server_name) - s += "[config.server_name] — " - - s += "[station_name()]"; - s += " (" - s += "" //Change this to wherever you want the hub to link to. - s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version. - s += "" - s += ")" - - var/list/features = list() - - if(GLOB.master_mode) - features += GLOB.master_mode - - if (!GLOB.enter_allowed) - features += "closed" - - features += GLOB.abandon_allowed ? "respawn" : "no respawn" - - if (config && config.allow_vote_mode) - features += "vote" - - if (config && config.allow_ai) - features += "AI allowed" - - var/n = 0 - for (var/mob/M in GLOB.player_list) - if (M.client) - n++ - - if (n > 1) - features += "~[n] players" - else if (n > 0) - features += "~[n] player" - - if (!host && config && config.hostedby) - features += "hosted by [config.hostedby]" - - if (features) - s += ": [jointext(features, ", ")]" - - status = s - -/world/proc/update_hub_visibility(new_visibility) - if(new_visibility == GLOB.hub_visibility) - return - GLOB.hub_visibility = new_visibility - if(GLOB.hub_visibility) - hub_password = "kMZy3U5jJHSiBQjr" - else - hub_password = "SORRYNOPASSWORD" diff --git a/code/world.dm.rej b/code/world.dm.rej new file mode 100644 index 0000000000..e82c17e503 --- /dev/null +++ b/code/world.dm.rej @@ -0,0 +1,301 @@ +diff a/code/world.dm b/code/world.dm (rejected hunks) +@@ -10,299 +13,3 @@ + #ifdef GC_FAILURE_HARD_LOOKUP + loop_checks = FALSE + #endif +- +-/world/New() +- log_world("World loaded at [time_stamp()]") +- +- SetupExternalRSC() +- +- GLOB.config_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = file("data/logs/config_error.log") //temporary file used to record errors with loading config, moved to log directory once logging is set bl +- +- make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) +- +- config = new +- +- CheckSchemaVersion() +- SetRoundID() +- +- SetupLogs() +- +- if(!RunningService()) //tgs2 support +- GLOB.revdata.DownloadPRDetails() +- +- load_motd() +- load_admins() +- LoadVerbs(/datum/verbs/menu) +- if(config.usewhitelist) +- load_whitelist() +- LoadBans() +- +- GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000 +- +- Master.Initialize(10, FALSE) +- +- if(config.irc_announce_new_game) +- IRCBroadcast("New round starting on [SSmapping.config.map_name]!") +- +-/world/proc/SetupExternalRSC() +-#if (PRELOAD_RSC == 0) +- external_rsc_urls = world.file2list("config/external_rsc_urls.txt","\n") +- var/i=1 +- while(i<=external_rsc_urls.len) +- if(external_rsc_urls[i]) +- i++ +- else +- external_rsc_urls.Cut(i,i+1) +-#endif +- +-/world/proc/CheckSchemaVersion() +- if(config.sql_enabled) +- if(SSdbcore.Connect()) +- log_world("Database connection established.") +- var/datum/DBQuery/query_db_version = SSdbcore.NewQuery("SELECT major, minor FROM [format_table_name("schema_revision")] ORDER BY date DESC LIMIT 1") +- query_db_version.Execute() +- if(query_db_version.NextRow()) +- var/db_major = text2num(query_db_version.item[1]) +- var/db_minor = text2num(query_db_version.item[2]) +- if(db_major < DB_MAJOR_VERSION || db_minor < DB_MINOR_VERSION) +- message_admins("Database schema ([db_major].[db_minor]) is behind latest schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors") +- log_sql("Database schema ([db_major].[db_minor]) is behind latest schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors") +- else +- message_admins("Could not get schema version from database") +- else +- log_world("Your server failed to establish a connection with the database.") +- +-/world/proc/SetRoundID() +- if(config.sql_enabled) +- if(SSdbcore.Connect()) +- var/datum/DBQuery/query_round_start = SSdbcore.NewQuery("INSERT INTO [format_table_name("round")] (start_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')") +- query_round_start.Execute() +- var/datum/DBQuery/query_round_last_id = SSdbcore.NewQuery("SELECT LAST_INSERT_ID()") +- query_round_last_id.Execute() +- if(query_round_last_id.NextRow()) +- GLOB.round_id = query_round_last_id.item[1] +- +-/world/proc/SetupLogs() +- GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-" +- if(GLOB.round_id) +- GLOB.log_directory += "[GLOB.round_id]" +- else +- GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]" +- GLOB.world_game_log = file("[GLOB.log_directory]/game.log") +- GLOB.world_attack_log = file("[GLOB.log_directory]/attack.log") +- GLOB.world_runtime_log = file("[GLOB.log_directory]/runtime.log") +- GLOB.world_href_log = file("[GLOB.log_directory]/hrefs.html") +- GLOB.world_game_log << "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------" +- GLOB.world_attack_log << "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------" +- GLOB.world_runtime_log << "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------" +- GLOB.changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently +- if(fexists(GLOB.config_error_log)) +- fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log") +- fdel(GLOB.config_error_log) +- +- if(GLOB.round_id) +- log_game("Round ID: [GLOB.round_id]") +- +-/world/Topic(T, addr, master, key) +- var/list/input = params2list(T) +- +- var/pinging = ("ping" in input) +- var/playing = ("players" in input) +- +- if(!pinging && !playing && config && config.log_world_topic) +- GLOB.world_game_log << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]" +- +- if(input[SERVICE_CMD_PARAM_KEY]) +- return ServiceCommand(input) +- var/key_valid = (global.comms_allowed && input["key"] == global.comms_key) +- +- if(pinging) +- var/x = 1 +- for (var/client/C in GLOB.clients) +- x++ +- return x +- +- else if(playing) +- var/n = 0 +- for(var/mob/M in GLOB.player_list) +- if(M.client) +- n++ +- return n +- +- else if("ircstatus" in input) //tgs2 support +- var/static/last_irc_status = 0 +- if(world.time - last_irc_status < 50) +- return +- var/list/adm = get_admin_counts() +- var/list/allmins = adm["total"] +- var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). " +- status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode.name]." +- send2irc("Status", status) +- last_irc_status = world.time +- +- else if("status" in input) +- var/list/s = list() +- s["version"] = GLOB.game_version +- s["mode"] = GLOB.master_mode +- s["respawn"] = config ? GLOB.abandon_allowed : 0 +- s["enter"] = GLOB.enter_allowed +- s["vote"] = config.allow_vote_mode +- s["ai"] = config.allow_ai +- s["host"] = host ? host : null +- s["active_players"] = get_active_player_count() +- s["players"] = GLOB.clients.len +- s["revision"] = GLOB.revdata.commit +- s["revision_date"] = GLOB.revdata.date +- +- var/list/adm = get_admin_counts() +- var/list/presentmins = adm["present"] +- var/list/afkmins = adm["afk"] +- s["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho +- s["gamestate"] = SSticker.current_state +- +- s["map_name"] = SSmapping.config.map_name +- +- if(key_valid && SSticker.HasRoundStarted()) +- s["real_mode"] = SSticker.mode.name +- // Key-authed callers may know the truth behind the "secret" +- +- s["security_level"] = get_security_level() +- s["round_duration"] = SSticker ? round((world.time-SSticker.round_start_time)/10) : 0 +- // Amount of world's ticks in seconds, useful for calculating round duration +- +- if(SSshuttle && SSshuttle.emergency) +- s["shuttle_mode"] = SSshuttle.emergency.mode +- // Shuttle status, see /__DEFINES/stat.dm +- s["shuttle_timer"] = SSshuttle.emergency.timeLeft() +- // Shuttle timer, in seconds +- +- return list2params(s) +- +- else if("announce" in input) +- if(!key_valid) +- return "Bad Key" +- else +- AnnouncePR(input["announce"], json_decode(input["payload"])) +- +- else if("crossmessage" in input) +- if(!key_valid) +- return +- else +- if(input["crossmessage"] == "Ahelp") +- relay_msg_admins("HELP: [input["source"]] [input["message_sender"]]: [input["message"]]") +- if(input["crossmessage"] == "Comms_Console") +- minor_announce(input["message"], "Incoming message from [input["message_sender"]]") +- for(var/obj/machinery/computer/communications/CM in GLOB.machines) +- CM.overrideCooldown() +- if(input["crossmessage"] == "News_Report") +- minor_announce(input["message"], "Breaking Update From [input["message_sender"]]") +- +- else if("adminmsg" in input) //tgs2 support +- if(!key_valid) +- return "Bad Key" +- else +- return IrcPm(input["adminmsg"],input["msg"],input["sender"]) +- +- else if("namecheck" in input) //tgs2 support +- if(!key_valid) +- return "Bad Key" +- else +- log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]") +- message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]") +- return keywords_lookup(input["namecheck"],1) +- else if("adminwho" in input) //tgs2 support +- if(!key_valid) +- return "Bad Key" +- else +- return ircadminwho() +- else if("server_hop" in input) +- show_server_hop_transfer_screen(input["server_hop"]) +- +-#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round +- //This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored +- +-/world/proc/AnnouncePR(announcement, list/payload) +- var/static/list/PRcounts = list() //PR id -> number of times announced this round +- var/id = "[payload["pull_request"]["id"]]" +- if(!PRcounts[id]) +- PRcounts[id] = 1 +- else +- ++PRcounts[id] +- if(PRcounts[id] > PR_ANNOUNCEMENTS_PER_ROUND) +- return +- +- var/final_composed = "PR: [announcement]" +- for(var/client/C in GLOB.clients) +- C.AnnouncePR(final_composed) +- +-/world/Reboot(reason = 0, fast_track = FALSE) +- ServiceReboot() //handles alternative actions if necessary +- if (reason || fast_track) //special reboot, do none of the normal stuff +- if (usr) +- log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools") +- message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools") +- to_chat(world, "Rebooting World immediately due to host request") +- else +- to_chat(world, "Rebooting world...") +- Master.Shutdown() //run SS shutdowns +- log_world("World rebooted at [time_stamp()]") +- ..() +- +-/world/proc/load_motd() +- GLOB.join_motd = file2text("config/motd.txt") + "
" + GLOB.revdata.GetTestMergeInfo() +- +-/world/proc/update_status() +- var/s = "" +- +- if (config && config.server_name) +- s += "[config.server_name] — " +- +- s += "[station_name()]"; +- s += " (" +- s += "" //Change this to wherever you want the hub to link to. +- s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version. +- s += "" +- s += ")" +- +- var/list/features = list() +- +- if(GLOB.master_mode) +- features += GLOB.master_mode +- +- if (!GLOB.enter_allowed) +- features += "closed" +- +- features += GLOB.abandon_allowed ? "respawn" : "no respawn" +- +- if (config && config.allow_vote_mode) +- features += "vote" +- +- if (config && config.allow_ai) +- features += "AI allowed" +- +- var/n = 0 +- for (var/mob/M in GLOB.player_list) +- if (M.client) +- n++ +- +- if (n > 1) +- features += "~[n] players" +- else if (n > 0) +- features += "~[n] player" +- +- if (!host && config && config.hostedby) +- features += "hosted by [config.hostedby]" +- +- if (features) +- s += ": [jointext(features, ", ")]" +- +- status = s +- +-/world/proc/update_hub_visibility(new_visibility) +- if(new_visibility == GLOB.hub_visibility) +- return +- GLOB.hub_visibility = new_visibility +- if(GLOB.hub_visibility) +- hub_password = "kMZy3U5jJHSiBQjr" +- else +- hub_password = "SORRYNOPASSWORD" diff --git a/html/changelogs/AutoChangeLog-pr-2231.yml b/html/changelogs/AutoChangeLog-pr-2231.yml new file mode 100644 index 0000000000..c25b4b2b49 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2231.yml @@ -0,0 +1,4 @@ +author: "Xhuis" +delete-after: True +changes: + - tweak: "Spell action buttons now have their description in a tooltip." diff --git a/html/changelogs/AutoChangeLog-pr-2278.yml b/html/changelogs/AutoChangeLog-pr-2278.yml new file mode 100644 index 0000000000..111ae24812 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2278.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - bugfix: "Fixed hair sticking through headgear." diff --git a/html/changelogs/AutoChangeLog-pr-2295.yml b/html/changelogs/AutoChangeLog-pr-2295.yml new file mode 100644 index 0000000000..c34d19ac6f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2295.yml @@ -0,0 +1,4 @@ +author: "More Robust Than You" +delete-after: True +changes: + - tweak: "Mulligan and non-continuous completion checks will not consider afk/logged out people to be \"living crew\"." diff --git a/html/changelogs/AutoChangeLog-pr-2320.yml b/html/changelogs/AutoChangeLog-pr-2320.yml new file mode 100644 index 0000000000..695f23e7de --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2320.yml @@ -0,0 +1,4 @@ +author: "LetterJay" +delete-after: True +changes: + - tweak: "Adds the option for bear ears and tails for humans as well." diff --git a/html/changelogs/AutoChangeLog-pr-2329.yml b/html/changelogs/AutoChangeLog-pr-2329.yml new file mode 100644 index 0000000000..2950b70fbb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2329.yml @@ -0,0 +1,6 @@ +author: "ktccd" +delete-after: True +changes: + - rscadd: "Adds flared, knotted or tapered dicks for Taur bodies." + - tweak: "Resized the cow-taur's over-extended belly to match the profile picture, no longer completely blocking the taur penises." + - bugfix: "Barbed, knotted penises and other such long-named cocks are now visible on the ground if dismembered." diff --git a/html/changelogs/AutoChangeLog-pr-2335.yml b/html/changelogs/AutoChangeLog-pr-2335.yml new file mode 100644 index 0000000000..5681e3d5f9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2335.yml @@ -0,0 +1,4 @@ +author: "ktccd" +delete-after: True +changes: + - bugfix: "Flavortext is now in the DNA of mobs who has that, meaning changelings, cloners and such things use it properly." diff --git a/html/changelogs/AutoChangeLog-pr-2339.yml b/html/changelogs/AutoChangeLog-pr-2339.yml new file mode 100644 index 0000000000..c7f3d42698 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2339.yml @@ -0,0 +1,4 @@ +author: "More Robust Than You" +delete-after: True +changes: + - tweak: "His Grace now shows up on the orbit list" diff --git a/html/changelogs/AutoChangeLog-pr-2346.yml b/html/changelogs/AutoChangeLog-pr-2346.yml new file mode 100644 index 0000000000..c42300a173 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2346.yml @@ -0,0 +1,4 @@ +author: "More Robust Than You" +delete-after: True +changes: + - tweak: "The wiki button now asks what page you want to be taken to" diff --git a/html/changelogs/AutoChangeLog-pr-2350.yml b/html/changelogs/AutoChangeLog-pr-2350.yml new file mode 100644 index 0000000000..07e0f51b62 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2350.yml @@ -0,0 +1,4 @@ +author: "Xhuis" +delete-after: True +changes: + - bugfix: "Minebots no longer lack icons for their action buttons." diff --git a/html/changelogs/AutoChangeLog-pr-2356.yml b/html/changelogs/AutoChangeLog-pr-2356.yml new file mode 100644 index 0000000000..218da24865 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2356.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - imageadd: "Adds icon_states to the unused and used Eldritch whetstones. Sprites by Fury McFlurry." diff --git a/html/changelogs/AutoChangeLog-pr-2357.yml b/html/changelogs/AutoChangeLog-pr-2357.yml new file mode 100644 index 0000000000..f63277f66f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2357.yml @@ -0,0 +1,8 @@ +author: "ktccd" +delete-after: True +changes: + - rscadd: "Breasts can now be used to masturbate/milk yourselves." + - rscadd: "You can now expose genitals through clothing using a verb in the IC tab." + - tweak: "Pressing the Arousal HUD symbol will now bring up several options to use. Pull or be pulled by someone who's exposed to have them appear as an option." + - tweak: "Made hexacamphor/hexacrocin less verbose and trigger forced climaxes less often to avoid incredible spam." + - tweak: "Being forced to orgasm while pulled or pulling someone now counts them as your selected partner." diff --git a/html/changelogs/AutoChangeLog-pr-2359.yml b/html/changelogs/AutoChangeLog-pr-2359.yml new file mode 100644 index 0000000000..8455963dc6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2359.yml @@ -0,0 +1,4 @@ +author: "Joan" +delete-after: True +changes: + - imageadd: "Ported CEV-Eris's APC sprites." diff --git a/html/changelogs/AutoChangeLog-pr-2362.yml b/html/changelogs/AutoChangeLog-pr-2362.yml new file mode 100644 index 0000000000..5bdc603b06 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2362.yml @@ -0,0 +1,4 @@ +author: "More Robust Than You" +delete-after: True +changes: + - bugfix: "Fixes a typo in the blobbernaut spawn text" diff --git a/html/changelogs/AutoChangeLog-pr-2363.yml b/html/changelogs/AutoChangeLog-pr-2363.yml new file mode 100644 index 0000000000..e8f5b574ae --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2363.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - tweak: "Canisters don't flash red lights anymore when empty." diff --git a/html/changelogs/AutoChangeLog-pr-2371.yml b/html/changelogs/AutoChangeLog-pr-2371.yml new file mode 100644 index 0000000000..ec1810b8a6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2371.yml @@ -0,0 +1,4 @@ +author: "Xhuis" +delete-after: True +changes: + - bugfix: "The Resurrect Cultist rune now works as intended." diff --git a/html/changelogs/AutoChangeLog-pr-2376.yml b/html/changelogs/AutoChangeLog-pr-2376.yml new file mode 100644 index 0000000000..1d1a2007b5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2376.yml @@ -0,0 +1,4 @@ +author: "ShizCalev" +delete-after: True +changes: + - bugfix: "The Singularity, Tesla energy ball, tears in the fabric of reality, and Narsie will no longer be frozen by freon." diff --git a/html/changelogs/AutoChangeLog-pr-2377.yml b/html/changelogs/AutoChangeLog-pr-2377.yml new file mode 100644 index 0000000000..4996a03563 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2377.yml @@ -0,0 +1,4 @@ +author: "More Robust Than You" +delete-after: True +changes: + - bugfix: "Fixes mining hardsuit heat_protection" diff --git a/html/changelogs/AutoChangeLog-pr-2399.yml b/html/changelogs/AutoChangeLog-pr-2399.yml new file mode 100644 index 0000000000..2d162a5edf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2399.yml @@ -0,0 +1,4 @@ +author: "More Robust Than You" +delete-after: True +changes: + - rscadd: "Blobs can now sense when they're being cuddled!" diff --git a/html/changelogs/AutoChangeLog-pr-2402.yml b/html/changelogs/AutoChangeLog-pr-2402.yml new file mode 100644 index 0000000000..0ef97907fd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2402.yml @@ -0,0 +1,5 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - imageadd: "Nanotrasen redesigned the area power controllers!" + - imageadd: "Thanks Xhuis for the contrast tweak on APCs" diff --git a/html/changelogs/AutoChangeLog-pr-2408.yml b/html/changelogs/AutoChangeLog-pr-2408.yml new file mode 100644 index 0000000000..92f33a9292 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2408.yml @@ -0,0 +1,4 @@ +author: "Xhuis" +delete-after: True +changes: + - soundadd: "The station's explosion now uses a new (or old) sound." diff --git a/html/changelogs/AutoChangeLog-pr-2437.yml b/html/changelogs/AutoChangeLog-pr-2437.yml new file mode 100644 index 0000000000..1a54eed45e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2437.yml @@ -0,0 +1,5 @@ +author: "BeeSting12" +delete-after: True +changes: + - bugfix: "Deltastation's N2O console has been renamed to be an N2O console." + - tweak: "Deltastation's atmos now has a fire axe." diff --git a/html/changelogs/AutoChangeLog-pr-2438.yml b/html/changelogs/AutoChangeLog-pr-2438.yml new file mode 100644 index 0000000000..9195a11183 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2438.yml @@ -0,0 +1,4 @@ +author: "XDTM" +delete-after: True +changes: + - bugfix: "Viruses will now be able to affect more than one person at a time." diff --git a/html/changelogs/AutoChangeLog-pr-2439.yml b/html/changelogs/AutoChangeLog-pr-2439.yml new file mode 100644 index 0000000000..c92b5e2235 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2439.yml @@ -0,0 +1,4 @@ +author: "ShizCalev" +delete-after: True +changes: + - tweak: "The singularity will now dig up asteroids when in proximity of them. Please watch for flying debris." diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi index 3ed8c153d8..42226c7d2b 100644 Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ diff --git a/icons/mob/hair_extensions.dmi b/icons/mob/hair_extensions.dmi index bd2adda94b..5a4ee36157 100644 Binary files a/icons/mob/hair_extensions.dmi and b/icons/mob/hair_extensions.dmi differ diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi index 968e12949b..a06f490fa7 100644 Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ diff --git a/icons/mob/inhands/equipment/custodial_lefthand.dmi b/icons/mob/inhands/equipment/custodial_lefthand.dmi index 80c77cf8df..b099ee1524 100644 Binary files a/icons/mob/inhands/equipment/custodial_lefthand.dmi and b/icons/mob/inhands/equipment/custodial_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/custodial_righthand.dmi b/icons/mob/inhands/equipment/custodial_righthand.dmi index fb64834ce9..8e0174150a 100644 Binary files a/icons/mob/inhands/equipment/custodial_righthand.dmi and b/icons/mob/inhands/equipment/custodial_righthand.dmi differ diff --git a/icons/mob/mam_body_markings.dmi b/icons/mob/mam_body_markings.dmi index a50181340d..fdb97490c8 100644 Binary files a/icons/mob/mam_body_markings.dmi and b/icons/mob/mam_body_markings.dmi differ diff --git a/icons/mob/mam_bodyparts.dmi b/icons/mob/mam_bodyparts.dmi index c9f1ba70e8..7de9b40734 100644 Binary files a/icons/mob/mam_bodyparts.dmi and b/icons/mob/mam_bodyparts.dmi differ diff --git a/icons/mob/mam_taur.dmi b/icons/mob/mam_taur.dmi index c0d62597ff..8cce485c7a 100644 Binary files a/icons/mob/mam_taur.dmi and b/icons/mob/mam_taur.dmi differ diff --git a/icons/mob/xeno_parts_greyscale.dmi b/icons/mob/xeno_parts_greyscale.dmi new file mode 100644 index 0000000000..44456309a7 Binary files /dev/null and b/icons/mob/xeno_parts_greyscale.dmi differ diff --git a/icons/obj/kitchen.dmi b/icons/obj/kitchen.dmi index a8f7708c46..87b2b46a2b 100644 Binary files a/icons/obj/kitchen.dmi and b/icons/obj/kitchen.dmi differ diff --git a/icons/obj/machines/telecomms.dmi b/icons/obj/machines/telecomms.dmi index 7f5f05e3af..4a6988f88e 100644 Binary files a/icons/obj/machines/telecomms.dmi and b/icons/obj/machines/telecomms.dmi differ diff --git a/icons/obj/power.dmi b/icons/obj/power.dmi index f3b2233283..e1604715ac 100644 Binary files a/icons/obj/power.dmi and b/icons/obj/power.dmi differ diff --git a/icons/obj/wallframe.dmi b/icons/obj/wallframe.dmi index 0e416cac77..70149901e3 100644 Binary files a/icons/obj/wallframe.dmi and b/icons/obj/wallframe.dmi differ diff --git a/interface/interface.dm b/interface/interface.dm index 253738064b..9ee5309585 100644 --- a/interface/interface.dm +++ b/interface/interface.dm @@ -1,12 +1,14 @@ //Please use mob or src (not usr) in these procs. This way they can be called in the same fashion as procs. -/client/verb/wiki() +/client/verb/wiki(query as text) set name = "wiki" - set desc = "Visit the wiki." + set desc = "Type what you want to know about. This will open the wiki in your web browser. Type nothing to go to the main page." set hidden = 1 if(config.wikiurl) - if(alert("This will open the wiki in your browser. Are you sure?",,"Yes","No")=="No") - return - src << link(config.wikiurl) + if(query) + var/output = config.wikiurl + "/index.php?title=Special%3ASearch&profile=default&search=" + query + src << link(output) + else if (query != null) + src << link(config.wikiurl) else to_chat(src, "The wiki URL is not set in the server configuration.") return diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index 6f38560b92..7ad30fb7b5 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -151,7 +151,7 @@ h1.alert, h2.alert {color: #000000;} .clown {color: #FF69Bf; font-size: 3; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} .his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} -BIG IMG.icon {width: 32px; height: 32px;} +.icon {height: 1em; width: auto;} .memo {color: #638500; text-align: center;} .memoedit {text-align: center; font-size: 2;} @@ -161,4 +161,6 @@ BIG IMG.icon {width: 32px; height: 32px;} .monkey {color: #975032;} .swarmer {color: #2C75FF;} .resonate {color: #298F85;} +.love {color: #FF69Bf;} +.lovebold {color: #FF69Bf; font-weight: bold;} "} diff --git a/power.dmi b/power.dmi new file mode 100644 index 0000000000..d0066b96de Binary files /dev/null and b/power.dmi differ diff --git a/sound/effects/explosion_distant.ogg b/sound/effects/explosion_distant.ogg new file mode 100644 index 0000000000..d9976c51fe Binary files /dev/null and b/sound/effects/explosion_distant.ogg differ diff --git a/strings/brain_damage_lines.json b/strings/brain_damage_lines.json index ce3e726dbc..af040d5ba0 100644 --- a/strings/brain_damage_lines.json +++ b/strings/brain_damage_lines.json @@ -1,17 +1,17 @@ { "brain_damage": [ - "IM A PONY NEEEEEEIIIIIIIIIGH", + "@pick(semicolon)IM A PONY NEEEEEEIIIIIIIIIGH", "without oxigen blob don't evoluate?", - "CAPTAINS A COMDOM", - "@pick(faggot_traitor) @pick(george) @pick(mellens) is grifing me HALP!!!", + "@pick(semicolon)CAPTAINS A COMDOM", + "@pick(semicolon)@pick(faggot_traitor) @pick(george) @pick(mellens) is grifing me HALP!!!", "can u give me @pick(mutations)?", "THe saiyans screwed", "Bi is THE BEST OF BOTH WORLDS>", - "I WANNA PET TEH monkeyS", + "@pick(semicolon)I WANNA PET TEH monkeyS", "stop grifing me!!!!", "SOTP IT#", "shiggey diggey!!", - "A PIRATE APPEAR", + "@pick(semicolon)A PIRATE APPEAR", "FUS RO DAH", "fucking 4rries!", "stat me", @@ -136,7 +136,8 @@ "random_gibberish": [ "g", "squid", - "r" + "r", + "carbon dioxide" ], "y_replacements": [ @@ -171,6 +172,19 @@ "abdoocters" ], + "bug": [ + "", + "IS TIS A BUG??", + "SI IST A BUGG/", + "BUG!!!" + ], + + "semicolon": [ + "", + ";", + ".h" + ], + "roles": [ "heds", "ceptin", diff --git a/strings/brain_damage_lines.json.rej b/strings/brain_damage_lines.json.rej new file mode 100644 index 0000000000..6d8e1cdb62 --- /dev/null +++ b/strings/brain_damage_lines.json.rej @@ -0,0 +1,10 @@ +diff a/strings/brain_damage_lines.json b/strings/brain_damage_lines.json (rejected hunks) +@@ -131,7 +131,7 @@ + "", + "IS TIS A BUG??", + "SI IST A BUGG/", +- "BUG!!!" ++ "BUG!!!" + ], + + "semicolon": [ diff --git a/strings/hallucination.json b/strings/hallucination.json new file mode 100644 index 0000000000..b28c70db4a --- /dev/null +++ b/strings/hallucination.json @@ -0,0 +1,229 @@ +{ + "suspicion": [ + "I'm watching you...", + "I know what you're doing", + "What are you hiding?", + "I saw that" + ], + + "greetings": [ + "", + "Hey, ", + "Hi ", + "Hello ", + "Wait, ", + "It's " + ], + + "getout": [ + "Get out", + "Get out!", + "Go away", + "Fuck off", + "OUT!", + "Out!" + ], + + "weird": [ + "Kchck-Chkck? Kchchck!", + "Kchckchk...", + "EEEeeeeEEEE", + "khhhhh", + "#@§*&£", + "H**p m*", + "H-hhhhh..." + ], + + "didyouhearthat": [ + "Did you hear that?", + "Did you see that?", + "What was that?" + ], + + "imatraitor": [ + "Hail Ratvar", + "Hail Nar'Sie", + "Hey, i've got some TC left, want something?", + "Viva!", + "I'll spare you if you don't tell anybody about me", + "Hey, are you a traitor too?", + "You're my target, but @pick(excuses)", + "Are you mr. @pick(ling_names)?" + ], + + "excuses": [ + "i like you, so i'll spare you", + "i don't really feel like following objectives today", + "i'm not robust enough to fight you", + "who cares", + "i'll kill you later" + ] + + "ling_names": [ + "Alpha", + "Beta", + "Gamma", + "Delta", + "Epsilon", + "Eta", + "Theta", + "Lambda", + "Mu", + "Xi", + "Rho", + "Sigma", + "Tau", + "Upsilon", + "Phi", + "Psi", + "Omega" + ] + + "doubt": [ + "Why?", + "What?", + "Wait, what?", + "Wait", + "Hold on", + "Uh..." + ], + + "aggressive": [ + "Give me that!", + "I'm going to kill you!", + "Fuck you!" + ], + + "help": [ + "HELP", + "HELP ME", + "HELP HIM", + "HELP HER", + "HELP THEM", + "HELP US", + "HELP YOURSELF" + ], + + "escape": [ + "RUN!!", + "They're behind me!", + "It's here!", + "Follow me!", + "Follow me" + ] + + "infection_advice": [ + "stay away", + "don't get close", + "be careful", + "help me", + "kill me" + ] + + "people": [ + "Captain", + "Hos", + "Cmo", + "Rd", + "Ce", + "Hop", + "Janitor", + "AI", + "Viro", + "Qm", + "[target.first_name()]" + ] + + "accusations": [ + "rogue", + "cult", + "a cultist", + "clockcult", + "a clock cultist", + "a revhead", + "a rev", + "a gang leader", + "a gangster", + "a traitor", + "a tator", + "a ling", + "a changeling" + ] + + "threat": [ + "Cult", + "Wizard", + "Blob", + "Ling", + "Ops", + "Swarmers", + "Revenant", + "Traitor", + "Harm", + "I hear flashing", + "Help" + ] + + "location": [ + "bridge", + "armory", + "sec", + "security", + "science", + "engineering", + "cargo", + "medbay", + "atmos", + "maint", + "hops office", + "captains office", + "chapel", + "library", + "tool storage", + "botany", + "kitchen", + "the ai sat" + ] + + "advice": [ + "Hmm...not sure about that.", + "Yes. You're doing the right thing.", + "No. Stop what you're doing.", + "You should be wary of that person.", + "Trust that person.", + "That person wants to kill you.", + "Kill that person. You know who.", + "You should go somewhere else. Quickly.", + "Good luck. You'll need it.", + "You have my permission. Do it." + ] + + "chemicals": [ + "Ooze", + "Fire", + "Earth", + "Lightning", + "Air", + "Magic", + "Spiders", + "Button", + "Surprise", + "Happiness", + "Despair", + "Blood", + "Awesome", + "Infinity", + "Electronics", + "Time", + "Space", + "Pain", + "Guts", + "Life", + "Death", + "Phlebotinium", + "Mana", + "Energy", + "?????" + ] + +} diff --git a/tgstation.dme b/tgstation.dme index fc5f811cef..c51dc6e899 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -375,6 +375,7 @@ #include "code\game\shuttle_engines.dm" #include "code\game\skincmd.dm" #include "code\game\sound.dm" +#include "code\game\world.dm" #include "code\game\area\ai_monitored.dm" #include "code\game\area\areas.dm" #include "code\game\area\Space_Station_13_areas.dm" diff --git a/tools/ColonCatcher/2015-10-25-colon_operator_log.txt b/tools/ColonCatcher/2015-10-25-colon_operator_log.txt deleted file mode 100644 index f8908a0fda..0000000000 --- a/tools/ColonCatcher/2015-10-25-colon_operator_log.txt +++ /dev/null @@ -1,434 +0,0 @@ -..code\world.dm Lines: 27, 28, 98?, 102?, 119?, 149?, 230? Total Colons: 7 -..code\ATMOSPHERICS\atmospherics.dm Lines: 213? Total Colons: 1 -..code\ATMOSPHERICS\components\binary_devices\dp_vent_pump.dm Lines: 137? Total Colons: 1 -..code\ATMOSPHERICS\components\binary_devices\passive_gate.dm Lines: 134?, 163? Total Colons: 2 -..code\ATMOSPHERICS\components\binary_devices\pump.dm Lines: 43?, 139?, 167? Total Colons: 3 -..code\ATMOSPHERICS\components\binary_devices\valve.dm Lines: 25?, 33?, 38? Total Colons: 3 -..code\ATMOSPHERICS\components\binary_devices\volume_pump.dm Lines: 42?, 136?, 163? Total Colons: 3 -..code\ATMOSPHERICS\components\trinary_devices\filter.dm Lines: 66?, 69?, 214? Total Colons: 3 -..code\ATMOSPHERICS\components\trinary_devices\mixer.dm Lines: 36?, 39?, 151? Total Colons: 3 -..code\ATMOSPHERICS\components\unary_devices\cryo.dm Lines: 152?, 187?, 189, 190, 312?, 313? Total Colons: 7 -..code\ATMOSPHERICS\components\unary_devices\Freezer.dm Lines: 82?, 205? Total Colons: 2 -..code\ATMOSPHERICS\components\unary_devices\vent_pump.dm Lines: 175?, 196?, 197?, 228? Total Colons: 4 -..code\ATMOSPHERICS\components\unary_devices\vent_scrubber.dm Lines: 140?, 141? Total Colons: 2 -..code\ATMOSPHERICS\pipes\manifold.dm Lines: 28? Total Colons: 1 -..code\ATMOSPHERICS\pipes\manifold4w.dm Lines: 19? Total Colons: 1 -..code\ATMOSPHERICS\pipes\pipes.dm Lines: 30?, 32?, 33?, 34?, 43? Total Colons: 5 -..code\ATMOSPHERICS\pipes\heat_exchange\manifold.dm Lines: 25?, 51? Total Colons: 2 -..code\controllers\subsystem\air.dm Lines: 100 Total Colons: 1 -..code\controllers\subsystem\bots.dm Lines: 18, 20 Total Colons: 2 -..code\controllers\subsystem\diseases.dm Lines: 18 Total Colons: 1 -..code\controllers\subsystem\events.dm Lines: 41, 199?, 200? Total Colons: 3 -..code\controllers\subsystem\jobs.dm Lines: 370? Total Colons: 1 -..code\controllers\subsystem\machines.dm Lines: 41, 42, 43 Total Colons: 3 -..code\controllers\subsystem\mobs.dm Lines: 20 Total Colons: 1 -..code\controllers\subsystem\objects.dm Lines: 37 Total Colons: 1 -..code\controllers\subsystem\shuttles.dm Lines: 251?, 253, 261?, 262?, 284, 285 Total Colons: 6 -..code\controllers\subsystem\ticker.dm Lines: 382?, 405? Total Colons: 4 -..code\controllers\subsystem\voting.dm Lines: 203?, 211? Total Colons: 2 -..code\controllers\subsystem\shuttles\emergency.dm Lines: 52?, 65? Total Colons: 4 -..code\controllers\subsystem\shuttles\supply.dm Lines: 97, 316?, 347?, 488?, 505? Total Colons: 10 -..code\datums\browser.dm Lines: 79? Total Colons: 1 -..code\datums\datacore.dm Lines: 91?, 127?, 132?, 137?, 142?, 147?, 152?, 157?, 163?, 169?, 259? Total Colons: 23 -..code\datums\datumvars.dm Lines: 57?, 93 Total Colons: 3 -..code\datums\material_container.dm Lines: 194? Total Colons: 1 -..code\datums\mind.dm Lines: 228?, 229?, 290?, 581?, 633, 634, 643, 648, 720?, 1243, 1244, 1245 Total Colons: 13 -..code\datums\mutations.dm Lines: 34?, 135?, 329? Total Colons: 3 -..code\datums\recipe.dm Lines: 52?, 114?, 115? Total Colons: 3 -..code\datums\diseases\_disease.dm Lines: 125? Total Colons: 1 -..code\datums\helper_datums\teleport.dm Lines: 63?, 64?, 74?, 75? Total Colons: 4 -..code\datums\helper_datums\topic_input.dm Lines: 23?, 27?, 31?, 35?, 42?, 46?, 50?, 56?, 60? Total Colons: 9 -..code\datums\spells\dumbfire.dm Lines: 43 Total Colons: 1 -..code\datums\spells\knock.dm Lines: 21 Total Colons: 1 -..code\datums\spells\projectile.dm Lines: 35 Total Colons: 1 -..code\datums\wires\airlock.dm Lines: 37?, 38?, 39?, 40?, 41?, 42?, 43? Total Colons: 7 -..code\datums\wires\alarm.dm Lines: 21? Total Colons: 3 -..code\datums\wires\apc.dm Lines: 13? Total Colons: 3 -..code\datums\wires\autolathe.dm Lines: 13? Total Colons: 3 -..code\datums\wires\particle_accelerator.dm Lines: 50? Total Colons: 1 -..code\datums\wires\pizza_bomb.dm Lines: 45?, 46? Total Colons: 2 -..code\datums\wires\robot.dm Lines: 16?, 17?, 18? Total Colons: 4 -..code\datums\wires\r_n_d.dm Lines: 48?, 49?, 50? Total Colons: 3 -..code\datums\wires\syndicatebomb.dm Lines: 46?, 75? Total Colons: 2 -..code\datums\wires\vending.dm Lines: 28?, 29?, 30?, 31? Total Colons: 4 -..code\datums\wires\wires.dm Lines: 119?, 121? Total Colons: 2 -..code\game\atoms.dm Lines: 297? Total Colons: 1 -..code\game\atoms_movable.dm Lines: 181?, 182?, 216? Total Colons: 3 -..code\game\communications.dm Lines: 288 Total Colons: 3 -..code\game\data_huds.dm Lines: 35? Total Colons: 1 -..code\game\dna.dm Lines: 231? Total Colons: 1 -..code\game\say.dm Lines: 45?, 49? Total Colons: 2 -..code\game\sound.dm Lines: 72? Total Colons: 1 -..code\game\gamemodes\antag_spawner.dm Lines: 103, 104 Total Colons: 3 -..code\game\gamemodes\objective.dm Lines: 84?, 112?, 139?, 172?, 201?, 433, 806 Total Colons: 7 -..code\game\gamemodes\abduction\abduction_gear.dm Lines: 159? Total Colons: 1 -..code\game\gamemodes\abduction\machinery\experiment.dm Lines: 41?, 107? Total Colons: 2 -..code\game\gamemodes\blob\blob_finish.dm Lines: 47? Total Colons: 1 -..code\game\gamemodes\blob\blob_report.dm Lines: 64, 70, 76, 85 Total Colons: 4 -..code\game\gamemodes\changeling\evolution_menu.dm Lines: 59? Total Colons: 3 -..code\game\gamemodes\changeling\powers\adrenaline.dm Lines: 12? Total Colons: 1 -..code\game\gamemodes\changeling\powers\mutations.dm Lines: 83? Total Colons: 1 -..code\game\gamemodes\cult\cult.dm Lines: 44? Total Colons: 1 -..code\game\gamemodes\cult\runes.dm Lines: 705?, 706? Total Colons: 2 -..code\game\gamemodes\gang\dominator.dm Lines: 101?, 187? Total Colons: 2 -..code\game\gamemodes\gang\gang.dm Lines: 261?, 266? Total Colons: 2 -..code\game\gamemodes\gang\gang_datum.dm Lines: 43?, 53?, 121? Total Colons: 3 -..code\game\gamemodes\gang\gang_pen.dm Lines: 59? Total Colons: 1 -..code\game\gamemodes\gang\recaller.dm Lines: 48?, 51? Total Colons: 4 -..code\game\gamemodes\malfunction\malfunction.dm Lines: 63, 64, 65, 185, 188, 189, 192, 204, 205, 216, 218, 219, 221, 233, 234 Total Colons: 15 -..code\game\gamemodes\meteor\meteors.dm Lines: 177? Total Colons: 2 -..code\game\gamemodes\nuclear\nuclearbomb.dm Lines: 197?, 212?, 215?, 217?, 220?, 222?, 265?, 359, 359?, 360, 365, 383? Total Colons: 25 -..code\game\gamemodes\revolution\revolution.dm Lines: 265?, 266?, 286? Total Colons: 3 -..code\game\gamemodes\shadowling\shadowling.dm Lines: 304? Total Colons: 1 -..code\game\gamemodes\traitor\traitor.dm Lines: 335? Total Colons: 1 -..code\game\gamemodes\wizard\artefact.dm Lines: 148? Total Colons: 1 -..code\game\gamemodes\wizard\rightandwrong.dm Lines: 9?, 10?, 11? Total Colons: 3 -..code\game\gamemodes\wizard\soulstone.dm Lines: 123, 195 Total Colons: 2 -..code\game\gamemodes\wizard\spellbook.dm Lines: 93?, 512?, 533? Total Colons: 3 -..code\game\gamemodes\wizard\wizard.dm Lines: 183?, 258, 261, 264, 278? Total Colons: 5 -..code\game\machinery\airlock_control.dm Lines: 59?, 60? Total Colons: 2 -..code\game\machinery\ai_slipper.dm Lines: 39?, 67, 77?, 93? Total Colons: 5 -..code\game\machinery\alarm.dm Lines: 134?, 135?, 730?, 742?, 895?, 934?, 1056?, 1071?, 1127?, 1128? Total Colons: 16 -..code\game\machinery\announcement_system.dm Lines: 45?, 47?, 136?, 137? Total Colons: 4 -..code\game\machinery\atmo_control.dm Lines: 273?, 284?, 396? Total Colons: 3 -..code\game\machinery\autolathe.dm Lines: 139?, 178?, 187?, 295?, 322?, 336?, 345? Total Colons: 10 -..code\game\machinery\Beacon.dm Lines: 31? Total Colons: 1 -..code\game\machinery\buttons.dm Lines: 22?, 23? Total Colons: 4 -..code\game\machinery\cell_charger.dm Lines: 15?, 31?, 64? Total Colons: 4 -..code\game\machinery\cloning.dm Lines: 88?, 92? Total Colons: 2 -..code\game\machinery\constructable_frame.dm Lines: 48?, 90?, 94?, 99?, 102?, 475? Total Colons: 8 -..code\game\machinery\deployable.dm Lines: 92 Total Colons: 1 -..code\game\machinery\dna_scanner.dm Lines: 44?, 48?, 57? Total Colons: 3 -..code\game\machinery\droneDispenser.dm Lines: 190? Total Colons: 1 -..code\game\machinery\iv_drip.dm Lines: 192?, 200?, 210? Total Colons: 3 -..code\game\machinery\lightswitch.dm Lines: 41? Total Colons: 1 -..code\game\machinery\machinery.dm Lines: 372?, 375? Total Colons: 2 -..code\game\machinery\magnet.dm Lines: 53?, 275?, 279? Total Colons: 3 -..code\game\machinery\navbeacon.dm Lines: 63?, 84?, 92?, 122?, 130? Total Colons: 6 -..code\game\machinery\newscaster.dm Lines: 205?, 206?, 291?, 304?, 311?, 318?, 319?, 372, 391?, 409?, 420?, 423, 424?, 430?, 431?, 436, 460?, 465?, 486, 614?, 724?, 727?, 922 Total Colons: 27 -..code\game\machinery\overview.dm Lines: 98, 167?, 243, 292? Total Colons: 4 -..code\game\machinery\portable_turret.dm Lines: 162?, 164?, 169?, 170?, 171?, 172?, 173?, 183?, 285?, 862?, 864?, 869?, 870?, 871?, 872?, 873?, 877?, 889?, 891?, 896?, 897?, 898?, 899?, 900?, 910?, 968?, 1049?, 1085, 1097?, 1098? Total Colons: 32 -..code\game\machinery\recharger.dm Lines: 19? Total Colons: 1 -..code\game\machinery\rechargestation.dm Lines: 122?, 124? Total Colons: 2 -..code\game\machinery\recycler.dm Lines: 43?, 44?, 45?, 84? Total Colons: 4 -..code\game\machinery\requests_console.dm Lines: 201?, 202?, 212?, 213? Total Colons: 4 -..code\game\machinery\robot_fabricator.dm Lines: 21, 23, 24, 25, 28 Total Colons: 5 -..code\game\machinery\shieldgen.dm Lines: 247?, 261?, 263?, 441? Total Colons: 4 -..code\game\machinery\Sleeper.dm Lines: 142?, 156?, 162? Total Colons: 4 -..code\game\machinery\slotmachine.dm Lines: 219?, 265?, 271? Total Colons: 3 -..code\game\machinery\spaceheater.dm Lines: 33?, 35?, 37?, 69?, 89?, 107? Total Colons: 9 -..code\game\machinery\status_display.dm Lines: 167 Total Colons: 4 -..code\game\machinery\suit_storage_unit.dm Lines: 199?, 200?, 212?, 215?, 218?, 221?, 227?, 231?, 232?, 519? Total Colons: 12 -..code\game\machinery\syndicatebeacon.dm Lines: 151? Total Colons: 1 -..code\game\machinery\syndicatebomb.dm Lines: 22?, 53?, 77?, 323?, 326? Total Colons: 6 -..code\game\machinery\teleporter.dm Lines: 69?, 442? Total Colons: 3 -..code\game\machinery\turrets.dm Lines: 542?, 578, 590?, 591? Total Colons: 6 -..code\game\machinery\vending.dm Lines: 248?, 323? Total Colons: 2 -..code\game\machinery\atmoalter\canister.dm Lines: 248, 289?, 290?, 291?, 292?, 295?, 297? Total Colons: 7 -..code\game\machinery\atmoalter\pump.dm Lines: 109? Total Colons: 3 -..code\game\machinery\atmoalter\scrubber.dm Lines: 127?, 203? Total Colons: 3 -..code\game\machinery\bots\bots.dm Lines: 244?, 337?, 338?, 340?, 416?, 481? Total Colons: 6 -..code\game\machinery\bots\cleanbot.dm Lines: 84?, 85?, 87?, 88?, 109? Total Colons: 6 -..code\game\machinery\bots\ed209bot.dm Lines: 107?, 109?, 115?, 116?, 117?, 118?, 119?, 120?, 155?, 258?, 456? Total Colons: 12 -..code\game\machinery\bots\floorbot.dm Lines: 104?, 105?, 107?, 109?, 110?, 111?, 112?, 113?, 114?, 115?, 116?, 147?, 360? Total Colons: 13 -..code\game\machinery\bots\medbot.dm Lines: 147?, 148?, 154?, 171?, 173?, 174?, 175?, 176?, 177?, 231?, 320?, 532? Total Colons: 12 -..code\game\machinery\bots\mulebot.dm Lines: 99?, 147?, 187?, 209?, 210?, 211?, 225?, 226?, 227?, 228?, 249?, 282?, 346?, 354?, 363?, 535? Total Colons: 17 -..code\game\machinery\bots\secbot.dm Lines: 97?, 99?, 104?, 105?, 106?, 107?, 108?, 109?, 142?, 222? Total Colons: 11 -..code\game\machinery\camera\camera.dm Lines: 141?, 151?, 152? Total Colons: 3 -..code\game\machinery\camera\tracking.dm Lines: 19?, 83? Total Colons: 2 -..code\game\machinery\computer\arcade.dm Lines: 860?, 862?, 863?, 871? Total Colons: 6 -..code\game\machinery\computer\camera.dm Lines: 56? Total Colons: 1 -..code\game\machinery\computer\camera_advanced.dm Lines: 154? Total Colons: 1 -..code\game\machinery\computer\card.dm Lines: 148?, 164?, 209?, 364?, 372?, 390? Total Colons: 6 -..code\game\machinery\computer\cloning.dm Lines: 146? Total Colons: 1 -..code\game\machinery\computer\communications.dm Lines: 106, 148?, 272?, 428?, 429?, 430, 453?, 468?, 531?, 532?, 533, 554? Total Colons: 12 -..code\game\machinery\computer\crew.dm Lines: 153?, 158?, 169? Total Colons: 3 -..code\game\machinery\computer\dna_console.dm Lines: 94?, 139?, 141?, 143?, 181? Total Colons: 5 -..code\game\machinery\computer\medical.dm Lines: 40?, 46, 153? Total Colons: 4 -..code\game\machinery\computer\message.dm Lines: 73?, 76?, 131?, 150? Total Colons: 4 -..code\game\machinery\computer\Operating.dm Lines: 50? Total Colons: 1 -..code\game\machinery\computer\pod.dm Lines: 56? Total Colons: 2 -..code\game\machinery\computer\robot.dm Lines: 65?, 107?, 109?, 110?, 112?, 114? Total Colons: 6 -..code\game\machinery\computer\security.dm Lines: 49?, 62, 117, 130, 275, 285 Total Colons: 7 -..code\game\machinery\computer\shuttle.dm Lines: 24, 25, 28, 30, 33, 34, 47, 48, 60 Total Colons: 9 -..code\game\machinery\computer\station_alert.dm Lines: 73? Total Colons: 1 -..code\game\machinery\doors\airlock.dm Lines: 790?, 791?, 800?, 801?, 809?, 877, 888 Total Colons: 7 -..code\game\machinery\doors\airlock_electronics.dm Lines: 81 Total Colons: 1 -..code\game\machinery\doors\brigdoors.dm Lines: 123?, 158?, 247 Total Colons: 7 -..code\game\machinery\doors\firedoor.dm Lines: 49?, 69 Total Colons: 2 -..code\game\machinery\doors\windowdoor.dm Lines: 188?, 200, 276? Total Colons: 3 -..code\game\machinery\embedded_controller\access_controller.dm Lines: 295?, 297? Total Colons: 2 -..code\game\machinery\embedded_controller\airlock_controller.dm Lines: 258?, 259?, 260?, 261? Total Colons: 4 -..code\game\machinery\pipe\construction.dm Lines: 134?, 162? Total Colons: 2 -..code\game\machinery\telecomms\machine_interactions.dm Lines: 57?, 64?, 159?, 160?, 161?, 184?, 220? Total Colons: 7 -..code\game\mecha\mecha.dm Lines: 561?, 582?, 838?, 843?, 935?, 936?, 937?, 986?, 987? Total Colons: 11 -..code\game\mecha\mecha_control_console.dm Lines: 72? Total Colons: 1 -..code\game\mecha\mecha_topic.dm Lines: 33?, 34?, 36?, 40?, 90?, 164?, 168?, 190?, 197? Total Colons: 21 -..code\game\mecha\mecha_wreckage.dm Lines: 25?, 42? Total Colons: 2 -..code\game\mecha\mech_fabricator.dm Lines: 120?, 132?, 237? Total Colons: 6 -..code\game\mecha\combat\combat.dm Lines: 65?, 67? Total Colons: 3 -..code\game\mecha\combat\durand.dm Lines: 38?, 50? Total Colons: 2 -..code\game\mecha\combat\gygax.dm Lines: 69?, 74?, 105? Total Colons: 3 -..code\game\mecha\combat\honker.dm Lines: 32?, 33?, 35? Total Colons: 14 -..code\game\mecha\combat\marauder.dm Lines: 70?, 158?, 160? Total Colons: 5 -..code\game\mecha\combat\phazon.dm Lines: 39?, 97?, 98? Total Colons: 3 -..code\game\mecha\equipment\mecha_equipment.dm Lines: 57? Total Colons: 3 -..code\game\mecha\equipment\tools\medical_tools.dm Lines: 96, 96?, 129?, 249?, 333?, 366, 370?, 371? Total Colons: 20 -..code\game\mecha\equipment\tools\mining_tools.dm Lines: 40, 51 Total Colons: 2 -..code\game\mecha\equipment\tools\other_tools.dm Lines: 132?, 160?, 182?, 222?, 328?, 406, 406?, 446? Total Colons: 10 -..code\game\mecha\equipment\tools\work_tools.dm Lines: 329?, 350?, 351?, 368, 368? Total Colons: 7 -..code\game\mecha\equipment\weapons\weapons.dm Lines: 208? Total Colons: 1 -..code\game\mecha\working\ripley.dm Lines: 53?, 55? Total Colons: 2 -..code\game\objects\explosion.dm Lines: 11?, 12?, 68? Total Colons: 5 -..code\game\objects\items.dm Lines: 213? Total Colons: 1 -..code\game\objects\items\candle.dm Lines: 23? Total Colons: 1 -..code\game\objects\items\crayons.dm Lines: 117, 171?, 172?, 173?, 210? Total Colons: 5 -..code\game\objects\items\toys.dm Lines: 133?, 187?, 234?, 452?, 471? Total Colons: 6 -..code\game\objects\items\devices\aicard.dm Lines: 83?, 85?, 129?, 138? Total Colons: 4 -..code\game\objects\items\devices\flashlight.dm Lines: 60? Total Colons: 2 -..code\game\objects\items\devices\geiger_counter.dm Lines: 93? Total Colons: 1 -..code\game\objects\items\devices\paicard.dm Lines: 40?, 41? Total Colons: 2 -..code\game\objects\items\devices\scanners.dm Lines: 123?, 137?, 139?, 141?, 143?, 147?, 149, 164?, 212?, 396? Total Colons: 11 -..code\game\objects\items\devices\taperecorder.dm Lines: 28?, 97, 117, 142 Total Colons: 4 -..code\game\objects\items\devices\transfer_valve.dm Lines: 69?, 102 Total Colons: 6 -..code\game\objects\items\devices\PDA\cart.dm Lines: 241, 245, 275, 292?, 293?, 294, 348?, 424, 435, 473?, 499?, 533?, 546?, 557?, 585, 594, 601, 605, 606, 609, 610, 611, 612, 631, 642?, 649?, 702?, 703?, 705?, 706?, 707?, 708?, 709?, 711, 712, 713, 716, 717, 718 Total Colons: 44 -..code\game\objects\items\devices\PDA\PDA.dm Lines: 298?, 299?, 330?, 356?, 358?, 360?, 364?, 378?, 382?, 383?, 388, 390, 392, 618, 619, 631, 632, 692, 693, 918, 1010?, 1036, 1039, 1131?, 1143? Total Colons: 25 -..code\game\objects\items\devices\radio\electropack.dm Lines: 129? Total Colons: 1 -..code\game\objects\items\devices\radio\radio.dm Lines: 136?, 137, 137?, 138, 138?, 139, 140, 141, 143, 144, 146, 147?, 148, 148?, 149, 150, 151, 153, 154, 155 Total Colons: 22 -..code\game\objects\items\robot\robot_parts.dm Lines: 137, 143, 150, 258?, 259?, 261?, 262?, 263?, 264? Total Colons: 11 -..code\game\objects\items\robot\robot_upgrades.dm Lines: 250? Total Colons: 1 -..code\game\objects\items\stacks\sheets\glass.dm Lines: 303? Total Colons: 1 -..code\game\objects\items\weapons\AI_modules.dm Lines: 37?, 72?, 73?, 74? Total Colons: 4 -..code\game\objects\items\weapons\cards_ids.dm Lines: 115?, 118?, 148? Total Colons: 6 -..code\game\objects\items\weapons\cigs_lighters.dm Lines: 479?, 496? Total Colons: 2 -..code\game\objects\items\weapons\cosmetics.dm Lines: 36?, 54? Total Colons: 2 -..code\game\objects\items\weapons\defib.dm Lines: 470?, 485?, 487?, 489?, 491?, 508?, 527?, 530? Total Colons: 8 -..code\game\objects\items\weapons\explosives.dm Lines: 57? Total Colons: 1 -..code\game\objects\items\weapons\extinguisher.dm Lines: 45?, 46? Total Colons: 2 -..code\game\objects\items\weapons\flamethrower.dm Lines: 90?, 128? Total Colons: 2 -..code\game\objects\items\weapons\handcuffs.dm Lines: 208? Total Colons: 1 -..code\game\objects\items\weapons\RCD.dm Lines: 500, 505 Total Colons: 4 -..code\game\objects\items\weapons\singularityhammer.dm Lines: 42 Total Colons: 1 -..code\game\objects\items\weapons\stunbaton.dm Lines: 94? Total Colons: 1 -..code\game\objects\items\weapons\grenades\chem_grenade.dm Lines: 60? Total Colons: 1 -..code\game\objects\items\weapons\grenades\grenade.dm Lines: 49? Total Colons: 1 -..code\game\objects\items\weapons\implants\implantchair.dm Lines: 46?, 47?, 49? Total Colons: 5 -..code\game\objects\items\weapons\implants\implantpad.dm Lines: 56 Total Colons: 1 -..code\game\objects\items\weapons\storage\book.dm Lines: 180 Total Colons: 1 -..code\game\objects\items\weapons\storage\fancy.dm Lines: 39? Total Colons: 1 -..code\game\objects\items\weapons\storage\secure.dm Lines: 32?, 39?, 84? Total Colons: 3 -..code\game\objects\items\weapons\storage\storage.dm Lines: 177? Total Colons: 1 -..code\game\objects\items\weapons\tanks\jetpack.dm Lines: 26?, 44?, 151? Total Colons: 3 -..code\game\objects\items\weapons\tanks\tanks.dm Lines: 121?, 122? Total Colons: 2 -..code\game\objects\items\weapons\tanks\watertank.dm Lines: 177?, 178? Total Colons: 2 -..code\game\objects\structures\ai_core.dm Lines: 212?, 213? Total Colons: 2 -..code\game\objects\structures\displaycase.dm Lines: 119?, 128?, 130? Total Colons: 3 -..code\game\objects\structures\fireaxe.dm Lines: 129? Total Colons: 1 -..code\game\objects\structures\grille.dm Lines: 148?, 149? Total Colons: 2 -..code\game\objects\structures\musician.dm Lines: 50?, 130?, 132? Total Colons: 3 -..code\game\objects\structures\safe.dm Lines: 78?, 98?, 104?, 188? Total Colons: 4 -..code\game\objects\structures\tank_dispenser.dm Lines: 43?, 44? Total Colons: 2 -..code\game\objects\structures\watercloset.dm Lines: 51?, 54? Total Colons: 3 -..code\game\objects\structures\windoor_assembly.dm Lines: 50? Total Colons: 1 -..code\game\objects\structures\window.dm Lines: 197?, 199?, 201?, 206?, 207?, 211?, 215?, 218?, 222?, 223?, 425? Total Colons: 11 -..code\game\objects\structures\beds_chairs\bed.dm Lines: 129? Total Colons: 1 -..code\game\objects\structures\crates_lockers\closets.dm Lines: 66?, 234?, 241?, 243?, 392? Total Colons: 6 -..code\game\objects\structures\transit_tubes\station.dm Lines: 130? Total Colons: 1 -..code\game\objects\structures\transit_tubes\transit_tube_construction.dm Lines: 41?, 43? Total Colons: 2 -..code\game\turfs\turf.dm Lines: 137, 248?, 250? Total Colons: 4 -..code\game\turfs\space\space.dm Lines: 114?, 125? Total Colons: 2 -..code\game\verbs\ooc.dm Lines: 44?, 53?, 55?, 57?, 69? Total Colons: 6 -..code\LINDA\LINDA_turf_tile.dm Lines: 458?, 463? Total Colons: 2 -..code\modules\admin\admin.dm Lines: 30?, 62?, 63?, 64?, 65?, 66?, 67?, 122, 129, 141, 192?, 205?, 212?, 246, 262?, 277?, 288?, 292, 293?, 300?, 301?, 306, 334?, 352, 415?, 442?, 550?, 551?, 676?, 677?, 696? Total Colons: 35 -..code\modules\admin\admin_verbs.dm Lines: 441?, 442? Total Colons: 2 -..code\modules\admin\create_poll.dm Lines: 25?, 26?, 94?, 95? Total Colons: 4 -..code\modules\admin\newbanjob.dm Lines: 216? Total Colons: 2 -..code\modules\admin\player_panel.dm Lines: 111?, 113?, 119?, 123?, 129?, 155?, 160?, 166?, 181?, 186?, 195?, 207?, 219?, 228?, 240?, 249?, 258?, 269?, 284?, 297? Total Colons: 36 -..code\modules\admin\sql_notes.dm Lines: 153 Total Colons: 2 -..code\modules\admin\topic.dm Lines: 299?, 310?, 341?, 348?, 349?, 447?, 986?, 1559?, 1561?, 1589?, 1796?, 1797?, 1798?, 1800?, 1982?, 2093?, 2096?, 2101?, 2102? Total Colons: 21 -..code\modules\admin\DB ban\functions.dm Lines: 93, 94, 95, 127?, 131?, 304, 305, 306, 441? Total Colons: 20 -..code\modules\admin\verbs\adminjump.dm Lines: 91, 127 Total Colons: 2 -..code\modules\admin\verbs\deadsay.dm Lines: 24? Total Colons: 1 -..code\modules\admin\verbs\debug.dm Lines: 82?, 86?, 89?, 112?, 116?, 289, 306, 498, 501 Total Colons: 9 -..code\modules\admin\verbs\diagnostics.dm Lines: 15?, 81 Total Colons: 5 -..code\modules\admin\verbs\massmodvar.dm Lines: 132 Total Colons: 1 -..code\modules\admin\verbs\modifyvariables.dm Lines: 542 Total Colons: 1 -..code\modules\admin\verbs\one_click_antag.dm Lines: 333?, 478?, 481?, 484?, 487?, 490?, 493?, 496?, 517? Total Colons: 9 -..code\modules\admin\verbs\panicbunker.dm Lines: 10?, 11? Total Colons: 2 -..code\modules\admin\verbs\randomverbs.dm Lines: 38?, 114?, 116?, 117?, 189?, 212?, 409?, 448?, 721?, 722?, 799, 804, 810, 816, 822, 828, 834, 840, 846, 852, 858, 864, 870, 876, 882, 888, 894, 900 Total Colons: 28 -..code\modules\assembly\bomb.dm Lines: 44 Total Colons: 1 -..code\modules\assembly\doorcontrol.dm Lines: 62? Total Colons: 1 -..code\modules\assembly\health.dm Lines: 77? Total Colons: 1 -..code\modules\assembly\infrared.dm Lines: 24?, 110? Total Colons: 3 -..code\modules\assembly\mousetrap.dm Lines: 30?, 127? Total Colons: 2 -..code\modules\assembly\proximity.dm Lines: 26?, 109?, 110? Total Colons: 3 -..code\modules\assembly\signaler.dm Lines: 142? Total Colons: 1 -..code\modules\assembly\timer.dm Lines: 75? Total Colons: 1 -..code\modules\assembly\voice.dm Lines: 32? Total Colons: 1 -..code\modules\awaymissions\maploader\reader.dm Lines: 262? Total Colons: 1 -..code\modules\awaymissions\maploader\swapmaps.dm Lines: 152, 153, 154, 161?, 162?, 163?, 343?, 356?, 362?, 385? Total Colons: 19 -..code\modules\client\client procs.dm Lines: 36, 36?, 177? Total Colons: 3 -..code\modules\client\preferences.dm Lines: 129?, 130?, 151?, 161?, 166?, 186?, 335?, 336?, 337?, 338?, 339?, 340?, 341?, 342?, 343?, 349?, 350?, 353?, 356?, 397?, 523? Total Colons: 21 -..code\modules\client\preferences_toggles.dm Lines: 7?, 16?, 25?, 34?, 43?, 54?, 64?, 74?, 83?, 92?, 113?, 122?, 172?, 226?, 235?, 259? Total Colons: 16 -..code\modules\clothing\clothing.dm Lines: 357? Total Colons: 1 -..code\modules\clothing\glasses\engine_goggles.dm Lines: 83?, 108? Total Colons: 2 -..code\modules\clothing\head\helmet.dm Lines: 240? Total Colons: 1 -..code\modules\clothing\head\soft_caps.dm Lines: 45? Total Colons: 1 -..code\modules\clothing\masks\gasmask.dm Lines: 66? Total Colons: 1 -..code\modules\clothing\masks\miscellaneous.dm Lines: 56? Total Colons: 1 -..code\modules\clothing\shoes\bananashoes.dm Lines: 59?, 65? Total Colons: 3 -..code\modules\clothing\shoes\magboots.dm Lines: 32?, 41? Total Colons: 2 -..code\modules\clothing\spacesuits\chronosuit.dm Lines: 146, 151, 152, 153, 158, 172, 175, 176, 177 Total Colons: 9 -..code\modules\crafting\table.dm Lines: 15, 59, 113, 126, 143, 167 Total Colons: 6 -..code\modules\detectivework\detective_work.dm Lines: 16? Total Colons: 1 -..code\modules\events\event.dm Lines: 37 Total Colons: 2 -..code\modules\events\shuttle_loan.dm Lines: 195, 196 Total Colons: 2 -..code\modules\flufftext\Hallucination.dm Lines: 47?, 49?, 51? Total Colons: 3 -..code\modules\food&drinks\food\customizables.dm Lines: 37? Total Colons: 1 -..code\modules\food&drinks\kitchen machinery\gibber.dm Lines: 165? Total Colons: 1 -..code\modules\food&drinks\kitchen machinery\monkeyrecycler.dm Lines: 72? Total Colons: 1 -..code\modules\food&drinks\kitchen machinery\processor.dm Lines: 198? Total Colons: 1 -..code\modules\games\cards.dm Lines: 177?, 211?, 225? Total Colons: 3 -..code\modules\holiday\easter.dm Lines: 77? Total Colons: 1 -..code\modules\html_interface\html_interface.dm Lines: 292? Total Colons: 1 -..code\modules\hydroponics\grown.dm Lines: 704 Total Colons: 1 -..code\modules\hydroponics\growninedible.dm Lines: 71, 194? Total Colons: 2 -..code\modules\hydroponics\hydroponics.dm Lines: 642?, 836? Total Colons: 2 -..code\modules\hydroponics\seeds.dm Lines: 1377?, 1378? Total Colons: 2 -..code\modules\library\lib_items.dm Lines: 186? Total Colons: 1 -..code\modules\library\lib_machines.dm Lines: 519 Total Colons: 1 -..code\modules\lighting\lighting_system.dm Lines: 254 Total Colons: 1 -..code\modules\mob\inventory.dm Lines: 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 170 Total Colons: 22 -..code\modules\mob\login.dm Lines: 6? Total Colons: 1 -..code\modules\mob\mob.dm Lines: 329?, 599?, 690, 756? Total Colons: 5 -..code\modules\mob\mob_helpers.dm Lines: 485? Total Colons: 2 -..code\modules\mob\transform_procs.dm Lines: 295 Total Colons: 1 -..code\modules\mob\dead\observer\observer.dm Lines: 285? Total Colons: 1 -..code\modules\mob\living\living.dm Lines: 181?, 359?, 402 Total Colons: 3 -..code\modules\mob\living\say.dm Lines: 116? Total Colons: 1 -..code\modules\mob\living\carbon\carbon.dm Lines: 114, 286?, 288?, 291?, 310?, 311?, 322?, 323?, 566? Total Colons: 12 -..code\modules\mob\living\carbon\life.dm Lines: 468? Total Colons: 1 -..code\modules\mob\living\carbon\alien\humanoid\emote.dm Lines: 60? Total Colons: 1 -..code\modules\mob\living\carbon\alien\humanoid\humanoid.dm Lines: 93? Total Colons: 2 -..code\modules\mob\living\carbon\alien\humanoid\caste\hunter.dm Lines: 43?, 46? Total Colons: 2 -..code\modules\mob\living\carbon\alien\larva\emote.dm Lines: 79? Total Colons: 1 -..code\modules\mob\living\carbon\brain\MMI.dm Lines: 131?, 132? Total Colons: 2 -..code\modules\mob\living\carbon\human\examine.dm Lines: 48?, 55?, 62?, 69?, 76?, 83?, 90?, 97?, 115?, 122?, 129?, 136? Total Colons: 12 -..code\modules\mob\living\carbon\human\human.dm Lines: 87?, 96?, 192?, 194?, 196?, 200?, 205?, 210?, 215?, 219?, 221?, 223?, 231?, 236?, 241?, 248?, 250?, 252?, 253?, 254?, 324?, 325?, 341?, 563?, 734? Total Colons: 26 -..code\modules\mob\living\carbon\human\human_attackalien.dm Lines: 10? Total Colons: 1 -..code\modules\mob\living\carbon\human\inventory.dm Lines: 223?, 234?, 238?, 246?, 250?, 254? Total Colons: 6 -..code\modules\mob\living\carbon\human\species.dm Lines: 115?, 117?, 126?, 329?, 673? Total Colons: 5 -..code\modules\mob\living\carbon\human\update_icons.dm Lines: 112?, 186?, 479? Total Colons: 4 -..code\modules\mob\living\carbon\human\whisper.dm Lines: 43? Total Colons: 1 -..code\modules\mob\living\carbon\monkey\emote.dm Lines: 60? Total Colons: 1 -..code\modules\mob\living\silicon\silicon.dm Lines: 129, 324? Total Colons: 2 -..code\modules\mob\living\silicon\ai\ai.dm Lines: 255?, 280?, 281?, 341?, 530?, 532?, 585?, 593? Total Colons: 9 -..code\modules\mob\living\silicon\ai\life.dm Lines: 73, 75, 78, 80, 96, 97, 121, 145, 150, 166 Total Colons: 10 -..code\modules\mob\living\silicon\ai\say.dm Lines: 15? Total Colons: 2 -..code\modules\mob\living\silicon\ai\freelook\eye.dm Lines: 106? Total Colons: 1 -..code\modules\mob\living\silicon\pai\pai.dm Lines: 161, 181 Total Colons: 2 -..code\modules\mob\living\silicon\pai\software.dm Lines: 220?, 277?, 279?, 281?, 317?, 410?, 415?, 422?, 434, 434?, 435, 436, 436?, 437, 437?, 438, 438?, 439, 439?, 440, 442, 443, 444, 445, 446, 550, 557? Total Colons: 29 -..code\modules\mob\living\silicon\robot\examine.dm Lines: 29?, 31? Total Colons: 2 -..code\modules\mob\living\silicon\robot\inventory.dm Lines: 54, 62, 70 Total Colons: 3 -..code\modules\mob\living\silicon\robot\laws.dm Lines: 47? Total Colons: 1 -..code\modules\mob\living\silicon\robot\life.dm Lines: 173, 175, 177 Total Colons: 3 -..code\modules\mob\living\silicon\robot\robot.dm Lines: 259?, 393?, 492?, 545?, 806?, 1034? Total Colons: 8 -..code\modules\mob\living\simple_animal\parrot.dm Lines: 412?, 414? Total Colons: 2 -..code\modules\mob\living\simple_animal\worm.dm Lines: 74? Total Colons: 1 -..code\modules\mob\living\simple_animal\friendly\drone\interaction.dm Lines: 103? Total Colons: 2 -..code\modules\mob\living\simple_animal\friendly\drone\verbs.dm Lines: 25? Total Colons: 1 -..code\modules\mob\living\simple_animal\friendly\drone\_drone.dm Lines: 123?, 130?, 137?, 144? Total Colons: 4 -..code\modules\mob\living\simple_animal\hostile\hostile.dm Lines: 255, 256 Total Colons: 4 -..code\modules\mob\living\simple_animal\morph\morph.dm Lines: 183? Total Colons: 1 -..code\modules\mob\living\simple_animal\slime\death.dm Lines: 15? Total Colons: 1 -..code\modules\mob\living\simple_animal\slime\life.dm Lines: 190? Total Colons: 1 -..code\modules\mob\living\simple_animal\slime\powers.dm Lines: 75? Total Colons: 1 -..code\modules\mob\living\simple_animal\slime\slime.dm Lines: 79?, 80?, 90? Total Colons: 3 -..code\modules\mob\new_player\new_player.dm Lines: 27, 29, 44?, 69?, 73? Total Colons: 5 -..code\modules\mob\new_player\poll.dm Lines: 12?, 29?, 478? Total Colons: 3 -..code\modules\nano\JSON Reader.dm Lines: 71 Total Colons: 2 -..code\modules\nano\nanoui.dm Lines: 304? Total Colons: 1 -..code\modules\ninja\admin_ninja_verbs.dm Lines: 30, 32 Total Colons: 2 -..code\modules\ninja\ninja_event.dm Lines: 141? Total Colons: 1 -..code\modules\ninja\suit\gloves.dm Lines: 80?, 87? Total Colons: 2 -..code\modules\ninja\suit\mask.dm Lines: 116?, 129?, 132?, 139? Total Colons: 4 -..code\modules\ninja\suit\ninjaDrainAct.dm Lines: 128?, 159? Total Colons: 2 -..code\modules\ninja\suit\suit.dm Lines: 75?, 79?, 116?, 172? Total Colons: 4 -..code\modules\ninja\suit\suit_attackby.dm Lines: 10?, 12?, 19? Total Colons: 3 -..code\modules\ninja\suit\suit_initialisation.dm Lines: 84 Total Colons: 1 -..code\modules\ninja\suit\n_suit_verbs\energy_net_nets.dm Lines: 64, 65, 112?, 131 Total Colons: 4 -..code\modules\ninja\suit\n_suit_verbs\ninja_stars.dm Lines: 12? Total Colons: 1 -..code\modules\paperwork\filingcabinet.dm Lines: 57? Total Colons: 1 -..code\modules\paperwork\folders.dm Lines: 43? Total Colons: 1 -..code\modules\paperwork\paper.dm Lines: 86? Total Colons: 1 -..code\modules\paperwork\paperbin.dm Lines: 97? Total Colons: 1 -..code\modules\paperwork\photocopier.dm Lines: 123?, 264?, 268? Total Colons: 5 -..code\modules\paperwork\photography.dm Lines: 66?, 67?, 79?, 183, 184, 189, 190, 217, 217?, 219, 219? Total Colons: 14 -..code\modules\power\apc.dm Lines: 128?, 129?, 133, 148, 199?, 201?, 202?, 262?, 454?, 469?, 474, 647, 647?, 664?, 671?, 715?, 838, 839, 840, 1184, 1221? Total Colons: 25 -..code\modules\power\cable.dm Lines: 108?, 293?, 564? Total Colons: 3 -..code\modules\power\generator.dm Lines: 117? Total Colons: 2 -..code\modules\power\gravitygenerator.dm Lines: 230?, 250?, 258?, 264?, 279?, 280?, 287? Total Colons: 7 -..code\modules\power\lighting.dm Lines: 261?, 440? Total Colons: 2 -..code\modules\power\port_gen.dm Lines: 89?, 273? Total Colons: 2 -..code\modules\power\smes.dm Lines: 57, 419? Total Colons: 4 -..code\modules\power\solar.dm Lines: 388?, 391? Total Colons: 2 -..code\modules\power\turbine.dm Lines: 308?, 365?, 367?, 369? Total Colons: 5 -..code\modules\power\antimatter\control.dm Lines: 267? Total Colons: 1 -..code\modules\power\antimatter\shielding.dm Lines: 119 Total Colons: 1 -..code\modules\power\singularity\collector.dm Lines: 44?, 45?, 46?, 98? Total Colons: 6 -..code\modules\power\singularity\emitter.dm Lines: 252? Total Colons: 1 -..code\modules\power\singularity\singularity.dm Lines: 117?, 236? Total Colons: 2 -..code\modules\power\singularity\particle_accelerator\particle.dm Lines: 42 Total Colons: 1 -..code\modules\power\singularity\particle_accelerator\particle_accelerator.dm Lines: 364 Total Colons: 1 -..code\modules\power\singularity\particle_accelerator\particle_control.dm Lines: 215?, 216?, 217? Total Colons: 6 -..code\modules\procedural mapping\mapGenerator.dm Lines: 153? Total Colons: 1 -..code\modules\projectiles\ammunition.dm Lines: 29?, 30?, 155? Total Colons: 3 -..code\modules\projectiles\gun.dm Lines: 108?, 110?, 310? Total Colons: 3 -..code\modules\projectiles\ammunition\magazines.dm Lines: 173? Total Colons: 1 -..code\modules\projectiles\guns\magic\wand.dm Lines: 25? Total Colons: 1 -..code\modules\projectiles\guns\projectile\automatic.dm Lines: 28?, 109?, 127?, 160?, 165?, 250? Total Colons: 11 -..code\modules\projectiles\guns\projectile\launchers.dm Lines: 49? Total Colons: 1 -..code\modules\projectiles\guns\projectile\pistol.dm Lines: 15?, 36? Total Colons: 3 -..code\modules\projectiles\guns\projectile\shotgun.dm Lines: 30?, 63?, 114?, 282? Total Colons: 4 -..code\modules\projectiles\guns\projectile\toy.dm Lines: 33? Total Colons: 1 -..code\modules\reagents\Chemistry-Machinery.dm Lines: 85?, 89, 90, 97, 330?, 350?, 367?, 368?, 512?, 551?, 665?, 705?, 708?, 788, 867?, 910?, 1248?, 1286?, 1508?, 1510?, 1511?, 1512? Total Colons: 24 -..code\modules\reagents\Chemistry-Recipes.dm Lines: 46? Total Colons: 1 -..code\modules\reagents\reagent_containers.dm Lines: 64? Total Colons: 1 -..code\modules\reagents\Chemistry-Reagents\Consumable-Reagents\Food-Reagents.dm Lines: 331 Total Colons: 2 -..code\modules\reagents\reagent_containers\spray.dm Lines: 97?, 98?, 99?, 177? Total Colons: 4 -..code\modules\recycling\disposal-construction.dm Lines: 86?, 91? Total Colons: 2 -..code\modules\recycling\disposal-structures.dm Lines: 240? Total Colons: 1 -..code\modules\recycling\disposal-unit.dm Lines: 82? Total Colons: 1 -..code\modules\recycling\sortingmachinery.dm Lines: 217? Total Colons: 1 -..code\modules\research\experimentor.dm Lines: 253? Total Colons: 1 -..code\modules\research\message_server.dm Lines: 130? Total Colons: 2 -..code\modules\shuttle\shuttle.dm Lines: 266?, 270?, 515?, 522?, 547?, 564? Total Colons: 8 -..code\modules\surgery\organs\augments_internal.dm Lines: 33?, 76?, 77?, 94? Total Colons: 4 -..code\modules\telesci\telesci_computer.dm Lines: 46?, 122?, 269? Total Colons: 4 -..code\modules\tooltip\tooltip.dm Lines: 90? Total Colons: 1 -..code\modules\vehicles\VehicleBase.dm Lines: 101?, 103?, 105?, 107? Total Colons: 4 -..code\modules\vehicles\VehicleClickInteractions.dm Lines: 128?, 157?, 186?, 214?, 252?, 254?, 257?, 259?, 262?, 264?, 267?, 269?, 272?, 274? Total Colons: 14 -..code\modules\vehicles\VehicleDefense.dm Lines: 31? Total Colons: 1 -..code\orphaned procs\dbcore.dm Lines: 79? Total Colons: 5 -..code\orphaned procs\statistics.dm Lines: 63, 64, 98, 99 Total Colons: 4 -..code\_onclick\other_mobs.dm Lines: 89 Total Colons: 1 -..code\_onclick\hud\action.dm Lines: 184? Total Colons: 1 -..code\_onclick\hud\alien.dm Lines: 90? Total Colons: 1 -..code\_onclick\hud\alien_larva.dm Lines: 16? Total Colons: 1 -..code\_onclick\hud\human.dm Lines: 59? Total Colons: 1 -..code\_onclick\hud\monkey.dm Lines: 17? Total Colons: 1 -..code\__DATASTRUCTURES\priority_queue.dm Lines: 33? Total Colons: 1 -..code\__DATASTRUCTURES\stacks.dm Lines: 29? Total Colons: 1 -..code\__HELPERS\game.dm Lines: 216? Total Colons: 1 -..code\__HELPERS\icons.dm Lines: 216?, 233?, 386?, 389?, 392?, 425?, 439?, 456?, 526?, 557?, 559?, 601?, 607?, 635?, 636?, 637?, 638?, 715, 752, 757, 762, 763, 764, 765, 774, 786, 787, 809?, 828?, 839? Total Colons: 38 -..code\__HELPERS\icon_smoothing.dm Lines: 176?, 178? Total Colons: 2 -..code\__HELPERS\lists.dm Lines: 201?, 206?, 214? Total Colons: 3 -..code\__HELPERS\maths.dm Lines: 13?, 18?, 35?, 39? Total Colons: 4 -..code\__HELPERS\mobs.dm Lines: 137?, 139?, 140? Total Colons: 11 -..code\__HELPERS\names.dm Lines: 63?, 174? Total Colons: 3 -..code\__HELPERS\sanitize_values.dm Lines: 34? Total Colons: 1 -..code\__HELPERS\text.dm Lines: 157?, 350? Total Colons: 2 -..code\__HELPERS\type2type.dm Lines: 68?, 143?, 381? Total Colons: 5 -..code\__HELPERS\unsorted.dm Lines: 41?, 573, 904, 991? Total Colons: 4 -..code\__HELPERS\sorts\__main.dm Lines: 2?, 57?, 391, 491, 585? Total Colons: 5 -433/1564 files have colons in them \ No newline at end of file diff --git a/tools/dmitool/dmitool.jar b/tools/dmitool/dmitool.jar index 4cfa49f36d..3e99778951 100644 Binary files a/tools/dmitool/dmitool.jar and b/tools/dmitool/dmitool.jar differ diff --git a/tools/dmitool/src/main/java/dmitool/IconState.java b/tools/dmitool/src/main/java/dmitool/IconState.java index 2a2202c71c..a214f5d621 100644 --- a/tools/dmitool/src/main/java/dmitool/IconState.java +++ b/tools/dmitool/src/main/java/dmitool/IconState.java @@ -189,6 +189,7 @@ public class IconState { px[i] = sl.clone(); } + int channelCount = in.imgInfo.alpha ? 4 : 3; Image[] images = new Image[frames*dirs]; for(int imageY=0; imageY LINES_LIMIT-1: break if counter+len(note) > LINE_LENGTH_LIM-2: - last_note_num = len(split_list)-1 - split_list[last_note_num] = split_list[last_note_num].rstrip(',') - split_list[last_note_num] += END_OF_LINE_CHAR + split_list[-1] = split_list[-1].rstrip(',') + split_list[-1] += END_OF_LINE_CHAR counter = 0 line_counter += 1 split_list.append(note)