diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm index f6812106ef..39ecc54ec7 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm @@ -476,7 +476,7 @@ }, /obj/item/storage/bag/plants/portaseeder, /obj/item/seeds/cotton, -/obj/item/seeds/cotton, +/obj/item/seeds/cotton/durathread, /turf/open/indestructible/boss, /area/ruin/unpowered/ash_walkers) "bk" = ( diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index a4f0e17229..86397c5751 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -23646,7 +23646,10 @@ /area/crew_quarters/bar/atrium) "aTH" = ( /obj/structure/table/wood, -/obj/item/reagent_containers/food/drinks/coffee, +/obj/item/reagent_containers/food/drinks/coffee{ + pixel_x = -4; + pixel_y = 2 + }, /obj/effect/turf_decal/tile/red{ dir = 1 }, @@ -60673,10 +60676,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/machinery/airalarm{ - dir = 1; - pixel_y = -22 - }, /obj/machinery/door/firedoor, /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -60691,10 +60690,6 @@ dir = 4 }, /obj/machinery/light, -/obj/machinery/firealarm{ - dir = 1; - pixel_y = -26 - }, /obj/effect/turf_decal/tile/neutral{ dir = 8 }, @@ -62744,43 +62739,36 @@ /turf/open/floor/plasteel/dark, /area/library) "cct" = ( -/obj/structure/table/wood, -/obj/item/flashlight/lamp, -/obj/machinery/computer/security/telescreen/entertainment{ - pixel_x = -32 +/obj/structure/table/wood/fancy, +/obj/machinery/door/window{ + name = "Secure Art Exhibition" }, -/obj/item/radio/intercom{ - name = "Station Intercom"; - pixel_y = 26 - }, -/turf/open/floor/plasteel/dark, -/area/library) -"ccu" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/obj/structure/table/wood, -/obj/item/folder, -/obj/item/pen, -/obj/machinery/newscaster{ +/obj/structure/sign/painting/library_secure{ pixel_y = 32 }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ +/turf/open/floor/carpet, +/area/library) +"ccu" = ( +/obj/structure/table/wood/fancy, +/obj/structure/window/reinforced{ dir = 4 }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 +/obj/structure/window/reinforced, +/obj/structure/sign/painting/library_secure{ + pixel_y = 32 }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/carpet, /area/library) "ccv" = ( -/obj/machinery/computer/libraryconsole, -/obj/structure/table/wood, -/turf/open/floor/plasteel/dark, +/obj/structure/extinguisher_cabinet{ + pixel_y = 32 + }, +/obj/machinery/camera{ + c_tag = "Library - Aft"; + dir = 2; + name = "library camera" + }, +/turf/open/floor/wood, /area/library) "ccw" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ @@ -63922,7 +63910,7 @@ /obj/structure/chair/office/dark{ dir = 8 }, -/obj/effect/landmark/start/librarian, +/obj/effect/landmark/start/assistant, /turf/open/floor/plasteel/dark, /area/library) "ceg" = ( @@ -63935,71 +63923,21 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 8 }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/library) -"cei" = ( -/obj/structure/chair/comfy/black{ - dir = 8 - }, -/obj/machinery/newscaster{ - pixel_x = 32 - }, -/obj/machinery/camera{ - c_tag = "Library - Fore"; - dir = 8; - name = "library camera" - }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/plasteel/grimy, /area/library) "cej" = ( -/obj/machinery/photocopier, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/library) -"cek" = ( -/obj/structure/chair/office/dark{ - dir = 1 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on, -/turf/open/floor/plasteel/dark, +/obj/effect/landmark/start/librarian, +/turf/open/floor/plasteel/grimy, /area/library) "cel" = ( -/obj/structure/table/wood, -/obj/item/paper_bin, -/obj/item/pen, -/obj/machinery/status_display/evac{ - pixel_x = 32 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ +/obj/structure/chair/sofa/right{ + icon_state = "sofaend_right"; dir = 8 }, -/turf/open/floor/plasteel/dark, +/obj/structure/sign/painting/library{ + pixel_x = 32 + }, +/turf/open/floor/wood, /area/library) "cem" = ( /obj/machinery/atmospherics/pipe/manifold/supply/hidden{ @@ -65176,34 +65114,16 @@ }, /turf/open/floor/plasteel/grimy, /area/library) -"cfY" = ( -/obj/item/kirbyplants/random, -/obj/machinery/light/small{ - dir = 4 +"cfZ" = ( +/obj/item/radio/intercom{ + name = "Station Intercom"; + pixel_x = -26 + }, +/obj/structure/sign/painting/library{ + pixel_y = -32 }, /turf/open/floor/wood, /area/library) -"cfZ" = ( -/obj/structure/sign/warning/nosmoking, -/turf/closed/wall, -/area/library) -"cga" = ( -/obj/machinery/door/morgue{ - name = "Private Study" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/library) "cgb" = ( /obj/structure/sign/plaques/kiddie/library{ pixel_x = -32 @@ -66351,61 +66271,28 @@ /obj/item/kirbyplants/random, /turf/open/floor/wood, /area/library) -"chQ" = ( -/obj/machinery/bookbinder, -/turf/open/floor/wood, -/area/library) -"chR" = ( -/obj/machinery/light{ - dir = 1 - }, -/obj/machinery/newscaster{ - pixel_y = 32 - }, -/obj/structure/bookcase/random, -/turf/open/floor/wood, -/area/library) -"chS" = ( -/obj/structure/chair/comfy/brown, -/obj/effect/landmark/start/assistant, -/turf/open/floor/wood, -/area/library) -"chT" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/turf/open/floor/wood, -/area/library) -"chU" = ( -/obj/machinery/photocopier, -/obj/structure/extinguisher_cabinet{ - pixel_y = 32 - }, -/turf/open/floor/wood, -/area/library) "chV" = ( -/obj/machinery/light{ - dir = 1 - }, /obj/machinery/newscaster{ - pixel_y = 32 + pixel_x = -32 }, -/obj/structure/bookcase/manuals/research_and_development, -/obj/machinery/camera{ - c_tag = "Library"; - name = "library camera" - }, -/turf/open/floor/wood, +/turf/open/floor/plasteel/dark, /area/library) "chW" = ( -/obj/structure/chair/comfy/brown, -/obj/item/radio/intercom{ - name = "Station Intercom"; - pixel_y = 26 - }, -/turf/open/floor/wood, +/obj/machinery/holopad, +/obj/effect/turf_decal/bot, +/turf/open/floor/plasteel/grimy, /area/library) "chX" = ( -/obj/machinery/vending/coffee, -/turf/open/floor/wood, +/obj/structure/table/wood, +/obj/item/newspaper{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/reagent_containers/food/drinks/coffee{ + pixel_x = -4; + pixel_y = 2 + }, +/turf/open/floor/plasteel/dark, /area/library) "chY" = ( /obj/machinery/door/poddoor/shutters/preopen{ @@ -67294,10 +67181,6 @@ }, /turf/open/floor/plasteel/grimy, /area/library) -"cju" = ( -/obj/machinery/atmospherics/pipe/manifold/supply/hidden, -/turf/open/floor/plasteel/grimy, -/area/library) "cjv" = ( /obj/machinery/door/airlock/public/glass{ name = "Library Access" @@ -68920,10 +68803,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/wood, /area/library) -"cmv" = ( -/obj/machinery/holopad, -/turf/open/floor/wood, -/area/library) "cmw" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/structure/extinguisher_cabinet{ @@ -69800,7 +69679,7 @@ /turf/open/floor/wood, /area/library) "cnP" = ( -/obj/structure/bookcase/manuals/medical, +/obj/structure/bookcase/random, /turf/open/floor/wood, /area/library) "cnQ" = ( @@ -74568,8 +74447,6 @@ /area/library) "cwr" = ( /obj/structure/easel, -/obj/item/canvas/twentythreeXnineteen, -/obj/item/canvas/twentythreeXtwentythree, /obj/item/canvas/twentythreeXtwentythree, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -78500,7 +78377,10 @@ pixel_x = 3; pixel_y = 3 }, -/obj/item/newspaper, +/obj/item/newspaper{ + pixel_x = 3; + pixel_y = 3 + }, /obj/machinery/status_display/evac{ pixel_x = -32 }, @@ -80213,7 +80093,10 @@ pixel_x = 7; pixel_y = 11 }, -/obj/item/newspaper, +/obj/item/newspaper{ + pixel_x = 3; + pixel_y = 3 + }, /obj/item/pen/red, /turf/open/floor/wood{ icon_state = "wood-broken2" @@ -110110,7 +109993,10 @@ pixel_x = 3; pixel_y = 3 }, -/obj/item/newspaper, +/obj/item/newspaper{ + pixel_x = 3; + pixel_y = 3 + }, /turf/open/floor/plating, /area/security/detectives_office/private_investigators_office) "dFu" = ( @@ -110973,7 +110859,10 @@ /area/crew_quarters/theatre/abandoned) "dGH" = ( /obj/structure/table/wood, -/obj/item/newspaper, +/obj/item/newspaper{ + pixel_x = 3; + pixel_y = 3 + }, /obj/item/clothing/head/bowler, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -125489,6 +125378,17 @@ /obj/structure/closet/crate/coffin, /turf/open/floor/plating, /area/chapel/office) +"gjg" = ( +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/airalarm{ + dir = 1; + pixel_y = -22 + }, +/turf/open/floor/plasteel, +/area/hallway/primary/port) "gmj" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall/r_wall, @@ -125557,6 +125457,12 @@ }, /turf/open/floor/plasteel/dark, /area/science/mixing) +"gOM" = ( +/obj/structure/sign/painting/library{ + pixel_y = -32 + }, +/turf/open/floor/wood, +/area/library) "gPv" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -125856,6 +125762,12 @@ /obj/item/integrated_circuit_printer, /turf/open/floor/plasteel/white/side, /area/science/circuit) +"jqs" = ( +/obj/structure/sign/painting/library{ + pixel_y = 32 + }, +/turf/open/floor/wood, +/area/library) "jqM" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line{ @@ -125974,6 +125886,17 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plating, /area/science/mixing) +"jVB" = ( +/obj/structure/table/wood/fancy, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced, +/obj/structure/sign/painting/library_secure{ + pixel_y = 32 + }, +/turf/open/floor/carpet, +/area/library) "kam" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/conveyor{ @@ -126386,6 +126309,12 @@ }, /turf/open/floor/plasteel/white, /area/science/research) +"mRS" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/open/floor/wood, +/area/library) "mWZ" = ( /obj/machinery/atmospherics/components/binary/pump, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ @@ -126425,6 +126354,17 @@ /obj/machinery/atmospherics/pipe/simple/general/hidden, /turf/closed/wall/r_wall, /area/maintenance/disposal/incinerator) +"oek" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/machinery/camera{ + c_tag = "Library - Aft"; + dir = 2; + name = "library camera" + }, +/turf/open/floor/plasteel/grimy, +/area/library) "oHk" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -126640,6 +126580,10 @@ }, /turf/open/floor/plating, /area/science/research/abandoned) +"pLF" = ( +/obj/machinery/light, +/turf/open/floor/wood, +/area/library) "pQm" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ @@ -126929,6 +126873,15 @@ "tCh" = ( /turf/closed/wall, /area/science/misc_lab) +"tDx" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/open/floor/plasteel/grimy, +/area/library) "tMk" = ( /turf/open/floor/plasteel/white/side{ dir = 10 @@ -127085,6 +127038,16 @@ }, /turf/open/floor/plating, /area/engine/atmos) +"vLX" = ( +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 8 + }, +/obj/structure/sign/plaques/kiddie/library{ + pixel_x = 32; + pixel_y = 32 + }, +/turf/open/floor/plasteel/grimy, +/area/library) "wei" = ( /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel, @@ -127104,6 +127067,19 @@ /obj/effect/turf_decal/tile/purple, /turf/open/floor/plasteel/white, /area/science/misc_lab) +"wEg" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -26 + }, +/turf/open/floor/plasteel, +/area/hallway/primary/port) "wFu" = ( /obj/structure/lattice, /obj/structure/grille, @@ -127292,6 +127268,13 @@ /obj/structure/fans/tiny/invisible, /turf/open/space/basic, /area/space) +"yin" = ( +/obj/structure/chair/sofa/left{ + icon_state = "sofaend_left"; + dir = 8 + }, +/turf/open/floor/wood, +/area/library) "yiv" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/neutral{ @@ -158292,7 +158275,7 @@ ccq ceg ccq chO -ceg +vLX ckQ cmr ccq @@ -158545,11 +158528,11 @@ bUt bWD bYM caH -ccr +cwq ceh -cfY -chP -cjt +caG +caG +oek ckR cms cnO @@ -158800,12 +158783,12 @@ bDl bDl bUu bWE -bYO +gjg caG -ccs -cei +mRS +cxV cfZ -chQ +caG cjt ckR cms @@ -159059,11 +159042,11 @@ bUv bWC bYR caG +jqs +cxV +gOM caG -caG -caG -chR -cjt +tDx ckR cmt cmt @@ -159316,10 +159299,10 @@ bUq bWI bYM caG -cct -cej +jqs +cxV +gOM caG -chS cjt ckR cms @@ -159573,11 +159556,11 @@ bUq bWD bYM caG -ccu -cek -cga -chT -cju +jqs +cxV +gOM +caG +cjt ckR cms cnQ @@ -159831,9 +159814,9 @@ bWD bYM caG ccv -cel +cxV +pLF caG -chU cjt ckR xuu @@ -160087,9 +160070,9 @@ bUq bWD bYS caG -caG -caG -caG +jVB +cxV +cmt chV cjt ckT @@ -160346,7 +160329,7 @@ bYM caG cct cej -caG +cxV chW cjt ckR @@ -160602,12 +160585,12 @@ bWD bYM caG ccu -cek -cga -chT -cju +cmt +cmt +ccr +cjt ckR -cmv +cmt cnU cpy cqT @@ -160856,11 +160839,11 @@ bQu bQv bUr bWD -bYM +wEg caG -ccv +chP cel -caG +yin chX cjt ckR diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 356eefbd35..bfea5f9289 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -7602,10 +7602,10 @@ /turf/open/floor/plating, /area/security/warden) "apa" = ( -/obj/machinery/atmospherics/pipe/manifold/cyan/visible{ - dir = 4 - }, /obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/cyan/visible{ + dir = 1 + }, /turf/open/floor/plasteel, /area/engine/atmos) "apb" = ( @@ -38665,11 +38665,20 @@ /turf/open/floor/plasteel, /area/engine/atmos) "bMM" = ( -/obj/machinery/atmospherics/components/unary/thermomachine/heater, +/obj/structure/rack, +/obj/item/clothing/suit/hazardvest, +/obj/item/clothing/suit/hazardvest, +/obj/item/clothing/suit/hazardvest, +/obj/item/clothing/suit/hazardvest, +/obj/item/clothing/gloves/color/black, +/obj/item/clothing/gloves/color/black, +/obj/item/clothing/gloves/color/black, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, /turf/open/floor/plasteel, /area/engine/atmos) "bMN" = ( -/obj/machinery/atmospherics/components/unary/thermomachine/freezer, +/obj/machinery/atmospherics/components/unary/thermomachine/heater, /turf/open/floor/plasteel, /area/engine/atmos) "bMO" = ( @@ -38739,15 +38748,13 @@ /turf/open/floor/plasteel, /area/engine/atmos) "bMY" = ( -/obj/machinery/atmospherics/pipe/simple/yellow/visible{ - dir = 4 +/obj/machinery/atmospherics/pipe/manifold/cyan/visible{ + dir = 1 }, -/turf/closed/wall/r_wall, +/turf/open/floor/plasteel, /area/engine/atmos) "bMZ" = ( -/obj/machinery/atmospherics/pipe/simple/yellow/visible{ - dir = 6 - }, +/obj/machinery/atmospherics/components/unary/thermomachine/heater/on, /turf/open/floor/plasteel, /area/engine/atmos) "bNc" = ( @@ -39075,6 +39082,9 @@ /obj/machinery/light{ dir = 8 }, +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 1 + }, /turf/open/floor/plasteel, /area/engine/atmos) "bNU" = ( @@ -39136,7 +39146,7 @@ /area/engine/atmos) "bOe" = ( /obj/machinery/meter, -/obj/machinery/atmospherics/pipe/manifold4w/cyan/visible, +/obj/machinery/atmospherics/pipe/manifold/cyan/visible, /turf/open/floor/plasteel, /area/engine/atmos) "bOf" = ( @@ -39147,13 +39157,7 @@ /turf/open/floor/plating, /area/engine/atmos) "bOg" = ( -/obj/machinery/atmospherics/pipe/simple/cyan/visible{ - dir = 4 - }, -/obj/machinery/atmospherics/components/binary/pump{ - dir = 1; - name = "Mix to Incinerator" - }, +/obj/machinery/atmospherics/pipe/manifold/cyan/visible, /turf/open/floor/plasteel, /area/engine/atmos) "bOh" = ( @@ -39460,17 +39464,16 @@ /turf/open/floor/plasteel, /area/engine/atmos) "bOR" = ( -/obj/machinery/atmospherics/pipe/manifold/yellow/visible{ +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/purple/visible{ dir = 1 }, -/obj/machinery/meter, /turf/open/floor/plasteel, /area/engine/atmos) "bOS" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 6 }, -/obj/structure/tank_dispenser, /turf/open/floor/plasteel, /area/engine/atmos) "bOT" = ( @@ -39483,8 +39486,8 @@ /area/engine/atmos) "bOU" = ( /obj/machinery/holopad, -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 }, /turf/open/floor/plasteel, /area/engine/atmos) @@ -39571,35 +39574,34 @@ /turf/open/floor/plasteel, /area/engine/atmos) "bPe" = ( -/obj/machinery/atmospherics/pipe/manifold/yellow/visible, +/obj/machinery/atmospherics/pipe/manifold/purple/visible, /turf/open/floor/plasteel, /area/engine/atmos) "bPf" = ( -/obj/machinery/atmospherics/pipe/simple/yellow/visible{ +/obj/machinery/atmospherics/pipe/simple/purple/visible{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/cyan/visible, /turf/open/floor/plasteel, /area/engine/atmos) "bPg" = ( -/obj/machinery/atmospherics/pipe/manifold/yellow/visible{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/purple/visible{ + dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/cyan/visible, /turf/open/floor/plasteel, /area/engine/atmos) "bPh" = ( /obj/machinery/atmospherics/pipe/simple/cyan/visible, -/obj/machinery/atmospherics/pipe/simple/yellow/visible{ +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/atmospherics/pipe/layer_manifold{ dir = 4 }, -/obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/engine/atmos) "bPi" = ( /obj/machinery/light{ dir = 4 }, -/obj/machinery/atmospherics/pipe/manifold/yellow/visible, /obj/effect/turf_decal/tile/green{ dir = 1 }, @@ -39607,6 +39609,9 @@ /obj/effect/turf_decal/tile/green{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/purple/visible{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/atmos) "bPj" = ( @@ -40030,8 +40035,8 @@ /obj/machinery/computer/atmos_alert{ dir = 8 }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 }, /turf/open/floor/plasteel/dark/corner, /area/engine/atmos) @@ -40045,7 +40050,11 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/obj/effect/spawner/structure/window, +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/door/poddoor/preopen{ + id = "atmos"; + name = "Atmospherics Blast Door" + }, /turf/open/floor/plating, /area/engine/atmos) "bQo" = ( @@ -40089,7 +40098,7 @@ /turf/open/floor/plasteel, /area/security/checkpoint/engineering) "bQr" = ( -/obj/structure/closet/crate, +/obj/machinery/atmospherics/components/unary/thermomachine/freezer, /turf/open/floor/plasteel, /area/engine/atmos) "bQs" = ( @@ -40113,38 +40122,31 @@ /turf/open/floor/plasteel/dark/corner, /area/hallway/primary/aft) "bQu" = ( -/obj/structure/rack, -/obj/item/clothing/suit/hazardvest, -/obj/item/clothing/suit/hazardvest, -/obj/item/clothing/suit/hazardvest, -/obj/item/clothing/suit/hazardvest, -/obj/item/clothing/gloves/color/black, -/obj/item/clothing/gloves/color/black, -/obj/item/clothing/gloves/color/black, -/obj/item/clothing/mask/gas, -/obj/item/clothing/mask/gas, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/closet/crate, /turf/open/floor/plasteel, /area/engine/atmos) "bQv" = ( +/obj/machinery/atmospherics/pipe/simple/purple/visible, /obj/machinery/atmospherics/pipe/simple/cyan/visible{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/yellow/visible, /turf/open/floor/plasteel, /area/engine/atmos) "bQw" = ( -/obj/machinery/atmospherics/pipe/simple/cyan/visible{ - dir = 9 +/obj/machinery/atmospherics/pipe/manifold/green/visible{ + dir = 1 }, /turf/open/floor/plasteel, /area/engine/atmos) "bQx" = ( -/obj/machinery/atmospherics/pipe/simple/cyan/visible{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/green/visible{ + dir = 6 }, -/obj/machinery/atmospherics/components/binary/pump{ - dir = 1; - name = "Mix to Distro" +/obj/machinery/atmospherics/pipe/simple/cyan/visible{ + dir = 9 }, /turf/open/floor/plasteel, /area/engine/atmos) @@ -40161,6 +40163,9 @@ /obj/effect/turf_decal/tile/green{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/green/visible{ + dir = 10 + }, /turf/open/floor/plasteel, /area/engine/atmos) "bQA" = ( @@ -40436,6 +40441,11 @@ /area/hallway/primary/aft) "bRr" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/tank_dispenser, /turf/open/floor/plasteel, /area/engine/atmos) "bRs" = ( @@ -40447,11 +40457,7 @@ /turf/open/floor/plating, /area/engine/atmos) "bRt" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/firealarm{ - dir = 1; - pixel_y = -24 - }, +/obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plasteel, /area/engine/atmos) "bRu" = ( @@ -40461,7 +40467,6 @@ /obj/machinery/computer/atmos_alert{ dir = 8 }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel/dark/corner, /area/engine/atmos) "bRv" = ( @@ -40480,8 +40485,10 @@ /turf/open/floor/plasteel, /area/engine/atmos) "bRx" = ( -/obj/effect/spawner/structure/window, -/turf/open/floor/plating, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{ + dir = 1 + }, +/turf/open/floor/plasteel, /area/engine/atmos) "bRy" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ @@ -40499,8 +40506,9 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ - dir = 4 +/obj/machinery/atmospherics/components/binary/pump/on{ + dir = 8; + name = "Waste to Filter" }, /turf/open/floor/plasteel, /area/engine/atmos) @@ -40516,26 +40524,26 @@ /turf/open/floor/plasteel, /area/engine/atmos) "bRD" = ( -/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible, +/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ + dir = 9 + }, /turf/open/floor/plasteel, /area/engine/atmos) "bRE" = ( -/obj/machinery/atmospherics/pipe/manifold/green/visible{ - dir = 1 +/obj/machinery/atmospherics/components/binary/pump{ + name = "Air to Ports" }, -/obj/machinery/meter, /turf/open/floor/plasteel, /area/engine/atmos) "bRF" = ( -/obj/machinery/atmospherics/pipe/simple/green/visible{ - dir = 4 +/obj/machinery/atmospherics/components/binary/pump{ + name = "Mix to Ports" }, -/obj/machinery/atmospherics/pipe/simple/yellow/visible, /turf/open/floor/plasteel, /area/engine/atmos) "bRG" = ( -/obj/machinery/atmospherics/pipe/manifold/green/visible{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/green/visible{ + dir = 5 }, /turf/open/floor/plasteel, /area/engine/atmos) @@ -40552,6 +40560,14 @@ dir = 4; name = "Unfiltered & Air to Mix" }, +/obj/machinery/atmospherics/pipe/simple/green/visible, +/obj/effect/turf_decal/tile/green{ + dir = 8 + }, +/obj/effect/turf_decal/tile/green, +/obj/effect/turf_decal/tile/green{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/atmos) "bRL" = ( @@ -40839,11 +40855,7 @@ /area/hallway/primary/aft) "bSB" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/machinery/door/airlock/atmos/glass{ - name = "Atmospherics Monitoring"; - req_access_txt = "24" - }, -/turf/open/floor/plasteel, +/turf/closed/wall, /area/engine/atmos) "bSC" = ( /obj/machinery/atmospherics/pipe/simple/orange/visible{ @@ -40853,13 +40865,19 @@ /area/engine/atmos) "bSD" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/turf/closed/wall, +/obj/machinery/door/airlock/atmos/glass{ + name = "Atmospherics Monitoring"; + req_access_txt = "24" + }, +/obj/machinery/door/firedoor/heavy, +/turf/open/floor/plasteel, /area/engine/atmos) "bSE" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 5 +/obj/machinery/atmospherics/components/binary/pump{ + dir = 1; + name = "Pure to Mix" }, -/turf/closed/wall, +/turf/open/floor/plasteel, /area/engine/atmos) "bSF" = ( /obj/effect/turf_decal/bot, @@ -40891,13 +40909,15 @@ /area/engine/atmos) "bSM" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/yellow/visible, +/obj/machinery/atmospherics/pipe/simple/general/visible{ + dir = 5 + }, /turf/open/floor/plating, /area/engine/atmos) "bSN" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/green/visible{ - dir = 5 +/obj/machinery/atmospherics/pipe/simple/yellow/visible{ + dir = 10 }, /turf/open/floor/plating, /area/engine/atmos) @@ -41235,7 +41255,12 @@ /obj/machinery/atmospherics/pipe/simple/orange/visible{ dir = 4 }, -/turf/open/floor/plasteel, +/obj/effect/turf_decal/tile/yellow{ + dir = 8 + }, +/turf/open/floor/plasteel/dark/corner{ + dir = 1 + }, /area/engine/atmos) "bTM" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, @@ -41248,14 +41273,16 @@ /obj/machinery/atmospherics/pipe/simple/orange/visible{ dir = 4 }, -/obj/effect/spawner/structure/window, /turf/open/floor/plasteel, /area/engine/atmos) "bTO" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ +/obj/machinery/atmospherics/pipe/simple/cyan/visible{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/machinery/atmospherics/components/binary/pump{ + dir = 1; + name = "External to Waste" + }, /turf/open/floor/plasteel, /area/engine/atmos) "bTP" = ( @@ -41265,19 +41292,14 @@ /turf/open/floor/plasteel, /area/engine/atmos) "bTQ" = ( -/obj/machinery/atmospherics/components/binary/pump/on{ - dir = 8; - name = "Waste to Filter" +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/atmospherics/pipe/simple/yellow/visible{ + dir = 5 }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible, -/turf/open/floor/plasteel, +/turf/open/floor/plating, /area/engine/atmos) "bTR" = ( -/obj/machinery/atmospherics/components/binary/pump/on{ - dir = 8; - name = "Filter to Waste" - }, -/obj/machinery/atmospherics/pipe/simple/cyan/visible, +/obj/machinery/atmospherics/pipe/manifold/orange/visible, /turf/open/floor/plasteel, /area/engine/atmos) "bTS" = ( @@ -41285,15 +41307,16 @@ /turf/open/floor/plasteel, /area/engine/atmos) "bTU" = ( -/obj/machinery/atmospherics/pipe/simple/yellow/visible{ - dir = 5 +/obj/machinery/atmospherics/components/binary/pump{ + dir = 8; + name = "Pure to Ports" }, /turf/open/floor/plasteel, /area/engine/atmos) "bTV" = ( /obj/machinery/atmospherics/components/binary/pump{ dir = 8; - name = "N2O Outlet Pump" + name = "N2O to Pure" }, /obj/effect/turf_decal/tile/red{ dir = 4 @@ -41639,7 +41662,9 @@ /area/engine/atmos) "bUL" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/green/visible, +/obj/machinery/atmospherics/pipe/manifold/general/visible{ + dir = 4 + }, /turf/open/floor/plating, /area/engine/atmos) "bUM" = ( @@ -41653,9 +41678,7 @@ /area/engine/atmos) "bUN" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/green/visible{ - dir = 10 - }, +/obj/machinery/atmospherics/pipe/simple/green/visible, /turf/open/floor/plating, /area/engine/atmos) "bUO" = ( @@ -41681,7 +41704,7 @@ icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/cyan/visible, -/obj/machinery/atmospherics/components/binary/pump/on{ +/obj/machinery/atmospherics/components/binary/pump{ dir = 8; name = "Mix to External" }, @@ -41695,6 +41718,9 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/green/visible, +/obj/machinery/atmospherics/pipe/simple/dark/visible{ + dir = 4 + }, /turf/open/floor/plasteel/white/corner, /area/engine/atmos) "bUU" = ( @@ -42023,10 +42049,10 @@ /turf/closed/wall/r_wall, /area/engine/atmos) "bVP" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ - dir = 6 +/obj/machinery/atmospherics/components/binary/pump{ + dir = 8; + name = "External to Pumps" }, -/obj/effect/spawner/structure/window, /turf/open/floor/plasteel, /area/engine/atmos) "bVQ" = ( @@ -42122,6 +42148,12 @@ /obj/machinery/atmospherics/components/trinary/filter/atmos/n2o{ dir = 1 }, +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, /turf/open/floor/plasteel/white/corner, /area/engine/atmos) "bWd" = ( @@ -42402,7 +42434,12 @@ dir = 4; pixel_x = -22 }, -/turf/open/floor/plasteel, +/obj/effect/turf_decal/tile/yellow{ + dir = 8 + }, +/turf/open/floor/plasteel/dark/corner{ + dir = 1 + }, /area/engine/atmos) "bWO" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ @@ -42411,8 +42448,10 @@ /turf/closed/wall/r_wall, /area/engine/atmos) "bWP" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible, -/turf/closed/wall, +/obj/machinery/atmospherics/pipe/manifold/general/visible{ + dir = 1 + }, +/turf/open/floor/plasteel, /area/engine/atmos) "bWQ" = ( /turf/closed/wall/r_wall, @@ -42436,7 +42475,7 @@ /obj/structure/cable{ icon_state = "1-4" }, -/turf/open/floor/plating, +/turf/open/floor/plasteel, /area/engine/atmos) "bWU" = ( /obj/machinery/light{ @@ -42774,7 +42813,12 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ dir = 9 }, -/turf/closed/wall, +/obj/machinery/door/poddoor/preopen{ + id = "atmos"; + name = "Atmospherics Blast Door" + }, +/obj/effect/turf_decal/delivery, +/turf/open/floor/plasteel, /area/engine/atmos) "bXM" = ( /obj/machinery/door/poddoor/preopen{ @@ -42853,7 +42897,10 @@ /turf/open/floor/plasteel, /area/engine/atmos) "bXU" = ( -/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/atmospherics/components/binary/pump{ + dir = 8; + name = "Ports to External" + }, /turf/open/floor/plasteel, /area/engine/atmos) "bXV" = ( @@ -42863,12 +42910,19 @@ }, /obj/machinery/atmospherics/components/binary/pump{ dir = 8; - name = "Plasma Outlet Pump" + name = "Plasma to Pure" }, +/obj/machinery/atmospherics/pipe/simple/green/visible, /obj/effect/turf_decal/stripes/line{ dir = 5 }, -/obj/machinery/atmospherics/pipe/simple/green/visible, +/obj/effect/turf_decal/tile/purple{ + dir = 1 + }, +/obj/effect/turf_decal/tile/purple, +/obj/effect/turf_decal/tile/purple{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/atmos) "bXW" = ( @@ -43172,17 +43226,8 @@ /turf/open/floor/plasteel, /area/hallway/primary/aft) "bYJ" = ( -/obj/effect/turf_decal/tile/yellow{ - dir = 4 - }, -/obj/machinery/door/airlock/atmos{ - name = "Atmospherics"; - req_access_txt = "24" - }, -/obj/machinery/door/firedoor/heavy, -/turf/open/floor/plasteel/dark/corner{ - dir = 1 - }, +/obj/machinery/atmospherics/pipe/manifold4w/general/visible, +/turf/open/floor/plasteel, /area/engine/atmos) "bYK" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible, @@ -43215,11 +43260,8 @@ /turf/open/floor/plasteel, /area/hallway/primary/aft) "bYN" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ - dir = 4 - }, -/turf/open/floor/plating, +/obj/machinery/atmospherics/pipe/manifold4w/yellow/visible, +/turf/open/floor/plasteel, /area/engine/atmos) "bYO" = ( /obj/structure/disposalpipe/segment{ @@ -43235,10 +43277,14 @@ /obj/machinery/computer/atmos_control/tank/toxin_tank{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/green/visible, +/obj/effect/turf_decal/tile/purple{ + dir = 4 + }, /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/green/visible, +/obj/effect/turf_decal/tile/purple, /turf/open/floor/plasteel, /area/engine/atmos) "bYU" = ( @@ -43539,16 +43585,32 @@ /area/engine/atmos) "bZH" = ( /obj/machinery/portable_atmospherics/canister, +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 1 + }, /turf/open/floor/plasteel, /area/engine/atmos) "bZI" = ( -/obj/machinery/portable_atmospherics/scrubber, +/obj/machinery/space_heater, +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, /turf/open/floor/plasteel, /area/engine/atmos) "bZK" = ( /obj/machinery/atmospherics/components/trinary/filter/atmos/plasma{ dir = 1 }, +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/obj/effect/turf_decal/tile/purple{ + dir = 8 + }, +/obj/effect/turf_decal/tile/purple, +/obj/effect/turf_decal/tile/purple{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/atmos) "bZL" = ( @@ -43933,13 +43995,18 @@ /turf/closed/wall/r_wall, /area/security/checkpoint/engineering) "caE" = ( -/obj/structure/reagent_dispensers/watertank/high, +/obj/machinery/atmospherics/pipe/manifold/general/visible{ + dir = 8 + }, /turf/open/floor/plasteel, /area/engine/atmos) "caF" = ( /obj/machinery/atmospherics/pipe/simple/green/visible{ dir = 6 }, +/obj/machinery/atmospherics/pipe/simple/yellow/visible{ + dir = 9 + }, /turf/open/floor/plasteel, /area/engine/atmos) "caG" = ( @@ -43953,12 +44020,10 @@ /turf/open/floor/plasteel, /area/engine/atmos) "caH" = ( -/obj/machinery/atmospherics/pipe/simple/yellow/visible{ - dir = 5 - }, /obj/effect/decal/cleanable/oil{ icon_state = "floor6" }, +/obj/machinery/atmospherics/pipe/manifold/yellow/visible, /turf/open/floor/plasteel, /area/engine/atmos) "caI" = ( @@ -44366,14 +44431,17 @@ /turf/open/floor/plating, /area/maintenance/port/aft) "cbA" = ( -/obj/machinery/portable_atmospherics/pump, +/obj/machinery/atmospherics/components/binary/pump{ + dir = 4; + name = "Ports to Incinerator" + }, /turf/open/floor/plasteel, /area/engine/atmos) "cbB" = ( /obj/machinery/atmospherics/pipe/simple/green/visible, /obj/machinery/atmospherics/components/binary/pump{ dir = 8; - name = "Air Outlet Pump" + name = "Air to Pure" }, /turf/open/floor/plasteel, /area/engine/atmos) @@ -44407,7 +44475,7 @@ "cbG" = ( /obj/machinery/atmospherics/components/binary/pump{ dir = 8; - name = "CO2 Outlet Pump" + name = "CO2 to Pure" }, /obj/effect/turf_decal/tile/yellow{ dir = 1 @@ -44783,7 +44851,10 @@ /turf/closed/wall/r_wall, /area/engine/engineering) "ccy" = ( -/obj/machinery/space_heater, +/obj/machinery/atmospherics/pipe/simple/yellow/visible, +/obj/machinery/atmospherics/pipe/simple/dark/visible{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/atmos) "ccz" = ( @@ -45132,15 +45203,24 @@ /turf/open/floor/plating/snowed/smoothed/icemoon, /area/engine/atmos) "cdB" = ( -/obj/machinery/atmospherics/pipe/simple/yellow/visible{ - dir = 9 +/obj/machinery/atmospherics/pipe/simple/cyan/visible, +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/atmospherics/pipe/simple/dark/visible{ + dir = 4 }, -/turf/open/floor/plasteel, +/turf/open/floor/plating, /area/engine/atmos) "cdC" = ( /obj/machinery/atmospherics/components/trinary/filter/atmos/co2{ dir = 1 }, +/obj/effect/turf_decal/tile/yellow{ + dir = 8 + }, +/obj/effect/turf_decal/tile/yellow, +/obj/effect/turf_decal/tile/yellow{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/atmos) "cdD" = ( @@ -45735,7 +45815,10 @@ /turf/open/floor/plasteel, /area/engine/break_room) "cfi" = ( -/obj/machinery/portable_atmospherics/scrubber/huge, +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/obj/structure/reagent_dispensers/watertank/high, /turf/open/floor/plasteel, /area/engine/atmos) "cfj" = ( @@ -46428,6 +46511,13 @@ /obj/machinery/atmospherics/components/trinary/filter/atmos/o2{ dir = 4 }, +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/effect/turf_decal/tile/blue{ + dir = 1 + }, /turf/open/floor/plasteel, /area/engine/atmos) "chb" = ( @@ -46470,8 +46560,11 @@ /turf/open/floor/plasteel/cafeteria, /area/engine/atmos) "che" = ( -/obj/machinery/door/airlock/atmos{ - name = "Atmospherics"; +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + name = "Atmospherics External Airlock"; req_access_txt = "24" }, /turf/open/floor/plating, @@ -46942,8 +47035,8 @@ /turf/closed/wall/r_wall, /area/engine/atmos) "ciu" = ( -/obj/machinery/atmospherics/pipe/simple/yellow/visible, /obj/effect/spawner/structure/window/reinforced, +/obj/machinery/atmospherics/pipe/layer_manifold, /turf/open/floor/plating, /area/engine/atmos) "civ" = ( @@ -52243,7 +52336,9 @@ /area/science/mixing) "cBF" = ( /obj/effect/landmark/event_spawn, -/obj/machinery/atmospherics/pipe/manifold4w/scrubbers/visible, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{ + dir = 8 + }, /turf/open/floor/plasteel, /area/engine/atmos) "cBH" = ( @@ -52432,10 +52527,10 @@ /turf/open/floor/plating, /area/maintenance/starboard/aft) "cCE" = ( -/obj/machinery/atmospherics/pipe/simple/yellow/visible, -/obj/machinery/atmospherics/pipe/simple/orange/visible{ +/obj/machinery/atmospherics/pipe/simple/general/visible{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/yellow/visible, /turf/open/floor/plasteel, /area/engine/atmos) "cCF" = ( @@ -52528,10 +52623,7 @@ /turf/open/floor/wood, /area/crew_quarters/theatre) "cGG" = ( -/obj/effect/spawner/structure/window, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 10 - }, +/obj/machinery/atmospherics/pipe/simple/general/visible, /turf/open/floor/plasteel, /area/engine/atmos) "cHf" = ( @@ -53723,6 +53815,13 @@ }, /turf/open/floor/plating, /area/maintenance/starboard/aft) +"dkV" = ( +/obj/machinery/space_heater, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "dly" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -53985,12 +54084,8 @@ }, /area/crew_quarters/fitness/pool) "ecE" = ( -/obj/machinery/atmospherics/pipe/simple/cyan/visible{ - dir = 4 - }, -/obj/machinery/atmospherics/components/binary/pump{ - dir = 1; - name = "Mix to Waste" +/obj/machinery/atmospherics/pipe/simple/general/visible{ + dir = 5 }, /turf/open/floor/plasteel, /area/engine/atmos) @@ -54751,6 +54846,11 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/plasteel, /area/science/circuit) +"fKv" = ( +/obj/machinery/portable_atmospherics/scrubber/huge, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plasteel, +/area/engine/atmos) "fMp" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel/dark, @@ -54932,13 +55032,9 @@ /turf/open/floor/carpet, /area/crew_quarters/cryopod) "gfJ" = ( -/obj/machinery/atmospherics/pipe/simple/cyan/visible{ +/obj/machinery/atmospherics/pipe/simple/general/visible{ dir = 4 }, -/obj/machinery/door/airlock/atmos{ - name = "Atmospherics"; - req_access_txt = "24" - }, /turf/open/floor/plasteel, /area/engine/atmos) "ghD" = ( @@ -54975,11 +55071,12 @@ dir = 4 }, /obj/structure/closet/secure_closet/atmospherics, -/obj/item/cartridge/atmos, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ +/obj/effect/turf_decal/tile/yellow{ + dir = 4 + }, +/turf/open/floor/plasteel/dark/corner{ dir = 1 }, -/turf/open/floor/plasteel, /area/engine/atmos) "gnf" = ( /obj/structure/disposalpipe/segment{ @@ -55478,6 +55575,13 @@ }, /turf/open/floor/engine, /area/engine/engineering) +"hOd" = ( +/obj/machinery/portable_atmospherics/scrubber, +/obj/effect/turf_decal/stripes/line{ + dir = 5 + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "hOv" = ( /obj/structure/table/wood/fancy, /obj/item/reagent_containers/food/snacks/burger/plain, @@ -55891,9 +55995,17 @@ /turf/open/floor/plasteel, /area/engine/engineering) "iYC" = ( -/obj/effect/spawner/structure/window, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/turf/open/floor/plasteel, +/obj/effect/turf_decal/tile/yellow{ + dir = 4 + }, +/obj/machinery/door/firedoor/heavy, +/obj/machinery/door/airlock/atmos{ + name = "Atmospherics"; + req_access_txt = "24" + }, +/turf/open/floor/plasteel/dark/corner{ + dir = 1 + }, /area/engine/atmos) "iYE" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ @@ -56426,6 +56538,13 @@ }, /turf/open/floor/plating, /area/maintenance/fore/secondary) +"khU" = ( +/obj/machinery/atmospherics/components/binary/pump{ + dir = 4; + name = "N2 to Pure" + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "khV" = ( /obj/machinery/vending/cola/red, /obj/structure/sign/poster/contraband/robust_softdrinks{ @@ -57729,6 +57848,13 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/locker) +"nNP" = ( +/obj/machinery/atmospherics/components/binary/pump{ + dir = 4; + name = "O2 to Pure" + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "nQi" = ( /obj/machinery/recharge_station, /turf/open/floor/plating, @@ -58344,6 +58470,13 @@ }, /turf/open/floor/wood, /area/crew_quarters/bar) +"plL" = ( +/obj/machinery/portable_atmospherics/pump, +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "plS" = ( /obj/machinery/door/window/brigdoor/security/cell{ id = "Cell 1"; @@ -58918,11 +59051,12 @@ dir = 4 }, /obj/structure/closet/secure_closet/atmospherics, -/obj/item/cartridge/atmos, -/obj/machinery/atmospherics/components/unary/vent_pump/on{ +/obj/effect/turf_decal/tile/yellow{ + dir = 4 + }, +/turf/open/floor/plasteel/dark/corner{ dir = 1 }, -/turf/open/floor/plasteel, /area/engine/atmos) "rcD" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ @@ -59114,6 +59248,13 @@ }, /turf/open/floor/plasteel, /area/engine/gravity_generator) +"rto" = ( +/obj/machinery/portable_atmospherics/scrubber, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "rtC" = ( /obj/effect/decal/cleanable/blood/old, /turf/open/floor/plating, @@ -59432,6 +59573,12 @@ /obj/effect/spawner/lootdrop/maintenance, /turf/open/floor/plating, /area/maintenance/fore) +"siv" = ( +/obj/machinery/atmospherics/pipe/simple/cyan/visible{ + dir = 9 + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "slk" = ( /obj/machinery/door/airlock/maintenance{ req_access_txt = "12" @@ -61316,6 +61463,11 @@ }, /turf/open/floor/plasteel/white, /area/medical/medbay/central) +"wcr" = ( +/obj/machinery/portable_atmospherics/pump, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plasteel, +/area/engine/atmos) "wcB" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 10 @@ -61469,7 +61621,7 @@ /obj/machinery/atmospherics/pipe/simple/cyan/visible{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/yellow/visible, +/obj/machinery/atmospherics/pipe/layer_manifold, /turf/open/floor/plating, /area/engine/atmos) "wAh" = ( @@ -61917,6 +62069,12 @@ /obj/item/radio/headset/headset_cargo, /turf/open/floor/plasteel, /area/quartermaster/storage) +"xBF" = ( +/obj/machinery/atmospherics/pipe/manifold/yellow/visible{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "xDM" = ( /obj/machinery/camera{ c_tag = "Locker Room South"; @@ -92203,7 +92361,7 @@ bUF bVN bWN bXM -bYJ +bLK bRi bZy cbu @@ -92453,14 +92611,14 @@ alk bNQ bOV bQk -bRt +bVQ bSD bTM bUH bVQ bVZ bXM -bLK +iYC cew bTh cdt @@ -92709,13 +92867,13 @@ bLL bOd bNQ bOU -bTO -bRr -bSE +bQj +bOd +bMK bTN -gfJ -bVP -bWP +bTP +bRy +cfN bXL bLK bRj @@ -92968,8 +93126,8 @@ bNS bOX bQm bRv -cGG -glY +bRs +rca bTP bVX bWQ @@ -93225,7 +93383,7 @@ bNR bOW bQl bRu -iYC +bRs rca bUI bVR @@ -93481,7 +93639,7 @@ bMK bMK bOY bQn -bRx +bRs bMK bUP bUJ @@ -93736,7 +93894,7 @@ bKz bLK bQr bNT -bOV +bQu bQo bRw bSF @@ -94249,7 +94407,7 @@ bJv bKB bLK bMM -bNV +bOd bOQ bQj bRy @@ -94518,12 +94676,12 @@ bVV bVV bWT bZG -caE -cbA -ccy -bZH -bZI -bQu +bOd +bOd +bOd +bOd +bOd +bOd bOd cgW cit @@ -94766,19 +94924,19 @@ bMO bIF bOZ bQp -bRA -bTP -bOd +bRx +bTO +bTR bOd bOd bOd bOd bXS bOd -bXU -cbA -ccy -bZH +bOd +bOd +bOd +bOd bZI cfi bOd @@ -95022,10 +95180,10 @@ bLK bMR bIH bJF -bRy -bTQ -ecE -bOd +bRt +bRA +bTP +bVP bOd bOd bOd @@ -95036,8 +95194,8 @@ bOd bOd bOd bOd -bOd -bOd +dkV +fKv cfQ cgY ciu @@ -95279,11 +95437,11 @@ bLK bMQ bNY bPa -bYN +bMQ bRC bSK -bOd -bOd +bWP +bZH bOd bOd bOd @@ -95293,8 +95451,8 @@ bOd bOd bOd bOd -bOd -bOd +rto +wcr apa cgX apF @@ -95539,8 +95697,8 @@ bPd cBF bRD bSK -bOd -bOd +bWP +bZH bOd bOd bOd @@ -95550,9 +95708,9 @@ bOd bOd cBJ bOd -bOd -bOd -bOd +hOd +plL +bTP cha civ axs @@ -95794,10 +95952,10 @@ bMS cfQ bPc bQs -bTR +cez bSJ -bOd -bOd +bWP +bZH bOd bOd bOd @@ -95807,9 +95965,9 @@ bOd bOd bOd bOd -bOd -bOd -bOd +cfQ +cez +siv cgZ bSK crk @@ -96053,9 +96211,7 @@ bOR bQv bRF bSM -bTS -bOd -bOd +bXU bOd bOd bOd @@ -96066,6 +96222,8 @@ bOd bOd bOd bOd +bTP +cfQ cbD chb wzX @@ -96307,15 +96465,13 @@ bLK bMU bOc bPe -bTP +bMY bRE bUL -cfT -bOd -bOd -bOd -bOd -bOd +bYJ +caE +cGG +ecE bOd bOd bOd @@ -96323,6 +96479,8 @@ bOd bOd bOd bOd +khU +nNP cfP ccz bSJ @@ -96562,12 +96720,15 @@ bvd bKH bLK bMX -bTP +bMY bPg bQx -bRF -bSM +bSE +bTQ bTU +cbA +bOd +gfJ bOd bOd bOd @@ -96575,10 +96736,7 @@ bOd bOd bOd bOd -bOd -bOd -bMZ -bTS +xBF caH cbE chd @@ -96824,8 +96982,8 @@ bPf bQw bRG bSN -bPg -bTS +bYN +ccy bTS cCE bWa @@ -96834,7 +96992,7 @@ bTS bTS bYL bTS -cdB +bTS caF cbB cfT @@ -97332,14 +97490,14 @@ bvj bvd bKH bLK -bMY +bLK bOf bPh bQy bRI ceA bPh -bQy +cdB bRI cCF bPh diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 07fba56f90..9f7e39af54 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -3807,7 +3807,8 @@ movement_type = 1; name = "Sergeant Araneus"; real_name = "Sergeant Araneus"; - response_help = "pets"; + response_help_continuous = "pets"; + response_help_simple = "pet"; turns_per_move = 10 }, /turf/open/floor/carpet, diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm index 737028385a..35d7152eeb 100644 --- a/_maps/map_files/Mining/Lavaland.dmm +++ b/_maps/map_files/Mining/Lavaland.dmm @@ -2367,9 +2367,7 @@ /obj/item/seeds/cotton{ yield = 5 }, -/obj/item/seeds/cotton{ - yield = 5 - }, +/obj/item/seeds/cotton/durathread, /turf/open/indestructible/boss, /area/ruin/unpowered/ash_walkers) "Vj" = ( diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 0b46f21a97..e8e75c132a 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -83,10 +83,3 @@ #define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu #define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you - -///Max length of a keypress command before it's considered to be a forged packet/bogus command -#define MAX_KEYPRESS_COMMANDLENGTH 16 -///Max amount of keypress messages per second over two seconds before client is autokicked -#define MAX_KEYPRESS_AUTOKICK 100 -///Length of max held keys -#define MAX_HELD_KEYS 15 diff --git a/code/__DEFINES/admin/keybindings.dm b/code/__DEFINES/admin/keybindings.dm new file mode 100644 index 0000000000..3efc26c7d5 --- /dev/null +++ b/code/__DEFINES/admin/keybindings.dm @@ -0,0 +1,18 @@ +// Defines for managed input/keybinding system. +/// Max length of a keypress command before it's considered to be a forged packet/bogus command +#define MAX_KEYPRESS_COMMANDLENGTH 16 +/// Maximum keys that can be bound to one button +#define MAX_COMMANDS_PER_KEY 5 +/// Maximum keys per keybind +#define MAX_KEYS_PER_KEYBIND 3 +/// Max amount of keypress messages per second over two seconds before client is autokicked +#define MAX_KEYPRESS_AUTOKICK 100 +/// Max keys that can be held down at once by a client +#define MAX_HELD_KEYS 15 + +/// Macroset name of hotkeys/keybind only/modern mode +#define SKIN_MACROSET_HOTKEYS "hotkeys" +/// Macroset name of classic hotkey mode +#define SKIN_MACROSET_CLASSIC_HOTKEYS "oldhotkeys" +/// Macroset name of classic input mode +#define SKIN_MACROSET_CLASSIC_INPUT "oldinput" diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index eb71b8b5bb..bcb29d72a5 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -149,7 +149,7 @@ // /mob signals #define COMSIG_MOB_CLICKED_SHIFT_ON "mob_shift_click_on" //from base of /atom/ShiftClick(): (atom/A), for return values, see COMSIG_CLICK_SHIFT -#define COMSIG_MOB_VISIBLE_ATOMS "mob_visible_atoms" //from base of mob/visible_atoms(): (list/visible_atoms) +#define COMSIG_MOB_FOV_VIEW "mob_visible_atoms" //from base of mob/fov_view(): (list/visible_atoms) #define COMSIG_MOB_EXAMINATE "mob_examinate" //from base of /mob/verb/examinate(): (atom/A), for return values, see COMSIG_CLICK_SHIFT #define COMPONENT_EXAMINATE_BLIND 3 //outputs the "something is there but you can't see it" message. #define COMSIG_MOB_DEATH "mob_death" //from base of mob/death(): (gibbed) @@ -185,7 +185,7 @@ #define SPEECH_LANGUAGE 5 // #define SPEECH_IGNORE_SPAM 6 // #define SPEECH_FORCED 7 -#define COMSIG_MOB_IS_VIEWER "mob_is_viewer" //from base of /get_actual_viewers(): (atom/center, depth, viewers_list) +#define COMSIG_MOB_FOV_VIEWER "mob_is_viewer" //from base of /fov_viewers(): (atom/center, depth, viewers_list) #define COMSIG_MOB_GET_VISIBLE_MESSAGE "mob_get_visible_message" //from base of atom/visible_message(): (atom/A, msg, range, ignored_mobs) #define COMPONENT_NO_VISIBLE_MESSAGE 1 //exactly what's said on the tin. #define COMSIG_MOB_ANTAG_ON_GAIN "mob_antag_on_gain" //from base of /datum/antagonist/on_gain(): (antag_datum) @@ -326,6 +326,9 @@ #define COMSIG_SPECIES_GAIN "species_gain" //from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species) #define COMSIG_SPECIES_LOSS "species_loss" //from datum/species/on_species_loss(): (datum/species/lost_species) +// /datum/mutation signals +#define COMSIG_HUMAN_MUTATION_LOSS "human_mutation_loss" //from datum/mutation/human/on_losing(): (datum/mutation/human/lost_mutation) + /*******Component Specific Signals*******/ //Janitor #define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values. diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 9d34bc14d2..9facaf5d70 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -20,27 +20,41 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define DF_ISPROCESSING (1<<2) //FLAGS BITMASK - -#define HEAR_1 (1<<3) // This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not. -#define CHECK_RICOCHET_1 (1<<4) // Projectiels will check ricochet on things impacted that have this. -#define CONDUCT_1 (1<<5) // conducts electricity (metal etc.) -#define NODECONSTRUCT_1 (1<<7) // For machines and structures that should not break into parts, eg, holodeck stuff -#define OVERLAY_QUEUED_1 (1<<8) // atom queued to SSoverlay -#define ON_BORDER_1 (1<<9) // item has priority to check when entering or leaving -#define PREVENT_CLICK_UNDER_1 (1<<11) //Prevent clicking things below it on the same turf eg. doors/ fulltile windows +///This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not. +#define HEAR_1 (1<<3) +///Projectiels will check ricochet on things impacted that have this. +#define CHECK_RICOCHET_1 (1<<4) +///Conducts electricity (metal etc.). +#define CONDUCT_1 (1<<5) +///For machines and structures that should not break into parts, eg, holodeck stuff. +#define NODECONSTRUCT_1 (1<<7) +///Atom queued to SSoverlay. +#define OVERLAY_QUEUED_1 (1<<8) +///Item has priority to check when entering or leaving. +#define ON_BORDER_1 (1<<9) +///Prevent clicking things below it on the same turf eg. doors/ fulltile windows. +#define PREVENT_CLICK_UNDER_1 (1<<11) #define HOLOGRAM_1 (1<<12) -#define TESLA_IGNORE_1 (1<<13) // TESLA_IGNORE grants immunity from being targeted by tesla-style electricity -#define INITIALIZED_1 (1<<14) //Whether /atom/Initialize() has already run for the object -#define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff. -#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16) /// should not get harmed if this gets caught by an explosion? -#define BLOCK_FACE_ATOM_1 (1<<17) /// Early returns mob.face_atom() +///Prevents mobs from getting chainshocked by teslas and the supermatter. +#define SHOCKED_1 (1<<13) +///Whether /atom/Initialize() has already run for the object. +#define INITIALIZED_1 (1<<14) +///was this spawned by an admin? used for stat tracking stuff. +#define ADMIN_SPAWNED_1 (1<<15) +/// should not get harmed if this gets caught by an explosion? +#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16) +/// Early returns mob.face_atom() +#define BLOCK_FACE_ATOM_1 (1<<17) //turf-only flags #define NOJAUNT_1 (1<<0) #define UNUSED_RESERVATION_TURF_1 (1<<1) -#define CAN_BE_DIRTY_1 (1<<2) // If a turf can be made dirty at roundstart. This is also used in areas. -#define NO_LAVA_GEN_1 (1<<6) //Blocks lava rivers being generated on the turf -#define NO_RUINS_1 (1<<10) //Blocks ruins spawning on the turf +///If a turf can be made dirty at roundstart. This is also used in areas. +#define CAN_BE_DIRTY_1 (1<<2) +///Blocks lava rivers being generated on the turf. +#define NO_LAVA_GEN_1 (1<<6) +///Blocks ruins spawning on the turf. +#define NO_RUINS_1 (1<<10) /* These defines are used specifically with the atom/pass_flags bitmask @@ -76,14 +90,15 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define GOLIATH_WEAKNESS (1<<9) //CIT CHANGE //tesla_zap -#define TESLA_MACHINE_EXPLOSIVE (1<<0) -#define TESLA_ALLOW_DUPLICATES (1<<1) -#define TESLA_OBJ_DAMAGE (1<<2) -#define TESLA_MOB_DAMAGE (1<<3) -#define TESLA_MOB_STUN (1<<4) +#define ZAP_MACHINE_EXPLOSIVE (1<<0) +#define ZAP_ALLOW_DUPLICATES (1<<1) +#define ZAP_OBJ_DAMAGE (1<<2) +#define ZAP_MOB_DAMAGE (1<<3) +#define ZAP_MOB_STUN (1<<4) -#define TESLA_DEFAULT_FLAGS ALL -#define TESLA_FUSION_FLAGS TESLA_OBJ_DAMAGE | TESLA_MOB_DAMAGE | TESLA_MOB_STUN +#define ZAP_DEFAULT_FLAGS ALL +#define ZAP_FUSION_FLAGS ZAP_OBJ_DAMAGE | ZAP_MOB_DAMAGE | ZAP_MOB_STUN +#define ZAP_SUPERMATTER_FLAGS NONE //EMP protection #define EMP_PROTECT_SELF (1<<0) diff --git a/code/__DEFINES/footsteps.dm b/code/__DEFINES/footsteps.dm index 16d763606b..5acda2274c 100644 --- a/code/__DEFINES/footsteps.dm +++ b/code/__DEFINES/footsteps.dm @@ -24,6 +24,15 @@ #define FOOTPRINT_SNAKE "snake" #define FOOTPRINT_DRAG "drag" +//footstep mob defines +#define FOOTSTEP_MOB_CLAW 1 +#define FOOTSTEP_MOB_BAREFOOT 2 +#define FOOTSTEP_MOB_HEAVY 3 +#define FOOTSTEP_MOB_SHOE 4 +#define FOOTSTEP_MOB_HUMAN 5 //Warning: Only works on /mob/living/carbon/human +#define FOOTSTEP_MOB_SLIME 6 +#define FOOTSTEP_MOB_CRAWL 7 + /* id = list( diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 122ba67402..28ec3383ae 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -148,50 +148,6 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isclown(A) (istype(A, /mob/living/simple_animal/hostile/retaliate/clown)) -GLOBAL_LIST_INIT(shoefootmob, typecacheof(list( - /mob/living/carbon/human/, - /mob/living/simple_animal/cow, - /mob/living/simple_animal/hostile/cat_butcherer, - /mob/living/simple_animal/hostile/faithless, - /mob/living/simple_animal/hostile/nanotrasen, - /mob/living/simple_animal/hostile/pirate, - /mob/living/simple_animal/hostile/russian, - /mob/living/simple_animal/hostile/syndicate, - /mob/living/simple_animal/hostile/wizard, - /mob/living/simple_animal/hostile/zombie, - /mob/living/simple_animal/hostile/retaliate/clown, - /mob/living/simple_animal/hostile/retaliate/spaceman, - /mob/living/simple_animal/hostile/retaliate/nanotrasenpeace, - /mob/living/simple_animal/hostile/retaliate/goat, - /mob/living/carbon/true_devil, - ))) - -GLOBAL_LIST_INIT(clawfootmob, typecacheof(list( - /mob/living/carbon/alien/humanoid, - /mob/living/simple_animal/hostile/alien, - /mob/living/simple_animal/pet/cat, - /mob/living/simple_animal/pet/dog, - /mob/living/simple_animal/pet/fox, - /mob/living/simple_animal/chicken, - /mob/living/simple_animal/hostile/bear, - /mob/living/simple_animal/hostile/jungle/mega_arachnid, - /mob/living/simple_animal/hostile/asteroid/ice_whelp, - /mob/living/simple_animal/hostile/asteroid/wolf, - /mob/living/simple_animal/hostile/asteroid/polarbear - ))) - -GLOBAL_LIST_INIT(barefootmob, typecacheof(list( - /mob/living/carbon/monkey, - /mob/living/simple_animal/pet/penguin, - /mob/living/simple_animal/hostile/gorilla, - /mob/living/simple_animal/hostile/jungle/mook - ))) - -GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list( - /mob/living/simple_animal/hostile/megafauna, - /mob/living/simple_animal/hostile/jungle/leaper - ))) - //Misc mobs #define isobserver(A) (istype(A, /mob/dead/observer)) diff --git a/code/__DEFINES/layers_planes.dm b/code/__DEFINES/layers_planes.dm index 210e5a4a35..6f33bb1a0e 100644 --- a/code/__DEFINES/layers_planes.dm +++ b/code/__DEFINES/layers_planes.dm @@ -42,6 +42,7 @@ #define BLACKNESS_PLANE 0 //To keep from conflicts with SEE_BLACKNESS internals #define BLACKNESS_PLANE_RENDER_TARGET "BLACKNESS_PLANE" +///Layers most often used by atoms of plane lower than GAME_PLANE #define SPACE_LAYER 1.8 //#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define #define MID_TURF_LAYER 2.02 @@ -61,11 +62,12 @@ #define GAS_PIPE_VISIBLE_LAYER 2.47 #define GAS_FILTER_LAYER 2.48 #define GAS_PUMP_LAYER 2.49 + #define LOW_OBJ_LAYER 2.5 #define LOW_SIGIL_LAYER 2.52 #define SIGIL_LAYER 2.54 #define HIGH_SIGIL_LAYER 2.56 - +///Layers most often used by atoms of plane equal or higher than GAME_PLANE #define BELOW_OPEN_DOOR_LAYER 2.6 #define BLASTDOOR_LAYER 2.65 #define OPEN_DOOR_LAYER 2.7 diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 0122cc68d8..c7e1d7b672 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -463,7 +463,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S #define PDAIMG(what) {""} //Filters -#define AMBIENT_OCCLUSION list("type"="drop_shadow","x"=0,"y"=-2,"size"=4,"color"="#04080FAA") +#define AMBIENT_OCCLUSION(_size, _color) list("type"="drop_shadow","x"=0,"y"=-2,"size"=_size,"color"=_color) #define EYE_BLUR(size) list("type"="blur", "size"=size) #define GRAVITY_MOTION_BLUR list("type"="motion_blur","x"=0,"y"=0) diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index affa23d30a..09cea91540 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -51,6 +51,19 @@ #define ASSEMBLY_FOURTH_STEP 3 #define ASSEMBLY_FIFTH_STEP 4 +//Bot Upgrade defines +#define UPGRADE_CLEANER_ADVANCED_MOP (1<<0) +#define UPGRADE_CLEANER_BROOM (1<<1) + +#define UPGRADE_MEDICAL_HYPOSPRAY (1<<0) +#define UPGRADE_MEDICAL_CHEM_BOARD (1<<1) +#define UPGRADE_MEDICAL_CRYO_BOARD (1<<2) +#define UPGRADE_MEDICAL_CHEM_MASTER (1<<3) +#define UPGRADE_MEDICAL_SLEEP_BOARD (1<<4) +#define UPGRADE_MEDICAL_PIERERCING (1<<5) + +#define UPGRADE_FLOOR_ARTBOX (1<<0) +#define UPGRADE_FLOOR_SYNDIBOX (1<<1) //Checks to determine borg availability depending on the server's config. These are defines in the interest of reducing copypasta #define BORG_SEC_AVAILABLE (!CONFIG_GET(flag/disable_secborg) && GLOB.security_level >= CONFIG_GET(number/minimum_secborg_alert)) diff --git a/code/__DEFINES/rust_g.config.dm b/code/__DEFINES/rust_g.config.dm deleted file mode 100644 index 68a1b42fb1..0000000000 --- a/code/__DEFINES/rust_g.config.dm +++ /dev/null @@ -1 +0,0 @@ -#define RUSTG_OVERRIDE_BUILTINS \ No newline at end of file diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm index ccd5b92c79..aeacdb7c51 100644 --- a/code/__DEFINES/rust_g.dm +++ b/code/__DEFINES/rust_g.dm @@ -1,10 +1,27 @@ // rust_g.dm - DM API for rust_g extension library #define RUST_G "rust_g" +#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET" +#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB" +#define RUSTG_JOB_ERROR "JOB PANICKED" + #define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname) +#define rustg_dmi_create_png(fname,width,height,data) call(RUST_G, "dmi_create_png")(fname,width,height,data) #define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev) #define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev) -#define rustg_log_write(fname, text) call(RUST_G, "log_write")(fname, text) +#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format) /proc/rustg_log_close_all() return call(RUST_G, "log_close_all")() + +// RUST-G defines & procs for HTTP component +#define RUSTG_HTTP_METHOD_GET "get" +#define RUSTG_HTTP_METHOD_POST "post" +#define RUSTG_HTTP_METHOD_PUT "put" +#define RUSTG_HTTP_METHOD_DELETE "delete" +#define RUSTG_HTTP_METHOD_PATCH "patch" +#define RUSTG_HTTP_METHOD_HEAD "head" + +#define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers) +#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers) +#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id) diff --git a/code/__DEFINES/skills/defines.dm b/code/__DEFINES/skills/defines.dm index 9127b4e3dd..659c0fe11b 100644 --- a/code/__DEFINES/skills/defines.dm +++ b/code/__DEFINES/skills/defines.dm @@ -27,25 +27,27 @@ #define DEF_SKILL_GAIN 1 #define SKILL_GAIN_SURGERY_PER_STEP 0.25 -#define SKILL_AFFINITY_MOOD_BONUS 1.25 +//An extra point for each few seconds of delay when using a tool. Before the multiplier. +#define SKILL_GAIN_DELAY_DIVISOR 3 SECONDS -///Items skill_flags and other defines -#define SKILL_USE_TOOL (1<<0) -#define SKILL_TRAINING_TOOL (1<<1) -#define SKILL_ATTACK_MOB (1<<2) -#define SKILL_TRAIN_ATTACK_MOB (1<<3) -#define SKILL_ATTACK_OBJ (1<<4) -#define SKILL_TRAIN_ATTACK_OBJ (1<<5) -#define SKILL_STAMINA_COST (1<<6) //Influences the stamina cost from weapon usage. -#define SKILL_THROW_STAM_COST (1<<7) -#define SKILL_COMBAT_MODE (1<<8) //The user must have combat mode on. -#define SKILL_USE_MOOD (1<<9) //Is the skill negatively affected by bad mood. -#define SKILL_TRAIN_MOOD (1<<10) //Is this skill training affected by good mood. +///Items skill_traits and other defines +#define SKILL_USE_TOOL "use_tool" +#define SKILL_TRAINING_TOOL "training_tool" +#define SKILL_ATTACK_MOB "attack_mob" +#define SKILL_TRAIN_ATTACK_MOB "train_attack_mob" +#define SKILL_ATTACK_OBJ "attack_obj" +#define SKILL_TRAIN_ATTACK_OBJ "train_attack_obj" +#define SKILL_STAMINA_COST "stamina_cost" //Influences the stamina cost from weapon usage. +#define SKILL_THROW_STAM_COST "throw_stam_cost" +#define SKILL_COMBAT_MODE "combat_mode" //The user must have combat mode on. +#define SKILL_SANITY "sanity" //Is the skill affected by (in)sanity. +#define SKILL_INTELLIGENCE "intelligence" //Is the skill affected by brain damage? -///competency_threshold index defines -#define THRESHOLD_COMPETENT 1 -#define THRESHOLD_EXPERT 2 -#define THRESHOLD_MASTER 3 +///competency_threshold defines +#define THRESHOLD_UNTRAINED "untrained" +#define THRESHOLD_COMPETENT "competent" +#define THRESHOLD_EXPERT "expert" +#define THRESHOLD_MASTER "master" /// Level/Experience skills defines. #define STD_XP_LVL_UP 100 @@ -88,11 +90,14 @@ #define MODIFIER_SKILL_BODYBOUND (1<<6) ///Adds the difference of the current value and the value stored at the time the modifier was added to the result. #define MODIFIER_SKILL_ORIGIN_DIFF (1<<7) +///Will this skill use competency thresholds instead of preset values +#define MODIFIER_USE_THRESHOLDS (1<<8) #define MODIFIER_TARGET_VALUE "value" #define MODIFIER_TARGET_LEVEL "level" #define MODIFIER_TARGET_AFFINITY "affinity" ///Ascending priority defines. +#define MODIFIER_SKILL_PRIORITY_LOW 100 #define MODIFIER_SKILL_PRIORITY_DEF 50 -#define MODIFIER_SKILL_PRIORITY_MAX 100 //max priority, meant for job/antag modifiers so they don't null out any debuff +#define MODIFIER_SKILL_PRIORITY_MAX 1 //max priority, meant for job/antag modifiers so they don't null out other (de)buffs \ No newline at end of file diff --git a/code/__DEFINES/tgs.config.dm b/code/__DEFINES/tgs.config.dm index 9f4f63a1fc..a2fcc7855a 100644 --- a/code/__DEFINES/tgs.config.dm +++ b/code/__DEFINES/tgs.config.dm @@ -4,8 +4,9 @@ #define TGS_READ_GLOBAL(Name) GLOB.##Name #define TGS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value #define TGS_WORLD_ANNOUNCE(message) to_chat(world, "[html_encode(##message)]") -#define TGS_INFO_LOG(message) log_world("TGS: Info: [##message]") -#define TGS_ERROR_LOG(message) log_world("TGS: Error: [##message]") +#define TGS_INFO_LOG(message) log_world("TGS Info: [##message]") +#define TGS_WARNING_LOG(message) log_world("TGS Warn: [##message]") +#define TGS_ERROR_LOG(message) log_world("TGS Error: [##message]") #define TGS_NOTIFY_ADMINS(event) message_admins(##event) #define TGS_CLIENT_COUNT GLOB.clients.len #define TGS_PROTECT_DATUM(Path) GENERAL_PROTECT_DATUM(##Path) diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index dcccfc9295..e164a4ec96 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -1,5 +1,7 @@ //tgstation-server DMAPI +#define TGS_DMAPI_VERSION "5.1.1" + //All functions and datums outside this document are subject to change with any version and should not be relied on //CONFIGURATION @@ -17,7 +19,6 @@ //Required interfaces (fill in with your codebase equivalent): //create a global variable named `Name` and set it to `Value` -//These globals must not be modifiable from anywhere outside of the server tools #define TGS_DEFINE_AND_SET_GLOBAL(Name, Value) //Read the value in the global variable `Name` @@ -26,10 +27,10 @@ //Set the value in the global variable `Name` to `Value` #define TGS_WRITE_GLOBAL(Name, Value) -//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game priveledge escalation +//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game use of DD -> TGS capabilities #define TGS_PROTECT_DATUM(Path) -//display an announcement `message` from the server to all players +//Display an announcement `message` from the server to all players #define TGS_WORLD_ANNOUNCE(message) //Notify current in-game administrators of a string `event` @@ -38,6 +39,9 @@ //Write an info `message` to a server log #define TGS_INFO_LOG(message) +//Write an warning `message` to a server log +#define TGS_WARNING_LOG(message) + //Write an error `message` to a server log #define TGS_ERROR_LOG(message) @@ -48,10 +52,12 @@ //EVENT CODES -#define TGS_EVENT_PORT_SWAP -2 //before a port change is about to happen, extra parameter is new port -#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //before a reboot mode change, extras parameters are the current and new reboot mode enums +#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //Before a reboot mode change, extras parameters are the current and new reboot mode enums +#define TGS_EVENT_PORT_SWAP -2 //Before a port change is about to happen, extra parameters is new port +#define TGS_EVENT_INSTANCE_RENAMED -3 //Before the instance is renamed, extra parameter is the new name +#define TGS_EVENT_WATCHDOG_REATTACH -4 //After the watchdog reattaches to DD, extra parameter is the new /datum/tgs_version of the server -//See the descriptions for these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs +//See the descriptions for the parameters of these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs #define TGS_EVENT_REPO_RESET_ORIGIN 0 #define TGS_EVENT_REPO_CHECKOUT 1 #define TGS_EVENT_REPO_FETCH 2 @@ -63,9 +69,12 @@ #define TGS_EVENT_COMPILE_START 8 #define TGS_EVENT_COMPILE_CANCELLED 9 #define TGS_EVENT_COMPILE_FAILURE 10 -#define TGS_EVENT_COMPILE_COMPLETE 11 +#define TGS_EVENT_COMPILE_COMPLETE 11 // Note, this event fires before the new .dmb is loaded into the watchdog. Consider using the TGS_EVENT_DEPLOYMENT_COMPLETE instead #define TGS_EVENT_INSTANCE_AUTO_UPDATE_START 12 #define TGS_EVENT_REPO_MERGE_CONFLICT 13 +#define TGS_EVENT_DEPLOYMENT_COMPLETE 14 +#define TGS_EVENT_WATCHDOG_SHUTDOWN 15 +#define TGS_EVENT_WATCHDOG_DETACH 16 //OTHER ENUMS @@ -80,6 +89,7 @@ //REQUIRED HOOKS //Call this somewhere in /world/New() that is always run +//IMPORTANT: This function may sleep! //event_handler: optional user defined event handler. The default behaviour is to broadcast the event in english to all connected admin channels //minimum_required_security_level: The minimum required security level to run the game in which the DMAPI is integrated /world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE) @@ -109,12 +119,12 @@ //represents a version of tgstation-server /datum/tgs_version - var/suite //The suite version, can be >=3 + var/suite //The suite/major version, can be >=3 //this group of variables can be null to represent a wild card - var/major //The major version var/minor //The minor version var/patch //The patch version + var/deprecated_patch //The legacy version var/raw_parameter //The unparsed parameter var/deprefixed_parameter //The version only bit of raw_parameter @@ -123,6 +133,10 @@ /datum/tgs_version/proc/Wildcard() return +//if the tgs_version equals some other_version +/datum/tgs_version/proc/Equals(datum/tgs_version/other_version) + return + //represents a merge of a GitHub pull request /datum/tgs_revision_information/test_merge var/number //pull request number @@ -179,14 +193,45 @@ return //Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise -//No function below this succeeds if it returns FALSE +//No function below this succeeds if it returns FALSE or if TgsNew() has yet to be called /world/proc/TgsAvailable() return +//Forces a hard reboot of BYOND by ending the process +//unlike del(world) clients will try to reconnect +//If the service has not requested a shutdown, the next server will take over +/world/proc/TgsEndProcess() + return + +//Send a message to non-admin connected chats +//message: The message to send +//admin_only: If TRUE, message will instead be sent to only admin connected chats +/world/proc/TgsTargetedChatBroadcast(message, admin_only) + return + +//Send a private message to a specific user +//message: The message to send +//user: The /datum/tgs_chat_user to send to +/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user) + return + +//The following functions will sleep if a call to TgsNew() is sleeping + +//Sends a message to connected game chats +//message: The message to send +//channels: optional channels to limit the broadcast to +/world/proc/TgsChatBroadcast(message, list/channels) + return + //Gets the current /datum/tgs_version of the server tools running the server /world/proc/TgsVersion() return +//Gets the current /datum/tgs_version of the DMAPI being used +/world/proc/TgsApiVersion() + return + +//Gets the name of the TGS instance running the game /world/proc/TgsInstanceName() return @@ -202,34 +247,10 @@ /world/proc/TgsTestMerges() return -//Forces a hard reboot of BYOND by ending the process -//unlike del(world) clients will try to reconnect -//If the service has not requested a shutdown, the next server will take over -/world/proc/TgsEndProcess() - return - //Gets a list of connected tgs_chat_channel /world/proc/TgsChatChannelInfo() return -//Sends a message to connected game chats -//message: The message to send -//channels: optional channels to limit the broadcast to -/world/proc/TgsChatBroadcast(message, list/channels) - return - -//Send a message to non-admin connected chats -//message: The message to send -//admin_only: If TRUE, message will instead be sent to only admin connected chats -/world/proc/TgsTargetedChatBroadcast(message, admin_only) - return - -//Send a private message to a specific user -//message: The message to send -//user: The /datum/tgs_chat_user to send to -/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user) - return - /* The MIT License @@ -255,4 +276,4 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ \ No newline at end of file +*/ diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 91a4a6f2c3..a63a59c75f 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -88,6 +88,7 @@ #define TRAIT_SLEEPIMMUNE "sleep_immunity" #define TRAIT_PUSHIMMUNE "push_immunity" #define TRAIT_SHOCKIMMUNE "shock_immunity" +#define TRAIT_TESLA_SHOCKIMMUNE "tesla_shock_immunity" #define TRAIT_STABLEHEART "stable_heart" #define TRAIT_STABLELIVER "stable_liver" #define TRAIT_RESISTHEAT "resist_heat" diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index a364e0b93c..889e1bb1c0 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -122,3 +122,6 @@ // misc #define VV_HK_SPACEVINE_PURGE "spacevine_purge" + +// paintings +#define VV_HK_REMOVE_PAINTING "remove_painting" diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index 86e8d1bc2b..5e57dd5328 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -1,9 +1,6 @@ //THIS FILE CONTAINS CONSTANTS, PROCS, AND OTHER THINGS// ///////////////////////////////////////////////////////// -/mob/proc/setClickCooldown(var/timeout) - next_move = max(world.time + timeout, next_move) - /proc/get_matrix_largest() var/matrix/mtrx=new() return mtrx.Scale(2) diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index e7b8560569..ba29205452 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -671,3 +671,13 @@ for(var/key in input) ret += key return ret + +/proc/is_type_in_ref_list(path, list/L) + if(!ispath(path))//not a path + return + for(var/i in L) + var/datum/D = i + if(!istype(D))//not an usable reference + continue + if(istype(D, path)) + return TRUE diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 8ef924eea4..5e0ac99bae 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -4,7 +4,9 @@ #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) -#define WRITE_LOG(log, text) rustg_log_write(log, text) +//This is an external call, "true" and "false" are how rust parses out booleans +#define WRITE_LOG(log, text) rustg_log_write(log, text, "true") +#define WRITE_LOG_NO_FORMAT(log, text) rustg_log_write(log, text, "false") //print a warning message to world.log #define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [UNLINT(src)] usr: [usr].") @@ -152,6 +154,9 @@ /proc/log_subsystem(subsystem, text) WRITE_LOG(GLOB.subsystem_log, "[subsystem]: [text]") +/proc/log_click(object, location, control, params, client/C, event = "clicked") + WRITE_LOG(GLOB.click_log, "CLICK: [C.ckey] - [event] : [object] | [location] | [control] | [params]") + /* Log to both DD and the logfile. */ /proc/log_world(text) #ifdef USE_CUSTOM_ERROR_HANDLER @@ -181,7 +186,7 @@ /proc/start_log(log) WRITE_LOG(log, "Starting up round ID [GLOB.round_id].\n-------------------------") -/* ui logging */ +/* ui logging */ /proc/log_tgui(text) WRITE_LOG(GLOB.tgui_log, text) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 6c0ffa5caa..75ac6a8b26 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -250,13 +250,13 @@ processing += A.contents //viewers() but with a signal, for blacklisting. -/proc/get_actual_viewers(depth = world.view, atom/center) +/proc/fov_viewers(depth = world.view, atom/center) if(!center) return . = viewers(depth, center) for(var/k in .) var/mob/M = k - SEND_SIGNAL(M, COMSIG_MOB_IS_VIEWER, center, depth, .) + SEND_SIGNAL(M, COMSIG_MOB_FOV_VIEWER, center, depth, .) /proc/get_mobs_in_radio_ranges(list/obj/item/radio/radios) . = list() diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index bcfaa1bed2..0b5c60a95a 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -75,6 +75,8 @@ var/datum/emote/E = new path() E.emote_list[E.key] = E + init_keybindings() + //Uplink Items for(var/path in subtypesof(/datum/uplink_item)) var/datum/uplink_item/I = path diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm index dadd4322fb..cbe1817233 100644 --- a/code/__HELPERS/sanitize_values.dm +++ b/code/__HELPERS/sanitize_values.dm @@ -18,6 +18,12 @@ return text return default +/proc/sanitize_islist(value, default) + if(islist(value) && length(value)) + return value + if(default) + return default + /proc/sanitize_inlist(value, list/List, default) if(value in List) return value diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 09047d32bf..2c8497d5ed 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -629,3 +629,45 @@ return null r += ascii2text(c) return r + +/proc/slot_to_string(slot) + switch(slot) + if(SLOT_BACK) + return "Backpack" + if(SLOT_WEAR_MASK) + return "Mask" + if(SLOT_HANDS) + return "Hands" + if(SLOT_BELT) + return "Belt" + if(SLOT_EARS) + return "Ears" + if(SLOT_GLASSES) + return "Glasses" + if(SLOT_GLOVES) + return "Gloves" + if(SLOT_NECK) + return "Neck" + if(SLOT_HEAD) + return "Head" + if(SLOT_SHOES) + return "Shoes" + if(SLOT_WEAR_SUIT) + return "Suit" + if(SLOT_W_UNIFORM) + return "Uniform" + if(SLOT_IN_BACKPACK) + return "In backpack" + +/proc/tg_ui_icon_to_cit_ui(ui_style) + switch(ui_style) + if('icons/mob/screen_plasmafire.dmi') + return 'modular_citadel/icons/ui/screen_plasmafire.dmi' + if('icons/mob/screen_slimecore.dmi') + return 'modular_citadel/icons/ui/screen_slimecore.dmi' + if('icons/mob/screen_operative.dmi') + return 'modular_citadel/icons/ui/screen_operative.dmi' + if('icons/mob/screen_clockwork.dmi') + return 'modular_citadel/icons/ui/screen_clockwork.dmi' + else + return 'modular_citadel/icons/ui/screen_midnight.dmi' diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 06dd746250..d6195b1dc6 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1600,8 +1600,13 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) //empty string - use TgsTargetBroadcast with admin_only = FALSE //other string - use TgsChatBroadcast with the tag that matches config_setting, only works with TGS4, if using TGS3 the above method is used /proc/send2chat(message, config_setting) - if(config_setting == null || !world.TgsAvailable()) + if(config_setting == null) return + + UNTIL(GLOB.tgs_initialized) + if(!world.TgsAvailable()) + return + var/datum/tgs_version/version = world.TgsVersion() if(config_setting == "" || version.suite == 3) world.TgsTargetedChatBroadcast(message, FALSE) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 52eff15492..1aab96f85e 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -132,9 +132,11 @@ GLOBAL_LIST_INIT(bitfields, list( "NO_RUINS_1" = NO_RUINS_1, "PREVENT_CLICK_UNDER_1" = PREVENT_CLICK_UNDER_1, "HOLOGRAM_1" = HOLOGRAM_1, - "TESLA_IGNORE_1" = TESLA_IGNORE_1, + "SHOCKED_1" = SHOCKED_1, "INITIALIZED_1" = INITIALIZED_1, "ADMIN_SPAWNED_1" = ADMIN_SPAWNED_1, + "BLOCK_FACE_ATOM_1" = BLOCK_FACE_ATOM_1, + "PREVENT_CONTENTS_EXPLOSION_1" = PREVENT_CONTENTS_EXPLOSION_1 ), "clothing_flags" = list( "LAVAPROTECT" = LAVAPROTECT, @@ -148,12 +150,12 @@ GLOBAL_LIST_INIT(bitfields, list( "IGNORE_HAT_TOSS" = IGNORE_HAT_TOSS, "SCAN_REAGENTS" = SCAN_REAGENTS ), - "tesla_flags" = list( - "TESLA_MOB_DAMAGE" = TESLA_MOB_DAMAGE, - "TESLA_OBJ_DAMAGE" = TESLA_OBJ_DAMAGE, - "TESLA_MOB_STUN" = TESLA_MOB_STUN, - "TESLA_ALLOW_DUPLICATES" = TESLA_ALLOW_DUPLICATES, - "TESLA_MACHINE_EXPLOSIVE" = TESLA_MACHINE_EXPLOSIVE, + "zap_flags" = list( + "ZAP_MOB_DAMAGE" = ZAP_MOB_DAMAGE, + "ZAP_OBJ_DAMAGE" = ZAP_OBJ_DAMAGE, + "ZAP_MOB_STUN" = ZAP_MOB_STUN, + "ZAP_ALLOW_DUPLICATES" = ZAP_ALLOW_DUPLICATES, + "ZAP_MACHINE_EXPLOSIVE" = ZAP_MACHINE_EXPLOSIVE, ), "smooth" = list( "SMOOTH_TRUE" = SMOOTH_TRUE, diff --git a/code/_globalvars/lists/client.dm b/code/_globalvars/lists/client.dm new file mode 100644 index 0000000000..5181d870c4 --- /dev/null +++ b/code/_globalvars/lists/client.dm @@ -0,0 +1,21 @@ +GLOBAL_LIST_EMPTY(classic_keybinding_list_by_key) +GLOBAL_LIST_EMPTY(hotkey_keybinding_list_by_key) +GLOBAL_LIST_EMPTY(keybindings_by_name) + +// This is a mapping from JS keys to Byond - ref: https://keycode.info/ +GLOBAL_LIST_INIT(_kbMap, list( + "UP" = "North", + "RIGHT" = "East", + "DOWN" = "South", + "LEFT" = "West", + "INSERT" = "Insert", + "HOME" = "Northwest", + "PAGEUP" = "Northeast", + "DEL" = "Delete", + "END" = "Southwest", + "PAGEDOWN" = "Southeast", + "SPACEBAR" = "Space", + "ALT" = "Alt", + "SHIFT" = "Shift", + "CONTROL" = "Ctrl" + )) diff --git a/code/_globalvars/lists/keybindings.dm b/code/_globalvars/lists/keybindings.dm new file mode 100644 index 0000000000..7e5b016a95 --- /dev/null +++ b/code/_globalvars/lists/keybindings.dm @@ -0,0 +1,31 @@ +/// Creates and sorts all the keybinding datums +/proc/init_keybindings() + for(var/KB in subtypesof(/datum/keybinding)) + var/datum/keybinding/keybinding = KB + if(!initial(keybinding.hotkey_keys)) + continue + add_keybinding(new keybinding) + // init_emote_keybinds() - Disabled - I don't particularly want this. + +/// Adds an instanced keybinding to the global tracker +/proc/add_keybinding(datum/keybinding/instance) + GLOB.keybindings_by_name[instance.name] = instance + + // Classic + if(LAZYLEN(instance.classic_keys)) + for(var/bound_key in instance.classic_keys) + LAZYADD(GLOB.classic_keybinding_list_by_key[bound_key], list(instance.name)) + + // Hotkey + if(LAZYLEN(instance.hotkey_keys)) + for(var/bound_key in instance.hotkey_keys) + LAZYADD(GLOB.hotkey_keybinding_list_by_key[bound_key], list(instance.name)) + +/proc/init_emote_keybinds() + for(var/i in subtypesof(/datum/emote)) + var/datum/emote/faketype = i + if(!initial(faketype.key)) + continue + var/datum/keybinding/emote/emote_kb = new + emote_kb.link_to_emote(faketype) + add_keybinding(emote_kb) diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index ba75fbfc9c..65fd772dfe 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -36,6 +36,8 @@ GLOBAL_VAR(reagent_log) GLOBAL_PROTECT(reagent_log) GLOBAL_VAR(world_crafting_log) GLOBAL_PROTECT(world_crafting_log) +GLOBAL_VAR(click_log) +GLOBAL_PROTECT(click_log) GLOBAL_LIST_EMPTY(bombers) GLOBAL_PROTECT(bombers) diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index dd8b9f0d94..1b100bebaf 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -29,6 +29,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SLEEPIMMUNE" = TRAIT_SLEEPIMMUNE, "TRAIT_PUSHIMMUNE" = TRAIT_PUSHIMMUNE, "TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE, + "TRAIT_TESLA_SHOCKIMMUNE" = TRAIT_TESLA_SHOCKIMMUNE, "TRAIT_STABLEHEART" = TRAIT_STABLEHEART, "TRAIT_STABLELIVER" = TRAIT_STABLELIVER, "TRAIT_RESISTHEAT" = TRAIT_RESISTHEAT, diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm index d7557b00d3..7a8b0a1121 100644 --- a/code/_onclick/hud/plane_master.dm +++ b/code/_onclick/hud/plane_master.dm @@ -57,7 +57,7 @@ /obj/screen/plane_master/wall/backdrop(mob/mymob) if(mymob?.client?.prefs.ambientocclusion) - add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION) + add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION(4, "#04080FAA")) else remove_filter("ambient_occlusion") @@ -70,6 +70,12 @@ . = ..() add_filter("vision_cone", 100, list(type="alpha", render_source=FIELD_OF_VISION_RENDER_TARGET, flags=MASK_INVERSE)) +/obj/screen/plane_master/above_wall/backdrop(mob/mymob) + if(mymob?.client?.prefs.ambientocclusion) + add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION(3, "#04080F64")) + else + remove_filter("ambient_occlusion") + ///Contains most things in the game world /obj/screen/plane_master/game_world name = "game world plane master" @@ -83,7 +89,7 @@ /obj/screen/plane_master/game_world/backdrop(mob/mymob) if(mymob?.client?.prefs.ambientocclusion) - add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION) + add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION(4, "#04080FAA")) else remove_filter("ambient_occlusion") diff --git a/code/_onclick/hud/screen_objects/storage.dm b/code/_onclick/hud/screen_objects/storage.dm index d7d711917d..7e8bfe12ab 100644 --- a/code/_onclick/hud/screen_objects/storage.dm +++ b/code/_onclick/hud/screen_objects/storage.dm @@ -65,6 +65,7 @@ return ..() /obj/screen/storage/volumetric_box/Destroy() + makeItemInactive() our_item = null return ..() @@ -87,10 +88,14 @@ makeItemInactive() /obj/screen/storage/volumetric_box/proc/makeItemInactive() + if(!our_item) + return our_item.layer = VOLUMETRIC_STORAGE_ITEM_LAYER our_item.plane = VOLUMETRIC_STORAGE_ITEM_PLANE /obj/screen/storage/volumetric_box/proc/makeItemActive() + if(!our_item) + return our_item.layer = VOLUMETRIC_STORAGE_ACTIVE_ITEM_LAYER //make sure we display infront of the others! our_item.plane = VOLUMETRIC_STORAGE_ACTIVE_ITEM_PLANE diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 9e120db102..3ad0219391 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -112,13 +112,13 @@ /obj/attacked_by(obj/item/I, mob/living/user) var/totitemdamage = I.force - var/bad_flag = NONE + var/bad_trait if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user)) totitemdamage *= 0.5 - bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills. + bad_trait = SKILL_COMBAT_MODE //blacklist combat skills. if(I.used_skills && user.mind) if(totitemdamage) - totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_flag) + totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait) for(var/skill in I.used_skills) if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ)) continue @@ -154,16 +154,16 @@ /mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user) . = I.force - var/bad_flag = NONE + var/bad_trait if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user)) . *= 0.5 - bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills. + bad_trait = SKILL_COMBAT_MODE //blacklist combat skills. if(!CHECK_MOBILITY(user, MOBILITY_STAND)) . *= 0.5 if(!user.mind || !I.used_skills) return if(.) - . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_flag) + . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_trait) for(var/skill in I.used_skills) if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB)) continue @@ -207,16 +207,16 @@ return 1 /// How much stamina this takes to swing this is not for realism purposes hecc off. -/obj/item/proc/getweight(mob/living/user, multiplier = 1, flags = SKILL_STAMINA_COST) +/obj/item/proc/getweight(mob/living/user, multiplier = 1, trait = SKILL_STAMINA_COST) . = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier if(!user) return - var/bad_flag = NONE + var/bad_trait if(iscarbon(user) && !(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) . *= STAM_COST_NO_COMBAT_MULT - bad_flag |= SKILL_COMBAT_MODE + bad_trait = SKILL_COMBAT_MODE if(used_skills && user.mind) - . = user.mind.item_action_skills_mod(src, ., skill_difficulty, flags, bad_flag, FALSE) + . = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, bad_trait, FALSE) /// How long this staggers for. 0 and negatives supported. /obj/item/proc/melee_stagger_duration(force_override) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index f8a66fce09..79b110a78a 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -508,6 +508,10 @@ //Allows players to set a hexadecimal color of their choice as skin tone, on top of the standard ones. /datum/config_entry/flag/allow_custom_skintones +///Initial loadout points +/datum/config_entry/number/initial_gear_points + config_entry_value = 10 + /** * Enables the FoV component, which hides objects and mobs behind the parent from their sight, unless they turn around, duh. * Camera mobs, AIs, ghosts and some other are of course exempt from this. This also doesn't influence simplemob AI, for the best. diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 166f930e33..8a1c08bc35 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -451,3 +451,18 @@ SUBSYSTEM_DEF(garbage) #endif #endif + +#ifdef TESTING +/proc/writeDatumCount() + var/list/datums = list() + for(var/datum/D in world) + datums[D.type] += 1 + for(var/datum/D) + datums[D.type] += 1 + datums = sortTim(datums, /proc/cmp_numeric_dsc, associative = TRUE) + if(fexists("data/DATUMCOUNT.txt")) + fdel("data/DATUMCOUNT.txt") + var/outfile = file("data/DATUMCOUNT.txt") + for(var/path in datums) + outfile << "[datums[path]]\t\t\t\t\t[path]" +#endif diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm index 1f8a03b3e7..7c51ba4506 100644 --- a/code/controllers/subsystem/input.dm +++ b/code/controllers/subsystem/input.dm @@ -6,13 +6,20 @@ SUBSYSTEM_DEF(input) priority = FIRE_PRIORITY_INPUT runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY - var/list/macro_sets - var/list/movement_keys + /// Classic mode input focused macro set. Manually set because we can't define ANY or ANY+UP for classic. + var/static/list/macroset_classic_input + /// Classic mode map focused macro set. Manually set because it needs to be clientside and go to macroset_classic_input. + var/static/list/macroset_classic_hotkey + /// New hotkey mode macro set. All input goes into map, game keeps incessently setting your focus to map, we can use ANY all we want here; we don't care about the input bar, the user has to force the input bar every time they want to type. + var/static/list/macroset_hotkey + + /// Macro set for hotkeys + var/list/hotkey_mode_macros + /// Macro set for classic. + var/list/input_mode_macros /datum/controller/subsystem/input/Initialize() - setup_default_macro_sets() - - setup_default_movement_keys() + setup_macrosets() initialized = TRUE @@ -20,94 +27,69 @@ SUBSYSTEM_DEF(input) return ..() -// This is for when macro sets are eventualy datumized -/datum/controller/subsystem/input/proc/setup_default_macro_sets() - var/list/static/default_macro_sets - - if(default_macro_sets) - macro_sets = default_macro_sets - return - - default_macro_sets = list( - "default" = list( - "Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"", - "O" = "ooc", - "Ctrl+O" = "looc", - "T" = "say", - "Ctrl+T" = "say_indicator", - "Y" = "whisper", - "M" = "me", - "Ctrl+M" = "me_indicator", - "5" = "subtle", - "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs - "Any" = "\"KeyDown \[\[*\]\]\"", - "Any+UP" = "\"KeyUp \[\[*\]\]\"", - ), - "old_default" = list( - "Tab" = "\".winset \\\"mainwindow.macro=old_hotkeys map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\"", - "Ctrl+T" = "say", - "Ctrl+O" = "ooc", - ), - "old_hotkeys" = list( - "Tab" = "\".winset \\\"mainwindow.macro=old_default input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"", - "O" = "ooc", - "L" = "looc", - "T" = "say", - "Ctrl+T" = "say_indicator", - "M" = "me", - "Ctrl+M" = "me_indicator", - "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs - "Any" = "\"KeyDown \[\[*\]\]\"", - "Any+UP" = "\"KeyUp \[\[*\]\]\"", - ), - ) - - // Because i'm lazy and don't want to type all these out twice - var/list/old_default = default_macro_sets["old_default"] - - var/list/static/oldmode_keys = list( +/// Sets up the key list for classic mode for when badmins screw up vv's. +/datum/controller/subsystem/input/proc/setup_macrosets() + // First, let's do the snowflake keyset! + macroset_classic_input = list() + var/list/classic_mode_keys = list( "North", "East", "South", "West", "Northeast", "Southeast", "Northwest", "Southwest", - "Insert", "Delete", "Ctrl", "Alt", + "Insert", "Delete", "Ctrl", "Alt", "Shift", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", ) + for(var/key in classic_mode_keys) + macroset_classic_input[key] = "\"KeyDown [key]\"" + macroset_classic_input["[key]+UP"] = "\"KeyUp [key]\"" + // LET'S PLAY THE BIND EVERY KEY GAME! + // oh except for Backspace and Enter; if you want to use those you shouldn't have used oldmode! + var/list/classic_ctrl_override_keys = list( + "\[", "\]", "\\\\", ";", "'", ",", ".", "/", "-", "=", "`" + ) + // i'm lazy let's play the list iteration game of numbers + for(var/i in 0 to 9) + classic_ctrl_override_keys += "[i]" + // let's play the ascii game of A to Z (UPPERCASE) + for(var/i in 65 to 90) + classic_ctrl_override_keys += ascii2text(i) + // let's play the game of clientside bind overrides! + classic_ctrl_override_keys -= list("T", "O", "M", "L") + macroset_classic_input["Ctrl+T"] = "say" + macroset_classic_input["Ctrl+O"] = "ooc" + macroset_classic_input["Ctrl+L"] = "looc" + // let's play the list iteration game x2 + for(var/key in classic_ctrl_override_keys) + // make sure to double double quote to ensure things are treated as a key combo instead of addition/semicolon logic. + macroset_classic_input["\"Ctrl+[key]\""] = "\"KeyDown [istext(classic_ctrl_override_keys[key])? classic_ctrl_override_keys[key] : key]\"" + macroset_classic_input["\"Ctrl+[key]+UP\""] = "\"KeyUp [istext(classic_ctrl_override_keys[key])? classic_ctrl_override_keys[key] : key]\"" + // Misc + macroset_classic_input["Tab"] = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_HOTKEYS] map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\"" + macroset_classic_input["Escape"] = "\".winset \\\"input.text=\\\"\\\"\\\"\"" - for(var/i in 1 to oldmode_keys.len) - var/key = oldmode_keys[i] - old_default[key] = "\"KeyDown [key]\"" - old_default["[key]+UP"] = "\"KeyUp [key]\"" + // FINALLY, WE CAN DO SOMETHING MORE NORMAL FOR THE SNOWFLAKE-BUT-LESS KEYSET. + macroset_classic_hotkey = list( + "Any" = "\"KeyDown \[\[*\]\]\"", + "Any+UP" = "\"KeyUp \[\[*\]\]\"", + "Tab" = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_INPUT] input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"", + "Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", + "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", + "O" = "ooc", + "T" = "say", + "L" = "looc", + "M" = "me" + ) - var/list/static/oldmode_ctrl_override_keys = list( - "W" = "W", "A" = "A", "S" = "S", "D" = "D", // movement - "1" = "1", "2" = "2", "3" = "3", "4" = "4", // intent - "B" = "B", // resist - "E" = "E", // quick equip - "F" = "F", // intent left - "G" = "G", // intent right - "H" = "H", // stop pulling - "Q" = "Q", // drop - "R" = "R", // throw - "X" = "X", // switch hands - "Y" = "Y", // activate item - "Z" = "Z", // activate item - ) - - for(var/i in 1 to oldmode_ctrl_override_keys.len) - var/key = oldmode_ctrl_override_keys[i] - var/override = oldmode_ctrl_override_keys[key] - old_default["Ctrl+[key]"] = "\"KeyDown [override]\"" - old_default["Ctrl+[key]+UP"] = "\"KeyUp [override]\"" - - macro_sets = default_macro_sets - -// For initially setting up or resetting to default the movement keys -/datum/controller/subsystem/input/proc/setup_default_movement_keys() - var/static/list/default_movement_keys = list( - "W" = NORTH, "A" = WEST, "S" = SOUTH, "D" = EAST, // WASD - "North" = NORTH, "West" = WEST, "South" = SOUTH, "East" = EAST, // Arrow keys & Numpad - ) - - movement_keys = default_movement_keys.Copy() + // And finally, the modern set. + macroset_hotkey = list( + "Any" = "\"KeyDown \[\[*\]\]\"", + "Any+UP" = "\"KeyUp \[\[*\]\]\"", + "Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"", + "Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", + "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", + "O" = "ooc", + "T" = "say", + "L" = "looc", + "M" = "me" + ) // Badmins just wanna have fun ♪ /datum/controller/subsystem/input/proc/refresh_client_macro_sets() @@ -115,9 +97,10 @@ SUBSYSTEM_DEF(input) for(var/i in 1 to clients.len) var/client/user = clients[i] user.set_macros() + user.update_movement_keys() /datum/controller/subsystem/input/fire() var/list/clients = GLOB.clients // Let's sing the list cache song - for(var/i in 1 to length(clients)) + for(var/i in 1 to clients.len) var/client/C = clients[i] C.keyLoop() diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm index 0a60c6e5d3..cd577e4ac6 100644 --- a/code/controllers/subsystem/persistence.dm +++ b/code/controllers/subsystem/persistence.dm @@ -24,6 +24,8 @@ SUBSYSTEM_DEF(persistence) var/list/saved_votes = list() var/list/obj/structure/sign/picture_frame/photo_frames var/list/obj/item/storage/photo_album/photo_albums + var/list/obj/structure/sign/painting/painting_frames = list() + var/list/paintings = list() /datum/controller/subsystem/persistence/Initialize() LoadSatchels() @@ -265,6 +267,7 @@ SUBSYSTEM_DEF(persistence) CollectAntagReputation() SaveRandomizedRecipes() SavePanicBunker() + SavePaintings() /datum/controller/subsystem/persistence/proc/LoadPanicBunker() var/bunker_path = file("data/bunker_passthrough.json") @@ -528,3 +531,19 @@ SUBSYSTEM_DEF(persistence) file_data["data"] = saved_votes[ckey] fdel(json_file) WRITE_FILE(json_file, json_encode(file_data)) + +/datum/controller/subsystem/persistence/proc/LoadPaintings() + var/json_file = file("data/paintings.json") + if(fexists(json_file)) + paintings = json_decode(file2text(json_file)) + + for(var/obj/structure/sign/painting/P in painting_frames) + P.load_persistent() + +/datum/controller/subsystem/persistence/proc/SavePaintings() + for(var/obj/structure/sign/painting/P in painting_frames) + P.save_persistent() + + var/json_file = file("data/paintings.json") + fdel(json_file) + WRITE_FILE(json_file, json_encode(paintings)) diff --git a/code/datums/actions/ninja.dm b/code/datums/actions/ninja.dm index b655078349..c0314b9c48 100644 --- a/code/datums/actions/ninja.dm +++ b/code/datums/actions/ninja.dm @@ -8,11 +8,11 @@ icon_icon = 'icons/mob/actions/actions_spells.dmi' /datum/action/item_action/ninjaboost - check_flags = NONE name = "Adrenaline Boost" desc = "Inject a secret chemical that will counteract all movement-impairing effect." button_icon_state = "repulse" icon_icon = 'icons/mob/actions/actions_spells.dmi' + required_mobility_flags = NONE /datum/action/item_action/ninjapulse name = "EM Burst (25E)" diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm index 7ff25eb12f..279118d877 100644 --- a/code/datums/brain_damage/phobia.dm +++ b/code/datums/brain_damage/phobia.dm @@ -44,7 +44,7 @@ return if(world.time > next_check && world.time > next_scare) next_check = world.time + 50 - var/list/seen_atoms = owner.visible_atoms(7) + var/list/seen_atoms = owner.fov_view(7) if(LAZYLEN(trigger_objs)) for(var/obj/O in seen_atoms) diff --git a/code/datums/components/art.dm b/code/datums/components/art.dm new file mode 100644 index 0000000000..f6d3cb6c61 --- /dev/null +++ b/code/datums/components/art.dm @@ -0,0 +1,56 @@ + +#define BAD_ART 12.5 +#define GOOD_ART 25 +#define GREAT_ART 50 + +/datum/component/art + var/impressiveness = 0 + +/datum/component/art/Initialize(impress) + impressiveness = impress + if(isobj(parent)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_obj_examine) + else + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_other_examine) + if(isstructure(parent)) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/on_attack_hand) + if(isitem(parent)) + RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/apply_moodlet) + +/datum/component/art/proc/apply_moodlet(mob/M, impress) + M.visible_message("[M] stops and looks intently at [parent].", \ + "You stop to take in [parent].") + switch(impress) + if (0 to BAD_ART) + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad) + if (BAD_ART to GOOD_ART) + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artok", /datum/mood_event/artok) + if (GOOD_ART to GREAT_ART) + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgood", /datum/mood_event/artgood) + if(GREAT_ART to INFINITY) + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat) + + +/datum/component/art/proc/on_other_examine(datum/source, mob/M) + apply_moodlet(M, impressiveness) + +/datum/component/art/proc/on_obj_examine(datum/source, mob/M) + var/obj/O = parent + apply_moodlet(M, impressiveness *(O.obj_integrity/O.max_integrity)) + +/datum/component/art/proc/on_attack_hand(datum/source, mob/M) + to_chat(M, "You start examining [parent]...") + if(!do_after(M, 20, target = parent)) + return + on_obj_examine(source, M) + +/datum/component/art/rev + +/datum/component/art/rev/apply_moodlet(mob/M, impress) + M.visible_message("[M] stops to inspect [parent].", \ + "You take in [parent], inspecting the fine craftsmanship of the proletariat.") + + if(M.mind && M.mind.has_antag_datum(/datum/antagonist/rev)) + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat) + else + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad) diff --git a/code/datums/components/crafting/glassware/glassware.dm b/code/datums/components/crafting/glassware/glassware.dm index 2b57837c5d..6e1a3d47a0 100644 --- a/code/datums/components/crafting/glassware/glassware.dm +++ b/code/datums/components/crafting/glassware/glassware.dm @@ -74,7 +74,7 @@ //////////////////////Lens////////////////////////// //Six Steps // -//Sells for 1800 cr, takes 15 glass shets // +//Sells for 1600 cr, takes 15 glass shets // //Usefull for selling and later crafting // //////////////////////////////////////////////////// @@ -146,14 +146,14 @@ /obj/item/glasswork/glass_base/glass_lens_part5 name = "Unpolished glass lens" - desc = "A small unpolished glass lens. Could be polished with some silk." + desc = "A small unpolished glass lens. Could be polished with some cloth." icon = 'icons/obj/glass_ware.dmi' icon_state = "glass_optics" next_step = /obj/item/glasswork/glass_base/glass_lens_part6 /obj/item/glasswork/glass_base/glass_lens_part5/attackby(obj/item/I, mob/user, params) ..() - if(istype(I, /obj/item/stack/sheet/silk)) + if(istype(I, /obj/item/stack/sheet/cloth)) if(do_after(user,10, target = src)) new next_step(user.loc, 1) qdel(src) @@ -324,7 +324,7 @@ //////////////////////Tea Plates//////////////////// //Three Steps // -//Sells for 1200 cr, takes 5 glass shets // +//Sells for 1000 cr, takes 5 glass shets // //Usefull for selling and chemical things // //////////////////////////////////////////////////// @@ -370,20 +370,20 @@ /obj/item/glasswork/glass_base/tea_plate3 name = "Disk of glass" - desc = "A disk of glass that can be cant be used for much. Needs to be polished with some silk." + desc = "A disk of glass that can be cant be used for much. Needs to be polished with some cloth." icon_state = "glass_base_half" next_step = /obj/item/tea_plate /obj/item/glasswork/glass_base/tea_plate3/attackby(obj/item/I, mob/user, params) ..() - if(istype(I, /obj/item/stack/sheet/silk)) + if(istype(I, /obj/item/stack/sheet/cloth)) if(do_after(user,10, target = src)) new next_step(user.loc, 1) qdel(src) //////////////////////Tea Cup/////////////////////// //Four Steps // -//Sells for 1800 cr, takes 6 glass shets // +//Sells for 1600 cr, takes 6 glass shets // //Usefull for selling and chemical things // //////////////////////////////////////////////////// @@ -429,13 +429,13 @@ /obj/item/glasswork/glass_base/tea_cup3 name = "Disk of glass" - desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some silk." + desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some cloth." icon_state = "glass_base_half" next_step = /obj/item/glasswork/glass_base/tea_cup4 /obj/item/glasswork/glass_base/cup3/attackby(obj/item/I, mob/user, params) ..() - if(istype(I, /obj/item/stack/sheet/silk)) + if(istype(I, /obj/item/stack/sheet/cloth)) if(do_after(user,10, target = src)) new next_step(user.loc, 1) qdel(src) diff --git a/code/datums/components/crafting/guncrafting.dm b/code/datums/components/crafting/guncrafting.dm index 89868c2332..e06583ab61 100644 --- a/code/datums/components/crafting/guncrafting.dm +++ b/code/datums/components/crafting/guncrafting.dm @@ -1,21 +1,20 @@ //Gun crafting parts til they can be moved elsewhere // PARTS // +/obj/item/weaponcrafting + icon = 'icons/obj/improvised.dmi' /obj/item/weaponcrafting/receiver name = "modular receiver" desc = "A prototype modular receiver and trigger assembly for a firearm." - icon = 'icons/obj/improvised.dmi' icon_state = "receiver" /obj/item/weaponcrafting/stock name = "rifle stock" desc = "A classic rifle stock that doubles as a grip, roughly carved out of wood." - icon = 'icons/obj/improvised.dmi' icon_state = "riflestock" -/obj/item/weaponcrafting/silkstring - name = "silkstring" - desc = "A long piece of silk with some resemblance to cable coil." - icon = 'icons/obj/improvised.dmi' - icon_state = "silkstring" +/obj/item/weaponcrafting/durathread_string + name = "durathread string" + desc = "A long piece of durathread with some resemblance to cable coil." + icon_state = "durastring" diff --git a/code/datums/components/crafting/recipes/recipes_clothing.dm b/code/datums/components/crafting/recipes/recipes_clothing.dm index 02dd3f2c05..7a7379c834 100644 --- a/code/datums/components/crafting/recipes/recipes_clothing.dm +++ b/code/datums/components/crafting/recipes/recipes_clothing.dm @@ -39,14 +39,14 @@ time = 10 reqs = list(/obj/item/paper = 20) category = CAT_CLOTHING - + /datum/crafting_recipe/armwraps name = "Armwraps" result = /obj/item/clothing/gloves/fingerless/pugilist time = 60 tools = list(TOOL_WIRECUTTER) reqs = list(/obj/item/stack/sheet/cloth = 4, - /obj/item/stack/sheet/silk = 2, + /obj/item/stack/sheet/durathread = 2, /obj/item/stack/sheet/leather = 2) category = CAT_CLOTHING diff --git a/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm index 318587f5cb..206895178a 100644 --- a/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm +++ b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm @@ -192,7 +192,7 @@ result = /obj/item/gun/ballistic/bow/pipe reqs = list(/obj/item/pipe = 5, /obj/item/stack/sheet/plastic = 15, - /obj/item/weaponcrafting/silkstring = 5) + /obj/item/weaponcrafting/durathread_string = 5) time = 450 category = CAT_WEAPONRY subcategory = CAT_WEAPON @@ -281,7 +281,7 @@ result = /obj/item/ammo_casing/caseless/arrow/wood time = 30 reqs = list(/obj/item/stack/sheet/mineral/wood = 1, - /obj/item/stack/sheet/silk = 1, + /obj/item/stack/sheet/durathread = 1, /obj/item/stack/rods = 1) // 1 metal sheet = 2 rods = 2 arrows category = CAT_WEAPONRY subcategory = CAT_AMMO diff --git a/code/datums/components/field_of_vision.dm b/code/datums/components/field_of_vision.dm index b819604168..5fb7b2596c 100644 --- a/code/datums/components/field_of_vision.dm +++ b/code/datums/components/field_of_vision.dm @@ -86,10 +86,10 @@ RegisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT, .proc/on_mob_logout) RegisterSignal(M, COMSIG_MOB_GET_VISIBLE_MESSAGE, .proc/on_visible_message) RegisterSignal(M, COMSIG_MOB_EXAMINATE, .proc/on_examinate) - RegisterSignal(M, COMSIG_MOB_VISIBLE_ATOMS, .proc/on_visible_atoms) + RegisterSignal(M, COMSIG_MOB_FOV_VIEW, .proc/on_fov_view) RegisterSignal(M, COMSIG_MOB_CLIENT_CHANGE_VIEW, .proc/on_change_view) RegisterSignal(M, COMSIG_MOB_RESET_PERSPECTIVE, .proc/on_reset_perspective) - RegisterSignal(M, COMSIG_MOB_IS_VIEWER, .proc/is_viewer) + RegisterSignal(M, COMSIG_MOB_FOV_VIEWER, .proc/is_viewer) /datum/component/field_of_vision/UnregisterFromParent() . = ..() @@ -109,8 +109,8 @@ UNREGISTER_NESTED_LOCS(nested_locs, COMSIG_MOVABLE_MOVED, 1) UnregisterSignal(M, list(COMSIG_MOB_CLIENT_LOGIN, COMSIG_MOB_CLIENT_LOGOUT, COMSIG_MOB_GET_VISIBLE_MESSAGE, COMSIG_MOB_EXAMINATE, - COMSIG_MOB_VISIBLE_ATOMS, COMSIG_MOB_RESET_PERSPECTIVE, - COMSIG_MOB_CLIENT_CHANGE_VIEW, COMSIG_MOB_IS_VIEWER)) + COMSIG_MOB_FOV_VIEW, COMSIG_MOB_RESET_PERSPECTIVE, + COMSIG_MOB_CLIENT_CHANGE_VIEW, COMSIG_MOB_FOV_VIEWER)) /** * Generates the holder and images (if not generated yet) and adds them to client.images. @@ -296,7 +296,7 @@ if(fov.alpha) FOV_ANGLE_CHECK(source, target, return, return COMPONENT_NO_VISIBLE_MESSAGE) -/datum/component/field_of_vision/proc/on_visible_atoms(mob/source, list/atoms) +/datum/component/field_of_vision/proc/on_fov_view(mob/source, list/atoms) if(!fov.alpha) return for(var/k in atoms) diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm index fbf559fe35..f767c607a5 100644 --- a/code/datums/components/footstep.dm +++ b/code/datums/components/footstep.dm @@ -1,26 +1,52 @@ +///Footstep component. Plays footsteps at parents location when it is appropriate. /datum/component/footstep + ///How many steps the parent has taken since the last time a footstep was played var/steps = 0 + ///volume determines the extra volume of the footstep. This is multiplied by the base volume, should there be one. var/volume + ///e_range stands for extra range - aka how far the sound can be heard. This is added to the base value and ignored if there isn't a base value. var/e_range + ///footstep_type is a define which determines what kind of sounds should get chosen. + var/footstep_type + ///This can be a list OR a soundfile OR null. Determines whatever sound gets played. + var/footstep_sounds -/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1) +/datum/component/footstep/Initialize(footstep_type_ = FOOTSTEP_MOB_BAREFOOT, volume_ = 0.5, e_range_ = -1) if(!isliving(parent)) return COMPONENT_INCOMPATIBLE volume = volume_ e_range = e_range_ - RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep) + footstep_type = footstep_type_ + switch(footstep_type) + if(FOOTSTEP_MOB_HUMAN) + if(!ishuman(parent)) + return COMPONENT_INCOMPATIBLE + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/play_humanstep) + return + if(FOOTSTEP_MOB_CLAW) + footstep_sounds = GLOB.clawfootstep + if(FOOTSTEP_MOB_BAREFOOT) + footstep_sounds = GLOB.barefootstep + if(FOOTSTEP_MOB_HEAVY) + footstep_sounds = GLOB.heavyfootstep + if(FOOTSTEP_MOB_SHOE) + footstep_sounds = GLOB.footstep + if(FOOTSTEP_MOB_SLIME) + footstep_sounds = 'sound/effects/footstep/slime1.ogg' + if(FOOTSTEP_MOB_CRAWL) + footstep_sounds = 'sound/effects/footstep/crawl1.ogg' + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/play_simplestep) //Note that this doesn't get called for humans. -/datum/component/footstep/proc/play_footstep() +///Prepares a footstep. Determines if it should get played. Returns the turf it should get played on. Note that it is always a /turf/open +/datum/component/footstep/proc/prepare_step() var/turf/open/T = get_turf(parent) if(!istype(T)) return var/mob/living/LM = parent - var/v = volume - var/e = e_range if(!T.footstep || LM.buckled || !CHECK_MOBILITY(LM, MOBILITY_STAND) || LM.buckled || LM.throwing || (LM.movement_type & (VENTCRAWLING | FLYING))) if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying - playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v) + playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * volume) return if(HAS_TRAIT(LM, TRAIT_SILENT_STEP)) @@ -30,79 +56,83 @@ var/mob/living/carbon/C = LM if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG)) return - if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK) - v /= 2 - e -= 5 + if(C.m_intent == MOVE_INTENT_WALK) + return steps++ - if(steps >= 3) + if(steps >= 6) steps = 0 - else + if(steps % 2) return - if(prob(80) && !LM.has_gravity(T)) // don't need to step as often when you hop around + if(steps != 0 && !LM.has_gravity(T)) // don't need to step as often when you hop around return + return T - //begin playsound shenanigans// - - //for barefooted non-clawed mobs like monkeys - if(isbarefoot(LM)) - playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]), - GLOB.barefootstep[T.barefootstep][2] * v, - TRUE, - GLOB.barefootstep[T.barefootstep][3] + e) +/datum/component/footstep/proc/play_simplestep() + var/turf/open/T = prepare_step() + if(!T) return - - //for xenomorphs, dogs, and other clawed mobs - if(isclawfoot(LM)) - if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps - v /= 3 - e -= 5 - - playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]), - GLOB.clawfootstep[T.clawfootstep][2] * v, - TRUE, - GLOB.clawfootstep[T.clawfootstep][3] + e) + if(isfile(footstep_sounds) || istext(footstep_sounds)) + playsound(T, footstep_sounds, volume) return - - //for megafauna and other large and imtimidating mobs such as the bloodminer - if(isheavyfoot(LM)) - playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]), - GLOB.heavyfootstep[T.heavyfootstep][2] * v, - TRUE, - GLOB.heavyfootstep[T.heavyfootstep][3] + e) + var/turf_footstep + switch(footstep_type) + if(FOOTSTEP_MOB_CLAW) + turf_footstep = T.clawfootstep + if(FOOTSTEP_MOB_BAREFOOT) + turf_footstep = T.barefootstep + if(FOOTSTEP_MOB_HEAVY) + turf_footstep = T.heavyfootstep + if(FOOTSTEP_MOB_SHOE) + turf_footstep = T.footstep + if(!turf_footstep) return + playsound(T, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range) - //for slimes - if(isslime(LM)) - playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v) +/datum/component/footstep/proc/play_humanstep() + var/turf/open/T = prepare_step() + if(!T) return - - //for (simple) humanoid mobs (clowns, russians, pirates, etc.) - if(isshoefoot(LM)) - if(!ishuman(LM)) - playsound(T, pick(GLOB.footstep[T.footstep][1]), - GLOB.footstep[T.footstep][2] * v, - TRUE, - GLOB.footstep[T.footstep][3] + e) - return - if(ishuman(LM)) //for proper humans, they're special - var/mob/living/carbon/human/H = LM - var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET))) - - if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature - playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v) + var/mob/living/carbon/human/H = parent + var/list/L = GLOB.barefootstep + var/turf_footstep = T.barefootstep + var/special = FALSE + if(H.physiology.footstep_type) + switch(H.physiology.footstep_type) + if(FOOTSTEP_MOB_CLAW) + turf_footstep = T.clawfootstep + L = GLOB.clawfootstep + if(FOOTSTEP_MOB_BAREFOOT) + turf_footstep = T.barefootstep + L = GLOB.barefootstep + if(FOOTSTEP_MOB_HEAVY) + turf_footstep = T.heavyfootstep + L = GLOB.heavyfootstep + if(FOOTSTEP_MOB_SHOE) + turf_footstep = T.footstep + L = GLOB.footstep + if(FOOTSTEP_MOB_SLIME) + playsound(T, 'sound/effects/footstep/slime1.ogg', 50 * volume) return + if(FOOTSTEP_MOB_CRAWL) + playsound(T, 'sound/effects/footstep/crawl1.ogg', 50 * volume) + return + special = TRUE + else + var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET))) + if(feetCover) //are we wearing shoes + playsound(T, pick(GLOB.footstep[T.footstep][1]), + GLOB.footstep[T.footstep][2] * volume, + TRUE, + GLOB.footstep[T.footstep][3] + e_range) + return - if(feetCover) //are we wearing shoes - playsound(T, pick(GLOB.footstep[T.footstep][1]), - GLOB.footstep[T.footstep][2] * v, - TRUE, - GLOB.footstep[T.footstep][3] + e) - - if(!feetCover) //are we NOT wearing shoes - playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]), - GLOB.barefootstep[T.barefootstep][2] * v, - TRUE, - GLOB.barefootstep[T.barefootstep][3] + e) \ No newline at end of file + if(!special && H.dna.species.special_step_sounds) + playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE) + else + playsound(T, pick(L[turf_footstep][1]), + L[turf_footstep][2] * volume, + TRUE, + L[turf_footstep][3] + e_range) diff --git a/code/datums/components/material_container.dm b/code/datums/components/material_container.dm index 2f411ff37f..5860bd029b 100644 --- a/code/datums/components/material_container.dm +++ b/code/datums/components/material_container.dm @@ -73,7 +73,7 @@ if(!material_amount) to_chat(user, "[I] does not contain sufficient materials to be accepted by [parent].") return - if(!has_space(material_amount)) + if((!precise_insertion || !GLOB.typecache_stack[I]) && !has_space(material_amount)) to_chat(user, "[parent] has not enough space. Please remove materials from [parent] in order to insert more.") return user_insert(I, user) diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm index 6a32a46aef..f5da669c3a 100644 --- a/code/datums/components/rotation.dm +++ b/code/datums/components/rotation.dm @@ -23,18 +23,12 @@ if(can_user_rotate) src.can_user_rotate = can_user_rotate - else - src.can_user_rotate = CALLBACK(src,.proc/default_can_user_rotate) if(can_be_rotated) src.can_be_rotated = can_be_rotated - else - src.can_be_rotated = CALLBACK(src,.proc/default_can_be_rotated) if(after_rotation) src.after_rotation = after_rotation - else - src.after_rotation = CALLBACK(src,.proc/default_after_rotation) //Try Clockwise,counter,flip in order if(src.rotation_flags & ROTATION_FLIP) @@ -103,14 +97,34 @@ examine_list += "Alt-click to rotate it clockwise." /datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction) - if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation)) - return + if(can_be_rotated) + if(!can_be_rotated.Invoke(user, default_rotation_direction)) + return + else + if(!default_can_be_rotated(user, default_rotation_direction)) + return + if(can_user_rotate) + if(!can_user_rotate.Invoke(user, default_rotation_direction)) + return + else + if(!default_can_user_rotate(user, default_rotation_direction)) + return BaseRot(user, rotation) return TRUE /datum/component/simple_rotation/proc/WrenchRot(datum/source, obj/item/I, mob/living/user) - if(!can_be_rotated.Invoke(user,default_rotation_direction) || !can_user_rotate.Invoke(user,default_rotation_direction)) - return + if(can_be_rotated) + if(!can_be_rotated.Invoke(user, default_rotation_direction)) + return + else + if(!default_can_be_rotated(user, default_rotation_direction)) + return + if(can_user_rotate) + if(!can_user_rotate.Invoke(user, default_rotation_direction)) + return + else + if(!default_can_user_rotate(user, default_rotation_direction)) + return if(istype(I,/obj/item/wrench)) BaseRot(user,default_rotation_direction) return COMPONENT_NO_AFTERATTACK @@ -126,7 +140,10 @@ if(ROTATION_FLIP) rot_degree = 180 AM.setDir(turn(AM.dir,rot_degree)) - after_rotation.Invoke(user,rotation_type) + if(after_rotation) + after_rotation.Invoke(user, rotation_type) + else + default_after_rotation(user, rotation_type) /datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type) if(!istype(user) || !user.canUseTopic(parent, BE_CLOSE, NO_DEXTERY)) diff --git a/code/datums/components/storage/concrete/_concrete.dm b/code/datums/components/storage/concrete/_concrete.dm index e044a59668..55c3e1d083 100644 --- a/code/datums/components/storage/concrete/_concrete.dm +++ b/code/datums/components/storage/concrete/_concrete.dm @@ -136,9 +136,7 @@ var/mob/M = parent.loc I.dropped(M) if(new_location) - //Reset the items values - _removal_reset(AM) - AM.forceMove(new_location) + AM.forceMove(new_location) // exited comsig will handle removal reset. //We don't want to call this if the item is being destroyed AM.on_exit_storage(src) else diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 68ba0e4272..f93d40bb04 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -351,7 +351,6 @@ return master._removal_reset(thing) /datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing) - _removal_reset(thing) if(LAZYACCESS(ui_item_blocks, thing)) var/obj/screen/storage/volumetric_box/center/C = ui_item_blocks[thing] for(var/i in can_see_contents()) //runtimes result if mobs can access post deletion. @@ -359,6 +358,7 @@ M.client?.screen -= C.on_screen_objects() ui_item_blocks -= thing qdel(C) + _removal_reset(thing) // THIS NEEDS TO HAPPEN AFTER SO LAYERING DOESN'T BREAK! refresh_mob_views() //Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted @@ -572,7 +572,7 @@ if(rustle_sound) playsound(parent, "rustle", 50, 1, -5) to_chat(user, "You put [I] [insert_preposition]to [parent].") - for(var/mob/viewing in get_actual_viewers(world.view, user)-M) + for(var/mob/viewing in fov_viewers(world.view, user)-M) if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is... viewing.show_message("[M] puts [I] [insert_preposition]to [parent].", MSG_VISUAL) else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance... diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index a7a61802d3..216d82b4c8 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -145,4 +145,10 @@ return !is_mouth_covered() /mob/living/carbon/CanSpreadAirborneDisease() - return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.armor.getRating("bio") >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.armor.getRating("bio") >= 25))) \ No newline at end of file + return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.armor.getRating("bio") >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.armor.getRating("bio") >= 25))) + +/mob/living/proc/set_shocked() + flags_1 |= SHOCKED_1 + +/mob/living/proc/reset_shocked() + flags_1 &= ~ SHOCKED_1 \ No newline at end of file diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 26786da776..747db3d6ce 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -47,8 +47,8 @@ destination.dna.uni_identity = uni_identity destination.dna.blood_type = blood_type destination.dna.skin_tone_override = skin_tone_override - destination.set_species(species.type, icon_update=0) destination.dna.features = features.Copy() + destination.set_species(species.type, icon_update=0) destination.dna.real_name = real_name destination.dna.nameless = nameless destination.dna.custom_species = custom_species @@ -246,6 +246,17 @@ construct_block(GLOB.mam_body_markings_list.Find(features["mam_body_markings"]), GLOB.mam_body_markings_list.len) if(DNA_TAUR_BLOCK) construct_block(GLOB.taur_list.Find(features["taur"]), GLOB.taur_list.len) + if(species.mutant_bodyparts["taur"] && ishuman(holder)) + var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]] + switch(T?.taur_mode) + if(STYLE_HOOF_TAURIC) + H.physiology.footstep_type = FOOTSTEP_MOB_SHOE + if(STYLE_PAW_TAURIC) + H.physiology.footstep_type = FOOTSTEP_MOB_CLAW + if(STYLE_SNEK_TAURIC) + H.physiology.footstep_type = FOOTSTEP_MOB_CRAWL + else + H.physiology.footstep_type = null //Please use add_mutation or activate_mutation instead /datum/dna/proc/force_give(datum/mutation/human/HM) diff --git a/code/datums/elements/dwarfism.dm b/code/datums/elements/dwarfism.dm new file mode 100644 index 0000000000..fefbe4fbe7 --- /dev/null +++ b/code/datums/elements/dwarfism.dm @@ -0,0 +1,42 @@ +#define SHORT 4/5 +#define TALL 5/4 + +///Very similar to squish, but for dwarves and shorties +/datum/element/dwarfism + element_flags = ELEMENT_DETACH|ELEMENT_BESPOKE + id_arg_index = 2 + var/comsig + var/list/attached_targets = list() + +/datum/element/dwarfism/Attach(datum/target, comsig, comsig_target) + . = ..() + if(!isliving(target)) + return ELEMENT_INCOMPATIBLE + + src.comsig = comsig + + var/mob/living/L = target + if(L.lying != 0) + L.transform = L.transform.Scale(SHORT, 1) + else + L.transform = L.transform.Scale(1, SHORT) + attached_targets[target] = comsig_target + RegisterSignal(target, comsig, .proc/check_loss) //Second arg of the signal will be checked against the comsig_target. + +/datum/element/dwarfism/proc/check_loss(mob/living/L, comsig_target) + if(attached_targets[L] == comsig_target) + Detach(L) + +/datum/element/dwarfism/Detach(mob/living/L) + . = ..() + if(QDELETED(L)) + return + if(L.lying != 0) + L.transform = L.transform.Scale(TALL, 1) + else + L.transform = L.transform.Scale(1, TALL) + UnregisterSignal(L, comsig) + attached_targets -= L + +#undef SHORT +#undef TALL diff --git a/code/datums/elements/wuv.dm b/code/datums/elements/wuv.dm index fffb90c681..6476a204cf 100644 --- a/code/datums/elements/wuv.dm +++ b/code/datums/elements/wuv.dm @@ -41,7 +41,7 @@ return //we want to delay the effect to be displayed after the mob is petted, not before. switch(user.a_intent) - if(INTENT_HARM, INTENT_DISARM) + if(INTENT_HARM) addtimer(CALLBACK(src, .proc/kick_the_dog, source, user), 1) if(INTENT_HELP) addtimer(CALLBACK(src, .proc/pet_the_dog, source, user), 1) diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index 0b0fed407c..91b8e32566 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -5,16 +5,18 @@ var/list/testmerge = list() /datum/getrev/New() + commit = rustg_git_revparse("HEAD") + if(commit) + date = rustg_git_commit_date(commit) + originmastercommit = rustg_git_revparse("origin/master") + +/datum/getrev/proc/load_tgs_info() testmerge = world.TgsTestMerges() var/datum/tgs_revision_information/revinfo = world.TgsRevision() if(revinfo) commit = revinfo.commit originmastercommit = revinfo.origin_commit - else - commit = rustg_git_revparse("HEAD") - if(commit) - date = rustg_git_commit_date(commit) - originmastercommit = rustg_git_revparse("origin/master") + date = rustg_git_commit_date(commit) // goes to DD log and config_error.txt log_world(get_log_message()) @@ -77,7 +79,9 @@ msg += "No commit information" if(world.TgsAvailable()) var/datum/tgs_version/version = world.TgsVersion() - msg += "Server tools version: [version.raw_parameter]" + msg += "TGS version: [version.raw_parameter]" + var/datum/tgs_version/api_version = world.TgsApiVersion() + msg += "DMAPI version: [api_version.raw_parameter]" // Game mode odds msg += "
Current Informational Settings:" @@ -121,4 +125,4 @@ if(probabilities[ctag] > 0) var/percentage = round(probabilities[ctag] / sum * 100, 0.1) msg += "[ctag] [percentage]%" - to_chat(src, msg.Join("
")) \ No newline at end of file + to_chat(src, msg.Join("
")) diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 1464927c3a..c56425b074 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -248,7 +248,7 @@ description = "Something I recently ate was horrifyingly disgusting.\n" mood_change = -5 timeout = 5 MINUTES - + /datum/mood_event/nanite_sadness description = "+++++++HAPPINESS SUPPRESSION+++++++\n" mood_change = -7 @@ -256,3 +256,7 @@ /datum/mood_event/nanite_sadness/add_effects(message) description = "+++++++[message]+++++++\n" +/datum/mood_event/artbad + description = "I've produced better art than that from my ass.\n" + mood_change = -2 + timeout = 1200 diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index 1e9a53cf57..95177f6869 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -182,3 +182,17 @@ description = "What a peculiar emblem. It makes me feel hopeful for my future.\n" mood_change = 5 +/datum/mood_event/artok + description = "It's nice to see people are making art around here.\n" + mood_change = 2 + timeout = 2 MINUTES + +/datum/mood_event/artgood + description = "What a thought-provoking piece of art. I'll remember that for a while.\n" + mood_change = 3 + timeout = 3 MINUTES + +/datum/mood_event/artgreat + description = "That work of art was so great it made me believe in the goodness of humanity. Says a lot in a place like this.\n" + mood_change = 4 + timeout = 4 MINUTES diff --git a/code/datums/mutations/_mutations.dm b/code/datums/mutations/_mutations.dm index 9edaa7605c..db739c5100 100644 --- a/code/datums/mutations/_mutations.dm +++ b/code/datums/mutations/_mutations.dm @@ -116,7 +116,8 @@ owner.apply_overlay(layer_used) if(power) owner.RemoveSpell(power) - qdel(src) + qdel(power) + SEND_SIGNAL(owner, COMSIG_HUMAN_MUTATION_LOSS, src) return 0 return 1 diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 9f8c74e2db..866ea85dbf 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -82,7 +82,7 @@ if(..()) return ADD_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION) - owner.transform = owner.transform.Scale(1, 0.8) + owner.AddElement(/datum/element/dwarfism, COMSIG_HUMAN_MUTATION_LOSS, src) passtable_on(owner, GENETIC_MUTATION) owner.visible_message("[owner] suddenly shrinks!", "Everything around you seems to grow..") @@ -90,7 +90,6 @@ if(..()) return REMOVE_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION) - owner.transform = owner.transform.Scale(1, 1.25) passtable_off(owner, GENETIC_MUTATION) owner.visible_message("[owner] suddenly grows!", "Everything around you seems to shrink..") diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm index 41ef52e317..571a8274d8 100644 --- a/code/datums/skills/_skill.dm +++ b/code/datums/skills/_skill.dm @@ -20,18 +20,20 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) var/desc /// Color of the name as shown in the html readout var/name_color = "#F0F0F0" // White on dark surface. - /// Our progression type + /// Our progression type. These are mostly used to skip typechecks overhead, don't go around messing with these. var/progression_type /// Abstract type var/abstract_type = /datum/skill /// List of max levels. Only used in level skills, but present here for helper macros. var/max_levels = INFINITY - /// skill threshold used in generic skill competency calculations. - var/list/competency_thresholds = list(0, 0, 0) - /// Multiplier of the difference of the holder skill value and the selected threshold. - var/list/competency_mults = list(0, 0, 0) - /// In which way this skil can affect or be affected through actions and skill modifiers. - var/skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD + /// skill threshold used in generic skill competency operations. + var/list/competency_thresholds + /// Base multiplier used in skill competency operations. + var/base_multiplier = 1 + /// Value added to the base multiplier depending on overall competency compared to maximum value/level. + var/competency_multiplier = 1 + /// A list of ways this skill can affect or be affected through actions and skill modifiers. + var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE) /** * Ensures what someone's setting as a value for this skill is valid. @@ -66,8 +68,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /datum/skill/binary abstract_type = /datum/skill/binary progression_type = SKILL_PROGRESSION_BINARY - competency_thresholds = list(FALSE, TRUE, TRUE) - competency_mults = list(0.5, 0.5, 0.5) + competency_thresholds = list(THRESHOLD_COMPETENT = FALSE, THRESHOLD_EXPERT = TRUE, THRESHOLD_MASTER = TRUE) /datum/skill/binary/sanitize_value(new_value) return new_value? TRUE : FALSE @@ -78,6 +79,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /datum/skill/numerical abstract_type = /datum/skill/numerical progression_type = SKILL_PROGRESSION_NUMERICAL + competency_thresholds = list(THRESHOLD_COMPETENT = 25, THRESHOLD_EXPERT = 50, THRESHOLD_MASTER = 75) /// Max value of this skill var/max_value = 100 /// Min value of this skill @@ -180,8 +182,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /datum/skill/level/job abstract_type = /datum/skill/level/job levels = list("Basic", "Trained", "Experienced", "Master") - competency_thresholds = list(JOB_SKILL_TRAINED, JOB_SKILL_EXPERT, JOB_SKILL_MASTER) - competency_mults = list(0.15, 0.1, 0.1) + competency_thresholds = list(THRESHOLD_COMPETENT = JOB_SKILL_TRAINED, THRESHOLD_EXPERT = JOB_SKILL_EXPERT, THRESHOLD_MASTER = JOB_SKILL_MASTER) associative = TRUE //quite the reference, no? @@ -195,7 +196,6 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) "Proficient", "Talented", "Adept", "Expert", "Professional", "Accomplished", "Great", "Master", "High Master", "Grand Master", "Legendary") - competency_thresholds = list(DORF_SKILL_COMPETENT, DORF_SKILL_EXPERT, DORF_SKILL_MASTER) - competency_mults = list(0.15, 0.1, 0.08) + competency_thresholds = list(THRESHOLD_COMPETENT = DORF_SKILL_COMPETENT, THRESHOLD_EXPERT = DORF_SKILL_EXPERT, THRESHOLD_MASTER = DORF_SKILL_MASTER) associative = TRUE unskilled_tier = "Dabbling" diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm index 500b49a1ff..071db3306a 100644 --- a/code/datums/skills/_skill_holder.dm +++ b/code/datums/skills/_skill_holder.dm @@ -122,16 +122,22 @@ * * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor. */ /datum/mind/proc/action_skill_mod(skill, value, threshold, modifier_is_multiplier = TRUE) - var/mod var/datum/skill/S = GLOB.skill_datums[skill] if(!S) - return + return value + var/mod = S.base_multiplier switch(S.progression_type) if(SKILL_PROGRESSION_LEVEL) - mod = get_skill_level(S.type) + var/datum/skill/level/L = S + var/skill_lvl = get_skill_level(L.type) + mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[threshold]-skill_lvl, 0))*L.competency_multiplier + if(SKILL_PROGRESSION_NUMERICAL) + var/datum/skill/numerical/N = S + var/skill_val = get_skill_value(N.type) + mod += skill_val/(N.max_value+max(N.competency_thresholds[threshold]-skill_val, 0))*N.competency_multiplier else - mod = get_skill_value(S.type) - mod = (1+(mod-S.competency_thresholds[threshold])*S.competency_mults[threshold]) + var/comp_threshold = S.competency_thresholds[threshold] + mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier . = modifier_is_multiplier ? value*mod : value/mod /** @@ -139,29 +145,42 @@ * Args: * * item/I : the item used in this action. its used_skills list variable contains the skills exercised with it. * * value : the value to modify, may be a delay, damage, probability. - * * flags : the required flags that each skill (either in I.used_skills or the skill datum skill_flags) must have to influence + * * traits : the required traits each skill (either in I.used_skills or the skill datum skill_traits) must have to influence * * the value. - * * bad_flags : the opposite of the above, skills that must not be present to impact the value. + * * bad_traits : the opposite of the above. * * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor. */ -/datum/mind/proc/item_action_skills_mod(obj/item/I, value, flags = NONE, bad_flags = NONE, modifier_is_multiplier = TRUE) +/datum/mind/proc/item_action_skills_mod(obj/item/I, value, traits, bad_traits, modifier_is_multiplier = TRUE) . = value var/sum = 0 var/divisor = 0 + var/one_trait = istext(traits) + var/one_bad_trait = istext(bad_traits) for(var/k in I.used_skills) var/datum/skill/S = GLOB.skill_datums[k] if(!S) continue - var/our_flags = (I.used_skills[k]|S.skill_flags) - if((flags && !(our_flags & flags)) || (bad_flags && our_flags & bad_flags)) + var/our_traits = S.skill_traits + our_traits |= I.used_skills[k] + if(traits && !(one_trait ? (traits in our_traits) : length(our_traits & traits))) continue - var/mod + if(bad_traits && (one_bad_trait ? (bad_traits in our_traits) : length(our_traits & bad_traits))) + continue + var/mod = S.base_multiplier switch(S.progression_type) if(SKILL_PROGRESSION_LEVEL) - mod = get_skill_level(S.type) + var/datum/skill/level/L = S + var/skill_lvl = get_skill_level(L.type) + mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[I.skill_difficulty]-skill_lvl, 0))*L.competency_multiplier + if(SKILL_PROGRESSION_NUMERICAL) + var/datum/skill/numerical/N = S + var/skill_val = get_skill_value(N.type) + mod += skill_val/(N.max_value+max(N.competency_thresholds[I.skill_difficulty]-skill_val, 0))*N.competency_multiplier else - mod = get_skill_value(S.type) - sum += 1+(mod - S.competency_thresholds[I.skill_difficulty])*S.competency_mults[I.skill_difficulty] + var/comp_threshold = S.competency_thresholds[I.skill_difficulty] + mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier + sum += mod + divisor++ if(divisor) . = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor) diff --git a/code/datums/skills/_skill_modifier.dm b/code/datums/skills/_skill_modifier.dm index b0115194a7..a28cf3aebd 100644 --- a/code/datums/skills/_skill_modifier.dm +++ b/code/datums/skills/_skill_modifier.dm @@ -9,11 +9,13 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill) /datum/skill_modifier /// flags for this skill modifier. var/modifier_flags = NONE - /// target skills, can be a specific skill typepath or a set of skill flags. - var/target_skills = NONE + /// target skills, can be a specific skill typepath or a list of skill traits. + var/target_skills = /datum/skill + /// the GLOB.potential_skills_per_mod key generated on runtime. You shouldn't be var-editing it. + var/target_skills_key /// The identifier key this skill modifier is associated with. var/identifier - /// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags flags. + /// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags. var/affinity_mod = 1 /// skill value modifier, see above. var/value_mod = 1 @@ -38,21 +40,25 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill) CRASH("Skill modifier identifier \"[identifier]\" already taken.") GLOB.skill_modifiers[identifier] = src if(ispath(target_skills)) + target_skills_key = target_skills var/list/mod_L = GLOB.potential_mods_per_skill[target_skills] if(!mod_L) mod_L = GLOB.potential_mods_per_skill[target_skills] = list() else BINARY_INSERT(identifier, mod_L, datum/skill_modifier, src, priority, COMPARE_VALUE) mod_L[identifier] = src - GLOB.potential_skills_per_mod["[target_skills]"] = list(target_skills) - else //Should be a bitfield. - var/list/L = GLOB.potential_skills_per_mod["[target_skills]"] + GLOB.potential_skills_per_mod[target_skills_key] = list(target_skills) + else //Should be a list. + var/list/T = target_skills + T = sortTim(target_skills, /proc/cmp_text_asc) //Sort the list contents alphabetically. + target_skills_key = T.Join("-") + var/list/L = GLOB.potential_skills_per_mod[target_skills_key] if(!L) L = list() for(var/path in GLOB.skill_datums) - if(GLOB.skill_datums[path].skill_flags & target_skills) + if(GLOB.skill_datums[path].skill_traits & target_skills) L += path - GLOB.potential_skills_per_mod["[target_skills]"] = L + GLOB.potential_skills_per_mod[target_skills_key] = L for(var/path in L) var/list/mod_L = GLOB.potential_mods_per_skill[path] if(!mod_L) @@ -62,7 +68,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill) mod_L[identifier] = src /datum/skill_modifier/Destroy() - for(var/path in GLOB.potential_skills_per_mod["[target_skills]"]) + for(var/path in GLOB.potential_skills_per_mod[target_skills_key]) var/mod_L = GLOB.potential_mods_per_skill[path] mod_L -= identifier if(!length(mod_L)) @@ -96,7 +102,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill) LAZYINITLIST(skill_holder.skill_affinity_mods) if(M.modifier_flags & MODIFIER_SKILL_LEVEL) LAZYINITLIST(skill_holder.skill_level_mods) - for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"]) + for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key]) if(M.modifier_flags & MODIFIER_SKILL_VALUE) ADD_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values, get_skill_value(path, FALSE)) if(M.modifier_flags & MODIFIER_SKILL_AFFINITY) @@ -127,7 +133,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill) if(!skill_holder.skill_value_mods && !skill_holder.skill_affinity_mods && !skill_holder.skill_level_mods) return - for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"]) + for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key]) if(M.modifier_flags & MODIFIER_SKILL_VALUE && skill_holder.skill_value_mods) REMOVE_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values) if(M.modifier_flags & MODIFIER_SKILL_AFFINITY && skill_holder.skill_affinity_mods) @@ -155,6 +161,18 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill) if(MODIFIER_TARGET_AFFINITY) mod = affinity_mod + if(modifier_flags & MODIFIER_USE_THRESHOLDS && istext(mod)) + var/datum/skill/S = GLOB.skill_datums[skillpath] + if(method == MODIFIER_TARGET_VALUE && S.progression_type == SKILL_PROGRESSION_LEVEL) + var/datum/skill/level/L = S + switch(L.level_up_method) + if(STANDARD_LEVEL_UP) + mod = XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod]) + if(DWARFY_LEVEL_UP) + mod = DORF_XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod]) + else + mod = S.competency_thresholds[mod] + var/diff = 0 if(modifier_flags & (MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_HANDICAP)) if(modifier_flags & MODIFIER_SKILL_VIRTUE) diff --git a/code/datums/skills/engineering.dm b/code/datums/skills/engineering.dm index 59c9436e46..db7b33450c 100644 --- a/code/datums/skills/engineering.dm +++ b/code/datums/skills/engineering.dm @@ -2,5 +2,4 @@ name = "Wiring" desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor." name_color = COLOR_PALE_ORANGE - competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER) - skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD|SKILL_USE_TOOL|SKILL_TRAINING_TOOL + skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL) diff --git a/code/datums/skills/medical.dm b/code/datums/skills/medical.dm index aaae1236a6..404c141157 100644 --- a/code/datums/skills/medical.dm +++ b/code/datums/skills/medical.dm @@ -2,4 +2,4 @@ name = "Surgery" desc = "How proficient you are at doing surgery." name_color = COLOR_PALE_BLUE_GRAY - competency_mults = list(0.025, 0.025, 0.025) // 60% surgery speed up at max value of 100. + competency_multiplier = 1.5 // 60% surgery speed up at max value of 100, considering the base multiplier. diff --git a/code/datums/skills/modifiers/mood.dm b/code/datums/skills/modifiers/mood.dm index 2ab74bdbbb..30f24afcc4 100644 --- a/code/datums/skills/modifiers/mood.dm +++ b/code/datums/skills/modifiers/mood.dm @@ -1,8 +1,8 @@ /datum/skill_modifier/bad_mood modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND - target_skills = SKILL_USE_MOOD + target_skills = list(SKILL_SANITY) /datum/skill_modifier/great_mood modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND - target_skills = SKILL_TRAIN_MOOD + target_skills = list(SKILL_SANITY) affinity_mod = 1.2 diff --git a/code/datums/skills/modifiers/organs.dm b/code/datums/skills/modifiers/organs.dm new file mode 100644 index 0000000000..13ebaf0658 --- /dev/null +++ b/code/datums/skills/modifiers/organs.dm @@ -0,0 +1,13 @@ +/datum/skill_modifier/brain_damage + target_skills = list(SKILL_INTELLIGENCE) + modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND + value_mod = 0.85 + level_mod = 0.85 + affinity_mod = 0.85 + +/datum/skill_modifier/heavy_brain_damage + target_skills = list(SKILL_INTELLIGENCE) + modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_BODYBOUND|MODIFIER_SKILL_HANDICAP|MODIFIER_USE_THRESHOLDS + priority = MODIFIER_SKILL_PRIORITY_LOW + value_mod = THRESHOLD_COMPETENT + level_mod = THRESHOLD_COMPETENT diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index ce6e2782e4..130988867d 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -120,11 +120,13 @@ /datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration) . = ..() ADD_TRAIT(owner, TRAIT_MUTE, "mesmerize") + ADD_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize") owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize) /datum/status_effect/mesmerize/on_remove() . = ..() REMOVE_TRAIT(owner, TRAIT_MUTE, "mesmerize") + REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize") owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize) /datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration) diff --git a/code/datums/tgs_event_handler.dm b/code/datums/tgs_event_handler.dm new file mode 100644 index 0000000000..a3324121bf --- /dev/null +++ b/code/datums/tgs_event_handler.dm @@ -0,0 +1,20 @@ +/datum/tgs_event_handler/impl/HandleEvent(event_code, ...) + switch(event_code) + if(TGS_EVENT_REBOOT_MODE_CHANGE) + var/list/reboot_mode_lookup = list ("[TGS_REBOOT_MODE_NORMAL]" = "be normal", "[TGS_REBOOT_MODE_SHUTDOWN]" = "shutdown the server", "[TGS_REBOOT_MODE_RESTART]" = "hard restart the server") + var old_reboot_mode = args[2] + var new_reboot_mode = args[3] + message_admins("TGS: Reboot will no longer [reboot_mode_lookup["[old_reboot_mode]"]], it will instead [reboot_mode_lookup["[new_reboot_mode]"]]") + if(TGS_EVENT_PORT_SWAP) + message_admins("TGS: Changing port from [world.port] to [args[2]]") + if(TGS_EVENT_INSTANCE_RENAMED) + message_admins("TGS: Instance renamed to from [world.TgsInstanceName()] to [args[2]]") + if(TGS_EVENT_COMPILE_START) + message_admins("TGS: Deployment started, new game version incoming...") + if(TGS_EVENT_COMPILE_CANCELLED) + message_admins("TGS: Deployment cancelled!") + if(TGS_EVENT_COMPILE_FAILURE) + message_admins("TGS: Deployment failed!") + if(TGS_EVENT_DEPLOYMENT_COMPLETE) + message_admins("TGS: Deployment complete!") + to_chat(world, "Server updated, changes will be applied on the next round...") diff --git a/code/game/atoms.dm b/code/game/atoms.dm index a63f63f4a4..1ff27bafa9 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -581,6 +581,14 @@ SEND_SIGNAL(src, COMSIG_ATOM_RCD_ACT, user, the_rcd, passed_mode) return FALSE +/** + * Respond to a electric bolt action on our item + * + * Default behaviour is to return, we define here to allow for cleaner code later on + */ +/atom/proc/zap_act(power, zap_flags, shocked_targets) + return + /atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user) if(GetComponent(/datum/component/storage)) return component_storage_contents_dump_act(src_object, user) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 206864d44c..9736f473e8 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -37,6 +37,8 @@ var/throwforce = 0 var/datum/component/orbiter/orbiting var/can_be_z_moved = TRUE + ///If we were without gravity and another animation happened, the bouncing will stop, and we need to restart it in next life(). + var/floating_need_update = FALSE var/zfalling = FALSE @@ -492,15 +494,16 @@ /atom/movable/proc/float(on) if(throwing) return - if(on && !(movement_type & FLOATING)) + if(on && (!(movement_type & FLOATING) || floating_need_update)) animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1) sleep(10) animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1) - setMovetype(movement_type | FLOATING) - else if (!on && (movement_type & FLOATING)) + if(!(movement_type & FLOATING)) + setMovetype(movement_type | FLOATING) + else if (!on && movement_type & FLOATING) animate(src, pixel_y = initial(pixel_y), time = 10) setMovetype(movement_type & ~FLOATING) - + floating_need_update = FALSE /* Language procs * Unless you are doing something very specific, these are the ones you want to use. diff --git a/code/game/gamemodes/gangs/dominator.dm b/code/game/gamemodes/gangs/dominator.dm index dca50be5b9..af75315ded 100644 --- a/code/game/gamemodes/gangs/dominator.dm +++ b/code/game/gamemodes/gangs/dominator.dm @@ -48,9 +48,6 @@ /obj/machinery/dominator/hulk_damage() return (max_integrity - integrity_failure) / DOM_HULK_HITS_REQUIRED -/obj/machinery/dominator/tesla_act() - qdel(src) - /obj/machinery/dominator/update_icon() cut_overlays() if(stat & BROKEN) diff --git a/code/game/gamemodes/gangs/gang_decals.dm b/code/game/gamemodes/gangs/gang_decals.dm index 7aaed769d9..a37b4cb63b 100644 --- a/code/game/gamemodes/gangs/gang_decals.dm +++ b/code/game/gamemodes/gangs/gang_decals.dm @@ -10,7 +10,7 @@ /obj/effect/decal/cleanable/crayon/gang icon = 'icons/effects/crayondecal.dmi' layer = ABOVE_NORMAL_TURF_LAYER //Harder to hide - plane = GAME_PLANE + plane = ABOVE_WALL_PLANE do_icon_rotate = FALSE //These are designed to always face south, so no rotation please. var/datum/team/gang/gang diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 470c26ed0f..e2f26d6617 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -522,11 +522,11 @@ Class Procs: /obj/machinery/proc/can_be_overridden() . = 1 -/obj/machinery/tesla_act(power, tesla_flags, shocked_objects) - ..() - if(prob(85) && (tesla_flags & TESLA_MACHINE_EXPLOSIVE)) +/obj/machinery/zap_act(power, zap_flags, shocked_objects) + . = ..() + if(prob(85) && (zap_flags & ZAP_MACHINE_EXPLOSIVE)) explosion(src, 1, 2, 4, flame_range = 2, adminlog = FALSE, smoke = FALSE) - if(tesla_flags & TESLA_OBJ_DAMAGE) + else if(zap_flags & ZAP_OBJ_DAMAGE) take_damage(power/2000, BURN, "energy") if(prob(40)) emp_act(EMP_LIGHT) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 5bfef9f925..7b92fb58d8 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -290,8 +290,6 @@ operating = TRUE do_animate("closing") layer = closingLayer - if(!safe) - crush() sleep(5) density = TRUE sleep(5) @@ -303,6 +301,8 @@ update_freelook_sight() if(safe) CheckForMobs() + else + crush() return 1 /obj/machinery/door/proc/CheckForMobs() diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 3a79ff3c82..621e486e90 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -34,7 +34,7 @@ GLOBAL_LIST_EMPTY(network_holopads) desc = "It's a floor-mounted device for projecting holographic images." icon_state = "holopad0" layer = LOW_OBJ_LAYER - plane = FLOOR_PLANE + plane = ABOVE_WALL_PLANE flags_1 = HEAR_1 use_power = IDLE_POWER_USE idle_power_usage = 5 diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index f9f4eb3e80..1730569e10 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -115,8 +115,8 @@ return PROCESS_KILL /obj/machinery/space_heater/RefreshParts() - var/laser = 0 - var/cap = 0 + var/laser = 2 + var/cap = 1 for(var/obj/item/stock_parts/micro_laser/M in component_parts) laser += M.rating for(var/obj/item/stock_parts/capacitor/M in component_parts) @@ -166,6 +166,11 @@ else return ..() +/obj/machinery/space_heater/wrench_act(mob/living/user, obj/item/I) + ..() + default_unfasten_wrench(user, I, 5) + return TRUE + /obj/machinery/space_heater/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm index f618888d98..dcd86c9f24 100644 --- a/code/game/machinery/wishgranter.dm +++ b/code/game/machinery/wishgranter.dm @@ -11,9 +11,6 @@ var/insisting = 0 /obj/machinery/wish_granter/attack_hand(mob/living/carbon/user) - . = ..() - if(.) - return if(charges <= 0) to_chat(user, "The Wish Granter lies silent.") return @@ -22,22 +19,116 @@ to_chat(user, "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's.") return - else if(is_special_character(user)) - to_chat(user, "Even to a heart as dark as yours, you know nothing good will come of this. Something instinctual makes you pull away.") - else if (!insisting) to_chat(user, "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?") insisting++ else - to_chat(user, "You speak. [pick("I want the station to disappear","Humanity is corrupt, mankind must be destroyed","I want to be rich", "I want to rule the world","I want immortality.")]. The Wish Granter answers.") - to_chat(user, "Your head pounds for a moment, before your vision clears. You are the avatar of the Wish Granter, and your power is LIMITLESS! And it's all yours. You need to make sure no one can take it from you. No one can know, first.") + if(is_special_character(user)) + to_chat(user, "You speak. [pick("I want power","Humanity is corrupt, mankind must be destroyed", "I want to rule the world","I want immortality")]. The Wish Granter answers.") + to_chat(user, "Your head pounds for a moment, before your vision clears. The Wish Granter, sensing the darkness in your heart, has given you limitless power, and it's all yours!") + user.dna.add_mutation(HULK) + user.dna.add_mutation(XRAY) + user.dna.add_mutation(SPACEMUT) + user.dna.add_mutation(TK) + user.next_move_modifier *= 0.5 //half the delay between attacks! + to_chat(user, "Things around you feel slower!") + charges-- + insisting = FALSE + to_chat(user, "You have a very great feeling about this!") + else + to_chat(user, "The Wish Granter awaits your wish.") + var/wish = input("You want...","Wish") as null|anything in list("Power","Wealth","The Station To Disappear","To Kill","Nothing") + switch(wish) + if("Power") //Gives infinite power in exchange for infinite power going off in your face! + if(charges <= 0) + return + to_chat(user, "Your wish is granted, but at a terrible cost...") + to_chat(user, "The Wish Granter punishes you for your selfishness, warping itself into a delaminating supermatter shard!") + var/obj/item/stock_parts/cell/infinite/powah = new /obj/item/stock_parts/cell/infinite(get_turf(user)) + if(user.put_in_hands(powah)) + to_chat(user, "[powah] materializes into your hands!") + else + to_chat(user, "[powah] materializes onto the floor.") + var/obj/machinery/power/supermatter_crystal/powerwish = new /obj/machinery/power/supermatter_crystal(loc) + powerwish.damage = 700 //right at the emergency threshold + powerwish.produces_gas = FALSE + charges-- + insisting = FALSE + if(!charges) + qdel(src) + if("Wealth") //Gives 1 million space bucks in exchange for being turned into gold! + if(charges <= 0) + return + to_chat(user, "Your wish is granted, but at a cost...") + to_chat(user, "The Wish Granter punishes you for your selfishness, warping your body to match the greed in your heart.") + new /obj/structure/closet/crate/trashcart/moneywish(loc) + new /obj/structure/closet/crate/trashcart/moneywish(loc) + user.set_species(/datum/species/golem/gold) + charges-- + insisting = FALSE + if(!charges) + qdel(src) + if("The Station To Disappear") //teleports you to the station and makes you blind, making the station disappear for you! + if(charges <= 0) + return + to_chat(user, "Your wish is 'granted', but at a terrible cost...") + to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your eyes to match the darkness in your heart.") + user.dna.add_mutation(BLINDMUT) + var/obj/item/organ/eyes/eyes = user.getorganslot(ORGAN_SLOT_EYES) + if(eyes) + eyes.applyOrganDamage(eyes.maxHealth) + var/list/destinations = list() + for(var/obj/item/beacon/B in GLOB.teleportbeacons) + var/turf/T = get_turf(B) + if(is_station_level(T.z)) + destinations += B + var/chosen_beacon = pick(destinations) + var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), src, 100, null, FALSE, get_turf(chosen_beacon)) + try_move_adjacent(J) + playsound(src,'sound/effects/sparks4.ogg',50,1) + charges-- + insisting = FALSE + if(!charges) + qdel(src) + if("To Kill") //Makes you kill things in exchange for rewards! + if(charges <= 0) + return + to_chat(user, "Your wish is granted, but at a terrible cost...") + to_chat(user, "The Wish Granter punishes you for your wickedness, warping itself into a dastardly creature for you to kill! ...but it almost seems to reward you for this.") + var/obj/item/melee/transforming/energy/sword/cx/killreward = new /obj/item/melee/transforming/energy/sword/cx(get_turf(user)) + if(user.put_in_hands(killreward)) + to_chat(user, "[killreward] materializes into your hands!") + else + to_chat(user, "[killreward] materializes onto the floor.") + user.next_move_modifier *= 0.8 //20% less delay between attacks! + to_chat(user, "Things around you feel slightly slower!") + var/mob/living/simple_animal/hostile/venus_human_trap/killwish = new /mob/living/simple_animal/hostile/venus_human_trap(loc) + killwish.maxHealth = 1500 + killwish.health = killwish.maxHealth + killwish.vine_grab_distance = 6 + killwish.melee_damage_upper = 30 + killwish.loot = list(/obj/item/dualsaber/hypereutactic) + charges-- + insisting = FALSE + if(!charges) + qdel(src) + if("Nothing") //Makes the wish granter disappear + if(charges <= 0) + return + to_chat(user, "The Wish Granter vanishes from sight!") + to_chat(user, "You feel as if you just narrowly avoided a terrible fate...") + charges-- + insisting = FALSE + qdel(src) - charges-- - insisting = 0 +//ITEMS THAT IT USES - user.mind.add_antag_datum(/datum/antagonist/wishgranter) +/obj/structure/closet/crate/trashcart/moneywish + desc = "A heavy, metal trashcart with wheels. Filled with cash." + name = "loaded trash cart" - to_chat(user, "You have a very bad feeling about this.") - - return +/obj/structure/closet/crate/trashcart/moneywish/PopulateContents() //25*20*1000=500,000 + for(var/i in 1 to 25) + var/obj/item/stack/spacecash/c1000/lodsamoney = new /obj/item/stack/spacecash/c1000(src) + lodsamoney.amount = lodsamoney.max_amount diff --git a/code/game/mecha/combat/neovgre.dm b/code/game/mecha/combat/neovgre.dm index c678912a21..fdcc4df151 100644 --- a/code/game/mecha/combat/neovgre.dm +++ b/code/game/mecha/combat/neovgre.dm @@ -62,18 +62,21 @@ /obj/mecha/combat/neovgre/process() ..() - if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hople to stop the superweapon + if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hope to stop the superweapon cell.charge = INFINITY max_integrity = INFINITY obj_integrity = max_integrity CHECK_TICK //Just to be on the safe side lag wise - else if(cell.charge < cell.maxcharge) - for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src)) - var/delta = min(recharge_rate, cell.maxcharge - cell.charge) - if (get_clockwork_power() <= delta) - cell.charge += delta - adjust_clockwork_power(-delta) - CHECK_TICK + else + if(cell.charge < cell.maxcharge) + for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src)) + var/delta = min(recharge_rate, cell.maxcharge - cell.charge) + if (get_clockwork_power() >= delta) + cell.charge += delta + adjust_clockwork_power(-delta) + if(obj_integrity < max_integrity && istype(loc, /turf/open/floor/clockwork)) + obj_integrity += min(max_integrity - obj_integrity, max_integrity / 200) + CHECK_TICK /obj/mecha/combat/neovgre/Initialize() .=..() @@ -90,7 +93,7 @@ energy_drain = 30 name = "Aribter Laser Cannon" desc = "Please re-attach this to neovgre and stop asking questions about why it looks like a normal Nanotrasen issue Solaris laser cannon - Nezbere" - fire_sound = "sound/weapons/neovgre_laser.ogg" + fire_sound = 'sound/weapons/neovgre_laser.ogg' /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/can_attach(obj/mecha/combat/neovgre/M) if(istype(M)) diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm index 53768fe9a9..1fe7f74dec 100644 --- a/code/game/mecha/mecha_defense.dm +++ b/code/game/mecha/mecha_defense.dm @@ -77,7 +77,7 @@ /obj/mecha/attack_animal(mob/living/simple_animal/user) mecha_log_message("Attack by simple animal. Attacker - [user].", color="red") if(!user.melee_damage_upper && !user.obj_damage) - user.emote("custom", message = "[user.friendly] [src].") + user.emote("custom", message = "[user.friendly_verb_continuous] [src].") return 0 else var/play_soundeffect = 1 diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm index 955b9935dd..8cfdad0432 100644 --- a/code/game/objects/effects/decals/crayon.dm +++ b/code/game/objects/effects/decals/crayon.dm @@ -3,7 +3,7 @@ desc = "Graffiti. Damn kids." icon = 'icons/effects/crayondecal.dmi' icon_state = "rune1" - plane = GAME_PLANE //makes the graffiti visible over a wall. + plane = ABOVE_WALL_PLANE //makes the graffiti visible over a wall. gender = NEUTER mergeable_decal = FALSE var/do_icon_rotate = TRUE diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm index 3e7706282a..5dbd18aa0c 100644 --- a/code/game/objects/effects/decals/decal.dm +++ b/code/game/objects/effects/decals/decal.dm @@ -35,6 +35,7 @@ icon = 'icons/turf/decals.dmi' icon_state = "warningline" layer = TURF_DECAL_LAYER + plane = ABOVE_WALL_PLANE /obj/effect/turf_decal/Initialize() ..() diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 992e9c84a7..6910bb1db0 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -469,6 +469,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player) /obj/effect/landmark/stationroom var/list/templates = list() layer = BULLET_HOLE_LAYER + plane = ABOVE_WALL_PLANE /obj/effect/landmark/stationroom/New() ..() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index a8422dedc0..2a4b6d7df5 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -135,7 +135,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) ///Skills vars //list of skill PATHS exercised when using this item. An associated bitfield can be set to indicate additional ways the skill is used by this specific item. var/list/datum/skill/used_skills - var/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general. + var/skill_difficulty = THRESHOLD_UNTRAINED //how difficult it's to use this item in general. var/skill_gain = DEF_SKILL_GAIN //base skill value gain from using this item. /obj/item/Initialize() @@ -805,7 +805,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) if(delay) if(user.mind && used_skills) - delay = user.mind.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, NONE, FALSE) + delay = user.mind.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, null, FALSE) // Create a callback with checks that would be called every tick by do_after. var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks) @@ -831,11 +831,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) if(delay >= MIN_TOOL_SOUND_DELAY) play_tool_sound(target, volume) + if(user.mind && used_skills && skill_gain_mult) + var/gain = skill_gain + delay/SKILL_GAIN_DELAY_DIVISOR for(var/skill in used_skills) - if(!(used_skills[skill] & SKILL_TRAINING_TOOL)) + if(!(SKILL_TRAINING_TOOL in used_skills[skill])) continue - user.mind.auto_gain_experience(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level)) + user.mind.auto_gain_experience(skill, gain*skill_gain_mult, GET_STANDARD_LVL(max_level)) return TRUE diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index 0676c439f0..cb44b82ad2 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -143,7 +143,7 @@ RLD //if user can't be seen from A (only checks surroundings' opaqueness) and can't see A. //jarring, but it should stop people from targetting atoms they can't see... //excluding darkness, to allow RLD to be used to light pitch black dark areas. - if(!((user in view(view_range, A)) || (user in get_actual_viewers(view_range, A)))) + if(!((user in view(view_range, A)) || (user in fov_viewers(view_range, A)))) to_chat(user, "You focus, pointing \the [src] at whatever outside your field of vision in that direction... to no avail.") return FALSE return TRUE diff --git a/code/game/objects/items/apc_frame.dm b/code/game/objects/items/apc_frame.dm index 1f6dff490d..3640db2d8a 100644 --- a/code/game/objects/items/apc_frame.dm +++ b/code/game/objects/items/apc_frame.dm @@ -58,18 +58,22 @@ /obj/item/wallframe/proc/after_attach(var/obj/O) transfer_fingerprints_to(O) -/obj/item/wallframe/attackby(obj/item/W, mob/user, params) - ..() - if(istype(W, /obj/item/screwdriver)) - // For camera-building borgs - var/turf/T = get_step(get_turf(user), user.dir) - if(iswallturf(T)) - T.attackby(src, user, params) +/obj/item/wallframe/screwdriver_act(mob/user, obj/item/I) + . = ..() + if(.) + return + // For camera-building borgs + var/turf/T = get_step(get_turf(user), user.dir) + if(iswallturf(T)) + T.attackby(src, user) +/obj/item/wallframe/wrench_act(mob/user, obj/item/I) + if(!custom_materials) + return var/metal_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]/MINERAL_MATERIAL_AMOUNT) var/glass_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)]/MINERAL_MATERIAL_AMOUNT) - if(istype(W, /obj/item/wrench) && (metal_amt || glass_amt)) + if(metal_amt || glass_amt) to_chat(user, "You dismantle [src].") if(metal_amt) new /obj/item/stack/sheet/metal(get_turf(src), metal_amt) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index f60edf2917..a4ed8dedd1 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -91,6 +91,11 @@ refill() +/obj/item/toy/crayon/examine(mob/user) + . = ..() + if(can_change_colour) + . += "Ctrl-click [src] while it's on your person to quickly recolour it." + /obj/item/toy/crayon/proc/refill() if(charges == -1) charges_left = 100 @@ -160,6 +165,12 @@ update_icon() return TRUE +/obj/item/toy/crayon/CtrlClick(mob/user) + if(can_change_colour && !isturf(loc) && user.canUseTopic(src, BE_CLOSE, ismonkey(user))) + select_colour(user) + else + return ..() + /obj/item/toy/crayon/proc/staticDrawables() . = list() @@ -237,14 +248,7 @@ else paint_mode = PAINT_NORMAL if("select_colour") - if(can_change_colour) - var/chosen_colour = input(usr,"","Choose Color",paint_color) as color|null - - if (!isnull(chosen_colour)) - paint_color = chosen_colour - . = TRUE - else - . = FALSE + . = can_change_colour && select_colour(usr) if("enter_text") var/txt = stripped_input(usr,"Choose what to write.", "Scribbles",default = text_buffer) @@ -254,6 +258,13 @@ drawtype = "a" update_icon() +/obj/item/toy/crayon/proc/select_colour(mob/user) + var/chosen_colour = input(user, "", "Choose Color", paint_color) as color|null + if (!isnull(chosen_colour) && user.canUseTopic(src, BE_CLOSE, ismonkey(user))) + paint_color = chosen_colour + return TRUE + return FALSE + /obj/item/toy/crayon/proc/crayon_text_strip(text) var/static/regex/crayon_r = new /regex(@"[^\w!?,.=%#&+\/\-]") return replacetext(lowertext(text), crayon_r, "") diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 92c2d40c98..b683ea9934 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -433,7 +433,7 @@ H.visible_message("The defibrillator safely discharges the excessive charge into the floor!") return var/mob/living/M = H.pulledby - if(M.electrocute_act(30, src)) + if(M.electrocute_act(30, H)) M.visible_message("[M] is electrocuted by [M.p_their()] contact with [H]!") M.emote("scream") diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 1d2a2c9ad1..c931d92379 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -135,7 +135,7 @@ outmsg = "You miss the lens of [C] with [src]!" //catpeople - var/list/viewers = get_actual_viewers(1,targloc) + var/list/viewers = fov_viewers(1,targloc) for(var/mob/living/carbon/human/H in viewers) if(!iscatperson(H) || H.incapacitated() || H.eye_blind ) continue diff --git a/code/game/objects/items/implants/implantpad.dm b/code/game/objects/items/implants/implantpad.dm index f0fc76a2e2..4766e534c9 100644 --- a/code/game/objects/items/implants/implantpad.dm +++ b/code/game/objects/items/implants/implantpad.dm @@ -66,7 +66,7 @@ if(ismob(loc)) attack_self(loc) else - for(var/mob/M in get_actual_viewers(1, src)) + for(var/mob/M in fov_viewers(1, src)) if(M.client) attack_self(M) add_fingerprint(usr) diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index fc7b196bd2..1459afeb2d 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -197,10 +197,10 @@ if(obj_integrity >= max_integrity) to_chat(user, "[src] is already in perfect condition.") else - var/obj/item/stack/sheet/mineral/titanium/T = W - T.use(1) + var/obj/item/stack/S = W + S.use(1) obj_integrity = max_integrity - to_chat(user, "You repair [src] with [T].") + to_chat(user, "You repair [src] with [S].") else return ..() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index f19dbb2a6b..aebc5121cd 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -5,7 +5,6 @@ * Wood * Bamboo * Cloth - * Silk * Durathread * Cardboard * Runed Metal (cult) @@ -268,6 +267,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 50),\ null, \ new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 10),\ + new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 10),\ new/datum/stack_recipe("mortar", /obj/item/reagent_containers/glass/mortar, 3), \ new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 10),\ )) @@ -388,6 +388,9 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \ null, \ new/datum/stack_recipe("blindfold", /obj/item/clothing/glasses/sunglasses/blindfold, 2), \ null, \ + new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteenXnineteen, 3), \ + new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythreeXnineteen, 4), \ + new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythreeXtwentythree, 5), \ )) /obj/item/stack/sheet/cloth @@ -401,7 +404,6 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \ throwforce = 0 pull_effort = 90 is_fabric = TRUE - loom_result = /obj/item/stack/sheet/silk merge_type = /obj/item/stack/sheet/cloth /obj/item/stack/sheet/cloth/get_main_recipes() @@ -414,30 +416,6 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \ /obj/item/stack/sheet/cloth/thirty amount = 30 -/* - * Silk - */ - - GLOBAL_LIST_INIT(silk_recipes, list ( \ - new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 4, time = 40), \ - new/datum/stack_recipe("white gloves", /obj/item/clothing/gloves/color/white, 2, time = 40), \ - null, \ - new/datum/stack_recipe("silk string", /obj/item/weaponcrafting/silkstring, 1, time = 40), \ - )) - -/obj/item/stack/sheet/silk - name = "silk" - desc = "A long, soft material. Made out of refined cotton, instead of relying on the habits of spiders or silkworms." - singular_name = "silk sheet" - icon_state = "sheet-silk" - item_state = "sheet-cloth" - novariants = TRUE - merge_type = /obj/item/stack/sheet/silk - -/obj/item/stack/sheet/silk/get_main_recipes() - . = ..() - . += GLOB.silk_recipes - /* * Durathread */ @@ -446,6 +424,7 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \ new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 40), \ new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 40), \ new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 25), \ + new/datum/stack_recipe("durathread string", /obj/item/weaponcrafting/durathread_string, 1, time = 40) \ )) /obj/item/stack/sheet/durathread diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 52802fa3df..5b7eb65d9b 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -61,7 +61,7 @@ switch(contents.len) if(0) icon_state = "[initial(icon_state)]" - if(0 to 11) + if(1 to 11) icon_state = "[initial(icon_state)]1" if(11 to 20) icon_state = "[initial(icon_state)]2" diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index 57e9ea9aaa..de5f332f43 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -210,6 +210,7 @@ power = 8 force = 10 precision = 1 + total_mass = 0.2 cooling_power = 5 w_class = WEIGHT_CLASS_HUGE item_flags = ABSTRACT // don't put in storage diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index d3272616b3..881e4d5f1a 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -104,7 +104,7 @@ if (ismob(src.loc)) attack_self(src.loc) else - for(var/mob/M in get_actual_viewers(1, src)) + for(var/mob/M in fov_viewers(1, src)) if (M.client) src.attack_self(M) return diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index fc5680e524..dc39f7f89d 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -478,6 +478,20 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 throw_range = 2 attack_verb = list("busted") +/obj/item/statuebust/attack_self(mob/living/user) + add_fingerprint(user) + user.examinate(src) + +/obj/item/statuebust/examine(mob/living/user) + . = ..() + if(.) + return + if (!isliving(user)) + return + user.visible_message("[user] stops to admire [src].", \ + "You take in [src], admiring its fine craftsmanship.") + SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artgood", /datum/mood_event/artgood) + /obj/item/tailclub name = "tail club" desc = "For the beating to death of lizards with their own tails." diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 8dac972d04..e64b7d8f8d 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -112,7 +112,7 @@ /obj/attack_animal(mob/living/simple_animal/M) if(!M.melee_damage_upper && !M.obj_damage) - M.emote("custom", message = "[M.friendly] [src].") + M.emote("custom", message = "[M.friendly_verb_continuous] [src].") return 0 else var/play_soundeffect = 1 @@ -232,15 +232,16 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e cut_overlay(GLOB.fire_overlay, TRUE) SSfire_burning.processing -= src -/obj/proc/tesla_act(power, tesla_flags, shocked_targets) +/obj/zap_act(power, zap_flags, shocked_targets) + if(QDELETED(src)) + return 0 obj_flags |= BEING_SHOCKED - var/power_bounced = power / 2 - tesla_zap(src, 3, power_bounced, tesla_flags, shocked_targets) addtimer(CALLBACK(src, .proc/reset_shocked), 10) + return power / 2 //The surgeon general warns that being buckled to certain objects receiving powerful shocks is greatly hazardous to your health -//Only tesla coils and grounding rods currently call this because mobs are already targeted over all other objects, but this might be useful for more things later. -/obj/proc/tesla_buckle_check(var/strength) +//Only tesla coils, vehicles, and grounding rods currently call this because mobs are already targeted over all other objects, but this might be useful for more things later. +/obj/proc/zap_buckle_check(var/strength) if(has_buckled_mobs()) for(var/m in buckled_mobs) var/mob/living/buckled_mob = m diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 6916e7c24a..0b2fe5ac2a 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -123,7 +123,7 @@ /obj/proc/updateUsrDialog() if((obj_flags & IN_USE) && !(obj_flags & USES_TGUI)) var/is_in_use = FALSE - var/list/nearby = get_actual_viewers(1, src) + var/list/nearby = fov_viewers(1, src) for(var/mob/M in nearby) if ((M.client && M.machine == src)) is_in_use = TRUE @@ -152,7 +152,7 @@ if(obj_flags & IN_USE) var/is_in_use = FALSE if(update_viewers) - for(var/mob/M in get_actual_viewers(1, src)) + for(var/mob/M in fov_viewers(1, src)) if ((M.client && M.machine == src)) is_in_use = TRUE src.interact(M) diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm index 405e697d3b..98f772a116 100644 --- a/code/game/objects/structures/artstuff.dm +++ b/code/game/objects/structures/artstuff.dm @@ -35,101 +35,368 @@ else painting = null - -////////////// -// CANVASES // -////////////// - -#define AMT_OF_CANVASES 4 //Keep this up to date or shit will break. - -//To safe memory on making /icons we cache the blanks.. -GLOBAL_LIST_INIT(globalBlankCanvases, new(AMT_OF_CANVASES)) - /obj/item/canvas name = "canvas" desc = "Draw out your soul on this canvas!" icon = 'icons/obj/artstuff.dmi' icon_state = "11x11" resistance_flags = FLAMMABLE - var/whichGlobalBackup = 1 //List index + var/width = 11 + var/height = 11 + var/list/grid + var/canvas_color = "#ffffff" //empty canvas color + var/ui_x = 400 + var/ui_y = 400 + var/used = FALSE + var/painting_name //Painting name, this is set after framing. + var/finalized = FALSE //Blocks edits + var/author_ckey + var/icon_generated = FALSE + var/icon/generated_icon -/obj/item/canvas/nineteenXnineteen - icon_state = "19x19" - whichGlobalBackup = 2 + // Painting overlay offset when framed + var/framed_offset_x = 11 + var/framed_offset_y = 10 -/obj/item/canvas/twentythreeXnineteen - icon_state = "23x19" - whichGlobalBackup = 3 + pixel_x = 10 + pixel_y = 9 -/obj/item/canvas/twentythreeXtwentythree - icon_state = "23x23" - whichGlobalBackup = 4 - -//HEY YOU -//ARE YOU READING THE CODE FOR CANVASES? -//ARE YOU AWARE THEY CRASH HALF THE SERVER WHEN SOMEONE DRAWS ON THEM... -//...AND NOBODY CAN FIGURE OUT WHY? -//THEN GO ON BRAVE TRAVELER -//TRY TO FIX THEM AND REMOVE THIS CODE /obj/item/canvas/Initialize() - ..() - return INITIALIZE_HINT_QDEL //Delete on creation + . = ..() + reset_grid() -//Find the right size blank canvas -/obj/item/canvas/proc/getGlobalBackup() - . = null - if(GLOB.globalBlankCanvases[whichGlobalBackup]) - . = GLOB.globalBlankCanvases[whichGlobalBackup] - else - var/icon/I = icon(initial(icon),initial(icon_state)) - GLOB.globalBlankCanvases[whichGlobalBackup] = I - . = I +/obj/item/canvas/proc/reset_grid() + grid = new/list(width,height) + for(var/x in 1 to width) + for(var/y in 1 to height) + grid[x][y] = canvas_color +/obj/item/canvas/attack_self(mob/user) + . = ..() + ui_interact(user) +/obj/item/canvas/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) -//One pixel increments -/obj/item/canvas/attackby(obj/item/I, mob/user, params) - //Click info - var/list/click_params = params2list(params) - var/pixX = text2num(click_params["icon-x"]) - var/pixY = text2num(click_params["icon-y"]) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "canvas", name, ui_x, ui_y, master_ui, state) + ui.set_autoupdate(FALSE) + ui.open() - //Should always be true, otherwise you didn't click the object, but let's check because SS13~ - if(!click_params || !click_params["icon-x"] || !click_params["icon-y"]) - return - - //Cleaning one pixel with a soap or rag - if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/rag)) - //Pixel info created only when needed - var/icon/masterpiece = icon(icon,icon_state) - var/thePix = masterpiece.GetPixel(pixX,pixY) - var/icon/Ico = getGlobalBackup() - if(!Ico) - qdel(masterpiece) - return - - var/theOriginalPix = Ico.GetPixel(pixX,pixY) - if(thePix != theOriginalPix) //colour changed - DrawPixelOn(theOriginalPix,pixX,pixY) - qdel(masterpiece) - - //Drawing one pixel with a crayon - else if(istype(I, /obj/item/toy/crayon)) - var/obj/item/toy/crayon/C = I - DrawPixelOn(C.paint_color, pixX, pixY) +/obj/item/canvas/attackby(obj/item/I, mob/living/user, params) + if(user.a_intent == INTENT_HELP) + ui_interact(user) else return ..() +/obj/item/canvas/ui_data(mob/user) + . = ..() + .["grid"] = grid + .["name"] = painting_name + .["finalized"] = finalized -//Clean the whole canvas -/obj/item/canvas/attack_self(mob/user) - if(!user) +/obj/item/canvas/examine(mob/user) + . = ..() + ui_interact(user) + +/obj/item/canvas/ui_act(action, params) + . = ..() + if(. || finalized) return - var/icon/blank = getGlobalBackup() - if(blank) - //it's basically a giant etch-a-sketch - icon = blank - user.visible_message("[user] cleans the canvas.","You clean the canvas.") + var/mob/user = usr + switch(action) + if("paint") + var/obj/item/I = user.get_active_held_item() + var/color = get_paint_tool_color(I) + if(!color) + return FALSE + var/x = text2num(params["x"]) + var/y = text2num(params["y"]) + grid[x][y] = color + used = TRUE + update_icon() + . = TRUE + if("finalize") + . = TRUE + if(!finalized) + finalize(user) + +/obj/item/canvas/proc/finalize(mob/user) + finalized = TRUE + author_ckey = user.ckey + generate_proper_overlay() + try_rename(user) + +/obj/item/canvas/update_overlays() + . = ..() + if(!icon_generated) + if(used) + var/mutable_appearance/detail = mutable_appearance(icon,"[icon_state]wip") + detail.pixel_x = 1 + detail.pixel_y = 1 + . += detail + else + var/mutable_appearance/detail = mutable_appearance(generated_icon) + detail.pixel_x = 1 + detail.pixel_y = 1 + . += detail + +/obj/item/canvas/proc/generate_proper_overlay() + if(icon_generated) + return + var/png_filename = "data/paintings/temp_painting.png" + var/result = rustg_dmi_create_png(png_filename,"[width]","[height]",get_data_string()) + if(result) + CRASH("Error generating painting png : [result]") + generated_icon = new(png_filename) + icon_generated = TRUE + update_icon() + +/obj/item/canvas/proc/get_data_string() + var/list/data = list() + for(var/y in 1 to height) + for(var/x in 1 to width) + data += grid[x][y] + return data.Join("") + +//Todo make this element ? +/obj/item/canvas/proc/get_paint_tool_color(obj/item/I) + if(!I) + return + if(istype(I, /obj/item/toy/crayon)) + var/obj/item/toy/crayon/C = I + return C.paint_color + else if(istype(I, /obj/item/pen)) + var/obj/item/pen/P = I + switch(P.colour) + if("black") + return "#000000" + if("blue") + return "#0000ff" + if("red") + return "#ff0000" + return P.colour + else if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/rag)) + return canvas_color + +/obj/item/canvas/proc/try_rename(mob/user) + var/new_name = stripped_input(user,"What do you want to name the painting?") + if(!painting_name && new_name && user.canUseTopic(src,BE_CLOSE)) + painting_name = new_name + SStgui.update_uis(src) + +/obj/item/canvas/nineteenXnineteen + icon_state = "19x19" + width = 19 + height = 19 + ui_x = 600 + ui_y = 600 + pixel_x = 6 + pixel_y = 9 + framed_offset_x = 8 + framed_offset_y = 9 + +/obj/item/canvas/twentythreeXnineteen + icon_state = "23x19" + width = 23 + height = 19 + ui_x = 800 + ui_y = 600 + pixel_x = 4 + pixel_y = 10 + framed_offset_x = 6 + framed_offset_y = 8 + +/obj/item/canvas/twentythreeXtwentythree + icon_state = "23x23" + width = 23 + height = 23 + ui_x = 800 + ui_y = 800 + pixel_x = 5 + pixel_y = 9 + framed_offset_x = 5 + framed_offset_y = 6 + +/obj/item/wallframe/painting + name = "painting frame" + desc = "The perfect showcase for your favorite deathtrap memories." + icon = 'icons/obj/decals.dmi' + custom_materials = null + flags_1 = 0 + icon_state = "frame-empty" + result_path = /obj/structure/sign/painting + +/obj/structure/sign/painting + name = "Painting" + desc = "Art or \"Art\"? You decide." + icon = 'icons/obj/decals.dmi' + icon_state = "frame-empty" + buildable_sign = FALSE + var/obj/item/canvas/C + var/persistence_id + +/obj/structure/sign/painting/Initialize(mapload, dir, building) + . = ..() + SSpersistence.painting_frames += src + AddComponent(/datum/component/art, 20) + if(dir) + setDir(dir) + if(building) + pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30) + pixel_y = (dir & 3)? (dir ==1 ? -30 : 30) : 0 + +/obj/structure/sign/painting/Destroy() + . = ..() + SSpersistence.painting_frames -= src + +/obj/structure/sign/painting/attackby(obj/item/I, mob/user, params) + if(!C && istype(I, /obj/item/canvas)) + frame_canvas(user,I) + else if(C && !C.painting_name && istype(I,/obj/item/pen)) + try_rename(user) + else + return ..() + +/obj/structure/sign/painting/examine(mob/user) + . = ..() + if(C) + C.ui_interact(user,state = GLOB.physical_obscured_state) + +/obj/structure/sign/painting/wirecutter_act(mob/living/user, obj/item/I) + . = ..() + if(C) + C.forceMove(drop_location()) + C = null + to_chat(user, "You remove the painting from the frame.") + update_icon() + return TRUE + +/obj/structure/sign/painting/proc/frame_canvas(mob/user,obj/item/canvas/new_canvas) + if(user.transferItemToLoc(new_canvas,src)) + C = new_canvas + if(!C.finalized) + C.finalize(user) + to_chat(user,"You frame [C].") + update_icon() + +/obj/structure/sign/painting/proc/try_rename(mob/user) + if(!C.painting_name) + C.try_rename(user) + +/obj/structure/sign/painting/update_icon_state() + . = ..() + if(C && C.generated_icon) + icon_state = null + else + icon_state = "frame-empty" -#undef AMT_OF_CANVASES +/obj/structure/sign/painting/update_overlays() + . = ..() + if(C && C.generated_icon) + var/mutable_appearance/MA = mutable_appearance(C.generated_icon) + MA.pixel_x = C.framed_offset_x + MA.pixel_y = C.framed_offset_y + . += MA + var/mutable_appearance/frame = mutable_appearance(C.icon,"[C.icon_state]frame") + frame.pixel_x = C.framed_offset_x - 1 + frame.pixel_y = C.framed_offset_y - 1 + . += frame + +/obj/structure/sign/painting/proc/load_persistent() + if(!persistence_id) + return + if(!SSpersistence.paintings || !SSpersistence.paintings[persistence_id] || !length(SSpersistence.paintings[persistence_id])) + return + var/list/chosen = pick(SSpersistence.paintings[persistence_id]) + var/title = chosen["title"] + var/author = chosen["ckey"] + var/png = "data/paintings/[persistence_id]/[chosen["md5"]].png" + if(!fexists(png)) + stack_trace("Persistent painting [chosen["md5"]].png was not found in [persistence_id] directory.") + return + var/icon/I = new(png) + var/obj/item/canvas/new_canvas + var/w = I.Width() + var/h = I.Height() + for(var/T in typesof(/obj/item/canvas)) + new_canvas = T + if(initial(new_canvas.width) == w && initial(new_canvas.height) == h) + new_canvas = new T(src) + break + new_canvas.fill_grid_from_icon(I) + new_canvas.generated_icon = I + new_canvas.icon_generated = TRUE + new_canvas.finalized = TRUE + new_canvas.painting_name = title + new_canvas.author_ckey = author + C = new_canvas + update_icon() + +/obj/structure/sign/painting/proc/save_persistent() + if(!persistence_id || !C) + return + if(sanitize_filename(persistence_id) != persistence_id) + stack_trace("Invalid persistence_id - [persistence_id]") + return + var/data = C.get_data_string() + var/md5 = md5(data) + var/list/current = SSpersistence.paintings[persistence_id] + if(!current) + current = list() + for(var/list/entry in current) + if(entry["md5"] == md5) + return + var/png_directory = "data/paintings/[persistence_id]/" + var/png_path = png_directory + "[md5].png" + var/result = rustg_dmi_create_png(png_path,"[C.width]","[C.height]",data) + if(result) + CRASH("Error saving persistent painting: [result]") + current += list(list("title" = C.painting_name , "md5" = md5, "ckey" = C.author_ckey)) + SSpersistence.paintings[persistence_id] = current + +/obj/item/canvas/proc/fill_grid_from_icon(icon/I) + var/h = I.Height() + 1 + for(var/x in 1 to width) + for(var/y in 1 to height) + grid[x][y] = I.GetPixel(x,h-y) + +//Presets for art gallery mapping, for paintings to be shared across stations +/obj/structure/sign/painting/library + persistence_id = "library" + +/obj/structure/sign/painting/library_secure + persistence_id = "library_secure" + +/obj/structure/sign/painting/library_private // keep your smut away from prying eyes, or non-librarians at least + persistence_id = "library_private" + +/obj/structure/sign/painting/vv_get_dropdown() + . = ..() + VV_DROPDOWN_OPTION(VV_HK_REMOVE_PAINTING, "Remove Persistent Painting") + +/obj/structure/sign/painting/vv_do_topic(list/href_list) + . = ..() + if(href_list[VV_HK_REMOVE_PAINTING]) + if(!check_rights(NONE)) + return + var/mob/user = usr + if(!persistence_id || !C) + to_chat(user,"This is not a persistent painting.") + return + var/md5 = md5(C.get_data_string()) + var/author = C.author_ckey + var/list/current = SSpersistence.paintings[persistence_id] + if(current) + for(var/list/entry in current) + if(entry["md5"] == md5) + current -= entry + var/png = "data/paintings/[persistence_id]/[md5].png" + fdel(png) + for(var/obj/structure/sign/painting/P in SSpersistence.painting_frames) + if(P.C && md5(P.C.get_data_string()) == md5) + QDEL_NULL(P.C) + log_admin("[key_name(user)] has deleted a persistent painting made by [author].") + message_admins("[key_name_admin(user)] has deleted persistent painting made by [author].") diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index d3e8ecf0a6..2225c4c0c2 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -108,7 +108,9 @@ if(!istype(poordude)) return TRUE user.visible_message("[user] pulls [src] out from under [poordude].", "You pull [src] out from under [poordude].") - var/C = new item_chair(loc) + var/obj/item/chair/C = new item_chair(loc) + C.set_custom_materials(custom_materials) + TransferComponents(C) user.put_in_hands(C) poordude.DefaultCombatKnockdown(20)//rip in peace user.adjustStaminaLoss(5) diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index 6256de247a..500b8d6a49 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -43,7 +43,7 @@ Snake = L break if(Snake) - alerted = get_actual_viewers(world.view,src) + alerted = fov_viewers(world.view,src) ..() if(LAZYLEN(alerted)) egged = world.time + SNAKE_SPAM_TICKS diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 54e08db210..20151a0bdb 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -267,7 +267,7 @@ var/obj/structure/cable/C = T.get_cable_node() if(C) playsound(src, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5) - tesla_zap(src, 3, C.newavail() * 0.01, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN | TESLA_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot. + tesla_zap(src, 3, C.newavail() * 0.01, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN | ZAP_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot. C.add_delayedload(C.newavail() * 0.0375) // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock. return ..() diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm index b8137d1332..0a5ba6a68c 100644 --- a/code/game/objects/structures/guillotine.dm +++ b/code/game/objects/structures/guillotine.dm @@ -130,7 +130,7 @@ // The crowd is pleased // The delay is to making large crowds have a longer laster applause var/delay_offset = 0 - for(var/mob/M in get_actual_viewers(world.view, src)) + for(var/mob/M in fov_viewers(world.view, src)) var/mob/living/carbon/human/C = M if (ishuman(M)) addtimer(CALLBACK(C, /mob/.proc/emote, "clap"), delay_offset * 0.3) diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm index 9a6b24b472..1f9491f4cf 100644 --- a/code/game/objects/structures/statues.dm +++ b/code/game/objects/structures/statues.dm @@ -8,12 +8,11 @@ max_integrity = 100 var/oreAmount = 5 var/material_drop_type = /obj/item/stack/sheet/metal + var/impressiveness = 15 CanAtmosPass = ATMOS_PASS_DENSITY - /obj/structure/statue/attackby(obj/item/W, mob/living/user, params) add_fingerprint(user) - user.changeNext_move(CLICK_CD_MELEE) if(!(flags_1 & NODECONSTRUCT_1)) if(default_unfasten_wrench(user, W)) return @@ -36,8 +35,22 @@ return user.changeNext_move(CLICK_CD_MELEE) add_fingerprint(user) - user.visible_message("[user] rubs some dust off from the [name]'s surface.", \ - "You rub some dust off from the [name]'s surface.") + if(!do_after(user, 20, target = src)) + return + user.visible_message("[user] rubs some dust off [src].", \ + "You take in [src], rubbing some dust off its surface.") + if(!ishuman(user)) // only humans have the capacity to appreciate art + return + var/totalimpressiveness = (impressiveness *(obj_integrity/max_integrity)) + switch(totalimpressiveness) + if(GREAT_ART to 100) + SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat) + if (GOOD_ART to GREAT_ART) + SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artgood", /datum/mood_event/artgood) + if (BAD_ART to GOOD_ART) + SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artok", /datum/mood_event/artok) + if (0 to BAD_ART) + SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad) /obj/structure/statue/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) @@ -58,6 +71,7 @@ material_drop_type = /obj/item/stack/sheet/mineral/uranium var/last_event = 0 var/active = null + impressiveness = 25 // radiation makes an impression /obj/structure/statue/uranium/nuke name = "statue of a nuclear fission explosive" @@ -101,6 +115,7 @@ max_integrity = 200 material_drop_type = /obj/item/stack/sheet/mineral/plasma desc = "This statue is suitably made from plasma." + impressiveness = 20 /obj/structure/statue/plasma/scientist name = "statue of a scientist" @@ -151,6 +166,7 @@ max_integrity = 300 material_drop_type = /obj/item/stack/sheet/mineral/gold desc = "This is a highly valuable statue made from gold." + impressiveness = 30 /obj/structure/statue/gold/hos name = "statue of the head of security" @@ -178,6 +194,7 @@ max_integrity = 300 material_drop_type = /obj/item/stack/sheet/mineral/silver desc = "This is a valuable statue made from silver." + impressiveness = 25 /obj/structure/statue/silver/md name = "statue of a medical officer" @@ -205,6 +222,7 @@ max_integrity = 1000 material_drop_type = /obj/item/stack/sheet/mineral/diamond desc = "This is a very expensive diamond statue." + impressiveness = 60 /obj/structure/statue/diamond/captain name = "statue of THE captain." @@ -225,6 +243,7 @@ material_drop_type = /obj/item/stack/sheet/mineral/bananium desc = "A bananium statue with a small engraving:'HOOOOOOONK'." var/spam_flag = 0 + impressiveness = 65 /obj/structure/statue/bananium/clown name = "statue of a clown" diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 30e451aa14..3d552fa236 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -183,7 +183,7 @@ /obj/structure/table/alt_attack_hand(mob/user) if(user && Adjacent(user) && !user.incapacitated()) - user.setClickCooldown(4) + user.changeNext_move(CLICK_CD_MELEE*0.5) if(istype(user) && user.a_intent == INTENT_HARM) user.visible_message("[user] slams [user.p_their()] palms down on [src].", "You slam your palms down on [src].") playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1) diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 3a719d05b9..38e0839617 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -80,7 +80,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( var/old_dynamic_lighting = dynamic_lighting var/old_affecting_lights = affecting_lights var/old_lighting_object = lighting_object - var/old_corners = corners + var/old_lc_topright = lc_topright + var/old_lc_topleft = lc_topleft + var/old_lc_bottomright = lc_bottomright + var/old_lc_bottomleft = lc_bottomleft var/old_exl = explosion_level var/old_exi = explosion_id @@ -119,7 +122,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( recalc_atom_opacity() lighting_object = old_lighting_object affecting_lights = old_affecting_lights - corners = old_corners + lc_topright = old_lc_topright + lc_topleft = old_lc_topleft + lc_bottomright = old_lc_bottomright + lc_bottomleft = old_lc_bottomleft if (old_opacity != opacity || dynamic_lighting != old_dynamic_lighting) reconsider_lights() diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 268e8e9109..5243341ac1 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -290,7 +290,7 @@ if(LAZYLEN(dent_decals) >= MAX_DENT_DECALS) return - var/mutable_appearance/decal = mutable_appearance('icons/effects/effects.dmi', "", BULLET_HOLE_LAYER) + var/mutable_appearance/decal = mutable_appearance('icons/effects/effects.dmi', "", BULLET_HOLE_LAYER, ABOVE_WALL_PLANE) switch(denttype) if(WALL_DENT_SHOT) decal.icon_state = "bullet_hole" diff --git a/code/game/world.dm b/code/game/world.dm index 10431e4af9..1c6f3bceba 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -1,6 +1,7 @@ #define RESTART_COUNTER_PATH "data/round_counter.txt" GLOBAL_VAR(restart_counter) +GLOBAL_VAR_INIT(tgs_initialized, FALSE) GLOBAL_VAR(topic_status_lastcache) GLOBAL_LIST(topic_status_cache) @@ -23,10 +24,11 @@ GLOBAL_LIST(topic_status_cache) make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) - TgsNew(minimum_required_security_level = TGS_SECURITY_TRUSTED) GLOB.revdata = new + InitTgs() + config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER]) //SetupLogs depends on the RoundID, so lets check @@ -62,6 +64,15 @@ GLOBAL_LIST(topic_status_cache) if(TEST_RUN_PARAMETER in params) HandleTestRun() +/world/proc/InitTgs() + TgsNew(new /datum/tgs_event_handler/impl, TGS_SECURITY_TRUSTED) + GLOB.revdata.load_tgs_info() +#ifdef USE_CUSTOM_ERROR_HANDLER + if (TgsAvailable()) + world.log = file("[GLOB.log_directory]/dd.log") //not all runtimes trigger world/Error, so this is the only way to ensure we can see all of them. +#endif + GLOB.tgs_initialized = TRUE + /world/proc/HandleTestRun() //trigger things to run the whole process Master.sleep_offline_after_initializations = FALSE @@ -125,6 +136,7 @@ GLOBAL_LIST(topic_status_cache) GLOB.subsystem_log = "[GLOB.log_directory]/subsystem.log" GLOB.reagent_log = "[GLOB.log_directory]/reagents.log" GLOB.world_crafting_log = "[GLOB.log_directory]/crafting.log" + GLOB.click_log = "[GLOB.log_directory]/click.log" #ifdef UNIT_TESTS @@ -144,6 +156,7 @@ GLOBAL_LIST(topic_status_cache) start_log(GLOB.subsystem_log) start_log(GLOB.reagent_log) start_log(GLOB.world_crafting_log) + start_log(GLOB.click_log) GLOB.changelog_hash = md5('html/changelog.html') //for telling if the changelog has changed recently if(fexists(GLOB.config_error_log)) @@ -223,16 +236,17 @@ GLOBAL_LIST(topic_status_cache) qdel(src) //shut it down /world/Reboot(reason = 0, fast_track = FALSE) - TgsReboot() 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") + to_chat(world, "Rebooting World immediately due to host request.") else to_chat(world, "Rebooting world...") Master.Shutdown() //run SS shutdowns + TgsReboot() + if(TEST_RUN_PARAMETER in params) FinishTestRun() return diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index a06b674e42..41662c1cad 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -69,11 +69,6 @@ The floor is lava! (DANGEROUS: extremely lame)
Spawn a custom portal storm

- Flip client movement directions
- Randomize client movement directions
- Set each movement direction manually
- Reset movement directions to default
-
Change bomb cap
Mass Purrbation
Mass Remove Purrbation
@@ -603,60 +598,6 @@ purrbation.") log_admin("[key_name(usr)] has removed everyone from purrbation.") - if("flipmovement") - if(!check_rights(R_FUN)) - return - if(alert("Flip all movement controls?","Confirm","Yes","Cancel") == "Cancel") - return - var/list/movement_keys = SSinput.movement_keys - for(var/i in 1 to movement_keys.len) - var/key = movement_keys[i] - movement_keys[key] = turn(movement_keys[key], 180) - message_admins("[key_name_admin(usr)] has flipped all movement directions.") - log_admin("[key_name(usr)] has flipped all movement directions.") - - if("randommovement") - if(!check_rights(R_FUN)) - return - if(alert("Randomize all movement controls?","Confirm","Yes","Cancel") == "Cancel") - return - var/list/movement_keys = SSinput.movement_keys - for(var/i in 1 to movement_keys.len) - var/key = movement_keys[i] - movement_keys[key] = turn(movement_keys[key], 45 * rand(1, 8)) - message_admins("[key_name_admin(usr)] has randomized all movement directions.") - log_admin("[key_name(usr)] has randomized all movement directions.") - - if("custommovement") - if(!check_rights(R_FUN)) - return - if(alert("Are you sure you want to change every movement key?","Confirm","Yes","Cancel") == "Cancel") - return - var/list/movement_keys = SSinput.movement_keys - var/list/new_movement = list() - for(var/i in 1 to movement_keys.len) - var/key = movement_keys[i] - - var/msg = "Please input the new movement direction when the user presses [key]. Ex. northeast" - var/title = "New direction for [key]" - var/new_direction = text2dir(input(usr, msg, title) as text|null) - if(!new_direction) - new_direction = movement_keys[key] - - new_movement[key] = new_direction - SSinput.movement_keys = new_movement - message_admins("[key_name_admin(usr)] has configured all movement directions.") - log_admin("[key_name(usr)] has configured all movement directions.") - - if("resetmovement") - if(!check_rights(R_FUN)) - return - if(alert("Are you sure you want to reset movement keys to default?","Confirm","Yes","Cancel") == "Cancel") - return - SSinput.setup_default_movement_keys() - message_admins("[key_name_admin(usr)] has reset all movement keys.") - log_admin("[key_name(usr)] has reset all movement keys.") - if("customportal") if(!check_rights(R_FUN)) return diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 4a7abda53c..3184a169fc 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -24,6 +24,8 @@ GLOBAL_LIST_EMPTY(antagonists) var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default. var/threat = 0 // Amount of threat this antag poses, for dynamic mode + var/list/skill_modifiers + /datum/antagonist/New() GLOB.antagonists += src typecache_datum_blacklist = typecacheof(typecache_datum_blacklist) @@ -68,15 +70,19 @@ GLOBAL_LIST_EMPTY(antagonists) //Proc called when the datum is given to a mind. /datum/antagonist/proc/on_gain() - if(owner && owner.current) - if(!silent) - greet() - apply_innate_effects() - give_antag_moodies() - remove_blacklisted_quirks() - if(is_banned(owner.current) && replace_banned) - replace_banned_player() - SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src) + if(!(owner?.current)) + return + if(!silent) + greet() + apply_innate_effects() + give_antag_moodies() + remove_blacklisted_quirks() + if(is_banned(owner.current) && replace_banned) + replace_banned_player() + if(skill_modifiers) + for(var/A in skill_modifiers) + ADD_SINGLETON_SKILL_MODIFIER(owner, A, type) + SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src) /datum/antagonist/proc/is_banned(mob/M) if(!M) @@ -99,6 +105,8 @@ GLOBAL_LIST_EMPTY(antagonists) clear_antag_moodies() if(owner) LAZYREMOVE(owner.antag_datums, src) + for(var/A in skill_modifiers) + owner.remove_skill_modifier(GET_SKILL_MOD_ID(A, type)) if(!silent && owner.current) farewell() var/datum/team/team = get_team() diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm index 44116dbe36..9132288415 100644 --- a/code/modules/antagonists/abductor/abductor.dm +++ b/code/modules/antagonists/abductor/abductor.dm @@ -21,6 +21,7 @@ landmark_type = /obj/effect/landmark/abductor/agent greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve." show_in_antagpanel = TRUE + skill_modifiers = list(/datum/skill_modifier/job/level/wiring) /datum/antagonist/abductor/scientist name = "Abductor Scientist" @@ -29,6 +30,7 @@ landmark_type = /obj/effect/landmark/abductor/scientist greet_text = "Use your experimental console and surgical equipment to monitor your agent and experiment upon abducted humans." show_in_antagpanel = TRUE + skill_modifiers = list(/datum/skill_modifier/job/affinity/surgery) /datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team) if(!new_team) diff --git a/code/modules/antagonists/abductor/equipment/glands/electric.dm b/code/modules/antagonists/abductor/equipment/glands/electric.dm index 82ee77d192..7e52f6fcb6 100644 --- a/code/modules/antagonists/abductor/equipment/glands/electric.dm +++ b/code/modules/antagonists/abductor/equipment/glands/electric.dm @@ -23,5 +23,5 @@ addtimer(CALLBACK(src, .proc/zap), rand(30, 100)) /obj/item/organ/heart/gland/electric/proc/zap() - tesla_zap(owner, 4, 8000, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN) + tesla_zap(owner, 4, 8000, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN) playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, TRUE) \ No newline at end of file diff --git a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm index fbdeea6b84..91fb538ca3 100644 --- a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm +++ b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm @@ -86,7 +86,8 @@ melee_damage_upper = 4 obj_damage = 20 environment_smash = ENVIRONMENT_SMASH_STRUCTURES - attacktext = "hits" + attack_verb_continuous = "hits" + attack_verb_simple = "hit" attack_sound = 'sound/weapons/genhit1.ogg' movement_type = FLYING del_on_death = 1 @@ -205,7 +206,8 @@ melee_damage_lower = 20 melee_damage_upper = 20 obj_damage = 60 - attacktext = "slams" + attack_verb_continuous = "slams" + attack_verb_simple = "slam" attack_sound = 'sound/effects/blobattack.ogg' verb_say = "gurgles" verb_ask = "demands" @@ -284,11 +286,11 @@ if(overmind) //if we have an overmind, we're doing chemical reactions instead of pure damage melee_damage_lower = 4 melee_damage_upper = 4 - attacktext = overmind.blobstrain.blobbernaut_message + attack_verb_continuous = overmind.blobstrain.blobbernaut_message else melee_damage_lower = initial(melee_damage_lower) melee_damage_upper = initial(melee_damage_upper) - attacktext = initial(attacktext) + attack_verb_continuous = initial(attack_verb_continuous) /mob/living/simple_animal/hostile/blob/blobbernaut/death(gibbed) ..(gibbed) diff --git a/code/modules/antagonists/blob/blob/theblob.dm b/code/modules/antagonists/blob/blob/theblob.dm index 5717dc557d..6a73dc579b 100644 --- a/code/modules/antagonists/blob/blob/theblob.dm +++ b/code/modules/antagonists/blob/blob/theblob.dm @@ -207,8 +207,8 @@ if(prob(100 - severity * 30)) new /obj/effect/temp_visual/emp(get_turf(src)) -/obj/structure/blob/tesla_act(power) - ..() +/obj/structure/blob/zap_act(power) + . = ..() if(overmind) if(overmind.blobstrain.tesla_reaction(src, power)) take_damage(power/400, BURN, "energy") diff --git a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm index b89b681539..090ef45d89 100644 --- a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm +++ b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm @@ -492,7 +492,7 @@ /obj/structure/bloodsucker/candelabrum/process() if(!lit) return - for(var/mob/living/carbon/human/H in get_actual_viewers(7, src)) + for(var/mob/living/carbon/human/H in fov_viewers(7, src)) var/datum/antagonist/vassal/T = H.mind.has_antag_datum(ANTAG_DATUM_VASSAL) if(AmBloodsucker(H) || T) //We dont want vassals or vampires affected by this return diff --git a/code/modules/antagonists/bloodsucker/powers/cloak.dm b/code/modules/antagonists/bloodsucker/powers/cloak.dm index f8f2bb4e34..5383e8c1ac 100644 --- a/code/modules/antagonists/bloodsucker/powers/cloak.dm +++ b/code/modules/antagonists/bloodsucker/powers/cloak.dm @@ -19,7 +19,7 @@ if(!.) return // must have nobody around to see the cloak - for(var/mob/living/M in get_actual_viewers(9, owner) - owner) + for(var/mob/living/M in fov_viewers(9, owner) - owner) to_chat(owner, "You may only vanish into the shadows unseen.") return FALSE return TRUE diff --git a/code/modules/antagonists/bloodsucker/powers/feed.dm b/code/modules/antagonists/bloodsucker/powers/feed.dm index da53b5cc81..cbb9693fba 100644 --- a/code/modules/antagonists/bloodsucker/powers/feed.dm +++ b/code/modules/antagonists/bloodsucker/powers/feed.dm @@ -169,7 +169,7 @@ vision_distance = notice_range, ignored_mobs = target) // Only people who AREN'T the target will notice this action. // Warn Feeder about Witnesses... var/was_unnoticed = TRUE - for(var/mob/living/M in get_actual_viewers(notice_range, owner) - owner - target) + for(var/mob/living/M in fov_viewers(notice_range, owner) - owner - target) if(M.client && !M.silicon_privileges && !M.eye_blind && !M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) was_unnoticed = FALSE break diff --git a/code/modules/antagonists/bloodsucker/powers/go_home.dm b/code/modules/antagonists/bloodsucker/powers/go_home.dm index 4892530d63..c46a7fce6c 100644 --- a/code/modules/antagonists/bloodsucker/powers/go_home.dm +++ b/code/modules/antagonists/bloodsucker/powers/go_home.dm @@ -64,7 +64,7 @@ var/turf/T = get_turf(user) if(T && T.lighting_object && T.get_lumcount()>= 0.1) // B) Check for Viewers - for(var/mob/living/M in get_actual_viewers(world.view, get_turf(owner)) - owner) + for(var/mob/living/M in fov_viewers(world.view, get_turf(owner)) - owner) if(M.client && !M.silicon_privileges && !M.eye_blind) am_seen = TRUE if (!M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) diff --git a/code/modules/antagonists/bloodsucker/powers/mesmerize.dm b/code/modules/antagonists/bloodsucker/powers/mesmerize.dm index 04d3be439f..eea80d52f3 100644 --- a/code/modules/antagonists/bloodsucker/powers/mesmerize.dm +++ b/code/modules/antagonists/bloodsucker/powers/mesmerize.dm @@ -64,7 +64,7 @@ to_chat(owner, "Your victim's eyes are glazed over. They cannot perceive you.") return FALSE // Check: Target See Me? (behind wall) - if(!(owner in target.visible_atoms())) + if(!(owner in target.fov_view())) // Sub-Check: GET CLOSER //if (!(owner in range(target_range, get_turf(target))) // if (display_error) @@ -117,8 +117,6 @@ RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget) // 5 second windup addtimer(CALLBACK(src, .proc/apply_effects, L, target, power_time), 6 SECONDS) - ADD_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src) - ADD_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src) /datum/action/bloodsucker/targeted/mesmerize/proc/apply_effects(aggressor, victim, power_time) var/mob/living/carbon/target = victim @@ -127,7 +125,6 @@ return PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time) - REMOVE_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src) target.face_atom(L) target.Stun(power_time) to_chat(L, "[target] is fixed in place by your hypnotic gaze.") @@ -136,8 +133,7 @@ spawn(power_time) if(istype(target) && success) target.notransform = FALSE - REMOVE_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src) - if(istype(L) && target.stat == CONSCIOUS && (target in L.visible_atoms(10))) // They Woke Up! (Notice if within view) + if(istype(L) && target.stat == CONSCIOUS && (target in L.fov_view(10))) // They Woke Up! (Notice if within view) to_chat(L, "[target] has snapped out of their trance.") diff --git a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm index 431416ede0..036ea37ada 100644 --- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm +++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm @@ -5,6 +5,7 @@ clockwork_desc = "A sigil of some purpose." icon_state = "sigil" layer = LOW_OBJ_LAYER + plane = ABOVE_WALL_PLANE alpha = 50 resistance_flags = NONE var/affects_servants = FALSE diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm new file mode 100644 index 0000000000..a681e9b38b --- /dev/null +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm @@ -0,0 +1,82 @@ +//Subtype of (riot) shield because of already implemented shieldbash stuff aswell as integrity and simillar things +//ratvarian shield: A shield that absorbs energy from attacks and uses it to empower its bashes with remendous force. It is also quite resistant to damage, though less so against lasers and energy weaponry. + +/obj/item/shield/riot/ratvarian + name = "ratvarian shield" + icon_state = "ratvarian_shield" //Its icons are in the same place the normal shields are in + item_state = "ratvarian_shield" + desc = "A resilient shield made out of brass.. It feels warm to the touch." + var/clockwork_desc = "A powerful shield of ratvarian making. It absorbs blocked attacks to charge devastating bashes." + armor = list("melee" = 80, "bullet" = 70, "laser" = -10, "energy" = -20, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) + shield_flags = SHIELD_FLAGS_DEFAULT + max_integrity = 300 //High integrity, extremely strong against melee / bullets, but still quite easy to destroy with lasers and energy + repair_material = /obj/item/stack/tile/brass + var/dam_absorbed = 0 + var/bash_mult_steps = 30 + var/max_bash_mult = 4 + +/obj/item/shield/riot/ratvarian/examine(mob/user) + if((is_servant_of_ratvar(user) || isobserver(user))) + desc = clockwork_desc + desc +="\n The shield has absorbed [dam_absorbed] damage, multiplying the effectiveness of its bashes by [calc_bash_mult()]" + . = ..() + desc = initial(desc) + +obj/item/shield/riot/ratvarian/proc/calc_bash_mult() + var/bash_mult = 0 + if(!dam_absorbed) + return 1 + else + bash_mult += round(clamp(1 + (dam_absorbed / bash_mult_steps), 1, max_bash_mult), 0.1) //Multiplies the effect of bashes by up to [max_bash_mult], though never less than one + return bash_mult + +/obj/item/shield/riot/ratvarian/proc/calc_bash_absorb_use() + var/absorb_use = 0 + absorb_use = max(0, round(dam_absorbed * (calc_bash_mult() / round(1 + (dam_absorbed / bash_mult_steps), 0.1)), 1)) //Calculates how much of the absorbed damage the bash would actually use, so its not wasted + return absorb_use + +/obj/item/shield/riot/ratvarian/on_shield_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) + if(!damage) + return ..() + + if(!is_servant_of_ratvar(owner)) + owner.visible_message("As [owner] blocks the attack with [src], [owner.p_they()] suddenly drops it, whincing in pain! ", "As you block the attack with [src], it heats up tremendously, forcing you to drop it from the pain alone! ") + owner.emote("scream") + playsound(src, 'sound/machines/fryer/deep_fryer_emerge.ogg', 50) + if(iscarbon(owner)) //Type safety for if a drone somehow got a shield (ratvar protect us) + var/mob/living/carbon/C = owner + var/obj/item/bodypart/part = C.get_holding_bodypart_of_item(src) + C.apply_damage((iscultist(C) ? damage * 2 : damage), BURN, (istype(part, /obj/item/bodypart/l_arm) ? BODY_ZONE_L_ARM : BODY_ZONE_R_ARM)) //Deals the damage to the holder instead of absorbing it instead + forcedrops. Doubled if a cultist of Nar'Sie. + else + owner.adjustFireLoss(iscultist(owner) ? damage * 2 : damage) + addtimer(CALLBACK(owner, /mob/living.proc/dropItemToGround, src, TRUE), 1) + else if(!is_servant_of_ratvar(attacker)) //No exploiting my snowflake mechanics + dam_absorbed += damage + playsound(owner, 'sound/machines/clockcult/steam_whoosh.ogg', 30) + + if(damage <= 10) //The shield itself is hard to break, this DOES NOT modify the actual blocking-mechanic + damage = 0 + else + damage -= 5 + return ..() + +/obj/item/shield/riot/ratvarian/shatter(mob/living/carbon/human/owner) + playsound(owner, 'sound/magic/clockwork/anima_fragment_death.ogg', 50) + new /obj/item/clockwork/alloy_shards/large(get_turf(src)) + +/obj/item/shield/riot/ratvarian/user_shieldbash(mob/living/user, atom/target, harmful) + if(!harmful || !is_servant_of_ratvar(user)) // No fun for non-clockies, but you can keep the normal bashes. Until you try to block with it. + shieldbash_knockback = initial(shieldbash_knockback) + shieldbash_brutedamage = initial(shieldbash_brutedamage) //Prevention for funky stuff that might happen otherwise + shieldbash_stamdmg = initial(shieldbash_stamdmg) + return ..() + var/actual_bash_mult = calc_bash_mult() + shieldbash_knockback = round(initial(shieldbash_knockback) * actual_bash_mult, 1) //Modifying the strength of the bash, done with initial() to prevent magic-number issues if the original shieldbash values are changed + shieldbash_brutedamage = round(initial(shieldbash_brutedamage) * actual_bash_mult, 1) //Where I think of it, better round this stuff because we don't need even more things that deal like 3.25 damage + shieldbash_stamdmg = round(initial(shieldbash_stamdmg) * actual_bash_mult, 1) //Like 20 brute and 60 stam + a fuckton of knockback at the moment (at maximum charge), seems mostly fine? I think? + . = ..() + if(.) //If this bash actually hit someone + if(actual_bash_mult > 1) + playsound(user, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25) + dam_absorbed -= calc_bash_absorb_use() + return diff --git a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm index f43f2814d8..dd37f3727c 100644 --- a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm +++ b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm @@ -17,7 +17,8 @@ obj_damage = 40 melee_damage_lower = 12 melee_damage_upper = 12 - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/weapons/bladeslice.ogg' weather_immunities = list("lava") movement_type = FLYING @@ -68,14 +69,16 @@ maxHealth = 300 melee_damage_upper = 25 melee_damage_lower = 25 - attacktext = "devastates" + attack_verb_continuous = "devastates" + attack_verb_simple = "devastate" speed = -1 obj_damage = 100 max_shield_health = INFINITY else if(GLOB.ratvar_approaches) //Hefty health bonus and slight attack damage increase melee_damage_upper = 15 melee_damage_lower = 15 - attacktext = "carves" + attack_verb_continuous = "carves" + attack_verb_simple = "carve" obj_damage = 50 max_shield_health = 4 diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm index 130fc24583..c40168a986 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm @@ -100,6 +100,24 @@ quickbind = TRUE quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning." +//Nezbere's shield: Creates a ratvarian shield which absorbs attacks, see ratvarian_shield.dm for details. +/datum/clockwork_scripture/create_object/nezberes_shield + descname = "Shield with empowerable bashes" + name = "Nezbere's shield" + desc = "Creates a shield which generates charge from blocking damage, using it to empower its bashes tremendously. It is repaired with brass, and while very durable, extremely weak to lasers and, even more so, to energy weaponry." + invocations = list("Shield me...", "... from the coming dark!") + channel_time = 20 + power_cost = 600 //Shouldn't be too spammable but not too hard to get either + whispered = TRUE + creator_message = "You form a ratvarian shield, which is capable of absorbing blocked attacks to empower its bashes." + object_path = /obj/item/shield/riot/ratvarian + usage_tip = "Bashes will only use charge when performed with intent to harm." + tier = SCRIPTURE_SCRIPT + space_allowed = TRUE + primary_component = VANGUARD_COGWHEEL + sort_priority = 5 + quickbind = TRUE + quickbind_desc = "Creates a Ratvarian shield, which can absorb energy from attacks for use in powerful bashes." //Clockwork Armaments: Grants the invoker the ability to call forth a Ratvarian spear and clockwork armor. /datum/clockwork_scripture/clockwork_armaments @@ -113,7 +131,7 @@ usage_tip = "Throwing the spear at a mob will do massive damage and knock them down, but break the spear. You will need to wait for 30 seconds before resummoning it." tier = SCRIPTURE_SCRIPT primary_component = VANGUARD_COGWHEEL - sort_priority = 5 + sort_priority = 6 important = TRUE quickbind = TRUE quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you." @@ -213,7 +231,7 @@ usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal." tier = SCRIPTURE_SCRIPT primary_component = GEIS_CAPACITOR - sort_priority = 6 + sort_priority = 7 quickbind = TRUE quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk." diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm index a730b52cc1..b6ed7dfe65 100644 --- a/code/modules/antagonists/clockcult/clockcult.dm +++ b/code/modules/antagonists/clockcult/clockcult.dm @@ -5,6 +5,7 @@ antagpanel_category = "Clockcult" job_rank = ROLE_SERVANT_OF_RATVAR antag_moodlet = /datum/mood_event/cult + skill_modifiers = list(/datum/skill_modifier/job/level/wiring) var/datum/action/innate/hierophant/hierophant_network = new threat = 3 var/datum/team/clockcult/clock_team diff --git a/code/modules/antagonists/devil/imp/imp.dm b/code/modules/antagonists/devil/imp/imp.dm index 1539bc384b..7a6850bfa1 100644 --- a/code/modules/antagonists/devil/imp/imp.dm +++ b/code/modules/antagonists/devil/imp/imp.dm @@ -7,9 +7,12 @@ desc = "A large, menacing creature covered in armored black scales." speak_emote = list("cackles") emote_hear = list("cackles","screeches") - response_help = "thinks better of touching" - response_disarm = "flails at" - response_harm = "punches" + response_help_continuous = "thinks better of touching" + response_help_simple = "think better of touching" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "punches" + response_harm_simple = "punch" icon = 'icons/mob/mob.dmi' icon_state = "imp" icon_living = "imp" @@ -23,7 +26,8 @@ minbodytemp = 250 //Weak to cold maxbodytemp = INFINITY faction = list("hell") - attacktext = "wildly tears into" + attack_verb_continuous = "wildly tears into" + attack_verb_simple = "wildly tear into" maxHealth = 200 health = 200 healable = 0 diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index bda1fbabe6..1d773627c7 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -51,6 +51,7 @@ /datum/antagonist/ert/engineer role = "Engineer" outfit = /datum/outfit/ert/engineer + skill_modifiers = list(/datum/skill_modifier/job/level/wiring) /datum/antagonist/ert/engineer/amber outfit = /datum/outfit/ert/engineer/alert @@ -61,6 +62,7 @@ /datum/antagonist/ert/medic role = "Medical Officer" outfit = /datum/outfit/ert/medic + skill_modifiers = list(/datum/skill_modifier/job/affinity/surgery) /datum/antagonist/ert/medic/amber outfit = /datum/outfit/ert/medic/alert diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm index ad2eb4792a..e91feda006 100644 --- a/code/modules/antagonists/morph/morph.dm +++ b/code/modules/antagonists/morph/morph.dm @@ -28,7 +28,8 @@ lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE vision_range = 1 // Only attack when target is close wander = FALSE - attacktext = "glomps" + attack_verb_continuous = "glomps" + attack_verb_simple = "glomp" attack_sound = 'sound/effects/blobattack.ogg' butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2) diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index 2907a1c285..a11ecaa3df 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -451,9 +451,9 @@ return qdel(src) -/obj/machinery/nuclearbomb/tesla_act(power, tesla_flags) +/obj/machinery/nuclearbomb/zap_act(power, zap_flags) ..() - if(tesla_flags & TESLA_MACHINE_EXPLOSIVE) + if(zap_flags & ZAP_MACHINE_EXPLOSIVE) qdel(src)//like the singulo, tesla deletes it. stops it from exploding over and over #define NUKERANGE 127 diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 7510ad6997..454cde6d72 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -5,6 +5,7 @@ job_rank = ROLE_OPERATIVE antag_moodlet = /datum/mood_event/focused threat = 10 + skill_modifiers = list(/datum/skill_modifier/job/level/wiring) var/datum/team/nuclear/nuke_team var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team. var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint. diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index 5ee673dddc..e06e8691b3 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -31,16 +31,20 @@ see_in_dark = 8 lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE - response_help = "passes through" - response_disarm = "swings through" - response_harm = "punches through" + response_help_continuous = "passes through" + response_help_simple = "pass through" + response_disarm_continuous = "swings through" + response_disarm_simple = "swing through" + response_harm_continuous = "punches through" + response_harm_simple = "punch through" unsuitable_atmos_damage = 0 damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway. atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 maxbodytemp = INFINITY harm_intent_damage = 0 - friendly = "touches" + friendly_verb_continuous = "touches" + friendly_verb_simple = "touch" status_flags = 0 wander = FALSE density = FALSE diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm index 5d409a7fb9..6b063559dc 100644 --- a/code/modules/antagonists/slaughter/slaughter.dm +++ b/code/modules/antagonists/slaughter/slaughter.dm @@ -6,9 +6,12 @@ desc = "A large, menacing creature covered in armored black scales." speak_emote = list("gurgles") emote_hear = list("wails","screeches") - response_help = "thinks better of touching" - response_disarm = "flails at" - response_harm = "punches" + response_help_continuous = "thinks better of touching" + response_help_simple = "think better of touching" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "punches" + response_harm_simple = "punch" icon = 'icons/mob/mob.dmi' icon_state = "daemon" icon_living = "daemon" @@ -24,7 +27,8 @@ minbodytemp = 0 maxbodytemp = INFINITY faction = list("slaughter") - attacktext = "wildly tears into" + attack_verb_continuous = "wildly tears into" + attack_verb_simple = "wildly tear into" maxHealth = 200 health = 200 healable = 0 @@ -116,8 +120,10 @@ desc = "A large, adorable creature covered in armor with pink bows." speak_emote = list("giggles","titters","chuckles") emote_hear = list("guffaws","laughs") - response_help = "hugs" - attacktext = "wildly tickles" + response_help_continuous = "hugs" + response_help_simple = "hug" + attack_verb_continuous = "wildly tickles" + attack_verb_simple = "wildly tickle" attack_sound = 'sound/items/bikehorn.ogg' feast_sound = 'sound/spookoween/scary_horn2.ogg' diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm index c1f493ac52..d0e36394ab 100644 --- a/code/modules/antagonists/swarmer/swarmer.dm +++ b/code/modules/antagonists/swarmer/swarmer.dm @@ -84,9 +84,11 @@ hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD) obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE - attacktext = "shocks" + attack_verb_continuous = "shocks" + attack_verb_simple = "shock" attack_sound = 'sound/effects/empulse.ogg' - friendly = "pinches" + friendly_verb_continuous = "pinches" + friendly_verb_simple = "pinch" speed = 0 faction = list("swarmer") AIStatus = AI_OFF diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 1d30cdbf77..4422f2f174 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -4,6 +4,7 @@ antagpanel_category = "Traitor" job_rank = ROLE_TRAITOR antag_moodlet = /datum/mood_event/focused + skill_modifiers = list(/datum/skill_modifier/job/level/wiring/basic) var/special_role = ROLE_TRAITOR var/employer = "The Syndicate" var/give_objectives = TRUE diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm index 68ed0d736e..aa2ec402d8 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook.dm @@ -226,7 +226,11 @@ /datum/spellbook_entry/lightningbolt/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) //return 1 on success . = ..() - user.flags_1 |= TESLA_IGNORE_1 + ADD_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "lightning_bolt_spell") + +/datum/spellbook_entry/lightningbolt/Refund(mob/living/carbon/human/user, obj/item/spellbook/book) + . = ..() + REMOVE_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "lightning_bolt_spell") /datum/spellbook_entry/infinite_guns name = "Lesser Summon Guns" diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 8f5ab7dd5e..97389848ba 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -17,6 +17,7 @@ active_power_usage = 0 power_channel = ENVIRON layer = GAS_PIPE_HIDDEN_LAYER //under wires + plane = ABOVE_WALL_PLANE resistance_flags = FIRE_PROOF max_integrity = 200 obj_flags = CAN_BE_HIT | ON_BLUEPRINTS diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm index c164dc5ae3..6b685d4bc1 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm @@ -7,6 +7,7 @@ name = "circulator/heat exchanger" desc = "A gas circulator pump and heat exchanger." icon_state = "circ-off-0" + plane = GAME_PLANE var/active = FALSE diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm index a45728d51f..c229a4ba27 100644 --- a/code/modules/atmospherics/machinery/components/components_base.dm +++ b/code/modules/atmospherics/machinery/components/components_base.dm @@ -32,7 +32,7 @@ var/turf/T = loc if(level == 2 || (istype(T) && !T.intact)) showpipe = TRUE - plane = GAME_PLANE + plane = ABOVE_WALL_PLANE else showpipe = FALSE plane = FLOOR_PLANE diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 9b7183092d..4f26a2f772 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -6,6 +6,7 @@ max_integrity = 350 armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 30, "acid" = 30) layer = ABOVE_WINDOW_LAYER + plane = GAME_PLANE state_open = FALSE circuit = /obj/item/circuitboard/machine/cryo_tube pipe_flags = PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY @@ -15,8 +16,8 @@ var/volume = 100 var/efficiency = 1 - var/sleep_factor = 0.00125 - var/unconscious_factor = 0.001 + var/base_knockout = 30 SECONDS + var/knockout_factor = 1 var/heat_capacity = 20000 var/conduction_coefficient = 0.3 @@ -53,10 +54,9 @@ var/C for(var/obj/item/stock_parts/matter_bin/M in component_parts) C += M.rating - + // 2 bins total, so C ranges from 2 to 8. efficiency = initial(efficiency) * C - sleep_factor = initial(sleep_factor) * C - unconscious_factor = initial(unconscious_factor) * C + knockout_factor = initial(knockout_factor) / max(1, (C * 0.33)) heat_capacity = initial(heat_capacity) / C conduction_coefficient = initial(conduction_coefficient) * C @@ -188,8 +188,10 @@ if(air1.gases.len) if(mob_occupant.bodytemperature < T0C) // Sleepytime. Why? More cryo magic. - mob_occupant.Sleeping((mob_occupant.bodytemperature * sleep_factor) * 2000) - mob_occupant.Unconscious((mob_occupant.bodytemperature * unconscious_factor) * 2000) + // temperature factor goes from 1 to about 2.5 + var/amount = max(1, (4 * log(T0C - mob_occupant.bodytemperature)) - 20) * knockout_factor * base_knockout + mob_occupant.Sleeping(amount) + mob_occupant.Unconscious(amount) if(beaker) if(reagent_transfer == 0) // Magically transfer reagents. Because cryo magic. beaker.reagents.trans_to(occupant, 1, efficiency * 0.25) // Transfer reagents. diff --git a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm index c1bd59f49b..79ff24e8b7 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm @@ -7,6 +7,7 @@ max_integrity = 800 density = TRUE layer = ABOVE_WINDOW_LAYER + plane = GAME_PLANE pipe_flags = PIPING_ONE_PER_TURF var/volume = 10000 //in liters var/gas_type = 0 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm index dddfdf08c1..7af3e57bc7 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm @@ -9,6 +9,7 @@ max_integrity = 300 armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 30) layer = OBJ_LAYER + plane = GAME_PLANE circuit = /obj/item/circuitboard/machine/thermomachine ui_x = 300 ui_y = 230 diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm index d1d895ca69..6968a5ccd8 100644 --- a/code/modules/cargo/console.dm +++ b/code/modules/cargo/console.dm @@ -119,6 +119,7 @@ var/list/data = list() data["requestonly"] = requestonly data["supplies"] = list() + data["emagged"] = obj_flags & EMAGGED for(var/pack in SSshuttle.supply_packs) var/datum/supply_pack/P = SSshuttle.supply_packs[pack] if(!data["supplies"][P.group]) @@ -133,7 +134,8 @@ "cost" = P.cost, "id" = pack, "desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name. - "access" = P.access + "access" = P.access, + "can_private_buy" = P.can_private_buy )) return data @@ -195,9 +197,10 @@ rank = "Silicon" var/datum/bank_account/account - if(self_paid && ishuman(usr)) - var/mob/living/carbon/human/H = usr - var/obj/item/card/id/id_card = H.get_idcard(TRUE) + if(self_paid) + if(!pack.can_private_buy && !(obj_flags & EMAGGED)) + return + var/obj/item/card/id/id_card = usr.get_idcard(TRUE) if(!istype(id_card)) say("No ID card detected.") return diff --git a/code/modules/cargo/exports/parts.dm b/code/modules/cargo/exports/parts.dm index 660d79cae4..da3c0cf31d 100644 --- a/code/modules/cargo/exports/parts.dm +++ b/code/modules/cargo/exports/parts.dm @@ -110,7 +110,7 @@ include_subtypes = FALSE /datum/export/glasswork_lens - cost = 1800 + cost = 1600 unit_name = "small glass lens" export_types = list(/obj/item/glasswork/glass_base/lens) @@ -133,13 +133,13 @@ include_subtypes = FALSE /datum/export/glasswork_teaplate - cost = 1200 + cost = 1000 unit_name = "tea gear" export_types = list(/obj/item/tea_plate) include_subtypes = FALSE /datum/export/glasswork_teacup - cost = 1800 + cost = 1600 unit_name = "tea gear" export_types = list(/obj/item/tea_cup) include_subtypes = FALSE diff --git a/code/modules/cargo/exports/sheets.dm b/code/modules/cargo/exports/sheets.dm index be0d2d6bee..120bfbe5e4 100644 --- a/code/modules/cargo/exports/sheets.dm +++ b/code/modules/cargo/exports/sheets.dm @@ -120,12 +120,6 @@ message = "of cloth" export_types = list(/obj/item/stack/sheet/cloth) -/datum/export/stack/silk - cost = 200 //The new plasma - unit_name = "sheets" - message = "of silk" - export_types = list(/obj/item/stack/sheet/silk) - /datum/export/stack/duracloth cost = 40 unit_name = "sheets" diff --git a/code/modules/cargo/gondolapod.dm b/code/modules/cargo/gondolapod.dm index 1b4ebd6c1a..be2db06346 100644 --- a/code/modules/cargo/gondolapod.dm +++ b/code/modules/cargo/gondolapod.dm @@ -2,9 +2,12 @@ name = "gondola" real_name = "gondola" desc = "The silent walker. This one seems to be part of a delivery agency." - response_help = "pets" - response_disarm = "bops" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "bops" + response_disarm_simple = "bop" + response_harm_continuous = "kicks" + response_harm_simple = "kick" faction = list("gondola") turns_per_move = 10 icon = 'icons/mob/gondolapod.dmi' diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 96557d58ef..f82e16ad5c 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -15,6 +15,7 @@ var/special_enabled = FALSE var/DropPodOnly = FALSE //only usable by the Bluespace Drop Pod via the express cargo console var/admin_spawned = FALSE //Can only an admin spawn this crate? + var/can_private_buy = TRUE //Can it be purchased privately by each crewmember? /datum/supply_pack/proc/generate(atom/A, datum/bank_account/paying_account) var/obj/structure/closet/crate/C diff --git a/code/modules/cargo/packs/armory.dm b/code/modules/cargo/packs/armory.dm index bcfbc83001..3a3357cc42 100644 --- a/code/modules/cargo/packs/armory.dm +++ b/code/modules/cargo/packs/armory.dm @@ -10,6 +10,7 @@ group = "Armory" access = ACCESS_ARMORY crate_type = /obj/structure/closet/crate/secure/weapon + can_private_buy = FALSE /datum/supply_pack/security/armory/bulletarmor name = "Bulletproof Armor Crate" diff --git a/code/modules/cargo/packs/engine.dm b/code/modules/cargo/packs/engine.dm index 89775c07ee..499881a110 100644 --- a/code/modules/cargo/packs/engine.dm +++ b/code/modules/cargo/packs/engine.dm @@ -148,7 +148,7 @@ crate_name = "supermatter shard crate" crate_type = /obj/structure/closet/crate/secure/engineering dangerous = TRUE - + /datum/supply_pack/engine/tesla_coils name = "Tesla Coil Crate" desc = "Whether it's high-voltage executions, creating research points, or just plain old power generation: This pack of four Tesla coils can do it all!" diff --git a/code/modules/cargo/packs/materials.dm b/code/modules/cargo/packs/materials.dm index 1ce3a6b084..771f7ce222 100644 --- a/code/modules/cargo/packs/materials.dm +++ b/code/modules/cargo/packs/materials.dm @@ -81,32 +81,6 @@ contains = list(/obj/item/stack/sheet/mineral/wood/fifty) crate_name = "wood planks crate" -/datum/supply_pack/materials/rawcotton - name = "Raw Cotton Crate" - desc = "Plushies have been on the down in the market, and now due to a flood of raw cotton the price of it is so cheap, its a steal! Contains 40 raw cotton sheets." - cost = 800 // 100 net cost, 20 x 20 = 400. 300 profit if turned into cloth sheets or more if turned to silk then 10 x 200 = 2000 - contains = list(/obj/item/stack/sheet/cotton/thirty, - /obj/item/stack/sheet/cotton/ten - ) - crate_name = "cotton crate" - crate_type = /obj/structure/closet/crate/hydroponics - -/datum/supply_pack/materials/rawcottonbulk - name = "Raw Cotton Crate (Bulk)" - desc = "We have so much of this stuff we need to get rid of it in -bulk- now. This crate contains 240 raw cotton sheets." - cost = 1300 // 600 net cost 20 x 120 = 2400 profit if turned into cloth sheets or if turned into silk 200 x 60 = 12000 - contains = list(/obj/item/stack/sheet/cotton/thirty, - /obj/item/stack/sheet/cotton/thirty, - /obj/item/stack/sheet/cotton/thirty, - /obj/item/stack/sheet/cotton/thirty, - /obj/item/stack/sheet/cotton/thirty, - /obj/item/stack/sheet/cotton/thirty, - /obj/item/stack/sheet/cotton/thirty, - /obj/item/stack/sheet/cotton/thirty, - ) - crate_name = "bulk cotton crate" - crate_type = /obj/structure/closet/crate/hydroponics - /datum/supply_pack/materials/rcdammo name = "Spare RCD ammo" desc = "This crate contains sixteen RCD compressed matter packs, to help with any holes or projects people might be working on." diff --git a/code/modules/cargo/packs/medical.dm b/code/modules/cargo/packs/medical.dm index 5d02bbe60f..ab188f235b 100644 --- a/code/modules/cargo/packs/medical.dm +++ b/code/modules/cargo/packs/medical.dm @@ -252,6 +252,7 @@ crate_name = "virus crate" crate_type = /obj/structure/closet/crate/secure/plasma dangerous = TRUE + can_private_buy = FALSE /datum/supply_pack/medical/anitvirus name = "Virus Containment Crate" @@ -271,4 +272,4 @@ /obj/item/storage/box/syringes, /obj/item/storage/box/beakers) crate_name = "virus containment unit crate" - crate_type = /obj/structure/closet/crate/secure/plasma \ No newline at end of file + crate_type = /obj/structure/closet/crate/secure/plasma diff --git a/code/modules/cargo/packs/organic.dm b/code/modules/cargo/packs/organic.dm index 22cb518926..249faae33d 100644 --- a/code/modules/cargo/packs/organic.dm +++ b/code/modules/cargo/packs/organic.dm @@ -370,22 +370,6 @@ /////////////////////////////////// Misc ///////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -/datum/supply_pack/organic/hunting - name = "Hunting Gear" - desc = "Even in space, we can find prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a hunting shotgun. " - cost = 3500 - contraband = TRUE - contains = list(/obj/item/clothing/head/flatcap, - /obj/item/clothing/suit/hooded/wintercoat/captain, - /obj/item/reagent_containers/food/drinks/bottle/cognac, - /obj/item/storage/fancy/cigarettes/cigars/havana, - /obj/item/clothing/gloves/color/white, - /obj/item/clothing/under/rank/civilian/curator, - /obj/item/gun/ballistic/shotgun/lethal) - access = ACCESS_ARMORY - crate_name = "sporting crate" - crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:( - /datum/supply_pack/organic/party name = "Party Equipment" desc = "Celebrate both life and death on the station with Nanotrasen's Party Essentials(tm)! Contains seven colored glowsticks, four beers, two ales, a drinking shaker, and a bottle of patron & goldschlager!" diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm index 51bb2b728f..fd6fee362d 100644 --- a/code/modules/cargo/packs/science.dm +++ b/code/modules/cargo/packs/science.dm @@ -17,6 +17,7 @@ cost = 2500 contains = list (/obj/item/reagent_containers/food/snacks/cube/ape) crate_name = "ape cube crate" + can_private_buy = FALSE /datum/supply_pack/science/beakers name = "Chemistry Beakers Crate" diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm index d134d7bab8..a48874e974 100644 --- a/code/modules/cargo/packs/security.dm +++ b/code/modules/cargo/packs/security.dm @@ -10,6 +10,7 @@ group = "Security" access = ACCESS_SECURITY crate_type = /obj/structure/closet/crate/secure/gear + can_private_buy = FALSE /datum/supply_pack/security/ammo name = "Ammo Crate - General Purpose" @@ -57,6 +58,7 @@ /obj/item/toy/crayon/white, /obj/item/clothing/head/fedora/det_hat) crate_name = "forensics crate" + can_private_buy = TRUE /datum/supply_pack/security/helmets name = "Helmets Crate" @@ -134,6 +136,7 @@ /obj/item/grenade/barrier) cost = 2000 crate_name = "security barriers crate" + can_private_buy = TRUE /datum/supply_pack/security/securityclothes name = "Security Clothing Crate" @@ -152,6 +155,7 @@ /obj/item/clothing/suit/armor/hos/navyblue, /obj/item/clothing/head/beret/sec/navyhos) crate_name = "security clothing crate" + can_private_buy = TRUE /datum/supply_pack/security/supplies name = "Security Supplies Crate" @@ -179,6 +183,7 @@ contains = list(/obj/item/clothing/head/helmet/justice, /obj/item/clothing/mask/gas/sechailer) crate_name = "security clothing crate" + can_private_buy = TRUE /datum/supply_pack/security/baton name = "Stun Batons Crate" @@ -207,3 +212,19 @@ /obj/item/storage/box/wall_flash, /obj/item/storage/box/wall_flash) crate_name = "wall-mounted flash crate" + +/datum/supply_pack/security/hunting + name = "Hunting Gear" + desc = "Even in space, we can find prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a hunting shotgun. " + cost = 3500 + contraband = TRUE + contains = list(/obj/item/clothing/head/flatcap, + /obj/item/clothing/suit/hooded/wintercoat/captain, + /obj/item/reagent_containers/food/drinks/bottle/cognac, + /obj/item/storage/fancy/cigarettes/cigars/havana, + /obj/item/clothing/gloves/color/white, + /obj/item/clothing/under/rank/civilian/curator, + /obj/item/gun/ballistic/shotgun/lethal) + access = ACCESS_ARMORY + crate_name = "sporting crate" + crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:( diff --git a/code/modules/cargo/packs/vending.dm b/code/modules/cargo/packs/vending.dm index 344d19f6c9..810cfd8d6e 100644 --- a/code/modules/cargo/packs/vending.dm +++ b/code/modules/cargo/packs/vending.dm @@ -99,6 +99,7 @@ contains = list(/obj/machinery/vending/security) crate_name = "SecTech supply crate" crate_type = /obj/structure/closet/crate/secure/gear + can_private_buy = FALSE /datum/supply_pack/vending/snack name = "Snack Supply Crate" diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index f865cfddbb..47255d9535 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -80,10 +80,24 @@ var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen. + /// Keys currently held + var/list/keys_held = list() + /// These next two vars are to apply movement for keypresses and releases made while move delayed. + /// Because discarding that input makes the game less responsive. + /// On next move, add this dir to the move that would otherwise be done + var/next_move_dir_add + /// On next move, subtract this dir from the move that would otherwise be done + var/next_move_dir_sub + /// Amount of keydowns in the last keysend checking interval var/client_keysend_amount = 0 + /// World tick time where client_keysend_amount will reset var/next_keysend_reset = 0 + /// World tick time where keysend_tripped will reset back to false var/next_keysend_trip_reset = 0 + /// When set to true, user will be autokicked if they trip the keysends in a second limit again var/keysend_tripped = FALSE + /// custom movement keys for this client + var/list/movement_keys = list() /// Messages currently seen by this client var/list/seen_messages diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index ab1db47db6..ce7ef441c4 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -265,6 +265,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) else prefs = new /datum/preferences(src) GLOB.preferences_datums[ckey] = prefs + if(SSinput.initialized) + set_macros() + update_movement_keys(prefs) prefs.last_ip = address //these are gonna be used for banning prefs.last_id = computer_id //these are gonna be used for banning @@ -328,9 +331,6 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) qdel(src) return - if(SSinput.initialized) - set_macros() - chatOutput.start() // Starts the chat if(alert_mob_dupe_login) @@ -789,7 +789,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) log_game("[key_name(src)] is using the middle click aimbot exploit") message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] is using the middle click aimbot exploit") add_system_note("aimbot", "Is using the middle click aimbot exploit") - + log_click(object, location, control, params, src, "lockout (spam - minute ab c [ab] s [middragtime])") + else + log_click(object, location, control, params, src, "lockout (spam - minute)") log_game("[key_name(src)] Has hit the per-minute click limit of [mcl] clicks in a given game minute") message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] Has hit the per-minute click limit of [mcl] clicks in a given game minute") to_chat(src, "[msg]") @@ -809,8 +811,12 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) return if(ab) //Citadel edit, things with stuff. + log_click(object, location, control, params, src, "dropped (ab c [ab] s [middragtime])") return + if(prefs.log_clicks) + log_click(object, location, control, params, src) + if (prefs.hotkeys) // If hotkey mode is enabled, then clicking the map will automatically // unfocus the text bar. This removes the red color from the text bar @@ -892,6 +898,23 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) y = clamp(y+change, min,max) change_view("[x]x[y]") +/client/proc/update_movement_keys(datum/preferences/direct_prefs) + var/datum/preferences/D = prefs || direct_prefs + if(!D?.key_bindings) + return + movement_keys = list() + for(var/key in D.key_bindings) + for(var/kb_name in D.key_bindings[key]) + switch(kb_name) + if("North") + movement_keys[key] = NORTH + if("East") + movement_keys[key] = EAST + if("West") + movement_keys[key] = WEST + if("South") + movement_keys[key] = SOUTH + /client/proc/change_view(new_size) if (isnull(new_size)) CRASH("change_view called without argument.") diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 100dbc66ae..040b56f124 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1,11 +1,6 @@ - /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\ - | THIS FILE CONTAINS HOOKS FOR FOR | - | CHANGES SPECIFIC TO CITADEL. IF | - | YOU'RE FIXING A MERGE CONFLICT | - | HERE, PLEASE ASK FOR REVIEW FROM | - | ANOTHER MAINTAINER TO ENSURE YOU | - | DON'T INTRODUCE REGRESSIONS. | - \* */ +#define DEFAULT_SLOT_AMT 2 +#define HANDS_SLOT_AMT 2 +#define BACKPACK_SLOT_AMT 4 GLOBAL_LIST_EMPTY(preferences_datums) @@ -20,6 +15,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/muted = 0 var/last_ip var/last_id + var/log_clicks = FALSE var/icon/custom_holoform_icon var/list/cached_holoform_icons @@ -51,6 +47,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/chat_on_map = TRUE var/max_chat_length = CHAT_MESSAGE_MAX_LENGTH var/see_chat_non_mob = TRUE + + /// Custom Keybindings + var/list/key_bindings = list() + + var/tgui_fancy = TRUE var/tgui_lock = TRUE var/windowflashing = TRUE @@ -189,9 +190,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/uplink_spawn_loc = UPLINK_PDA - var/sprint_spacebar = FALSE - var/sprint_toggle = FALSE - var/hud_toggle_flash = TRUE var/hud_toggle_color = "#ffffff" @@ -204,6 +202,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/vore_flags = 0 var/list/belly_prefs = list() var/vore_taste = "nothing in particular" + var/toggleeatingnoise = TRUE + var/toggledigestionnoise = TRUE + var/hound_sleeper = TRUE + var/cit_toggles = TOGGLES_CITADEL //backgrounds var/mutable_appearance/character_background @@ -214,6 +216,19 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/no_tetris_storage = FALSE + ///loadout stuff + var/gear_points = 10 + var/list/gear_categories + var/list/chosen_gear = list() + var/gear_tab + + var/screenshake = 100 + var/damagescreenshake = 2 + var/arousable = TRUE + var/widescreenpref = TRUE + var/autostand = TRUE + var/auto_ooc = FALSE + /datum/preferences/New(client/C) parent = C @@ -233,6 +248,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) return //we couldn't load character data so just randomize the character appearance + name random_character() //let's create a random character then - rather than a fat, bald and naked man. + key_bindings = deepCopyList(GLOB.hotkey_keybinding_list_by_key) // give them default keybinds and update their movement keys + C?.update_movement_keys(src) real_name = pref_species.random_name(gender,1) if(!loaded_preferences_successfully) save_preferences() @@ -254,6 +271,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Loadout" dat += "Game Preferences" dat += "Content Preferences" + dat += "Keybindings" if(!path) dat += "
Please create an account to save your preferences
" @@ -395,7 +413,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) mutant_colors = TRUE if (CONFIG_GET(number/body_size_min) != CONFIG_GET(number/body_size_max)) - dat += "Sprite Size: [features["body_size"]]%
" + dat += "Sprite Size: [features["body_size"]*100]%
" if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits)) @@ -843,7 +861,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "See Runechat for non-mobs: [see_chat_non_mob ? "Enabled" : "Disabled"]
" dat += "
" dat += "Action Buttons: [(buttons_locked) ? "Locked In Place" : "Unlocked"]
" - dat += "Keybindings: [(hotkeys) ? "Hotkeys" : "Default"]
" dat += "
" dat += "PDA Color:     Change
" dat += "PDA Style: [pda_style]
" @@ -939,8 +956,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
" dat += "Ambient Occlusion: [ambientocclusion ? "Enabled" : "Disabled"]
" dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"]
" - dat += "Sprint Key: [sprint_spacebar ? "Space" : "Shift"]
" - dat += "Toggle Sprint: [sprint_toggle ? "Enabled" : "Disabled"]
" dat += "HUD Button Flashes: [hud_toggle_flash ? "Enabled" : "Disabled"]
" dat += "HUD Button Flash Color:     Change
" @@ -1063,6 +1078,56 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Ass Slapping: [(cit_toggles & NO_ASS_SLAP) ? "Disallowed" : "Allowed"]
" dat += "" dat += "
" + if(5) // Custom keybindings + dat += "Keybindings: [(hotkeys) ? "Hotkeys" : "Input"]
" + dat += "Keybindings mode controls how the game behaves with tab and map/input focus.
If it is on Hotkeys, the game will always attempt to force you to map focus, meaning keypresses are sent \ + directly to the map instead of the input. You will still be able to use the command bar, but you need to tab to do it every time you click on the game map.
\ + If it is on Input, the game will not force focus away from the input bar, and you can switch focus using TAB between these two modes: If the input bar is pink, that means that you are in non-hotkey mode, sending all keypresses of the normal \ + alphanumeric characters, punctuation, spacebar, backspace, enter, etc, typing keys into the input bar. If the input bar is white, you are in hotkey mode, meaning all keypresses go into the game's keybind handling system unless you \ + manually click on the input bar to shift focus there.
\ + Input mode is the closest thing to the old input system.
\ + IMPORTANT: While in input mode's non hotkey setting (tab toggled), Ctrl + KEY will send KEY to the keybind system as the key itself, not as Ctrl + KEY. This means Ctrl + T/W/A/S/D/all your familiar stuff still works, but you \ + won't be able to access any regular Ctrl binds.
" + // Create an inverted list of keybindings -> key + var/list/user_binds = list() + for (var/key in key_bindings) + for(var/kb_name in key_bindings[key]) + user_binds[kb_name] += list(key) + + var/list/kb_categories = list() + // Group keybinds by category + for (var/name in GLOB.keybindings_by_name) + var/datum/keybinding/kb = GLOB.keybindings_by_name[name] + kb_categories[kb.category] += list(kb) + + dat += "" + + for (var/category in kb_categories) + dat += "

[category]

" + for (var/i in kb_categories[category]) + var/datum/keybinding/kb = i + if(!length(user_binds[kb.name])) + dat += " Unbound" + var/list/default_keys = hotkeys ? kb.hotkey_keys : kb.classic_keys + if(LAZYLEN(default_keys)) + dat += "| Default: [default_keys.Join(", ")]" + dat += "
" + else + var/bound_key = user_binds[kb.name][1] + dat += " [bound_key]" + for(var/bound_key_index in 2 to length(user_binds[kb.name])) + bound_key = user_binds[kb.name][bound_key_index] + dat += " | [bound_key]" + if(length(user_binds[kb.name]) < MAX_KEYS_PER_KEYBIND) + dat += "| Add Secondary" + var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys + if(LAZYLEN(default_keys)) + dat += "| Default: [default_keys.Join(", ")]" + dat += "
" + + dat += "

" + dat += "\[Reset to default\]" + dat += "" dat += "
" @@ -1083,6 +1148,31 @@ GLOBAL_LIST_EMPTY(preferences_datums) #undef APPEARANCE_CATEGORY_COLUMN #undef MAX_MUTANT_ROWS +/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, var/old_key) + var/HTML = {" +
Keybinding: [kb.full_name]
[kb.description]

Press any key to change
Press ESC to clear
+ + "} + winshow(user, "capturekeypress", TRUE) + var/datum/browser/popup = new(user, "capturekeypress", "
Keybindings
", 350, 300) + popup.set_content(HTML) + popup.open(FALSE) + onclose(user, "capturekeypress", src) + /datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620) if(!SSjob) return @@ -2263,10 +2353,73 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("hotkeys") hotkeys = !hotkeys - if(hotkeys) - winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default") - else - winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default") + user.client.set_macros() + + if("keybindings_capture") + var/datum/keybinding/kb = GLOB.keybindings_by_name[href_list["keybinding"]] + var/old_key = href_list["old_key"] + CaptureKeybinding(user, kb, old_key) + return + + if("keybindings_set") + var/kb_name = href_list["keybinding"] + if(!kb_name) + user << browse(null, "window=capturekeypress") + ShowChoices(user) + return + + var/clear_key = text2num(href_list["clear_key"]) + var/old_key = href_list["old_key"] + if(clear_key) + if(key_bindings[old_key]) + key_bindings[old_key] -= kb_name + if(!length(key_bindings[old_key])) + key_bindings -= old_key + user << browse(null, "window=capturekeypress") + save_preferences() + ShowChoices(user) + return + + var/new_key = uppertext(href_list["key"]) + var/AltMod = text2num(href_list["alt"]) ? "Alt" : "" + var/CtrlMod = text2num(href_list["ctrl"]) ? "Ctrl" : "" + var/ShiftMod = text2num(href_list["shift"]) ? "Shift" : "" + var/numpad = text2num(href_list["numpad"]) ? "Numpad" : "" + // var/key_code = text2num(href_list["key_code"]) + + if(GLOB._kbMap[new_key]) + new_key = GLOB._kbMap[new_key] + + var/full_key + switch(new_key) + if("Alt") + full_key = "[new_key][CtrlMod][ShiftMod]" + if("Ctrl") + full_key = "[AltMod][new_key][ShiftMod]" + if("Shift") + full_key = "[AltMod][CtrlMod][new_key]" + else + full_key = "[AltMod][CtrlMod][ShiftMod][numpad][new_key]" + if(key_bindings[old_key]) + key_bindings[old_key] -= kb_name + if(!length(key_bindings[old_key])) + key_bindings -= old_key + key_bindings[full_key] += list(kb_name) + key_bindings[full_key] = sortList(key_bindings[full_key]) + + user << browse(null, "window=capturekeypress") + user.client.update_movement_keys() + save_preferences() + + if("keybindings_reset") + var/choice = tgalert(user, "Would you prefer 'hotkey' or 'classic' defaults?", "Setup keybindings", "Hotkey", "Classic", "Cancel") + if(choice == "Cancel") + ShowChoices(user) + return + hotkeys = (choice == "Hotkey") + key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key) + user.client.update_movement_keys() + if("chat_on_map") chat_on_map = !chat_on_map if("see_chat_non_mob") @@ -2385,9 +2538,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("ambientocclusion") ambientocclusion = !ambientocclusion if(parent && parent.screen && parent.screen.len) - var/obj/screen/plane_master/game_world/PM = parent.mob.hud_used.plane_masters["[GAME_PLANE]"] + var/obj/screen/plane_master/game_world/G = parent.mob.hud_used.plane_masters["[GAME_PLANE]"] + var/obj/screen/plane_master/above_wall/A = parent.mob.hud_used.plane_masters["[ABOVE_WALL_PLANE]"] var/obj/screen/plane_master/wall/W = parent.mob.hud_used.plane_masters["[WALL_PLANE]"] - PM.backdrop(parent.mob) + G.backdrop(parent.mob) + A.backdrop(parent.mob) W.backdrop(parent.mob) if("auto_fit_viewport") @@ -2395,13 +2550,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(auto_fit_viewport && parent) parent.fit_viewport() - if("sprint_key") - sprint_spacebar = !sprint_spacebar - - if("sprint_toggle") - sprint_toggle = !sprint_toggle - - if("hud_toggle_flash") hud_toggle_flash = !hud_toggle_flash @@ -2580,3 +2728,37 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(!cached_holoform_icons[filter_type]) cached_holoform_icons[filter_type] = process_holoform_icon_filter(custom_holoform_icon, filter_type) return cached_holoform_icons[filter_type] + +//Used in savefile update 32, can be removed once that is no longer relevant. +/datum/preferences/proc/force_reset_keybindings() + var/choice = tgalert(parent.mob, "Your basic keybindings need to be reset, emotes will remain as before. Would you prefer 'hotkey' or 'classic' mode?", "Reset keybindings", "Hotkey", "Classic") + hotkeys = (choice != "Classic") + var/list/oldkeys = key_bindings + key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key) + + for(var/key in oldkeys) + if(!key_bindings[key]) + key_bindings[key] = oldkeys[key] + parent.update_movement_keys() + +/datum/preferences/proc/is_loadout_slot_available(slot) + var/list/L + LAZYINITLIST(L) + for(var/i in chosen_gear) + var/datum/gear/G = i + var/occupied_slots = L[slot_to_string(initial(G.category))] ? L[slot_to_string(initial(G.category))] + 1 : 1 + LAZYSET(L, slot_to_string(initial(G.category)), occupied_slots) + switch(slot) + if(SLOT_IN_BACKPACK) + if(L[slot_to_string(SLOT_IN_BACKPACK)] < BACKPACK_SLOT_AMT) + return TRUE + if(SLOT_HANDS) + if(L[slot_to_string(SLOT_HANDS)] < HANDS_SLOT_AMT) + return TRUE + else + if(L[slot_to_string(slot)] < DEFAULT_SLOT_AMT) + return TRUE + +#undef DEFAULT_SLOT_AMT +#undef HANDS_SLOT_AMT +#undef BACKPACK_SLOT_AMT diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index ca8599c4d5..a2da5d1ae2 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -5,7 +5,7 @@ // You do not need to raise this if you are adding new values that have sane defaults. // Only raise this value when changing the meaning/format/name/layout of an existing value // where you would want the updater procs below to run -#define SAVEFILE_VERSION_MAX 31 +#define SAVEFILE_VERSION_MAX 32 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -42,7 +42,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //if your savefile is 3 months out of date, then 'tough shit'. /datum/preferences/proc/update_preferences(current_version, savefile/S) - return + if(current_version < 32) //If you remove this, remove force_reset_keybindings() too. + addtimer(CALLBACK(src, .proc/force_reset_keybindings), 30) //No mob available when this is run, timer allows user choice. /datum/preferences/proc/update_character(current_version, savefile/S) if(current_version < 19) @@ -250,8 +251,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["parallax"] >> parallax S["ambientocclusion"] >> ambientocclusion S["auto_fit_viewport"] >> auto_fit_viewport - S["sprint_spacebar"] >> sprint_spacebar - S["sprint_toggle"] >> sprint_toggle S["hud_toggle_flash"] >> hud_toggle_flash S["hud_toggle_color"] >> hud_toggle_color S["menuoptions"] >> menuoptions @@ -261,6 +260,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["pda_color"] >> pda_color S["pda_skin"] >> pda_skin + // Custom hotkeys + S["key_bindings"] >> key_bindings + //citadel code S["arousable"] >> arousable S["screenshake"] >> screenshake @@ -295,8 +297,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car parallax = sanitize_integer(parallax, PARALLAX_INSANE, PARALLAX_DISABLE, null) ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion)) auto_fit_viewport = sanitize_integer(auto_fit_viewport, 0, 1, initial(auto_fit_viewport)) - sprint_spacebar = sanitize_integer(sprint_spacebar, 0, 1, initial(sprint_spacebar)) - sprint_toggle = sanitize_integer(sprint_toggle, 0, 1, initial(sprint_toggle)) hud_toggle_flash = sanitize_integer(hud_toggle_flash, 0, 1, initial(hud_toggle_flash)) hud_toggle_color = sanitize_hexcolor(hud_toggle_color, 6, 1, initial(hud_toggle_color)) ghost_form = sanitize_inlist(ghost_form, GLOB.ghost_forms, initial(ghost_form)) @@ -315,9 +315,25 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car cit_toggles = sanitize_integer(cit_toggles, 0, 16777215, initial(cit_toggles)) auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc)) no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage)) + key_bindings = sanitize_islist(key_bindings, list()) + + verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped return 1 +/datum/preferences/proc/verify_keybindings_valid() + // Sanitize the actual keybinds to make sure they exist. + for(var/key in key_bindings) + if(!islist(key_bindings[key])) + key_bindings -= key + var/list/binds = key_bindings[key] + for(var/bind in binds) + if(!GLOB.keybindings_by_name[bind]) + binds -= bind + if(!length(binds)) + key_bindings -= key + // End + /datum/preferences/proc/save_preferences() if(!path) return 0 @@ -362,8 +378,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["parallax"], parallax) WRITE_FILE(S["ambientocclusion"], ambientocclusion) WRITE_FILE(S["auto_fit_viewport"], auto_fit_viewport) - WRITE_FILE(S["sprint_spacebar"], sprint_spacebar) - WRITE_FILE(S["sprint_toggle"], sprint_toggle) WRITE_FILE(S["hud_toggle_flash"], hud_toggle_flash) WRITE_FILE(S["hud_toggle_color"], hud_toggle_color) WRITE_FILE(S["menuoptions"], menuoptions) @@ -372,6 +386,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["pda_style"], pda_style) WRITE_FILE(S["pda_color"], pda_color) WRITE_FILE(S["pda_skin"], pda_skin) + WRITE_FILE(S["key_bindings"], key_bindings) //citadel code WRITE_FILE(S["screenshake"], screenshake) @@ -465,6 +480,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_insect_wings"] >> features["insect_wings"] S["feature_insect_fluff"] >> features["insect_fluff"] S["feature_insect_markings"] >> features["insect_markings"] + S["feature_horns_color"] >> features["horns_color"] + S["feature_wings_color"] >> features["wings_color"] + //Custom names for(var/custom_name_id in GLOB.preferences_custom_names) @@ -541,6 +559,21 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["vore_taste"] >> vore_taste S["belly_prefs"] >> belly_prefs + //gear loadout + var/text_to_load + S["loadout"] >> text_to_load + var/list/saved_loadout_paths = splittext(text_to_load, "|") + chosen_gear = list() + gear_points = CONFIG_GET(number/initial_gear_points) + for(var/i in saved_loadout_paths) + var/datum/gear/path = text2path(i) + if(path) + var/init_cost = initial(path.cost) + if(init_cost > gear_points) + continue + chosen_gear += path + gear_points -= init_cost + //try to fix any outdated data if necessary if(needs_update >= 0) update_character(needs_update, S) //needs_update == savefile_version if we need an update (positive integer) @@ -701,8 +734,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["shirt_color"] , shirt_color) WRITE_FILE(S["socks"] , socks) WRITE_FILE(S["socks_color"] , socks_color) - WRITE_FILE(S["horns_color"] , features["horns_color"]) - WRITE_FILE(S["wings_color"] , features["wings_color"]) WRITE_FILE(S["backbag"] , backbag) WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style) WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc) @@ -718,6 +749,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["feature_lizard_body_markings"] , features["body_markings"]) WRITE_FILE(S["feature_lizard_legs"] , features["legs"]) WRITE_FILE(S["feature_deco_wings"] , features["deco_wings"]) + WRITE_FILE(S["feature_horns_color"] , features["horns_color"]) + WRITE_FILE(S["feature_wings_color"] , features["wings_color"]) WRITE_FILE(S["feature_insect_wings"] , features["insect_wings"]) WRITE_FILE(S["feature_insect_fluff"] , features["insect_fluff"]) WRITE_FILE(S["feature_insect_markings"] , features["insect_markings"]) @@ -771,6 +804,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["vore_taste"] , vore_taste) WRITE_FILE(S["belly_prefs"] , belly_prefs) + //gear loadout + if(chosen_gear.len) + var/text_to_save = chosen_gear.Join("|") + S["loadout"] << text_to_save + else + S["loadout"] << "" //empty string to reset the value + cit_character_pref_save(S) return 1 diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index d5aa49072d..695d25dbf4 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -649,7 +649,6 @@ max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | IMMUTABLE_SLOW resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - flags_1 = TESLA_IGNORE_1 /obj/item/clothing/head/helmet/space/hardsuit/ancient/mason name = "M.A.S.O.N RIG helmet" @@ -665,7 +664,6 @@ max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS | SCAN_REAGENTS resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - flags_1 = TESLA_IGNORE_1 /obj/item/clothing/head/helmet/space/hardsuit/ancient/mason/Initialize() . = ..() @@ -676,12 +674,14 @@ if (slot == SLOT_HEAD) var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_DIAGNOSTIC_BASIC] DHUD.add_hud_to(user) + ADD_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "mason_hardsuit") /obj/item/clothing/head/helmet/space/hardsuit/ancient/mason/dropped(mob/living/carbon/human/user) ..() - if (user.head == src) + if (HAS_TRAIT_FROM(user, TRAIT_TESLA_SHOCKIMMUNE, "mason_hardsuit")) var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_DIAGNOSTIC_BASIC] DHUD.remove_hud_from(user) + REMOVE_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "mason_hardsuit") /obj/item/clothing/suit/space/hardsuit/ancient/proc/on_mob_move() var/mob/living/carbon/human/H = loc diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm index e1deb5d28c..f4fd3f7bf3 100644 --- a/code/modules/clothing/spacesuits/miscellaneous.dm +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -395,10 +395,18 @@ Contains: actions_types = list() resistance_flags = FIRE_PROOF mutantrace_variation = NONE + var/charges = INFINITY -/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize() +/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD) + AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD, charges, TRUE, null, CALLBACK(src, .proc/anti_magic_gone)) + +/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/proc/anti_magic_gone() + var/mob/M = loc + if(!istype(M)) + return + do_sparks(2, TRUE, M) + M.show_message("\The [src] sparks and fizzles as its psychic wards wane away at last...", MSG_VISUAL) /obj/item/clothing/suit/space/hardsuit/ert/paranormal name = "paranormal response team suit" @@ -408,10 +416,18 @@ Contains: helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF + var/charges = INFINITY /obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_OCLOTHING) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_OCLOTHING, charges, TRUE, null, CALLBACK(src, .proc/anti_magic_gone)) + +/obj/item/clothing/suit/space/hardsuit/ert/paranormal/proc/anti_magic_gone() + var/mob/M = loc + if(!istype(M)) + return + do_sparks(2, TRUE, M) + M.show_message("\The [src] sparks and fizzles as its anti magic wards wane away at last...", MSG_VISUAL) /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor name = "inquisitor's hardsuit" @@ -424,6 +440,19 @@ Contains: icon_state = "hardsuit0-inq" item_state = "hardsuit0-inq" +/obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor/old + desc = "Powerful wards are built into this hardsuit, protecting the user from all manner of paranormal threats. Alas, this one looks pretty worn out and rusted." + armor = list("melee" = 55, "bullet" = 40, "laser" = 40, "energy" = 40, "bomb" = 40, "bio" = 80, "rad" = 80, "fire" = 60, "acid" = 60) + slowdown = 0.8 + obj_flags = IMMUTABLE_SLOW //rest in peace rusty joints. + helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor/old + charges = 12 + +/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor/old + desc = "A helmet worn by those who deal with paranormal threats for a living. Alas, this one looks pretty worn out and rusted." + armor = list("melee" = 55, "bullet" = 40, "laser" = 40, "energy" = 40, "bomb" = 40, "bio" = 80, "rad" = 80, "fire" = 60, "acid" = 60) + charges = 12 + /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker name = "champion's hardsuit" desc = "Voices echo from the hardsuit, driving the user insane." @@ -437,6 +466,19 @@ Contains: icon_state = "hardsuit0-beserker" item_state = "hardsuit0-beserker" +/obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker/old + desc = "Voices echo from the hardsuit, driving the user insane. This one is pretty battle-worn, but still fearsome." + armor = list("melee" = 55, "bullet" = 40, "laser" = 40, "energy" = 40, "bomb" = 40, "bio" = 80, "rad" = 80, "fire" = 60, "acid" = 60) + slowdown = 0.8 + obj_flags = IMMUTABLE_SLOW //rest in peace rusty joints. + helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor/old + charges = 6 + +/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/beserker/old + desc = "Peering into the eyes of the helmet is enough to seal damnation. This one is pretty battle-worn, but still fearsome." + armor = list("melee" = 55, "bullet" = 40, "laser" = 40, "energy" = 40, "bomb" = 40, "bio" = 80, "rad" = 80, "fire" = 60, "acid" = 60) + charges = 6 + /obj/item/clothing/head/helmet/space/fragile name = "emergency space helmet" desc = "A bulky, air-tight helmet meant to protect the user during emergency situations. It doesn't look very durable." @@ -477,4 +519,4 @@ Contains: name = "paramedic EVA helmet" desc = "A deep blue space helmet with a large red cross on the faceplate to designate the wearer as trained emergency medical personnel." icon_state = "paramedic-eva-helmet" - item_state = "paramedic-eva-helmet" \ No newline at end of file + item_state = "paramedic-eva-helmet" diff --git a/code/modules/clothing/suits/cloaks.dm b/code/modules/clothing/suits/cloaks.dm index c765247dc0..d5f65e4fa8 100644 --- a/code/modules/clothing/suits/cloaks.dm +++ b/code/modules/clothing/suits/cloaks.dm @@ -76,7 +76,7 @@ icon_state = "dragon" desc = "A suit of armour fashioned from the remains of an ash drake." allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe, /obj/item/spear) - armor = list("melee" = 60, "bullet" = 20, "laser" = 30, "energy" = 25, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) + armor = list("melee" = 70, "bullet" = 20, "laser" = 35, "energy" = 25, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) hoodtype = /obj/item/clothing/head/hooded/cloakhood/drake heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS @@ -87,7 +87,7 @@ name = "drake helm" icon_state = "dragon" desc = "The skull of a dragon." - armor = list("melee" = 60, "bullet" = 20, "laser" = 30, "energy" = 25, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) + armor = list("melee" = 70, "bullet" = 20, "laser" = 35, "energy" = 25, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) heat_protection = HEAD max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF | ACID_PROOF | GOLIATH_RESISTANCE diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index fadb1b481b..cf69f65e0f 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -647,6 +647,19 @@ desc = "A white winter coat hood with green markings." icon_state = "winterhood_viro" +/obj/item/clothing/suit/hooded/wintercoat/paramedic + name = "paramedic winter coat" + desc = "A winter coat with blue markings. Warm, but probably won't protect from biological agents. For the cozy doctor on the go." + icon_state = "coatparamed" + item_state = "coatparamed" + allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 0, "acid" = 45) + hoodtype = /obj/item/clothing/head/hooded/winterhood/paramedic + +/obj/item/clothing/head/hooded/winterhood/paramedic + desc = "A white winter coat hood with blue markings." + icon_state = "winterhood_paramed" + /obj/item/clothing/suit/hooded/wintercoat/science name = "science winter coat" desc = "A white winter coat with an outdated atomic model instead of a plastic zipper tab." diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm index c9b7695779..98fb836c38 100644 --- a/code/modules/clothing/suits/reactive_armour.dm +++ b/code/modules/clothing/suits/reactive_armour.dm @@ -164,21 +164,21 @@ desc = "An experimental suit of armor with sensitive detectors hooked up to a huge capacitor grid, with emitters strutting out of it. Zap." siemens_coefficient = -1 reactivearmor_cooldown_duration = 20 - var/tesla_power = 25000 - var/tesla_range = 20 - var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE + var/zap_power = 25000 + var/zap_range = 20 + var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE var/legacy = FALSE var/legacy_dmg = 30 /obj/item/clothing/suit/armor/reactive/tesla/dropped(mob/user) ..() if(istype(user)) - user.flags_1 &= ~TESLA_IGNORE_1 + REMOVE_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "reactive_tesla_armor") /obj/item/clothing/suit/armor/reactive/tesla/equipped(mob/user, slot) ..() if(slot_flags & slotdefine2slotbit(slot)) //Was equipped to a valid slot for this item? - user.flags_1 |= TESLA_IGNORE_1 + ADD_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "reactive_tesla_armor") /obj/item/clothing/suit/armor/reactive/tesla/block_action(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) if(prob(hit_reaction_chance)) @@ -190,7 +190,7 @@ return owner.visible_message("[src] blocks [attack_text], sending out arcs of lightning!") if(!legacy) - tesla_zap(owner, tesla_range, tesla_power, tesla_flags) + tesla_zap(owner, zap_range, zap_power, zap_flags) else for(var/mob/living/M in view(7, owner)) if(M == owner) diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm index 88821e1afe..cb173f3bde 100644 --- a/code/modules/clothing/under/accessories.dm +++ b/code/modules/clothing/under/accessories.dm @@ -329,14 +329,14 @@ name = "bone talisman" desc = "A hunter's talisman, some say the old gods smile on those who wear it." icon_state = "talisman" - armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 20, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25) + armor = list("melee" = 5, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25) /obj/item/clothing/accessory/skullcodpiece name = "skull codpiece" desc = "A skull shaped ornament, intended to protect the important things in life." icon_state = "skull" above_suit = TRUE - armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 20, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25) + armor = list("melee" = 5, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25) /obj/item/clothing/accessory/skullcodpiece/fake name = "false codpiece" diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index f361a72d17..2c1299f5b4 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -1258,7 +1258,7 @@ GLOBAL_LIST_INIT(hallucination_list, list( ..() if(!target.halbody) var/list/possible_points = list() - for(var/turf/open/floor/F in target.visible_atoms(world.view)) + for(var/turf/open/floor/F in target.fov_view(world.view)) possible_points += F if(possible_points.len) var/turf/open/floor/husk_point = pick(possible_points) @@ -1289,7 +1289,7 @@ GLOBAL_LIST_INIT(hallucination_list, list( set waitfor = FALSE ..() var/list/turf/startlocs = list() - for(var/turf/open/T in target.visible_atoms(world.view+1)-view(world.view,target)) + for(var/turf/open/T in target.fov_view(world.view+1)-view(world.view,target)) startlocs += T if(!startlocs.len) qdel(src) diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html index 314cd42446..0acb127517 100644 --- a/code/modules/goonchat/browserassets/html/browserOutput.html +++ b/code/modules/goonchat/browserassets/html/browserOutput.html @@ -29,7 +29,7 @@ --ms
- +
diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm index 7f6d48e731..107282b642 100644 --- a/code/modules/holiday/halloween/jacqueen.dm +++ b/code/modules/holiday/halloween/jacqueen.dm @@ -38,8 +38,10 @@ health = 25 density = FALSE speech_span = "spooky" - friendly = "pets" - response_help = "chats with" + friendly_verb_continuous = "pets" + friendly_verb_simple = "pet" + response_help_continuous = "chats with" + response_help_simple = "chat with" light_range = 3 light_color = "#ff9842" var/last_poof diff --git a/code/modules/holodeck/mobs.dm b/code/modules/holodeck/mobs.dm index adac4ea7b2..121989bf1e 100644 --- a/code/modules/holodeck/mobs.dm +++ b/code/modules/holodeck/mobs.dm @@ -15,6 +15,9 @@ speak_chance = 1 turns_per_move = 2 butcher_results = list() - response_help = "pets" - response_disarm = "pushes aside" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "pushes aside" + response_disarm_simple = "push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm index 4b6b8723dd..8f9a45ac4d 100644 --- a/code/modules/integrated_electronics/passive/power.dm +++ b/code/modules/integrated_electronics/passive/power.dm @@ -89,7 +89,7 @@ desc = "Produces electricity from chemicals." icon_state = "chemical_cell" extended_desc = "This is effectively an internal beaker. It will consume and produce power from plasma, slime jelly, welding fuel, carbon,\ - ethanol, nutriment, and blood in order of decreasing efficiency. It will consume fuel only if the battery can take more energy." + ethanol, nutriment, and blood in order of decreasing efficiency. It will consume fuel only if the battery can take more energy. But no fuel can be compared with blood of living human." complexity = 4 inputs = list() outputs = list("volume used" = IC_PINTYPE_NUMBER, "self reference" = IC_PINTYPE_SELFREF) @@ -102,10 +102,8 @@ var/lfwb =TRUE /obj/item/integrated_circuit/passive/power/chemical_cell/Initialize() - ..() + . = ..() create_reagents(volume, OPENCONTAINER) - extended_desc +="But no fuel can be compared with blood of living human." - /obj/item/integrated_circuit/passive/power/chemical_cell/interact(mob/user) set_pin_data(IC_OUTPUT, 2, WEAKREF(src)) diff --git a/code/modules/integrated_electronics/subtypes/converters.dm b/code/modules/integrated_electronics/subtypes/converters.dm index 8c7529651b..ebb91a894e 100644 --- a/code/modules/integrated_electronics/subtypes/converters.dm +++ b/code/modules/integrated_electronics/subtypes/converters.dm @@ -426,7 +426,7 @@ activators = list("compute abs coordinates" = IC_PINTYPE_PULSE_IN, "on convert" = IC_PINTYPE_PULSE_OUT) spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH -/obj/item/integrated_circuit/converter/abs_to_rel_coords/do_work() +/obj/item/integrated_circuit/converter/rel_to_abs_coords/do_work() var/x1 = get_pin_data(IC_INPUT, 1) var/y1 = get_pin_data(IC_INPUT, 2) @@ -456,7 +456,7 @@ activators = list("compute abs coordinates" = IC_PINTYPE_PULSE_IN, "on convert" = IC_PINTYPE_PULSE_OUT) spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH -/obj/item/integrated_circuit/converter/abs_to_rel_coords/do_work() +/obj/item/integrated_circuit/converter/adv_rel_to_abs_coords/do_work() var/turf/T = get_turf(src) if(!T) diff --git a/code/modules/integrated_electronics/subtypes/weaponized.dm b/code/modules/integrated_electronics/subtypes/weaponized.dm index 88742dfa9a..80c56d90c2 100644 --- a/code/modules/integrated_electronics/subtypes/weaponized.dm +++ b/code/modules/integrated_electronics/subtypes/weaponized.dm @@ -296,6 +296,7 @@ var/x_abs = clamp(T.x + target_x_rel, 0, world.maxx) var/y_abs = clamp(T.y + target_y_rel, 0, world.maxy) var/range = round(clamp(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1) + playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1) assembly.visible_message("\The [assembly] has thrown [A]!") log_attack("[assembly] [REF(assembly)] has thrown [A] with lethal force.") A.forceMove(drop_location()) diff --git a/code/modules/keybindings/bindings_admin.dm b/code/modules/keybindings/bindings_admin.dm deleted file mode 100644 index ca232adbe0..0000000000 --- a/code/modules/keybindings/bindings_admin.dm +++ /dev/null @@ -1,24 +0,0 @@ -/datum/admins/key_down(_key, client/user) - switch(_key) - if("F3") - user.get_admin_say() - return - if("F5") - user.admin_ghost() - return - if("F6") - player_panel_new() - return - if("F7") - user.togglebuildmodeself() - return - if("F8") - if(user.keys_held["Ctrl"]) - user.stealth() - else - user.invisimin() - return - if("F10") - user.get_dead_say() - return - ..() diff --git a/code/modules/keybindings/bindings_atom.dm b/code/modules/keybindings/bindings_atom.dm index 5f3e879237..47d6b16feb 100644 --- a/code/modules/keybindings/bindings_atom.dm +++ b/code/modules/keybindings/bindings_atom.dm @@ -5,7 +5,7 @@ if(!user.keys_held["Ctrl"]) var/movement_dir = NONE for(var/_key in user.keys_held) - movement_dir = movement_dir | SSinput.movement_keys[_key] + movement_dir = movement_dir | user.movement_keys[_key] if(user.next_move_dir_add) movement_dir |= user.next_move_dir_add if(user.next_move_dir_sub) diff --git a/code/modules/keybindings/bindings_carbon.dm b/code/modules/keybindings/bindings_carbon.dm deleted file mode 100644 index e344bc9d20..0000000000 --- a/code/modules/keybindings/bindings_carbon.dm +++ /dev/null @@ -1,9 +0,0 @@ -/mob/living/carbon/key_down(_key, client/user) - switch(_key) - if("R", "Southwest") // Southwest is End - toggle_throw_mode() - return - if("C") - user_toggle_intentional_combat_mode() - return - return ..() \ No newline at end of file diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm index 6030362a61..a73dd9a59b 100644 --- a/code/modules/keybindings/bindings_client.dm +++ b/code/modules/keybindings/bindings_client.dm @@ -33,55 +33,69 @@ to_chat(src, "Invalid KeyDown detected! You have been disconnected from the server automatically.") log_admin("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.") message_admins("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.") - QDEL_IN(src, 1) + qdel(src) + return + + if(_key == "Tab") + ForceAllKeysUp() //groan, more hacky kevcode return if(length(keys_held) > MAX_HELD_KEYS) keys_held.Cut(1,2) keys_held[_key] = TRUE - var/movement = SSinput.movement_keys[_key] + var/movement = movement_keys[_key] if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"]) next_move_dir_add |= movement // Client-level keybindings are ones anyone should be able to do at any time // Things like taking screenshots, hitting tab, and adminhelps. - + var/AltMod = keys_held["Alt"] ? "Alt" : "" + var/CtrlMod = keys_held["Ctrl"] ? "Ctrl" : "" + var/ShiftMod = keys_held["Shift"] ? "Shift" : "" + var/full_key switch(_key) - if("F1") - if(keys_held["Ctrl"] && keys_held["Shift"]) // Is this command ever used? - winset(src, null, "command=.options") - else - get_adminhelp() - return - if("F2") // Screenshot. Hold shift to choose a name and location to save in - winset(src, null, "command=.screenshot [!keys_held["shift"] ? "auto" : ""]") - return - if("F12") // Toggles minimal HUD - mob.button_pressed_F12() - return + if("Alt", "Ctrl", "Shift") + full_key = "[AltMod][CtrlMod][ShiftMod]" + else + full_key = "[AltMod][CtrlMod][ShiftMod][_key]" + var/keycount = 0 + for(var/kb_name in prefs.key_bindings[full_key]) + keycount++ + var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name] + if(kb.can_use(src) && kb.down(src) && keycount >= MAX_COMMANDS_PER_KEY) + break - if(holder) - holder.key_down(_key, src) - if(mob.focus) - mob.focus.key_down(_key, src) + holder?.key_down(_key, src) + mob.focus?.key_down(_key, src) + +/// Keyup's all keys held down. +/client/proc/ForceAllKeysUp() + // simulate a user releasing all keys except for the mod keys. groan. i hate this. thanks, byond. why aren't keyups able to be forced to fire on macro change aoaoaoao. + // groan + for(var/key in keys_held) // all of these won't be the 3 mod keys. + if((key == "Ctrl") || (key == "Alt") || (key == "Shift")) + continue + keyUp("[key]") /client/verb/keyUp(_key as text) set instant = TRUE set hidden = TRUE keys_held -= _key - var/movement = SSinput.movement_keys[_key] + var/movement = movement_keys[_key] if(!(next_move_dir_add & movement)) next_move_dir_sub |= movement - if(holder) - holder.key_up(_key, src) - if(mob.focus) - mob.focus.key_up(_key, src) + // We don't do full key for release, because for mod keys you + // can hold different keys and releasing any should be handled by the key binding specifically + for (var/kb_name in prefs.key_bindings[_key]) + var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name] + if(kb.can_use(src) && kb.up(src)) + break + holder?.key_up(_key, src) + mob.focus?.key_up(_key, src) // Called every game tick /client/keyLoop() - if(holder) - holder.keyLoop(src) - if(mob.focus) - mob.focus.keyLoop(src) \ No newline at end of file + holder?.keyLoop(src) + mob.focus?.keyLoop(src) diff --git a/code/modules/keybindings/bindings_human.dm b/code/modules/keybindings/bindings_human.dm deleted file mode 100644 index 9569de338c..0000000000 --- a/code/modules/keybindings/bindings_human.dm +++ /dev/null @@ -1,80 +0,0 @@ -/mob/living/carbon/human/key_down(_key, client/user) - if(client.keys_held["Shift"]) - switch(_key) - if("E") // Put held thing in belt or take out most recent thing from belt - var/obj/item/thing = get_active_held_item() - var/obj/item/storage/equipped_belt = get_item_by_slot(SLOT_BELT) - if(!equipped_belt) // We also let you equip a belt like this - if(!thing) - to_chat(user, "You have no belt to take something out of.") - return - equip_to_slot_if_possible(thing, SLOT_BELT) - return - if(!istype(equipped_belt)) // not a storage item - if(!thing) - to_chat(user, "You have no belt to take something out of.") - else - to_chat(user, "You can't fit anything in.") - return - if(thing) // put thing in belt - if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, user.mob)) - to_chat(user, "You can't fit anything in.") - return - if(!equipped_belt.contents.len) // nothing to take out - to_chat(user, "There's nothing in your belt to take out.") - return - var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len] - if(!stored || stored.on_found(src)) - return - stored.attack_hand(src) // take out thing from belt - return - - if("B") // Put held thing in backpack or take out most recent thing from backpack - var/obj/item/thing = get_active_held_item() - var/obj/item/storage/equipped_backpack = get_item_by_slot(SLOT_BACK) - if(!equipped_backpack) // We also let you equip a backpack like this - if(!thing) - to_chat(user, "You have no backpack to take something out of.") - return - equip_to_slot_if_possible(thing, SLOT_BACK) - return - if(!istype(equipped_backpack)) // not a storage item - if(!thing) - to_chat(user, "You have no backpack to take something out of.") - else - to_chat(user, "You can't fit anything in.") - return - if(thing) // put thing in backpack - if(!SEND_SIGNAL(equipped_backpack, COMSIG_TRY_STORAGE_INSERT, thing, user.mob)) - to_chat(user, "You can't fit anything in.") - return - if(!equipped_backpack.contents.len) // nothing to take out - to_chat(user, "There's nothing in your backpack to take out.") - return - var/obj/item/stored = equipped_backpack.contents[equipped_backpack.contents.len] - if(!stored || stored.on_found(src)) - return - stored.attack_hand(src) // take out thing from backpack - return - switch(_key) - if("Shift") - if(!user.prefs.sprint_spacebar) - user.prefs.sprint_toggle ? default_toggle_sprint() : sprint_hotkey(TRUE) //Yes, this looks hacky. Yes, this works. - return - if("Space") - if(user.prefs.sprint_spacebar) - user.prefs.sprint_toggle ? default_toggle_sprint() : sprint_hotkey(TRUE) - return - return ..() - -/mob/living/carbon/human/key_up(_key, client/user) - switch(_key) - if("Shift") - if(!user.prefs.sprint_spacebar && !user.prefs.sprint_toggle) - sprint_hotkey(FALSE) - return - if("Space") - if(user.prefs.sprint_spacebar && !user.prefs.sprint_toggle) - sprint_hotkey(FALSE) - return - return ..() diff --git a/code/modules/keybindings/bindings_living.dm b/code/modules/keybindings/bindings_living.dm deleted file mode 100644 index b338c5e899..0000000000 --- a/code/modules/keybindings/bindings_living.dm +++ /dev/null @@ -1,26 +0,0 @@ -/mob/living/key_down(_key, client/user) - switch(_key) - if("B") - resist() - return - if("1") - if(possible_a_intents) - a_intent_change(INTENT_HELP) - return - if("2") - if(possible_a_intents) - a_intent_change(INTENT_DISARM) - return - if("3") - if(possible_a_intents) - a_intent_change(INTENT_GRAB) - return - if("4") - if(possible_a_intents) - a_intent_change(INTENT_HARM) - return - if ("V") - lay_down() - return - - return ..() \ No newline at end of file diff --git a/code/modules/keybindings/bindings_mob.dm b/code/modules/keybindings/bindings_mob.dm deleted file mode 100644 index 36b4775c34..0000000000 --- a/code/modules/keybindings/bindings_mob.dm +++ /dev/null @@ -1,94 +0,0 @@ -// Technically the client argument is unncessary here since that SHOULD be src.client but let's not assume things -// All it takes is one badmin setting their focus to someone else's client to mess things up -// Or we can have NPC's send actual keypresses and detect that by seeing no client - -/mob/key_down(_key, client/user) - switch(_key) - if("Delete", "H") - if(!pulling) - to_chat(src, "You are not pulling anything.") - else - stop_pulling() - return - if("Insert", "G") - a_intent_change(INTENT_HOTKEY_RIGHT) - return - if("F") - a_intent_change(INTENT_HOTKEY_LEFT) - return - if("X", "Northeast") // Northeast is Page-up - swap_hand() - return - if("Y", "Z", "Southeast") // Southeast is Page-down - mode() // attack_self(). No idea who came up with "mode()" - return - if("Q", "Northwest") // Northwest is Home - var/obj/item/I = get_active_held_item() - if(!I) - to_chat(src, "You have nothing to drop in your hand!") - else - dropItemToGround(I) - return - if("E") - quick_equip() - return - if("Alt") - toggle_move_intent() - return - //Bodypart selections - if("Numpad8") - user.body_toggle_head() - return - if("Numpad4") - user.body_r_arm() - return - if("Numpad5") - user.body_chest() - return - if("Numpad6") - user.body_l_arm() - return - if("Numpad1") - user.body_r_leg() - return - if("Numpad2") - user.body_groin() - return - if("Numpad3") - user.body_l_leg() - return - - if(client.keys_held["Ctrl"]) - switch(SSinput.movement_keys[_key]) - if(NORTH) - if(client.keys_held["Shift"]) - northshift() - else - northface() - return - if(SOUTH) - if(client.keys_held["Shift"]) - southshift() - else - southface() - return - if(WEST) - if(client.keys_held["Shift"]) - westshift() - else - westface() - return - if(EAST) - if(client.keys_held["Shift"]) - eastshift() - else - eastface() - return - return ..() - -/mob/key_up(_key, client/user) - switch(_key) - if("Alt") - toggle_move_intent() - return - return ..() diff --git a/code/modules/keybindings/bindings_robot.dm b/code/modules/keybindings/bindings_robot.dm deleted file mode 100644 index 29fb36fa65..0000000000 --- a/code/modules/keybindings/bindings_robot.dm +++ /dev/null @@ -1,22 +0,0 @@ -/mob/living/silicon/robot/key_down(_key, client/user) - switch(_key) - if("1", "2", "3") - toggle_module(text2num(_key)) - return - if("4") - a_intent_change(INTENT_HOTKEY_LEFT) - return - if("Q") - uneq_active() - return - if("Shift") - sprint_hotkey(TRUE) - return - return ..() - -/mob/living/silicon/robot/key_up(_key, client/user) - switch(_key) - if("Shift") - sprint_hotkey(FALSE) - return - return ..() diff --git a/code/modules/keybindings/focus.dm b/code/modules/keybindings/focus.dm index 205b293e9a..d542b49267 100644 --- a/code/modules/keybindings/focus.dm +++ b/code/modules/keybindings/focus.dm @@ -1,6 +1,3 @@ -/mob - var/datum/focus //What receives our keyboard inputs. src by default - /mob/proc/set_focus(datum/new_focus) if(focus == new_focus) return diff --git a/code/modules/keybindings/keybind/__defines.dm b/code/modules/keybindings/keybind/__defines.dm new file mode 100644 index 0000000000..baa095987c --- /dev/null +++ b/code/modules/keybindings/keybind/__defines.dm @@ -0,0 +1,20 @@ +#define CATEGORY_CLIENT "CLIENT" +#define CATEGORY_EMOTE "EMOTE" +#define CATEGORY_ADMIN "ADMIN" +#define CATEGORY_XENO "XENO" +#define CATEGORY_CARBON "CARBON" +#define CATEGORY_HUMAN "HUMAN" +#define CATEGORY_ROBOT "ROBOT" +#define CATEGORY_MISC "MISC" +#define CATEGORY_MOVEMENT "MOVEMENT" +#define CATEGORY_TARGETING "TARGETING" + +#define WEIGHT_HIGHEST 0 +#define WEIGHT_ADMIN 10 +#define WEIGHT_CLIENT 20 +#define WEIGHT_ROBOT 30 +#define WEIGHT_MOB 40 +#define WEIGHT_LIVING 50 +#define WEIGHT_DEAD 60 +#define WEIGHT_EMOTE 70 +#define WEIGHT_LOWEST 999 diff --git a/code/modules/keybindings/keybind/_keybind.dm b/code/modules/keybindings/keybind/_keybind.dm new file mode 100644 index 0000000000..1d68e2d037 --- /dev/null +++ b/code/modules/keybindings/keybind/_keybind.dm @@ -0,0 +1,24 @@ +/datum/keybinding + var/list/hotkey_keys + var/list/classic_keys + var/name + var/full_name + var/description = "" + var/category = CATEGORY_MISC + var/weight = WEIGHT_LOWEST + var/keybind_signal + +/datum/keybinding/New() + + // Default keys to the master "hotkey_keys" + if(LAZYLEN(hotkey_keys) && !LAZYLEN(classic_keys)) + classic_keys = hotkey_keys.Copy() + +/datum/keybinding/proc/down(client/user) + return FALSE + +/datum/keybinding/proc/up(client/user) + return FALSE + +/datum/keybinding/proc/can_use(client/user) + return TRUE diff --git a/code/modules/keybindings/keybind/admin.dm b/code/modules/keybindings/keybind/admin.dm new file mode 100644 index 0000000000..b63221e97a --- /dev/null +++ b/code/modules/keybindings/keybind/admin.dm @@ -0,0 +1,96 @@ +/datum/keybinding/admin + category = CATEGORY_ADMIN + weight = WEIGHT_ADMIN + +/datum/keybinding/admin/can_use(client/user) + return user.holder ? TRUE : FALSE + +/datum/keybinding/admin/admin_say + hotkey_keys = list("F3") + name = "admin_say" + full_name = "Admin say" + description = "Talk with other admins." + +/datum/keybinding/admin/admin_say/down(client/user) + user.get_admin_say() + return TRUE + +/datum/keybinding/admin/admin_ghost + hotkey_keys = list("F5") + name = "admin_ghost" + full_name = "Aghost" + description = "Go ghost" + +/datum/keybinding/admin/admin_ghost/down(client/user) + user.admin_ghost() + return TRUE + +/datum/keybinding/admin/player_panel_new + hotkey_keys = list("F6") + name = "player_panel_new" + full_name = "Player Panel New" + description = "Opens up the new player panel" + +/datum/keybinding/admin/player_panel_new/down(client/user) + user.holder.player_panel_new() + return TRUE + +/datum/keybinding/admin/toggle_buildmode_self + hotkey_keys = list("F7") + name = "toggle_buildmode_self" + full_name = "Toggle Buildmode Self" + description = "Toggles buildmode" + +/datum/keybinding/admin/toggle_buildmode_self/down(client/user) + user.togglebuildmodeself() + return TRUE + +/datum/keybinding/admin/stealthmode + hotkey_keys = list("CtrlF8") + name = "stealth_mode" + full_name = "Stealth mode" + description = "Enters stealth mode" + +/datum/keybinding/admin/stealthmode/down(client/user) + user.stealth() + return TRUE + +/datum/keybinding/admin/invisimin + hotkey_keys = list("F8") + name = "invisimin" + full_name = "Admin invisibility" + description = "Toggles ghost-like invisibility (Don't abuse this)" + +/datum/keybinding/admin/invisimin/down(client/user) + user.invisimin() + return TRUE + +/datum/keybinding/admin/deadsay + hotkey_keys = list("F10") + name = "dsay" + full_name = "deadsay" + description = "Allows you to send a message to dead chat" + +/datum/keybinding/admin/deadsay/down(client/user) + user.get_dead_say() + return TRUE + +/datum/keybinding/admin/deadmin + hotkey_keys = list("Unbound") + name = "deadmin" + full_name = "Deadmin" + description = "Shed your admin powers" + +/datum/keybinding/admin/deadmin/down(client/user) + user.deadmin() + return TRUE + +/datum/keybinding/admin/readmin + hotkey_keys = list("Unbound") + name = "readmin" + full_name = "Readmin" + description = "Regain your admin powers" + +/datum/keybinding/admin/readmin/down(client/user) + user.readmin() + return TRUE diff --git a/code/modules/keybindings/keybind/carbon.dm b/code/modules/keybindings/keybind/carbon.dm new file mode 100644 index 0000000000..46cb5cd0ac --- /dev/null +++ b/code/modules/keybindings/keybind/carbon.dm @@ -0,0 +1,62 @@ +/datum/keybinding/carbon + category = CATEGORY_CARBON + weight = WEIGHT_MOB + +/datum/keybinding/carbon/can_use(client/user) + return iscarbon(user.mob) + +/datum/keybinding/carbon/toggle_throw_mode + hotkey_keys = list("R", "Southwest") // END + name = "toggle_throw_mode" + full_name = "Toggle throw mode" + description = "Toggle throwing the current item or not." + category = CATEGORY_CARBON + +/datum/keybinding/carbon/toggle_throw_mode/down(client/user) + var/mob/living/carbon/C = user.mob + C.toggle_throw_mode() + return TRUE + +/datum/keybinding/carbon/select_help_intent + hotkey_keys = list("1") + name = "select_help_intent" + full_name = "Select help intent" + description = "" + category = CATEGORY_CARBON + +/datum/keybinding/carbon/select_help_intent/down(client/user) + user.mob?.a_intent_change(INTENT_HELP) + return TRUE + +/datum/keybinding/carbon/select_disarm_intent + hotkey_keys = list("2") + name = "select_disarm_intent" + full_name = "Select disarm intent" + description = "" + category = CATEGORY_CARBON + +/datum/keybinding/carbon/select_disarm_intent/down(client/user) + user.mob?.a_intent_change(INTENT_DISARM) + return TRUE + +/datum/keybinding/carbon/select_grab_intent + hotkey_keys = list("3") + name = "select_grab_intent" + full_name = "Select grab intent" + description = "" + category = CATEGORY_CARBON + +/datum/keybinding/carbon/select_grab_intent/down(client/user) + user.mob?.a_intent_change(INTENT_GRAB) + return TRUE + +/datum/keybinding/carbon/select_harm_intent + hotkey_keys = list("4") + name = "select_harm_intent" + full_name = "Select harm intent" + description = "" + category = CATEGORY_CARBON + +/datum/keybinding/carbon/select_harm_intent/down(client/user) + user.mob?.a_intent_change(INTENT_HARM) + return TRUE diff --git a/code/modules/keybindings/keybind/client.dm b/code/modules/keybindings/keybind/client.dm new file mode 100644 index 0000000000..1d44efa063 --- /dev/null +++ b/code/modules/keybindings/keybind/client.dm @@ -0,0 +1,33 @@ +/datum/keybinding/client + category = CATEGORY_CLIENT + weight = WEIGHT_HIGHEST + +/datum/keybinding/client/admin_help + hotkey_keys = list("F1") + name = "admin_help" + full_name = "Admin Help" + description = "Ask an admin for help." + +/datum/keybinding/client/admin_help/down(client/user) + user.get_adminhelp() + return TRUE + +/datum/keybinding/client/screenshot + hotkey_keys = list("F2") + name = "screenshot" + full_name = "Screenshot" + description = "Take a screenshot." + +/datum/keybinding/client/screenshot/down(client/user) + winset(user, null, "command=.screenshot [!user.keys_held["shift"] ? "auto" : ""]") + return TRUE + +/datum/keybinding/client/minimal_hud + hotkey_keys = list("F12") + name = "minimal_hud" + full_name = "Minimal HUD" + description = "Hide most HUD features" + +/datum/keybinding/client/minimal_hud/down(client/user) + user.mob.button_pressed_F12() + return TRUE diff --git a/code/modules/keybindings/keybind/emote.dm b/code/modules/keybindings/keybind/emote.dm new file mode 100644 index 0000000000..6099826819 --- /dev/null +++ b/code/modules/keybindings/keybind/emote.dm @@ -0,0 +1,15 @@ +/datum/keybinding/emote + category = CATEGORY_EMOTE + weight = WEIGHT_EMOTE + var/emote_key + +/datum/keybinding/emote/proc/link_to_emote(datum/emote/faketype) + hotkey_keys = list("Unbound") + emote_key = initial(faketype.key) + name = initial(faketype.key) + full_name = capitalize(initial(faketype.key)) + description = "Do the emote '*[emote_key]'" + +/datum/keybinding/emote/down(client/user) + . = ..() + return user.mob.emote(emote_key, intentional=TRUE) diff --git a/code/modules/keybindings/keybind/human.dm b/code/modules/keybindings/keybind/human.dm new file mode 100644 index 0000000000..43f5653472 --- /dev/null +++ b/code/modules/keybindings/keybind/human.dm @@ -0,0 +1,39 @@ +/datum/keybinding/human + category = CATEGORY_HUMAN + weight = WEIGHT_MOB + +/datum/keybinding/human/can_use(client/user) + return ishuman(user.mob) + +/datum/keybinding/human/quick_equip + hotkey_keys = list("E") + name = "quick_equip" + full_name = "Quick Equip" + description = "Quickly puts an item in the best slot available" + +/datum/keybinding/human/quick_equip/down(client/user) + var/mob/living/carbon/human/H = user.mob + H.quick_equip() + return TRUE + +/datum/keybinding/human/quick_equipbelt + hotkey_keys = list("ShiftE") + name = "quick_equipbelt" + full_name = "Quick equip belt" + description = "Put held thing in belt or take out most recent thing from belt" + +/datum/keybinding/human/quick_equipbelt/down(client/user) + var/mob/living/carbon/human/H = user.mob + H.smart_equipbelt() + return TRUE + +/datum/keybinding/human/bag_equip + hotkey_keys = list("ShiftB") + name = "bag_equip" + full_name = "Bag equip" + description = "Put held thing in backpack or take out most recent thing from backpack" + +/datum/keybinding/human/bag_equip/down(client/user) + var/mob/living/carbon/human/H = user.mob + H.smart_equipbag() + return TRUE diff --git a/code/modules/keybindings/keybind/living.dm b/code/modules/keybindings/keybind/living.dm new file mode 100644 index 0000000000..0408d0889b --- /dev/null +++ b/code/modules/keybindings/keybind/living.dm @@ -0,0 +1,41 @@ +/datum/keybinding/living + category = CATEGORY_HUMAN + weight = WEIGHT_MOB + +/datum/keybinding/living/can_use(client/user) + return isliving(user.mob) + +/datum/keybinding/living/resist + hotkey_keys = list("B") + name = "resist" + full_name = "Resist" + description = "Break free of your current state. Handcuffed? on fire? Resist!" + +/datum/keybinding/living/resist/down(client/user) + var/mob/living/L = user.mob + L.resist() + return TRUE + +/datum/keybinding/living/toggle_combat_mode + hotkey_keys = list("C") + name = "toggle_combat_mode" + full_name = "Toggle combat mode" + description = "Toggles whether or not you're in combat mode." + +/datum/keybinding/living/toggle_combat_mode/can_use(client/user) + return iscarbon(user.mob) // for now, only carbons should be using combat mode, although all livings have combat mode implemented. + +/datum/keybinding/living/toggle_combat_mode/down(client/user) + var/mob/living/carbon/C = user.mob + C.user_toggle_intentional_combat_mode() + return TRUE + +/datum/keybinding/living/toggle_resting + hotkey_keys = list("V") + name = "toggle_resting" + full_name = "Toggle Resting" + description = "Toggles whether or not you are intentionally laying down." + +/datum/keybinding/living/toggle_resting/down(client/user) + var/mob/living/L = user.mob + L.lay_down() diff --git a/code/modules/keybindings/keybind/mob.dm b/code/modules/keybindings/keybind/mob.dm new file mode 100644 index 0000000000..083d4a19fd --- /dev/null +++ b/code/modules/keybindings/keybind/mob.dm @@ -0,0 +1,123 @@ +/datum/keybinding/mob + category = CATEGORY_HUMAN + weight = WEIGHT_MOB + +/datum/keybinding/mob/stop_pulling + hotkey_keys = list("H", "Delete") + name = "stop_pulling" + full_name = "Stop pulling" + description = "" + +/datum/keybinding/mob/stop_pulling/down(client/user) + var/mob/M = user.mob + if(!M.pulling) + to_chat(user, "You are not pulling anything.") + else + M.stop_pulling() + return TRUE + +/datum/keybinding/mob/cycle_intent_right + hotkey_keys = list("Northwest", "F") // HOME + name = "cycle_intent_right" + full_name = "Cycle Action Intent Right" + description = "" + +/datum/keybinding/mob/cycle_intent_right/down(client/user) + var/mob/M = user.mob + M.a_intent_change(INTENT_HOTKEY_RIGHT) + return TRUE + +/datum/keybinding/mob/cycle_intent_left + hotkey_keys = list("Insert", "G") + name = "cycle_intent_left" + full_name = "Cycle Action Intent Left" + description = "" + +/datum/keybinding/mob/cycle_intent_left/down(client/user) + var/mob/M = user.mob + M.a_intent_change(INTENT_HOTKEY_LEFT) + return TRUE + +/datum/keybinding/mob/swap_hands + hotkey_keys = list("X", "Northeast") // PAGEUP + name = "swap_hands" + full_name = "Swap hands" + description = "" + +/datum/keybinding/mob/swap_hands/down(client/user) + var/mob/M = user.mob + M.swap_hand() + return TRUE + +/datum/keybinding/mob/activate_inhand + hotkey_keys = list("Z", "Southeast") // PAGEDOWN + name = "activate_inhand" + full_name = "Activate in-hand" + description = "Uses whatever item you have inhand" + +/datum/keybinding/mob/activate_inhand/down(client/user) + var/mob/M = user.mob + M.mode() + return TRUE + +/datum/keybinding/mob/drop_item + hotkey_keys = list("Q") + name = "drop_item" + full_name = "Drop Item" + description = "" + +/datum/keybinding/mob/drop_item/down(client/user) + if(iscyborg(user.mob)) //cyborgs can't drop items + return FALSE + var/mob/M = user.mob + var/obj/item/I = M.get_active_held_item() + if(!I) + to_chat(user, "You have nothing to drop in your hand!") + else + user.mob.dropItemToGround(I) + return TRUE + +/datum/keybinding/mob/say_with_indicator + hotkey_keys = list("CtrlT") + classic_keys = list() + name = "say_with_indicator" + full_name = "Say with Typing Indicator" + +/datum/keybinding/mob/say_with_indicator/down(client/user) + var/mob/M = user.mob + M.say_typing_indicator() + return TRUE + +/datum/keybinding/mob/me_with_indicator + hotkey_keys = list("CtrlM") + classic_keys = list() + name = "me_with_indicator" + full_name = "Me (emote) with Typing Indicator" + +/datum/keybinding/mob/me_with_indicator/down(client/user) + var/mob/M = user.mob + M.me_typing_indicator() + return TRUE + +/datum/keybinding/living/subtle + hotkey_keys = list("5") + classic_keys = list() + name = "subtle_emote" + full_name = "Subtle Emote" + +/datum/keybinding/living/subtle/down(client/user) + var/mob/living/L = user.mob + L.subtle_keybind() + return TRUE + +/datum/keybinding/mob/whisper + hotkey_keys = list("Y") + classic_keys = list() + name = "whisper" + full_name = "Whisper" + +/datum/keybinding/mob/whisper/down(client/user) + var/mob/M = user.mob + M.whisper_keybind() + return TRUE + diff --git a/code/modules/keybindings/keybind/movement.dm b/code/modules/keybindings/keybind/movement.dm new file mode 100644 index 0000000000..176e6b9fb8 --- /dev/null +++ b/code/modules/keybindings/keybind/movement.dm @@ -0,0 +1,187 @@ +/datum/keybinding/movement + category = CATEGORY_MOVEMENT + weight = WEIGHT_HIGHEST + +/datum/keybinding/movement/north + hotkey_keys = list("W", "North") + name = "North" + full_name = "Move North" + description = "Moves your character north" + +/datum/keybinding/movement/south + hotkey_keys = list("S", "South") + name = "South" + full_name = "Move South" + description = "Moves your character south" + +/datum/keybinding/movement/west + hotkey_keys = list("A", "West") + name = "West" + full_name = "Move West" + description = "Moves your character left" + +/datum/keybinding/movement/east + hotkey_keys = list("D", "East") + name = "East" + full_name = "Move East" + description = "Moves your character east" + +/datum/keybinding/mob/face_north + hotkey_keys = list("CtrlW", "CtrlNorth") + name = "face_north" + full_name = "Face North" + description = "" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/face_north/down(client/user) + var/mob/M = user.mob + M.northface() + return TRUE + +/datum/keybinding/mob/face_east + hotkey_keys = list("CtrlD", "CtrlEast") + name = "face_east" + full_name = "Face East" + description = "" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/face_east/down(client/user) + var/mob/M = user.mob + M.eastface() + return TRUE + +/datum/keybinding/mob/face_south + hotkey_keys = list("CtrlS", "CtrlSouth") + name = "face_south" + full_name = "Face South" + description = "" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/face_south/down(client/user) + var/mob/M = user.mob + M.southface() + return TRUE + +/datum/keybinding/mob/face_west + hotkey_keys = list("CtrlA", "CtrlWest") + name = "face_west" + full_name = "Face West" + description = "" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/face_west/down(client/user) + var/mob/M = user.mob + M.westface() + return TRUE + +/datum/keybinding/mob/shift_north + hotkey_keys = list("CtrlShiftW", "CtrlShiftNorth") + name = "pixel_shift_north" + full_name = "Pixel Shift North" + description = "" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/shift_north/down(client/user) + var/mob/M = user.mob + M.northshift() + return TRUE + +/datum/keybinding/mob/shift_east + hotkey_keys = list("CtrlShiftD", "CtrlShiftEast") + name = "pixel_shift_east" + full_name = "Pixel Shift East" + description = "" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/shift_east/down(client/user) + var/mob/M = user.mob + M.eastshift() + return TRUE + +/datum/keybinding/mob/shift_south + hotkey_keys = list("CtrlShiftS", "CtrlShiftSouth") + name = "pixel_shift_south" + full_name = "Pixel Shift South" + description = "" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/shift_south/down(client/user) + var/mob/M = user.mob + M.southshift() + return TRUE + +/datum/keybinding/mob/shift_west + hotkey_keys = list("CtrlShiftA", "CtrlShiftWest") + name = "pixel_shift_west" + full_name = "Pixel Shift West" + description = "" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/shift_west/down(client/user) + var/mob/M = user.mob + M.westshift() + return TRUE + +/datum/keybinding/living/hold_sprint + hotkey_keys = list("Shift") + name = "hold_sprint" + full_name = "Sprint (hold down)" + description = "Hold down to sprint" + category = CATEGORY_MOVEMENT + +/datum/keybinding/living/hold_sprint/can_use(client/user) + return ishuman(user.mob) || iscyborg(user.mob) + +/datum/keybinding/living/hold_sprint/down(client/user) + var/mob/living/L = user.mob + L.sprint_hotkey(TRUE) + return TRUE + +/datum/keybinding/living/hold_sprint/up(client/user) + var/mob/living/L = user.mob + L.sprint_hotkey(FALSE) + return TRUE + +/datum/keybinding/living/toggle_sprint + hotkey_keys = list() + name = "toggle_sprint" + full_name = "Sprint (toggle)" + description = "Press to toggle sprint" + category = CATEGORY_MOVEMENT + +/datum/keybinding/living/toggle_sprint/can_use(client/user) + return ishuman(user.mob) || iscyborg(user.mob) + +/datum/keybinding/living/toggle_sprint/down(client/user) + var/mob/living/L = user.mob + L.default_toggle_sprint(TRUE) + return TRUE + +/datum/keybinding/mob/toggle_move_intent + hotkey_keys = list("Alt") + name = "toggle_move_intent" + full_name = "Hold to toggle move intent" + description = "Held down to cycle to the other move intent, release to cycle back" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/toggle_move_intent/down(client/user) + var/mob/M = user.mob + M.toggle_move_intent() + return TRUE + +/datum/keybinding/mob/toggle_move_intent/up(client/user) + var/mob/M = user.mob + M.toggle_move_intent() + return TRUE + +/datum/keybinding/mob/toggle_move_intent_alternative + hotkey_keys = list("Unbound") + name = "toggle_move_intent_alt" + full_name = "press to cycle move intent" + description = "Pressing this cycle to the opposite move intent, does not cycle back" + category = CATEGORY_MOVEMENT + +/datum/keybinding/mob/toggle_move_intent_alternative/down(client/user) + var/mob/M = user.mob + M.toggle_move_intent() + return TRUE diff --git a/code/modules/keybindings/keybind/robot.dm b/code/modules/keybindings/keybind/robot.dm new file mode 100644 index 0000000000..b9f6ce83eb --- /dev/null +++ b/code/modules/keybindings/keybind/robot.dm @@ -0,0 +1,61 @@ +/datum/keybinding/robot + category = CATEGORY_ROBOT + weight = WEIGHT_ROBOT + +/datum/keybinding/robot/can_use(client/user) + return iscyborg(user.mob) + +/datum/keybinding/robot/moduleone + hotkey_keys = list("1") + name = "module_one" + full_name = "Toggle module 1" + description = "Equips or unequips the first module" + +/datum/keybinding/robot/moduleone/down(client/user) + var/mob/living/silicon/robot/R = user.mob + R.toggle_module(1) + return TRUE + +/datum/keybinding/robot/moduletwo + hotkey_keys = list("2") + name = "module_two" + full_name = "Toggle module 2" + description = "Equips or unequips the second module" + +/datum/keybinding/robot/moduletwo/down(client/user) + var/mob/living/silicon/robot/R = user.mob + R.toggle_module(2) + return TRUE + +/datum/keybinding/robot/modulethree + hotkey_keys = list("3") + name = "module_three" + full_name = "Toggle module 3" + description = "Equips or unequips the third module" + +/datum/keybinding/robot/modulethree/down(client/user) + var/mob/living/silicon/robot/R = user.mob + R.toggle_module(3) + return TRUE + +/datum/keybinding/robot/intent_cycle + hotkey_keys = list("4") + name = "cycle_intent" + full_name = "Cycle intent left" + description = "Cycles the intent left" + +/datum/keybinding/robot/intent_cycle/down(client/user) + var/mob/living/silicon/robot/R = user.mob + R.a_intent_change(INTENT_HOTKEY_LEFT) + return TRUE + +/datum/keybinding/robot/unequip_module + hotkey_keys = list("Q") + name = "unequip_module" + full_name = "Unequip module" + description = "Unequips the active module" + +/datum/keybinding/robot/unequip_module/down(client/user) + var/mob/living/silicon/robot/R = user.mob + R.uneq_active() + return TRUE diff --git a/code/modules/keybindings/keybind/targeting.dm b/code/modules/keybindings/keybind/targeting.dm new file mode 100644 index 0000000000..1548d768cf --- /dev/null +++ b/code/modules/keybindings/keybind/targeting.dm @@ -0,0 +1,76 @@ +/datum/keybinding/mob/target_head_cycle + hotkey_keys = list("Numpad8") + name = "target_head_cycle" + full_name = "Target: Cycle head" + description = "" + category = CATEGORY_TARGETING + +/datum/keybinding/mob/target_head_cycle/down(client/user) + user.body_toggle_head() + return TRUE + +/datum/keybinding/mob/target_r_arm + hotkey_keys = list("Numpad4") + name = "target_r_arm" + full_name = "Target: right arm" + description = "" + category = CATEGORY_TARGETING + +/datum/keybinding/mob/target_r_arm/down(client/user) + user.body_r_arm() + return TRUE + +/datum/keybinding/mob/target_body_chest + hotkey_keys = list("Numpad5") + name = "target_body_chest" + full_name = "Target: Body" + description = "" + category = CATEGORY_TARGETING + +/datum/keybinding/mob/target_body_chest/down(client/user) + user.body_chest() + return TRUE + +/datum/keybinding/mob/target_left_arm + hotkey_keys = list("Numpad6") + name = "target_left_arm" + full_name = "Target: left arm" + description = "" + category = CATEGORY_TARGETING + +/datum/keybinding/mob/target_left_arm/down(client/user) + user.body_l_arm() + return TRUE + +/datum/keybinding/mob/target_right_leg + hotkey_keys = list("Numpad1") + name = "target_right_leg" + full_name = "Target: Right leg" + description = "" + category = CATEGORY_TARGETING + +/datum/keybinding/mob/target_right_leg/down(client/user) + user.body_r_leg() + return TRUE + +/datum/keybinding/mob/target_body_groin + hotkey_keys = list("Numpad2") + name = "target_body_groin" + full_name = "Target: Groin" + description = "" + category = CATEGORY_TARGETING + +/datum/keybinding/mob/target_body_groin/down(client/user) + user.body_groin() + return TRUE + +/datum/keybinding/mob/target_left_leg + hotkey_keys = list("Numpad3") + name = "target_left_leg" + full_name = "Target: left leg" + description = "" + category = CATEGORY_TARGETING + +/datum/keybinding/mob/target_left_leg/down(client/user) + user.body_l_leg() + return TRUE diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm index 9a13bfb11c..a53820b5d2 100644 --- a/code/modules/keybindings/setup.dm +++ b/code/modules/keybindings/setup.dm @@ -1,55 +1,47 @@ -/client - /// Keys currently held - var/list/keys_held = list() - /// These next two vars are to apply movement for keypresses and releases made while move delayed. - /// Because discarding that input makes the game less responsive. - /// On next move, add this dir to the move that would otherwise be done - var/next_move_dir_add - /// On next move, subtract this dir from the move that would otherwise be done - var/next_move_dir_sub - -// Set a client's focus to an object and override these procs on that object to let it handle keypresses - /datum/proc/key_down(key, client/user) // Called when a key is pressed down initially return + /datum/proc/key_up(key, client/user) // Called when a key is released return + /datum/proc/keyLoop(client/user) // Called once every frame set waitfor = FALSE return // removes all the existing macros /client/proc/erase_all_macros() - var/list/macro_sets = params2list(winget(src, null, "macros")) var/erase_output = "" - for(var/i in 1 to macro_sets.len) - var/setname = macro_sets[i] - var/list/macro_set = params2list(winget(src, "[setname].*", "command")) // The third arg doesnt matter here as we're just removing them all - for(var/k in 1 to macro_set.len) - var/list/split_name = splittext(macro_set[k], ".") - var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command" - erase_output = "[erase_output];[macro_name].parent=null" + var/list/macro_set = params2list(winget(src, "default.*", "command")) // The third arg doesnt matter here as we're just removing them all + for(var/k in 1 to length(macro_set)) + var/list/split_name = splittext(macro_set[k], ".") + var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command" + erase_output = "[erase_output];[macro_name].parent=null" winset(src, null, erase_output) -/client/proc/set_macros() +/client/proc/apply_macro_set(name, list/macroset) + ASSERT(name) + ASSERT(islist(macroset)) + winclone(src, "default", name) + for(var/i in 1 to length(macroset)) + var/key = macroset[i] + var/command = macroset[key] + winset(src, "[name]-[REF(key)]", "parent=[name];name=[key];command=[command]") + +/client/proc/set_macros(datum/preferences/prefs_override = prefs) set waitfor = FALSE keys_held.Cut() erase_all_macros() - var/list/macro_sets = SSinput.macro_sets - for(var/i in 1 to macro_sets.len) - var/setname = macro_sets[i] - if(setname != "default") - winclone(src, "default", setname) - var/list/macro_set = macro_sets[setname] - for(var/k in 1 to macro_set.len) - var/key = macro_set[k] - var/command = macro_set[key] - winset(src, "[setname]-[REF(key)]", "parent=[setname];name=[key];command=[command]") + apply_macro_set(SKIN_MACROSET_HOTKEYS, SSinput.macroset_hotkey) + apply_macro_set(SKIN_MACROSET_CLASSIC_HOTKEYS, SSinput.macroset_classic_hotkey) + apply_macro_set(SKIN_MACROSET_CLASSIC_INPUT, SSinput.macroset_classic_input) - if(prefs.hotkeys) - winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default") + set_hotkeys_preference() + +/client/proc/set_hotkeys_preference(datum/preferences/prefs_override = prefs) + if(prefs_override.hotkeys) + winset(src, null, "map.focus=true input.background-color=[COLOR_INPUT_DISABLED] mainwindow.macro=[SKIN_MACROSET_HOTKEYS]") else - winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default") + winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=[SKIN_MACROSET_CLASSIC_INPUT]") diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm index d4530acd04..c6e363be07 100644 --- a/code/modules/lighting/lighting_corner.dm +++ b/code/modules/lighting/lighting_corner.dm @@ -2,11 +2,11 @@ // And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't). // For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting. -// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list. -GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST)) - /datum/lighting_corner - var/list/turf/masters + var/turf/northeast + var/turf/northwest + var/turf/southeast + var/turf/southwest var/list/datum/light_source/affecting // Light sources affecting us. var/active = FALSE // TRUE if one of our masters has dynamic lighting. @@ -25,10 +25,18 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, var/cache_b = LIGHTING_SOFT_THRESHOLD var/cache_mx = 0 -/datum/lighting_corner/New(var/turf/new_turf, var/diagonal) +// Diagonal is our direction FROM them, not to. +/datum/lighting_corner/New(turf/new_turf, diagonal) . = ..() - masters = list() - masters[new_turf] = turn(diagonal, 180) + +#define SET_DIAGONAL(turf, diagonal) \ + switch(diagonal){ \ + if(SOUTHWEST) { northeast = turf; turf.lc_bottomleft = src; } \ + if(SOUTHEAST) { northwest = turf; turf.lc_bottomright = src; } \ + if(NORTHEAST) { southwest = turf; turf.lc_topright = src; } \ + if(NORTHWEST) { southeast = turf; turf.lc_topleft = src; } \ + } + SET_DIAGONAL(new_turf, diagonal) z = new_turf.z var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction. @@ -37,52 +45,28 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, x = new_turf.x + (horizontal == EAST ? 0.5 : -0.5) y = new_turf.y + (vertical == NORTH ? 0.5 : -0.5) - // My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal). - // Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered. - // So we'll have this hardcode instead. var/turf/T - var/i - - // Diagonal one is easy. + // Build diagonal one T = get_step(new_turf, diagonal) - if (T) // In case we're on the map's border. - if (!T.corners) - T.corners = list(null, null, null, null) - - masters[T] = diagonal - i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180)) - T.corners[i] = src - - // Now the horizontal one. + if(T) + SET_DIAGONAL(T, turn(diagonal, 180)) + // Build horizontal T = get_step(new_turf, horizontal) - if (T) // Ditto. - if (!T.corners) - T.corners = list(null, null, null, null) - - masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. - i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) - T.corners[i] = src - - // And finally the vertical one. + if(T) + SET_DIAGONAL(T, turn(((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH), 180)) + // Build vertical T = get_step(new_turf, vertical) - if (T) - if (!T.corners) - T.corners = list(null, null, null, null) - - masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. - i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) - T.corners[i] = src + if(T) + SET_DIAGONAL(T, turn(((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH), 180)) update_active() +#undef SET_DIAGONAL + /datum/lighting_corner/proc/update_active() active = FALSE - var/turf/T - var/thing - for (thing in masters) - T = thing - if (T.lighting_object) - active = TRUE + if(northeast?.lighting_object || northwest?.lighting_object || southeast?.lighting_object || southwest?.lighting_object) + active = TRUE // God that was a mess, now to do the rest of the corner code! Hooray! /datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b) @@ -122,13 +106,12 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, #endif cache_mx = round(mx, LIGHTING_ROUND_VALUE) - for (var/TT in masters) - var/turf/T = TT - if (T.lighting_object) - if (!T.lighting_object.needs_update) - T.lighting_object.needs_update = TRUE - GLOB.lighting_update_objects += T.lighting_object - + #define QUEUE(turf) if(turf?.lighting_object && !turf.lighting_object.needs_update) { turf.lighting_object.needs_update = TRUE; GLOB.lighting_update_objects += turf.lighting_object } + QUEUE(northeast) + QUEUE(northwest) + QUEUE(southeast) + QUEUE(southwest) + #undef QUEUE /datum/lighting_corner/dummy/New() return diff --git a/code/modules/lighting/lighting_object.dm b/code/modules/lighting/lighting_object.dm index 9ceb341f91..ffa2d86e15 100644 --- a/code/modules/lighting/lighting_object.dm +++ b/code/modules/lighting/lighting_object.dm @@ -55,7 +55,7 @@ if (loc) var/turf/oldturf = get_turf(myturf) var/turf/newturf = get_turf(loc) - warning("A lighting object realised it's loc had changed in update() ([myturf]\[[myturf ? myturf.type : "null"]]([COORD(oldturf)]) -> [loc]\[[ loc ? loc.type : "null"]]([COORD(newturf)]))!") + stack_trace("A lighting object realised it's loc had changed in update() ([myturf]\[[myturf ? myturf.type : "null"]]([COORD(oldturf)]) -> [loc]\[[ loc ? loc.type : "null"]]([COORD(newturf)]))!") qdel(src, TRUE) return @@ -71,16 +71,10 @@ // See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are. var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new - var/list/corners = myturf.corners - var/datum/lighting_corner/cr = dummy_lighting_corner - var/datum/lighting_corner/cg = dummy_lighting_corner - var/datum/lighting_corner/cb = dummy_lighting_corner - var/datum/lighting_corner/ca = dummy_lighting_corner - if (corners) //done this way for speed - cr = corners[3] || dummy_lighting_corner - cg = corners[2] || dummy_lighting_corner - cb = corners[4] || dummy_lighting_corner - ca = corners[1] || dummy_lighting_corner + var/datum/lighting_corner/cr = myturf.lc_bottomleft || dummy_lighting_corner + var/datum/lighting_corner/cg = myturf.lc_bottomright || dummy_lighting_corner + var/datum/lighting_corner/cb = myturf.lc_topleft || dummy_lighting_corner + var/datum/lighting_corner/ca = myturf.lc_topright || dummy_lighting_corner var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index 6e48d0097c..d97967dff9 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -237,18 +237,25 @@ return //nothing's changed var/list/datum/lighting_corner/corners = list() + var/datum/lighting_corner/C var/list/turf/turfs = list() var/thing - var/datum/lighting_corner/C var/turf/T if (source_turf) var/oldlum = source_turf.luminosity source_turf.luminosity = CEILING(light_range, 1) for(T in view(CEILING(light_range, 1), source_turf)) - for (thing in T.get_corners(source_turf)) - C = thing - corners[C] = 0 turfs += T + if(!IS_DYNAMIC_LIGHTING(T) && !T.light_sources) + continue + if(!T.lighting_corners_initialised) + T.generate_missing_corners() + if(T.has_opaque_atom) + continue + corners[T.lc_topright] = 0 + corners[T.lc_bottomright] = 0 + corners[T.lc_bottomleft] = 0 + corners[T.lc_topleft] = 0 source_turf.luminosity = oldlum LAZYINITLIST(affecting_turfs) diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index fdd581a292..fc9cd0336d 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -6,9 +6,15 @@ var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf. var/tmp/atom/movable/lighting_object/lighting_object // Our lighting object. - var/tmp/list/datum/lighting_corner/corners + var/tmp/datum/lighting_corner/lc_topleft + var/tmp/datum/lighting_corner/lc_topright + var/tmp/datum/lighting_corner/lc_bottomleft + var/tmp/datum/lighting_corner/lc_bottomright var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile. +// counterclockwisse 0 to 360 +#define PROC_ON_CORNERS(operation) lc_topright?.##operation;lc_bottomright?.##operation;lc_bottomleft?.##operation;lc_topleft?.##operation + // Causes any affecting light sources to be queued for a visibility update, for example a door got opened. /turf/proc/reconsider_lights() var/datum/light_source/L @@ -21,13 +27,7 @@ if (lighting_object) qdel(lighting_object, TRUE) - var/datum/lighting_corner/C - var/thing - for (thing in corners) - if(!thing) - continue - C = thing - C.update_active() + PROC_ON_CORNERS(update_active()) // Builds a lighting object for us, but only if our area is dynamic. /turf/proc/lighting_build_overlay() @@ -43,32 +43,31 @@ new/atom/movable/lighting_object(src) - var/thing - var/datum/lighting_corner/C var/datum/light_source/S - for (thing in corners) - if(!thing) - continue - C = thing - if (!C.active) // We would activate the corner, calculate the lighting for it. - for (thing in C.affecting) - S = thing - S.recalc_corner(C) - C.active = TRUE + var/i +#define OPERATE(corner) \ + if(corner && !corner.active) { \ + for(i in corner.affecting) { \ + S = i ; \ + S.recalc_corner(corner) \ + } \ + corner.active = TRUE \ + } + OPERATE(lc_topright) + OPERATE(lc_bottomright) + OPERATE(lc_bottomleft) + OPERATE(lc_topleft) +#undef OPERATE // Used to get a scaled lumcount. /turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1) - if (!lighting_object) + if(!lighting_object) return 1 - var/totallums = 0 - var/thing - var/datum/lighting_corner/L - for (thing in corners) - if(!thing) - continue - L = thing - totallums += L.lum_r + L.lum_b + L.lum_g + var/totallums = (lc_topright? (lc_topright.lum_r + lc_topright.lum_g + lc_topright.lum_b) : 0) \ + + (lc_bottomright? (lc_bottomright.lum_r + lc_bottomright.lum_g + lc_bottomright.lum_b) : 0) \ + + (lc_bottomleft? (lc_bottomleft.lum_r + lc_bottomleft.lum_g + lc_bottomleft.lum_b) : 0) \ + + (lc_topleft? (lc_topleft.lum_r + lc_topleft.lum_g + lc_topleft.lum_b) : 0) totallums /= 12 // 4 corners, each with 3 channels, get the average. @@ -110,27 +109,18 @@ else lighting_clear_overlay() -/turf/proc/get_corners() - if (!IS_DYNAMIC_LIGHTING(src) && !light_sources) - return null - if (!lighting_corners_initialised) - generate_missing_corners() - if (has_opaque_atom) - return null // Since this proc gets used in a for loop, null won't be looped though. - - return corners - /turf/proc/generate_missing_corners() if (!IS_DYNAMIC_LIGHTING(src) && !light_sources) return lighting_corners_initialised = TRUE - if (!corners) - corners = list(null, null, null, null) - - for (var/i = 1 to 4) - if (corners[i]) // Already have a corner on this direction. - continue - - corners[i] = new/datum/lighting_corner(src, GLOB.LIGHTING_CORNER_DIAGONAL[i]) - + // counterclockwise from 0 to 360. + if(!lc_topright) + new /datum/lighting_corner(src, NORTHEAST) + if(!lc_bottomright) + new /datum/lighting_corner(src, SOUTHEAST) + if(!lc_bottomleft) + new /datum/lighting_corner(src, SOUTHWEST) + if(!lc_topleft) + new /datum/lighting_corner(src, NORTHWEST) +#undef PROC_ON_CORNERS diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm index a45275e0c8..39f8e296af 100644 --- a/code/modules/mining/equipment/explorer_gear.dm +++ b/code/modules/mining/equipment/explorer_gear.dm @@ -16,7 +16,6 @@ resistance_flags = FIRE_PROOF mutantrace_variation = STYLE_DIGITIGRADE|STYLE_SNEK_TAURIC|STYLE_PAW_TAURIC - /obj/item/clothing/head/hooded/explorer name = "explorer hood" desc = "An armoured hood for exploring harsh environments." @@ -51,7 +50,7 @@ visor_flags_inv = HIDEFACIALHAIR visor_flags_cover = MASKCOVERSMOUTH actions_types = list(/datum/action/item_action/adjust) - armor = list("melee" = 10, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 20, "acid" = 40) + armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 5, "bio" = 50, "rad" = 0, "fire" = 20, "acid" = 40) resistance_flags = FIRE_PROOF /obj/item/clothing/mask/gas/explorer/attack_self(mob/user) @@ -140,7 +139,7 @@ max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS hoodtype = /obj/item/clothing/head/hooded/explorer/seva - armor = list("melee" = 15, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 25, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25) + armor = list("melee" = 15, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 35, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25) resistance_flags = FIRE_PROOF | GOLIATH_WEAKNESS /obj/item/clothing/head/hooded/explorer/seva @@ -149,7 +148,7 @@ icon_state = "seva" item_state = "seva" max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 25, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25) + armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 35, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25) resistance_flags = FIRE_PROOF | GOLIATH_WEAKNESS /obj/item/clothing/mask/gas/seva diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 9767ff3866..53ce676317 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -39,7 +39,7 @@ if(11) new /obj/item/ship_in_a_bottle(src) if(12) - new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker(src) + new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker/old(src) if(13) new /obj/item/jacobs_ladder(src) if(14) @@ -67,7 +67,7 @@ new /obj/item/grenade/clusterbuster/inferno(src) if(24) new /obj/item/reagent_containers/food/drinks/bottle/holywater/hell(src) - new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor(src) + new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor/old(src) if(25) new /obj/item/book/granter/spell/summonitem(src) if(26) diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm index 0c8aef51a8..fb37dcbca0 100644 --- a/code/modules/mining/minebot.dm +++ b/code/modules/mining/minebot.dm @@ -24,7 +24,8 @@ environment_smash = ENVIRONMENT_SMASH_NONE check_friendly_fire = TRUE stop_automated_movement_when_pulled = TRUE - attacktext = "drills" + attack_verb_continuous = "drills" + attack_verb_simple = "drill" attack_sound = 'sound/weapons/circsawhit.ogg' sentience_type = SENTIENCE_MINEBOT speak_emote = list("states") diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 581072c5bf..02410960e7 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -102,7 +102,22 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ /obj/item/stack/ore/glass/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) if(..() || !ishuman(hit_atom)) return - var/mob/living/carbon/human/C = hit_atom + var/mob/living/carbon/human/poorsod = hit_atom + eyesand(poorsod) + +/obj/item/stack/ore/glass/attack(mob/living/M, mob/living/user) + if(!ishuman(M)) + return ..() + if(user.zone_selected != BODY_ZONE_PRECISE_EYES && user.zone_selected != BODY_ZONE_HEAD) + return ..() + var/mob/living/carbon/human/poorsod = M + visible_message("[user] throws the sand at [poorsod]'s face!") + if(ishuman(user)) + var/mob/living/carbon/human/sayer = user + sayer.forcesay("POCKET SAAND!!") + eyesand(poorsod) + +/obj/item/stack/ore/glass/proc/eyesand(mob/living/carbon/human/C) if(C.head && C.head.flags_cover & HEADCOVERSEYES) visible_message("[C]'s headgear blocks the sand!") return @@ -116,8 +131,10 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ C.adjustStaminaLoss(15)//the pain from your eyes burning does stamina damage C.confused += 5 to_chat(C, "\The [src] gets into your eyes! The pain, it burns!") + C.forcesay("*scream") qdel(src) + /obj/item/stack/ore/glass/ex_act(severity, target) if (severity == EXPLODE_NONE) return diff --git a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm index 2bb0d6ba77..33dbd7059f 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -450,6 +450,18 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' +/datum/sprite_accessory/tails/human/tamamo_kitsune + name = "Tamamo Kitsune Tails" //Tamamo-no-Tiro, let it be known! + icon_state = "9sune" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/tamamo_kitsune + name = "Tamamo Kitsune Tails" + icon_state = "9sune" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + /datum/sprite_accessory/tails/human/tentacle name = "Tentacle" icon_state = "tentacle" @@ -816,6 +828,14 @@ datum/sprite_accessory/mam_tails/insect name = "Squirrel" icon_state = "squirrel" +/datum/sprite_accessory/mam_tails/tamamo_kitsune + name = "Tamamo Kitsune Tails" + icon_state = "9sune" + +/datum/sprite_accessory/mam_tails_animated/tamamo_kitsune + name = "Tamamo Kitsune Tails" + icon_state = "9sune" + /datum/sprite_accessory/mam_tails/tentacle name = "Tentacle" icon_state = "tentacle" diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 942a99abd9..838de24b60 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -707,7 +707,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp //this is a mob verb instead of atom for performance reasons //see /mob/verb/examinate() in mob.dm for more info //overridden here and in /mob/living for different point span classes and sanity checks -/mob/dead/observer/pointed(atom/A as mob|obj|turf in visible_atoms()) +/mob/dead/observer/pointed(atom/A as mob|obj|turf in fov_view()) if(!..()) return 0 usr.visible_message("[src] points to [A].") diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index 90621ecd3f..6d3bf648f6 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -51,6 +51,12 @@ var/datum/brain_trauma/BT = X BT.owner = owner BT.on_gain() + if(damage > BRAIN_DAMAGE_MILD) + var/datum/skill_modifier/S + ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, C, S) + if(damage > BRAIN_DAMAGE_SEVERE) + var/datum/skill_modifier/S + ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C, S) //Update the body's icon so it doesnt appear debrained anymore C.update_hair() @@ -66,6 +72,8 @@ if((!QDELETED(src) || C) && !no_id_transfer) transfer_identity(C) if(C) + REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, C) + REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C) C.update_hair() /obj/item/organ/brain/prepare_eat() @@ -219,31 +227,6 @@ Insert(C) else ..() -/* TO BE REMOVED, KEPT IN CASE OF BUGS -/obj/item/organ/brain/proc/get_brain_damage() - var/brain_damage_threshold = max_integrity * BRAIN_DAMAGE_INTEGRITY_MULTIPLIER - var/offset_integrity = obj_integrity - (max_integrity - brain_damage_threshold) - . = round((1 - (offset_integrity / brain_damage_threshold)) * BRAIN_DAMAGE_DEATH, DAMAGE_PRECISION) - -/obj/item/organ/brain/proc/adjust_brain_damage(amount, maximum) - var/adjusted_amount - if(amount >= 0 && maximum) - var/brainloss = get_brain_damage() - var/new_brainloss = clamp(brainloss + amount, 0, maximum) - if(brainloss > new_brainloss) //brainloss is over the cap already - return 0 - adjusted_amount = new_brainloss - brainloss - else - adjusted_amount = amount - - adjusted_amount = round(adjusted_amount * BRAIN_DAMAGE_INTEGRITY_MULTIPLIER, DAMAGE_PRECISION) - if(adjusted_amount) - if(adjusted_amount >= DAMAGE_PRECISION) - take_damage(adjusted_amount) - else if(adjusted_amount <= -DAMAGE_PRECISION) - obj_integrity = min(max_integrity, obj_integrity-adjusted_amount) - . = adjusted_amount -*/ /obj/item/organ/brain/applyOrganDamage(var/d, var/maximum = maxHealth) . = ..() @@ -261,18 +244,28 @@ . = ..() //if we're not more injured than before, return without gambling for a trauma if(damage <= prev_damage) + if(damage < prev_damage && owner) + if(prev_damage > BRAIN_DAMAGE_MILD && damage <= BRAIN_DAMAGE_MILD) + REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, owner) + if(prev_damage > BRAIN_DAMAGE_SEVERE && damage <= BRAIN_DAMAGE_SEVERE) + REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, owner) return damage_delta = damage - prev_damage if(damage > BRAIN_DAMAGE_MILD) if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_MILD)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1% //learn how to do your bloody math properly goddamnit gain_trauma_type(BRAIN_TRAUMA_MILD) + if(prev_damage <= BRAIN_DAMAGE_MILD && owner) + var/datum/skill_modifier/S + ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, owner, S) if(damage > BRAIN_DAMAGE_SEVERE) if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_SEVERE)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1% if(prob(20)) gain_trauma_type(BRAIN_TRAUMA_SPECIAL) else gain_trauma_type(BRAIN_TRAUMA_SEVERE) - + if(prev_damage <= BRAIN_DAMAGE_SEVERE && owner) + var/datum/skill_modifier/S + ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, owner, S) if (owner) if(owner.stat < UNCONSCIOUS) //conscious or soft-crit var/brain_message diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index bf9854e0b4..442bcf8027 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -140,7 +140,8 @@ Des: Removes all infected images from the alien. /mob/living/carbon/alien/proc/alien_evolve(mob/living/carbon/alien/new_xeno) to_chat(src, "You begin to evolve!") - visible_message("[src] begins to twist and contort!") + visible_message("[src] begins to twist and contort!", + "You begin to twist and contort!") new_xeno.setDir(dir) if(!alien_name_regex.Find(name)) new_xeno.name = name diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index cdb8aff2c6..00ce3a320a 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -27,13 +27,16 @@ In all, this is a lot like the monkey code. /N AdjustUnconscious(-60, FALSE) AdjustSleeping(-100, FALSE) update_mobility() - visible_message("[M.name] nuzzles [src] trying to wake [p_them()] up!") + visible_message("[M.name] nuzzles [src] trying to wake [p_them()] up!", + "[M.name] nuzzles you trying to wake you up!", target = M, + target_message = "You nuzzle [src] trying to wake [p_them()] up!") if(INTENT_DISARM, INTENT_HARM) if(health > 0) M.do_attack_animation(src, ATTACK_EFFECT_BITE) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) visible_message("[M.name] bites [src]!", \ - "[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE) + "[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE, null, M, + "You bite [src]!") adjustBruteLoss(1) log_combat(M, src, "attacked") updatehealth() diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index c813ce40f0..11849641ef 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -25,6 +25,7 @@ /mob/living/carbon/alien/humanoid/Initialize() AddAbility(new/obj/effect/proc_holder/alien/regurgitate(null)) . = ..() + AddComponent(/datum/component/footstep, FOOTSTEP_MOB_CLAW, 0.5, -3) /mob/living/carbon/alien/humanoid/restrained(ignore_grab) return handcuffed diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index e15c2b010d..dfc6fd735a 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -22,9 +22,6 @@ QDEL_NULL(dna) GLOB.carbon_list -= src -/mob/living/carbon/initialize_footstep() - AddComponent(/datum/component/footstep, 0.6, 2) - /mob/living/carbon/relaymove(mob/user, direction) if(user in src.stomach_contents) if(prob(40)) @@ -253,7 +250,8 @@ var/obj/item/ITEM = get_item_by_slot(slot) if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS)) visible_message("[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].", \ - "[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].") + "[usr] tries to [internal ? "close" : "open"] the valve on your [ITEM.name].", \ + target = usr, target_message = "You try to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].") if(do_mob(usr, src, POCKET_STRIP_DELAY)) if(internal) internal = null @@ -264,7 +262,8 @@ update_internals_hud_icon(1) visible_message("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].", \ - "[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].") + "[usr] [internal ? "opens" : "closes"] the valve on your [ITEM.name].", \ + target = usr, target_message = "You [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].") /mob/living/carbon/fall(forced) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 3023907831..94589b3a4a 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -185,7 +185,8 @@ M.powerlevel = 0 visible_message("The [M.name] has shocked [src]!", \ - "The [M.name] has shocked [src]!") + "The [M.name] has shocked you!", target = M, + target_message = "You have shocked [src]!") do_sparks(5, TRUE, src) var/power = M.powerlevel + rand(0,3) @@ -234,38 +235,44 @@ var/obj/item/organ/O = X O.emp_act(severity) +///Adds to the parent by also adding functionality to propagate shocks through pulling and doing some fluff effects. /mob/living/carbon/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) - if((flags & SHOCK_TESLA) && (flags_1 & TESLA_IGNORE_1)) - return FALSE - if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE)) - return FALSE - shock_damage *= siemens_coeff - if(dna && dna.species) - shock_damage *= dna.species.siemens_coeff - if(shock_damage < 1) - return 0 - if(reagents.has_reagent(/datum/reagent/teslium)) - shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging! - if((flags & SHOCK_ILLUSION)) - adjustStaminaLoss(shock_damage) - else - take_overall_damage(0,shock_damage) - visible_message( - "[src] was shocked by \the [source]!", \ - "You feel a powerful shock coursing through your body!", \ - "You hear a heavy electrical crack." \ - ) - jitteriness += 1000 //High numbers for violent convulsions + . = ..() + if(!.) + return + //Propagation through pulling, fireman carry + if(!(flags & SHOCK_ILLUSION)) + var/list/shocking_queue = list() + if(iscarbon(pulling) && source != pulling) + shocking_queue += pulling + if(iscarbon(pulledby) && source != pulledby) + shocking_queue += pulledby + if(iscarbon(buckled) && source != buckled) + shocking_queue += buckled + for(var/mob/living/carbon/carried in buckled_mobs) + if(source != carried) + shocking_queue += carried + //Found our victims, now lets shock them all + for(var/victim in shocking_queue) + var/mob/living/carbon/C = victim + C.electrocute_act(shock_damage*0.75, src, 1, flags) + //Stun + var/should_stun = (!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN) + if(should_stun) + Stun(40) + //Jitter and other fluff. + jitteriness += 1000 do_jitter_animation(jitteriness) stuttering += 2 - if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN)) - Stun(40) - spawn(20) - jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less - if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN)) - DefaultCombatKnockdown(60) + addtimer(CALLBACK(src, .proc/secondary_shock, should_stun), 20) return shock_damage +///Called slightly after electrocute act to reduce jittering and apply a secondary stun. +/mob/living/carbon/proc/secondary_shock(should_stun) + jitteriness = max(jitteriness - 990, 10) + if(should_stun) + DefaultCombatKnockdown(60) + /mob/living/carbon/proc/help_shake_act(mob/living/carbon/M) if(on_fire) to_chat(M, "You can't put [p_them()] out with just your bare hands!") @@ -280,12 +287,14 @@ to_chat(M, "You need to unbuckle [src] first to do that!") return M.visible_message("[M] shakes [src] trying to get [p_them()] up!", \ - "You shake [src] trying to get [p_them()] up!") + "You shake [src] trying to get [p_them()] up!", target = src, + target_message = "[M] shakes you trying to get you up!") else if(M.zone_selected == BODY_ZONE_PRECISE_MOUTH) // I ADDED BOOP-EH-DEH-NOSEH - Jon M.visible_message( \ "[M] boops [src]'s nose.", \ - "You boop [src] on the nose.", ) + "You boop [src] on the nose.", target = src, + target_message = "[M] boops your nose.") playsound(src, 'sound/items/Nose_boop.ogg', 50, 0) else if(check_zone(M.zone_selected) == BODY_ZONE_HEAD) @@ -294,7 +303,8 @@ S = dna.species M.visible_message("[M] gives [src] a pat on the head to make [p_them()] feel better!", \ - "You give [src] a pat on the head to make [p_them()] feel better!") + "You give [src] a pat on the head to make [p_them()] feel better!", target = src, + target_message = "[M] gives you a pat on the head to make you feel better!") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat) friendly_check = TRUE if(S?.can_wag_tail(src) && !dna.species.is_wagging_tail()) @@ -307,11 +317,13 @@ else if(check_zone(M.zone_selected) == BODY_ZONE_R_ARM || check_zone(M.zone_selected) == BODY_ZONE_L_ARM) M.visible_message( \ "[M] shakes [src]'s hand.", \ - "You shake [src]'s hand.", ) + "You shake [src]'s hand.", target = src, + target_message = "[M] shakes your hand.") else M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \ - "You hug [src] to make [p_them()] feel better!") + "You hug [src] to make [p_them()] feel better!", target = src,\ + target_message = "[M] hugs you to make you feel better!") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug) friendly_check = TRUE diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index 60fa395319..4cf82bb0b4 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -25,7 +25,8 @@ if(M in stomach_contents) stomach_contents.Remove(M) M.forceMove(Tsec) - visible_message("[M] bursts out of [src]!") + M.visible_message("[M] bursts out of [src]!", + "You burst out of [src]!") ..() /mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index ea91a90ee9..007bca3518 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -26,6 +26,7 @@ physiology = new() AddComponent(/datum/component/personal_crafting) + AddComponent(/datum/component/footstep, FOOTSTEP_MOB_HUMAN, 1, 2) . = ..() if(CONFIG_GET(flag/disable_stambuffer)) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 856c57687f..3a2d0535e6 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -102,11 +102,15 @@ . = ..(user, TRUE) if(.) return - var/hulk_verb = pick("smash","pummel") + var/hulk_verb_continous = "smashes" + var/hulk_verb_simple = "smash" + if(prob(50)) + hulk_verb_continous = "pummels" + hulk_verb_simple = "pummel" playsound(loc, user.dna.species.attack_sound, 25, 1, -1) - var/message = "[user] has [hulk_verb]ed [src]!" - visible_message("[message]", \ - "[message]") + visible_message("[user] [hulk_verb_continous] [src]!", \ + "[user] [hulk_verb_continous] you!", null, COMBAT_MESSAGE_RANGE, null, user, + "You [hulk_verb_simple] [src]!") adjustBruteLoss(15) return 1 @@ -130,14 +134,16 @@ var/obj/item/I = get_active_held_item() if(I && dropItemToGround(I)) playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) - visible_message("[M] disarmed [src]!", \ - "[M] disarmed [src]!") + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed you!", null, COMBAT_MESSAGE_RANGE, null, M, + "You have disarmed [src]!") else if(!M.client || prob(5)) // only natural monkeys get to stun reliably, (they only do it occasionaly) playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) DefaultCombatKnockdown(100) log_combat(M, src, "tackled") visible_message("[M] has tackled down [src]!", \ - "[M] has tackled down [src]!") + "[M] has tackled you down!", null, COMBAT_MESSAGE_RANGE, null, M, + "You have tackled [src] down!") if(M.limb_destroyer) dismembering_strike(M, affecting.body_zone) @@ -159,7 +165,8 @@ if(!damage) playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1) visible_message("[M] has lunged at [src]!", \ - "[M] has lunged at [src]!") + "[M] has lunged at you!", target = M, \ + target_message = "You have lunged at [src]!") return 0 var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) if(!affecting) @@ -168,7 +175,8 @@ playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) visible_message("[M] has slashed at [src]!", \ - "[M] has slashed at [src]!") + "[M] has slashed at you!", target = M, \ + target_message = "You have slashed at [src]!") log_combat(M, src, "attacked") if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful return 1 @@ -178,14 +186,16 @@ var/obj/item/I = get_active_held_item() if(I && dropItemToGround(I)) playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) - visible_message("[M] disarmed [src]!", \ - "[M] disarmed [src]!") + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed you!", target = M, \ + target_message = "You have disarmed [src]!") else playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) DefaultCombatKnockdown(M.meleeKnockdownPower) log_combat(M, src, "tackled") visible_message("[M] has tackled down [src]!", \ - "[M] has tackled down [src]!") + "[M] has tackled you down!", target = M, \ + target_message = "You have tackled down [src]!") /mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L) . = ..() @@ -268,7 +278,8 @@ updatehealth() visible_message("[M.name] has hit [src]!", \ - "[M.name] has hit [src]!", null, COMBAT_MESSAGE_RANGE) + "[M.name] has hit you!", null, COMBAT_MESSAGE_RANGE, target = M, + target_message = "You have hit [src]!") log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") else @@ -348,40 +359,34 @@ apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee")) -//Added a safety check in case you want to shock a human mob directly through electrocute_act. +///Calculates the siemens coeff based on clothing and species, can also restart hearts. /mob/living/carbon/human/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) - if(flags & SHOCK_TESLA) - var/total_coeff = 1 - if(gloves) - var/obj/item/clothing/gloves/G = gloves - if(G.siemens_coefficient <= 0) - total_coeff -= 0.5 + //Calculates the siemens coeff based on clothing. Completely ignores the arguments + if(flags & SHOCK_TESLA) //I hate this entire block. This gets the siemens_coeff for tesla shocks + if(gloves && gloves.siemens_coefficient <= 0) + siemens_coeff -= 0.5 if(wear_suit) - var/obj/item/clothing/suit/S = wear_suit - if(S.siemens_coefficient <= 0) - total_coeff -= 0.95 - else if(S.siemens_coefficient == (-1)) - total_coeff -= 1 - siemens_coeff = total_coeff - if(flags_1 & TESLA_IGNORE_1) - siemens_coeff = 0 - else if(!(flags & SHOCK_NOGLOVES)) - var/gloves_siemens_coeff = 1 + if(wear_suit.siemens_coefficient == -1) + siemens_coeff -= 1 + else if(wear_suit.siemens_coefficient <= 0) + siemens_coeff -= 0.95 + siemens_coeff = max(siemens_coeff, 0) + else if(!(flags & SHOCK_NOGLOVES)) //This gets the siemens_coeff for all non tesla shocks if(gloves) - var/obj/item/clothing/gloves/G = gloves - gloves_siemens_coeff = G.siemens_coefficient - siemens_coeff = gloves_siemens_coeff - if(undergoing_cardiac_arrest() && !(flags & SHOCK_ILLUSION)) - if(shock_damage * siemens_coeff >= 1 && prob(25)) - var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART) - heart.beating = TRUE - if(stat == CONSCIOUS) - to_chat(src, "You feel your heart beating again!") + siemens_coeff *= gloves.siemens_coefficient siemens_coeff *= physiology.siemens_coeff . = ..() - if(.) - electrocution_animation(40) - + //Don't go further if the shock was blocked/too weak. + if(!.) + return + //Note we both check that the user is in cardiac arrest and can actually heartattack + //If they can't, they're missing their heart and this would runtime + if(undergoing_cardiac_arrest() && can_heartattack() && !(flags & SHOCK_ILLUSION)) + if(shock_damage * siemens_coeff >= 1 && prob(25)) + var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART) + if(heart.Restart() && stat == CONSCIOUS) + to_chat(src, "You feel your heart beating again!") + electrocution_animation(40) /mob/living/carbon/human/emp_act(severity) . = ..() diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 580b0aaaf0..8de143e2bd 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -277,3 +277,65 @@ qdel(slot) for(var/obj/item/I in held_items) qdel(I) + +/mob/living/carbon/human/proc/smart_equipbag() // take most recent item out of bag or place held item in bag + if(incapacitated()) + return + var/obj/item/thing = get_active_held_item() + var/obj/item/equipped_back = get_item_by_slot(SLOT_BACK) + if(!equipped_back) // We also let you equip a backpack like this + if(!thing) + to_chat(src, "You have no backpack to take something out of!") + return + if(equip_to_slot_if_possible(thing, ITEM_SLOT_BACK)) + update_inv_hands() + return + if(!SEND_SIGNAL(equipped_back, COMSIG_CONTAINS_STORAGE)) // not a storage item + if(!thing) + equipped_back.attack_hand(src) + else + to_chat(src, "You can't fit anything in!") + return + if(thing) // put thing in backpack + if(!SEND_SIGNAL(equipped_back, COMSIG_TRY_STORAGE_INSERT, thing, src)) + to_chat(src, "You can't fit anything in!") + return + if(!equipped_back.contents.len) // nothing to take out + to_chat(src, "There's nothing in your backpack to take out!") + return + var/obj/item/stored = equipped_back.contents[equipped_back.contents.len] + if(!stored || stored.on_found(src)) + return + stored.attack_hand(src) // take out thing from backpack + return + +/mob/living/carbon/human/proc/smart_equipbelt() // put held thing in belt or take most recent item out of belt + if(incapacitated()) + return + var/obj/item/thing = get_active_held_item() + var/obj/item/equipped_belt = get_item_by_slot(SLOT_BELT) + if(!equipped_belt) // We also let you equip a belt like this + if(!thing) + to_chat(src, "You have no belt to take something out of!") + return + if(equip_to_slot_if_possible(thing, ITEM_SLOT_BELT)) + update_inv_hands() + return + if(!SEND_SIGNAL(equipped_belt, COMSIG_CONTAINS_STORAGE)) // not a storage item + if(!thing) + equipped_belt.attack_hand(src) + else + to_chat(src, "You can't fit anything in!") + return + if(thing) // put thing in belt + if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, src)) + to_chat(src, "You can't fit anything in!") + return + if(!equipped_belt.contents.len) // nothing to take out + to_chat(src, "There's nothing in your belt to take out!") + return + var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len] + if(!stored || stored.on_found(src)) + return + stored.attack_hand(src) // take out thing from belt + return diff --git a/code/modules/mob/living/carbon/human/physiology.dm b/code/modules/mob/living/carbon/human/physiology.dm index 4d411deb53..fd0df0bde9 100644 --- a/code/modules/mob/living/carbon/human/physiology.dm +++ b/code/modules/mob/living/carbon/human/physiology.dm @@ -25,5 +25,8 @@ var/do_after_speed = 1 //Speed mod for do_after. Lower is better. If temporarily adjusting, please only modify using *= and /=, so you don't interrupt other calculations. + /// footstep type override for both shoeless and not footstep sounds. + var/footstep_type + /datum/physiology/New() armor = new diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 65d09f6cf2..a1de0bf532 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -332,6 +332,21 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(mutant_bodyparts["meat_type"]) //I can't believe it's come to the meat H.type_of_meat = GLOB.meat_types[H.dna.features["meat_type"]] + if(H.physiology) + if(mutant_bodyparts["taur"]) + var/datum/sprite_accessory/taur/T = GLOB.taur_list[H.dna.features["taur"]] + switch(T?.taur_mode) + if(STYLE_HOOF_TAURIC) + H.physiology.footstep_type = FOOTSTEP_MOB_SHOE + if(STYLE_PAW_TAURIC) + H.physiology.footstep_type = FOOTSTEP_MOB_CLAW + if(STYLE_SNEK_TAURIC) + H.physiology.footstep_type = FOOTSTEP_MOB_CRAWL + else + H.physiology.footstep_type = null + else + H.physiology.footstep_type = null + if(H.client && has_field_of_vision && CONFIG_GET(flag/use_field_of_vision)) H.LoadComponent(/datum/component/field_of_vision, H.field_of_vision_type) @@ -369,7 +384,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation) if(!new_species.has_field_of_vision && has_field_of_vision && ishuman(C) && CONFIG_GET(flag/use_field_of_vision)) - var/datum/component/field_of_vision/F = GetComponent(/datum/component/field_of_vision) + var/datum/component/field_of_vision/F = C.GetComponent(/datum/component/field_of_vision) if(F) qdel(F) @@ -1407,7 +1422,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) /datum/species/proc/grab(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(target.check_martial_melee_block()) - target.visible_message("[target] blocks [user]'s grab attempt!") + target.visible_message("[target] blocks [user]'s grab attempt!", target = user, \ + target_message = "[target] blocks your grab attempt!") return 0 if(attacker_style && attacker_style.grab_act(user,target)) return 1 @@ -1423,7 +1439,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) to_chat(user, "You're too exhausted.") //CITADEL CHANGE - ditto return FALSE //CITADEL CHANGE - ditto if(target.check_martial_melee_block()) - target.visible_message("[target] blocks [user]'s attack!") + target.visible_message("[target] blocks [user]'s attack!", target = user, \ + target_message = "[target] blocks your attack!") return FALSE if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount @@ -1478,8 +1495,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted playsound(target.loc, user.dna.species.miss_sound, 25, TRUE, -1) target.visible_message("[user]'s [atk_verb] misses [target]!", \ - "You avoid [user]'s [atk_verb]!", "You hear a swoosh!", COMBAT_MESSAGE_RANGE, user) - to_chat(user, "Your [atk_verb] misses [target]!") + "You avoid [user]'s [atk_verb]!", "You hear a swoosh!", null, COMBAT_MESSAGE_RANGE, null, \ + user, "Your [atk_verb] misses [target]!") log_combat(user, target, "attempted to punch") return FALSE @@ -1488,8 +1505,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) playsound(target.loc, user.dna.species.attack_sound, 25, 1, -1) - target.visible_message("[user] has [atk_verb]ed [target]!", \ - "[user] has [atk_verb]ed [target]!", null, COMBAT_MESSAGE_RANGE) + target.visible_message("[user] [atk_verb]s [target]!", \ + "[user] [atk_verb]s you!", null, COMBAT_MESSAGE_RANGE, null, \ + user, "You [atk_verb] [target]!") target.lastattacker = user.real_name target.lastattackerckey = user.ckey @@ -1511,8 +1529,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if((punchedstam > 50) && prob(punchedstam*0.5)) //If our punch victim has been hit above the threshold, and they have more than 50 stamina damage, roll for stun, probability of 1% per 2 stamina damage target.visible_message("[user] knocks [target] down!", \ - "You're knocked down by [user]!", "You hear aggressive shuffling followed by a loud thud!", COMBAT_MESSAGE_RANGE, user) - to_chat(user, "You knock [target] down!") + "You're knocked down by [user]!", + "You hear aggressive shuffling followed by a loud thud!", COMBAT_MESSAGE_RANGE, null, + user, "You knock [target] down!") var/knockdown_duration = 40 + (punchedstam + (punchedbrute*0.5))*0.8 - armor_block target.DefaultCombatKnockdown(knockdown_duration) @@ -1544,7 +1563,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/target_aiming_for_groin = target.zone_selected == "groin" if(target.check_martial_melee_block()) //END EDIT - target.visible_message("[target] blocks [user]'s disarm attempt!") + target.visible_message("[target] blocks [user]'s disarm attempt!", target = user, \ + target_message = "[target] blocks your disarm attempt!") return FALSE if(IS_STAMCRIT(user)) to_chat(user, "You're too exhausted!") @@ -1554,10 +1574,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1) target.visible_message(\ - "\The [user] slaps \the [target] in the face!",\ - "You [user == target ? "slap yourself" : "are slapped by \the [target]"] in the face! ",\ - "You hear a slap." - ) + "\The [user] slaps [user == target ? "[user.p_them()]self" : "\the [target]"] in the face!",\ + "[user] slaps you in the face! ",\ + "You hear a slap.", target = user, target_message = "You slap [user == target ? "yourself" : "\the [target]"] in the face! ") user.do_attack_animation(target, ATTACK_EFFECT_FACE_SLAP) user.adjustStaminaLossBuffered(3) if (!HAS_TRAIT(target, TRAIT_PERMABONER)) @@ -1576,10 +1595,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) stop_wagging_tail(target) playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1) target.visible_message(\ - "\The [user] slaps \the [target]'s ass!",\ - "You slap [user == target ? "slap your" : "are slapped by \the [target]'s in the"] ass!",\ - "You hear a slap." - ) + "\The [user] slaps [user == target ? "[user.p_their()] own" : "\the [target]'s"] ass!",\ + "[user] slaps your ass! ",\ + "You hear a slap.", target = user, target_message = "You slap [user == target ? "your own" : "\the [target]'s"] ass! ") + return FALSE else @@ -1598,21 +1617,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) //var/randomized_zone = ran_zone(user.zone_selected) CIT CHANGE - comments out to prevent compiling errors SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected) if(target.pulling == user) - target.visible_message("[user] wrestles out of [target]'s grip!") + target.visible_message("[user] wrestles out of [target]'s grip!", \ + "[user] wrestles out of your grip!", target = user, \ + target_message = "You wrestle out of [target]'s grip!") target.stop_pulling() playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) log_combat(user, target, "disarmed out of grab from") return - //var/obj/item/bodypart/affecting = target.get_bodypart(randomized_zone) CIT CHANGE - comments this out to prevent compile errors due to the below commented out bit var/randn = rand(1, 100) - /*if(randn <= 25) CITADEL CHANGE - moves disarm push attempts to right click - playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - target.visible_message("[user] has pushed [target]!", - "[user] has pushed [target]!", null, COMBAT_MESSAGE_RANGE) - target.apply_effect(40, EFFECT_KNOCKDOWN, target.run_armor_check(affecting, "melee", "Your armor prevents your fall!", "Your armor softens your fall!")) - target.forcesay(GLOB.hit_appends) - log_combat(user, target, "pushed over") - return*/ if(!(target.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) // CITADEL CHANGE randn += -10 //CITADEL CHANGE - being out of combat mode makes it easier for you to get disarmed if(!CHECK_MOBILITY(user, MOBILITY_STAND)) //CITADEL CHANGE @@ -1629,13 +1641,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(randn <= 35)//CIT CHANGE - changes this back to a 35% chance to accomodate for the above being commented out in favor of right-click pushing var/obj/item/I = null if(target.pulling) - target.visible_message("[user] has broken [target]'s grip on [target.pulling]!") + target.visible_message("[user] has broken [target]'s grip on [target.pulling]!", \ + "[user] has broken your grip on [target.pulling]!", target = user, \ + target_message = "You have broken [target]'s grip on [target.pulling]!") target.stop_pulling() else I = target.get_active_held_item() if(target.dropItemToGround(I)) target.visible_message("[user] has disarmed [target]!", \ - "[user] has disarmed [target]!", null, COMBAT_MESSAGE_RANGE) + "[user] has disarmed you!", null, COMBAT_MESSAGE_RANGE, null, \ + user, "You have disarmed [target]!") else I = null playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) @@ -1645,7 +1660,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) playsound(target, 'sound/weapons/punchmiss.ogg', 25, 1, -1) target.visible_message("[user] attempted to disarm [target]!", \ - "[user] attemped to disarm [target]!", null, COMBAT_MESSAGE_RANGE) + "[user] attemped to disarm [target]!", null, COMBAT_MESSAGE_RANGE, null, \ + user, "You attempted to disarm [target]!") log_combat(user, target, "attempted to disarm") @@ -1733,7 +1749,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20) if(H.stat == CONSCIOUS) H.visible_message("[H] has been knocked senseless!", \ - "[H] has been knocked senseless!") + "You have been knocked senseless!") H.confused = max(H.confused, 20) H.adjust_blurriness(10) if(prob(10)) @@ -1791,7 +1807,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) attacker_style = M.mind.martial_art if((M != H) && M.a_intent != INTENT_HELP && (H.mob_run_block(M, 0, "[M]", ATTACK_TYPE_UNARMED, 0, M, M.zone_selected, null) & BLOCK_SUCCESS)) log_combat(M, H, "attempted to touch") - H.visible_message("[M] attempted to touch [H]!") + H.visible_message("[M] attempted to touch [H]!", \ + "[M] attempted to touch you!", target = M, \ + target_message = "You attempted to touch [H]!") return TRUE switch(M.a_intent) if(INTENT_HELP) @@ -1828,7 +1846,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) to_chat(user, "You're too exhausted.") return FALSE if(target.check_martial_melee_block()) - target.visible_message("[target] blocks [user]'s shoving attempt!") + target.visible_message("[target] blocks [user]'s shoving attempt!", \ + "You block [user]'s shoving attempt!", target = user, \ + target_message = "[target] blocks your shoving attempt!") return FALSE if(attacker_style && attacker_style.disarm_act(user,target)) return TRUE @@ -1874,18 +1894,21 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if((directional_blocked || !(target_collateral_human || target_shove_turf.shove_act(target, user))) && !targetatrest) target.DefaultCombatKnockdown(SHOVE_KNOCKDOWN_SOLID) target.visible_message("[user.name] shoves [target.name], knocking them down!", - "You are shoved by [user.name] and knocked down!", null, COMBAT_MESSAGE_RANGE) + "[user.name] shoves you, knocking you down!", null, COMBAT_MESSAGE_RANGE, null, + user, "You shove [target.name], knocking them down!") log_combat(user, target, "shoved", "knocking them down") else if(target_collateral_human && !targetatrest) target.DefaultCombatKnockdown(SHOVE_KNOCKDOWN_HUMAN) target_collateral_human.DefaultCombatKnockdown(SHOVE_KNOCKDOWN_COLLATERAL) target.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]!", - "You are shoved by [user.name] into [target_collateral_human.name]!", null, COMBAT_MESSAGE_RANGE) + "[user.name] shoves you into [target_collateral_human.name]!", null, COMBAT_MESSAGE_RANGE, null, + user, "You shove [target.name] into [target_collateral_human.name]!") append_message += ", into [target_collateral_human.name]" else target.visible_message("[user.name] shoves [target.name]!", - "You are shoved by [user.name]!", null, COMBAT_MESSAGE_RANGE) + "[user.name] shoves you!", null, COMBAT_MESSAGE_RANGE, null, + user, "You shove [target.name]!") var/obj/item/target_held_item = target.get_active_held_item() if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types)) target_held_item = null diff --git a/code/modules/mob/living/carbon/human/species_types/dwarves.dm b/code/modules/mob/living/carbon/human/species_types/dwarves.dm index e3beafa18a..dfeff24141 100644 --- a/code/modules/mob/living/carbon/human/species_types/dwarves.dm +++ b/code/modules/mob/living/carbon/human/species_types/dwarves.dm @@ -33,12 +33,11 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) // var/mob/living/carbon/human/H = C H.facial_hair_style = dwarf_hair H.update_hair() - H.transform = H.transform.Scale(1, 0.8) //We use scale, and yeah. Dwarves can become gnomes with DWARFISM. + H.AddElement(/datum/element/dwarfism, COMSIG_SPECIES_LOSS, src) RegisterSignal(C, COMSIG_MOB_SAY, .proc/handle_speech) //We register handle_speech is being used. /datum/species/dwarf/on_species_loss(mob/living/carbon/H, datum/species/new_species) . = ..() - H.transform = H.transform.Scale(1, 1.25) //And we undo it. UnregisterSignal(H, COMSIG_MOB_SAY) //We register handle_speech is not being used. //Dwarf Name stuff @@ -121,7 +120,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) // return //Filth Reactions - Since miasma now exists var/filth_counter = 0 //Holder for the filth check cycle, basically contains how much filth dwarf sees numerically. - for(var/fuck in owner.visible_atoms(7)) //hello byond for view loop. + for(var/fuck in owner.fov_view(7)) //hello byond for view loop. if(istype(fuck, /mob/living/carbon/human)) var/mob/living/carbon/human/H = fuck if(H.stat == DEAD || (HAS_TRAIT(H, TRAIT_FAKEDEATH))) diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 81132080ab..2b9d28a5f7 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -293,7 +293,7 @@ if(isturf(H.loc)) //else, there's considered to be no light var/turf/T = H.loc light_amount = min(1,T.get_lumcount()) - 0.5 - H.adjust_nutrition(light_amount * 10, NUTRITION_LEVEL_FULL) + H.adjust_nutrition(light_amount * 4, NUTRITION_LEVEL_FULL) if(light_amount > 0.2) //if there's enough light, heal H.heal_overall_damage(1,1) H.adjustToxLoss(-1) diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index fd958ccc13..817498e417 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -13,7 +13,7 @@ disliked_food = MEAT | DAIRY liked_food = VEGETABLES | FRUIT | GRAIN species_language_holder = /datum/language_holder/sylvan - var/light_nutrition_gain_factor = 10 + var/light_nutrition_gain_factor = 4 var/light_toxheal = 1 var/light_oxyheal = 1 var/light_burnheal = 1 @@ -76,7 +76,7 @@ species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS) mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs") limbs_id = "pod" - light_nutrition_gain_factor = 7.5 + light_nutrition_gain_factor = 3 light_bruteheal = 0.2 light_burnheal = 0.2 light_toxheal = 0.7 diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 18c3fde188..5b91119789 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -45,6 +45,7 @@ /mob/living/carbon/monkey/ComponentInitialize() . = ..() AddElement(/datum/element/mob_holder, worn_state = "monkey", inv_slots = ITEM_SLOT_HEAD) + AddComponent(/datum/component/footstep, FOOTSTEP_MOB_BAREFOOT, 1, 2) /mob/living/carbon/monkey/Destroy() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index c36568ce37..502ebcbe5d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -9,10 +9,6 @@ diag_hud.add_to_hud(src) faction += "[REF(src)]" GLOB.mob_living_list += src - initialize_footstep() - -/mob/living/proc/initialize_footstep() - AddComponent(/datum/component/footstep) /mob/living/prepare_huds() ..() @@ -46,7 +42,8 @@ return ..() /mob/living/proc/ZImpactDamage(turf/T, levels) - visible_message("[src] crashes into [T] with a sickening noise!") + visible_message("[src] crashes into [T] with a sickening noise!", \ + "You crash into [T] with a sickening noise!") adjustBruteLoss((levels * 5) ** 1.5) DefaultCombatKnockdown(levels * 50) @@ -124,7 +121,9 @@ to_chat(src, "You're too exhausted to crawl under [L].") return TRUE ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_ATTEMPTING_CRAWL) - visible_message("[src] is attempting to crawl under [L].", "You are now attempting to crawl under [L].") + visible_message("[src] is attempting to crawl under [L].", + "You are now attempting to crawl under [L].", + target = L, target_message = "[src] is attempting to crawl under you.") if(!do_after(src, CRAWLUNDER_DELAY, target = src) || CHECK_MOBILITY(src, MOBILITY_STAND)) DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_ATTEMPTING_CRAWL) return TRUE @@ -276,7 +275,9 @@ if(AM.pulledby) if(!supress_message) - visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.") + AM.pulledby.visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.", + "[src] has pulled [AM] from your grip.", target = src, + target_message = "You have pulled [AM] from [AM.pulledby]'s grip.") log_combat(AM, AM.pulledby, "pulled from", src) AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. @@ -291,7 +292,9 @@ log_combat(src, M, "grabbed", addition="passive grab") if(!supress_message && !(iscarbon(AM) && HAS_TRAIT(src, TRAIT_STRONG_GRABBER))) - visible_message("[src] has grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by their hands":" passively"]!") //Cit change - And they thought ERP was bad. + visible_message("[src] has grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by [M.p_their()] hands":" passively"]!", + "You have grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by [M.p_their()] hands":" passively"]!", target = M, + target_message = "[src] has grabbed you[(zone_selected == "l_arm" || zone_selected == "r_arm")? " by your hands":" passively"]!") if(!iscarbon(src)) M.LAssailant = null else @@ -379,7 +382,7 @@ stop_pulling() //same as above -/mob/living/pointed(atom/A as mob|obj|turf in visible_atoms()) +/mob/living/pointed(atom/A as mob|obj|turf in fov_view()) if(incapacitated()) return FALSE if(HAS_TRAIT(src, TRAIT_DEATHCOMA)) @@ -756,12 +759,16 @@ . = ..() if(pulledby.grab_state > GRAB_PASSIVE) if(CHECK_MOBILITY(src, MOBILITY_RESIST) && prob(30/pulledby.grab_state)) - visible_message("[src] has broken free of [pulledby]'s grip!") + pulledby.visible_message("[src] has broken free of [pulledby]'s grip!", + "[src] has broken free of your grip!", target = src, + target_message = "You have broken free of [pulledby]'s grip!") pulledby.stop_pulling() return TRUE else if(moving_resist && client) //we resisted by trying to move // this is a horrible system and whoever thought using client instead of mob is okay is not an okay person client.move_delay = world.time + 20 - visible_message("[src] resists against [pulledby]'s grip!") + pulledby.visible_message("[src] resists against [pulledby]'s grip!", + "[src] resists against your grip!", target = src, + target_message = "You resist against [pulledby]'s grip!") else pulledby.stop_pulling() return TRUE @@ -826,7 +833,8 @@ strip_silence = g.strip_silence if (!strip_silence) who.visible_message("[src] tries to remove [who]'s [what.name].", \ - "[src] tries to remove [who]'s [what.name].") + "[src] tries to remove your [what.name].", target = src, + target_message = "You try to remove [who]'s [what.name].") what.add_fingerprint(src) else to_chat(src,"You try to remove [who]'s [what.name].") @@ -874,7 +882,9 @@ to_chat(src, "\The [what.name] doesn't fit in that place!") return - visible_message("[src] tries to put [what] on [who].") + who.visible_message("[src] tries to put [what] on [who].", + "[src] tries to put [what] on you.", target = src, + target_message = "You try to put [what] on [who].") if(do_mob(src, who, what.equip_delay_other)) if(what && Adjacent(who) && what.mob_can_equip(who, src, final_where, TRUE, TRUE)) if(temporarilyRemoveItemFromInventory(what)) @@ -899,7 +909,7 @@ var/final_pixel_y = get_standard_pixel_y_offset(lying) animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff , time = 2, loop = 6) animate(pixel_x = final_pixel_x , pixel_y = final_pixel_y , time = 2) - setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure to restart it in next life(). + floating_need_update = TRUE /mob/living/proc/get_temperature(datum/gas_mixture/environment) var/loc_temp = environment ? environment.temperature : T0C @@ -1058,7 +1068,7 @@ /mob/living/proc/IgniteMob() if(fire_stacks > 0 && !on_fire) on_fire = 1 - src.visible_message("[src] catches fire!", \ + visible_message("[src] catches fire!", \ "You're set on fire!") new/obj/effect/dummy/lighting_obj/moblight/fire(src) throw_alert("fire", /obj/screen/alert/fire) diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm index 8156f83dbd..817863f257 100644 --- a/code/modules/mob/living/living_block.dm +++ b/code/modules/mob/living/living_block.dm @@ -85,7 +85,8 @@ if(. & BLOCK_SUCCESS) return if(prob(final_block_chance)) - owner.visible_message("[owner] blocks [attack_text] with [src]!") + owner.visible_message("[owner] blocks [attack_text] with [src]!", + "You block [attack_text] with [src]!") return . | BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL return . | BLOCK_NONE diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 44b41c8cd8..17eb51b154 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -43,21 +43,21 @@ P.setAngle(SIMPLIFY_DEGREES(P.Angle + rand(120, 240))) if(!silent) visible_message("[P] gets deflected by [src]!", \ - "[P] gets deflected by [src]!") + "You deflect [P]!") if(REDIRECT_METHOD_REFLECT) P.setAngle(SIMPLIFY_DEGREES(P.Angle + 180)) if(!silent) visible_message("[P] gets reflected by [src]!", \ - "[P] gets reflected by [src]!") + "You reflect [P]!") if(REDIRECT_METHOD_PASSTHROUGH) if(!silent) visible_message("[P] passes through [src]!", \ - "[P] passes through [src]!") + "[P] passes through you!") return if(REDIRECT_METHOD_RETURN_TO_SENDER) if(!silent) visible_message("[src] deflects [P] back at their attacker!", \ - "[src] deflects [P] back at their attacker!") + "You deflect [P] back at your attacker!") if(P.firer) P.setAngle(Get_Angle(src, P.firer)) else @@ -141,7 +141,7 @@ playsound(loc, 'sound/weapons/throwtap.ogg', 1, volume, -1)//...play throwtap.ogg. if(!blocked) visible_message("[src] has been hit by [I].", \ - "[src] has been hit by [I].") + "You have been hit by [I].") var/armor = run_armor_check(impacting_zone, "melee", "Your armor has protected your [parse_zone(impacting_zone)].", "Your armor has softened hit to your [parse_zone(impacting_zone)].",I.armour_penetration) apply_damage(I.throwforce, dtype, impacting_zone, armor) if(I.thrownby) @@ -175,12 +175,15 @@ return updatehealth() visible_message("[M.name] has hit [src]!", \ - "[M.name] has hit [src]!", null, COMBAT_MESSAGE_RANGE) + "[M.name] has hit you!", null, COMBAT_MESSAGE_RANGE, null, + M.occupant, "You hit [src] with your [M.name]!") log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") else step_away(src,M) log_combat(M.occupant, src, "pushed", M) - visible_message("[M] pushes [src] out of the way.", null, null, 5) + visible_message("[M] pushes [src] out of the way.", \ + "[M] pushes you out of the way.", null, COMBAT_MESSAGE_RANGE, null, + M.occupant, "You push [src] out of the way with your [M.name].") /mob/living/fire_act() adjust_fire_stacks(3) @@ -224,7 +227,8 @@ var/old_grab_state = user.grab_state var/grab_upgrade_time = instant ? 0 : 30 visible_message("[user] starts to tighten [user.p_their()] grip on [src]!", \ - "[user] starts to tighten [user.p_their()] grip on you!") + "[user] starts to tighten [user.p_their()] grip on you!", target = user, + target_message = "You start to tighten your grip on [src]!") switch(user.grab_state) if(GRAB_AGGRESSIVE) log_combat(user, src, "attempted to neck grab", addition="neck grab") @@ -242,25 +246,29 @@ var/add_log = "" if(HAS_TRAIT(user, TRAIT_PACIFISM)) visible_message("[user] has firmly gripped [src]!", - "[user] has firmly gripped you!") + "[user] has firmly gripped you!", target = user, + target_message = "You have firmly gripped [src]!") add_log = " (pacifist)" else visible_message("[user] has grabbed [src] aggressively!", \ - "[user] has grabbed you aggressively!") + "[user] has grabbed you aggressively!", target = user, \ + target_message = "You have grabbed [src] aggressively!") update_mobility() stop_pulling() log_combat(user, src, "grabbed", addition="aggressive grab[add_log]") if(GRAB_NECK) log_combat(user, src, "grabbed", addition="neck grab") visible_message("[user] has grabbed [src] by the neck!",\ - "[user] has grabbed you by the neck!") + "[user] has grabbed you by the neck!", target = user, \ + target_message = "You have grabbed [src] by the neck!") update_mobility() //we fall down if(!buckled && !density) Move(user.loc) if(GRAB_KILL) log_combat(user, src, "strangled", addition="kill grab") visible_message("[user] is strangling [src]!", \ - "[user] is strangling you!") + "[user] is strangling you!", target = user, \ + target_message = "You are strangling [src]!") update_mobility() //we fall down if(!buckled && !density) Move(user.loc) @@ -272,7 +280,9 @@ SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user) if((user != src) && user.a_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE, null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS)) log_combat(user, src, "attempted to touch") - visible_message("[user] attempted to touch [src]!") + visible_message("[user] attempted to touch [src]!", + "[user] attempted to touch you!", target = user, + target_message = "You attempted to touch [src]!") return TRUE /mob/living/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) @@ -310,13 +320,16 @@ log_combat(M, src, "attacked") M.do_attack_animation(src) visible_message("The [M.name] glomps [src]!", \ - "The [M.name] glomps [src]!", null, COMBAT_MESSAGE_RANGE) + "The [M.name] glomps [src]!", null, COMBAT_MESSAGE_RANGE, null, + M, "You glomp [src]!") return TRUE /mob/living/attack_animal(mob/living/simple_animal/M) M.face_atom(src) if(M.melee_damage_upper == 0) - M.visible_message("\The [M] [M.friendly] [src]!") + M.visible_message("\The [M] [M.friendly_verb_continuous] [src]!", + "You [M.friendly_verb_simple] [src]!", target = src, + target_message = "\The [M] [M.friendly_verb_continuous] you!") return FALSE else if(HAS_TRAIT(M, TRAIT_PACIFISM)) @@ -327,8 +340,9 @@ if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) M.do_attack_animation(src) - visible_message("\The [M] [M.attacktext] [src]!", \ - "\The [M] [M.attacktext] [src]!", null, COMBAT_MESSAGE_RANGE) + visible_message("\The [M] [M.attack_verb_continuous] [src]!", \ + "\The [M] [M.attack_verb_continuous] you!", null, COMBAT_MESSAGE_RANGE, null, + M, "You [M.attack_verb_simple] [src]!") log_combat(M, src, "attacked") return TRUE @@ -347,17 +361,21 @@ log_combat(M, src, "attacked") playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) visible_message("[M.name] bites [src]!", \ - "[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE) + "[M.name] bites you!", null, COMBAT_MESSAGE_RANGE, null, + M, "You bite [src]!") return TRUE else visible_message("[M.name] has attempted to bite [src]!", \ - "[M.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE) + "[M.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE, null, + M, "You have attempted to bite [src]!") return FALSE /mob/living/attack_larva(mob/living/carbon/alien/larva/L) switch(L.a_intent) if(INTENT_HELP) - visible_message("[L.name] rubs its head against [src].") + visible_message("[L.name] rubs its head against [src].", + "[L.name] rubs its head against you.", target = L, \ + target_message = "You rub your head against [src].") return FALSE else @@ -370,21 +388,26 @@ if(prob(90)) log_combat(L, src, "attacked") visible_message("[L.name] bites [src]!", \ - "[L.name] bites [src]!", null, COMBAT_MESSAGE_RANGE) + "[L.name] bites you!", null, COMBAT_MESSAGE_RANGE, null, L, \ + "You bite [src]!") playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) return TRUE else visible_message("[L.name] has attempted to bite [src]!", \ - "[L.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE) + "[L.name] has attempted to bite you!", null, COMBAT_MESSAGE_RANGE, null, L, \ + "You have attempted to bite [src]!") /mob/living/attack_alien(mob/living/carbon/alien/humanoid/M) if((M != src) && M.a_intent != INTENT_HELP && (mob_run_block(M, 0, "the [M.name]", ATTACK_TYPE_MELEE | ATTACK_TYPE_UNARMED, 0, M, check_zone(M.zone_selected), null) & BLOCK_SUCCESS)) - visible_message("[M] attempted to touch [src]!") + visible_message("[M] attempted to touch [src]!", + "[M] attempted to touch you!") return FALSE switch(M.a_intent) if (INTENT_HELP) if(!isalien(src)) //I know it's ugly, but the alien vs alien attack_alien behaviour is a bit different. - visible_message("[M] caresses [src] with its scythe like arm.") + visible_message("[M] caresses [src] with its scythe like arm.", + "[M] caresses you with its scythe like arm.", target = M, + target_message = "You caress [src] with your scythe like arm.") return FALSE if (INTENT_GRAB) grabbedby(M) @@ -412,21 +435,26 @@ take_bodypart_damage(acidpwr * min(1, acid_volume * 0.1)) return 1 +///As the name suggests, this should be called to apply electric shocks. /mob/living/proc/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) SEND_SIGNAL(src, COMSIG_LIVING_ELECTROCUTE_ACT, shock_damage, source, siemens_coeff, flags) - if((flags & SHOCK_TESLA) && (flags_1 & TESLA_IGNORE_1)) + shock_damage *= siemens_coeff + if((flags & SHOCK_TESLA) && HAS_TRAIT(src, TRAIT_TESLA_SHOCKIMMUNE)) return FALSE if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE)) return FALSE - if(shock_damage > 0) - if(!(flags & SHOCK_ILLUSION)) - adjustFireLoss(shock_damage) - visible_message( - "[src] was shocked by \the [source]!", \ - "You feel a powerful shock coursing through your body!", \ - "You hear a heavy electrical crack." \ - ) - return shock_damage + if(shock_damage < 1) + return FALSE + if(!(flags & SHOCK_ILLUSION)) + adjustFireLoss(shock_damage) + else + adjustStaminaLoss(shock_damage) + visible_message( + "[src] was shocked by \the [source]!", \ + "You feel a powerful shock coursing through your body!", \ + "You hear a heavy electrical crack." \ + ) + return shock_damage /mob/living/emp_act(severity) . = ..() @@ -505,11 +533,11 @@ if(!used_item) used_item = get_active_held_item() ..() - setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement. + floating_need_update = TRUE + /mob/living/proc/getBruteLoss_nonProsthetic() return getBruteLoss() - + /mob/living/proc/getFireLoss_nonProsthetic() return getFireLoss() - \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm index ba162ecf2c..dcb7ac66c9 100644 --- a/code/modules/mob/living/silicon/pai/pai_defense.dm +++ b/code/modules/mob/living/silicon/pai/pai_defense.dm @@ -32,22 +32,28 @@ /mob/living/silicon/pai/attack_hand(mob/living/carbon/human/user) switch(user.a_intent) if(INTENT_HELP) - visible_message("[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.") + visible_message("[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.", + "[user] gently pats you on the head, eliciting an off-putting buzzing from your holographic field.", target = user, + target_message = "You gently pat [src] on the head, eliciting an off-putting buzzing from its holographic field.") if(INTENT_DISARM) - visible_message("[user] boops [src] on the head!") + visible_message("[user] boops [src] on the head!", + "[user] boops you on the head!", target = user, + target_message = "You boop [src] on the head!") if(INTENT_HARM) user.do_attack_animation(src) if (user.name == master) visible_message("Responding to its master's touch, [src] disengages its holochassis emitter, rapidly losing coherence.") - spawn(10) - fold_in() - if(user.put_in_hands(card)) - user.visible_message("[user] promptly scoops up [user.p_their()] pAI's card.") + fold_in() + if(user.put_in_hands(card)) + user.visible_message("[user] promptly scoops up [user.p_their()] pAI's card.", + "You promptly scoops up your pAI's card.") else if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to hurt [src]!") return - visible_message("[user] stomps on [src]!.") + visible_message("[user] stomps on [src]!.", + "[user] stomps on you!.", target = user, + target_message = "You stomp on [src]!.") take_holo_damage(2) else grabbedby(user) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 5750543a92..e337618e4b 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -32,15 +32,17 @@ var/obj/item/I = get_active_held_item() if(I) uneq_active() - visible_message("[M] disarmed [src]!", \ - "[M] has disabled [src]'s active module!", null, COMBAT_MESSAGE_RANGE) + visible_message("[M] has disarmed [src]!", \ + "[M] has disabled your active module!", null, COMBAT_MESSAGE_RANGE, null, M, + "You have disarmed [src]!") log_combat(M, src, "disarmed", "[I ? " removing \the [I]" : ""]") else Paralyze(40) step(src,get_dir(M,src)) log_combat(M, src, "pushed") visible_message("[M] has forced back [src]!", \ - "[M] has forced back [src]!", null, COMBAT_MESSAGE_RANGE) + "[M] has forced you back!", null, COMBAT_MESSAGE_RANGE, null, M, + "You have forced back [src]!") playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1) /mob/living/silicon/robot/attack_slime(mob/living/simple_animal/slime/M) diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index 94ce1e42fc..cd50ffbae6 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -17,7 +17,8 @@ log_combat(M, src, "attacked") playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) visible_message("[M] has slashed at [src]!", \ - "[M] has slashed at [src]!") + "[M] has slashed at you!", target = M, \ + target_message = "You have slashed at [src]!") if(prob(8)) flash_act(affect_silicon = 1) log_combat(M, src, "attacked") @@ -25,8 +26,9 @@ updatehealth() else playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - visible_message("[M] took a swipe at [src]!", \ - "[M] took a swipe at [src]!") + visible_message("[M] take a swipe at [src]!", \ + "[M] take a swipe at you!", target = M, \ + target_message = "You take a swipe at [src]!") /mob/living/silicon/attack_animal(mob/living/simple_animal/M) . = ..() @@ -36,7 +38,8 @@ for(var/mob/living/N in buckled_mobs) N.DefaultCombatKnockdown(20) unbuckle_mob(N) - N.visible_message("[N] is knocked off of [src] by [M]!") + N.visible_message("[N] is knocked off of [src] by [M]!", + "You are knocked off of [src] by [M]!") switch(M.melee_damage_type) if(BRUTE) adjustBruteLoss(damage) @@ -62,7 +65,8 @@ adjustBruteLoss(rand(10, 15)) playsound(loc, "punch", 25, 1, -1) visible_message("[user] has punched [src]!", \ - "[user] has punched [src]!") + "[user] has punched you!", target = user, \ + target_message = "You have punched [src]!") return TRUE return FALSE @@ -73,14 +77,16 @@ switch(M.a_intent) if (INTENT_HELP) M.visible_message("[M] pets [src].", \ - "You pet [src].") + "You pet [src].", target = src, + target_message = "[M] pets you.") if(INTENT_GRAB) grabbedby(M) else M.do_attack_animation(src, ATTACK_EFFECT_PUNCH) playsound(src.loc, 'sound/effects/bang.ogg', 10, 1) visible_message("[M] punches [src], but doesn't leave a dent.", \ - "[M] punches [src], but doesn't leave a dent.", null, COMBAT_MESSAGE_RANGE) + "[M] punches you, but doesn't leave a dent.", null, COMBAT_MESSAGE_RANGE, null, M, + "You punch [src], but don't leave a dent.") /mob/living/silicon/attack_drone(mob/living/simple_animal/drone/M) if(M.a_intent == INTENT_HARM) @@ -109,7 +115,8 @@ if(prob(severity*50)) unbuckle_mob(M) M.DefaultCombatKnockdown(40) - M.visible_message("[M] is thrown off of [src]!") + M.visible_message("[M] is thrown off of [src]!", + "You are thrown off of [src]!") flash_act(affect_silicon = 1) /mob/living/silicon/bullet_act(obj/item/projectile/P, def_zone) @@ -127,13 +134,15 @@ adjustBruteLoss(P.damage) if(prob(P.damage*1.5)) for(var/mob/living/M in buckled_mobs) - M.visible_message("[M] is knocked off of [src]!") + M.visible_message("[M] is knocked off of [src]!", + "You are knocked off of [src]!") unbuckle_mob(M) M.DefaultCombatKnockdown(40) if(P.stun || P.knockdown) for(var/mob/living/M in buckled_mobs) unbuckle_mob(M) - M.visible_message("[M] is knocked off of [src] by the [P]!") + M.visible_message("[M] is knocked off of [src] by the [P]!", + "You are knocked off of [src] by the [P]!") P.on_hit(src) return BULLET_ACT_HIT diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm index fe18d48718..1e56e91ae1 100644 --- a/code/modules/mob/living/simple_animal/animal_defense.dm +++ b/code/modules/mob/living/simple_animal/animal_defense.dm @@ -7,7 +7,9 @@ switch(M.a_intent) if(INTENT_HELP) if (health > 0) - visible_message("[M] [response_help] [src].") + visible_message("[M] [response_help_continuous] [src].", \ + "[M] [response_help_continuous] you.", null, null, null, + M, "You [response_help_simple] [src].") playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if(INTENT_GRAB) @@ -16,13 +18,22 @@ else grabbedby(M) - if(INTENT_HARM, INTENT_DISARM) + if(INTENT_DISARM) + M.do_attack_animation(src, ATTACK_EFFECT_DISARM) + visible_message("[M] [response_disarm_continuous] [src]!",\ + "[M] [response_disarm_continuous] you!", null, COMBAT_MESSAGE_RANGE, null, \ + M, "You [response_disarm_simple] [src]!") + playsound(src, 'sound/weapons/thudswoosh.ogg', 25, 1) + log_combat(M, src, "disarmed") + + if(INTENT_HARM) if(HAS_TRAIT(M, TRAIT_PACIFISM)) to_chat(M, "You don't want to hurt [src]!") return M.do_attack_animation(src, ATTACK_EFFECT_PUNCH) - visible_message("[M] [response_harm] [src]!",\ - "[M] [response_harm] [src]!", null, COMBAT_MESSAGE_RANGE) + visible_message("[M] [response_harm_continuous] [src]!",\ + "[M] [response_harm_continuous] you!", null, COMBAT_MESSAGE_RANGE, null, \ + M, "You [response_harm_simple] [src]!") playsound(loc, attacked_sound, 25, 1, -1) attack_threshold_check(harm_intent_damage) log_combat(M, src, "attacked") @@ -35,8 +46,9 @@ if(.) return playsound(loc, "punch", 25, 1, -1) - visible_message("[user] has punched [src]!", \ - "[user] has punched [src]!", null, COMBAT_MESSAGE_RANGE) + visible_message("[user] punches [src]!", \ + "[user] punches you!", null, COMBAT_MESSAGE_RANGE, null, \ + user, "You punch [src]!") adjustBruteLoss(15) return TRUE @@ -48,7 +60,9 @@ return 1 if (M.a_intent == INTENT_HELP) if (health > 0) - visible_message("[M.name] [response_help] [src].") + visible_message("[M.name] [response_help_continuous] [src].", \ + "[M.name] [response_help_continuous] you.", \ + target = M, target_message = "You [response_help_simple] [src].") playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) /mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M) @@ -57,12 +71,14 @@ return if(M.a_intent == INTENT_DISARM) playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - visible_message("[M] [response_disarm] [name]!", \ - "[M] [response_disarm] [name]!", null, COMBAT_MESSAGE_RANGE) + visible_message("[M] [response_disarm_continuous] [name]!", \ + "[M] [response_disarm_continuous] [name]!", null, COMBAT_MESSAGE_RANGE, null, \ + M, "You [response_disarm_simple] [name]!") log_combat(M, src, "disarmed") else visible_message("[M] has slashed at [src]!", \ - "[M] has slashed at [src]!", null, COMBAT_MESSAGE_RANGE) + "[M] has slashed at [src]!", null, COMBAT_MESSAGE_RANGE, null, \ + M, "[M] has slashed at [src]!") playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) attack_threshold_check(M.meleeSlashSAPower) log_combat(M, src, "attacked") @@ -102,7 +118,7 @@ temp_damage *= damage_coeff[damagetype] if(temp_damage >= 0 && temp_damage <= force_threshold) - visible_message("[src] looks unharmed.") + visible_message("[src] looks unharmed!") return FALSE else apply_damage(damage, damagetype, null, getarmor(null, armorcheck)) diff --git a/code/modules/mob/living/simple_animal/astral.dm b/code/modules/mob/living/simple_animal/astral.dm index 8e10376265..4fb9e9273e 100644 --- a/code/modules/mob/living/simple_animal/astral.dm +++ b/code/modules/mob/living/simple_animal/astral.dm @@ -6,10 +6,14 @@ icon_living = "ghost" mob_biotypes = MOB_SPIRIT has_field_of_vision = FALSE //we are a spoopy ghost - attacktext = "raises the hairs on the neck of" - response_harm = "disrupts the concentration of" - response_disarm = "wafts" - friendly = "communes with" + attack_verb_continuous = "raises the hair on the neck of" + attack_verb_simple = "raise the hair on the neck of" + response_harm_continuous = "disrupts the concentration of" + response_harm_simple = "disrupt the concentration of" + response_disarm_continuous = "wafts" + response_disarm_simple = "waft" + friendly_verb_continuous = "communes with" + friendly_verb_simple = "commute with" loot = null maxHealth = 10 health = 10 @@ -19,7 +23,6 @@ deathmessage = "disappears as if it was never really there to begin with" incorporeal_move = 1 alpha = 50 - attacktext = "touches the mind of" speak_emote = list("echos") movement_type = FLYING var/pseudo_death = FALSE @@ -33,7 +36,6 @@ /mob/living/simple_animal/astral/death() icon_state = "shade_dead" Stun(1000) - friendly = "deads at" pseudo_death = TRUE incorporeal_move = 0 to_chat(src, "Your astral projection is interrupted and your mind is sent back to your body with a shock!") @@ -50,14 +52,14 @@ to_chat(src, "The intensity of the astrogen in your body is too much allow you to return to yourself yet!") return to_chat(src, "You astrally possess [H]!") - log_game("FERMICHEM: [src] has astrally possessed [A]!") + log_reagent("FERMICHEM: [src] has astrally possessed [A]!") src.mind.transfer_to(H) qdel(src) var/message = html_decode(stripped_input(src, "Enter a message to send to [A]", MAX_MESSAGE_LEN)) if(!message) return to_chat(A, "[src] projects into your mind, \"[message]\"") - log_game("FERMICHEM: [src] has astrally transmitted [message] into [A]") + log_reagent("FERMICHEM: [src] has astrally transmitted [message] into [A]") //Delete the mob if there's no mind! Pay that mob no mind. /mob/living/simple_animal/astral/Life() diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 5bfaf8ad27..0b78cdc95a 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -20,9 +20,7 @@ weather_immunities = list("lava","ash") var/clean_time = 50 //How long do we take to clean? - var/broom = FALSE //Do we have an speed buff from a broom? - var/adv_mop = FALSE //Do we have a cleaning buff from a better mop? - + var/upgrades = 0 var/blood = 1 var/trash = 0 @@ -79,26 +77,38 @@ if(open) to_chat(user, "Please close the access panel before locking it.") else - to_chat(user, "\The [src] doesn't seem to respect your authority.") + to_chat(user, "The [src] doesn't seem to respect your authority.") - if(istype(W, /obj/item/mop/advanced)) - if(bot_core.allowed(user) && open && adv_mop == TRUE) + else if(istype(W, /obj/item/mop/advanced)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_CLEANER_ADVANCED_MOP)) to_chat(user, "You replace \the [src] old mop with a new better one!") - adv_mop = TRUE + upgrades |= UPGRADE_CLEANER_ADVANCED_MOP clean_time = 20 //2.5 the speed! window_name = "Automatic Station Cleaner v2.1 BETA" //New! qdel(W) + if(!open) + to_chat(user, "The [src] access pannle is not open!") + return + if(!bot_core.allowed(user)) + to_chat(user, "The [src] access pannel locked off to you!") + return else - to_chat(user, "\the [src] already has this mop!") + to_chat(user, "The [src] already has this mop!") - if(istype(W, /obj/item/broom)) - if(bot_core.allowed(user) && open && broom == TRUE) + else if(istype(W, /obj/item/broom)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_CLEANER_BROOM)) to_chat(user, "You add to \the [src] a broom speeding it up!") - broom = TRUE + upgrades |= UPGRADE_CLEANER_BROOM base_speed = 1 //2x faster! qdel(W) + if(!open) + to_chat(user, "The [src] access pannel is not open!") + return + if(!bot_core.allowed(user)) + to_chat(user, "The [src] access pannel locked off to you!") + return else - to_chat(user, "\the [src] already has a broom!") + to_chat(user, "The [src] already has a broom!") else return ..() diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 469a395169..6febb942a1 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -44,8 +44,6 @@ var/cell_type = /obj/item/stock_parts/cell var/vest_type = /obj/item/clothing/suit/armor/vest - do_footstep = TRUE - /mob/living/simple_animal/bot/ed209/Initialize(mapload,created_name,created_lasercolor) . = ..() diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 1bf3883ea7..0f4608f48c 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -33,6 +33,8 @@ var/oldloc = null var/toolbox = /obj/item/storage/toolbox/mechanical + var/upgrades = 0 + #define HULL_BREACH 1 #define LINE_SPACE_MODE 2 #define FIX_TILE 3 @@ -120,6 +122,36 @@ to_chat(user, "You load [loaded] tiles into the floorbot. It now contains [specialtiles] tiles.") else to_chat(user, "You need at least one floor tile to put into [src]!") + + else if(istype(W, /obj/item/storage/toolbox/artistic)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_FLOOR_ARTBOX)) + to_chat(user, "You upgrade \the [src] case to hold more!") + upgrades |= UPGRADE_FLOOR_ARTBOX + maxtiles += 100 //Double the storage! + qdel(W) + if(!open) + to_chat(user, "The [src] access pannle is not open!") + return + if(!bot_core.allowed(user)) + to_chat(user, "The [src] access pannel locked off to you!") + return + else + to_chat(user, "The [src] already has a upgraded case!") + + else if(istype(W, /obj/item/storage/toolbox/syndicate)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_FLOOR_SYNDIBOX)) + to_chat(user, "You upgrade \the [src] case to hold more!") + upgrades |= UPGRADE_FLOOR_SYNDIBOX + maxtiles += 200 //Double bse storage + base_speed = 1 //2x faster! + qdel(W) + if(!bot_core.allowed(user)) + to_chat(user, "The [src] access pannel locked off to you!") + return + else + to_chat(user, "The [src] already has a upgraded case!") + + else ..() diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index d3d5a65eb2..7d93669c31 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -42,6 +42,7 @@ var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users. var/declare_cooldown = 0 //Prevents spam of critical patient alerts. var/stationary_mode = 0 //If enabled, the Medibot will not move automatically. + var/injection_time = 30 //How long we take to inject someone //Setting which reagents to use to treat what by default. By id. var/treatment_brute_avoid = /datum/reagent/medicine/tricordrazine var/treatment_brute = /datum/reagent/medicine/bicaridine @@ -51,19 +52,25 @@ var/treatment_fire = /datum/reagent/medicine/kelotane var/treatment_tox_avoid = /datum/reagent/medicine/tricordrazine var/treatment_tox = /datum/reagent/medicine/charcoal - var/treatment_tox_toxlover = /datum/reagent/toxin + var/treatment_tox_toxlover = /datum/reagent/toxin //Injects toxins into people that heal via toxins var/treatment_virus_avoid = null var/treatment_virus = /datum/reagent/medicine/spaceacillin var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible. var/shut_up = 0 //self explanatory :) + var/upgrades = 0 + var/upgraded_dispenser_1 //Do we have the nicer chemicals? - replaces dex with salbutamol + var/upgraded_dispenser_2 //Do we have the nicer chemicals? - replaces kep with oxandrolone + var/upgraded_dispenser_3 //Do we have the nicer chemicals? - replaces bic with sal acid + var/upgraded_dispenser_4 //Do we have the nicer chemicals? - replaces charcoal/toxin with pentetic acid / pentetic jelly + /mob/living/simple_animal/bot/medbot/mysterious name = "\improper Mysterious Medibot" desc = "International Medibot of mystery." skin = "bezerk" - treatment_brute = /datum/reagent/medicine/tricordrazine - treatment_fire = /datum/reagent/medicine/tricordrazine - treatment_tox = /datum/reagent/medicine/tricordrazine + treatment_brute = /datum/reagent/medicine/regen_jelly + treatment_fire = /datum/reagent/medicine/regen_jelly + treatment_tox = /datum/reagent/medicine/regen_jelly /mob/living/simple_animal/bot/medbot/derelict name = "\improper Old Medibot" @@ -220,7 +227,6 @@ /mob/living/simple_animal/bot/medbot/attackby(obj/item/W as obj, mob/user as mob, params) if(istype(W, /obj/item/reagent_containers/glass)) - . = 1 //no afterattack if(locked) to_chat(user, "You cannot insert a beaker because the panel is locked!") return @@ -234,6 +240,97 @@ to_chat(user, "You insert [W].") show_controls(user) + else if(istype(W, /obj/item/reagent_containers/syringe/piercing)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_PIERERCING)) + to_chat(user, "You replace \the [src] syringe with a diamond-tipped one!") + upgrades |= UPGRADE_MEDICAL_PIERERCING + qdel(W) + if(!open) + to_chat(user, "The [src] access pannel is not open!") + return + if(!bot_core.allowed(user)) + to_chat(user, "The [src] access pannel locked off to you!") + return + else + to_chat(user, "The [src] already has a diamond-tipped syringe!") + + else if(istype(W, /obj/item/hypospray/mkii)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_HYPOSPRAY)) + to_chat(user, "You replace \the [src] syringe base with a DeForest Medical MK.II Hypospray!") + upgrades |= UPGRADE_MEDICAL_HYPOSPRAY + injection_time = 15 //Half the time half the death! + window_name = "Automatic Medical Unit v2.4 ALPHA" + qdel(W) + if(!open) + to_chat(user, "The [src] access pannel is not open!") + return + if(!bot_core.allowed(user)) + to_chat(user, "The [src] access pannel locked off to you!") + return + else + to_chat(user, "The [src] already has a DeForest Medical Hypospray base!") + + else if(istype(W, /obj/item/circuitboard/machine/chem_dispenser)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_CHEM_BOARD)) + to_chat(user, "You add in the board upgrading \the [src] reagent banks!") + upgrades |= UPGRADE_MEDICAL_CHEM_BOARD + treatment_oxy = /datum/reagent/medicine/salbutamol //Replaces Dex with salbutamol "better" healing of o2 + qdel(W) + if(!open) + to_chat(user, "The [src] access pannel is not open!") + return + if(!bot_core.allowed(user)) + to_chat(user, "The [src] access pannel locked off to you!") + return + else + to_chat(user, "The [src] already has this upgrade!") + + else if(istype(W, /obj/item/circuitboard/machine/cryo_tube)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_CRYO_BOARD)) + to_chat(user, "You add in the board upgrading \the [src] reagent banks!") + upgrades |= UPGRADE_MEDICAL_CRYO_BOARD + treatment_fire = /datum/reagent/medicine/oxandrolone //Replaces Kep with oxandrolone "better" healing of burns + qdel(W) + if(!open) + to_chat(user, "The [src] access pannel is not open!") + return + if(!bot_core.allowed(user)) + to_chat(user, "The [src] access pannel locked off to you!") + return + else + to_chat(user, "The [src] already has this upgrade!") + + else if(istype(W, /obj/item/circuitboard/machine/chem_master)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_CHEM_MASTER)) + to_chat(user, "You add in the board upgrading \the [src] reagent banks!") + upgrades |= UPGRADE_MEDICAL_CHEM_MASTER + treatment_brute = /datum/reagent/medicine/sal_acid //Replaces Bic with Sal Acid "better" healing of brute + qdel(W) + if(!open) + to_chat(user, "the [src] access pannel is not open!") + return + if(!bot_core.allowed(user)) + to_chat(user, "the [src] access pannel locked off to you!") + return + else + to_chat(user, "the [src] already has this upgrade!") + + else if(istype(W, /obj/item/circuitboard/machine/sleeper)) + if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_SLEEP_BOARD)) + to_chat(user, "You add in the board upgrading \the [src] reagent banks!") + upgrades |= UPGRADE_MEDICAL_SLEEP_BOARD + treatment_tox = /datum/reagent/medicine/pen_acid //replaces charcoal with pen acid a "better" healing of toxins + treatment_tox_toxlover = /datum/reagent/medicine/pen_acid/pen_jelly //Injects pen jelly into people that heal via toxins + qdel(W) + if(!open) + to_chat(user, "The [src] access pannle is not open!") + return + if(!bot_core.allowed(user)) + to_chat(user, "The [src] access pannel locked off to you!") + return + else + to_chat(user, "The [src] already has this upgrade!") + else var/current_health = health ..() @@ -249,6 +346,8 @@ audible_message("[src] buzzes oddly!") flick("medibot_spark", src) playsound(src, "sparks", 75, 1) + if(!CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_PIERERCING)) + upgrades |= UPGRADE_MEDICAL_PIERERCING //Jabs even harder through the clothing! if(user) oldpatient = user @@ -361,7 +460,7 @@ if(ishuman(C)) var/mob/living/carbon/human/H = C - if (H.wear_suit && H.head && istype(H.wear_suit, /obj/item/clothing) && istype(H.head, /obj/item/clothing)) + if (H.wear_suit && H.head && istype(H.wear_suit, /obj/item/clothing) && istype(H.head, /obj/item/clothing) && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_PIERERCING)) var/obj/item/clothing/CS = H.wear_suit var/obj/item/clothing/CH = H.head if (CS.clothing_flags & CH.clothing_flags & THICKMATERIAL) @@ -418,7 +517,7 @@ else ..() -/mob/living/simple_animal/bot/medbot/examinate(atom/A as mob|obj|turf in visible_atoms()) +/mob/living/simple_animal/bot/medbot/examinate(atom/A as mob|obj|turf in fov_view()) ..() if(!is_blind(src)) chemscan(src, A) @@ -504,7 +603,7 @@ "[src] is trying to inject you!") var/failed = FALSE - if(do_mob(src, patient, 30)) //Is C == patient? This is so confusing + if(do_mob(src, patient, injection_time)) //Is C == patient? This is so confusing if((get_dist(src, patient) <= 1) && (on) && assess_patient(patient)) if(reagent_id == "internal_beaker") if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 674cc722d8..354bc9ed0f 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -5,9 +5,12 @@ gender = NEUTER mob_biotypes = NONE speak_emote = list("hisses") - response_help = "thinks better of touching" - response_disarm = "flails at" - response_harm = "punches" + response_help_continuous = "thinks better of touching" + response_help_simple = "think better of touching" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "punches" + response_harm_simple = "punch" threat = 1 speak_chance = 1 icon = 'icons/mob/mob.dmi' @@ -122,12 +125,14 @@ threat = 3 maxHealth = 150 health = 150 - response_harm = "harmlessly punches" + response_harm_continuous = "harmlessly punches" + response_harm_simple = "harmlessly punch" harm_intent_damage = 0 obj_damage = 90 melee_damage_lower = 25 melee_damage_upper = 25 - attacktext = "smashes their armored gauntlet into" + attack_verb_continuous = "smashes their armored gauntlet into" + attack_verb_simple = "smash your armored gauntlet into" speed = 2.5 environment_smash = ENVIRONMENT_SMASH_WALLS attack_sound = 'sound/weapons/punch3.ogg' @@ -188,7 +193,8 @@ melee_damage_lower = 20 melee_damage_upper = 20 retreat_distance = 2 //AI wraiths will move in and out of combat - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/weapons/bladeslice.ogg' construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift) runetype = /datum/action/innate/cult/create_rune/tele @@ -232,14 +238,16 @@ icon_living = "artificer" maxHealth = 50 health = 50 - response_harm = "viciously beats" + response_harm_continuous = "viciously beats" + response_harm_simple = "viciously beat" harm_intent_damage = 5 obj_damage = 60 melee_damage_lower = 5 melee_damage_upper = 5 retreat_distance = 10 minimum_distance = 10 //AI artificers will flee like fuck - attacktext = "rams" + attack_verb_continuous = "rams" + attack_verb_simple = "ram" environment_smash = ENVIRONMENT_SMASH_WALLS attack_sound = 'sound/weapons/punch2.ogg' construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/wall, @@ -319,7 +327,8 @@ sight = SEE_MOBS melee_damage_lower = 15 melee_damage_upper = 20 - attacktext = "butchers" + attack_verb_continuous = "butchers" + attack_verb_simple = "butcher" attack_sound = 'sound/weapons/bladeslice.ogg' construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/area_conversion, /obj/effect/proc_holder/spell/targeted/forcewall/cult) diff --git a/code/modules/mob/living/simple_animal/friendly/bumbles.dm b/code/modules/mob/living/simple_animal/friendly/bumbles.dm index 1a78a47031..2d236a4327 100644 --- a/code/modules/mob/living/simple_animal/friendly/bumbles.dm +++ b/code/modules/mob/living/simple_animal/friendly/bumbles.dm @@ -5,14 +5,18 @@ icon_living = "bumbles" icon_dead = "bumbles_dead" turns_per_move = 1 - response_help = "pets" - response_disarm = "brushes aside" - response_harm = "squashes" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "brushes aside" + response_help_simple = "brush aside" + response_harm_continuous = "squashes" + response_harm_simple = "squash" speak_emote = list("buzzes") maxHealth = 100 health = 100 harm_intent_damage = 1 - friendly = "bzzs" + friendly_verb_continuous = "bzzs" + friendly_verb_simple = "bzz" density = FALSE movement_type = FLYING pass_flags = PASSTABLE | PASSGRILLE | PASSMOB diff --git a/code/modules/mob/living/simple_animal/friendly/butterfly.dm b/code/modules/mob/living/simple_animal/friendly/butterfly.dm index 80fba5a9a4..bf4f45e283 100644 --- a/code/modules/mob/living/simple_animal/friendly/butterfly.dm +++ b/code/modules/mob/living/simple_animal/friendly/butterfly.dm @@ -5,14 +5,18 @@ icon_living = "butterfly" icon_dead = "butterfly_dead" turns_per_move = 1 - response_help = "shoos" - response_disarm = "brushes aside" - response_harm = "squashes" + response_help_continuous = "shoos" + response_help_simple = "shoo" + response_disarm_continuous = "brushes aside" + response_disarm_simple = "brush aside" + response_harm_continuous = "squashes" + response_harm_simple = "squash" speak_emote = list("flutters") maxHealth = 2 health = 2 harm_intent_damage = 1 - friendly = "nudges" + friendly_verb_continuous = "nudges" + friendly_verb_simple = "nudge" density = FALSE movement_type = FLYING pass_flags = PASSTABLE | PASSGRILLE | PASSMOB diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index 7d41068020..5f7ff198e2 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -24,15 +24,18 @@ animal_species = /mob/living/simple_animal/pet/cat childtype = list(/mob/living/simple_animal/pet/cat/kitten) butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2, /obj/item/organ/ears/cat = 1, /obj/item/organ/tail/cat = 1) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" var/turns_since_scan = 0 var/mob/living/simple_animal/mouse/movement_target gold_core_spawnable = FRIENDLY_SPAWN collar_type = "cat" var/held_icon = "cat2" - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW /mob/living/simple_animal/pet/cat/Initialize() . = ..() @@ -245,7 +248,8 @@ harm_intent_damage = 10 butcher_results = list(/obj/item/organ/brain = 1, /obj/item/organ/heart = 1, /obj/item/reagent_containers/food/snacks/cakeslice/birthday = 3, \ /obj/item/reagent_containers/food/snacks/meat/slab = 2) - response_harm = "takes a bite out of" + response_harm_continuous = "takes a bite out of" + response_harm_simple = "take a bite out of" attacked_sound = 'sound/items/eatfood.ogg' deathmessage = "loses its false life and collapses!" death_sound = "bodyfall" @@ -306,7 +310,6 @@ if (pseudo_death == TRUE) //secret cat chem icon_state = "custom_cat_dead" Stun(1000) - friendly = "deads at" return else ..() diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm index 95aa86aaab..9a34f2c176 100644 --- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm +++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm @@ -14,9 +14,12 @@ pass_flags = PASSTABLE | PASSGRILLE | PASSMOB mob_size = MOB_SIZE_TINY mob_biotypes = MOB_ORGANIC|MOB_BUG - response_help = "pokes" - response_disarm = "shoos" - response_harm = "splats" + response_help_continuous = "pokes" + response_help_simple = "poke" + response_disarm_continuous = "shoos" + response_disarm_simple = "shoo" + response_harm_continuous = "splats" + response_harm_simple = "splat" speak_emote = list("chitters") density = FALSE ventcrawler = VENTCRAWLER_ALWAYS diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm index cce5edc513..d86362c974 100644 --- a/code/modules/mob/living/simple_animal/friendly/crab.dm +++ b/code/modules/mob/living/simple_animal/friendly/crab.dm @@ -12,11 +12,15 @@ speak_chance = 1 turns_per_move = 5 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/rawcrab = 4) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "stomps" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "stomps" + response_harm_continuous = "stomp" stop_automated_movement = 1 - friendly = "pinches" + friendly_verb_continuous = "pinches" + friendly_verb_simple = "pinch" ventcrawler = VENTCRAWLER_ALWAYS var/obj/item/inventory_head var/obj/item/inventory_mask @@ -41,9 +45,6 @@ real_name = "Coffee" desc = "It's Coffee, the other pet!" gender = FEMALE - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "stomps" gold_core_spawnable = NO_SPAWN /mob/living/simple_animal/crab/evil @@ -53,9 +54,10 @@ icon_state = "evilcrab" icon_living = "evilcrab" icon_dead = "evilcrab_dead" - response_help = "pokes" - response_disarm = "shoves" - response_harm = "stomps" + response_help_continuous = "pokes" + response_help_simple = "poke" + response_disarm_continuous = "shoves" + response_disarm_simple = "shove" gold_core_spawnable = HOSTILE_SPAWN /mob/living/simple_animal/crab/kreb @@ -65,9 +67,6 @@ icon_state = "kreb" icon_living = "kreb" icon_dead = "kreb_dead" - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "stomps" gold_core_spawnable = NO_SPAWN /mob/living/simple_animal/crab/evil/kreb diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index 485cece8b7..57a4ecc5c9 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -2,9 +2,12 @@ /mob/living/simple_animal/pet/dog mob_biotypes = MOB_ORGANIC|MOB_BEAST - response_help = "pets" - response_disarm = "bops" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "bops" + response_disarm_simple = "bop" + response_harm_continuous = "kicks" + response_harm_simple = "kick" speak = list("YAP", "Woof!", "Bark!", "AUUUUUU") speak_emote = list("barks", "woofs") emote_hear = list("barks!", "woofs!", "yaps.","pants.") @@ -15,7 +18,7 @@ turns_per_move = 10 var/held_icon = "corgi" - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW /mob/living/simple_animal/pet/dog/ComponentInitialize() . = ..() @@ -332,9 +335,6 @@ desc = "It's the HoP's beloved corgi." var/turns_since_scan = 0 var/obj/movement_target - response_help = "pets" - response_disarm = "bops" - response_harm = "kicks" gold_core_spawnable = NO_SPAWN unique_pet = TRUE var/age = 0 @@ -604,9 +604,6 @@ icon_state = "lisa" icon_living = "lisa" icon_dead = "lisa_dead" - response_help = "pets" - response_disarm = "bops" - response_harm = "kicks" var/turns_since_scan = 0 var/puppies = 0 held_icon = "lisa" diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index e67e649ac6..59fa94a1fa 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -13,13 +13,17 @@ turns_per_move = 5 see_in_dark = 6 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 4) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" faction = list("neutral") mob_biotypes = MOB_ORGANIC|MOB_BEAST attack_same = 1 - attacktext = "kicks" + attack_verb_continuous = "kicks" + attack_verb_simple = "kick" attack_sound = 'sound/weapons/punch1.ogg' health = 40 maxHealth = 40 @@ -30,7 +34,7 @@ blood_volume = BLOOD_VOLUME_NORMAL var/obj/item/udder/udder = null - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE /mob/living/simple_animal/hostile/retaliate/goat/Initialize() udder = new() @@ -121,10 +125,14 @@ turns_per_move = 5 see_in_dark = 6 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 6) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "kicks" + attack_verb_simple = "kick" attack_sound = 'sound/weapons/punch1.ogg' health = 50 maxHealth = 50 @@ -132,7 +140,7 @@ gold_core_spawnable = FRIENDLY_SPAWN blood_volume = BLOOD_VOLUME_NORMAL - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE /mob/living/simple_animal/cow/Initialize() udder = new() @@ -198,10 +206,14 @@ speak_chance = 2 turns_per_move = 2 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 1) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "kicks" + attack_verb_simple = "kick" health = 3 maxHealth = 3 ventcrawler = VENTCRAWLER_ALWAYS @@ -210,7 +222,7 @@ mob_size = MOB_SIZE_TINY gold_core_spawnable = FRIENDLY_SPAWN - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW /mob/living/simple_animal/chick/Initialize() . = ..() @@ -249,10 +261,14 @@ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 2) var/egg_type = /obj/item/reagent_containers/food/snacks/egg var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "kicks" + attack_verb_simple = "kick" health = 15 maxHealth = 15 ventcrawler = VENTCRAWLER_ALWAYS @@ -268,7 +284,7 @@ gold_core_spawnable = FRIENDLY_SPAWN var/static/chicken_count = 0 - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW /mob/living/simple_animal/chicken/Initialize() . = ..() @@ -342,10 +358,14 @@ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3) var/egg_type = /obj/item/reagent_containers/food/snacks/egg/kiwiEgg var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "kicks" + attack_verb_simple = "kick" health = 25 maxHealth = 25 ventcrawler = VENTCRAWLER_ALWAYS @@ -358,6 +378,8 @@ gold_core_spawnable = FRIENDLY_SPAWN var/static/kiwi_count = 0 + footstep_type = FOOTSTEP_MOB_CLAW + /mob/living/simple_animal/kiwi/Destroy() --kiwi_count return ..() @@ -418,10 +440,14 @@ speak_chance = 2 turns_per_move = 2 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "kicks" + attack_verb_simple = "kick" health = 10 maxHealth = 10 ventcrawler = VENTCRAWLER_ALWAYS @@ -430,6 +456,8 @@ mob_size = MOB_SIZE_TINY gold_core_spawnable = FRIENDLY_SPAWN + footstep_type = FOOTSTEP_MOB_CLAW + /mob/living/simple_animal/babyKiwi/Initialize() . = ..() pixel_x = rand(-6, 6) diff --git a/code/modules/mob/living/simple_animal/friendly/fox.dm b/code/modules/mob/living/simple_animal/friendly/fox.dm index 95b082b733..4e4fd7ccfc 100644 --- a/code/modules/mob/living/simple_animal/friendly/fox.dm +++ b/code/modules/mob/living/simple_animal/friendly/fox.dm @@ -14,11 +14,14 @@ turns_per_move = 5 see_in_dark = 6 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" gold_core_spawnable = FRIENDLY_SPAWN - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW /mob/living/simple_animal/pet/fox/ComponentInitialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/friendly/gondola.dm b/code/modules/mob/living/simple_animal/friendly/gondola.dm index 04d53e7d05..0cfea3548b 100644 --- a/code/modules/mob/living/simple_animal/friendly/gondola.dm +++ b/code/modules/mob/living/simple_animal/friendly/gondola.dm @@ -9,9 +9,12 @@ name = "gondola" real_name = "gondola" desc = "Gondola is the silent walker. Having no hands he embodies the Taoist principle of wu-wei (non-action) while his smiling facial expression shows his utter and complete acceptance of the world as it is. Its hide is extremely valuable." - response_help = "pets" - response_disarm = "bops" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "bops" + response_disarm_simple = "bop" + response_harm_continuous = "kicks" + response_harm_simple = "kick" faction = list("gondola") turns_per_move = 10 icon = 'icons/mob/gondolas.dmi' diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm index 9ae46f29e5..b9ff99b677 100644 --- a/code/modules/mob/living/simple_animal/friendly/lizard.dm +++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm @@ -8,12 +8,16 @@ health = 5 maxHealth = 5 faction = list("Lizard") - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" melee_damage_lower = 1 melee_damage_upper = 2 - response_help = "pets" - response_disarm = "shoos" - response_harm = "stomps on" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "shoos" + response_disarm_simple = "shoo" + response_harm_continuous = "stomps on" + response_harm_simple = "stomp on" ventcrawler = VENTCRAWLER_ALWAYS density = FALSE pass_flags = PASSTABLE | PASSMOB diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 7f83bb9f9b..50d1e44d2a 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -15,9 +15,12 @@ maxHealth = 5 health = 5 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "splats" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "splats" + response_harm_simple = "splat" density = FALSE ventcrawler = VENTCRAWLER_ALWAYS pass_flags = PASSTABLE | PASSGRILLE | PASSMOB @@ -103,9 +106,6 @@ GLOBAL_VAR(tom_existed) /mob/living/simple_animal/mouse/brown/Tom name = "Tom" desc = "Jerry the cat is not amused." - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "splats" gold_core_spawnable = NO_SPAWN /mob/living/simple_animal/mouse/brown/Tom/Initialize() diff --git a/code/modules/mob/living/simple_animal/friendly/panda.dm b/code/modules/mob/living/simple_animal/friendly/panda.dm index a7b6143ef5..7e523fea83 100644 --- a/code/modules/mob/living/simple_animal/friendly/panda.dm +++ b/code/modules/mob/living/simple_animal/friendly/panda.dm @@ -13,8 +13,11 @@ turns_per_move = 5 see_in_dark = 6 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" gold_core_spawnable = FRIENDLY_SPAWN - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW diff --git a/code/modules/mob/living/simple_animal/friendly/penguin.dm b/code/modules/mob/living/simple_animal/friendly/penguin.dm index 9835840dbf..f92f4184b7 100644 --- a/code/modules/mob/living/simple_animal/friendly/penguin.dm +++ b/code/modules/mob/living/simple_animal/friendly/penguin.dm @@ -1,9 +1,12 @@ //Penguins /mob/living/simple_animal/pet/penguin - response_help = "pets" - response_disarm = "bops" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "bops" + response_disarm_simple = "bop" + response_harm_continuous = "kicks" + response_harm_simple = "kick" speak = list("Gah Gah!", "NOOT NOOT!", "NOOT!", "Noot", "noot", "Prah!", "Grah!") speak_emote = list("squawks", "gakkers") emote_hear = list("squawk!", "gakkers!", "noots.","NOOTS!") @@ -15,7 +18,7 @@ turns_per_move = 10 icon = 'icons/mob/penguins.dmi' - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_BAREFOOT /mob/living/simple_animal/pet/penguin/emperor name = "Emperor penguin" diff --git a/code/modules/mob/living/simple_animal/friendly/sloth.dm b/code/modules/mob/living/simple_animal/friendly/sloth.dm index 28063d6e52..83fe42a7a4 100644 --- a/code/modules/mob/living/simple_animal/friendly/sloth.dm +++ b/code/modules/mob/living/simple_animal/friendly/sloth.dm @@ -11,9 +11,12 @@ speak_chance = 1 turns_per_move = 5 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" mob_biotypes = MOB_ORGANIC|MOB_BEAST gold_core_spawnable = FRIENDLY_SPAWN melee_damage_lower = 18 @@ -22,7 +25,7 @@ maxHealth = 50 speed = 10 glide_size = 2 - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW /mob/living/simple_animal/pet/fox/ComponentInitialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/friendly/snake.dm b/code/modules/mob/living/simple_animal/friendly/snake.dm index 7f75888649..4d20b927a6 100644 --- a/code/modules/mob/living/simple_animal/friendly/snake.dm +++ b/code/modules/mob/living/simple_animal/friendly/snake.dm @@ -19,12 +19,16 @@ speak_emote = list("hisses") health = 20 maxHealth = 20 - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" melee_damage_lower = 5 melee_damage_upper = 6 - response_help = "pets" - response_disarm = "shoos" - response_harm = "steps on" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "shoos" + response_disarm_simple = "shoo" + response_harm_continuous = "steps on" + response_harm_simple = "step on" faction = list("hostile") ventcrawler = VENTCRAWLER_ALWAYS density = FALSE diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index d2794a3a78..9d94992747 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -13,9 +13,12 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians gender = NEUTER mob_biotypes = NONE bubble_icon = "guardian" - response_help = "passes through" - response_disarm = "flails at" - response_harm = "punches" + response_help_continuous = "passes through" + response_help_simple = "pass through" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "punches" + response_harm_simple = "punch" icon = 'icons/mob/guardian.dmi' icon_state = "magicbase" icon_living = "magicbase" @@ -29,7 +32,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 maxbodytemp = INFINITY - attacktext = "punches" + attack_verb_continuous = "punches" + attack_verb_simple = "punch" maxHealth = INFINITY //The spirit itself is invincible health = INFINITY healable = FALSE //don't brusepack the guardian @@ -109,7 +113,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians icon_dead = "holocarp" speak_emote = list("gnashes") desc = "A mysterious fish that stands by its charge, ever vigilant." - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" attack_sound = 'sound/weapons/bite.ogg' recolorentiresprite = TRUE if(!recolorentiresprite) //we want this to proc before stand logs in, so the overlay isnt gone for some reason diff --git a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm index e507a4c831..e82d6cd16a 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm @@ -1,6 +1,7 @@ //Assassin /mob/living/simple_animal/hostile/guardian/assassin - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/weapons/bladeslice.ogg' damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) playstyle_string = "As an assassin type you do medium damage and have no damage resistance, but can enter stealth, massively increasing the damage of your next attack and causing it to ignore armor. Stealth is broken when you attack or take damage." 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 718bfd71af..97003a53e2 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/fire.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/fire.dm @@ -4,7 +4,8 @@ melee_damage_lower = 10 melee_damage_upper = 10 attack_sound = 'sound/items/welder.ogg' - attacktext = "ignites" + attack_verb_continuous = "ignites" + attack_verb_simple = "ignite" melee_damage_type = BURN damage_coeff = list(BRUTE = 0.7, BURN = 0.1, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7) playstyle_string = "As a chaos type, you take 30% damage reduction to all but burn, which you are almost immune to. You will ignite any enemy you bump into. in addition, your melee attacks will cause human targets to see everyone as you." diff --git a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm index 7b7651822a..a1552f6648 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm @@ -6,7 +6,8 @@ /mob/living/simple_animal/hostile/guardian/beam melee_damage_lower = 10 melee_damage_upper = 10 - attacktext = "shocks" + attack_verb_continuous = "shocks" + attack_verb_simple = "shock" melee_damage_type = BURN attack_sound = 'sound/machines/defib_zap.ogg' damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7) diff --git a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm index 539ee9081b..1746936ba3 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm @@ -8,7 +8,8 @@ /mob/living/simple_animal/hostile/guardian/ranged a_intent = INTENT_HELP - friendly = "quietly assesses" + friendly_verb_continuous = "quietly assesses" + friendly_verb_simple = "quietly assess" melee_damage_lower = 10 melee_damage_upper = 10 damage_coeff = list(BRUTE = 0.9, BURN = 0.9, TOX = 0.9, CLONE = 0.9, STAMINA = 0, OXY = 0.9) diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm index 7b519e1ca1..21460b5c6b 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/support.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm @@ -1,7 +1,8 @@ //Healer /mob/living/simple_animal/hostile/guardian/healer a_intent = INTENT_HARM - friendly = "heals" + friendly_verb_continuous = "heals" + friendly_verb_simple = "heal" damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7) playstyle_string = "As a support type, you have 30% damage reduction and may toggle your basic attacks to a healing mode. In addition, Alt-Clicking on an adjacent object or mob will warp them to your bluespace beacon after a short delay." magic_fluff_string = "..And draw the CMO, a potent force of life... and death." diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm index 8aec10ec48..7120ab6d0a 100644 --- a/code/modules/mob/living/simple_animal/hostile/alien.dm +++ b/code/modules/mob/living/simple_animal/hostile/alien.dm @@ -8,9 +8,12 @@ icon_gib = "syndicate_gib" gender = FEMALE threat = 1 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" + response_help_continuous = "pokes" + response_help_simple = "poke" + response_disarm_continuous = "shoves" + response_disarm_simple = "shove" + response_harm_continuous = "hits" + response_harm_simple = "hit" speed = 0 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno = 4, /obj/item/stack/sheet/animalhide/xeno = 1) @@ -20,7 +23,8 @@ obj_damage = 60 melee_damage_lower = 25 melee_damage_upper = 25 - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" speak_emote = list("hisses") bubble_icon = "alien" a_intent = INTENT_HARM @@ -37,7 +41,9 @@ death_sound = 'sound/voice/hiss6.ogg' deathmessage = "lets out a waning guttural screech, green blood bubbling from its maw..." - do_footstep = TRUE +/mob/living/simple_animal/hostile/alien/Initialize() + . = ..() + AddComponent(/datum/component/footstep, FOOTSTEP_MOB_CLAW) /mob/living/simple_animal/hostile/alien/drone name = "alien drone" @@ -163,7 +169,8 @@ melee_damage_upper = 0 threat = -1 a_intent = INTENT_HELP - friendly = "caresses" + friendly_verb_continuous = "caresses" + friendly_verb_simple = "caress" obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE gold_core_spawnable = HOSTILE_SPAWN diff --git a/code/modules/mob/living/simple_animal/hostile/banana_spider.dm b/code/modules/mob/living/simple_animal/hostile/banana_spider.dm index f3ce343bfd..259c0bc721 100644 --- a/code/modules/mob/living/simple_animal/hostile/banana_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/banana_spider.dm @@ -13,14 +13,16 @@ maxbodytemp = INFINITY pass_flags = PASSTABLE | PASSGRILLE | PASSMOB mob_size = MOB_SIZE_TINY - response_help = "pokes" - response_disarm = "shoos" - response_harm = "splats" + response_help_continuous = "pokes" + response_help_simple = "poke" + response_disarm_continuous = "shoos" + response_disarm_simple = "shoo" + response_harm_continuous = "splats" + response_harm_simple = "plat" speak_emote = list("chitters") mouse_opacity = 2 density = TRUE ventcrawler = VENTCRAWLER_ALWAYS - gold_core_spawnable = FRIENDLY_SPAWN verb_say = "chitters" verb_ask = "chitters inquisitively" verb_exclaim = "chitters loudly" diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index a77098cb80..0e864a1e37 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -17,9 +17,12 @@ turns_per_move = 5 see_in_dark = 6 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/bear = 5, /obj/item/clothing/head/bearpelt = 1) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "hits" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" maxHealth = 60 health = 60 spacewalk = TRUE @@ -28,9 +31,11 @@ obj_damage = 60 melee_damage_lower = 20 melee_damage_upper = 30 - attacktext = "claws" + attack_verb_continuous = "claws" + attack_verb_simple = "claw" attack_sound = 'sound/weapons/bladeslice.ogg' - friendly = "bear hugs" + friendly_verb_continuous = "bear hugs" + friendly_verb_simple = "bear hug" //Space bears aren't affected by cold. atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) @@ -40,7 +45,7 @@ faction = list("russian") gold_core_spawnable = HOSTILE_SPAWN - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW //SPACE BEARS! SQUEEEEEEEE~ OW! FUCK! IT BIT MY HAND OFF!! /mob/living/simple_animal/hostile/bear/Hudson @@ -111,12 +116,14 @@ mob/living/simple_animal/hostile/bear/butter //The mighty companion to Cak. Seve melee_damage_lower = 1 melee_damage_upper = 1 armour_penetration = 0 - response_harm = "takes a bite out of" + response_harm_continuous = "takes a bite out of" + response_harm_simple = "take a bite out of" attacked_sound = 'sound/items/eatfood.ogg' deathmessage = "loses its false life and collapses!" butcher_results = list(/obj/item/reagent_containers/food/snacks/butter = 6, /obj/item/reagent_containers/food/snacks/meat/slab = 3, /obj/item/organ/brain = 1, /obj/item/organ/heart = 1) attack_sound = 'sound/weapons/slap.ogg' - attacktext = "slaps" + attack_verb_continuous = "slaps" + attack_verb_simple = "slap" /mob/living/simple_animal/hostile/bear/butter/Life() //Heals butter bear really fast when he takes damage. if(stat) diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm index f5454933c8..5f3d4f11c1 100644 --- a/code/modules/mob/living/simple_animal/hostile/bees.dm +++ b/code/modules/mob/living/simple_animal/hostile/bees.dm @@ -23,10 +23,14 @@ turns_per_move = 0 melee_damage_lower = 1 melee_damage_upper = 1 - attacktext = "stings" - response_help = "shoos" - response_disarm = "swats away" - response_harm = "squashes" + attack_verb_continuous = "stings" + attack_verb_simple = "sting" + response_help_continuous = "shoos" + response_help_simple = "shoo" + response_disarm_continuous = "swats away" + response_disarm_simple = "swat away" + response_harm_continuous = "squashes" + response_harm_simple = "squash" maxHealth = 10 health = 10 spacewalk = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm b/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm index 07572fff83..aef3fb714d 100644 --- a/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm +++ b/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm @@ -23,7 +23,7 @@ attack_sound = 'sound/hallucinations/growl1.ogg' var/list/copies = list() - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE //Summon Ability diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm index ced56f0705..a56a8dcc29 100644 --- a/code/modules/mob/living/simple_animal/hostile/carp.dm +++ b/code/modules/mob/living/simple_animal/hostile/carp.dm @@ -12,9 +12,10 @@ speak_chance = 0 turns_per_move = 5 butcher_results = list(/obj/item/reagent_containers/food/snacks/carpmeat = 2) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "hits" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" emote_taunt = list("gnashes") taunt_chance = 30 speed = 0 @@ -25,7 +26,8 @@ obj_damage = 50 melee_damage_lower = 15 melee_damage_upper = 15 - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" attack_sound = 'sound/weapons/bite.ogg' speak_emote = list("gnashes") //Space carp aren't affected by cold. diff --git a/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm b/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm index 4e3375caf7..d85f75cbbd 100644 --- a/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm +++ b/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm @@ -8,9 +8,6 @@ icon_gib = "syndicate_gib" speak_chance = 0 turns_per_move = 5 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" speed = 0 stat_attack = UNCONSCIOUS robust_searching = 1 @@ -19,7 +16,8 @@ harm_intent_damage = 5 melee_damage_lower = 15 melee_damage_upper = 15 - attacktext = "slashes at" + attack_verb_continuous = "slashes at" + attack_verb_simple = "slash at" attack_sound = 'sound/weapons/circsawhit.ogg' a_intent = INTENT_HARM mob_biotypes = MOB_ORGANIC|MOB_HUMANOID diff --git a/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm b/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm index 6ca6eac0cc..48266e3e76 100644 --- a/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm +++ b/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm @@ -17,7 +17,8 @@ obj_damage = 20 melee_damage_lower = 5 melee_damage_upper = 5 - attacktext = "staves" + attack_verb_continuous = "staves" + attack_verb_simple = "stave" a_intent = INTENT_HARM speak_emote = list("chants") attack_sound = 'sound/weapons/bladeslice.ogg' @@ -25,7 +26,7 @@ turns_per_move = 5 gold_core_spawnable = HOSTILE_SPAWN faction = list(ROLE_WIZARD) - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE weather_immunities = list("lava","ash") minbodytemp = 0 maxbodytemp = INFINITY diff --git a/code/modules/mob/living/simple_animal/hostile/eyeballs.dm b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm index 19d4dad6e8..75e8c55236 100644 --- a/code/modules/mob/living/simple_animal/hostile/eyeballs.dm +++ b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm @@ -8,9 +8,10 @@ icon_gib = "" gender = NEUTER mob_biotypes = MOB_ORGANIC - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "hits" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" emote_taunt = list("glares") taunt_chance = 25 maxHealth = 45 @@ -21,7 +22,8 @@ obj_damage = 60 melee_damage_lower = 20 melee_damage_upper = 25 - attacktext = "blinks at" + attack_verb_continuous = "blinks at" + attack_verb_simple = "blink at" attack_sound = 'sound/weapons/pierce.ogg' movement_type = FLYING diff --git a/code/modules/mob/living/simple_animal/hostile/faithless.dm b/code/modules/mob/living/simple_animal/hostile/faithless.dm index 7ac0ea2b44..4f8d2fef6c 100644 --- a/code/modules/mob/living/simple_animal/hostile/faithless.dm +++ b/code/modules/mob/living/simple_animal/hostile/faithless.dm @@ -9,9 +9,12 @@ gender = MALE speak_chance = 0 turns_per_move = 5 - response_help = "passes through" - response_disarm = "shoves" - response_harm = "hits" + response_help_continuous = "passes through" + response_help_simple = "pass through" + response_disarm_continuous = "shoves" + response_disarm_simple = "shove" + response_harm_continuous = "hits" + response_harm_simple = "hit" emote_taunt = list("wails") taunt_chance = 25 speed = 0 @@ -26,7 +29,8 @@ obj_damage = 50 melee_damage_lower = 15 melee_damage_upper = 15 - attacktext = "grips" + attack_verb_continuous = "grips" + attack_verb_simple = "grip" attack_sound = 'sound/hallucinations/growl1.ogg' speak_emote = list("growls") @@ -36,7 +40,7 @@ faction = list("faithless") gold_core_spawnable = HOSTILE_SPAWN - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE /mob/living/simple_animal/hostile/faithless/AttackingTarget() . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index b556cce8fe..a253ecfd96 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -30,9 +30,12 @@ turns_per_move = 5 see_in_dark = 10 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/spider = 2, /obj/item/reagent_containers/food/snacks/spiderleg = 8) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "hits" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" maxHealth = 200 health = 200 obj_damage = 60 @@ -43,19 +46,19 @@ pass_flags = PASSTABLE move_to_delay = 6 ventcrawler = VENTCRAWLER_ALWAYS - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" attack_sound = 'sound/weapons/bite.ogg' unique_name = 1 gold_core_spawnable = HOSTILE_SPAWN see_in_dark = 4 lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE + footstep_type = FOOTSTEP_MOB_CLAW has_field_of_vision = FALSE // 360° vision. var/playable_spider = FALSE var/datum/action/innate/spider/lay_web/lay_web var/directive = "" //Message passed down to children, to relay the creator's orders - do_footstep = TRUE - /mob/living/simple_animal/hostile/poison/giant_spider/Initialize() . = ..() lay_web = new diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm index db232c20c4..1dcb13aa9b 100644 --- a/code/modules/mob/living/simple_animal/hostile/goose.dm +++ b/code/modules/mob/living/simple_animal/hostile/goose.dm @@ -10,9 +10,12 @@ speak_chance = 0 turns_per_move = 5 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" emote_taunt = list("hisses") taunt_chance = 30 speed = 0 @@ -21,7 +24,8 @@ harm_intent_damage = 5 melee_damage_lower = 5 melee_damage_upper = 5 - attacktext = "pecks" + attack_verb_continuous = "pecks" + attack_verb_simple = "peck" attack_sound = "goose" speak_emote = list("honks") faction = list("neutral") diff --git a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm index 7c6f9e9c7b..f48eef083b 100644 --- a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm +++ b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm @@ -16,16 +16,20 @@ health = 220 loot = list(/obj/effect/gibspawner/generic) butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/gorilla = 4) - response_help = "prods" - response_disarm = "challenges" - response_harm = "thumps" + response_help_continuous = "prods" + response_help_simple = "prod" + response_disarm_continuous = "challenges" + response_disarm_simple = "challenge" + response_harm_continuous = "thumps" + response_harm_simple = "thump" speed = 1 melee_damage_lower = 15 melee_damage_upper = 18 damage_coeff = list(BRUTE = 1, BURN = 1.5, TOX = 1.5, CLONE = 0, STAMINA = 0, OXY = 1.5) obj_damage = 20 environment_smash = ENVIRONMENT_SMASH_WALLS - attacktext = "pummels" + attack_verb_continuous = "pummels" + attack_verb_simple = "pummel" attack_sound = 'sound/weapons/punch1.ogg' dextrous = TRUE held_items = list(null, null) @@ -39,7 +43,7 @@ var/list/gorilla_overlays[GORILLA_TOTAL_LAYERS] var/oogas = 0 - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_BAREFOOT // Gorillas like to dismember limbs from unconcious mobs. // Returns null when the target is not an unconcious carbon mob; a list of limbs (possibly empty) otherwise. diff --git a/code/modules/mob/living/simple_animal/hostile/headcrab.dm b/code/modules/mob/living/simple_animal/hostile/headcrab.dm index 9d64b76198..501534237a 100644 --- a/code/modules/mob/living/simple_animal/hostile/headcrab.dm +++ b/code/modules/mob/living/simple_animal/hostile/headcrab.dm @@ -12,7 +12,8 @@ maxHealth = 50 melee_damage_lower = 5 melee_damage_upper = 5 - attacktext = "chomps" + attack_verb_continuous = "chomps" + attack_verb_simple = "chomp" attack_sound = 'sound/weapons/bite.ogg' faction = list("creature") robust_searching = 1 diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm index 1cc675825f..b627bf67c2 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm @@ -16,7 +16,8 @@ healable = 0 melee_damage_lower = 10 melee_damage_upper = 10 - attacktext = "saw" + attack_verb_continuous = "saw" + attack_verb_simple = "saw" attack_sound = 'sound/weapons/bladeslice.ogg' projectilesound = 'sound/weapons/gunshot.ogg' projectiletype = /obj/item/projectile/hivebotbullet @@ -30,7 +31,7 @@ loot = list(/obj/effect/decal/cleanable/robot_debris) blood_volume = 0 - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW /mob/living/simple_animal/hostile/hivebot/Initialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/illusion.dm b/code/modules/mob/living/simple_animal/hostile/illusion.dm index 6936a18cb9..cab87010ef 100644 --- a/code/modules/mob/living/simple_animal/hostile/illusion.dm +++ b/code/modules/mob/living/simple_animal/hostile/illusion.dm @@ -10,7 +10,8 @@ melee_damage_lower = 5 melee_damage_upper = 5 a_intent = INTENT_HARM - attacktext = "gores" + attack_verb_continuous = "gores" + attack_verb_simple = "gore" maxHealth = 100 health = 100 speed = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm b/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm index c337344c90..c2b553aad7 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm @@ -7,9 +7,8 @@ environment_smash = ENVIRONMENT_SMASH_WALLS minbodytemp = 0 maxbodytemp = 450 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "strikes" + response_harm_continuous = "strikes" + response_harm_simple = "strike" status_flags = NONE a_intent = INTENT_HARM see_in_dark = 4 diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm index 05c4007b6f..574811c968 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm @@ -27,7 +27,7 @@ var/hop_cooldown = 0 //Strictly for player controlled leapers var/projectile_ready = FALSE //Stopping AI leapers from firing whenever they want, and only doing it after a hop has finished instead - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_HEAVY /obj/item/projectile/leaper name = "leaper bubble" diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm index ae161d596d..40274c0029 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm @@ -25,7 +25,7 @@ projectilesound = 'sound/weapons/pierce.ogg' alpha = 50 - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_CLAW /mob/living/simple_animal/hostile/jungle/mega_arachnid/Life() ..() diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm index c05d14965e..6efa0cf468 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm @@ -32,7 +32,7 @@ var/attack_state = MOOK_ATTACK_NEUTRAL var/struck_target_leap = FALSE - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_BAREFOOT /mob/living/simple_animal/hostile/jungle/mook/CanPass(atom/movable/O) if(istype(O, /mob/living/simple_animal/hostile/jungle/mook)) diff --git a/code/modules/mob/living/simple_animal/hostile/killertomato.dm b/code/modules/mob/living/simple_animal/hostile/killertomato.dm index e418cc4ab0..9cb65d7c30 100644 --- a/code/modules/mob/living/simple_animal/hostile/killertomato.dm +++ b/code/modules/mob/living/simple_animal/hostile/killertomato.dm @@ -12,12 +12,16 @@ health = 30 see_in_dark = 3 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/killertomato = 2) - response_help = "prods" - response_disarm = "pushes aside" - response_harm = "smacks" + response_help_continuous = "prods" + response_help_simple = "prod" + response_disarm_continuous = "pushes aside" + response_disarm_simple = "push aside" + response_harm_continuous = "smacks" + response_harm_simple = "smack" melee_damage_lower = 8 melee_damage_upper = 12 - attacktext = "slams" + attack_verb_continuous = "slams" + attack_verb_simple = "slam" attack_sound = 'sound/weapons/punch1.ogg' ventcrawler = VENTCRAWLER_ALWAYS faction = list("plants") diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm index fd278eb438..8c358fd625 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm @@ -54,7 +54,7 @@ Difficulty: Medium deathmessage = "falls to the ground, decaying into glowing particles." death_sound = "bodyfall" - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_HEAVY /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance guidance = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index 1e63767649..fe6c2290c4 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -29,12 +29,14 @@ Difficulty: Hard threat = 35 health = 2500 maxHealth = 2500 - attacktext = "rends" + attack_verb_continuous = "rends" + attack_verb_simple = "rend" attack_sound = 'sound/magic/demon_attack1.ogg' icon_state = "bubblegum" icon_living = "bubblegum" icon_dead = "" - friendly = "stares down" + friendly_verb_continuous = "stares down" + friendly_verb_simple = "stare down" icon = 'icons/mob/lavaland/96x96megafauna.dmi' speak_emote = list("gurgles") armour_penetration = 40 @@ -55,7 +57,7 @@ Difficulty: Hard deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... " death_sound = 'sound/magic/enter_blood.ogg' - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_HEAVY /obj/item/gps/internal/bubblegum icon_state = null @@ -227,7 +229,8 @@ Difficulty: Hard icon_state = "bloodbrood" icon_living = "bloodbrood" icon_aggro = "bloodbrood" - attacktext = "pierces" + attack_verb_continuous = "pierces" + attack_verb_simple = "pierce" color = "#C80000" density = FALSE faction = list("mining", "boss") 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 73fb9d4e48..be3552822f 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -27,12 +27,14 @@ Difficulty: Very Hard threat = 40 health = 2500 maxHealth = 2500 - attacktext = "judges" + attack_verb_continuous = "judges" + attack_verb_simple = "judge" attack_sound = 'sound/magic/clockwork/ratvar_attack.ogg' icon_state = "eva" icon_living = "eva" icon_dead = "dragon_dead" - friendly = "stares down" + friendly_verb_continuous = "stares down" + friendly_verb_simple = "stare down" icon = 'icons/mob/lavaland/96x96megafauna.dmi' speak_emote = list("roars") armour_penetration = 40 @@ -606,14 +608,18 @@ Difficulty: Very Hard icon_dead = "butterfly_dead" threat = -0.7 turns_per_move = 1 - response_help = "waves away" - response_disarm = "brushes aside" - response_harm = "disrupts" + response_help_continuous = "waves away" + response_help_simple = "wave away" + response_disarm_continuous = "brushes aside" + response_disarm_simple = "brush aside" + response_harm_continuous = "disrupts" + response_harm_simple = "disrupt" speak_emote = list("oscillates") maxHealth = 2 health = 2 harm_intent_damage = 1 - friendly = "mends" + friendly_verb_continuous = "mends" + friendly_verb_simple = "mend" density = FALSE movement_type = FLYING pass_flags = PASSTABLE | PASSGRILLE | PASSMOB diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm index 3d106021de..88e33ed91a 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm @@ -10,7 +10,8 @@ Difficulty: Extremely Hard icon_state = "demonic_miner" icon_living = "demonic_miner" icon = 'icons/mob/icemoon/icemoon_monsters.dmi' - attacktext = "pummels" + attack_verb_continuous = "pummels" + attack_verb_simple = "pummel" attack_sound = 'sound/weapons/sonic_jackhammer.ogg' mob_biotypes = MOB_ORGANIC|MOB_HUMANOID light_color = "#E4C7C5" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index c59272214b..062a4c9a43 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -37,13 +37,15 @@ Difficulty: Medium health = 2500 maxHealth = 2500 spacewalk = TRUE - attacktext = "chomps" + attack_verb_continuous = "chomps" + attack_verb_simple = "chomp" attack_sound = 'sound/magic/demon_attack1.ogg' icon = 'icons/mob/lavaland/64x64megafauna.dmi' icon_state = "dragon" icon_living = "dragon" icon_dead = "dragon_dead" - friendly = "stares down" + friendly_verb_continuous = "stares down" + friendly_verb_simple = "stare down" speak_emote = list("roars") armour_penetration = 40 melee_damage_lower = 40 @@ -64,7 +66,7 @@ Difficulty: Medium death_sound = 'sound/magic/demon_dies.ogg' var/datum/action/small_sprite/smallsprite = new/datum/action/small_sprite/drake() - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_HEAVY /mob/living/simple_animal/hostile/megafauna/dragon/Initialize() smallsprite.Grant(src) @@ -81,7 +83,7 @@ Difficulty: Medium return FALSE return ..() -/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs) +/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message) if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit return return ..() 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 477c2ce3aa..4ade831f95 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -40,11 +40,13 @@ Difficulty: Normal threat = 30 health = 2500 maxHealth = 2500 - attacktext = "clubs" + attack_verb_continuous = "clubs" + attack_verb_simple = "club" attack_sound = 'sound/weapons/sonic_jackhammer.ogg' icon_state = "hierophant" icon_living = "hierophant" - friendly = "stares down" + friendly_verb_continuous = "stares down" + friendly_verb_simple = "stare down" icon = 'icons/mob/lavaland/hierophant_new.dmi' faction = list("boss") //asteroid mobs? get that shit out of my beautiful square house speak_emote = list("preaches") diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm index 62a09dff65..4da8a90b23 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm @@ -26,7 +26,8 @@ Difficulty: Medium icon_living = "legion" desc = "One of many." icon = 'icons/mob/lavaland/legion.dmi' - attacktext = "chomps" + attack_verb_continuous = "chomps" + attack_verb_simple = "chomp" attack_sound = 'sound/magic/demon_attack1.ogg' speak_emote = list("echoes") armour_penetration = 50 diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm index 5ed163ae7e..ed189f052d 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm @@ -11,7 +11,8 @@ Difficulty: Hard icon_living = "wendigo" icon_dead = "wendigo_dead" icon = 'icons/mob/icemoon/64x64megafauna.dmi' - attacktext = "claws" + attack_verb_continuous = "claws" + attack_verb_simple = "claw" attack_sound = 'sound/magic/demon_attack1.ogg' weather_immunities = list("snow") speak_emote = list("roars") diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm index 138d7f155e..5afe109550 100644 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -5,9 +5,12 @@ icon_state = "crate" icon_living = "crate" - response_help = "touches" - response_disarm = "pushes" - response_harm = "hits" + response_help_continuous = "touches" + response_help_simple = "touch" + response_disarm_continuous = "pushes" + response_disarm_simple = "push" + response_harm_continuous = "hits" + response_harm_simple = "hit" speed = 0 maxHealth = 250 health = 250 @@ -18,7 +21,8 @@ harm_intent_damage = 5 melee_damage_lower = 8 melee_damage_upper = 12 - attacktext = "attacks" + attack_verb_continuous = "attacks" + attack_verb_simple = "attack" attack_sound = 'sound/weapons/punch1.ogg' emote_taunt = list("growls") speak_emote = list("creaks") @@ -34,7 +38,8 @@ // Aggro when you try to open them. Will also pickup loot when spawns and drop it when dies. /mob/living/simple_animal/hostile/mimic/crate - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" speak_emote = list("clatters") stop_automated_movement = 1 wander = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm index 2810bf6c17..b69a4b69cf 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm @@ -25,7 +25,8 @@ obj_damage = 60 melee_damage_lower = 12 melee_damage_upper = 12 - attacktext = "bites into" + attack_verb_continuous = "bites into" + attack_verb_simple = "bite into" a_intent = INTENT_HARM speak_emote = list("chitters") attack_sound = 'sound/weapons/bladeslice.ogg' @@ -72,7 +73,8 @@ throw_message = "bounces harmlessly off of" melee_damage_lower = 15 melee_damage_upper = 15 - attacktext = "impales" + attack_verb_continuous = "impales" + attack_verb_simple = "impale" a_intent = INTENT_HARM speak_emote = list("telepathically cries") attack_sound = 'sound/weapons/bladeslice.ogg' diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm index 652840f7e3..116082d571 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm @@ -16,7 +16,8 @@ melee_damage_lower = 10 melee_damage_upper = 10 melee_damage_type = BURN - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/effects/curseattack.ogg' throw_message = "passes through the smokey body of" obj_damage = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm index 68a0e81cc7..e662f4e525 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm @@ -31,9 +31,8 @@ melee_damage_lower = 30 melee_damage_upper = 30 armour_penetration = 30 - attacktext = "beats down on" - /*attack_verb_continuous = "beats down on" - attack_verb_simple = "beat down on"*/ + attack_verb_continuous = "beats down on" + attack_verb_simple = "beat down on" attack_sound = 'sound/weapons/punch1.ogg' throw_message = "does nothing to the rocky hide of the" speed = 2 @@ -172,9 +171,8 @@ health = 30 melee_damage_lower = 5 melee_damage_upper = 5 - attacktext = "bashes against" - /*attack_verb_continuous = "bashes against" - attack_verb_simple = "bash against"*/ + attack_verb_continuous = "bashes against" + attack_verb_simple = "bash against" attack_sound = 'sound/weapons/punch1.ogg' throw_message = "does nothing to the rocky hide of the" speed = 2 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm index 884e3bb989..106cb20efc 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm @@ -29,9 +29,8 @@ health = 800 melee_damage_lower = 20 melee_damage_upper = 20 - attacktext = "preaches to" - /*attack_verb_continuous = "preaches to" - attack_verb_simple = "preach to"*/ + attack_verb_continuous = "preaches to" + attack_verb_simple = "preach to" attack_sound = 'sound/magic/clockwork/ratvar_attack.ogg' throw_message = "doesn't affect the purity of" speed = 4 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm index c9011c5f5f..c2faa002bc 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm @@ -29,9 +29,8 @@ health = 800 melee_damage_lower = 30 melee_damage_upper = 30 - attacktext = "slashes its arms at" - /*attack_verb_continuous = "slashes its arms at" - attack_verb_simple = "slash your arms at"*/ + attack_verb_continuous = "slashes its arms at" + attack_verb_simple = "slash your arms at" attack_sound = 'sound/weapons/bladeslice.ogg' throw_message = "doesn't affect the sturdiness of" speed = 1 @@ -227,9 +226,8 @@ health = 80 melee_damage_lower = 10 melee_damage_upper = 10 - attacktext = "bites at" - /*attack_verb_continuous = "bites at" - attack_verb_simple = "bite at"*/ + attack_verb_continuous = "bites at" + attack_verb_simple = "bite at" attack_sound = 'sound/effects/curse1.ogg' throw_message = "simply misses" speed = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm index 3276965fa2..ebbf032859 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm @@ -29,9 +29,8 @@ health = 800 melee_damage_lower = 15 melee_damage_upper = 15 - attacktext = "smashes into the side of" - /*attack_verb_continuous = "smashes into the side of" - attack_verb_simple = "smash into the side of"*/ + attack_verb_continuous = "smashes into the side of" + attack_verb_simple = "smash into the side of" attack_sound = 'sound/weapons/sonic_jackhammer.ogg' throw_message = "merely dinks off of the" speed = 4 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm index c43e9a7461..4a3497055a 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm @@ -13,14 +13,16 @@ vision_range = 2 aggro_vision_range = 9 move_to_delay = 5 - friendly = "harmlessly rolls into" + friendly_verb_continuous = "harmlessly rolls into" + friendly_verb_simple = "harmlessly roll into" maxHealth = 45 health = 45 gold_core_spawnable = HOSTILE_SPAWN harm_intent_damage = 5 melee_damage_lower = 0 melee_damage_upper = 0 - attacktext = "barrels into" + attack_verb_continuous = "barrels into" + attack_verb_simple = "barrel into" attack_sound = 'sound/weapons/punch1.ogg' a_intent = INTENT_HELP speak_emote = list("screeches") diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm index 3c8cf9025f..a61f1924c8 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm @@ -14,7 +14,8 @@ move_to_delay = 10 ranged = 1 ranged_cooldown_time = 60 - friendly = "wails at" + friendly_verb_continuous = "wails at" + friendly_verb_simple = "wail at" speak_emote = list("bellows") speed = 3 maxHealth = 300 @@ -23,7 +24,8 @@ obj_damage = 100 melee_damage_lower = 18 melee_damage_upper = 18 - attacktext = "pulverizes" + attack_verb_continuous = "pulverizes" + attack_verb_simple = "pulverize" attack_sound = 'sound/weapons/punch1.ogg' throw_message = "does nothing to the rocky hide of the" vision_range = 4 @@ -35,7 +37,7 @@ var/pre_attack_icon = "Goliath_preattack" loot = list(/obj/item/stack/sheet/animalhide/goliath_hide) - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_HEAVY /mob/living/simple_animal/hostile/asteroid/goliath/Life() . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm index 39b66fbdc2..c9e650531c 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm @@ -18,10 +18,14 @@ obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE move_to_delay = 15 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "squishes" - friendly = "pinches" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "squishes" + response_harm_simple = "squish" + friendly_verb_continuous = "pinches" + friendly_verb_simple = "pinch" a_intent = INTENT_HELP ventcrawler = VENTCRAWLER_ALWAYS gold_core_spawnable = FRIENDLY_SPAWN diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index 822dafcb9f..079be02953 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -20,7 +20,8 @@ harm_intent_damage = 5 melee_damage_lower = 0 melee_damage_upper = 0 - attacktext = "lashes out at" + attack_verb_continuous = "lashes out at" + attack_verb_simple = "lash out at" speak_emote = list("telepathically cries") attack_sound = 'sound/weapons/pierce.ogg' throw_message = "falls right through the strange body of the" @@ -67,7 +68,8 @@ icon_gib = "syndicate_gib" mouse_opacity = MOUSE_OPACITY_OPAQUE move_to_delay = 1 - friendly = "buzzes near" + friendly_verb_continuous = "buzzes near" + friendly_verb_simple = "buzz near" vision_range = 10 speed = 3 maxHealth = 1 @@ -76,7 +78,8 @@ harm_intent_damage = 5 melee_damage_lower = 2 melee_damage_upper = 2 - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" speak_emote = list("telepathically cries") attack_sound = 'sound/weapons/pierce.ogg' throw_message = "falls right through the strange body of the" @@ -107,7 +110,8 @@ obj_damage = 60 melee_damage_lower = 15 melee_damage_upper = 15 - attacktext = "lashes out at" + attack_verb_continuous = "lashes out at" + attack_verb_simple = "lash out at" speak_emote = list("echoes") attack_sound = 'sound/weapons/pierce.ogg' throw_message = "bounces harmlessly off of" @@ -173,14 +177,16 @@ icon_aggro = "legion_head" icon_dead = "legion_head" icon_gib = "syndicate_gib" - friendly = "buzzes near" + friendly_verb_continuous = "buzzes near" + friendly_verb_simple = "buzz near" vision_range = 10 maxHealth = 1 health = 5 harm_intent_damage = 5 melee_damage_lower = 12 melee_damage_upper = 12 - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" speak_emote = list("echoes") attack_sound = 'sound/weapons/pierce.ogg' throw_message = "is shrugged off by" diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm index 88ee27fcc9..66241e3d75 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm @@ -23,7 +23,8 @@ obj_damage = 40 melee_damage_lower = 15 melee_damage_upper = 15 - attacktext = "slices" + attack_verb_continuous = "slices" + attack_verb_simple = "slice" attack_sound = 'sound/weapons/bladeslice.ogg' vision_range = 7 aggro_vision_range = 7 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm index c8d5cf4b73..b62fb4a665 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm @@ -7,7 +7,8 @@ icon_dead = "ice_whelp_dead" mob_biotypes = MOB_ORGANIC|MOB_BEAST mouse_opacity = MOUSE_OPACITY_ICON - friendly = "stares down" + friendly_verb_continuous = "stares down" + friendly_verb_simple = "stare down" speak_emote = list("roars") speed = 30 move_to_delay = 30 @@ -19,7 +20,8 @@ armour_penetration = 20 melee_damage_lower = 20 melee_damage_upper = 20 - attacktext = "chomps" + attack_verb_continuous = "chomps" + attack_verb_simple = "chomp" attack_sound = 'sound/magic/demon_attack1.ogg' vision_range = 9 aggro_vision_range = 9 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm index 6ad869afe6..c3e4f24c43 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm @@ -8,9 +8,8 @@ environment_smash = ENVIRONMENT_SMASH_WALLS minbodytemp = 0 maxbodytemp = INFINITY - response_help = "pokes" - response_disarm = "shoves" - response_harm = "strikes" + response_harm_continuous = "strikes" + response_harm_simple = "strike" status_flags = 0 a_intent = INTENT_HARM var/crusher_loot diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm index 0576d0ecfe..ac2ce37d3f 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm @@ -7,7 +7,8 @@ icon_dead = "polarbear_dead" mob_biotypes = MOB_ORGANIC|MOB_BEAST mouse_opacity = MOUSE_OPACITY_ICON - friendly = "growls at" + friendly_verb_continuous = "growls at" + friendly_verb_simple = "growl at" speak_emote = list("growls") speed = 12 move_to_delay = 12 @@ -16,7 +17,8 @@ obj_damage = 40 melee_damage_lower = 25 melee_damage_upper = 25 - attacktext = "claws" + attack_verb_continuous = "claws" + attack_verb_simple = "claw" attack_sound = 'sound/weapons/bladeslice.ogg' vision_range = 2 // don't aggro unless you basically antagonize it, though they will kill you worse than a goliath will aggro_vision_range = 9 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm index 9f17421691..013a75be75 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm @@ -7,7 +7,8 @@ icon_dead = "whitewolf_dead" mob_biotypes = MOB_ORGANIC|MOB_BEAST mouse_opacity = MOUSE_OPACITY_ICON - friendly = "howls at" + friendly_verb_continuous = "howls at" + friendly_verb_simple = "howl at" speak_emote = list("howls") speed = 5 move_to_delay = 5 @@ -19,7 +20,8 @@ rapid_melee = 2 // every second attack dodging = TRUE dodge_prob = 50 - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" attack_sound = 'sound/weapons/bite.ogg' vision_range = 7 aggro_vision_range = 7 diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm index d023cf0dd8..1b13200729 100644 --- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm +++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm @@ -9,15 +9,19 @@ maxHealth = 10 health = 10 butcher_results = list(/obj/item/reagent_containers/food/snacks/hugemushroomslice = 1) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "whacks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "whacks" + response_harm_simple = "whack" harm_intent_damage = 5 obj_damage = 0 melee_damage_lower = 1 melee_damage_upper = 1 attack_same = 2 - attacktext = "chomps" + attack_verb_continuous = "chomps" + attack_verb_simple = "chomp" attack_sound = 'sound/weapons/bite.ogg' faction = list("mushroom") environment_smash = ENVIRONMENT_SMASH_NONE diff --git a/code/modules/mob/living/simple_animal/hostile/nanotrasen.dm b/code/modules/mob/living/simple_animal/hostile/nanotrasen.dm index ed2a407b8e..8653c40cea 100644 --- a/code/modules/mob/living/simple_animal/hostile/nanotrasen.dm +++ b/code/modules/mob/living/simple_animal/hostile/nanotrasen.dm @@ -9,9 +9,6 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID speak_chance = 12 turns_per_move = 5 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" speed = 0 stat_attack = UNCONSCIOUS robust_searching = 1 @@ -20,7 +17,8 @@ harm_intent_damage = 5 melee_damage_lower = 10 melee_damage_upper = 15 - attacktext = "punches" + attack_verb_continuous = "punches" + attack_verb_simple = "punch" attack_sound = 'sound/weapons/punch1.ogg' a_intent = INTENT_HARM loot = list(/obj/effect/mob_spawn/human/corpse/nanotrasensoldier) @@ -31,7 +29,7 @@ speak = list("Stop resisting!", "I AM THE LAW!", "Face the wrath of the golden bolt!", "Stop breaking the law, asshole!") search_objects = 1 - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE /mob/living/simple_animal/hostile/nanotrasen/Aggro() diff --git a/code/modules/mob/living/simple_animal/hostile/netherworld.dm b/code/modules/mob/living/simple_animal/hostile/netherworld.dm index 1c8b171738..ca5d047326 100644 --- a/code/modules/mob/living/simple_animal/hostile/netherworld.dm +++ b/code/modules/mob/living/simple_animal/hostile/netherworld.dm @@ -11,7 +11,8 @@ melee_damage_lower = 25 melee_damage_upper = 50 threat = 2 - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/weapons/bladeslice.ogg' faction = list("creature") speak_emote = list("screams") @@ -27,7 +28,8 @@ icon_state = "mi-go" icon_living = "mi-go" icon_dead = "mi-go-dead" - attacktext = "lacerates" + attack_verb_continuous = "lacerates" + attack_verb_simple = "lacerate" speed = -0.5 var/static/list/migo_sounds deathmessage = "wails as its form turns into a pulpy mush." @@ -63,7 +65,8 @@ maxHealth = 100 melee_damage_lower = 5 melee_damage_upper = 10 - attacktext = "punches" + attack_verb_continuous = "punches" + attack_verb_simple = "punch" deathmessage = "falls apart into a fine dust." /obj/structure/spawner/nether diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm index d8737d1edc..0544ddc676 100644 --- a/code/modules/mob/living/simple_animal/hostile/pirate.dm +++ b/code/modules/mob/living/simple_animal/hostile/pirate.dm @@ -8,9 +8,8 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID speak_chance = 0 turns_per_move = 5 - response_help = "pushes" - response_disarm = "shoves" - response_harm = "hits" + response_help_continuous = "pushes" + response_help_simple = "push" threat = 3 speed = 0 maxHealth = 115 @@ -19,7 +18,8 @@ harm_intent_damage = 5 melee_damage_lower = 10 melee_damage_upper = 10 - attacktext = "punches" + attack_verb_continuous = "punches" + attack_verb_simple = "punch" attack_sound = 'sound/weapons/punch1.ogg' a_intent = INTENT_HARM atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) @@ -39,11 +39,12 @@ melee_damage_lower = 30 melee_damage_upper = 30 armour_penetration = 35 - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/weapons/blade1.ogg' var/obj/effect/light_emitter/red_energy_sword/sord - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE /mob/living/simple_animal/hostile/pirate/melee/space name = "Space Pirate Swashbuckler" diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm index cc17759cc6..9045ccef51 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm @@ -7,9 +7,12 @@ icon_gib = "bat_dead" turns_per_move = 1 blood_volume = 250 - response_help = "brushes aside" - response_disarm = "flails at" - response_harm = "hits" + response_help_continuous = "brushes aside" + response_help_simple = "brush aside" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "hits" + response_harm_simple = "hit" mob_biotypes = MOB_ORGANIC|MOB_BEAST speak_chance = 0 maxHealth = 15 @@ -19,7 +22,8 @@ harm_intent_damage = 6 melee_damage_lower = 6 melee_damage_upper = 5 - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1) pass_flags = PASSTABLE faction = list("hostile") @@ -47,5 +51,6 @@ icon_gib = "secbat_dead" desc = "A fruit bat with a tiny little security hat who is ready to inject cuteness into any security operation." emote_see = list("is ready to law down the law.", "flaps about with an air of authority.") - response_help = "respects the authority of" + response_help_continuous = "respects the authority of" + response_help_simple = "respect the authority of" gold_core_spawnable = FRIENDLY_SPAWN diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm index c94046329b..35f2817028 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm @@ -8,8 +8,10 @@ icon_gib = "clown_gib" mob_biotypes = MOB_ORGANIC|MOB_HUMANOID turns_per_move = 5 - response_disarm = "gently pushes aside" - response_harm = "robusts" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "robusts" + response_harm_simple = "robust" speak = list("HONK", "Honk!", "Welcome to clown planet!") emote_see = list("honks", "squeaks") speak_chance = 1 @@ -30,6 +32,7 @@ minbodytemp = 270 maxbodytemp = 370 unsuitable_atmos_damage = 10 + footstep_type = FOOTSTEP_MOB_SHOE var/banana_time = 0 // If there's no time set it won't spawn. var/banana_type = /obj/item/grown/bananapeel var/attack_reagent @@ -69,8 +72,10 @@ icon_state = "lube" icon_living = "lube" turns_per_move = 1 - response_help = "dips a finger into" - response_disarm = "gently scoops and pours aside" + response_help_continuous = "dips a finger into" + response_help_simple = "dip a finger into" + response_disarm_continuous = "gently scoops and pours aside" + response_disarm_simple = "gently scoop and pour aside" emote_see = list("bubbles", "oozes") loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/particle_effect/foam) @@ -83,8 +88,10 @@ desc = "A fusion of clown and banana DNA birthed from a botany experiment gone wrong." icon_state = "banana tree" icon_living = "banana tree" - response_disarm = "peels" - response_harm = "peels" + response_disarm_continuous = "peels" + response_disarm_simple = "peel" + response_harm_continuous = "peels" + response_harm_simple = "peel" turns_per_move = 1 speak = list("HONK", "Honk!", "YA-HONK!!!") emote_see = list("honks", "bites into the banana", "plucks a banana off its head", "photosynthesizes") @@ -104,7 +111,8 @@ harm_intent_damage = 1 melee_damage_lower = 1 melee_damage_upper = 1 - attacktext = "cheers up" + attack_verb_continuous = "cheers up" + attack_verb_simple = "cheer up" loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap, /obj/item/seeds/banana/bluespace) banana_type = /obj/item/grown/bananapeel attack_reagent = /datum/reagent/consumable/laughter @@ -114,9 +122,12 @@ desc = "A being forged out of the pure essence of pranking, cursed into existence by a cruel maker." icon_state = "fleshclown" icon_living = "fleshclown" - response_help = "reluctantly pokes" - response_disarm = "sinks his hands into the spongy flesh of" - response_harm = "cleanses the world of" + response_help_continuous = "reluctantly pokes" + response_help_simple = "reluctantly poke" + response_disarm_continuous = "sinks his hands into the spongy flesh of" + response_disarm_simple = "sink your hands into the spongy flesh of" + response_harm_continuous = "cleanses the world of" + response_harm_simple = "cleanse the world of" speak = list("HONK", "Honk!", "I didn't ask for this", "I feel constant and horrible pain", "YA-HONK!!!", "this body is a merciless and unforgiving prison", "I was born out of mirthful pranking but I live in suffering") emote_see = list("honks", "sweats", "jiggles", "contemplates its existence") speak_chance = 5 @@ -126,7 +137,8 @@ health = 140 speed = -5 melee_damage_upper = 15 - attacktext = "limply slaps" + attack_verb_continuous = "limply slaps" + attack_verb_simple = "limply slap" obj_damage = 5 loot = list(/obj/item/clothing/suit/hooded/bloated_human, /obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap) @@ -137,9 +149,12 @@ icon_living = "long face" move_resist = INFINITY turns_per_move = 10 - response_help = "tries to awkwardly hug" - response_disarm = "pushes the unwieldy frame of" - response_harm = "tries to shut up" + response_help_continuous = "tries to awkwardly hug" + response_help_simple = "try to awkwardly hug" + response_disarm_continuous = "pushes the unwieldy frame of" + response_disarm_simple = "push the unwieldy frame of" + response_harm_continuous = "tries to shut up" + response_harm_simple = "try to shut up" speak = list("YA-HONK!!!") emote_see = list("honks", "squeaks") speak_chance = 60 @@ -149,7 +164,8 @@ speed = 10 harm_intent_damage = 5 melee_damage_lower = 5 - attacktext = "YA-HONKs" + attack_verb_continuous = "YA-HONKs" + attack_verb_simple = "YA-HONK" loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap) /mob/living/simple_animal/hostile/retaliate/clown/clownhulk @@ -158,9 +174,12 @@ icon_state = "honkhulk" icon_living = "honkhulk" move_resist = INFINITY - response_help = "tries desperately to appease" - response_disarm = "foolishly pushes" - response_harm = "angers" + response_help_continuous = "tries desperately to appease" + response_help_simple = "tries desperately to appease" + response_disarm_continuous = "foolishly pushes" + response_disarm_simple = "foolishly push" + response_harm_continuous = "angers" + response_harm_simple = "anger" speak = list("HONK", "Honk!", "HAUAUANK!!!", "GUUURRRRAAAHHH!!!") emote_see = list("honks", "sweats", "grunts") speak_chance = 5 @@ -171,7 +190,8 @@ harm_intent_damage = 15 melee_damage_lower = 15 melee_damage_upper = 20 - attacktext = "pummels" + attack_verb_continuous = "pummels" + attack_verb_simple = "pummel" obj_damage = 30 environment_smash = ENVIRONMENT_SMASH_WALLS loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap) @@ -181,16 +201,20 @@ desc = "A real lunkhead who somehow gets all the girls." icon_state = "chlown" icon_living = "chlown" - response_help = "submits to" - response_disarm = "tries to assert dominance over" - response_harm = "makes a weak beta attack at" + response_help_continuous = "submits to" + response_help_simple = "submit to" + response_disarm_continuous = "tries to assert dominance over" + response_disarm_simple = "try to assert dominance over" + response_harm_continuous = "makes a weak beta attack at" + response_harm_simple = "make a weak beta attack at" speak = list("HONK", "Honk!", "Bruh", "cheeaaaahhh?") emote_see = list("asserts his dominance", "emasculates everyone implicitly") maxHealth = 500 health = 500 speed = -2 armour_penetration = 20 - attacktext = "steals the girlfriend of" + attack_verb_continuous = "steals the girlfriend of" + attack_verb_simple = "steal the girlfriend of" attack_sound = 'sound/items/airhorn2.ogg' loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/foam, /obj/item/soap) @@ -199,8 +223,10 @@ desc = "A slender wiry figure of alchemical origin." icon_state = "honkmunculus" icon_living = "honkmunculus" - response_help = "skeptically pokes" - response_disarm = "pushes the unwieldy frame of" + response_help_continuous = "skeptically pokes" + response_help_simple = "skeptically poke" + response_disarm_continuous = "pushes the unwieldy frame of" + response_disarm_simple = "push the unwieldy frame of" speak = list("honk") emote_see = list("squirms", "writhes") speak_chance = 1 @@ -210,7 +236,8 @@ harm_intent_damage = 5 melee_damage_lower = 5 melee_damage_upper = 10 - attacktext = "ferociously mauls" + attack_verb_continuous = "ferociously mauls" + attack_verb_simple = "ferociously maul" environment_smash = ENVIRONMENT_SMASH_NONE loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap) attack_reagent = /datum/reagent/peaceborg_confuse @@ -220,8 +247,10 @@ desc = "An ancient being born of arcane honking." icon_state = "destroyer" icon_living = "destroyer" - response_disarm = "bounces off of" - response_harm = "bounces off of" + response_disarm_continuous = "bounces off of" + response_disarm_simple = "bounce off of" + response_harm_continuous = "bounces off of" + response_harm_simple = "bounce off ot" speak = list("HONK!!!", "The Honkmother is merciful, so I must act out her wrath.", "parce mihi ad beatus honkmother placet mihi ut peccata committere,", "DIE!!!") maxHealth = 400 health = 400 @@ -231,7 +260,8 @@ melee_damage_upper = 40 armour_penetration = 30 stat_attack = UNCONSCIOUS - attacktext = "acts out divine vengeance on" + attack_verb_continuous = "acts out divine vengeance on" + attack_verb_simple = "act out divine vengeance on" obj_damage = 50 environment_smash = ENVIRONMENT_SMASH_RWALLS loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/foam, /obj/item/soap) @@ -243,9 +273,12 @@ icon_living = "mutant" move_resist = INFINITY turns_per_move = 10 - response_help = "reluctantly sinks a finger into" - response_disarm = "squishes into" - response_harm = "squishes into" + response_help_continuous = "reluctantly sinks a finger into" + response_help_simple = "reluctantly sink a finger into" + response_disarm_continuous = "squishes into" + response_disarm_simple = "squish into" + response_harm_continuous = "squishes into" + response_harm_simple = "squish into" speak = list("aaaaaahhhhuuhhhuhhhaaaaa", "AAAaaauuuaaAAAaauuhhh", "huuuuuh... hhhhuuuooooonnnnkk", "HuaUAAAnKKKK") emote_see = list("squirms", "writhes", "pulsates", "froths", "oozes") speak_chance = 10 @@ -256,7 +289,8 @@ harm_intent_damage = 10 melee_damage_lower = 10 melee_damage_upper = 20 - attacktext = "awkwardly flails at" + attack_verb_continuous = "awkwardly flails at" + attack_verb_simple = "awkwardly flail at" loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human) /mob/living/simple_animal/hostile/retaliate/clown/mutant/blob @@ -269,6 +303,7 @@ health = 130 mob_size = MOB_SIZE_LARGE speed = 20 - attacktext = "bounces off of" + attack_verb_continuous = "bounces off of" + attack_verb_simple = "bounce off of" loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human) attack_reagent = /datum/reagent/toxin/mindbreaker diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm index ef51d8621b..8424a0a576 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm @@ -13,10 +13,14 @@ health = 15 melee_damage_lower = 5 melee_damage_upper = 5 - attacktext = "bites" - response_help = "pets" - response_disarm = "pokes" - response_harm = "splats" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "pokes" + response_disarm_simple = "poke" + response_harm_continuous = "splats" + response_harm_simple = "splat" density = FALSE ventcrawler = VENTCRAWLER_ALWAYS faction = list("hostile") diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm index 7d1f08201f..2c94739180 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm @@ -7,9 +7,12 @@ mob_biotypes = MOB_SPIRIT speak_chance = 0 turns_per_move = 5 - response_help = "passes through" - response_disarm = "shoves" - response_harm = "hits" + response_help_continuous = "passes through" + response_help_simple = "pass through" + response_disarm_continuous = "shoves" + response_disarm_simple = "shove" + response_harm_continuous = "hits" + response_harm_simple = "hit" a_intent = INTENT_HARM healable = 0 speed = 0 @@ -20,7 +23,8 @@ melee_damage_upper = 15 del_on_death = 1 emote_see = list("weeps silently", "groans", "mumbles") - attacktext = "grips" + attack_verb_continuous = "grips" + attack_verb_simple = "grip" attack_sound = 'sound/hallucinations/growl1.ogg' speak_emote = list("weeps") deathmessage = "wails, disintegrating into a pile of ectoplasm!" diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/spaceman.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/spaceman.dm index 16358f736b..ebeb2d28ec 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/spaceman.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/spaceman.dm @@ -8,9 +8,12 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID gender = MALE turns_per_move = 5 - response_help = "pokes" - response_disarm = "gently pushes aside" - response_harm = "punches" + response_help_continuous = "pokes" + response_help_simple = "poke" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "punches" + response_harm_simple = "punch" a_intent = INTENT_HARM maxHealth = 100 health = 100 @@ -18,14 +21,14 @@ harm_intent_damage = 8 melee_damage_lower = 10 melee_damage_upper = 10 - attacktext = "hits" + attack_verb_continuous = "hits" + attack_verb_simple = "hit" attack_sound = 'sound/weapons/punch1.ogg' obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE del_on_death = 0 - has_field_of_vision = FALSE //Legacy. Also they only have one dir visually. - - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE + has_field_of_vision = FALSE //Legacy gameplay experience. Also they only have one dir visually. /mob/living/simple_animal/hostile/retaliate/nanotrasenpeace //this should be in a different file name = "Nanotrasen Private Security Officer" @@ -36,9 +39,12 @@ icon_dead = null icon_gib = "syndicate_gib" turns_per_move = 5 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" + response_help_continuous = "pokes" + response_help_simple = "poke" + response_disarm_continuous = "shoves" + response_disarm_simple = "shove" + response_harm_continuous = "hits" + response_harm_simple = "hit" speed = 0 stat_attack = UNCONSCIOUS robust_searching = 1 @@ -48,7 +54,8 @@ harm_intent_damage = 5 melee_damage_lower = 10 melee_damage_upper = 15 - attacktext = "punches" + attack_verb_continuous = "punches" + attack_verb_simple = "punch" attack_sound = 'sound/weapons/punch1.ogg' faction = list("nanotrasenprivate") a_intent = INTENT_HARM diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm index 9c3e3e0b92..f7a46658c4 100644 --- a/code/modules/mob/living/simple_animal/hostile/russian.dm +++ b/code/modules/mob/living/simple_animal/hostile/russian.dm @@ -9,9 +9,6 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID speak_chance = 0 turns_per_move = 5 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" speed = 0 threat = 1 maxHealth = 100 @@ -19,7 +16,8 @@ harm_intent_damage = 5 melee_damage_lower = 15 melee_damage_upper = 15 - attacktext = "punches" + attack_verb_continuous = "punches" + attack_verb_simple = "punch" attack_sound = 'sound/weapons/punch1.ogg' a_intent = INTENT_HARM loot = list(/obj/effect/mob_spawn/human/corpse/russian, @@ -30,7 +28,7 @@ status_flags = CANPUSH del_on_death = 1 - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE /mob/living/simple_animal/hostile/russian/ranged diff --git a/code/modules/mob/living/simple_animal/hostile/sharks.dm b/code/modules/mob/living/simple_animal/hostile/sharks.dm index 4008334a57..1263a23d26 100644 --- a/code/modules/mob/living/simple_animal/hostile/sharks.dm +++ b/code/modules/mob/living/simple_animal/hostile/sharks.dm @@ -12,9 +12,12 @@ speak_chance = 0 turns_per_move = 3 butcher_results = list(/obj/item/reagent_containers/food/snacks/carpmeat = 3) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "hits" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" speed = 0 threat = 1 maxHealth = 75 @@ -22,7 +25,8 @@ harm_intent_damage = 18 melee_damage_lower = 18 melee_damage_upper = 18 - attacktext = "maims" + attack_verb_continuous = "maims" + attack_verb_simple = "maim" attack_sound = 'sound/weapons/bite.ogg' gold_core_spawnable = 1 //Space shark aren't affected by cold. @@ -82,7 +86,8 @@ harm_intent_damage = 0 melee_damage_lower = 0 melee_damage_upper = 0 - attacktext = "violently hugs" + attack_verb_continuous = "violently hugs" + attack_verb_simple = "violently hug" vision_range = 0 /mob/living/simple_animal/hostile/shark/kawaii/death() diff --git a/code/modules/mob/living/simple_animal/hostile/skeleton.dm b/code/modules/mob/living/simple_animal/hostile/skeleton.dm index 9aee944c6d..3091949552 100644 --- a/code/modules/mob/living/simple_animal/hostile/skeleton.dm +++ b/code/modules/mob/living/simple_animal/hostile/skeleton.dm @@ -22,7 +22,8 @@ minbodytemp = 0 maxbodytemp = 1500 healable = 0 //they're skeletons how would bruise packs help them?? - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/hallucinations/growl1.ogg' atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) unsuitable_atmos_damage = 10 @@ -36,7 +37,7 @@ del_on_death = 1 loot = list(/obj/effect/decal/remains/human) - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE /mob/living/simple_animal/hostile/skeleton/eskimo name = "undead eskimo" @@ -104,7 +105,8 @@ melee_damage_lower = 15 melee_damage_upper = 20 light_color = LIGHT_COLOR_PURPLE - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/hallucinations/growl1.ogg' deathmessage = "collapses into a pile of bones, their suit dissolving among the plasma!" loot = list(/obj/effect/decal/remains/plasma) @@ -120,7 +122,8 @@ harm_intent_damage = 15 melee_damage_lower = 20 melee_damage_upper = 25 - attacktext = "blasts" + attack_verb_continuous = "blasts" + attack_verb_simple = "blast" attack_sound = 'sound/weapons/sonic_jackhammer.ogg' loot = list(/obj/effect/decal/remains/plasma, /obj/item/pickaxe/drill/jackhammer) diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm index d693c96c8f..23304a2ef3 100644 --- a/code/modules/mob/living/simple_animal/hostile/statue.dm +++ b/code/modules/mob/living/simple_animal/hostile/statue.dm @@ -11,9 +11,10 @@ a_intent = INTENT_HARM mob_biotypes = MOB_HUMANOID threat = 3 - response_help = "touches" - response_disarm = "pushes" - + response_help_continuous = "touches" + response_help_simple = "touch" + response_disarm_continuous = "pushes" + response_disarm_simple = "push" speed = -1 maxHealth = 50000 health = 50000 @@ -24,7 +25,8 @@ obj_damage = 100 melee_damage_lower = 68 melee_damage_upper = 83 - attacktext = "claws" + attack_verb_continuous = "claws" + attack_verb_simple = "claw" attack_sound = 'sound/hallucinations/growl1.ogg' atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) @@ -125,7 +127,7 @@ // This loop will, at most, loop twice. for(var/atom/check in check_list) - for(var/mob/living/M in get_actual_viewers(world.view + 1, check) - src) + for(var/mob/living/M in fov_viewers(world.view + 1, check) - src) if(M.client && CanAttack(M) && !M.silicon_privileges) if(!M.eye_blind) return M diff --git a/code/modules/mob/living/simple_animal/hostile/stickman.dm b/code/modules/mob/living/simple_animal/hostile/stickman.dm index 24bf5e9ea9..2edcc4021a 100644 --- a/code/modules/mob/living/simple_animal/hostile/stickman.dm +++ b/code/modules/mob/living/simple_animal/hostile/stickman.dm @@ -10,9 +10,6 @@ gender = MALE speak_chance = 0 turns_per_move = 5 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" speed = 0 blood_volume = 0 stat_attack = UNCONSCIOUS @@ -24,7 +21,8 @@ obj_damage = 0 melee_damage_lower = 10 melee_damage_upper = 10 - attacktext = "punches" + attack_verb_continuous = "punches" + attack_verb_simple = "punch" attack_sound = 'sound/weapons/punch1.ogg' a_intent = INTENT_HARM atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index 8c4e19774d..9a362b680d 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -25,9 +25,6 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID speak_chance = 0 turns_per_move = 5 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" threat = 1 speed = 0 stat_attack = UNCONSCIOUS @@ -37,7 +34,8 @@ harm_intent_damage = 5 melee_damage_lower = 10 melee_damage_upper = 10 - attacktext = "punches" + attack_verb_continuous = "punches" + attack_verb_simple = "punch" attack_sound = 'sound/weapons/punch1.ogg' a_intent = INTENT_HARM loot = list(/obj/effect/mob_spawn/human/corpse/syndicatesoldier) @@ -50,7 +48,7 @@ dodging = TRUE rapid_melee = 2 - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE ///////////////Melee//////////// @@ -82,7 +80,8 @@ icon_state = "syndicate_knife" icon_living = "syndicate_knife" loot = list(/obj/effect/gibspawner/human) - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/weapons/bladeslice.ogg' status_flags = 0 @@ -113,7 +112,8 @@ melee_damage_upper = 30 icon_state = "syndicate_sword" icon_living = "syndicate_sword" - attacktext = "slashes" + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" attack_sound = 'sound/weapons/blade1.ogg' armour_penetration = 35 light_color = LIGHT_COLOR_RED @@ -292,7 +292,8 @@ melee_damage_upper = 15 obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE - attacktext = "cuts" + attack_verb_continuous = "cuts" + attack_verb_simple = "cut" attack_sound = 'sound/weapons/bladeslice.ogg' faction = list(ROLE_SYNDICATE) atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/hostile/tree.dm index bc932666f6..3aa3c9e566 100644 --- a/code/modules/mob/living/simple_animal/hostile/tree.dm +++ b/code/modules/mob/living/simple_animal/hostile/tree.dm @@ -10,9 +10,12 @@ threat = 1 speak_chance = 0 turns_per_move = 5 - response_help = "brushes" - response_disarm = "pushes" - response_harm = "hits" + response_help_continuous = "brushes" + response_help_simple = "brush" + response_disarm_continuous = "pushes" + response_disarm_simple = "push" + response_harm_continuous = "hits" + response_harm_simple = "hit" speed = 1 maxHealth = 250 health = 250 @@ -23,7 +26,8 @@ harm_intent_damage = 5 melee_damage_lower = 8 melee_damage_upper = 12 - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" attack_sound = 'sound/weapons/bite.ogg' speak_emote = list("pines") emote_taunt = list("growls") diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm index 15d641299d..57fb6f829d 100644 --- a/code/modules/mob/living/simple_animal/hostile/wizard.dm +++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm @@ -8,9 +8,6 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID speak_chance = 0 turns_per_move = 3 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" threat = 3 speed = 0 maxHealth = 100 @@ -18,7 +15,8 @@ harm_intent_damage = 5 melee_damage_lower = 5 melee_damage_upper = 5 - attacktext = "punches" + attack_verb_continuous = "punches" + attack_verb_simple = "punch" attack_sound = 'sound/weapons/punch1.ogg' a_intent = INTENT_HARM atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) @@ -38,7 +36,7 @@ var/next_cast = 0 - do_footstep = TRUE + footstep_type = FOOTSTEP_MOB_SHOE /mob/living/simple_animal/hostile/wizard/Initialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm index 8878f17893..5c881a7b0d 100644 --- a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm +++ b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm @@ -12,7 +12,8 @@ mouse_opacity = MOUSE_OPACITY_ICON move_to_delay = 5 threat = 1 - friendly = "floats near" + friendly_verb_continuous = "floats near" + friendly_verb_simple = "float near" speak_emote = list("puffs") vision_range = 5 speed = 0 @@ -23,7 +24,8 @@ obj_damage = 0 melee_damage_lower = 0 melee_damage_upper = 0 - attacktext = "chomps" + attack_verb_continuous = "chomps" + attack_verb_simple = "chomp" attack_sound = 'sound/weapons/punch1.ogg' throw_message = "is avoided by the" vision_range = 5 diff --git a/code/modules/mob/living/simple_animal/hostile/zombie.dm b/code/modules/mob/living/simple_animal/hostile/zombie.dm index 503f5c121e..6e4cbac022 100644 --- a/code/modules/mob/living/simple_animal/hostile/zombie.dm +++ b/code/modules/mob/living/simple_animal/hostile/zombie.dm @@ -13,7 +13,8 @@ harm_intent_damage = 5 melee_damage_lower = 21 melee_damage_upper = 21 - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" attack_sound = 'sound/hallucinations/growl1.ogg' a_intent = INTENT_HARM atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) @@ -73,7 +74,8 @@ harm_intent_damage = 5 melee_damage_lower = 21 melee_damage_upper = 21 - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" attack_sound = 'sound/hallucinations/growl1.ogg' a_intent = INTENT_HARM atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 9ad9a121ca..e8d6411c01 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -50,13 +50,18 @@ melee_damage_upper = 10 melee_damage_lower = 5 - response_help = "pets" - response_disarm = "gently moves aside" - response_harm = "swats" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently moves aside" + response_disarm_simple = "gently move aside" + response_harm_continuous = "swats" + response_harm_simple = "swat" stop_automated_movement = 1 a_intent = INTENT_HARM //parrots now start "aggressive" since only player parrots will nuzzle. - attacktext = "chomps" - friendly = "grooms" + attack_verb_continuous = "chomps" + attack_verb_simple = "chomp" + friendly_verb_continuous = "grooms" + friendly_verb_simple = "groom" mob_size = MOB_SIZE_SMALL movement_type = FLYING gold_core_spawnable = FRIENDLY_SPAWN @@ -575,7 +580,12 @@ parrot_state = PARROT_WANDER return - attacktext = pick("claws at", "chomps") + if(prob(50)) + attack_verb_continuous = "claws at" + attack_verb_simple = "claw_at" + else + attack_verb_continuous = "chomps" + attack_verb_simple = "chomp" L.attack_animal(src)//Time for the hurt to begin! //Otherwise, fly towards the mob! else diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index 1d22313edd..75182b85e5 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -13,13 +13,17 @@ healable = 0 speak_emote = list("hisses") emote_hear = list("wails.","screeches.") - response_help = "puts their hand through" - response_disarm = "flails at" - response_harm = "punches" + response_help_continuous = "puts their hand through" + response_help_simple = "put your hand through" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "punches" + response_harm_simple = "punch" speak_chance = 1 melee_damage_lower = 5 melee_damage_upper = 12 - attacktext = "metaphysically strikes" + attack_verb_continuous = "metaphysically strikes" + attack_verb_simple = "metaphysically strike" minbodytemp = 0 maxbodytemp = INFINITY atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 25a4215670..261778b28f 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -4,95 +4,141 @@ health = 20 maxHealth = 20 gender = PLURAL //placeholder - blood_volume = 550 //How much blud it has for bloodsucking + ///How much blud it has for bloodsucking + blood_volume = 550 status_flags = CANPUSH var/icon_living = "" - var/icon_dead = "" //icon when the animal is dead. Don't use animated icons for this. - var/icon_gib = null //We only try to show a gibbing animation if this exists. + ///icon when the animal is dead. Don't use animated icons for this. + var/icon_dead = "" + ///We only try to show a gibbing animation if this exists. + var/icon_gib = null var/list/speak = list() - var/list/speak_emote = list()// Emotes while speaking IE: Ian [emote], [text] -- Ian barks, "WOOF!". Spoken text is generated from the speak variable. + ///Emotes while speaking IE: Ian [emote], [text] -- Ian barks, "WOOF!". Spoken text is generated from the speak variable. + var/list/speak_emote = list() var/speak_chance = 0 - var/list/emote_hear = list() //Hearable emotes - var/list/emote_see = list() //Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps + ///Hearable emotes + var/list/emote_hear = list() + ///Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps. + var/list/emote_see = list() var/turns_per_move = 1 var/turns_since_move = 0 - var/stop_automated_movement = 0 //Use this to temporarely stop random movement or to if you write special movement code for animals. - var/wander = 1 // Does the mob wander around when idle? - var/stop_automated_movement_when_pulled = 1 //When set to 1 this stops the animal from moving when someone is pulling it. + ///Use this to temporarely stop random movement or to if you write special movement code for animals. + var/stop_automated_movement = 0 + ///Does the mob wander around when idle? + var/wander = 1 + ///When set to 1 this stops the animal from moving when someone is pulling it. + var/stop_automated_movement_when_pulled = 1 - //Interaction - var/response_help = "pokes" - var/response_disarm = "shoves" - var/response_harm = "hits" + ///When someone interacts with the simple animal. + ///Help-intent verb in present continuous tense. + var/response_help_continuous = "pokes" + ///Help-intent verb in present simple tense. + var/response_help_simple = "poke" + ///Disarm-intent verb in present continuous tense. + var/response_disarm_continuous = "shoves" + ///Disarm-intent verb in present simple tense. + var/response_disarm_simple = "shove" + ///Harm-intent verb in present continuous tense. + var/response_harm_continuous = "hits" + ///Harm-intent verb in present simple tense. + var/response_harm_simple = "hit" var/harm_intent_damage = 3 - var/force_threshold = 0 //Minimum force required to deal any damage + ///Minimum force required to deal any damage. + var/force_threshold = 0 - //Temperature effect + ///Temperature effect. var/minbodytemp = 250 var/maxbodytemp = 350 - //Healable by medical stacks? Defaults to yes. + ///Healable by medical stacks? Defaults to yes. var/healable = 1 - //Atmos effect - Yes, you can make creatures that require plasma or co2 to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage + ///Atmos effect - Yes, you can make creatures that require plasma or co2 to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage var/list/atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) //Leaving something at 0 means it's off - has no maximum - var/unsuitable_atmos_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above + ///This damage is taken when atmos doesn't fit all the requirements above. + var/unsuitable_atmos_damage = 2 - //LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly + ///LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly. var/melee_damage_lower = 0 var/melee_damage_upper = 0 - var/obj_damage = 0 //how much damage this simple animal does to objects, if any - var/armour_penetration = 0 //How much armour they ignore, as a flat reduction from the targets armour value - var/melee_damage_type = BRUTE //Damage type of a simple mob's melee attack, should it do damage. - var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) // 1 for full damage , 0 for none , -1 for 1:1 heal from that source - var/attacktext = "attacks" + ///How much damage this simple animal does to objects, if any. + var/obj_damage = 0 + ///How much armour they ignore, as a flat reduction from the targets armour value. + var/armour_penetration = 0 + ///Damage type of a simple mob's melee attack, should it do damage. + var/melee_damage_type = BRUTE + /// 1 for full damage , 0 for none , -1 for 1:1 heal from that source. + var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) + ///Attacking verb in present continuous tense. + var/attack_verb_continuous = "attacks" + ///Attacking verb in present simple tense. + var/attack_verb_simple = "attack" var/attack_sound = null - var/friendly = "nuzzles" //If the mob does no damage with it's attack - var/environment_smash = ENVIRONMENT_SMASH_NONE //Set to 1 to allow breaking of crates,lockers,racks,tables; 2 for walls; 3 for Rwalls + ///Attacking, but without damage, verb in present continuous tense. + var/friendly_verb_continuous = "nuzzles" + ///Attacking, but without damage, verb in present simple tense. + var/friendly_verb_simple = "nuzzle" + ///Set to 1 to allow breaking of crates,lockers,racks,tables; 2 for walls; 3 for Rwalls. + var/environment_smash = ENVIRONMENT_SMASH_NONE - var/speed = 1 //LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster + ///LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster. + var/speed = 1 - //Hot simple_animal baby making vars + ///Hot simple_animal baby making vars. var/list/childtype = null var/next_scan_time = 0 - var/animal_species //Sorry, no spider+corgi buttbabies. + ///Sorry, no spider+corgi buttbabies. + var/animal_species - //simple_animal access - var/obj/item/card/id/access_card = null //innate access uses an internal ID card - var/buffed = 0 //In the event that you want to have a buffing effect on the mob, but don't want it to stack with other effects, any outside force that applies a buff to a simple mob should at least set this to 1, so we have something to check against - var/gold_core_spawnable = NO_SPAWN //If the mob can be spawned with a gold slime core. HOSTILE_SPAWN are spawned with plasma, FRIENDLY_SPAWN are spawned with blood + ///Innate access uses an internal ID card. + var/obj/item/card/id/access_card = null + ///In the event that you want to have a buffing effect on the mob, but don't want it to stack with other effects, any outside force that applies a buff to a simple mob should at least set this to TRUE, so we have something to check against. + var/buffed = FALSE + ///If the mob can be spawned with a gold slime core. HOSTILE_SPAWN are spawned with plasma, FRIENDLY_SPAWN are spawned with blood. + var/gold_core_spawnable = NO_SPAWN var/datum/component/spawner/nest - var/sentience_type = SENTIENCE_ORGANIC // Sentience type, for slime potions + ///Sentience type, for slime potions. + var/sentience_type = SENTIENCE_ORGANIC - var/list/loot = list() //list of things spawned at mob's loc when it dies - var/del_on_death = 0 //causes mob to be deleted on death, useful for mobs that spawn lootable corpses + ///list of things spawned at mob's loc when it dies. + var/list/loot = list() + ///causes mob to be deleted on death, useful for mobs that spawn lootable corpses. + var/del_on_death = FALSE var/deathmessage = "" - var/death_sound = null //The sound played on death + ///The sound played on death. + var/death_sound = null var/allow_movement_on_non_turfs = FALSE - var/attacked_sound = "punch" //Played when someone punches the creature + ///Played when someone punches the creature. + var/attacked_sound = "punch" - var/dextrous = FALSE //If the creature has, and can use, hands + ///If the creature has, and can use, hands. + var/dextrous = FALSE var/dextrous_hud_type = /datum/hud/dextrous - var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players) - var/can_have_ai = TRUE //once we have become sentient, we can never go back + ///The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players). + var/AIStatus = AI_ON + ///once we have become sentient, we can never go back. + var/can_have_ai = TRUE - var/shouldwakeup = FALSE //convenience var for forcibly waking up an idling AI on next check. + ///convenience var for forcibly waking up an idling AI on next check. + var/shouldwakeup = FALSE - //domestication + ///Domestication. var/tame = 0 - var/my_z // I don't want to confuse this with client registered_z + ///I don't want to confuse this with client registered_z. + var/my_z - var/do_footstep = FALSE + ///What kind of footstep this mob should have. Null if it shouldn't have any. + var/footstep_type /mob/living/simple_animal/Initialize() . = ..() @@ -106,6 +152,8 @@ update_simplemob_varspeed() if(dextrous) AddComponent(/datum/component/personal_crafting) + if(footstep_type) + AddComponent(/datum/component/footstep, footstep_type) /mob/living/simple_animal/Destroy() GLOB.simple_animals[AIStatus] -= src @@ -122,10 +170,6 @@ return ..() -/mob/living/simple_animal/initialize_footstep() - if(do_footstep) - ..() - /mob/living/simple_animal/updatehealth() ..() health = clamp(health, 0, maxHealth) diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm index 08a5f0a2c9..6e8c79c3d0 100644 --- a/code/modules/mob/living/simple_animal/slime/life.dm +++ b/code/modules/mob/living/simple_animal/slime/life.dm @@ -264,7 +264,7 @@ . = ..() if(!slime_check) return - if(nutrition == max) + if(nutrition >= get_grow_nutrition()) if(powerlevel<10) if(prob(30-powerlevel*2)) powerlevel++ diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm index 007140417c..d93993bf1f 100644 --- a/code/modules/mob/living/simple_animal/slime/powers.dm +++ b/code/modules/mob/living/simple_animal/slime/powers.dm @@ -28,7 +28,7 @@ return 0 var/list/choices = list() - for(var/mob/living/C in visible_atoms(1,src)) + for(var/mob/living/C in fov_view(1,src)) if(C!=src && Adjacent(C)) choices += C diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 1c5916a249..0ef5cabc91 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -12,9 +12,12 @@ harm_intent_damage = 5 icon_living = "grey baby slime" icon_dead = "grey baby slime dead" - response_help = "pets" - response_disarm = "shoos" - response_harm = "stomps on" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "shoos" + response_disarm_simple = "shoo" + response_harm_continuous = "stomps on" + response_harm_simple = "stomp on" emote_see = list("jiggles", "bounces in place") speak_emote = list("blorbles") bubble_icon = "slime" @@ -64,8 +67,6 @@ var/mutator_used = FALSE //So you can't shove a dozen mutators into a single slime var/force_stasis = FALSE - do_footstep = TRUE - var/static/regex/slime_name_regex = new("\\w+ (baby|adult) slime \\(\\d+\\)") ///////////TIME FOR SUBSPECIES @@ -103,6 +104,7 @@ create_reagents(100, NONE, NO_REAGENTS_VALUE) set_colour(new_colour) . = ..() + AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 7.5) /mob/living/simple_animal/slime/Destroy() for (var/A in actions) diff --git a/code/modules/mob/living/update_icons.dm b/code/modules/mob/living/update_icons.dm index b10d78aeb3..f8d5d7e0ba 100644 --- a/code/modules/mob/living/update_icons.dm +++ b/code/modules/mob/living/update_icons.dm @@ -22,4 +22,4 @@ if(changed) animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, easing = EASE_IN|EASE_OUT) - setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life(). + floating_need_update = TRUE diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index a3d5a4f3c5..e7c5373543 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -125,8 +125,10 @@ * * blind_message (optional) is what blind people will hear e.g. "You hear something!" * * vision_distance (optional) define how many tiles away the message can be seen. * * ignored_mobs (optional) doesn't show any message to any given mob in the list. + * * target (optional) is the other mob involved with the visible message. For example, the attacker in many combat messages. + * * target_message (optional) is what the target mob will see e.g. "[src] does something to you!" */ -/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs) +/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message) var/turf/T = get_turf(src) if(!T) return @@ -136,7 +138,19 @@ if(!islist(ignored_mobs)) ignored_mobs = list(ignored_mobs) hearers -= ignored_mobs - if(self_message) + + if(target_message && target && istype(target) && target.client) + hearers -= target + //This entire if/else chain could be in two lines but isn't for readibilties sake. + var/msg = target_message + if(target.see_invisible") diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 1d69ba3be8..1350c36348 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -433,7 +433,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) env.merge(removed) air_update_turf() - for(var/mob/living/carbon/human/l in get_actual_viewers(HALLUCINATION_RANGE(power), src)) // If they can see it without mesons on. Bad on them. + for(var/mob/living/carbon/human/l in fov_viewers(HALLUCINATION_RANGE(power), src)) // If they can see it without mesons on. Bad on them. if(!istype(l.glasses, /obj/item/clothing/glasses/meson)) var/D = sqrt(1 / max(1, get_dist(l, src))) l.hallucination += power * config_hallucination_power * D @@ -559,14 +559,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) dust_mob(user, cause = "alien attack") /obj/machinery/power/supermatter_crystal/attack_animal(mob/living/simple_animal/S) - var/murder - if(!S.melee_damage_upper && !S.melee_damage_lower) - murder = S.friendly - else - murder = S.attacktext dust_mob(S, \ - "[S] unwisely [murder] [src], and [S.p_their()] body burns brilliantly before flashing into ash!", \ - "You unwisely touch [src], and your vision glows brightly as your body crumbles to dust. Oops.", \ + "[S] unwisely [S.attack_verb_continuous] [src], and [S.p_their()] body burns brilliantly before flashing into ash!", \ + "You unwisely [S.attack_verb_simple] [src], and your vision glows brightly as your body crumbles to dust. Oops.", \ "simple animal attack") /obj/machinery/power/supermatter_crystal/attack_robot(mob/user) @@ -666,7 +661,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) //Some poor sod got eaten, go ahead and irradiate people nearby. radiation_pulse(src, 3000, 2, TRUE) - var/list/viewers = get_actual_viewers(world.view, src) + var/list/viewers = fov_viewers(world.view, src) for(var/mob/living/L in range(10)) investigate_log("has irradiated [key_name(L)] after consuming [AM].", INVESTIGATE_SUPERMATTER) if(L in viewers) diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm index 64d317b385..eb80548441 100644 --- a/code/modules/power/tesla/coil.dm +++ b/code/modules/power/tesla/coil.dm @@ -73,7 +73,7 @@ return ..() -/obj/machinery/power/tesla_coil/tesla_act(power, tesla_flags, shocked_targets) +/obj/machinery/power/tesla_coil/zap_act(power, zap_flags, shocked_targets) if(anchored && !panel_open) obj_flags |= BEING_SHOCKED //don't lose arc power when it's not connected to anything @@ -81,17 +81,17 @@ var/power_produced = powernet ? power / power_loss : power add_avail(power_produced*input_power_multiplier) flick("coilhit", src) - playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5) - tesla_zap(src, 5, power_produced, tesla_flags, shocked_targets) var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_ENG) if(D) D.adjust_money(min(power_produced, 1)) if(istype(linked_techweb)) linked_techweb.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min(power_produced, 1)) // x4 coils = ~240/m point bonus for R&D addtimer(CALLBACK(src, .proc/reset_shocked), 10) - tesla_buckle_check(power) + zap_buckle_check(power) + playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) + return power_produced else - ..() + . = ..() /obj/machinery/power/tesla_coil/proc/zap() if((last_zap + zap_cooldown) > world.time || !powernet) @@ -102,8 +102,8 @@ var/power = (powernet.avail/2) add_load(power) playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5) - tesla_zap(src, 10, power/(coeff/2), TESLA_FUSION_FLAGS) - tesla_buckle_check(power/(coeff/2)) + tesla_zap(src, 10, power/(coeff/2), ZAP_FUSION_FLAGS) + zap_buckle_check(power/(coeff/2)) // Tesla R&D researcher /obj/machinery/power/tesla_coil/research @@ -113,23 +113,23 @@ circuit = /obj/item/circuitboard/machine/tesla_coil/research power_loss = 20 // something something, high voltage + resistance -/obj/machinery/power/tesla_coil/research/tesla_act(power, tesla_flags, shocked_things) +/obj/machinery/power/tesla_coil/research/zap_act(power, zap_flags, shocked_targets) if(anchored && !panel_open) obj_flags |= BEING_SHOCKED var/power_produced = powernet ? power / power_loss : power add_avail(power_produced*input_power_multiplier) flick("rpcoilhit", src) - playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5) - tesla_zap(src, 5, power_produced, tesla_flags, shocked_things) var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_ENG) if(D) D.adjust_money(min(power_produced, 3)) if(istype(linked_techweb)) linked_techweb.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min(power_produced, 3)) // x4 coils with a pulse per second or so = ~720/m point bonus for R&D addtimer(CALLBACK(src, .proc/reset_shocked), 10) - tesla_buckle_check(power) + zap_buckle_check(power) + playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) + return power_produced else - ..() + . = ..() /obj/machinery/power/tesla_coil/research/default_unfasten_wrench(mob/user, obj/item/wrench/W, time = 20) . = ..() @@ -180,9 +180,10 @@ return ..() -/obj/machinery/power/grounding_rod/tesla_act(var/power) +/obj/machinery/power/grounding_rod/zap_act(var/power) if(anchored && !panel_open) flick("grounding_rodhit", src) - tesla_buckle_check(power) + zap_buckle_check(power) + return 0 else - ..() + . = ..() diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index e98fe3c88e..06e5d27f6d 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -1,5 +1,14 @@ #define TESLA_DEFAULT_POWER 1738260 #define TESLA_MINI_POWER 869130 +//Zap constants, speeds up targeting +#define BIKE (COIL + 1) +#define COIL (ROD + 1) +#define ROD (RIDE + 1) +#define RIDE (LIVING + 1) +#define LIVING (MACHINERY + 1) +#define MACHINERY (BLOB + 1) +#define BLOB (STRUCTURE + 1) +#define STRUCTURE (1) /obj/singularity/energy_ball name = "energy ball" @@ -32,6 +41,9 @@ /obj/singularity/energy_ball/ex_act(severity, target) return +/obj/singularity/energy_ball/consume(severity, target) + return + /obj/singularity/energy_ball/Destroy() if(orbiting && istype(orbiting.parent, /obj/singularity/energy_ball)) var/obj/singularity/energy_ball/EB = orbiting.parent @@ -39,7 +51,7 @@ for(var/ball in orbiting_balls) var/obj/singularity/energy_ball/EB = ball - qdel(EB) + QDEL_NULL(EB) . = ..() @@ -55,12 +67,12 @@ move_the_basket_ball(4 + orbiting_balls.len * 1.5) - playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, 1, extrarange = 30) + playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, TRUE, extrarange = 30) pixel_x = 0 pixel_y = 0 - tesla_zap(src, 7, TESLA_DEFAULT_POWER, TRUE) + tesla_zap(src, 7, TESLA_DEFAULT_POWER) pixel_x = -32 pixel_y = -32 @@ -73,7 +85,7 @@ /obj/singularity/energy_ball/examine(mob/user) . = ..() if(orbiting_balls.len) - . += "The amount of orbiting mini-balls is [orbiting_balls.len]." + . += "There are [orbiting_balls.len] mini-balls orbiting it." /obj/singularity/energy_ball/proc/move_the_basket_ball(var/move_amount) @@ -96,7 +108,7 @@ energy_to_lower = energy_to_raise - 20 energy_to_raise = energy_to_raise * 1.25 - playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, 1, extrarange = 30) + playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, TRUE, extrarange = 30) addtimer(CALLBACK(src, .proc/new_mini_ball), 100) else if(energy < energy_to_lower && orbiting_balls.len) @@ -132,22 +144,19 @@ /obj/singularity/energy_ball/attack_tk(mob/user) if(iscarbon(user)) var/mob/living/carbon/C = user - log_game("[key_name(C)] has been disintegrated by a telekenetic grab on a tesla ball.") to_chat(C, "That was a shockingly dumb idea.") - C.visible_message("A bright flare of lightning is seen from [C]'s head, shortly before you hear a sickening sizzling!") var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs - rip_u.Remove() + C.ghostize(0) qdel(rip_u) - return - return ..() + C.death() /obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target) if (istype(target)) target.orbiting_balls += src GLOB.poi_list -= src target.dissipate_strength = target.orbiting_balls.len - . = ..() + /obj/singularity/energy_ball/stop_orbit() if (orbiting && istype(orbiting.parent, /obj/singularity/energy_ball)) var/obj/singularity/energy_ball/orbitingball = orbiting.parent @@ -171,20 +180,19 @@ var/mob/living/carbon/C = A C.dust() -/proc/tesla_zap(atom/source, zap_range = 3, power, tesla_flags = TESLA_DEFAULT_FLAGS, list/shocked_targets) +/proc/tesla_zap(atom/source, zap_range = 3, power, zap_flags = ZAP_DEFAULT_FLAGS, list/shocked_targets) + if(QDELETED(source)) + return . = source.dir if(power < 1000) return - var/closest_dist = 0 - var/closest_atom - var/obj/machinery/power/tesla_coil/closest_tesla_coil - var/obj/machinery/power/grounding_rod/closest_grounding_rod - var/mob/living/closest_mob - var/obj/machinery/closest_machine - var/obj/structure/closest_structure - var/obj/structure/blob/closest_blob - var/static/things_to_shock = typecacheof(list(/obj/machinery, /mob/living, /obj/structure)) + /* + THIS IS SO FUCKING UGLY AND I HATE IT, but I can't make it nice without making it slower, check*N rather then n. So we're stuck with it. + */ + var/atom/closest_atom + var/closest_type = 0 + var/static/things_to_shock = typecacheof(list(/obj/machinery, /mob/living, /obj/structure, /obj/vehicle/ridden)) var/static/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics, /obj/machinery/power/emitter, /obj/machinery/field/generator, @@ -205,112 +213,133 @@ /obj/machinery/gateway, /obj/structure/lattice, /obj/structure/grille, - /obj/machinery/the_singularitygen/tesla, /obj/structure/frame/machine)) - for(var/A in typecache_filter_multi_list_exclusion(oview(source, zap_range+2), things_to_shock, blacklisted_tesla_types)) - if(!(tesla_flags & TESLA_ALLOW_DUPLICATES) && LAZYACCESS(shocked_targets, A)) + //Ok so we are making an assumption here. We assume that view() still calculates from the center out. + //This means that if we find an object we can assume it is the closest one of its type. This is somewhat of a speed increase. + //This also means we have no need to track distance, as the doview() proc does it all for us. + + //Darkness fucks oview up hard. I've tried dview() but it doesn't seem to work + //I hate existance + for(var/a in typecache_filter_multi_list_exclusion(oview(zap_range+2, source), things_to_shock, blacklisted_tesla_types)) + var/atom/A = a + if(!(zap_flags & ZAP_ALLOW_DUPLICATES) && LAZYACCESS(shocked_targets, A)) continue + if(closest_type >= BIKE) + break - if(istype(A, /obj/machinery/power/tesla_coil)) - var/dist = get_dist(source, A) - var/obj/machinery/power/tesla_coil/C = A - if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !(C.obj_flags & BEING_SHOCKED)) - closest_dist = dist - + else if(istype(A, /obj/vehicle/ridden/bicycle))//God's not on our side cause he hates idiots. + var/obj/vehicle/ridden/bicycle/B = A + if(!(B.obj_flags & BEING_SHOCKED) && B.can_buckle)//Gee goof thanks for the boolean //we use both of these to save on istype and typecasting overhead later on //while still allowing common code to run before hand - closest_tesla_coil = C - closest_atom = C + closest_type = BIKE + closest_atom = B - - else if(closest_tesla_coil) + else if(closest_type >= COIL) continue //no need checking these other things - else if(istype(A, /obj/machinery/power/grounding_rod)) - var/dist = get_dist(source, A)-2 - if(dist <= zap_range && (dist < closest_dist || !closest_grounding_rod)) - closest_grounding_rod = A - closest_atom = A - closest_dist = dist + else if(istype(A, /obj/machinery/power/tesla_coil)) + var/obj/machinery/power/tesla_coil/C = A + if(!(C.obj_flags & BEING_SHOCKED)) + closest_type = COIL + closest_atom = C - else if(closest_grounding_rod) + else if(closest_type >= ROD) + continue + + else if(istype(A, /obj/machinery/power/grounding_rod)) + closest_type = ROD + closest_atom = A + + else if(closest_type >= RIDE) + continue + + else if(istype(A,/obj/vehicle/ridden)) + var/obj/vehicle/ridden/R = A + if(R.can_buckle && !(R.obj_flags & BEING_SHOCKED)) + closest_type = RIDE + closest_atom = A + + else if(closest_type >= LIVING) continue else if(isliving(A)) - var/dist = get_dist(source, A) var/mob/living/L = A - if(dist <= zap_range && (dist < closest_dist || !closest_mob) && L.stat != DEAD && !(L.flags_1 & TESLA_IGNORE_1)) - closest_mob = L + if(L.stat != DEAD && !(HAS_TRAIT(L, TRAIT_TESLA_SHOCKIMMUNE)) && !(L.flags_1 & SHOCKED_1)) + closest_type = LIVING closest_atom = A - closest_dist = dist - else if(closest_mob) + else if(closest_type >= MACHINERY) continue else if(ismachinery(A)) var/obj/machinery/M = A - var/dist = get_dist(source, A) - if(dist <= zap_range && (dist < closest_dist || !closest_machine) && !(M.obj_flags & BEING_SHOCKED)) - closest_machine = M + if(!(M.obj_flags & BEING_SHOCKED)) + closest_type = MACHINERY closest_atom = A - closest_dist = dist - else if(closest_mob) + else if(closest_type >= BLOB) continue else if(istype(A, /obj/structure/blob)) var/obj/structure/blob/B = A - var/dist = get_dist(source, A) - if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !(B.obj_flags & BEING_SHOCKED)) - closest_blob = B + if(!(B.obj_flags & BEING_SHOCKED)) + closest_type = BLOB closest_atom = A - closest_dist = dist - else if(closest_blob) + else if(closest_type >= STRUCTURE) continue else if(isstructure(A)) var/obj/structure/S = A - var/dist = get_dist(source, A) - if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !(S.obj_flags & BEING_SHOCKED)) - closest_structure = S + if(!(S.obj_flags & BEING_SHOCKED)) + closest_type = STRUCTURE closest_atom = A - closest_dist = dist //Alright, we've done our loop, now lets see if was anything interesting in range - if(closest_atom) - //common stuff - source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", time=5, maxdistance = INFINITY) - if(!(tesla_flags & TESLA_ALLOW_DUPLICATES)) - LAZYSET(shocked_targets, closest_atom, TRUE) - var/zapdir = get_dir(source, closest_atom) - if(zapdir) - . = zapdir + if(!closest_atom) + return + //common stuff + source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", time=5, maxdistance = INFINITY) + if(!(zap_flags & ZAP_ALLOW_DUPLICATES)) + LAZYSET(shocked_targets, closest_atom, TRUE) + var/zapdir = get_dir(source, closest_atom) + if(zapdir) + . = zapdir - //per type stuff: - if(closest_tesla_coil) - closest_tesla_coil.tesla_act(power, tesla_flags, shocked_targets) + var/next_range = 3 + if(closest_type == COIL) + next_range = 5 - else if(closest_grounding_rod) - closest_grounding_rod.tesla_act(power, tesla_flags, shocked_targets) - - else if(closest_mob) - var/shock_damage = (tesla_flags & TESLA_MOB_DAMAGE)? (min(round(power/600), 90) + rand(-5, 5)) : 0 - closest_mob.electrocute_act(shock_damage, source, 1, SHOCK_TESLA | ((tesla_flags & TESLA_MOB_STUN) ? NONE : SHOCK_NOSTUN)) + if(closest_type == LIVING) + var/mob/living/closest_mob = closest_atom + closest_mob.set_shocked() + addtimer(CALLBACK(closest_mob, /mob/living/proc/reset_shocked), 10) + var/shock_damage = (zap_flags & ZAP_MOB_DAMAGE) ? (min(round(power/600), 90) + rand(-5, 5)) : 0 + closest_mob.electrocute_act(shock_damage, source, 1, SHOCK_TESLA | ((zap_flags & ZAP_MOB_STUN) ? NONE : SHOCK_NOSTUN)) if(issilicon(closest_mob)) var/mob/living/silicon/S = closest_mob - if((tesla_flags & TESLA_MOB_STUN) && (tesla_flags & TESLA_MOB_DAMAGE)) + if((zap_flags & ZAP_MOB_STUN) && (zap_flags & ZAP_MOB_DAMAGE)) S.emp_act(EMP_LIGHT) - tesla_zap(S, 7, power / 1.5, tesla_flags, shocked_targets) // metallic folks bounce it further + next_range = 7 // metallic folks bounce it further else - tesla_zap(closest_mob, 5, power / 1.5, tesla_flags, shocked_targets) + next_range = 5 + power /= 1.5 - else if(closest_machine) - closest_machine.tesla_act(power, tesla_flags, shocked_targets) + else + power = closest_atom.zap_act(power, zap_flags, shocked_targets) + if(prob(20))//I know I know + tesla_zap(closest_atom, next_range, power * 0.5, zap_flags, shocked_targets) + tesla_zap(closest_atom, next_range, power * 0.5, zap_flags, shocked_targets) + else + tesla_zap(closest_atom, next_range, power, zap_flags, shocked_targets) - else if(closest_blob) - closest_blob.tesla_act(power, tesla_flags, shocked_targets) - - else if(closest_structure) - closest_structure.tesla_act(power, tesla_flags, shocked_targets) +#undef BIKE +#undef COIL +#undef ROD +#undef RIDE +#undef LIVING +#undef MACHINERY +#undef BLOB +#undef STRUCTURE diff --git a/code/modules/power/tesla/generator.dm b/code/modules/power/tesla/generator.dm index 53d7010806..260f4128bc 100644 --- a/code/modules/power/tesla/generator.dm +++ b/code/modules/power/tesla/generator.dm @@ -5,6 +5,6 @@ icon_state = "TheSingGen" creation_type = /obj/singularity/energy_ball -/obj/machinery/the_singularitygen/tesla/tesla_act(power, tesla_flags) - if(tesla_flags & TESLA_MACHINE_EXPLOSIVE) +/obj/machinery/the_singularitygen/tesla/zap_act(power, zap_flags) + if(zap_flags & ZAP_MACHINE_EXPLOSIVE) energy += power diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm index 848163d658..1a6786524c 100644 --- a/code/modules/projectiles/ammunition/_firing.dm +++ b/code/modules/projectiles/ammunition/_firing.dm @@ -31,6 +31,10 @@ else BB.def_zone = user.zone_selected BB.suppressed = quiet + + if(isgun(fired_from)) + var/obj/item/gun/G = fired_from + BB.damage *= G.projectile_damage_multiplier if(reagents && BB.reagents) reagents.trans_to(BB, reagents.total_volume) //For chemical darts/bullets diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 9c1a23174e..cf9e606ffc 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -76,6 +76,9 @@ var/datum/action/item_action/toggle_scope_zoom/azoom var/dualwield_spread_mult = 1 //dualwield spread multiplier + + /// Just 'slightly' snowflakey way to modify projectile damage for projectiles fired from this gun. + var/projectile_damage_multiplier = 1 /obj/item/gun/Initialize() . = ..() diff --git a/code/modules/projectiles/guns/ballistic/bow.dm b/code/modules/projectiles/guns/ballistic/bow.dm index 3f3d2c6f47..4bd7d34fe2 100644 --- a/code/modules/projectiles/guns/ballistic/bow.dm +++ b/code/modules/projectiles/guns/ballistic/bow.dm @@ -59,7 +59,7 @@ /obj/item/gun/ballistic/bow/pipe name = "pipe bow" - desc = "Some sort of pipe made projectile weapon made of a silk string and lots of bending. Used to fire arrows." + desc = "Some sort of pipe made projectile weapon made of a durathread string and lots of bending. Used to fire arrows." icon_state = "pipebow" item_state = "pipebow" force = 0 diff --git a/code/modules/projectiles/projectile/energy/tesla.dm b/code/modules/projectiles/projectile/energy/tesla.dm index 2439cee429..1afbdeae25 100644 --- a/code/modules/projectiles/projectile/energy/tesla.dm +++ b/code/modules/projectiles/projectile/energy/tesla.dm @@ -3,7 +3,7 @@ icon_state = "tesla_projectile" impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser var/chain - var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE + var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE var/zap_range = 3 var/power = 10000 @@ -15,7 +15,7 @@ /obj/item/projectile/energy/tesla/on_hit(atom/target) . = ..() - tesla_zap(target, zap_range, power, tesla_flags) + tesla_zap(target, zap_range, power, zap_flags) qdel(src) /obj/item/projectile/energy/tesla/Destroy() diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index ff6340bcdb..dbb1497367 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -437,9 +437,9 @@ speed = 0.3 flag = "magic" - var/tesla_power = 20000 - var/tesla_range = 15 - var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_MOB_STUN | TESLA_OBJ_DAMAGE + var/zap_power = 20000 + var/zap_range = 15 + var/zap_flags = ZAP_MOB_DAMAGE | ZAP_MOB_STUN | ZAP_OBJ_DAMAGE var/chain var/mob/living/caster @@ -456,7 +456,7 @@ visible_message("[src] fizzles on contact with [target]!") qdel(src) return BULLET_ACT_BLOCK - tesla_zap(src, tesla_range, tesla_power, tesla_flags) + tesla_zap(src, zap_range, zap_power, zap_flags) qdel(src) /obj/item/projectile/magic/aoe/lightning/Destroy() diff --git a/code/modules/projectiles/projectile/special/hallucination.dm b/code/modules/projectiles/projectile/special/hallucination.dm index 5c65571ab0..19fd13857a 100644 --- a/code/modules/projectiles/projectile/special/hallucination.dm +++ b/code/modules/projectiles/projectile/special/hallucination.dm @@ -50,7 +50,7 @@ if(M == hal_target) to_chat(hal_target, "[M] is hit by \a [src] in the chest!") hal_apply_effect() - else if(M in hal_target.visible_atoms()) + else if(M in hal_target.fov_view()) to_chat(hal_target, "[M] is hit by \a [src] in the chest!!") if(damage_type == BRUTE) var/splatter_dir = dir diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 7182f13646..38aafc665f 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -535,7 +535,7 @@ add_reagent(P, cached_results[P]*multiplier, null, chem_temp) - var/list/seen = get_actual_viewers(4, get_turf(my_atom))//Sound and sight checkers + var/list/seen = fov_viewers(4, get_turf(my_atom))//Sound and sight checkers var/iconhtml = icon2html(cached_my_atom, seen) if(cached_my_atom) if(!ismob(cached_my_atom)) // No bubbling mobs diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm index 25315f457d..38a05cd541 100644 --- a/code/modules/reagents/chemistry/machinery/pandemic.dm +++ b/code/modules/reagents/chemistry/machinery/pandemic.dm @@ -170,7 +170,7 @@ if(!A.mutable) return if(A) - var/new_name = sanitize_name(html_encode(params["name"])) + var/new_name = sanitize_name(html_encode(trim(params["name"], 50))) if(!new_name || ..()) return A.AssignName(new_name) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 7913b24218..b51e28decf 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -274,7 +274,11 @@ /datum/reagent/medicine/silver_sulfadiazine/overdose_start(mob/living/M) metabolization_rate = 15 * REAGENTS_METABOLISM - M.adjustBruteLoss(2*REM, 0) + ..() + . = 1 + +/datum/reagent/medicine/silver_sulfadiazine/overdose_process(mob/living/M) + M.adjustFireLoss(2*REM, 0) var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER) if(L) L.applyOrganDamage(1) @@ -340,8 +344,12 @@ ..() . = 1 -datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M) +/datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M) metabolization_rate = 15 * REAGENTS_METABOLISM + ..() + . = 1 + +/datum/reagent/medicine/styptic_powder/overdose_process(mob/living/M) M.adjustBruteLoss(2*REM, 0) var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER) if(L) diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm index 67ff61610d..50d94a637e 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm @@ -227,6 +227,18 @@ playsound(M, "sparks", 50, 1) ..() +/datum/reagent/teslium/on_mob_metabolize(mob/living/carbon/human/L) + . = ..() + if(!istype(L)) + return + L.physiology.siemens_coeff *= 2 + +/datum/reagent/teslium/on_mob_end_metabolize(mob/living/carbon/human/L) + . = ..() + if(!istype(L)) + return + L.physiology.siemens_coeff *= 0.5 + /datum/reagent/teslium/energized_jelly name = "Energized Jelly" description = "Electrically-charged jelly. Boosts jellypeople's nervous system, but only shocks other lifeforms." diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index 8782d65f76..1d06aaacde 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -429,7 +429,7 @@ noexplosion = TRUE mix_message = "The teslium starts to spark as electricity arcs away from it!" mix_sound = 'sound/machines/defib_zap.ogg' - var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN + var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN /datum/chemical_reaction/reagent_explosion/teslium_lightning/on_reaction(datum/reagents/holder, multiplier) var/T1 = multiplier * 20 //100 units : Zap 3 times, with powers 2000/5000/12000. Tesla revolvers have a power of 10000 for comparison. @@ -437,15 +437,15 @@ var/T3 = multiplier * 120 sleep(5) if(multiplier >= 75) - tesla_zap(holder.my_atom, 7, T1, tesla_flags) + tesla_zap(holder.my_atom, 7, T1, zap_flags) playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1) sleep(15) if(multiplier >= 40) - tesla_zap(holder.my_atom, 7, T2, tesla_flags) + tesla_zap(holder.my_atom, 7, T2, zap_flags) playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1) sleep(15) if(multiplier >= 10) //10 units minimum for lightning, 40 units for secondary blast, 75 units for tertiary blast. - tesla_zap(holder.my_atom, 7, T3, tesla_flags) + tesla_zap(holder.my_atom, 7, T3, zap_flags) playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1) ..() diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index c8e50667a8..9ef08590a8 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -120,9 +120,10 @@ /obj/structure/reagent_dispensers/fueltank/fire_act(exposed_temperature, exposed_volume) boom() -/obj/structure/reagent_dispensers/fueltank/tesla_act() +/obj/structure/reagent_dispensers/fueltank/zap_act(power, zap_flags, shocked_objects) ..() //extend the zap - boom() + if(ZAP_OBJ_DAMAGE & zap_flags) + boom() /obj/structure/reagent_dispensers/fueltank/bullet_act(obj/item/projectile/P) . = ..() diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm index aed2310a7f..45d3d9da25 100644 --- a/code/modules/recycling/disposal/pipe.dm +++ b/code/modules/recycling/disposal/pipe.dm @@ -14,6 +14,7 @@ max_integrity = 200 armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30) layer = DISPOSAL_PIPE_LAYER // slightly lower than wires and other pipes + plane = ABOVE_WALL_PLANE rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE var/dpdir = NONE // bitmask of pipe directions var/initialize_dirs = NONE // bitflags of pipe directions added on init, see \code\_DEFINES\pipe_construction.dm diff --git a/code/modules/ruins/spaceruin_code/clericsden.dm b/code/modules/ruins/spaceruin_code/clericsden.dm index 67e071b274..7d1fda6740 100644 --- a/code/modules/ruins/spaceruin_code/clericsden.dm +++ b/code/modules/ruins/spaceruin_code/clericsden.dm @@ -27,7 +27,8 @@ melee_damage_lower = 8 melee_damage_upper = 10 retreat_distance = 4 //AI proteons will rapidly move in and out of combat to avoid conflict, but will still target and follow you. - attacktext = "pinches" + attack_verb_continuous = "pinches" + attack_verb_simple = "pinch" environment_smash = ENVIRONMENT_SMASH_WALLS attack_sound = 'sound/weapons/punch2.ogg' playstyle_string = "You are a Proteon. Your abilities in combat are outmatched by most combat constructs, but you are still fast and nimble. Run metal and supplies, and cooperate with your fellow cultists." diff --git a/code/modules/spells/spell_types/aimed.dm b/code/modules/spells/spell_types/aimed.dm index 1a904b1076..8fab4a221d 100644 --- a/code/modules/spells/spell_types/aimed.dm +++ b/code/modules/spells/spell_types/aimed.dm @@ -101,7 +101,7 @@ base_icon_state = "lightning" sound = 'sound/magic/lightningbolt.ogg' active = FALSE - projectile_var_overrides = list("tesla_range" = 15, "tesla_power" = 20000, "tesla_flags" = TESLA_MOB_DAMAGE) + projectile_var_overrides = list("zap_range" = 15, "zap_power" = 20000, "zap_flags" = ZAP_MOB_DAMAGE) active_msg = "You energize your hand with arcane lightning!" deactive_msg = "You let the energy flow out of your hands back into yourself..." projectile_type = /obj/item/projectile/magic/aoe/lightning diff --git a/code/modules/surgery/advanced/bioware/nerve_grounding.dm b/code/modules/surgery/advanced/bioware/nerve_grounding.dm index 99902ff6d6..eb70a838a4 100644 --- a/code/modules/surgery/advanced/bioware/nerve_grounding.dm +++ b/code/modules/surgery/advanced/bioware/nerve_grounding.dm @@ -32,13 +32,11 @@ name = "Grounded Nerves" desc = "Nerves form a safe path for electricity to traverse, protecting the body from electric shocks." mod_type = BIOWARE_NERVES - var/prev_coeff /datum/bioware/grounded_nerves/on_gain() ..() - prev_coeff = owner.physiology.siemens_coeff - owner.physiology.siemens_coeff = 0 + ADD_TRAIT(owner, TRAIT_SHOCKIMMUNE, "grounded_nerves") /datum/bioware/grounded_nerves/on_lose() ..() - owner.physiology.siemens_coeff = prev_coeff + REMOVE_TRAIT(owner, TRAIT_SHOCKIMMUNE, "grounded_nerves") diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 671d31530a..65e53df26f 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -1254,12 +1254,12 @@ if (trigger2 == "speak" || trigger2 == "echo") var/trigger3 = html_decode(stripped_input(user, "Enter the phrase spoken. Abusing this to self antag is bannable.", MAX_MESSAGE_LEN)) E.customTriggers[trigger] = list(trigger2, trigger3) - log_game("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2], to send [trigger3].") + log_reagent("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2], to send [trigger3].") if(findtext(trigger3, "admin")) message_admins("FERMICHEM: [user] maybe be trying to abuse MKUltra by implanting by [H] with [trigger], triggering [trigger2], to send [trigger3].") else E.customTriggers[trigger] = trigger2 - log_game("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2].") + log_reagent("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2].") E.mental_capacity -= 5 addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(E.lewd?"your [E.enthrallGender]":"[E.master]")] whispers you a new trigger."), 5) to_chat(user, "You sucessfully set the trigger word [trigger] in [H]") @@ -1322,7 +1322,7 @@ objective = replacetext(lowertext(objective), "strangle", "meow at") objective = replacetext(lowertext(objective), "suicide", "self-love") message_admins("[H] has been implanted by [user] with the objective [objective].") - log_game("FERMICHEM: [H] has been implanted by [user] with the objective [objective] via MKUltra.") + log_reagent("FERMICHEM: [H] has been implanted by [user] with the objective [objective] via MKUltra.") addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(E.lewd?"Your [E.enthrallGender]":"[E.master]")] whispers you a new objective."), 5) brainwash(H, objective) E.mental_capacity -= 200 @@ -1341,7 +1341,7 @@ var/instill = stripped_input(user, "Instill an emotion in [H].", MAX_MESSAGE_LEN) to_chat(H, "[instill]") to_chat(user, "You sucessfully instill a feeling in [H]") - log_game("FERMICHEM: [H] has been instilled by [user] with [instill] via MKUltra.") + log_reagent("FERMICHEM: [H] has been instilled by [user] with [instill] via MKUltra.") E.cooldown += 1 //RECOGNISE @@ -1455,7 +1455,7 @@ if(message_admins || debug)//Do you want this in? message_admins("[ADMIN_LOOKUPFLW(user)] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].") - log_game("FERMICHEM: [key_name(user)] ckey: [user.key] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].") + log_reagent("FERMICHEM: [key_name(user)] ckey: [user.key] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].") SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have spoken with a velvet voice") //SSblackbox.record_feedback("tally", "Velvet_voice", 1, log_message) If this is on, it fills the thing up and OOFs the server diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index 57661901ae..e287b38ca1 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -57,10 +57,11 @@ surgery.step_in_progress = FALSE return FALSE if(tool) - speed_mod = tool.toolspeed + speed_mod = tool.toolspeed //faster tools mean faster surgeries, but also less experience. if(user.mind) - speed_mod = user.mind.action_skill_mod(/datum/skill/numerical/surgery, speed_mod, THRESHOLD_COMPETENT, FALSE) - if(do_after(user, time * speed_mod, target = target)) + speed_mod = user.mind.action_skill_mod(/datum/skill/numerical/surgery, speed_mod, THRESHOLD_UNTRAINED, FALSE) + var/delay = time * speed_mod + if(do_after(user, delay, target = target)) var/prob_chance = 100 if(implement_type) //this means it isn't a require hand or any item step. prob_chance = implements[implement_type] @@ -68,7 +69,10 @@ if((prob(prob_chance) || (iscyborg(user) && !silicons_obey_prob)) && chem_check(target) && !try_to_fail) if(success(user, target, target_zone, tool, surgery)) - user.mind?.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP) + var/multi = (delay/SKILL_GAIN_DELAY_DIVISOR) + if(repeatable) + multi *= 0.5 //Spammable surgeries award less experience. + user.mind?.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP * multi) advance = TRUE else if(failure(user, target, target_zone, tool, surgery)) diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm index 70252cfb49..a74c9bbab2 100644 --- a/code/modules/tgs/core/core.dm +++ b/code/modules/tgs/core/core.dm @@ -1,11 +1,17 @@ /world/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE) var/current_api = TGS_READ_GLOBAL(tgs) if(current_api) - TGS_ERROR_LOG("TgsNew(): TGS API datum already set ([current_api])! Was TgsNew() called more than once?") + TGS_ERROR_LOG("API datum already set (\ref[current_api] ([current_api]))! Was TgsNew() called more than once?") + return + + if(!(minimum_required_security_level in list(TGS_SECURITY_ULTRASAFE, TGS_SECURITY_SAFE, TGS_SECURITY_TRUSTED))) + TGS_ERROR_LOG("Invalid minimum_required_security_level: [minimum_required_security_level]!") return #ifdef TGS_V3_API - minimum_required_security_level = TGS_SECURITY_TRUSTED + if(minimum_required_security_level != TGS_SECURITY_TRUSTED) + TGS_WARNING_LOG("V3 DMAPI requires trusted security!") + minimum_required_security_level = TGS_SECURITY_TRUSTED #endif var/raw_parameter = world.params[TGS_VERSION_PARAMETER] if(!raw_parameter) @@ -13,7 +19,7 @@ var/datum/tgs_version/version = new(raw_parameter) if(!version.Valid(FALSE)) - TGS_ERROR_LOG("Failed to validate TGS version parameter: [raw_parameter]!") + TGS_ERROR_LOG("Failed to validate DMAPI version parameter: [raw_parameter]!") return var/api_datum @@ -21,18 +27,21 @@ if(3) #ifndef TGS_V3_API TGS_ERROR_LOG("Detected V3 API but TGS_V3_API isn't defined!") + return #else - switch(version.major) + switch(version.minor) if(2) api_datum = /datum/tgs_api/v3210 #endif if(4) - switch(version.major) + switch(version.minor) if(0) api_datum = /datum/tgs_api/v4 + if(5) + api_datum = /datum/tgs_api/v5 var/datum/tgs_version/max_api_version = TgsMaximumAPIVersion(); - if(version.suite != null && version.major != null && version.minor != null && version.patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter) + if(version.suite != null && version.minor != null && version.patch != null && version.deprecated_patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter) TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.") api_datum = /datum/tgs_api/latest @@ -41,20 +50,25 @@ return TGS_INFO_LOG("Activating API for version [version.deprefixed_parameter]") - var/datum/tgs_api/new_api = new api_datum(version) + + if(event_handler && !istype(event_handler)) + TGS_ERROR_LOG("Invalid parameter for event_handler: [event_handler]") + event_handler = null + + var/datum/tgs_api/new_api = new api_datum(event_handler, version) TGS_WRITE_GLOBAL(tgs, new_api) - var/result = new_api.OnWorldNew(event_handler, minimum_required_security_level) + var/result = new_api.OnWorldNew(minimum_required_security_level) if(!result || result == TGS_UNIMPLEMENTED) TGS_WRITE_GLOBAL(tgs, null) TGS_ERROR_LOG("Failed to activate API!") /world/TgsMaximumAPIVersion() - return new /datum/tgs_version("4.0.x.x") + return new /datum/tgs_version("5.x.x") /world/TgsMinimumAPIVersion() - return new /datum/tgs_version("3.2.0.0") + return new /datum/tgs_version("3.2.x") /world/TgsInitializationComplete() var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) @@ -88,6 +102,11 @@ if(api) return api.version +/world/TgsApiVersion() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + return api.ApiVersion() + /world/TgsInstanceName() var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) if(api) diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm index fb2508059a..ccc75fe344 100644 --- a/code/modules/tgs/core/datum.dm +++ b/code/modules/tgs/core/datum.dm @@ -2,13 +2,15 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null) /datum/tgs_api var/datum/tgs_version/version + var/datum/tgs_event_handler/event_handler -/datum/tgs_api/New(datum/tgs_version/version) +/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version) . = ..() + src.event_handler = event_handler src.version = version /datum/tgs_api/latest - parent_type = /datum/tgs_api/v4 + parent_type = /datum/tgs_api/v5 TGS_PROTECT_DATUM(/datum/tgs_api) diff --git a/code/modules/tgs/core/tgs_version.dm b/code/modules/tgs/core/tgs_version.dm index b97745611f..a5dae1241a 100644 --- a/code/modules/tgs/core/tgs_version.dm +++ b/code/modules/tgs/core/tgs_version.dm @@ -5,11 +5,11 @@ suite = text2num(version_bits[1]) if(version_bits.len > 1) - major = text2num(version_bits[2]) + minor = text2num(version_bits[2]) if(version_bits.len > 2) - minor = text2num(version_bits[3]) + patch = text2num(version_bits[3]) if(version_bits.len == 4) - patch = text2num(version_bits[4]) + deprecated_patch = text2num(version_bits[4]) /datum/tgs_version/proc/Valid(allow_wildcards = FALSE) if(suite == null) @@ -19,4 +19,10 @@ return !Wildcard() /datum/tgs_version/Wildcard() - return major == null || minor == null || patch == null + return minor == null || patch == null + +/datum/tgs_version/Equals(datum/tgs_version/other_version) + if(!istype(other_version)) + return FALSE + + return suite == other_version.suite && minor == other_version.minor && patch == other_version.patch && deprecated_patch == other_version.deprecated_patch diff --git a/code/modules/tgs/includes.dm b/code/modules/tgs/includes.dm index 247f1fda5d..b3c1728f34 100644 --- a/code/modules/tgs/includes.dm +++ b/code/modules/tgs/includes.dm @@ -2,9 +2,43 @@ #include "core\core.dm" #include "core\datum.dm" #include "core\tgs_version.dm" + #ifdef TGS_V3_API #include "v3210\api.dm" #include "v3210\commands.dm" #endif + #include "v4\api.dm" #include "v4\commands.dm" + +#include "v5\_defines.dm" +#include "v5\api.dm" +#include "v5\commands.dm" +#include "v5\undef.dm" + +/* +The MIT License + +Copyright (c) 2017 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgs/v3210/api.dm b/code/modules/tgs/v3210/api.dm index c536995b04..0fc0076c8b 100644 --- a/code/modules/tgs/v3210/api.dm +++ b/code/modules/tgs/v3210/api.dm @@ -39,7 +39,7 @@ var/warned_custom_commands = FALSE /datum/tgs_api/v3210/ApiVersion() - return "3.2.1.0" + return new /datum/tgs_version("3.2.1.0") /datum/tgs_api/v3210/proc/trim_left(text) for (var/i = 1 to length(text)) @@ -56,7 +56,7 @@ /datum/tgs_api/v3210/proc/file2list(filename) return splittext(trim_left(trim_right(file2text(filename))), "\n") -/datum/tgs_api/v3210/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level) //don't use event handling in this version +/datum/tgs_api/v3210/OnWorldNew(minimum_required_security_level) . = FALSE comms_key = world.params[SERVICE_WORLD_PARAM] @@ -76,7 +76,8 @@ TGS_ERROR_LOG("This API version is only supported on Windows. Not running on Windows. Aborting initialization!") return ListServiceCustomCommands(TRUE) - ExportService("[SERVICE_REQUEST_API_VERSION] [ApiVersion()]", TRUE) + var/datum/tgs_version/api_version = ApiVersion() + ExportService("[SERVICE_REQUEST_API_VERSION] [api_version.deprefixed_parameter]", TRUE) return TRUE //nothing to do for v3 @@ -166,7 +167,8 @@ /datum/tgs_api/v3210/Revision() if(!warned_revison) - TGS_ERROR_LOG("Use of TgsRevision on [ApiVersion()] origin_commit only points to master!") + var/datum/tgs_version/api_version = ApiVersion() + TGS_ERROR_LOG("Use of TgsRevision on [api_version.deprefixed_parameter] origin_commit only points to master!") warned_revison = TRUE var/datum/tgs_revision_information/ri = new ri.commit = commit diff --git a/code/modules/tgs/v3210/commands.dm b/code/modules/tgs/v3210/commands.dm index e5bc6f4895..5046631981 100644 --- a/code/modules/tgs/v3210/commands.dm +++ b/code/modules/tgs/v3210/commands.dm @@ -19,7 +19,7 @@ TGS_ERROR_LOG("Custom command [command_name] can't be used as it is empty or contains illegal characters!") warned_command_names[command_name] = TRUE continue - + if(command_name_types[command_name]) if(warnings_only) TGS_ERROR_LOG("Custom commands [command_name_types[command_name]] and [stc] have the same name, only [command_name_types[command_name]] will be available!") @@ -55,24 +55,24 @@ The MIT License Copyright (c) 2017 Jordan Brown -Permission is hereby granted, free of charge, -to any person obtaining a copy of this software and -associated documentation files (the "Software"), to -deal in the Software without restriction, including -without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom -the Software is furnished to do so, +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ diff --git a/code/modules/tgs/v4/api.dm b/code/modules/tgs/v4/api.dm index b61cddbeba..ba18aab688 100644 --- a/code/modules/tgs/v4/api.dm +++ b/code/modules/tgs/v4/api.dm @@ -43,15 +43,13 @@ var/list/cached_test_merges var/datum/tgs_revision_information/cached_revision - var/datum/tgs_event_handler/event_handler - var/export_lock = FALSE var/list/last_interop_response /datum/tgs_api/v4/ApiVersion() - return "4.0.0.0" + return new /datum/tgs_version("4.0.0.0") -/datum/tgs_api/v4/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level) +/datum/tgs_api/v4/OnWorldNew(minimum_required_security_level) json_path = world.params[TGS4_PARAM_INFO_JSON] if(!json_path) TGS_ERROR_LOG("Missing [TGS4_PARAM_INFO_JSON] world parameter!") @@ -76,7 +74,6 @@ security_level = cached_json["securityLevel"] chat_channels_json_path = cached_json["chatChannelsJson"] chat_commands_json_path = cached_json["chatCommandsJson"] - src.event_handler = event_handler instance_name = cached_json["instanceName"] ListCustomCommands() diff --git a/code/modules/tgs/v4/commands.dm b/code/modules/tgs/v4/commands.dm index af21a86fb6..1d9951bc04 100644 --- a/code/modules/tgs/v4/commands.dm +++ b/code/modules/tgs/v4/commands.dm @@ -46,24 +46,24 @@ The MIT License Copyright (c) 2017 Jordan Brown -Permission is hereby granted, free of charge, -to any person obtaining a copy of this software and -associated documentation files (the "Software"), to -deal in the Software without restriction, including -without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom -the Software is furnished to do so, +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ diff --git a/code/modules/tgs/v5/_defines.dm b/code/modules/tgs/v5/_defines.dm new file mode 100644 index 0000000000..2baf3e12d7 --- /dev/null +++ b/code/modules/tgs/v5/_defines.dm @@ -0,0 +1,124 @@ +#define DMAPI5_PARAM_SERVER_PORT "tgs_port" +#define DMAPI5_PARAM_ACCESS_IDENTIFIER "tgs_key" + +#define DMAPI5_BRIDGE_DATA "data" +#define DMAPI5_TOPIC_DATA "tgs_data" + +#define DMAPI5_BRIDGE_COMMAND_PORT_UPDATE 0 +#define DMAPI5_BRIDGE_COMMAND_STARTUP 1 +#define DMAPI5_BRIDGE_COMMAND_PRIME 2 +#define DMAPI5_BRIDGE_COMMAND_REBOOT 3 +#define DMAPI5_BRIDGE_COMMAND_KILL 4 +#define DMAPI5_BRIDGE_COMMAND_CHAT_SEND 5 + +#define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier" +#define DMAPI5_RESPONSE_ERROR_MESSAGE "errorMessage" + +#define DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE "commandType" +#define DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT "currentPort" +#define DMAPI5_BRIDGE_PARAMETER_VERSION "version" +#define DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE "chatMessage" +#define DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS "customCommands" +#define DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL "minimumSecurityLevel" + +#define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort" +#define DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION "runtimeInformation" + +#define DMAPI5_CHAT_MESSAGE_TEXT "text" +#define DMAPI5_CHAT_MESSAGE_CHANNEL_IDS "channelIds" + +#define DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER "accessIdentifier" +#define DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION "serverVersion" +#define DMAPI5_RUNTIME_INFORMATION_SERVER_PORT "serverPort" +#define DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY "apiValidateOnly" +#define DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME "instanceName" +#define DMAPI5_RUNTIME_INFORMATION_REVISION "revision" +#define DMAPI5_RUNTIME_INFORMATION_TEST_MERGES "testMerges" +#define DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL "securityLevel" + +#define DMAPI5_CHAT_UPDATE_CHANNELS "channels" + +#define DMAPI5_TEST_MERGE_TIME_MERGED "timeMerged" +#define DMAPI5_TEST_MERGE_REVISION "revision" +#define DMAPI5_TEST_MERGE_TITLE_AT_MERGE "titleAtMerge" +#define DMAPI5_TEST_MERGE_BODY_AT_MERGE "bodyAtMerge" +#define DMAPI5_TEST_MERGE_URL "url" +#define DMAPI5_TEST_MERGE_AUTHOR "author" +#define DMAPI5_TEST_MERGE_NUMBER "number" +#define DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION "pullRequestRevision" +#define DMAPI5_TEST_MERGE_COMMENT "comment" + +#define DMAPI5_CHAT_COMMAND_NAME "name" +#define DMAPI5_CHAT_COMMAND_PARAMS "params" +#define DMAPI5_CHAT_COMMAND_USER "user" + +#define DMAPI5_EVENT_NOTIFICATION_TYPE "type" +#define DMAPI5_EVENT_NOTIFICATION_PARAMETERS "parameters" + +#define DMAPI5_TOPIC_COMMAND_CHAT_COMMAND 0 +#define DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION 1 +#define DMAPI5_TOPIC_COMMAND_CHANGE_PORT 2 +#define DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE 3 +#define DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED 4 +#define DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE 5 +#define DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE 6 +#define DMAPI5_TOPIC_COMMAND_HEARTBEAT 7 +#define DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH 8 + +#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType" +#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand" +#define DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION "eventNotification" +#define DMAPI5_TOPIC_PARAMETER_NEW_PORT "newPort" +#define DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE "newRebootState" +#define DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME "newInstanceName" +#define DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE "chatUpdate" +#define DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION "newServerVersion" + +#define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE "commandResponseMessage" +#define DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES "chatResponses" + +#define DMAPI5_REVISION_INFORMATION_COMMIT_SHA "commitSha" +#define DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA "originCommitSha" + +#define DMAPI5_CHAT_USER_ID "id" +#define DMAPI5_CHAT_USER_FRIENDLY_NAME "friendlyName" +#define DMAPI5_CHAT_USER_MENTION "mention" +#define DMAPI5_CHAT_USER_CHANNEL "channel" + +#define DMAPI5_CHAT_CHANNEL_ID "id" +#define DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME "friendlyName" +#define DMAPI5_CHAT_CHANNEL_CONNECTION_NAME "connectionName" +#define DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL "isAdminChannel" +#define DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL "isPrivateChannel" +#define DMAPI5_CHAT_CHANNEL_TAG "tag" + +#define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name" +#define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText" +#define DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY "adminOnly" + +/* +The MIT License + +Copyright (c) 2020 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm new file mode 100644 index 0000000000..eedefb2877 --- /dev/null +++ b/code/modules/tgs/v5/api.dm @@ -0,0 +1,372 @@ +/datum/tgs_api/v5 + var/server_port + var/access_identifier + + var/instance_name + var/security_level + + var/reboot_mode = TGS_REBOOT_MODE_NORMAL + + var/list/intercepted_message_queue + + var/list/custom_commands + + var/list/test_merges + var/datum/tgs_revision_information/revision + var/list/chat_channels + +/datum/tgs_api/v5/ApiVersion() + return new /datum/tgs_version("5.1.1") + +/datum/tgs_api/v5/OnWorldNew(minimum_required_security_level) + server_port = world.params[DMAPI5_PARAM_SERVER_PORT] + access_identifier = world.params[DMAPI5_PARAM_ACCESS_IDENTIFIER] + + var/datum/tgs_version/api_version = ApiVersion() + version = null + var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands())) + if(!istype(bridge_response)) + TGS_ERROR_LOG("Failed initial bridge request!") + return FALSE + + var/list/runtime_information = bridge_response[DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION] + if(!istype(runtime_information)) + TGS_ERROR_LOG("Failed to decode runtime information from bridge response: [json_encode(bridge_response)]!") + return FALSE + + if(runtime_information[DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY]) + TGS_INFO_LOG("DMAPI validation, exiting...") + del(world) + + version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION]) + security_level = runtime_information[DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL] + instance_name = runtime_information[DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME] + + var/list/revisionData = runtime_information[DMAPI5_RUNTIME_INFORMATION_REVISION] + if(istype(revisionData)) + revision = new + revision.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA] + revision.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA] + else + TGS_ERROR_LOG("Failed to decode [DMAPI5_RUNTIME_INFORMATION_REVISION] from runtime information!") + + test_merges = list() + var/list/test_merge_json = runtime_information[DMAPI5_RUNTIME_INFORMATION_TEST_MERGES] + if(istype(test_merge_json)) + for(var/entry in test_merge_json) + var/datum/tgs_revision_information/test_merge/tm = new + tm.number = entry[DMAPI5_TEST_MERGE_NUMBER] + + var/list/revInfo = entry[DMAPI5_TEST_MERGE_REVISION] + if(revInfo) + tm.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA] + tm.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA] + else + TGS_WARNING_LOG("Failed to decode [DMAPI5_TEST_MERGE_REVISION] from test merge #[tm.number]!") + + tm.time_merged = text2num(entry[DMAPI5_TEST_MERGE_TIME_MERGED]) + tm.title = entry[DMAPI5_TEST_MERGE_TITLE_AT_MERGE] + tm.body = entry[DMAPI5_TEST_MERGE_BODY_AT_MERGE] + tm.url = entry[DMAPI5_TEST_MERGE_URL] + tm.author = entry[DMAPI5_TEST_MERGE_AUTHOR] + tm.pull_request_commit = entry[DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION] + tm.comment = entry[DMAPI5_TEST_MERGE_COMMENT] + + test_merges += tm + else + TGS_WARNING_LOG("Failed to decode [DMAPI5_RUNTIME_INFORMATION_TEST_MERGES] from runtime information!") + + chat_channels = list() + DecodeChannels(runtime_information) + + return TRUE + +/datum/tgs_api/v5/proc/RequireInitialBridgeResponse() + while(!version) + sleep(1) + +/datum/tgs_api/v5/OnInitializationComplete() + Bridge(DMAPI5_BRIDGE_COMMAND_PRIME) + + var/tgs4_secret_sleep_offline_sauce = 29051994 + var/old_sleep_offline = world.sleep_offline + world.sleep_offline = tgs4_secret_sleep_offline_sauce + sleep(1) + if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it + world.sleep_offline = old_sleep_offline + +/datum/tgs_api/v5/proc/TopicResponse(error_message = null) + var/list/response = list() + response[DMAPI5_RESPONSE_ERROR_MESSAGE] = error_message + + return json_encode(response) + +/datum/tgs_api/v5/OnTopic(T) + var/list/params = params2list(T) + var/json = params[DMAPI5_TOPIC_DATA] + if(!json) + return FALSE //continue world/Topic + + var/list/topic_parameters = json_decode(json) + if(!topic_parameters) + return TopicResponse("Invalid topic parameters json!"); + + var/their_sCK = topic_parameters[DMAPI5_PARAMETER_ACCESS_IDENTIFIER] + if(their_sCK != access_identifier) + return TopicResponse("Failed to decode [DMAPI5_PARAMETER_ACCESS_IDENTIFIER] from: [json]!"); + + var/command = topic_parameters[DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE] + if(!isnum(command)) + return TopicResponse("Failed to decode [DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE] from: [json]!") + + switch(command) + if(DMAPI5_TOPIC_COMMAND_CHAT_COMMAND) + var/result = HandleCustomCommand(topic_parameters[DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND]) + if(!result) + result = TopicResponse("Error running chat command!") + return result + if(DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION) + intercepted_message_queue = list() + var/list/event_notification = topic_parameters[DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION] + if(!istype(event_notification)) + return TopicResponse("Invalid [DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION]!") + + var/event_type = event_notification[DMAPI5_EVENT_NOTIFICATION_TYPE] + if(!isnum(event_type)) + return TopicResponse("Invalid or missing [DMAPI5_EVENT_NOTIFICATION_TYPE]!") + + var/list/event_parameters = event_notification[DMAPI5_EVENT_NOTIFICATION_PARAMETERS] + if(event_parameters && !istype(event_parameters)) + return TopicResponse("Invalid or missing [DMAPI5_EVENT_NOTIFICATION_PARAMETERS]!") + + var/list/event_call = list(event_type) + if(event_parameters) + event_call += event_parameters + + if(event_handler != null) + event_handler.HandleEvent(arglist(event_call)) + + var/list/response = list() + response[DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES] = intercepted_message_queue + intercepted_message_queue = null + return json_encode(response) + if(DMAPI5_TOPIC_COMMAND_CHANGE_PORT) + var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT] + if (!isnum(new_port) || !(new_port > 0)) + return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]") + + if(event_handler != null) + event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port) + + //the topic still completes, miraculously + //I honestly didn't believe byond could do it without exploding + if(!world.OpenPort(new_port)) + return TopicResponse("Port change failed!") + + return TopicResponse() + if(DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE) + var/new_reboot_mode = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE] + if(!isnum(new_reboot_mode)) + return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE]!") + + if(event_handler != null) + event_handler.HandleEvent(TGS_EVENT_REBOOT_MODE_CHANGE, reboot_mode, new_reboot_mode) + + reboot_mode = new_reboot_mode + return TopicResponse() + if(DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED) + var/new_instance_name = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME] + if(!istext(new_instance_name)) + return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME]!") + + if(event_handler != null) + event_handler.HandleEvent(TGS_EVENT_INSTANCE_RENAMED, new_instance_name) + + instance_name = new_instance_name + return TopicResponse() + if(DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE) + var/list/chat_update_json = topic_parameters[DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE] + if(!istype(chat_update_json)) + return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE]!") + + DecodeChannels(chat_update_json) + return TopicResponse() + if(DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE) + var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT] + if (!isnum(new_port) || !(new_port > 0)) + return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]") + + server_port = new_port + return TopicResponse() + if(DMAPI5_TOPIC_COMMAND_HEARTBEAT) + return TopicResponse() + if(DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH) + var/new_version_string = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION] + if (!istext(new_version_string)) + return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION]]") + + var/datum/tgs_version/new_version = new(new_version_string) + if (event_handler) + event_handler.HandleEvent(TGS_EVENT_WATCHDOG_REATTACH, new_version) + + version = new_version + + return TopicResponse() + + return TopicResponse("Unknown command: [command]") + +/datum/tgs_api/v5/proc/Bridge(command, list/data) + if(!data) + data = list() + + data[DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE] = command + data[DMAPI5_PARAMETER_ACCESS_IDENTIFIER] = access_identifier + + var/json = json_encode(data) + var/encoded_json = url_encode(json) + + // This is an infinite sleep until we get a response + var/export_response = world.Export("http://127.0.0.1:[server_port]/Bridge?[DMAPI5_BRIDGE_DATA]=[encoded_json]") + if(!export_response) + TGS_ERROR_LOG("Failed export request: [json]") + return + + var/response_json = file2text(export_response["CONTENT"]) + if(!response_json) + TGS_ERROR_LOG("Failed export request, missing content!") + return + + var/list/bridge_response = json_decode(response_json) + if(!bridge_response) + TGS_ERROR_LOG("Failed export request, bad json: [response_json]") + return + + var/error = bridge_response[DMAPI5_RESPONSE_ERROR_MESSAGE] + if(error) + TGS_ERROR_LOG("Failed export request, bad request: [error]") + return + + return bridge_response + +/datum/tgs_api/v5/OnReboot() + var/list/result = Bridge(DMAPI5_BRIDGE_COMMAND_REBOOT) + if(!result) + return + + //okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter + + var/port = result[DMAPI5_BRIDGE_RESPONSE_NEW_PORT] + if(!isnum(port)) + return //this is valid, server may just want use to reboot + + if(port == 0) + //to byond 0 means any port and "none" means close vOv + port = "none" + + if(!world.OpenPort(port)) + TGS_ERROR_LOG("Unable to set port to [port]!") + +/datum/tgs_api/v5/InstanceName() + RequireInitialBridgeResponse() + return instance_name + +/datum/tgs_api/v5/TestMerges() + RequireInitialBridgeResponse() + return test_merges + +/datum/tgs_api/v5/EndProcess() + Bridge(DMAPI5_BRIDGE_COMMAND_KILL) + +/datum/tgs_api/v5/Revision() + RequireInitialBridgeResponse() + return revision + +/datum/tgs_api/v5/ChatBroadcast(message, list/channels) + if(!length(channels)) + channels = ChatChannelInfo() + + var/list/ids = list() + for(var/I in channels) + var/datum/tgs_chat_channel/channel = I + ids += channel.id + + message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = ids) + if(intercepted_message_queue) + intercepted_message_queue += list(message) + else + Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message)) + +/datum/tgs_api/v5/ChatTargetedBroadcast(message, admin_only) + var/list/channels = list() + for(var/I in ChatChannelInfo()) + var/datum/tgs_chat_channel/channel = I + if (!channel.is_private_channel && ((channel.is_admin_channel && admin_only) || (!channel.is_admin_channel && !admin_only))) + channels += channel.id + message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = channels) + if(intercepted_message_queue) + intercepted_message_queue += list(message) + else + Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message)) + +/datum/tgs_api/v5/ChatPrivateMessage(message, datum/tgs_chat_user/user) + message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = list(user.channel.id)) + if(intercepted_message_queue) + intercepted_message_queue += list(message) + else + Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message)) + +/datum/tgs_api/v5/ChatChannelInfo() + RequireInitialBridgeResponse() + return chat_channels + +/datum/tgs_api/v5/proc/DecodeChannels(chat_update_json) + var/list/chat_channels_json = chat_update_json[DMAPI5_CHAT_UPDATE_CHANNELS] + if(istype(chat_channels_json)) + chat_channels.Cut() + for(var/channel_json in chat_channels_json) + var/datum/tgs_chat_channel/channel = DecodeChannel(channel_json) + if(channel) + chat_channels += channel + else + TGS_WARNING_LOG("Failed to decode [DMAPI5_CHAT_UPDATE_CHANNELS] from channel update!") + +/datum/tgs_api/v5/proc/DecodeChannel(channel_json) + var/datum/tgs_chat_channel/channel = new + channel.id = channel_json[DMAPI5_CHAT_CHANNEL_ID] + channel.friendly_name = channel_json[DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME] + channel.connection_name = channel_json[DMAPI5_CHAT_CHANNEL_CONNECTION_NAME] + channel.is_admin_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL] + channel.is_private_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL] + channel.custom_tag = channel_json[DMAPI5_CHAT_CHANNEL_TAG] + return channel + +/datum/tgs_api/v5/SecurityLevel() + RequireInitialBridgeResponse() + return security_level + +/* +The MIT License + +Copyright (c) 2020 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgs/v5/commands.dm b/code/modules/tgs/v5/commands.dm new file mode 100644 index 0000000000..2775157656 --- /dev/null +++ b/code/modules/tgs/v5/commands.dm @@ -0,0 +1,68 @@ +/datum/tgs_api/v5/proc/ListCustomCommands() + var/results = list() + custom_commands = list() + for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command) + var/datum/tgs_chat_command/stc = new I + var/command_name = stc.name + if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\"")) + TGS_WARNING_LOG("Custom command [command_name] ([I]) can't be used as it is empty or contains illegal characters!") + continue + + if(results[command_name]) + var/datum/other = custom_commands[command_name] + TGS_WARNING_LOG("Custom commands [other.type] and [I] have the same name (\"[command_name]\"), only [other.type] will be available!") + continue + results += list(list(DMAPI5_CUSTOM_CHAT_COMMAND_NAME = command_name, DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT = stc.help_text, DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY = stc.admin_only)) + custom_commands[command_name] = stc + + return results + +/datum/tgs_api/v5/proc/HandleCustomCommand(list/command_json) + var/command = command_json[DMAPI5_CHAT_COMMAND_NAME] + var/user = command_json[DMAPI5_CHAT_COMMAND_USER] + var/params = command_json[DMAPI5_CHAT_COMMAND_PARAMS] + + var/datum/tgs_chat_user/u = new + u.id = user[DMAPI5_CHAT_USER_ID] + u.friendly_name = user[DMAPI5_CHAT_USER_FRIENDLY_NAME] + u.mention = user[DMAPI5_CHAT_USER_MENTION] + u.channel = DecodeChannel(user[DMAPI5_CHAT_USER_CHANNEL]) + + var/datum/tgs_chat_command/sc = custom_commands[command] + if(sc) + var/text_response = sc.Run(u, params) + var/list/topic_response = list() + if(!istext(text_response)) + TGS_ERROR_LOG("Custom command [command] should return a string! Got: \"[text_response]\"") + text_response = null + topic_response[DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE] = text_response + return json_encode(topic_response) + return TopicResponse("Unknown custom chat command: [command]!") + +/* + +The MIT License + +Copyright (c) 2020 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgs/v5/undef.dm b/code/modules/tgs/v5/undef.dm new file mode 100644 index 0000000000..b27e3abe95 --- /dev/null +++ b/code/modules/tgs/v5/undef.dm @@ -0,0 +1,124 @@ +#undef DMAPI5_PARAM_SERVER_PORT +#undef DMAPI5_PARAM_ACCESS_IDENTIFIER + +#undef DMAPI5_BRIDGE_DATA +#undef DMAPI5_TOPIC_DATA + +#undef DMAPI5_BRIDGE_COMMAND_PORT_UPDATE +#undef DMAPI5_BRIDGE_COMMAND_STARTUP +#undef DMAPI5_BRIDGE_COMMAND_PRIME +#undef DMAPI5_BRIDGE_COMMAND_REBOOT +#undef DMAPI5_BRIDGE_COMMAND_KILL +#undef DMAPI5_BRIDGE_COMMAND_CHAT_SEND + +#undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER +#undef DMAPI5_RESPONSE_ERROR_MESSAGE + +#undef DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE +#undef DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT +#undef DMAPI5_BRIDGE_PARAMETER_VERSION +#undef DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE +#undef DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS +#undef DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL + +#undef DMAPI5_BRIDGE_RESPONSE_NEW_PORT +#undef DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION + +#undef DMAPI5_CHAT_MESSAGE_TEXT +#undef DMAPI5_CHAT_MESSAGE_CHANNEL_IDS + +#undef DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER +#undef DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION +#undef DMAPI5_RUNTIME_INFORMATION_SERVER_PORT +#undef DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY +#undef DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME +#undef DMAPI5_RUNTIME_INFORMATION_REVISION +#undef DMAPI5_RUNTIME_INFORMATION_TEST_MERGES +#undef DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL + +#undef DMAPI5_CHAT_UPDATE_CHANNELS + +#undef DMAPI5_TEST_MERGE_TIME_MERGED +#undef DMAPI5_TEST_MERGE_REVISION +#undef DMAPI5_TEST_MERGE_TITLE_AT_MERGE +#undef DMAPI5_TEST_MERGE_BODY_AT_MERGE +#undef DMAPI5_TEST_MERGE_URL +#undef DMAPI5_TEST_MERGE_AUTHOR +#undef DMAPI5_TEST_MERGE_NUMBER +#undef DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION +#undef DMAPI5_TEST_MERGE_COMMENT + +#undef DMAPI5_CHAT_COMMAND_NAME +#undef DMAPI5_CHAT_COMMAND_PARAMS +#undef DMAPI5_CHAT_COMMAND_USER + +#undef DMAPI5_EVENT_NOTIFICATION_TYPE +#undef DMAPI5_EVENT_NOTIFICATION_PARAMETERS + +#undef DMAPI5_TOPIC_COMMAND_CHAT_COMMAND +#undef DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION +#undef DMAPI5_TOPIC_COMMAND_CHANGE_PORT +#undef DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE +#undef DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED +#undef DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE +#undef DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE +#undef DMAPI5_TOPIC_COMMAND_HEARTBEAT +#undef DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH + +#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE +#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND +#undef DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION +#undef DMAPI5_TOPIC_PARAMETER_NEW_PORT +#undef DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE +#undef DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME +#undef DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE +#undef DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION + +#undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE +#undef DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES + +#undef DMAPI5_REVISION_INFORMATION_COMMIT_SHA +#undef DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA + +#undef DMAPI5_CHAT_USER_ID +#undef DMAPI5_CHAT_USER_FRIENDLY_NAME +#undef DMAPI5_CHAT_USER_MENTION +#undef DMAPI5_CHAT_USER_CHANNEL + +#undef DMAPI5_CHAT_CHANNEL_ID +#undef DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME +#undef DMAPI5_CHAT_CHANNEL_CONNECTION_NAME +#undef DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL +#undef DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL +#undef DMAPI5_CHAT_CHANNEL_TAG + +#undef DMAPI5_CUSTOM_CHAT_COMMAND_NAME +#undef DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT +#undef DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY + +/* +The MIT License + +Copyright (c) 2020 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm index 33fc4d8703..723e5f90ed 100644 --- a/code/modules/tgui/states.dm +++ b/code/modules/tgui/states.dm @@ -99,7 +99,7 @@ * return UI_state The state of the UI. **/ /mob/living/proc/shared_living_ui_distance(atom/movable/src_object) - if(!(src_object in visible_atoms())) // If the object is obscured, close it. + if(!(src_object in fov_view())) // If the object is obscured, close it. return UI_CLOSE var/dist = get_dist(src_object, src) diff --git a/code/modules/tgui/states/physical.dm b/code/modules/tgui/states/physical.dm index a4cea7c7c2..3b13dc5b3d 100644 --- a/code/modules/tgui/states/physical.dm +++ b/code/modules/tgui/states/physical.dm @@ -2,7 +2,7 @@ * tgui state: physical_state * * Short-circuits the default state to only check physical distance. - **/ + */ GLOBAL_DATUM_INIT(physical_state, /datum/ui_state/physical, new) @@ -22,3 +22,28 @@ GLOBAL_DATUM_INIT(physical_state, /datum/ui_state/physical, new) /mob/living/silicon/ai/physical_can_use_topic(src_object) return UI_UPDATE // AIs are not physical. + +/** + * tgui state: physical_obscured_state + * + * Short-circuits the default state to only check physical distance, being in view doesn't matter + */ + +GLOBAL_DATUM_INIT(physical_obscured_state, /datum/ui_state/physical_obscured_state, new) + +/datum/ui_state/physical_obscured_state/can_use_topic(src_object, mob/user) + . = user.shared_ui_interaction(src_object) + if(. > UI_CLOSE) + return min(., user.physical_obscured_can_use_topic(src_object)) + +/mob/proc/physical_obscured_can_use_topic(src_object) + return UI_CLOSE + +/mob/living/physical_obscured_can_use_topic(src_object) + return shared_living_ui_distance(src_object) + +/mob/living/silicon/physical_obscured_can_use_topic(src_object) + return max(UI_UPDATE, shared_living_ui_distance(src_object)) // Silicons can always see. + +/mob/living/silicon/ai/physical_obscured_can_use_topic(src_object) + return UI_UPDATE // AIs are not physical. \ No newline at end of file diff --git a/code/modules/vehicles/bicycle.dm b/code/modules/vehicles/bicycle.dm index 84e0fcbefc..3784f4d459 100644 --- a/code/modules/vehicles/bicycle.dm +++ b/code/modules/vehicles/bicycle.dm @@ -24,10 +24,12 @@ buckled_mob.stop_sound_channel(CHANNEL_BICYCLE) . =..() -/obj/vehicle/ridden/bicycle/tesla_act() // :::^^^))) +/obj/vehicle/ridden/bicycle/zap_act(zap_str, zap_flags, shocked_targets) // :::^^^))) + //This didn't work for 3 years because none ever tested it I hate life name = "fried bicycle" desc = "Well spent." color = rgb(63, 23, 4) can_buckle = FALSE + . = ..() for(var/m in buckled_mobs) unbuckle_mob(m,1) diff --git a/code/modules/vehicles/ridden.dm b/code/modules/vehicles/ridden.dm index 4f3970dd37..f71d9367d3 100644 --- a/code/modules/vehicles/ridden.dm +++ b/code/modules/vehicles/ridden.dm @@ -77,3 +77,7 @@ if(!force && occupant_amount() >= max_occupants) return FALSE return ..() + +/obj/vehicle/ridden/zap_act(zap_str, zap_flags, shocked_targets) + zap_buckle_check(zap_str) + . = ..() diff --git a/code/modules/vending/dinnerware.dm b/code/modules/vending/dinnerware.dm index e780104b1e..521e76b5e2 100644 --- a/code/modules/vending/dinnerware.dm +++ b/code/modules/vending/dinnerware.dm @@ -20,12 +20,10 @@ /obj/item/reagent_containers/food/condiment/saltshaker = 5, /obj/item/reagent_containers/food/condiment/peppermill = 5) contraband = list( - /obj/item/reagent_containers/food/snacks/cube/monkey= 1, /obj/item/kitchen/knife/butcher = 2, /obj/item/reagent_containers/syringe = 3) premium = list( - /obj/item/reagent_containers/food/condiment/enzyme = 1, - /obj/item/reagent_containers/glass/bottle/cryoxadone = 2) // Bartender can literally make this with upgraded parts, or it gets stolen from medical. + /obj/item/reagent_containers/food/condiment/enzyme = 1) armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) refill_canister = /obj/item/vending_refill/dinnerware resistance_flags = FIRE_PROOF @@ -35,4 +33,4 @@ cost_multiplier_per_dept = list(ACCOUNT_SRV = 0) /obj/item/vending_refill/dinnerware - icon_state = "refill_cook" \ No newline at end of file + icon_state = "refill_cook" diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index a1caca0200..756e546a02 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -49,6 +49,7 @@ /obj/item/storage/backpack/medic = 5, /obj/item/storage/backpack/satchel/med = 5, /obj/item/clothing/suit/hooded/wintercoat/medical = 5, + /obj/item/clothing/suit/hooded/wintercoat/paramedic = 2, /obj/item/clothing/under/rank/medical/doctor/nurse = 5, /obj/item/clothing/head/nursehat = 5, /obj/item/clothing/under/rank/medical/doctor/skirt= 5, diff --git a/code/modules/vore/eating/belly_obj.dm b/code/modules/vore/eating/belly_obj.dm index 685f8d76bb..03d0bbba45 100644 --- a/code/modules/vore/eating/belly_obj.dm +++ b/code/modules/vore/eating/belly_obj.dm @@ -542,7 +542,7 @@ if (!(R in contents)) return // User is not in this belly - R.setClickCooldown(50) + R.changeNext_move(CLICK_CD_BREAKOUT*0.5) if(owner.stat) //If owner is stat (dead, KO) we can actually escape to_chat(R,"You attempt to climb out of \the [lowertext(name)]. (This will take around [escapetime/10] seconds.)") diff --git a/code/modules/vore/eating/living.dm b/code/modules/vore/eating/living.dm index 33f8d78300..a7cc316cc3 100644 --- a/code/modules/vore/eating/living.dm +++ b/code/modules/vore/eating/living.dm @@ -358,6 +358,9 @@ if(incapacitated(ignore_restraints = TRUE)) to_chat(src, "You can't do that while incapacitated.") return + if(next_move > world.time) + to_chat(src, "You can't do that so fast, slow down.") + return var/list/choices for(var/mob/living/L in view(1)) @@ -372,7 +375,7 @@ if(QDELETED(tasted) || (tasted.ckey && !(tasted.client?.prefs.vore_flags & LICKABLE)) || !Adjacent(tasted) || incapacitated(ignore_restraints = TRUE)) return - setClickCooldown(100) + changeNext_move(CLICK_CD_MELEE) visible_message("[src] licks [tasted]!","You lick [tasted]. They taste rather like [tasted.get_taste_message()].","Slurp!") diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi index 85cb1e0c0a..7902487873 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index 803b4aa390..134c03f71b 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/clothing/uniform.dmi b/icons/mob/clothing/uniform.dmi index b717b33c61..e126629b77 100644 Binary files a/icons/mob/clothing/uniform.dmi and b/icons/mob/clothing/uniform.dmi differ diff --git a/icons/mob/inhands/equipment/shields_lefthand.dmi b/icons/mob/inhands/equipment/shields_lefthand.dmi index 24bb824f1d..850bbaa043 100644 Binary files a/icons/mob/inhands/equipment/shields_lefthand.dmi and b/icons/mob/inhands/equipment/shields_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/shields_righthand.dmi b/icons/mob/inhands/equipment/shields_righthand.dmi index 31d84f480c..d4db35b9b2 100644 Binary files a/icons/mob/inhands/equipment/shields_righthand.dmi and b/icons/mob/inhands/equipment/shields_righthand.dmi differ diff --git a/icons/obj/artstuff.dmi b/icons/obj/artstuff.dmi index ea24341f5e..14970b76ef 100644 Binary files a/icons/obj/artstuff.dmi and b/icons/obj/artstuff.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index c88d1ce766..a19627b8ea 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index 607c26bb62..fcfbd36df6 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi index 7ed9244ea4..f66767292c 100644 Binary files a/icons/obj/decals.dmi and b/icons/obj/decals.dmi differ diff --git a/icons/obj/doors/shutters.dmi b/icons/obj/doors/shutters.dmi index 6f10860cfa..816d1f94f9 100644 Binary files a/icons/obj/doors/shutters.dmi and b/icons/obj/doors/shutters.dmi differ diff --git a/icons/obj/doors/shutters_radiation.dmi b/icons/obj/doors/shutters_radiation.dmi index 36d232b197..657b613b0c 100644 Binary files a/icons/obj/doors/shutters_radiation.dmi and b/icons/obj/doors/shutters_radiation.dmi differ diff --git a/icons/obj/doors/shutters_window.dmi b/icons/obj/doors/shutters_window.dmi index 20197593c1..c99790c6cf 100644 Binary files a/icons/obj/doors/shutters_window.dmi and b/icons/obj/doors/shutters_window.dmi differ diff --git a/icons/obj/improvised.dmi b/icons/obj/improvised.dmi index b90e3cb3bb..5c2c2a1f1b 100644 Binary files a/icons/obj/improvised.dmi and b/icons/obj/improvised.dmi differ diff --git a/icons/obj/shields.dmi b/icons/obj/shields.dmi index ed528d4a5a..c8b1110e1a 100644 Binary files a/icons/obj/shields.dmi and b/icons/obj/shields.dmi differ diff --git a/interface/skin.dmf b/interface/skin.dmf index 04a78af061..8d68336754 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -54,6 +54,7 @@ window "mainwindow" size = 640x440 anchor1 = none anchor2 = none + background-color = #242424 is-default = true saved-params = "pos;size;is-minimized;is-maximized" icon = 'icons\\ss13_64.png' @@ -61,60 +62,23 @@ window "mainwindow" menu = "menu" elem "split" type = CHILD - pos = 3,0 - size = 634x417 + pos = 0,0 + size = 637x440 anchor1 = 0,0 anchor2 = 100,100 + background-color = #272727 saved-params = "splitter" left = "mapwindow" right = "infowindow" is-vert = true - elem "input" - type = INPUT - pos = 3,420 - size = 517x20 - anchor1 = 0,100 - anchor2 = 100,100 - background-color = #d3b5b5 - is-default = true - border = sunken - saved-params = "command" - elem "saybutton" - type = BUTTON - pos = 600,420 - size = 40x20 - anchor1 = 100,100 - anchor2 = none - saved-params = "is-checked" - text = "Chat" - command = ".winset \"saybutton.is-checked=true ? input.command=\"!say \\\"\" : input.command=\"\"saybutton.is-checked=true ? mebutton.is-checked=false\"\"saybutton.is-checked=true ? oocbutton.is-checked=false\"" - button-type = pushbox - elem "oocbutton" - type = BUTTON - pos = 520,420 - size = 40x20 - anchor1 = 100,100 - anchor2 = none - saved-params = "is-checked" - text = "OOC" - command = ".winset \"oocbutton.is-checked=true ? input.command=\"!ooc \\\"\" : input.command=\"\"oocbutton.is-checked=true ? mebutton.is-checked=false\"\"oocbutton.is-checked=true ? saybutton.is-checked=false\"" - button-type = pushbox - elem "mebutton" - type = BUTTON - pos = 560,420 - size = 40x20 - anchor1 = 100,100 - anchor2 = none - saved-params = "is-checked" - text = "Me" - command = ".winset \"mebutton.is-checked=true ? input.command=\"!me \\\"\" : input.command=\"\"mebutton.is-checked=true ? saybutton.is-checked=false\"\"mebutton.is-checked=true ? oocbutton.is-checked=false\"" - button-type = pushbox + splitter = 75 elem "asset_cache_browser" type = BROWSER pos = 0,0 size = 200x200 anchor1 = none anchor2 = none + background-color = #272727 is-visible = false saved-params = "" elem "tooltip" @@ -123,6 +87,7 @@ window "mainwindow" size = 999x999 anchor1 = none anchor2 = none + background-color = #272727 is-visible = false saved-params = "" @@ -134,11 +99,11 @@ window "mapwindow" anchor1 = none anchor2 = none background-color = none - saved-params = "" + saved-params = "pos;size;is-minimized;is-maximized" statusbar = false is-pane = true - outer-size = 1090x1192 - inner-size = 1068x1136 + outer-size = 684x617 + inner-size = 662x561 elem "map" type = MAP pos = 0,0 @@ -159,6 +124,7 @@ window "infowindow" size = 640x480 anchor1 = none anchor2 = none + background-color = #242424 saved-params = "pos;size;is-minimized;is-maximized" is-pane = true elem "info" @@ -167,6 +133,7 @@ window "infowindow" size = 640x445 anchor1 = 0,0 anchor2 = 100,100 + background-color = #272727 saved-params = "splitter" left = "statwindow" right = "outputwindow" @@ -177,6 +144,8 @@ window "infowindow" size = 104x20 anchor1 = 3,0 anchor2 = 19,0 + text-color = #e0e0e0 + background-color = #40628a saved-params = "is-checked" text = "Changelog" command = "changelog" @@ -186,6 +155,8 @@ window "infowindow" size = 100x20 anchor1 = 19,0 anchor2 = 34,0 + text-color = #e0e0e0 + background-color = #40628a saved-params = "is-checked" text = "Rules" command = "rules" @@ -195,6 +166,8 @@ window "infowindow" size = 100x20 anchor1 = 34,0 anchor2 = 50,0 + text-color = #e0e0e0 + background-color = #40628a saved-params = "is-checked" text = "Wiki" command = "wiki" @@ -204,6 +177,8 @@ window "infowindow" size = 100x20 anchor1 = 50,0 anchor2 = 66,0 + text-color = #e0e0e0 + background-color = #40628a saved-params = "is-checked" text = "Forum" command = "forum" @@ -213,8 +188,10 @@ window "infowindow" size = 100x20 anchor1 = 66,0 anchor2 = 81,0 + text-color = #e0e0e0 + background-color = #40628a saved-params = "is-checked" - text = "Github" + text = "GitHub" command = "github" elem "report-issue" type = BUTTON @@ -222,6 +199,9 @@ window "infowindow" size = 100x20 anchor1 = 81,0 anchor2 = 97,0 + font-size = 8 + text-color = #e0e0e0 + background-color = #a92c2c saved-params = "is-checked" text = "Report Issue" command = "report-issue" @@ -233,15 +213,44 @@ window "outputwindow" size = 640x480 anchor1 = none anchor2 = none + background-color = #272727 saved-params = "pos;size;is-minimized;is-maximized" + titlebar = false + statusbar = false + can-close = false + can-minimize = false + can-resize = false is-pane = true + elem "input" + type = INPUT + pos = 2,460 + size = 595x20 + anchor1 = 0,100 + anchor2 = 100,100 + background-color = #d3b5b5 + is-default = true + border = sunken + saved-params = "command" + elem "say" + type = BUTTON + pos = 600,460 + size = 37x20 + anchor1 = 100,100 + anchor2 = none + text-color = #e0e0e0 + background-color = #272727 + saved-params = "is-checked" + text = "Chat" + command = ".winset \"say.is-checked=true ? input.command=\"!say \\\"\" : input.command=\"" + is-flat = true + button-type = pushbox elem "browseroutput" type = BROWSER pos = 0,0 - size = 640x480 + size = 640x456 anchor1 = 0,0 anchor2 = 100,100 - background-color = #ffffff + background-color = #272727 is-visible = false is-disabled = true saved-params = "" @@ -249,19 +258,22 @@ window "outputwindow" elem "output" type = OUTPUT pos = 0,0 - size = 640x480 + size = 640x456 anchor1 = 0,0 anchor2 = 100,100 + text-color = #e0e0e0 + background-color = #272727 is-default = true saved-params = "" window "statwindow" elem "statwindow" type = MAIN - pos = 0,0 + pos = 281,0 size = 640x480 anchor1 = none anchor2 = none + background-color = #242424 saved-params = "pos;size;is-minimized;is-maximized" is-pane = true elem "stat" @@ -270,8 +282,14 @@ window "statwindow" size = 640x480 anchor1 = 0,0 anchor2 = 100,100 + text-color = #e0e0e0 + background-color = #272727 is-default = true saved-params = "" + tab-text-color = #e0e0e0 + tab-background-color = #242424 + prefix-color = #e0e0e0 + suffix-color = #e0e0e0 window "preferences_window" elem "preferences_window" diff --git a/modular_citadel/code/__HELPERS/list2list.dm b/modular_citadel/code/__HELPERS/list2list.dm deleted file mode 100644 index e812b3a1e9..0000000000 --- a/modular_citadel/code/__HELPERS/list2list.dm +++ /dev/null @@ -1,12 +0,0 @@ -/proc/tg_ui_icon_to_cit_ui(ui_style) - switch(ui_style) - if('icons/mob/screen_plasmafire.dmi') - return 'modular_citadel/icons/ui/screen_plasmafire.dmi' - if('icons/mob/screen_slimecore.dmi') - return 'modular_citadel/icons/ui/screen_slimecore.dmi' - if('icons/mob/screen_operative.dmi') - return 'modular_citadel/icons/ui/screen_operative.dmi' - if('icons/mob/screen_clockwork.dmi') - return 'modular_citadel/icons/ui/screen_clockwork.dmi' - else - return 'modular_citadel/icons/ui/screen_midnight.dmi' diff --git a/modular_citadel/code/__HELPERS/lists.dm b/modular_citadel/code/__HELPERS/lists.dm deleted file mode 100644 index b249dfc554..0000000000 --- a/modular_citadel/code/__HELPERS/lists.dm +++ /dev/null @@ -1,9 +0,0 @@ -/proc/is_type_in_ref_list(path, list/L) - if(!ispath(path))//not a path - return - for(var/i in L) - var/datum/D = i - if(!istype(D))//not an usable reference - continue - if(istype(D, path)) - return TRUE \ No newline at end of file diff --git a/modular_citadel/code/__HELPERS/mobs.dm b/modular_citadel/code/__HELPERS/mobs.dm deleted file mode 100644 index 2666696564..0000000000 --- a/modular_citadel/code/__HELPERS/mobs.dm +++ /dev/null @@ -1,28 +0,0 @@ -/proc/slot_to_string(slot) - switch(slot) - if(SLOT_BACK) - return "Backpack" - if(SLOT_WEAR_MASK) - return "Mask" - if(SLOT_HANDS) - return "Hands" - if(SLOT_BELT) - return "Belt" - if(SLOT_EARS) - return "Ears" - if(SLOT_GLASSES) - return "Glasses" - if(SLOT_GLOVES) - return "Gloves" - if(SLOT_NECK) - return "Neck" - if(SLOT_HEAD) - return "Head" - if(SLOT_SHOES) - return "Shoes" - if(SLOT_WEAR_SUIT) - return "Suit" - if(SLOT_W_UNIFORM) - return "Uniform" - if(SLOT_IN_BACKPACK) - return "In backpack" diff --git a/modular_citadel/code/_onclick/other_mobs.dm b/modular_citadel/code/_onclick/other_mobs.dm index 2838a363ea..ec740f023b 100644 --- a/modular_citadel/code/_onclick/other_mobs.dm +++ b/modular_citadel/code/_onclick/other_mobs.dm @@ -12,7 +12,7 @@ if(isturf(A) || incapacitated()) // pretty annoying to wave your fist at floors and walls. And useless. return TRUE changeNext_move(CLICK_CD_RANGE) - var/list/target_viewers = get_actual_viewers(11, A) //doesn't check for blindness. + var/list/target_viewers = fov_viewers(11, A) //doesn't check for blindness. if(!(src in target_viewers)) //click catcher issuing calls for out of view objects. return TRUE if(!has_active_hand()) diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm index 62fe30f2d7..57cbdb6beb 100644 --- a/modular_citadel/code/datums/status_effects/chems.dm +++ b/modular_citadel/code/datums/status_effects/chems.dm @@ -10,7 +10,7 @@ alert_type = null /datum/status_effect/chem/SGDF/on_apply() - log_game("FERMICHEM: SGDF status appied on [owner], ID: [owner.key]") + log_reagent("FERMICHEM: SGDF status appied on [owner], ID: [owner.key]") fermi_Clone = owner return ..() @@ -24,7 +24,7 @@ ..() /datum/status_effect/chem/SGDF/on_remove() - log_game("FERMICHEM: SGDF mind shift applied. [owner] is now playing as their clone and should not have memories after their clone split (look up SGDF status applied). ID: [owner.key]") + log_reagent("FERMICHEM: SGDF mind shift applied. [owner] is now playing as their clone and should not have memories after their clone split (look up SGDF status applied). ID: [owner.key]") originalmind.transfer_to(fermi_Clone) to_chat(owner, "Lucidity shoots to your previously blank mind as your mind suddenly finishes the cloning process. You marvel for a moment at yourself, as your mind subconciously recollects all your memories up until the point when you cloned yourself. Curiously, you find that you memories are blank after you ingested the synthetic serum, leaving you to wonder where the other you is.") fermi_Clone = null @@ -40,7 +40,7 @@ var/last_checked_size //used to prevent potential cpu waste from happening every tick. /datum/status_effect/chem/breast_enlarger/on_apply()//Removes clothes, they're too small to contain you. You belong to space now. - log_game("FERMICHEM: [owner]'s breasts has reached comical sizes. ID: [owner.key]") + log_reagent("FERMICHEM: [owner]'s breasts has reached comical sizes. ID: [owner.key]") var/mob/living/carbon/human/H = owner var/message = FALSE if(H.w_uniform) @@ -91,7 +91,7 @@ ..() /datum/status_effect/chem/breast_enlarger/on_remove() - log_game("FERMICHEM: [owner]'s breasts has reduced to an acceptable size. ID: [owner.key]") + log_reagent("FERMICHEM: [owner]'s breasts has reduced to an acceptable size. ID: [owner.key]") to_chat(owner, "Your expansive chest has become a more managable size, liberating your movements.") owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/breast_hypertrophy) sizeMoveMod(1) @@ -114,7 +114,7 @@ var/last_checked_size //used to prevent potential cpu waste, just like the above. /datum/status_effect/chem/penis_enlarger/on_apply()//Removes clothes, they're too small to contain you. You belong to space now. - log_game("FERMICHEM: [owner]'s dick has reached comical sizes. ID: [owner.key]") + log_reagent("FERMICHEM: [owner]'s dick has reached comical sizes. ID: [owner.key]") var/mob/living/carbon/human/H = owner var/message = FALSE if(H.w_uniform) @@ -162,7 +162,7 @@ ..() /datum/status_effect/chem/penis_enlarger/on_remove() - log_game("FERMICHEM: [owner]'s dick has reduced to an acceptable size. ID: [owner.key]") + log_reagent("FERMICHEM: [owner]'s dick has reduced to an acceptable size. ID: [owner.key]") owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/penis_hypertrophy) owner.ResetBloodVol() return ..() @@ -189,7 +189,7 @@ var/mob/living/simple_animal/astral/G = new(get_turf(M.loc)) owner.mind.transfer_to(G)//Just in case someone else is inside of you, it makes them a ghost and should hopefully bring them home at the end. to_chat(G, "[M]'s conciousness snaps back to them as their astrogen runs out, kicking your projected mind out!'") - log_game("FERMICHEM: [M]'s possesser has been booted out into a astral ghost!") + log_reagent("FERMICHEM: [M]'s possesser has been booted out into a astral ghost!") originalmind.transfer_to(original) /datum/status_effect/chem/astral_insurance/on_remove() //God damnit get them home! @@ -198,7 +198,7 @@ var/mob/living/simple_animal/astral/G = new(get_turf(owner)) owner.mind.transfer_to(G)//Just in case someone else is inside of you, it makes them a ghost and should hopefully bring them home at the end. to_chat(G, "[owner]'s conciousness snaps back to them as their astrogen runs out, kicking your projected mind out!'") - log_game("FERMICHEM: [owner]'s possesser has been booted out into a astral ghost!") + log_reagent("FERMICHEM: [owner]'s possesser has been booted out into a astral ghost!") originalmind.transfer_to(original) return ..() @@ -272,7 +272,7 @@ var/message = "[(lewd ? "I am a good pet for [enthrallGender]." : "[master] is a really inspirational person!")]" SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "enthrall", /datum/mood_event/enthrall, message) to_chat(owner, "You feel inexplicably drawn towards [master], their words having a demonstrable effect on you. It seems the closer you are to them, the stronger the effect is. However you aren't fully swayed yet and can resist their effects by repeatedly resisting as much as you can!") - log_game("FERMICHEM: MKULTRA: Status applied on [owner] ckey: [owner.key] with a master of [master] ckey: [enthrallID].") + log_reagent("FERMICHEM: MKULTRA: Status applied on [owner] ckey: [owner.key] with a master of [master] ckey: [enthrallID].") SSblackbox.record_feedback("tally", "fermi_chem", 1, "Enthrall attempts") return ..() @@ -303,7 +303,7 @@ switch(phase) if(-1)//fully removed SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "enthrall") - log_game("FERMICHEM: MKULTRA: Status REMOVED from [owner] ckey: [owner.key] with a master of [master] ckey: [enthrallID].") + log_reagent("FERMICHEM: MKULTRA: Status REMOVED from [owner] ckey: [owner.key] with a master of [master] ckey: [enthrallID].") owner.remove_status_effect(src) return if(0)// sleeper agent @@ -344,7 +344,7 @@ else to_chat(owner, "You are unable to put up a resistance any longer, and now are under the influence of [master]. However you find that in your intoxicated state you are unable to resort to violence. Equally you are unable to commit suicide, even if ordered to, as you cannot follow [master] in death. ") to_chat(master, "Your [(lewd?"pet":"follower")] [owner] appears to have fully fallen under your sway.") - log_game("FERMICHEM: MKULTRA: Status on [owner] ckey: [owner.key] has been fully entrhalled (state 3) with a master of [master] ckey: [enthrallID].") + log_reagent("FERMICHEM: MKULTRA: Status on [owner] ckey: [owner.key] has been fully entrhalled (state 3) with a master of [master] ckey: [enthrallID].") SSblackbox.record_feedback("tally", "fermi_chem", 1, "thralls fully enthralled.") else if (resistanceTally > 200) enthrallTally *= 0.5 @@ -616,14 +616,14 @@ var/cached_trigger = lowertext(trigger) if (findtext(raw_message, cached_trigger))//if trigger1 is the message cTriggered = 5 //Stops triggerparties and as a result, stops servercrashes. - log_game("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been triggered with [cached_trigger] from [hearing_args[HEARING_SPEAKER]] saying: \"[hearing_args[HEARING_MESSAGE]]\". (their master being [master] ckey: [enthrallID].)") + log_reagent("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been triggered with [cached_trigger] from [hearing_args[HEARING_SPEAKER]] saying: \"[hearing_args[HEARING_MESSAGE]]\". (their master being [master] ckey: [enthrallID].)") //Speak (Forces player to talk) if (lowertext(customTriggers[trigger][1]) == "speak")//trigger2 var/saytext = "Your mouth moves on it's own before you can even catch it." addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "[saytext]"), 5) addtimer(CALLBACK(C, /atom/movable/proc/say, "[customTriggers[trigger][2]]"), 5) - log_game("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been forced to say: \"[customTriggers[trigger][2]]\" from previous trigger.") + log_reagent("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been forced to say: \"[customTriggers[trigger][2]]\" from previous trigger.") //Echo (repeats message!) allows customisation, but won't display var calls! Defaults to hypnophrase. @@ -671,7 +671,7 @@ var/mob/living/carbon/human/o = owner o.apply_status_effect(/datum/status_effect/trance, 200, TRUE) tranceTime = 50 - log_game("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been tranced from previous trigger.") + log_reagent("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been tranced from previous trigger.") return diff --git a/modular_citadel/code/game/machinery/wishgranter.dm b/modular_citadel/code/game/machinery/wishgranter.dm deleted file mode 100644 index 0035828136..0000000000 --- a/modular_citadel/code/game/machinery/wishgranter.dm +++ /dev/null @@ -1,122 +0,0 @@ -/obj/machinery/wish_granter/attack_hand(mob/living/carbon/user) - if(charges <= 0) - to_chat(user, "The Wish Granter lies silent.") - return - - else if(!ishuman(user)) - to_chat(user, "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's.") - return - - else if (!insisting) - to_chat(user, "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?") - insisting++ - - else - if(is_special_character(user)) - to_chat(user, "You speak. [pick("I want power","Humanity is corrupt, mankind must be destroyed", "I want to rule the world","I want immortality")]. The Wish Granter answers.") - to_chat(user, "Your head pounds for a moment, before your vision clears. The Wish Granter, sensing the darkness in your heart, has given you limitless power, and it's all yours!") - user.dna.add_mutation(HULK) - user.dna.add_mutation(XRAY) - user.dna.add_mutation(SPACEMUT) - user.dna.add_mutation(TK) - user.next_move_modifier *= 0.5 //half the delay between attacks! - to_chat(user, "Things around you feel slower!") - charges-- - insisting = FALSE - to_chat(user, "You have a very great feeling about this!") - else - to_chat(user, "The Wish Granter awaits your wish.") - var/wish = input("You want...","Wish") as null|anything in list("Power","Wealth","The Station To Disappear","To Kill","Nothing") - switch(wish) - if("Power") //Gives infinite power in exchange for infinite power going off in your face! - if(charges <= 0) - return - to_chat(user, "Your wish is granted, but at a terrible cost...") - to_chat(user, "The Wish Granter punishes you for your selfishness, warping itself into a delaminating supermatter shard!") - var/obj/item/stock_parts/cell/infinite/powah = new /obj/item/stock_parts/cell/infinite(get_turf(user)) - if(user.put_in_hands(powah)) - to_chat(user, "[powah] materializes into your hands!") - else - to_chat(user, "[powah] materializes onto the floor.") - var/obj/machinery/power/supermatter_crystal/powerwish = new /obj/machinery/power/supermatter_crystal(loc) - powerwish.damage = 700 //right at the emergency threshold - powerwish.produces_gas = FALSE - charges-- - insisting = FALSE - if(!charges) - qdel(src) - if("Wealth") //Gives 1 million space bucks in exchange for being turned into gold! - if(charges <= 0) - return - to_chat(user, "Your wish is granted, but at a cost...") - to_chat(user, "The Wish Granter punishes you for your selfishness, warping your body to match the greed in your heart.") - new /obj/structure/closet/crate/trashcart/moneywish(loc) - new /obj/structure/closet/crate/trashcart/moneywish(loc) - user.set_species(/datum/species/golem/gold) - charges-- - insisting = FALSE - if(!charges) - qdel(src) - if("The Station To Disappear") //teleports you to the station and makes you blind, making the station disappear for you! - if(charges <= 0) - return - to_chat(user, "Your wish is 'granted', but at a terrible cost...") - to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your eyes to match the darkness in your heart.") - user.dna.add_mutation(BLINDMUT) - var/obj/item/organ/eyes/eyes = user.getorganslot(ORGAN_SLOT_EYES) - if(eyes) - eyes.applyOrganDamage(eyes.maxHealth) - var/list/destinations = list() - for(var/obj/item/beacon/B in GLOB.teleportbeacons) - var/turf/T = get_turf(B) - if(is_station_level(T.z)) - destinations += B - var/chosen_beacon = pick(destinations) - var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), src, 100, null, FALSE, get_turf(chosen_beacon)) - try_move_adjacent(J) - playsound(src,'sound/effects/sparks4.ogg',50,1) - charges-- - insisting = FALSE - if(!charges) - qdel(src) - if("To Kill") //Makes you kill things in exchange for rewards! - if(charges <= 0) - return - to_chat(user, "Your wish is granted, but at a terrible cost...") - to_chat(user, "The Wish Granter punishes you for your wickedness, warping itself into a dastardly creature for you to kill! ...but it almost seems to reward you for this.") - var/obj/item/melee/transforming/energy/sword/cx/killreward = new /obj/item/melee/transforming/energy/sword/cx(get_turf(user)) - if(user.put_in_hands(killreward)) - to_chat(user, "[killreward] materializes into your hands!") - else - to_chat(user, "[killreward] materializes onto the floor.") - user.next_move_modifier *= 0.8 //20% less delay between attacks! - to_chat(user, "Things around you feel slightly slower!") - var/mob/living/simple_animal/hostile/venus_human_trap/killwish = new /mob/living/simple_animal/hostile/venus_human_trap(loc) - killwish.maxHealth = 1500 - killwish.health = killwish.maxHealth - killwish.vine_grab_distance = 6 - killwish.melee_damage_upper = 30 - killwish.loot = list(/obj/item/dualsaber/hypereutactic) - charges-- - insisting = FALSE - if(!charges) - qdel(src) - if("Nothing") //Makes the wish granter disappear - if(charges <= 0) - return - to_chat(user, "The Wish Granter vanishes from sight!") - to_chat(user, "You feel as if you just narrowly avoided a terrible fate...") - charges-- - insisting = FALSE - qdel(src) - -//ITEMS THAT IT USES - -/obj/structure/closet/crate/trashcart/moneywish - desc = "A heavy, metal trashcart with wheels. Filled with cash." - name = "loaded trash cart" - -/obj/structure/closet/crate/trashcart/moneywish/PopulateContents() //25*20*1000=500,000 - for(var/i = 0, i < 25, i++) - var/obj/item/stack/spacecash/c1000/lodsamoney = new /obj/item/stack/spacecash/c1000(src) - lodsamoney.amount = lodsamoney.max_amount diff --git a/modular_citadel/code/game/objects/items/devices/radio/shockcollar.dm b/modular_citadel/code/game/objects/items/devices/radio/shockcollar.dm deleted file mode 100644 index 6c9f12a852..0000000000 --- a/modular_citadel/code/game/objects/items/devices/radio/shockcollar.dm +++ /dev/null @@ -1,83 +0,0 @@ -/obj/item/electropack/shockcollar - name = "shock collar" - desc = "A reinforced metal collar. It seems to have some form of wiring near the front. Strange.." - icon = 'modular_citadel/icons/obj/clothing/cit_neck.dmi' - mob_overlay_icon = 'modular_citadel/icons/mob/citadel/neck.dmi' - icon_state = "shockcollar" - item_state = "shockcollar" - body_parts_covered = NECK - slot_flags = ITEM_SLOT_NECK | ITEM_SLOT_DENYPOCKET //no more pocket shockers - w_class = WEIGHT_CLASS_SMALL - strip_delay = 60 - equip_delay_other = 60 - materials = list(MAT_METAL=5000, MAT_GLASS=2000) - var/tagname = null - -/datum/design/electropack/shockcollar - name = "Shockcollar" - id = "shockcollar" - build_type = AUTOLATHE - build_path = /obj/item/electropack/shockcollar - materials = list(MAT_METAL=5000, MAT_GLASS=2000) - category = list("hacked", "Misc") - -/obj/item/electropack/shockcollar/attack_hand(mob/user) - if(loc == user && user.get_item_by_slot(SLOT_NECK)) - to_chat(user, "The collar is fastened tight! You'll need help taking this off!") - return - ..() - -/obj/item/electropack/shockcollar/receive_signal(datum/signal/signal) - if(!signal || signal.data["code"] != code) - return - - if(isliving(loc) && on) - if(shock_cooldown != 0) - return - shock_cooldown = 1 - spawn(100) - shock_cooldown = 0 - var/mob/living/L = loc - step(L, pick(GLOB.cardinals)) - - to_chat(L, "You feel a sharp shock from the collar!") - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(3, 1, L) - s.start() - - L.DefaultCombatKnockdown(100) - - if(master) - master.receive_signal() - return - -/obj/item/electropack/shockcollar/attack_self(mob/user) //Turns out can't fully source this from the parent item, spritepath gets confused if power toggled. Will come back to this when I know how to code better and readd powertoggle.. - var/option = "Change Name" - option = input(user, "What do you want to do?", "[src]", option) as null|anything in list("Change Name", "Change Frequency") - switch(option) - if("Change Name") - var/t = input(user, "Would you like to change the name on the tag?", "Name your new pet", tagname ? tagname : "Spot") as null|text - if(t) - tagname = copytext(sanitize(t), 1, MAX_NAME_LEN) - name = "[initial(name)] - [tagname]" - if("Change Frequency") - if(!ishuman(user)) - return - user.set_machine(src) - var/dat = {"
- Frequency/Code for shock collar:
- Frequency: - - - - [format_frequency(frequency)] - + - +
- Code: - - - - [code] - + - +
-
"} - - user << browse(dat, "window=radio") - onclose(user, "radio") - return diff --git a/modular_citadel/code/game/objects/structures/beds_chairs/chair.dm b/modular_citadel/code/game/objects/structures/beds_chairs/chair.dm deleted file mode 100644 index 5b20fe048b..0000000000 --- a/modular_citadel/code/game/objects/structures/beds_chairs/chair.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/structure/chair/alt_attack_hand(mob/living/user) - if(Adjacent(user) && istype(user)) - if(!item_chair || !user.can_hold_items() || !has_buckled_mobs() || buckled_mobs.len > 1 || dir != user.dir || flags_1 & NODECONSTRUCT_1) - return TRUE - if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user))) - to_chat(user, "You can't do that right now!") - return TRUE - if(user.getStaminaLoss() >= STAMINA_SOFTCRIT) - to_chat(user, "You're too exhausted for that.") - return TRUE - var/mob/living/poordude = buckled_mobs[1] - if(!istype(poordude)) - return TRUE - user.visible_message("[user] pulls [src] out from under [poordude].", "You pull [src] out from under [poordude].") - var/C = new item_chair(loc) - user.put_in_hands(C) - poordude.DefaultCombatKnockdown(20)//rip in peace - user.adjustStaminaLoss(5) - unbuckle_all_mobs(TRUE) - qdel(src) - return TRUE diff --git a/modular_citadel/code/modules/client/loadout/_loadout.dm b/modular_citadel/code/modules/client/loadout/_loadout.dm index d35bede179..51256f8cde 100644 --- a/modular_citadel/code/modules/client/loadout/_loadout.dm +++ b/modular_citadel/code/modules/client/loadout/_loadout.dm @@ -10,7 +10,6 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids) /proc/load_loadout_config(loadout_config) if(!loadout_config) loadout_config = "config/loadout_config.txt" - LAZYINITLIST(GLOB.loadout_whitelist_ids) var/list/file_lines = world.file2list(loadout_config) for(var/line in file_lines) if(!line || line[1] == "#") @@ -26,12 +25,9 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids) GLOB.loadout_whitelist_ids["[lineID]"] = sublinecontent /proc/initialize_global_loadout_items() - LAZYINITLIST(GLOB.loadout_items) load_loadout_config() for(var/item in subtypesof(/datum/gear)) var/datum/gear/I = new item - if(!GLOB.loadout_items[slot_to_string(I.category)]) - LAZYINITLIST(GLOB.loadout_items[slot_to_string(I.category)]) LAZYSET(GLOB.loadout_items[slot_to_string(I.category)], I.name, I) if(islist(I.geargroupID)) var/list/ggidlist = I.geargroupID diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm index d51f4b6125..8d089a129a 100644 --- a/modular_citadel/code/modules/client/loadout/backpack.dm +++ b/modular_citadel/code/modules/client/loadout/backpack.dm @@ -69,18 +69,6 @@ path = /obj/item/toy/katana cost = 3 -/datum/gear/box - name = "Spare box" - category = SLOT_IN_BACKPACK - path = /obj/item/storage/box - cost = 2 - -/datum/gear/crowbar - name = "Pocket Crowbar" - category = SLOT_IN_BACKPACK - path = /obj/item/crowbar - cost = 2 - /datum/gear/tapeplayer name = "Taperecorder" category = SLOT_IN_BACKPACK @@ -96,11 +84,6 @@ category = SLOT_IN_BACKPACK path = /obj/item/newspaper -/datum/gear/paperbin - name = "Paper Bin" - category = SLOT_IN_BACKPACK - path = /obj/item/paper_bin - /datum/gear/crayons name = "Box of crayons" category = SLOT_IN_BACKPACK @@ -146,4 +129,4 @@ category = SLOT_IN_BACKPACK path = /obj/item/storage/fancy/ringbox/diamond cost = 5 - + diff --git a/modular_citadel/code/modules/client/loadout/mask.dm b/modular_citadel/code/modules/client/loadout/mask.dm index 82824814ae..eeba06cad4 100644 --- a/modular_citadel/code/modules/client/loadout/mask.dm +++ b/modular_citadel/code/modules/client/loadout/mask.dm @@ -12,5 +12,5 @@ name = "Joy mask" category = SLOT_WEAR_MASK path = /obj/item/clothing/mask/joy - cost = 9 - + cost = 3 + diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm index 9b39d006bd..64bfd34172 100644 --- a/modular_citadel/code/modules/client/loadout/suit.dm +++ b/modular_citadel/code/modules/client/loadout/suit.dm @@ -85,20 +85,18 @@ path = /obj/item/clothing/suit/hooded/wintercoat/polychromic cost = 4 //too many people with neon green coats is hard on the eyes -/* Commented out until it is "balanced" -/datum/gear/coat/sec - name = "Security winter coat" - category = SLOT_WEAR_SUIT - path = /obj/item/clothing/suit/hooded/wintercoat/security - restricted_roles = list("Head of Security", "Warden", "Detective", "Security Officer") // Reserve it to the Security Departement -*/ - /datum/gear/coat/med name = "Medical winter coat" category = SLOT_WEAR_SUIT path = /obj/item/clothing/suit/hooded/wintercoat/medical restricted_roles = list("Chief Medical Officer", "Medical Doctor") // Reserve it to Medical Doctors and their boss, the Chief Medical Officer +/datum/gear/coat/paramedic + name = "Paramedic winter coat" + category = SLOT_WEAR_SUIT + path = /obj/item/clothing/suit/hooded/wintercoat/paramedic + restricted_roles = list("Chief Medical Officer", "Paramedic") // Reserve it to Paramedics and their boss, the Chief Medical Officer + /datum/gear/coat/robotics name = "Robotics winter coat" category = SLOT_WEAR_SUIT @@ -234,4 +232,4 @@ /datum/gear/christmascoatrg name = "Red and Green Christmas Coat" category = SLOT_WEAR_SUIT - path = /obj/item/clothing/suit/hooded/wintercoat/christmascoatrg \ No newline at end of file + path = /obj/item/clothing/suit/hooded/wintercoat/christmascoatrg diff --git a/modular_citadel/code/modules/client/preferences.dm b/modular_citadel/code/modules/client/preferences.dm deleted file mode 100644 index 8c55f2d9a8..0000000000 --- a/modular_citadel/code/modules/client/preferences.dm +++ /dev/null @@ -1,47 +0,0 @@ -#define DEFAULT_SLOT_AMT 2 -#define HANDS_SLOT_AMT 2 -#define BACKPACK_SLOT_AMT 4 - -/datum/preferences - //gear - var/gear_points = 10 - var/list/gear_categories - var/list/chosen_gear - var/gear_tab - - //pref vars - var/screenshake = 100 - var/damagescreenshake = 2 - var/arousable = TRUE - var/widescreenpref = TRUE - var/autostand = TRUE - var/auto_ooc = FALSE - - //vore prefs - var/toggleeatingnoise = TRUE - var/toggledigestionnoise = TRUE - var/hound_sleeper = TRUE - var/cit_toggles = TOGGLES_CITADEL - - -/datum/preferences/New(client/C) - ..() - LAZYINITLIST(chosen_gear) - -/datum/preferences/proc/is_loadout_slot_available(slot) - var/list/L - LAZYINITLIST(L) - for(var/i in chosen_gear) - var/datum/gear/G = i - var/occupied_slots = L[slot_to_string(initial(G.category))] ? L[slot_to_string(initial(G.category))] + 1 : 1 - LAZYSET(L, slot_to_string(initial(G.category)), occupied_slots) - switch(slot) - if(SLOT_IN_BACKPACK) - if(L[slot_to_string(SLOT_IN_BACKPACK)] < BACKPACK_SLOT_AMT) - return TRUE - if(SLOT_HANDS) - if(L[slot_to_string(SLOT_HANDS)] < HANDS_SLOT_AMT) - return TRUE - else - if(L[slot_to_string(slot)] < DEFAULT_SLOT_AMT) - return TRUE diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm index d9b902656f..d0363d228f 100644 --- a/modular_citadel/code/modules/client/preferences_savefile.dm +++ b/modular_citadel/code/modules/client/preferences_savefile.dm @@ -14,17 +14,6 @@ features["mcolor2"] = sanitize_hexcolor(features["mcolor2"], 3, 0) features["mcolor3"] = sanitize_hexcolor(features["mcolor3"], 3, 0) - //gear loadout - var/text_to_load - S["loadout"] >> text_to_load - var/list/saved_loadout_paths = splittext(text_to_load, "|") - LAZYCLEARLIST(chosen_gear) - gear_points = initial(gear_points) - for(var/i in saved_loadout_paths) - var/datum/gear/path = text2path(i) - if(path) - LAZYADD(chosen_gear, path) - gear_points -= initial(path.cost) /datum/preferences/proc/cit_character_pref_save(savefile/S) //ipcs @@ -47,10 +36,3 @@ //flavor text WRITE_FILE(S["feature_flavor_text"], features["flavor_text"]) - //gear loadout - if(islist(chosen_gear)) - if(chosen_gear.len) - var/text_to_save = chosen_gear.Join("|") - S["loadout"] << text_to_save - else - S["loadout"] << "" //empty string to reset the value diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm index cd672e2c6a..f66c0289b6 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm @@ -171,10 +171,10 @@ Creating a chem with a low purity will make you permanently fall in love with so E.enthrallGender = creatorGender E.master = get_mob_by_key(creatorID) to_chat(M, "Your addled, plastic, mind bends under the chemical influence of a new [(E.lewd?"master":"leader")]. Your highest priority is now to stay by [creatorName]'s side, following and aiding them at all costs.") //THIS SHOULD ONLY EVER APPEAR IF YOU MINDBREAK YOURSELF AND THEN GET INJECTED FROM SOMEONE ELSE. - log_game("FERMICHEM: Narcissist [M] ckey: [M.key] been rebound to [creatorName], ID: [creatorID]") + log_reagent("FERMICHEM: Narcissist [M] ckey: [M.key] been rebound to [creatorName], ID: [creatorID]") return if((M.ckey == creatorID) && (creatorName == M.real_name)) //same name AND same player - same instance of the player. (should work for clones?) - log_game("FERMICHEM: [M] ckey: [M.key] has been given velvetspeech") + log_reagent("FERMICHEM: [M] ckey: [M.key] has been given velvetspeech") var/obj/item/organ/vocal_cords/Vc = M.getorganslot(ORGAN_SLOT_VOICE) var/obj/item/organ/vocal_cords/nVc = new /obj/item/organ/vocal_cords/velvet if(Vc) @@ -183,9 +183,9 @@ Creating a chem with a low purity will make you permanently fall in love with so qdel(Vc) to_chat(M, "You feel your vocal chords tingle you speak in a more charasmatic and sultry tone.") else - log_game("FERMICHEM: MKUltra: [creatorName], [creatorID], is enthralling [M.name], [M.ckey]") + log_reagent("FERMICHEM: MKUltra: [creatorName], [creatorID], is enthralling [M.name], [M.ckey]") M.apply_status_effect(/datum/status_effect/chem/enthrall) - log_game("FERMICHEM: [M] ckey: [M.key] has taken MKUltra") + log_reagent("FERMICHEM: [M] ckey: [M.key] has taken MKUltra") /datum/reagent/fermi/enthrall/on_mob_life(mob/living/carbon/M) . = ..() @@ -194,7 +194,7 @@ Creating a chem with a low purity will make you permanently fall in love with so if (M.ckey == creatorID && creatorName == M.real_name)//If the creator drinks it, they fall in love randomly. If someone else drinks it, the creator falls in love with them. if(M.has_status_effect(STATUS_EFFECT_INLOVE))//Can't be enthralled when enthralled, so to speak. return - var/list/seen = (M.visible_atoms(M.client?.view || world.view) - M) | viewers(M.client?.view || world.view, M) + var/list/seen = (M.fov_view(M.client?.view || world.view) - M) | viewers(M.client?.view || world.view, M) for(var/victim in seen) if(ishuman(victim)) var/mob/living/carbon/V = victim @@ -213,7 +213,7 @@ Creating a chem with a low purity will make you permanently fall in love with so var/mob/living/carbon/C = get_mob_by_key(creatorID) if(M.has_status_effect(STATUS_EFFECT_INLOVE)) return - if(C.client && (M in C.visible_atoms(C.client.view))) + if(C.client && (M in C.fov_view(C.client.view))) M.reagents.del_reagent(type) FallInLove(C, M) return @@ -251,7 +251,7 @@ Creating a chem with a low purity will make you permanently fall in love with so to_chat(M, "Your mind shatters under the volume of the mild altering chem inside of you, breaking all will and thought completely. Instead the only force driving you now is the instinctual desire to obey and follow [creatorName]. Your highest priority is now to stay by their side and protect them at all costs.") else to_chat(M, "The might volume of chemicals in your system overwhelms your mind, and you suddenly agree with what [creatorName] has been saying. Your highest priority is now to stay by their side and protect them at all costs.") - log_game("FERMICHEM: [M] ckey: [M.key] has been mindbroken for [creatorName] ckey: [creatorID]") + log_reagent("FERMICHEM: [M] ckey: [M.key] has been mindbroken for [creatorName] ckey: [creatorID]") M.slurring = 100 M.confused = 100 E.phase = 4 @@ -279,7 +279,7 @@ Creating a chem with a low purity will make you permanently fall in love with so if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) return ..() if(!M.has_status_effect(STATUS_EFFECT_INLOVE)) - var/list/seen = (M.visible_atoms(M.client?.view || world.view) - M) | viewers(M.client?.view || world.view, M) + var/list/seen = (M.fov_view(M.client?.view || world.view) - M) | viewers(M.client?.view || world.view, M) for(var/victim in seen) if((isanimal(victim)) || (!isliving(victim))) seen -= victim @@ -289,7 +289,7 @@ Creating a chem with a low purity will make you permanently fall in love with so M.apply_status_effect(STATUS_EFFECT_INLOVE, love) lewd = (M.client?.prefs.cit_toggles & HYPNO) && (love.client?.prefs.cit_toggles & HYPNO) to_chat(M, "[(lewd?"":"")][(lewd?"You develop a sudden crush on [love], your heart beginning to race as you look upon them with new eyes.":"You suddenly feel like making friends with [love].")] You feel strangely drawn towards them.") - log_game("FERMICHEM: [M] ckey: [M.key] has temporarily bonded with [love] ckey: [love.key]") + log_reagent("FERMICHEM: [M] ckey: [M.key] has temporarily bonded with [love] ckey: [love.key]") SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have bonded") else if(get_dist(M, love) < 8) @@ -314,7 +314,7 @@ Creating a chem with a low purity will make you permanently fall in love with so SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "InLove") SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "MissingLove") to_chat(M, "[(lewd?"":"")]Your feelings for [love] suddenly vanish!") - log_game("FERMICHEM: [M] ckey: [M.key] is no longer in temp bond") + log_reagent("FERMICHEM: [M] ckey: [M.key] is no longer in temp bond") ..() /datum/reagent/fermi/proc/FallInLove(mob/living/carbon/Lover, mob/living/carbon/Love) @@ -331,7 +331,7 @@ Creating a chem with a low purity will make you permanently fall in love with so Lover.apply_status_effect(STATUS_EFFECT_INLOVE, Love) forge_valentines_objective(Lover, Love, TRUE) SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have become infatuated.") - log_game("FERMICHEM: [Lover] ckey: [Lover.key] has been chemically made to fall for [Love] ckey: [Love.key]") + log_reagent("FERMICHEM: [Lover] ckey: [Lover.key] has been chemically made to fall for [Love] ckey: [Love.key]") return //For addiction see chem.dm diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm index 51b13f8c55..37ec1ee69f 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm @@ -64,7 +64,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING if(pollStarted == FALSE) pollStarted = TRUE candies = pollGhostCandidates("Do you want and agree to play as a clone of [M], respect their character and not engage in ERP without permission from the original?", ignore_category = POLL_IGNORE_CLONE) - log_game("FERMICHEM: [M] ckey: [M.key] has taken SDGF, and ghosts have been polled.") + log_reagent("FERMICHEM: [M] ckey: [M.key] has taken SDGF, and ghosts have been polled.") if(20 to INFINITY) if(LAZYLEN(candies) && playerClone == FALSE) //If there's candidates, clone the person and put them in there! to_chat(M, "The cells reach a critical micelle concentration, nucleating rapidly within your body!") @@ -82,7 +82,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING if(C2.key && C2) C2.transfer_ckey(SM, FALSE) message_admins("Ghost candidate found! [C2] key [C2.key] is becoming a clone of [M] key: [M.key] (They agreed to respect the character they're becoming, and agreed to not ERP without express permission from the original.)") - log_game("FERMICHEM: [M] ckey: [M.key] is creating a clone, controlled by [C2]") + log_reagent("FERMICHEM: [M] ckey: [M.key] is creating a clone, controlled by [C2]") break else candies -= C2 @@ -97,16 +97,16 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING var/obj/item/organ/zombie_infection/ZI = M.getorganslot(ORGAN_SLOT_ZOMBIE) ZI.Remove() ZI.Insert(SM) - log_game("FERMICHEM: [M] ckey: [M.key]'s zombie_infection has been transferred to their clone") + log_reagent("FERMICHEM: [M] ckey: [M.key]'s zombie_infection has been transferred to their clone") to_chat(SM, "You feel a strange sensation building in your mind as you realise there's two of you, before you get a chance to think about it, you suddenly split from your old body, and find yourself face to face with your original, a perfect clone of your origin.") if(prob(50)) to_chat(SM, "While you find your newfound existence strange, you share the same memories as [M.real_name]. However, You find yourself indifferent to the goals you previously had, and take more interest in your newfound independence, but still have an indescribable care for the safety of your original.") - log_game("FERMICHEM: [SM] ckey: [SM.key]'s is not bound by [M] ckey [M.key]'s will, and is free to determine their own goals, while respecting and acting as their origin.") + log_reagent("FERMICHEM: [SM] ckey: [SM.key]'s is not bound by [M] ckey [M.key]'s will, and is free to determine their own goals, while respecting and acting as their origin.") else to_chat(SM, "While you find your newfound existence strange, you share the same memories as [M.real_name]. Your mind has not deviated from the tasks you set out to do, and now that there's two of you the tasks should be much easier.") - log_game("FERMICHEM: [SM] ckey: [SM.key]'s is bound by [M] ckey [M.key]'s objectives, and is encouraged to help them complete them.") + log_reagent("FERMICHEM: [SM] ckey: [SM.key]'s is bound by [M] ckey [M.key]'s objectives, and is encouraged to help them complete them.") to_chat(M, "You feel a strange sensation building in your mind as you realise there's two of you, before you get a chance to think about it, you suddenly split from your old body, and find yourself face to face with yourself.") M.visible_message("[M] suddenly shudders, and splits into two identical twins!") @@ -124,7 +124,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING //Transfer remaining reagent to clone. I think around 30u will make a healthy clone, otherwise they'll have clone damage, blood loss, brain damage and hunger. SM.reagents.add_reagent(/datum/reagent/fermi/SDGFheal, volume) M.reagents.remove_reagent(type, volume) - log_game("FERMICHEM: [volume]u of SDGFheal has been transferred to the clone") + log_reagent("FERMICHEM: [volume]u of SDGFheal has been transferred to the clone") SSblackbox.record_feedback("tally", "fermi_chem", 1, "Sentient clones made") return ..() @@ -135,7 +135,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING if(21) to_chat(M, "The cells fail to catalyse around a nucleation event, instead merging with your cells.") //This stuff is hard enough to make to rob a user of some benefit. Shouldn't replace Rezadone as it requires the user to not only risk making a player controlled clone, but also requires them to have split in two (which also requires 30u of SGDF). REMOVE_TRAIT(M, TRAIT_DISFIGURED, TRAIT_GENERIC) - log_game("FERMICHEM: [M] ckey: [M.key] is being healed by SDGF") + log_reagent("FERMICHEM: [M] ckey: [M.key] is being healed by SDGF") if(22 to INFINITY) M.adjustCloneLoss(-1, 0) M.adjustBruteLoss(-1, 0) @@ -182,7 +182,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING S.originalmind = M.mind S.status_set = TRUE - log_game("FERMICHEM: [M] ckey: [M.key] has created a mindless clone of themselves") + log_reagent("FERMICHEM: [M] ckey: [M.key] has created a mindless clone of themselves") SSblackbox.record_feedback("tally", "fermi_chem", 1, "Braindead clones made") if(87 to INFINITY) M.reagents.remove_reagent(type, volume)//removes SGDF on completion. Has to do it this way because of how i've coded it. If some madlab gets over 1k of SDGF, they can have the clone healing. @@ -349,7 +349,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING ZI.real_name = M.real_name//Give your offspring a big old kiss. ZI.name = M.real_name ZI.desc = "[M]'s clone, gone horribly wrong." - log_game("FERMICHEM: [M] ckey: [M.key]'s clone has become a horrifying zombie instead") + log_reagent("FERMICHEM: [M] ckey: [M.key]'s clone has become a horrifying zombie instead") M.reagents.remove_reagent(type, 20) else//easier to deal with @@ -362,7 +362,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING S.rabid = 1//Make them an angery boi M.reagents.remove_reagent(type, volume) to_chat(M, "A large glob of the tumour suddenly splits itself from your body. You feel grossed out and slimey...") - log_game("FERMICHEM: [M] ckey: [M.key]'s clone has become a horrifying teratoma instead") + log_reagent("FERMICHEM: [M] ckey: [M.key]'s clone has become a horrifying teratoma instead") SSblackbox.record_feedback("tally", "fermi_chem", 1, "Zombie clones made!") if(87 to INFINITY) diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm index 8348569fbb..bdc599a5e2 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm @@ -67,7 +67,7 @@ I'd like to point out from my calculations it'll take about 60-80 minutes to die M.alpha = 255 if(current_cycle == 0) originalmind = M.mind - log_game("FERMICHEM: [M] ckey: [M.key] became an astral ghost") + log_reagent("FERMICHEM: [M] ckey: [M.key] became an astral ghost") origin = M if (G == null) G = new(get_turf(M.loc)) @@ -100,29 +100,25 @@ I'd like to point out from my calculations it'll take about 60-80 minutes to die ..() /datum/reagent/fermi/astral/on_mob_delete(mob/living/carbon/M) - if(!G) - if(M.mind) - var/mob/living/simple_animal/astral/G2 = new(get_turf(M.loc)) - M.mind.transfer_to(G2)//Just in case someone else is inside of you, it makes them a ghost and should hopefully bring them home at the end. - to_chat(G, "[M]'s conciousness snaps back to them as their astrogen runs out, kicking your projected mind out!'") - log_game("FERMICHEM: [M]'s possesser has been booted out into a astral ghost!") - if(!G2.mind) - qdel(G2) - originalmind.transfer_to(M) - else if(G.mind) - G.mind.transfer_to(origin) - qdel(G) + if(!(G?.mind)) + if(!G) + qdel(G) + return ..() + if(M.mind) //Just in case someone else is inside of you, it makes them a ghost and should hopefully bring them home at the end. + var/mob/living/simple_animal/astral/G2 = new(get_turf(M)) + M.mind.transfer_to(G2) + to_chat(G2, "[M]'s conciousness snaps back to them as [M.p_their()] astrogen runs out, kicking your projected mind out!'") + log_reagent("FERMICHEM: [G2.mind.name] has been booted out of [M] as their original mind came back as the Astrogen reagent ran out!") + G.mind.transfer_to(origin) + qdel(G) if(overdosed) to_chat(M, "The high volume of astrogen you just took causes you to black out momentarily as your mind snaps back to your body.") M.Sleeping(sleepytime, 0) antiGenetics = 255 - if(G)//just in case - qdel(G) - log_game("FERMICHEM: [M] has astrally returned to their body!") + log_reagent("FERMICHEM: [M] has astrally returned to their body!") if(M.mind && M.mind == originalmind) M.remove_status_effect(/datum/status_effect/chem/astral_insurance) - //AS.Remove(M) - ..() + return ..() //Okay so, this might seem a bit too good, but my counterargument is that it'll likely take all round to eventually kill you this way, then you have to be revived without a body. It takes approximately 50-80 minutes to die from this. /datum/reagent/fermi/astral/addiction_act_stage1(mob/living/carbon/M) @@ -137,7 +133,7 @@ I'd like to point out from my calculations it'll take about 60-80 minutes to die to_chat(M, "You notice your body starting to disappear, maybe you took too much Astrogen...?") M.alpha-- antiGenetics-- - log_game("FERMICHEM: [M] ckey: [M.key] has become addicted to Astrogen") + log_reagent("FERMICHEM: [M] ckey: [M.key] has become addicted to Astrogen") if(220) to_chat(M, "Your addiction is only getting worse as your body disappears. Maybe you should get some more, and fast?") M.alpha-- @@ -172,5 +168,5 @@ I'd like to point out from my calculations it'll take about 60-80 minutes to die message_admins("[M] (ckey: [M.ckey]) has become one with the universe, and have continuous memories thoughout their lives should they find a way to come back to life (such as an inteligence potion, midround antag, ghost role).") SSblackbox.record_feedback("tally", "fermi_chem", 1, "Astral obliterations") qdel(M) //Approx 60minutes till death from initial addiction - log_game("FERMICHEM: [M] ckey: [M.key] has been obliterated from Astrogen addiction") + log_reagent("FERMICHEM: [M] ckey: [M.key] has been obliterated from Astrogen addiction") ..() diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm index 1500d52b25..40077cd02a 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm @@ -37,7 +37,7 @@ //Main functions /datum/reagent/fermi/eigenstate/on_mob_life(mob/living/M) //Teleports to chemistry! if(current_cycle == 0) - log_game("FERMICHEM: [M] ckey: [M.key] took eigenstasium") + log_reagent("FERMICHEM: [M] ckey: [M.key] took eigenstasium") //make hologram at return point Eigenstate = new(loc) @@ -55,7 +55,7 @@ if(cached_purity > 0.9) //Teleports you home if it's pure enough if(!location_created && data) //Just in case location_created = data["location_created"] - log_game("FERMICHEM: [M] ckey: [M.key] returned to [location_created] using eigenstasium") + log_reagent("FERMICHEM: [M] ckey: [M.key] returned to [location_created] using eigenstasium") do_sparks(5,FALSE,M) do_teleport(M, location_created, 0, asoundin = 'sound/effects/phasein.ogg') do_sparks(5,FALSE,M) @@ -78,7 +78,7 @@ /datum/reagent/fermi/eigenstate/overdose_start(mob/living/M) //Overdose, makes you teleport randomly . = ..() to_chat(M, "Oh god, you feel like your wavefunction is about to tear.") - log_game("FERMICHEM: [M] ckey: [M.key] has overdosed on eigenstasium") + log_reagent("FERMICHEM: [M] ckey: [M.key] has overdosed on eigenstasium") M.Jitter(20) metabolization_rate += 0.5 //So you're not stuck forever teleporting. @@ -92,7 +92,7 @@ /datum/reagent/fermi/eigenstate/addiction_act_stage1(mob/living/M) //Welcome to Fermis' wild ride. if(addiction_stage == 1) to_chat(M, "Your wavefunction feels like it's been ripped in half. You feel empty inside.") - log_game("FERMICHEM: [M] ckey: [M.key] has become addicted to eigenstasium") + log_reagent("FERMICHEM: [M] ckey: [M.key] has become addicted to eigenstasium") M.Jitter(10) M.adjust_nutrition(-M.nutrition/15) ..() @@ -158,7 +158,7 @@ M.DefaultCombatKnockdown(100) to_chat(M, "You feel your eigenstate settle, snapping an alternative version of yourself into reality. All your previous memories are lost and replaced with the alternative version of yourself.") M.emote("me",1,"flashes into reality suddenly, gasping as they gaze around in a bewildered and highly confused fashion!",TRUE) - log_game("FERMICHEM: [M] ckey: [M.key] has become an alternative universe version of themselves.") + log_reagent("FERMICHEM: [M] ckey: [M.key] has become an alternative universe version of themselves.") M.reagents.remove_all_type(/datum/reagent, 100, 0, 1) /* for(var/datum/mood_event/Me in M) diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm index 8bc67b6d1d..82efabc4e2 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm @@ -118,7 +118,7 @@ to_chat(M, "You find yourself unable to supress the desire to howl!") M.emote("awoo") if(prob(20)) - var/list/seen = M.visible_atoms() - M //Sound and sight checkers + var/list/seen = M.fov_view() - M //Sound and sight checkers for(var/victim in seen) if(isanimal(victim) || !isliving(victim)) seen -= victim @@ -139,7 +139,7 @@ to_chat(M, "You find yourself unable to supress the desire to howl!") M.emote("awoo") if(prob(5)) - var/list/seen = M.visible_atoms() - M //Sound and sight checkers + var/list/seen = M.fov_view() - M //Sound and sight checkers for(var/victim in seen) if(isanimal(victim) || !isliving(victim)) seen -= victim @@ -156,7 +156,7 @@ to_chat(M, "You feel your tongue.... unfluffify...?") M.say("Pleh!") else - log_game("FERMICHEM: [M] ckey: [M.key]'s tongue has been made permanent") + log_reagent("FERMICHEM: [M] ckey: [M.key]'s tongue has been made permanent") /////////////////////////////////////////////////////////////////////////////////////////////// @@ -374,7 +374,7 @@ datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume) catto.color = "#[H.dna.features["mcolor"]]" catto.pseudo_death = TRUE H.forceMove(catto) - log_game("FERMICHEM: [H] ckey: [H.key] has been made into a cute catto.") + log_reagent("FERMICHEM: [H] ckey: [H.key] has been made into a cute catto.") SSblackbox.record_feedback("tally", "fermi_chem", 1, "cats") if(H.InCritical()) perma = TRUE @@ -408,7 +408,7 @@ datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume) H.say("*wag")//force update sprites. to_chat(H, "[words]") qdel(catto) - log_game("FERMICHEM: [H] ckey: [H.key] has returned to normal") + log_reagent("FERMICHEM: [H] ckey: [H.key] has returned to normal") /datum/reagent/fermi/secretcatchem/reaction_mob(var/mob/living/L) @@ -417,7 +417,7 @@ datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume) if(catto.origin) var/mob/living/carbon/human/H = catto.origin H.stat = CONSCIOUS - log_game("FERMICHEM: [catto] ckey: [catto.key] has returned to normal.") + log_reagent("FERMICHEM: [catto] ckey: [catto.key] has returned to normal.") to_chat(catto, "Your body shifts back to normal!") H.forceMove(catto.loc) catto.mind.transfer_to(H) diff --git a/modular_citadel/icons/mob/mam_tails.dmi b/modular_citadel/icons/mob/mam_tails.dmi index d91f15a3f7..a67c1b718c 100644 Binary files a/modular_citadel/icons/mob/mam_tails.dmi and b/modular_citadel/icons/mob/mam_tails.dmi differ diff --git a/modular_citadel/interface/skin.dmf b/modular_citadel/interface/skin.dmf deleted file mode 100644 index ec9a010128..0000000000 --- a/modular_citadel/interface/skin.dmf +++ /dev/null @@ -1,319 +0,0 @@ -macro "default" - - -menu "menu" - elem - name = "&File" - command = "" - saved-params = "is-checked" - elem - name = "&Quick screenshot\tF2" - command = ".screenshot auto" - category = "&File" - saved-params = "is-checked" - elem - name = "&Save screenshot as...\tShift+F2" - command = ".screenshot" - category = "&File" - saved-params = "is-checked" - elem - name = "" - command = "" - category = "&File" - saved-params = "is-checked" - elem "reconnectbutton" - name = "&Reconnect" - command = ".reconnect" - category = "&File" - saved-params = "is-checked" - elem - name = "&Quit\tAlt-F4" - command = ".quit" - category = "&File" - saved-params = "is-checked" - elem - name = "&Help" - command = "" - saved-params = "is-checked" - elem - name = "&Admin Help\tF1" - command = "adminhelp" - category = "&Help" - saved-params = "is-checked" - elem - name = "&Hotkeys" - command = "hotkeys-help" - category = "&Help" - saved-params = "is-checked" - - -window "mainwindow" - elem "mainwindow" - type = MAIN - pos = 0,0 - size = 640x440 - anchor1 = none - anchor2 = none - background-color = #242424 - is-default = true - saved-params = "pos;size;is-minimized;is-maximized" - icon = 'icons\\ss13_64.png' - macro = "default" - menu = "menu" - elem "split" - type = CHILD - pos = 0,0 - size = 637x440 - anchor1 = 0,0 - anchor2 = 100,100 - background-color = #272727 - saved-params = "splitter" - left = "mapwindow" - right = "infowindow" - is-vert = true - splitter = 75 - elem "asset_cache_browser" - type = BROWSER - pos = 0,0 - size = 200x200 - anchor1 = none - anchor2 = none - background-color = #272727 - is-visible = false - saved-params = "" - elem "tooltip" - type = BROWSER - pos = 0,0 - size = 999x999 - anchor1 = none - anchor2 = none - background-color = #272727 - is-visible = false - saved-params = "" - -window "mapwindow" - elem "mapwindow" - type = MAIN - pos = 418,0 - size = 1024x1024 - anchor1 = none - anchor2 = none - background-color = none - saved-params = "pos;size;is-minimized;is-maximized" - statusbar = false - is-pane = true - outer-size = 684x617 - inner-size = 662x561 - elem "map" - type = MAP - pos = 0,0 - size = 1024x1024 - anchor1 = 0,0 - anchor2 = 100,100 - font-family = "Arial" - font-size = 7 - is-default = true - saved-params = "icon-size" - zoom-mode = distort - style = ".center { text-align: center; }\n.maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; }\n.command_headset { font-weight: bold;\tfont-size: 8px; } .small { font-size: 6px; }\n.big { font-size: 8px; }\n.reallybig { font-size: 8px; }\n.extremelybig { font-size: 8px; }\n.greentext { color: #00ff00; font-size: 7px; }\n.redtext { color: #ff0000; font-size: 7px; }\n.clown { color: #ff69bf; font-size: 7px; font-weight: bold; }\n.his_grace { color: #15d512; }\n.hypnophrase { color: #0d0d0d; font-weight: bold; }\n.yell { font-weight: bold; }\n.italics { font-size: 6px; }" - -window "infowindow" - elem "infowindow" - type = MAIN - pos = 0,0 - size = 640x480 - anchor1 = none - anchor2 = none - background-color = #242424 - saved-params = "pos;size;is-minimized;is-maximized" - is-pane = true - elem "info" - type = CHILD - pos = 0,30 - size = 640x445 - anchor1 = 0,0 - anchor2 = 100,100 - background-color = #272727 - saved-params = "splitter" - left = "statwindow" - right = "outputwindow" - is-vert = false - elem "changelog" - type = BUTTON - pos = 16,5 - size = 104x20 - anchor1 = 3,0 - anchor2 = 19,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "Changelog" - command = "changelog" - elem "rules" - type = BUTTON - pos = 120,5 - size = 100x20 - anchor1 = 19,0 - anchor2 = 34,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "Rules" - command = "rules" - elem "wiki" - type = BUTTON - pos = 220,5 - size = 100x20 - anchor1 = 34,0 - anchor2 = 50,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "Wiki" - command = "wiki" - elem "forum" - type = BUTTON - pos = 320,5 - size = 100x20 - anchor1 = 50,0 - anchor2 = 66,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "Forum" - command = "forum" - elem "github" - type = BUTTON - pos = 420,5 - size = 100x20 - anchor1 = 66,0 - anchor2 = 81,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "GitHub" - command = "github" - elem "report-issue" - type = BUTTON - pos = 520,5 - size = 100x20 - anchor1 = 81,0 - anchor2 = 97,0 - font-size = 8 - text-color = #e0e0e0 - background-color = #a92c2c - saved-params = "is-checked" - text = "Report Issue" - command = "report-issue" - -window "outputwindow" - elem "outputwindow" - type = MAIN - pos = 0,0 - size = 640x480 - anchor1 = none - anchor2 = none - background-color = #272727 - saved-params = "pos;size;is-minimized;is-maximized" - titlebar = false - statusbar = false - can-close = false - can-minimize = false - can-resize = false - is-pane = true - elem "input" - type = INPUT - pos = 2,460 - size = 595x20 - anchor1 = 0,100 - anchor2 = 100,100 - background-color = #d3b5b5 - is-default = true - border = sunken - saved-params = "command" - elem "say" - type = BUTTON - pos = 600,460 - size = 37x20 - anchor1 = 100,100 - anchor2 = none - text-color = #e0e0e0 - background-color = #272727 - saved-params = "is-checked" - text = "Chat" - command = ".winset \"say.is-checked=true ? input.command=\"!say \\\"\" : input.command=\"" - is-flat = true - button-type = pushbox - elem "browseroutput" - type = BROWSER - pos = 0,0 - size = 640x456 - anchor1 = 0,0 - anchor2 = 100,100 - background-color = #272727 - is-visible = false - is-disabled = true - saved-params = "" - auto-format = false - elem "output" - type = OUTPUT - pos = 0,0 - size = 640x456 - anchor1 = 0,0 - anchor2 = 100,100 - text-color = #e0e0e0 - background-color = #272727 - is-default = true - saved-params = "" - -window "statwindow" - elem "statwindow" - type = MAIN - pos = 281,0 - size = 640x480 - anchor1 = none - anchor2 = none - background-color = #242424 - saved-params = "pos;size;is-minimized;is-maximized" - is-pane = true - elem "stat" - type = INFO - pos = 0,0 - size = 640x480 - anchor1 = 0,0 - anchor2 = 100,100 - text-color = #e0e0e0 - background-color = #272727 - is-default = true - saved-params = "" - tab-text-color = #e0e0e0 - tab-background-color = #242424 - prefix-color = #e0e0e0 - suffix-color = #e0e0e0 - -window "preferences_window" - elem "preferences_window" - type = MAIN - pos = 372,0 - size = 1280x1000 - anchor1 = none - anchor2 = none - is-visible = false - saved-params = "pos;size;is-minimized;is-maximized" - statusbar = false - elem "preferences_browser" - type = BROWSER - pos = 0,0 - size = 960x1000 - anchor1 = 0,0 - anchor2 = 75,100 - saved-params = "" - elem "character_preview_map" - type = MAP - pos = 960,0 - size = 320x1000 - anchor1 = 75,0 - anchor2 = 100,100 - right-click = true - saved-params = "zoom;letterbox;zoom-mode" - diff --git a/rust_g.dll b/rust_g.dll index 27ee495684..f4be6e730a 100644 Binary files a/rust_g.dll and b/rust_g.dll differ diff --git a/strings/tips.txt b/strings/tips.txt index c8f233bb1a..0176420dd3 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -64,6 +64,7 @@ As a Roboticist, you can greatly help out Shaft Miners by building a Firefighter As a Roboticist, you can augment people with cyborg limbs. Augmented limbs can easily be repaired with cables and welders. As a Roboticist, you can use your printer that is linked to the ore silo to teleport mats into your work place! As a Roboticist, you can upgrade cleanbots with adv mops and brooms to make them faster and better! +As a Roboticist, you can upgrade medical bots with diamond-tipped syringes, MK.II Hypospray, dispenser-sleeper-chemheater boards to make them inject faster, harder and better chems! As the AI, you can click on people's names to look at them. This only works if there are cameras that can see them. As the AI, you can quickly open and close doors by holding shift while clicking them, bolt them when holding ctrl, and even shock them while holding alt. As the AI, you can take pictures with your camera and upload them to newscasters. diff --git a/tgstation.dme b/tgstation.dme index ff68c231c2..2a13cb472e 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -94,7 +94,6 @@ #include "code\__DEFINES\research.dm" #include "code\__DEFINES\robots.dm" #include "code\__DEFINES\role_preferences.dm" -#include "code\__DEFINES\rust_g.config.dm" #include "code\__DEFINES\rust_g.dm" #include "code\__DEFINES\say.dm" #include "code\__DEFINES\security_levels.dm" @@ -120,6 +119,7 @@ #include "code\__DEFINES\vv.dm" #include "code\__DEFINES\wall_dents.dm" #include "code\__DEFINES\wires.dm" +#include "code\__DEFINES\admin\keybindings.dm" #include "code\__DEFINES\dcs\flags.dm" #include "code\__DEFINES\dcs\helpers.dm" #include "code\__DEFINES\dcs\signals.dm" @@ -186,7 +186,9 @@ #include "code\_globalvars\misc.dm" #include "code\_globalvars\regexes.dm" #include "code\_globalvars\traits.dm" +#include "code\_globalvars\lists\client.dm" #include "code\_globalvars\lists\flavor_misc.dm" +#include "code\_globalvars\lists\keybindings.dm" #include "code\_globalvars\lists\maintenance_loot.dm" #include "code\_globalvars\lists\mapping.dm" #include "code\_globalvars\lists\medals.dm" @@ -369,6 +371,7 @@ #include "code\datums\shuttles.dm" #include "code\datums\soullink.dm" #include "code\datums\spawners_menu.dm" +#include "code\datums\tgs_event_handler.dm" #include "code\datums\verbs.dm" #include "code\datums\weakrefs.dm" #include "code\datums\world_topic.dm" @@ -385,6 +388,7 @@ #include "code\datums\components\_component.dm" #include "code\datums\components\anti_magic.dm" #include "code\datums\components\armor_plate.dm" +#include "code\datums\components\art.dm" #include "code\datums\components\bane.dm" #include "code\datums\components\bouncy.dm" #include "code\datums\components\butchering.dm" @@ -525,6 +529,7 @@ #include "code\datums\elements\cleaning.dm" #include "code\datums\elements\dusts_on_catatonia.dm" #include "code\datums\elements\dusts_on_leaving_area.dm" +#include "code\datums\elements\dwarfism.dm" #include "code\datums\elements\earhealing.dm" #include "code\datums\elements\firestacker.dm" #include "code\datums\elements\flavor_text.dm" @@ -592,6 +597,7 @@ #include "code\datums\skills\medical.dm" #include "code\datums\skills\modifiers\job.dm" #include "code\datums\skills\modifiers\mood.dm" +#include "code\datums\skills\modifiers\organs.dm" #include "code\datums\status_effects\buffs.dm" #include "code\datums\status_effects\debuffs.dm" #include "code\datums\status_effects\gas.dm" @@ -1476,6 +1482,7 @@ #include "code\modules\antagonists\clockcult\clock_items\soul_vessel.dm" #include "code\modules\antagonists\clockcult\clock_items\wraith_spectacles.dm" #include "code\modules\antagonists\clockcult\clock_items\clock_weapons\_call_weapon.dm" +#include "code\modules\antagonists\clockcult\clock_items\clock_weapons\ratvarian_shield.dm" #include "code\modules\antagonists\clockcult\clock_items\clock_weapons\ratvarian_spear.dm" #include "code\modules\antagonists\clockcult\clock_mobs\_eminence.dm" #include "code\modules\antagonists\clockcult\clock_mobs\clockwork_marauder.dm" @@ -2145,16 +2152,22 @@ #include "code\modules\jobs\job_types\virologist.dm" #include "code\modules\jobs\job_types\warden.dm" #include "code\modules\jobs\map_changes\map_changes.dm" -#include "code\modules\keybindings\bindings_admin.dm" #include "code\modules\keybindings\bindings_atom.dm" -#include "code\modules\keybindings\bindings_carbon.dm" #include "code\modules\keybindings\bindings_client.dm" -#include "code\modules\keybindings\bindings_human.dm" -#include "code\modules\keybindings\bindings_living.dm" -#include "code\modules\keybindings\bindings_mob.dm" -#include "code\modules\keybindings\bindings_robot.dm" #include "code\modules\keybindings\focus.dm" #include "code\modules\keybindings\setup.dm" +#include "code\modules\keybindings\keybind\__defines.dm" +#include "code\modules\keybindings\keybind\_keybind.dm" +#include "code\modules\keybindings\keybind\admin.dm" +#include "code\modules\keybindings\keybind\carbon.dm" +#include "code\modules\keybindings\keybind\client.dm" +#include "code\modules\keybindings\keybind\emote.dm" +#include "code\modules\keybindings\keybind\human.dm" +#include "code\modules\keybindings\keybind\living.dm" +#include "code\modules\keybindings\keybind\mob.dm" +#include "code\modules\keybindings\keybind\movement.dm" +#include "code\modules\keybindings\keybind\robot.dm" +#include "code\modules\keybindings\keybind\targeting.dm" #include "code\modules\language\aphasia.dm" #include "code\modules\language\beachbum.dm" #include "code\modules\language\codespeak.dm" @@ -3337,9 +3350,6 @@ #include "interface\menu.dm" #include "interface\stylesheet.dm" #include "interface\skin.dmf" -#include "modular_citadel\code\__HELPERS\list2list.dm" -#include "modular_citadel\code\__HELPERS\lists.dm" -#include "modular_citadel\code\__HELPERS\mobs.dm" #include "modular_citadel\code\_onclick\click.dm" #include "modular_citadel\code\_onclick\item_attack.dm" #include "modular_citadel\code\_onclick\other_mobs.dm" @@ -3348,7 +3358,6 @@ #include "modular_citadel\code\_onclick\hud\stamina.dm" #include "modular_citadel\code\datums\components\souldeath.dm" #include "modular_citadel\code\datums\status_effects\chems.dm" -#include "modular_citadel\code\game\machinery\wishgranter.dm" #include "modular_citadel\code\game\objects\cit_screenshake.dm" #include "modular_citadel\code\game\objects\effects\temporary_visuals\souldeath.dm" #include "modular_citadel\code\modules\admin\chat_commands.dm" @@ -3356,7 +3365,6 @@ #include "modular_citadel\code\modules\admin\secrets.dm" #include "modular_citadel\code\modules\client\client_defines.dm" #include "modular_citadel\code\modules\client\client_procs.dm" -#include "modular_citadel\code\modules\client\preferences.dm" #include "modular_citadel\code\modules\client\preferences_savefile.dm" #include "modular_citadel\code\modules\client\preferences_toggles.dm" #include "modular_citadel\code\modules\client\loadout\__donator.dm" @@ -3423,5 +3431,4 @@ #include "modular_citadel\code\modules\reagents\objects\clothes.dm" #include "modular_citadel\code\modules\reagents\objects\items.dm" #include "modular_citadel\code\modules\reagents\reagents\cit_reagents.dm" -#include "modular_citadel\interface\skin.dmf" // END_INCLUDE diff --git a/tgui-next/packages/tgui/interfaces/Canvas.js b/tgui-next/packages/tgui/interfaces/Canvas.js new file mode 100644 index 0000000000..b30639697c --- /dev/null +++ b/tgui-next/packages/tgui/interfaces/Canvas.js @@ -0,0 +1,96 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Box, Button } from '../components'; +import { Component, createRef } from 'inferno'; +import { pureComponentHooks } from 'common/react'; + + +class PaintCanvas extends Component { + constructor(props) { + super(props); + this.canvasRef = createRef(); + this.onCVClick = props.onCanvasClick; + } + + componentDidMount() { + this.drawCanvas(this.props); + } + + componentDidUpdate() { + this.drawCanvas(this.props); + } + + drawCanvas(propSource) { + const ctx = this.canvasRef.current.getContext("2d"); + const grid = propSource.value; + const x_size = grid.length; + if (!x_size) { + return; + } + const y_size = grid[0].length; + const x_scale = Math.round(this.canvasRef.current.width / x_size); + const y_scale = Math.round(this.canvasRef.current.height / y_size); + ctx.save(); + ctx.scale(x_scale, y_scale); + for (let x = 0; x < grid.length; x++) { + const element = grid[x]; + for (let y = 0; y < element.length; y++) { + const color = element[y]; + ctx.fillStyle = color; + ctx.fillRect(x, y, 1, 1); + } + } + ctx.restore(); + } + + clickwrapper(event) { + const x_size = this.props.value.length; + if (!x_size) + { + return; + } + const y_size = this.props.value[0].length; + const x_scale = this.canvasRef.current.width / x_size; + const y_scale = this.canvasRef.current.height / y_size; + const x = Math.floor(event.offsetX / x_scale)+1; + const y = Math.floor(event.offsetY / y_scale)+1; + this.onCVClick(x, y); + } + + render() { + const { + res = 1, + value, + px_per_unit = 28, + ...rest + } = this.props; + const x_size = value.length * px_per_unit; + const y_size = x_size !== 0 ? value[0].length * px_per_unit : 0; + return ( + this.clickwrapper(e)}> + Canvas failed to render. + + ); + } +} +export const Canvas = props => { + const { act, data } = useBackend(props); + return ( + + act("paint", { x, y })} /> + + {!data.finalized + && act("finalize")} + content="Finalize" />} + {data.name} + + ); +}; diff --git a/tgui-next/packages/tgui/interfaces/Cargo.js b/tgui-next/packages/tgui/interfaces/Cargo.js index b31a25c611..133b1b00ab 100644 --- a/tgui-next/packages/tgui/interfaces/Cargo.js +++ b/tgui-next/packages/tgui/interfaces/Cargo.js @@ -154,6 +154,10 @@ const Catalog = props => {