Merge branch 'master' of https://github.com/tgstation/tgstation into upstream-sync

This commit is contained in:
xPokee
2025-09-24 10:13:01 -04:00
313 changed files with 6548 additions and 4624 deletions
@@ -1601,8 +1601,8 @@
/obj/structure/rack,
/obj/effect/decal/cleanable/dirt,
/obj/item/storage/toolbox/mechanical,
/obj/item/ammo_box/c38,
/obj/item/ammo_box/c38,
/obj/item/ammo_box/speedloader/c38,
/obj/item/ammo_box/speedloader/c38,
/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{
dir = 1
},
@@ -3661,7 +3661,7 @@
/obj/structure/window/reinforced/spawner/directional/south,
/obj/effect/spawner/random/contraband/permabrig_weapon,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/item/ammo_box/c38,
/obj/item/ammo_box/speedloader/c38,
/obj/effect/turf_decal/tile/dark_red/anticorner,
/turf/open/floor/iron/dark,
/area/ruin/space/has_grav/dangerous_research)
+1 -1
View File
@@ -28,7 +28,7 @@
/obj/item/clothing/shoes/workboots/mining,
/obj/item/clothing/gloves/color/black,
/obj/effect/mob_spawn/corpse/human/charredskeleton,
/obj/item/borg/sight/meson,
/obj/item/clothing/glasses/meson,
/obj/item/pickaxe/improvised,
/turf/open/misc/asteroid/basalt/airless,
/area/ruin/unpowered/no_grav)
+2 -2
View File
@@ -5093,8 +5093,8 @@
/obj/item/spess_knife,
/obj/item/clothing/suit/armor/vest/old,
/obj/item/gun/ballistic/rifle/boltaction,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/turf/open/floor/plating,
/area/ruin/space/ancientstation/delta/hall)
"Cc" = (
+118 -98
View File
@@ -103,7 +103,7 @@
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/cobweb,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"aR" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue{
@@ -264,7 +264,7 @@
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/dark,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"cm" = (
/obj/machinery/door/airlock/grunge,
/obj/structure/barricade/wooden/crude,
@@ -815,7 +815,7 @@
"gE" = (
/obj/item/clothing/suit/caution,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"gG" = (
/obj/effect/turf_decal/siding/dark_blue/corner{
dir = 4
@@ -952,7 +952,7 @@
dir = 5
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"hT" = (
/mob/living/basic/statue/mannequin{
name = "Dale Knox";
@@ -983,6 +983,9 @@
},
/turf/open/floor/engine,
/area/awaymission/museum)
"ia" = (
/turf/open/floor/iron/white/small,
/area/awaymission/museum/cafeteria)
"il" = (
/obj/structure/table/wood,
/obj/item/clothing/suit/costume/judgerobe,
@@ -1160,7 +1163,7 @@
name = "Restrooms"
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"jy" = (
/mob/living/basic/statue/mannequin{
name = "Dale Knox";
@@ -1183,7 +1186,7 @@
queue_id = "museum_right_wing"
},
/turf/closed/indestructible/reinforced,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"jF" = (
/obj/machinery/suit_storage_unit/open,
/obj/effect/turf_decal/box,
@@ -1315,7 +1318,7 @@
name = "Restrooms"
},
/turf/open/floor/iron,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"kA" = (
/obj/machinery/conveyor{
dir = 1
@@ -1332,7 +1335,7 @@
id = "museum_cafeteria"
},
/turf/open/floor/iron,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"kO" = (
/obj/structure/railing{
dir = 8
@@ -1740,7 +1743,7 @@
"nY" = (
/obj/structure/sign/poster/official/no_erp/directional/north,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"nZ" = (
/obj/structure/chair/sofa/bench/left{
dir = 1
@@ -1831,7 +1834,7 @@
queue_id = "museum_cafeteria"
},
/turf/closed/indestructible/reinforced,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"oQ" = (
/turf/open/floor/holofloor/beach/coast{
dir = 1
@@ -1914,7 +1917,7 @@
id = "museum_cafeteria"
},
/turf/open/floor/iron,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"pD" = (
/obj/structure/broken_flooring/corner/always_floorplane/directional/west,
/obj/effect/decal/cleanable/dirt/dust,
@@ -1954,7 +1957,7 @@
dir = 4
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"pX" = (
/obj/structure/rack,
/obj/effect/spawner/random/maintenance/two,
@@ -2317,6 +2320,13 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine,
/area/awaymission/museum)
"sR" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue{
dir = 10
},
/turf/open/floor/iron/dark,
/area/awaymission/museum/cafeteria)
"sX" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue{
@@ -2522,7 +2532,7 @@
/obj/structure/tank_holder/extinguisher/anti,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"up" = (
/obj/effect/turf_decal/siding/wood{
dir = 4
@@ -2538,7 +2548,7 @@
id_tag = "museum_toilet2"
},
/turf/open/floor/iron,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"ut" = (
/obj/machinery/light/very_dim/directional/north,
/obj/effect/decal/cleanable/dirt/dust,
@@ -2546,7 +2556,7 @@
/obj/structure/mop_bucket,
/obj/effect/decal/cleanable/cobweb/cobweb2,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"uu" = (
/obj/structure/rack,
/obj/effect/spawner/random/engineering/material,
@@ -2711,7 +2721,7 @@
note_info = "I'VE WORKED HERE FOR 7 YEARS! JUST TO BE REPLACED BY A VENDING MACHINE?! YOU KNOW WHAT? FUCK YOU, I'VE LOCKED DOWN THE CAFETERIA AND WON'T BE COMING OUT 'TILL YOU GIVE ME MY JOB BACK!"
},
/turf/open/floor/iron,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"wh" = (
/obj/structure/broken_flooring/corner/always_floorplane/directional/west,
/obj/structure/lattice,
@@ -2723,7 +2733,7 @@
id = "museum_right_wing"
},
/turf/open/floor/iron,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"wk" = (
/obj/machinery/vending/dinnerware,
/turf/open/floor/iron/freezer,
@@ -2805,7 +2815,7 @@
},
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/turf/open/floor/iron/dark,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"wZ" = (
/turf/open/misc/beach/coast{
dir = 1
@@ -3547,7 +3557,7 @@
/obj/structure/mirror/directional/east,
/obj/structure/sink/directional/west,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"CI" = (
/obj/effect/turf_decal/caution,
/obj/effect/decal/cleanable/dirt/dust,
@@ -3973,7 +3983,7 @@
dir = 4
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"FY" = (
/obj/structure/chair/sofa/bench/left,
/turf/open/floor/iron/cafeteria,
@@ -4156,7 +4166,7 @@
id = "museum_right_wing"
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"HE" = (
/obj/effect/turf_decal/siding/dark_blue{
dir = 1
@@ -4210,7 +4220,7 @@
},
/obj/machinery/light/small/dim/directional/west,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"HY" = (
/obj/machinery/light/floor,
/obj/effect/decal/cleanable/dirt/dust,
@@ -4242,7 +4252,7 @@
/area/awaymission/museum)
"Ir" = (
/turf/closed/indestructible/fakedoor,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"Iu" = (
/turf/open/floor/mineral/titanium/blue,
/area/awaymission/museum)
@@ -4369,7 +4379,7 @@
id_tag = "museum_toilet1"
},
/turf/open/floor/iron,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"Js" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue{
@@ -4493,7 +4503,7 @@
content = list("Instructions; stand upright; remove safety clip; aim noozle at base of fire... the rest is up to you.")
},
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"KB" = (
/obj/structure/sign/warning/no_smoking/circle/directional/east,
/turf/open/floor/iron/cafeteria,
@@ -4623,7 +4633,7 @@
/obj/effect/turf_decal/siding/dark_blue,
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/turf/open/floor/iron/dark,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"Mg" = (
/obj/structure/plaque/static_plaque/golden/commission/tram,
/turf/closed/indestructible/reinforced,
@@ -4971,6 +4981,12 @@
},
/turf/open/indestructible/plating,
/area/awaymission/museum)
"PI" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/dark_blue,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/dark,
/area/awaymission/museum/cafeteria)
"PK" = (
/obj/machinery/door/poddoor{
id = "gatewayfake"
@@ -5291,7 +5307,7 @@
/obj/effect/decal/cleanable/dirt/dust,
/obj/structure/fluff/fake_scrubber,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"So" = (
/obj/machinery/shower/directional/east,
/turf/open/floor/iron/white/textured_large,
@@ -5340,7 +5356,7 @@
late_initialize_pop = 1
},
/turf/open/floor/iron/dark,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"SU" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/item/stack/spacecash/c1000,
@@ -5491,6 +5507,10 @@
/obj/structure/fluff/fake_scrubber,
/turf/open/floor/iron,
/area/awaymission/museum)
"Up" = (
/obj/machinery/light/floor,
/turf/open/floor/iron,
/area/awaymission/museum/cafeteria)
"Uq" = (
/obj/effect/smooths_with_walls,
/turf/cordon/secret,
@@ -5543,7 +5563,7 @@
/obj/structure/sink/directional/west,
/obj/effect/decal/cleanable/blood/oil/slippery,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"UI" = (
/obj/effect/turf_decal/tile/green/opposingcorners,
/obj/effect/decal/cleanable/dirt/dust,
@@ -5878,7 +5898,7 @@
},
/obj/machinery/light/small/dim/directional/west,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"WZ" = (
/obj/structure/chair/sofa/bench{
dir = 1
@@ -6026,7 +6046,7 @@
/obj/effect/decal/cleanable/dirt/dust,
/obj/structure/fluff/fake_camera,
/turf/open/floor/iron/white/small,
/area/awaymission/museum)
/area/awaymission/museum/cafeteria)
"Yr" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/structure/table/reinforced,
@@ -43388,11 +43408,11 @@ re
re
re
re
FK
Ph
HD
wi
ST
FK
Ph
re
re
re
@@ -43637,17 +43657,17 @@ re
re
re
re
FK
FK
FK
FK
FK
FK
FK
Ph
Ph
Ph
Ph
Ph
Ph
Ph
re
FK
aa
uY
Ph
PI
ms
ci
jC
re
@@ -43894,19 +43914,19 @@ re
re
re
re
FK
Ph
aO
FK
Ph
WY
FK
Ph
HW
FK
FK
FK
Ph
Ph
Ph
Mb
TM
Up
wV
FK
Ph
re
re
re
@@ -44151,19 +44171,19 @@ re
re
re
re
FK
Ph
wg
FK
Ph
us
FK
Ph
Jp
FK
Ph
um
FK
Ph
Mb
uY
ms
wV
FK
Ph
re
re
re
@@ -44408,17 +44428,17 @@ re
re
re
re
FK
Gn
Gn
Gn
Ph
ia
ia
ia
Sm
Gn
ia
Kz
Gn
FK
ia
Ph
ju
uY
ms
ci
Ir
re
@@ -44665,19 +44685,19 @@ re
re
re
re
FK
Ph
nY
Gn
Gn
Gn
Gn
Gn
Gn
ia
ia
ia
ia
ia
ia
kx
uY
uY
ms
ms
wV
FK
Ph
re
re
re
@@ -44922,19 +44942,19 @@ re
re
re
re
FK
Ph
ut
UH
gE
CG
Gn
ia
CG
Yn
FK
RC
TM
Ph
sR
Up
FU
FK
Ph
re
re
re
@@ -45179,19 +45199,19 @@ re
re
re
re
FK
FK
FK
FK
FK
FK
FK
FK
FK
Ph
Ph
Ph
Ph
Ph
Ph
Ph
Ph
Ph
Mb
uY
ms
wV
FK
Ph
Uq
re
re
@@ -45444,9 +45464,9 @@ re
re
re
re
FK
Ph
pN
uY
ms
hS
oP
re
@@ -45701,11 +45721,11 @@ re
re
re
re
FK
FK
Ph
Ph
pz
kL
FK
Ph
re
re
re
+2 -2
View File
@@ -2113,8 +2113,8 @@
/area/awaymission/snowdin/post/hydro)
"hZ" = (
/obj/item/gun/ballistic/rifle/boltaction,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/structure/closet/secure_closet{
icon_state = "sec";
name = "security officer's locker";
@@ -36029,12 +36029,9 @@
/turf/open/floor/plating,
/area/station/engineering/atmos/project)
"kpz" = (
/obj/structure/rack,
/obj/item/aicard,
/obj/item/pai_card,
/obj/item/circuitboard/aicore,
/obj/machinery/power/apc/auto_name/directional/north,
/obj/structure/cable,
/obj/machinery/modular_computer/preset/research,
/turf/open/floor/wood,
/area/station/command/heads_quarters/rd)
"kpC" = (
@@ -39959,6 +39956,10 @@
/area/station/commons/fitness/recreation)
"lAu" = (
/obj/structure/cable,
/obj/structure/rack,
/obj/item/aicard,
/obj/item/pai_card,
/obj/item/circuitboard/aicore,
/turf/open/floor/wood,
/area/station/command/heads_quarters/rd)
"lAE" = (
@@ -82589,7 +82590,7 @@
/turf/open/floor/iron,
/area/station/hallway/primary/aft)
"xZp" = (
/obj/machinery/computer/rdconsole,
/obj/machinery/modular_computer/preset/research,
/turf/open/floor/carpet,
/area/station/command/bridge)
"xZG" = (
@@ -15709,10 +15709,10 @@
},
/area/station/hallway/primary/fore)
"dRh" = (
/obj/machinery/telecomms/bus/preset_four,
/obj/effect/turf_decal/tile/brown/anticorner/contrasted{
dir = 1
},
/obj/machinery/telecomms/bus/preset_two,
/turf/open/floor/iron/telecomms,
/area/station/tcommsat/server)
"dRo" = (
@@ -39973,10 +39973,10 @@
/turf/open/floor/iron,
/area/station/security/range)
"jPC" = (
/obj/machinery/telecomms/bus/preset_two,
/obj/effect/turf_decal/tile/neutral/anticorner/contrasted{
dir = 4
},
/obj/machinery/telecomms/bus/preset_four,
/turf/open/floor/iron/telecomms,
/area/station/tcommsat/server)
"jPE" = (
@@ -47677,9 +47677,6 @@
/area/station/engineering/atmos/mix)
"lKk" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/effect/turf_decal/siding/green/corner{
dir = 4
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/landmark/event_spawn,
/turf/open/floor/iron,
@@ -27799,7 +27799,7 @@
/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass,
/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass,
/obj/item/gun/ballistic/revolver/russian,
/obj/item/ammo_box/a357,
/obj/item/ammo_box/speedloader/c357,
/obj/item/reagent_containers/cup/glass/bottle/vodka/badminka,
/obj/effect/turf_decal/bot_white/left,
/obj/effect/turf_decal/tile/neutral/fourcorners,
File diff suppressed because it is too large Load Diff
@@ -15284,6 +15284,7 @@
dir = 1
},
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/item/pipe_dispenser,
/turf/open/floor/engine,
/area/station/engineering/supermatter/room)
"cpk" = (
@@ -44751,7 +44752,6 @@
/obj/structure/table/reinforced,
/obj/item/t_scanner,
/obj/item/pipe_dispenser,
/obj/item/pipe_dispenser,
/obj/item/storage/belt/utility,
/obj/effect/turf_decal/bot,
/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible,
+2 -2
View File
@@ -9129,8 +9129,8 @@
/area/centcom/central_command_areas/courtroom)
"QY" = (
/obj/item/storage/box/handcuffs,
/obj/item/ammo_box/a357,
/obj/item/ammo_box/a357,
/obj/item/ammo_box/speedloader/c357,
/obj/item/ammo_box/speedloader/c357,
/obj/item/gun/ballistic/revolver/mateba,
/obj/structure/table/reinforced,
/obj/machinery/firealarm/directional/south,
@@ -256,6 +256,10 @@
/obj/structure/cable,
/turf/open/floor/catwalk_floor,
/area/station/maintenance/department/crew_quarters/dorms)
"Gv" = (
/obj/effect/landmark/firealarm_sanity,
/turf/open/floor/grass,
/area/station/asteroid)
"GE" = (
/obj/structure/flora/bush/flowers_br/style_random,
/turf/open/floor/grass,
@@ -1082,7 +1086,7 @@ GE
vg
ci
rO
rO
Gv
rO
rO
Cp
+1 -1
View File
@@ -45250,7 +45250,7 @@
/obj/structure/safe/vault,
/obj/item/clothing/head/costume/bearpelt,
/obj/item/gun/ballistic/revolver/russian,
/obj/item/ammo_box/a357,
/obj/item/ammo_box/speedloader/c357,
/obj/effect/turf_decal/bot_white/left,
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/machinery/light/dim/directional/east,
@@ -45211,6 +45211,7 @@
pixel_x = -3;
pixel_y = 3
},
/obj/item/clothing/gloves/color/yellow,
/turf/open/floor/iron/textured,
/area/station/engineering/storage/tech)
"pEk" = (
+6 -6
View File
@@ -6,9 +6,9 @@
/area/centcom/basketball)
"aw" = (
/obj/structure/table,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/effect/turf_decal/stripes/line{
dir = 8
},
@@ -348,9 +348,9 @@
/area/centcom/basketball)
"Bd" = (
/obj/structure/table,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/turf/open/floor/iron/dark,
/area/centcom/basketball)
"BJ" = (
+1 -1
View File
@@ -876,7 +876,7 @@
/area/deathmatch)
"Kz" = (
/obj/effect/spawner/random/trash/box,
/obj/item/ammo_box/a357,
/obj/item/ammo_box/speedloader/c357,
/turf/open/indestructible/plating,
/area/deathmatch)
"KC" = (
+4 -4
View File
@@ -34,7 +34,7 @@
locked = 0
},
/obj/effect/decal/cleanable/fuel_pool/hivis,
/obj/item/ammo_box/c38,
/obj/item/ammo_box/speedloader/c38,
/obj/effect/turf_decal/stripes/asteroid/line{
dir = 6
},
@@ -242,7 +242,7 @@
locked = 0
},
/obj/effect/decal/cleanable/fuel_pool/hivis,
/obj/item/ammo_box/c38,
/obj/item/ammo_box/speedloader/c38,
/obj/effect/turf_decal/stripes/asteroid/line{
dir = 4
},
@@ -617,7 +617,7 @@
/area/deathmatch)
"EX" = (
/obj/structure/lattice/catwalk,
/obj/item/ammo_box/c38/match,
/obj/item/ammo_box/speedloader/c38/match,
/turf/open/chasm/true/no_smooth/fake_motion_sand/fast,
/area/deathmatch)
"Fa" = (
@@ -932,7 +932,7 @@
locked = 0
},
/obj/effect/decal/cleanable/fuel_pool/hivis,
/obj/item/ammo_box/c38,
/obj/item/ammo_box/speedloader/c38,
/obj/effect/turf_decal/stripes/asteroid/line{
dir = 4
},
@@ -564,7 +564,7 @@
/area/deathmatch)
"Kb" = (
/obj/structure/table/reinforced,
/obj/item/ammo_box/strilka310/surplus,
/obj/item/ammo_box/speedloader/strilka310/surplus,
/turf/open/indestructible/dark/smooth_large,
/area/deathmatch)
"Kr" = (
+1 -1
View File
@@ -242,7 +242,7 @@
/obj/effect/turf_decal/siding/wood{
dir = 4
},
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/effect/decal/cleanable/dirt,
/obj/structure/railing/corner/end/flip{
dir = 8
+1 -1
View File
@@ -77,7 +77,7 @@
/obj/effect/turf_decal/trimline/dark_blue/corner{
dir = 8
},
/obj/item/ammo_box/a357,
/obj/item/ammo_box/speedloader/c357,
/obj/item/gun/ballistic/revolver/golden,
/turf/open/floor/iron/smooth_corner{
dir = 8
+6 -6
View File
@@ -147,25 +147,25 @@
"gE" = (
/obj/effect/turf_decal/tile/dark_blue/diagonal_edge,
/obj/structure/table/reinforced/plasmarglass,
/obj/item/ammo_box/c38/match{
/obj/item/ammo_box/speedloader/c38/match{
pixel_x = -5;
pixel_y = 4
},
/obj/item/ammo_box/c38/match{
/obj/item/ammo_box/speedloader/c38/match{
pixel_x = -1;
pixel_y = 4
},
/obj/item/ammo_box/c38/match{
/obj/item/ammo_box/speedloader/c38/match{
pixel_x = 3;
pixel_y = 4
},
/obj/item/ammo_box/c38/match{
/obj/item/ammo_box/speedloader/c38/match{
pixel_x = -8
},
/obj/item/ammo_box/c38/match{
/obj/item/ammo_box/speedloader/c38/match{
pixel_x = -4
},
/obj/item/ammo_box/c38/match,
/obj/item/ammo_box/speedloader/c38/match,
/turf/open/floor/iron/white/diagonal,
/area/shuttle/hunter)
"gW" = (
+5 -5
View File
@@ -173,10 +173,10 @@
/obj/structure/closet/crate/secure/weapon{
name = "surplus crate"
},
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/turf/open/floor/pod/dark,
/area/shuttle/hunter/russian)
"qF" = (
@@ -611,7 +611,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/item/gun/ballistic/automatic/pistol,
/obj/item/ammo_box/magazine/m9mm,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader/strilka310,
/obj/item/crowbar,
/turf/open/floor/pod/dark,
/area/shuttle/hunter/russian)
+4 -4
View File
@@ -802,18 +802,18 @@
dir = 8
},
/obj/effect/turf_decal/bot,
/obj/item/ammo_box/strilka310/phasic{
/obj/item/ammo_box/speedloader/strilka310/phasic{
pixel_y = -5;
pixel_x = 5
},
/obj/item/ammo_box/strilka310/phasic{
/obj/item/ammo_box/speedloader/strilka310/phasic{
pixel_x = 5
},
/obj/item/ammo_box/strilka310/phasic{
/obj/item/ammo_box/speedloader/strilka310/phasic{
pixel_x = -5;
pixel_y = -5
},
/obj/item/ammo_box/strilka310/phasic{
/obj/item/ammo_box/speedloader/strilka310/phasic{
pixel_x = -5
},
/obj/item/gun/ballistic/rifle/boltaction/prime{
+3 -3
View File
@@ -2205,11 +2205,11 @@
pixel_y = 4
},
/obj/item/ammo_box/c10mm,
/obj/item/ammo_box/a357{
/obj/item/ammo_box/speedloader/c357{
icon_state = "357-7";
pixel_y = 3
},
/obj/item/ammo_box/a357{
/obj/item/ammo_box/speedloader/c357{
icon_state = "357-7";
pixel_x = 2
},
@@ -2360,7 +2360,7 @@
/obj/item/storage/lockbox/medal{
req_access = list("syndicate_leader")
},
/obj/item/ammo_box/a357{
/obj/item/ammo_box/speedloader/c357{
icon_state = "357-7";
pixel_x = 2
},
+1 -1
View File
@@ -4096,7 +4096,7 @@
/area/virtual_domain)
"Il" = (
/obj/structure/lattice,
/obj/item/ammo_box/strilka310/surplus,
/obj/item/ammo_box/speedloader/strilka310/surplus,
/turf/open/space/basic,
/area/virtual_domain)
"Io" = (
+9 -3
View File
@@ -236,16 +236,22 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
// Ammo box multiload defines
/// Ammo box does not accept multiload in or out, e.g. ammo box CANNOT transfer multiple casings in one action, either IN or OUT.
#define AMMO_BOX_MULTILOAD_NONE 0
/// Ammo box accepts multiload going in, e.g. ammo box can transfer multiple casings IN at once.
/// Ammo box accepts multiload going in, e.g. a magazine being fed from a stripper clip.
#define AMMO_BOX_MULTILOAD_IN (1 << 0)
/// Ammo box accepts multiload going out, e.g. ammo box can transfer multiple casings OUT at once.
/// Ammo box can multiload going out to other ammo boxes, but not loaded magazines, e.g. an ammo box feeding into an unloaded magazine.
#define AMMO_BOX_MULTILOAD_OUT (1 << 1)
/// Ammo box can multiload going out into loaded magazines, e.g. a speedloader feeding into a revolver's cylinder or a stripper clip feeding into a loaded magazine.
#define AMMO_BOX_MULTILOAD_OUT_LOADED (1 << 2)
/// Ammo box accepts multiload in AND out, e.g. ammo box can transfer multiple casings IN at once *and* OUT at once.
#define AMMO_BOX_MULTILOAD_BOTH AMMO_BOX_MULTILOAD_IN | AMMO_BOX_MULTILOAD_OUT
/// Ammo boxes are assumed to have some variety of magazine loading assistance.
#define AMMO_BOX_MULTILOAD_BOTH (AMMO_BOX_MULTILOAD_IN | AMMO_BOX_MULTILOAD_OUT)
/// Ammo box can accept multiloads, AND can give multiloads to boxes that are loaded or not loaded. Individual stripper clips would count for this.
#define AMMO_BOX_MULTILOAD_ALL (AMMO_BOX_MULTILOAD_IN | AMMO_BOX_MULTILOAD_OUT | AMMO_BOX_MULTILOAD_OUT_LOADED)
DEFINE_BITFIELD(ammo_box_multiload, list(
"LOAD_IN" = AMMO_BOX_MULTILOAD_IN,
"LOAD_OUT" = AMMO_BOX_MULTILOAD_OUT,
"LOAD_OUT_LOADED" = AMMO_BOX_MULTILOAD_OUT_LOADED,
))
#define SUPPRESSED_NONE 0
@@ -65,16 +65,15 @@
#define COMSIG_MOVABLE_CANCEL_HEARING (1<<0)
///from base of atom/movable/Hear(): (proc args list(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range))
#define COMSIG_MOVABLE_HEAR "movable_hear"
#define HEARING_MESSAGE 1
#define HEARING_SPEAKER 2
#define HEARING_LANGUAGE 3
#define HEARING_RAW_MESSAGE 4
#define HEARING_RADIO_FREQ 5
#define HEARING_RADIO_FREQ_NAME 6
#define HEARING_RADIO_FREQ_COLOR 7
#define HEARING_SPANS 8
#define HEARING_MESSAGE_MODE 9
#define HEARING_RANGE 10
#define HEARING_SPEAKER 1
#define HEARING_LANGUAGE 2
#define HEARING_RAW_MESSAGE 3
#define HEARING_RADIO_FREQ 4
#define HEARING_RADIO_FREQ_NAME 5
#define HEARING_RADIO_FREQ_COLOR 6
#define HEARING_SPANS 7
#define HEARING_MESSAGE_MODE 8
#define HEARING_RANGE 9
///called when space wind can't move a movable. (pressure_difference, pressure_direction)
#define COMSIG_MOVABLE_RESISTED_SPACEWIND "movable_resisted_wind"
@@ -116,7 +115,7 @@
#define MOVABLE_SAY_QUOTE_MESSAGE_SPANS 2
#define MOVABLE_SAY_QUOTE_MESSAGE_MODS 3
/// From /datum/element/immerse/proc/add_submerge_overlay(): (visual_overlay)
/// From /datum/element/immerse/proc/add_immerse_overlay(): (atom/movable/immerse_mask/effect_relay)
#define COMSIG_MOVABLE_EDIT_UNIQUE_IMMERSE_OVERLAY "movable_edit_unique_submerge_overlay"
/// From base of area/Exited(): (area/left, direction)
#define COMSIG_MOVABLE_EXITED_AREA "movable_exited_area"
@@ -351,4 +351,7 @@
#define COMSIG_LIVING_GHOSTROLE_INFO "living_ghostrole_info"
///from mob/living/befriend()
#define COMSIG_LIVING_MADE_NEW_FRIEND "made_new_friend"
#define COMSIG_LIVING_MADE_NEW_FRIEND "living_made_new_friend"
/// From /mob/living/update_offsets(animate) : (new_x, new_y, new_w, new_z, animate)
#define COMSIG_LIVING_UPDATE_OFFSETS "living_update_offsets"
-7
View File
@@ -270,13 +270,6 @@
#define GASFIRE_LAYER 5.05
#define RIPPLE_LAYER 5.1
/**
* The layer of the visual overlay used in the submerge element.
* The vis overlay inherits the planes of the movables it's attached to (that also have KEEP_TOGETHER added)
* We just have to make sure the visual overlay is rendered above all the other overlays of those movables.
*/
#define WATER_VISUAL_OVERLAY_LAYER 1000
// SEETHROUGH_PLANE layers here, tho it has no layer values
//---------- LIGHTING -------------
+1
View File
@@ -25,6 +25,7 @@
#define BORGTHERM (1<<1)
#define BORGXRAY (1<<2)
#define BORGMATERIAL (1<<3)
#define BORGDEFAULT 0
//for clothing visor toggles, these determine which vars to toggle
#define VISOR_FLASHPROTECT (1<<0)
-5
View File
@@ -1192,11 +1192,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_ELEVATING_OBJECT "elevating_object"
/// From [/datum/element/elevation_core] for purpose of checking if the turf has the trait from an instance of the element
#define TRAIT_ELEVATED_TURF "elevated_turf"
/**
* With this, the immerse overlay will give the atom its own submersion visual overlay
* instead of one that's also shared with other movables, thus making editing its appearance possible.
*/
#define TRAIT_UNIQUE_IMMERSE "unique_immerse"
/// This item is currently under the control of telekinesis
#define TRAIT_TELEKINESIS_CONTROLLED "telekinesis_controlled"
+3 -3
View File
@@ -272,19 +272,19 @@ GLOBAL_LIST_INIT(wounding_types_to_series, list(
RETURN_TYPE(/datum/wound) // note that just because its set to return this doesnt mean its non-nullable
var/list/wounding_type_list = list()
for (var/wounding_type as anything in wounding_types)
for (var/wounding_type in wounding_types)
wounding_type_list += GLOB.wounding_types_to_series[wounding_type]
if (!length(wounding_type_list))
return null
var/list/datum/wound/paths_to_pick_from = list()
for (var/series as anything in shuffle(wounding_type_list))
for (var/series in shuffle(wounding_type_list))
var/list/severity_list = GLOB.wound_series_collections[series]
if (!length(severity_list))
continue
var/picked_severity
for (var/severity_text as anything in shuffle(GLOB.wound_severities_chronological))
for (var/severity_text in shuffle(GLOB.wound_severities_chronological))
var/severity = text2num(severity_text)
if (!ISINRANGE(severity, severity_min, severity_max))
continue
+1
View File
@@ -197,6 +197,7 @@
} while(FALSE)
#define SORT_FIRST_INDEX(list) (list[1])
#define SORT_PRIORITY_INDEX(list) (list["priority"])
#define SORT_COMPARE_DIRECTLY(thing) (thing)
#define SORT_VAR_NO_TYPE(varname) var/varname
/****
+2 -6
View File
@@ -6,9 +6,7 @@
var/gun_neurons_activated = controller.blackboard[BB_MONKEY_GUN_NEURONS_ACTIVATED]
var/top_force = 0
var/obj/item/top_force_item
for(var/obj/item/item as anything in held_weapons)
if(!item)
continue
for(var/obj/item/item in held_weapons)
if(HAS_TRAIT(item, TRAIT_NEEDS_TWO_HANDS) || controller.blackboard[BB_MONKEY_BLACKLISTITEMS][item])
continue
if(gun_neurons_activated && isgun(item))
@@ -19,9 +17,7 @@
top_force = item.force
top_force_item = item
for(var/obj/item/item as anything in choices)
if(!item)
continue
for(var/obj/item/item in choices)
if(HAS_TRAIT(item, TRAIT_NEEDS_TWO_HANDS) || controller.blackboard[BB_MONKEY_BLACKLISTITEMS][item])
continue
if(gun_neurons_activated && isgun(item))
+3 -3
View File
@@ -89,7 +89,7 @@
var/list/material_map_amounts = list()
for(var/atom/object as anything in reccursive_contents)
var/list/item_materials = object.custom_materials
for(var/mat as anything in custom_materials)
for(var/mat in custom_materials)
var/mat_amount = 1 //no materials mean we assign this default amount
if(length(item_materials))
mat_amount = item_materials[mat] || 1 //if this object doesn't have our material type then assign a default value of 1
@@ -104,7 +104,7 @@
mat_list_per_item += mat_amount
//Step 3: normalize & scale material_map_amounts with material_map_sum
for(var/mat as anything in material_map_amounts)
for(var/mat in material_map_amounts)
var/mat_sum = material_map_sum[mat]
var/list/mat_per_item = material_map_amounts[mat]
for(var/i in 1 to mat_per_item.len)
@@ -114,7 +114,7 @@
var/index = 1
for(var/atom/object as anything in reccursive_contents)
var/list/final_material_list = list()
for(var/mat as anything in material_map_amounts)
for(var/mat in material_map_amounts)
var/list/mat_per_item = material_map_amounts[mat]
final_material_list[mat] = mat_per_item[index]
object.set_custom_materials(final_material_list, multiplier)
+10 -7
View File
@@ -34,6 +34,7 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars, list(
"parent",
"parent_type",
"power_supply",
"pixloc",
"quirks",
"reagents",
"_signal_procs",
@@ -65,14 +66,16 @@ GLOBAL_PROTECT(duplicate_forbidden_vars)
var/atom/made_copy = new original.type(spawning_location)
for(var/atom_vars in original.vars - GLOB.duplicate_forbidden_vars)
if(islist(original.vars[atom_vars]))
var/list/var_list = original.vars[atom_vars]
made_copy.vars[atom_vars] = var_list.Copy()
continue
else if(istype(original.vars[atom_vars], /datum) || ismob(original.vars[atom_vars]))
for(var/atom_vars in (original.vars - GLOB.duplicate_forbidden_vars))
var/var_value = original.vars[atom_vars]
if(isdatum(var_value))
continue // this would reference the original's object, that will break when it is used or deleted.
made_copy.vars[atom_vars] = original.vars[atom_vars]
if(islist(var_value))
var/list/var_list = var_value
var_value = var_list.Copy()
made_copy.vars[atom_vars] = var_value
if(isliving(made_copy))
if(iscarbon(made_copy))
+1 -1
View File
@@ -161,7 +161,7 @@
/proc/init_subtypes_w_path_keys(prototype, list/L)
if(!istype(L))
L = list()
for(var/path as anything in subtypesof(prototype))
for(var/path in subtypesof(prototype))
L[path] = new path()
return L
+1 -1
View File
@@ -7,7 +7,7 @@
playsound(origin_turf, 'sound/items/airhorn/airhorn.ogg', 100, TRUE)
for(var/mob/living/carbon/victim as anything in hearers(max(light_range, medium_range, heavy_range), origin_turf))
for(var/mob/living/carbon/victim in hearers(max(light_range, medium_range, heavy_range), origin_turf))
if(!victim.can_hear())
continue
var/distance = get_dist(origin_turf, victim.loc)
+3
View File
@@ -29,6 +29,9 @@
/obj/item/organ = "ORGAN",
/obj/item/mod/control = "MODSUIT",
/obj/item/mod/module = "MODSUIT_MOD",
/obj/item/ammo_box = "AMMOBOX",
/obj/item/ammo_box/magazine = "AMMOBOX_MAGAZINE",
/obj/item/ammo_box/speedloader = "AMMOBOX_SPEEDLOADER",
/obj/item/gun = "GUN",
/obj/item/gun/magic = "GUN_MAGIC",
/obj/item/gun/energy = "GUN_ENERGY",
+3 -3
View File
@@ -121,7 +121,7 @@ GLOBAL_LIST_INIT(plant_traits, init_plant_traits())
// So instead, we're gonna wing it
var/list/reagent_to_react_count = list()
for(var/datum/chemical_reaction/reaction as anything in reactions)
for(var/reagent_id as anything in reaction.required_reagents)
for(var/reagent_id in reaction.required_reagents)
reagent_to_react_count[reagent_id] += 1
var/list/reaction_lookup = GLOB.chemical_reactions_list_reactant_index
@@ -130,7 +130,7 @@ GLOBAL_LIST_INIT(plant_traits, init_plant_traits())
// Doing this separately because it relies on the loop above, and this is easier to parse
for(var/datum/chemical_reaction/reaction as anything in reactions)
var/preferred_id = null
for(var/reagent_id as anything in reaction.required_reagents)
for(var/reagent_id in reaction.required_reagents)
if(isnull(preferred_id))
preferred_id = reagent_id
continue
@@ -207,5 +207,5 @@ GLOBAL_LIST_INIT(plant_traits, init_plant_traits())
only_names = sort_list(only_names)
//build map with sorted keys
for(var/name as anything in only_names)
for(var/name in only_names)
.[name] = name_to_reagent[name]
-1
View File
@@ -90,7 +90,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH" = TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH,
"TRAIT_TELEKINESIS_CONTROLLED" = TRAIT_TELEKINESIS_CONTROLLED,
"TRAIT_UNDERFLOOR" = TRAIT_UNDERFLOOR,
"TRAIT_UNIQUE_IMMERSE" = TRAIT_UNIQUE_IMMERSE,
"TRAIT_VALID_DNA_INFUSION" = TRAIT_VALID_DNA_INFUSION,
"TRAIT_WADDLING" = TRAIT_WADDLING,
"TRAIT_WAS_RENAMED" = TRAIT_WAS_RENAMED,
+2 -2
View File
@@ -213,7 +213,7 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
if(should_sight_scale(new_sight) == should_sight_scale(old_sight))
return
for(var/group_key as anything in master_groups)
for(var/group_key in master_groups)
var/datum/plane_master_group/group = master_groups[group_key]
group.build_planes_offset(src, current_plane_offset)
@@ -237,7 +237,7 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
current_plane_offset = new_offset
SEND_SIGNAL(src, COMSIG_HUD_OFFSET_CHANGED, old_offset, new_offset)
for(var/group_key as anything in master_groups)
for(var/group_key in master_groups)
var/datum/plane_master_group/group = master_groups[group_key]
group.build_planes_offset(src, new_offset)
@@ -31,21 +31,21 @@ INITIALIZE_IMMEDIATE(/atom/movable/plane_master_controller)
return returned_planes
///Full override so we can just use filterrific
/atom/movable/plane_master_controller/add_filter(name, priority, list/params)
/atom/movable/plane_master_controller/add_filter(name, priority, list/params, update = TRUE)
. = ..()
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
pm_iterator.add_filter(name, priority, params)
pm_iterator.add_filter(name, priority, params, update)
///Full override so we can just use filterrific
/atom/movable/plane_master_controller/remove_filter(name_or_names)
/atom/movable/plane_master_controller/remove_filter(name_or_names, update = TRUE)
. = ..()
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
pm_iterator.remove_filter(name_or_names)
pm_iterator.remove_filter(name_or_names, update)
/atom/movable/plane_master_controller/update_filters()
/atom/movable/plane_master_controller/update_filters(start_index = null)
. = ..()
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
pm_iterator.update_filters()
pm_iterator.update_filters(start_index)
///Gets all filters for this controllers plane masters
/atom/movable/plane_master_controller/proc/get_filters(name)
+2 -3
View File
@@ -347,7 +347,7 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
// Allows subsystems to declare other subsystems that must initialize after them.
for(var/datum/controller/subsystem/subsystem as anything in subsystems)
for(var/dependent_type as anything in subsystem.dependents)
for(var/dependent_type in subsystem.dependents)
if(!ispath(dependent_type, /datum/controller/subsystem))
stack_trace("ERROR: MC: subsystem `[subsystem.type]` has an invalid dependent: `[dependent_type]`. Skipping")
continue
@@ -357,7 +357,7 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
// Constructs a reverse-dependency graph.
for(var/datum/controller/subsystem/subsystem as anything in subsystems)
for(var/dependency_type as anything in subsystem.dependencies)
for(var/dependency_type in subsystem.dependencies)
if(!ispath(dependency_type, /datum/controller/subsystem))
stack_trace("ERROR: MC: subsystem `[subsystem.type]` has an invalid dependency: `[dependency_type]`. Skipping")
continue
@@ -1041,4 +1041,3 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
return FALSE
last_profiled = REALTIMEOFDAY
SSprofiler.DumpFile(allow_yield = FALSE)
+1 -1
View File
@@ -431,7 +431,7 @@ Versioning
/datum/controller/subsystem/blackbox/proc/ReportRoundstartManifest(list/characters)
var/list/query_rows = list()
var/list/special_columns = list("server_ip" = "INET_ATON(?)")
for(var/mob_ckey as anything in characters)
for(var/mob_ckey in characters)
var/mob/living/new_character = characters[mob_ckey]
query_rows += list(list(
"server_ip" = world.internet_address || 0,
@@ -14,6 +14,6 @@ MOVEMENT_SUBSYSTEM_DEF(ai_movement)
/datum/controller/subsystem/movement/ai_movement/proc/SetupAIMovementInstances()
movement_types = list()
for(var/key as anything in subtypesof(/datum/ai_movement))
for(var/key in subtypesof(/datum/ai_movement))
var/datum/ai_movement/ai_movement = new key
movement_types[key] = ai_movement
+4 -18
View File
@@ -21,26 +21,12 @@ SUBSYSTEM_DEF(ore_generation)
*/
var/list/ore_vent_minerals = list()
/// A tracker of how many of each ore vent size we have in the game. Useful for tracking purposes.
/datum/controller/subsystem/ore_generation/Initialize()
//Basically, we're going to round robin through the list of ore vents and assign a mineral to them until complete.
while(length(ore_vent_minerals) > 0) //Keep looping if there's more to assign
var/stallbreaker = 0
for(var/obj/structure/ore_vent/vent as anything in possible_vents)
if(length(ore_vent_minerals) <= 0) //But break early if there's none left.
break
if(vent.unique_vent)
continue //Ya'll already got your minerals.
if(length(difflist(first = ore_vent_minerals, second = vent.mineral_breakdown, skiprep = 1)))
vent.generate_mineral_breakdown(new_minerals = 1, map_loading = TRUE)
else
stallbreaker++
if(stallbreaker >= length(possible_vents))
break //We've done all we can here. break inner loop
continue
if(stallbreaker >= length(possible_vents))
break //We've done all we can here. break outer loop
for(var/obj/structure/ore_vent/vent as anything in possible_vents)
if(vent.unique_vent)
continue //Ya'll already got your minerals.
vent.generate_mineral_breakdown(map_loading = TRUE)
/// Handles roundstart logging
logger.Log(
@@ -117,7 +117,7 @@ PROCESSING_SUBSYSTEM_DEF(fishing)
continue
LAZYOR(fish_safe_turfs_by_type[fish_path], source.associated_safe_turfs)
//If a subtype doesn't have set safe turfs, it'll inherit them from the parent type.
for(var/fish_type as anything in fish_safe_turfs_by_type)
for(var/fish_type in fish_safe_turfs_by_type)
for(var/fish_subtype in subtypesof(fish_type))
if(!length(fish_safe_turfs_by_type[fish_subtype]))
fish_safe_turfs_by_type[fish_subtype] = fish_safe_turfs_by_type[fish_type]
@@ -34,7 +34,7 @@ PROCESSING_SUBSYSTEM_DEF(greyscale)
#endif
// This final verification step is for things that need other greyscale configurations to be finished loading
for(var/greyscale_type as anything in configurations)
for(var/greyscale_type in configurations)
CHECK_TICK
var/datum/greyscale_config/config = configurations[greyscale_type]
config.CrossVerify()
@@ -91,7 +91,7 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/
/datum/ai_behavior/find_potential_targets/proc/new_turf_found(turf/found, datum/ai_controller/controller, datum/targeting_strategy/strategy)
var/valid_found = FALSE
var/mob/pawn = controller.pawn
for(var/maybe_target as anything in found)
for(var/maybe_target in found)
if(maybe_target == pawn)
continue
if(!is_type_in_typecache(maybe_target, GLOB.target_interested_atoms))
@@ -120,7 +120,7 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/
/datum/ai_behavior/find_potential_targets/proc/new_atoms_found(list/atom/movable/found, datum/ai_controller/controller, target_key, datum/targeting_strategy/strategy, hiding_location_key)
var/mob/pawn = controller.pawn
var/list/accepted_targets = list()
for(var/maybe_target as anything in found)
for(var/maybe_target in found)
if(maybe_target == pawn)
continue
// Need to better handle viewers here
@@ -97,7 +97,7 @@
if (!length(required_traits))
return TRUE
for (var/trait as anything in required_traits)
for (var/trait in required_traits)
if (HAS_TRAIT(the_target, trait))
return TRUE
return FALSE
+1 -1
View File
@@ -95,7 +95,7 @@
var/mob/living/living_pawn = controller.pawn
var/list/nearby_items = list()
for (var/obj/new_friend as anything in oview(search_range, controller.pawn))
for (var/obj/new_friend in oview(search_range, controller.pawn))
if (!isitem(new_friend) && !isstructure(new_friend))
continue
if (is_type_in_list(new_friend, GLOB.animatable_blacklist))
+1 -1
View File
@@ -198,7 +198,7 @@
var/list/alarms_cache = alarms //Cache for sonic speec
for(var/alarm_type in alarms_cache)
var/list/alarms_of_type = alarms_cache[alarm_type] //Sonic cache speed forads
for(var/area_name as anything in alarms_of_type)
for(var/area_name in alarms_of_type)
var/list/alarm_packet = alarms_of_type[area_name]
var/list/cameras = alarm_packet[2]
if(cameras)
+1 -1
View File
@@ -183,7 +183,7 @@ GLOBAL_LIST_INIT(armor_by_type, generate_armor_type_cache())
/// Checks if any of the armor values are non-zero, so this technically also counts negative armor!
/datum/armor/proc/has_any_armor()
for(var/rating as anything in ARMOR_LIST_ALL())
for(var/rating in ARMOR_LIST_ALL())
if(vars[rating])
return TRUE
return FALSE
+3 -4
View File
@@ -216,7 +216,7 @@
owner.imaginary_group -= src
return ..()
/mob/eye/imaginary_friend/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, freq_name, freq_color, list/spans, list/message_mods = list(), message_range)
/mob/eye/imaginary_friend/Hear(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, freq_name, freq_color, list/spans, list/message_mods = list(), message_range)
if (safe_read_pref(client, /datum/preference/toggle/enable_runechat) && (safe_read_pref(client, /datum/preference/toggle/enable_runechat_non_mobs) || ismob(speaker)))
create_chat_message(speaker, message_language, raw_message, spans)
to_chat(src, compose_message(speaker, message_language, raw_message, radio_freq, freq_name, freq_color, spans, message_mods))
@@ -257,14 +257,13 @@
log_sayverb_talk(message, message_mods, tag = "imaginary friend", forced_by = forced)
var/messagepart = generate_messagepart(message, spans, message_mods)
var/rendered = "[span_name("[name]")] [messagepart]"
var/dead_rendered = "[span_name("[name] (Imaginary friend of [owner])")] [messagepart]"
var/language = message_language || owner.get_selected_language()
Hear(rendered, src, language, message, null, null, null, spans, message_mods) // We always hear what we say
Hear(src, language, message, null, null, null, spans, message_mods) // We always hear what we say
var/group = owner.imaginary_group - src // The people in our group don't, so we have to exclude ourselves not to hear twice
for(var/mob/person in group)
person.Hear(null, src, language, message, null, null, null, spans, message_mods, range)
person.Hear(src, language, message, null, null, null, spans, message_mods, range)
// Speech bubble, but only for those who have runechat off
var/list/speech_bubble_recipients = list()
+1 -1
View File
@@ -690,7 +690,7 @@
talk_tuah(pick(hurt_lines))
/datum/brain_trauma/special/axedoration/proc/talk_tuah(sent_message = "Hello World.")
owner.Hear(null, GLOB.bridge_axe, owner.get_selected_language(), sent_message)
owner.Hear(GLOB.bridge_axe, owner.get_selected_language(), sent_message)
/datum/brain_trauma/special/axedoration/proc/get_axe_location()
if(!GLOB.bridge_axe)
+1 -1
View File
@@ -540,7 +540,7 @@
var/list/highest_val_list = list(tracked_fish_by_type[1]) //In case there's only one type of fish in here...
var/highest_val = -1
for(var/fish_type as anything in can_survive_with)
for(var/fish_type in can_survive_with)
var/list/compatible_types = can_survive_with[fish_type]
var/fish_amount = fish_alive_by_type[fish_type]
for(var/obj/item/fish/fish_instance as anything in tracked_fish_by_type[fish_type])
+39 -50
View File
@@ -2,8 +2,9 @@
#define CONTENTS_INSTANCES "instances"
#define CONTENTS_MACHINERY "machinery"
#define CONTENTS_STRUCTURES "structures"
#define CONTENTS_REAGENTS "reagents"
#define CONTENTS_REQS_COUNT "reqs_count"
#define CONTENTS_TOOL_BEHAVIOUR "tool_behaviour"
#define CONTENTS_POSSIBLE_TOOLS "tool_instances"
/// The portion of time spent crafting that recipe dependant on the speed of the tools
#define RECIPE_DYNAMIC_TIME_COEFF 0.85
@@ -61,7 +62,7 @@
var/list/item_instances = contents[CONTENTS_INSTANCES]
var/list/machines = contents[CONTENTS_MACHINERY]
var/list/structures = contents[CONTENTS_STRUCTURES]
contents = contents[CONTENTS_REAGENTS]
contents = contents[CONTENTS_REQS_COUNT]
var/list/requirements_list = list()
@@ -132,81 +133,68 @@
continue
. += AM
/datum/component/personal_crafting/proc/get_surroundings(atom/a, list/blacklist=null)
/datum/component/personal_crafting/proc/get_surroundings(atom/source, list/blacklist=null)
. = list()
.[CONTENTS_TOOL_BEHAVIOUR] = list()
.[CONTENTS_REAGENTS] = list()
.[CONTENTS_REQS_COUNT] = list()
.[CONTENTS_INSTANCES] = list()
.[CONTENTS_MACHINERY] = list()
.[CONTENTS_STRUCTURES] = list()
for(var/obj/object in get_environment(a, blacklist))
for(var/obj/object in get_environment(source, blacklist))
if(isitem(object))
var/obj/item/item = object
LAZYADDASSOCLIST(.[CONTENTS_INSTANCES], item.type, item)
if(isstack(item))
var/obj/item/stack/stack = item
.[CONTENTS_REAGENTS][item.type] += stack.amount
.[CONTENTS_REQS_COUNT][item.type] += stack.amount
else
.[CONTENTS_REAGENTS][item.type] += 1
.[CONTENTS_REQS_COUNT][item.type] += 1
if(is_reagent_container(item) && item.is_drainable() && length(item.reagents.reagent_list)) //some container that has some reagents inside it that can be drained
var/obj/item/reagent_containers/container = item
for(var/datum/reagent/reagent as anything in container.reagents.reagent_list)
.[CONTENTS_REAGENTS][reagent.type] += reagent.volume
else //a reagent container that is empty can also be used as a tool. e.g. glass bottle can be used as a rolling pin
if(item.tool_behaviour)
var/current_tool_speed = .[CONTENTS_TOOL_BEHAVIOUR][item.tool_behaviour]
if(current_tool_speed < item.toolspeed)
.[CONTENTS_TOOL_BEHAVIOUR][item.tool_behaviour] = item.toolspeed
.[CONTENTS_REQS_COUNT][reagent.type] += reagent.volume
if(item.tool_behaviour)
var/current_tool_speed = .[CONTENTS_TOOL_BEHAVIOUR][item.tool_behaviour]
if(current_tool_speed < item.toolspeed)
.[CONTENTS_TOOL_BEHAVIOUR][item.tool_behaviour] = item.toolspeed
else if (ismachinery(object))
LAZYADDASSOCLIST(.[CONTENTS_MACHINERY], object.type, object)
else if (isstructure(object))
LAZYADDASSOCLIST(.[CONTENTS_STRUCTURES], object.type, object)
var/list/within_source = list()
for(var/obj/item/item in source.contents)
within_source += item
if(item.atom_storage)
within_source += item.contents
for(var/obj/item/item as anything in within_source)
if(!item.tool_behaviour)
continue
var/current_tool_speed = .[CONTENTS_TOOL_BEHAVIOUR][item.tool_behaviour]
if(current_tool_speed < item.toolspeed)
.[CONTENTS_TOOL_BEHAVIOUR][item.tool_behaviour] = item.toolspeed
var/list/instances = .[CONTENTS_INSTANCES]
for(var/item_type in instances)
.[CONTENTS_POSSIBLE_TOOLS] += instances[item_type]
.[CONTENTS_POSSIBLE_TOOLS] += within_source
/// Returns a boolean on whether the tool requirements of the input recipe are satisfied by the input source and surroundings.
/datum/component/personal_crafting/proc/check_tools(atom/source, datum/crafting_recipe/recipe, list/surroundings, final_check = FALSE)
if(!length(recipe.tool_behaviors) && !length(recipe.tool_paths))
return TRUE
var/list/available_tools = list()
var/list/present_qualities = list()
var/list/all_instances = list()
for(var/atom/movable/movable as anything in source.contents)
all_instances += movable
if(movable.atom_storage)
all_instances += movable.contents
for(var/obj/item/contained_item in all_instances) //fill the available tools list with available tool types and behaviours
available_tools[contained_item.type] = TRUE
if(contained_item.tool_behaviour)
present_qualities[contained_item.tool_behaviour] = TRUE
for(var/quality in surroundings[CONTENTS_TOOL_BEHAVIOUR])
present_qualities[quality] = TRUE
for(var/path in surroundings[CONTENTS_REAGENTS])
available_tools[path] = TRUE
for(var/required_quality in recipe.tool_behaviors)
if(!present_qualities[required_quality])
if(!(required_quality in surroundings[CONTENTS_TOOL_BEHAVIOUR]))
return FALSE
var/list/possible_tool_instances = surroundings[CONTENTS_POSSIBLE_TOOLS]
for(var/required_path in recipe.tool_paths)
var/found_this_tool = FALSE
for(var/tool_path in available_tools)
if(!ispath(tool_path, required_path))
continue
found_this_tool = TRUE
break
if(!found_this_tool)
if(!(locate(required_path) in possible_tool_instances))
return FALSE
//add the contents of the assoc list of the surrounding instances to all_instances for the recipe.check_tools() call
var/list/surrounding_instances = surroundings[CONTENTS_INSTANCES]
for(var/type_key in surrounding_instances)
all_instances |= surrounding_instances[type_key]
return recipe.check_tools(source, all_instances, final_check)
return recipe.check_tools(source, possible_tool_instances, final_check)
/datum/component/personal_crafting/proc/construct_item(atom/crafter, datum/crafting_recipe/recipe)
if(!crafter)
@@ -233,10 +221,10 @@
//Then divide it by the number of tools used in the recipe, and recalculate it.
dynamic_recipe_time /= tools_used
var/instances = contents[CONTENTS_INSTANCES]
var/list/possible_tool_instances = contents[CONTENTS_POSSIBLE_TOOLS]
for(var/tool in recipe.tool_paths)
var/best_speed = 10 //failsafe-ish
for(var/obj/item/item as anything in instances)
for(var/obj/item/item as anything in possible_tool_instances)
if(!istype(item, tool) || best_speed < item.toolspeed)
continue
best_speed = item.toolspeed
@@ -760,6 +748,7 @@
#undef CONTENTS_INSTANCES
#undef CONTENTS_MACHINERY
#undef CONTENTS_STRUCTURES
#undef CONTENTS_REAGENTS
#undef CONTENTS_REQS_COUNT
#undef CONTENTS_TOOL_BEHAVIOUR
#undef RECIPE_DYNAMIC_TIME_COEFF
#undef CONTENTS_POSSIBLE_TOOLS
+1 -1
View File
@@ -58,7 +58,7 @@
ingredient_names = processed_holder.ingredient_names
custom_name = processed_holder.custom_name
atom_parent.name = "[custom_adjective()] [custom_name] [atom_parent.name]"
for(var/fillcol as anything in processed_holder.filling_colors)
for(var/fillcol in processed_holder.filling_colors)
apply_fill(fillcol)
/datum/component/ingredients_holder/Destroy(force)
@@ -460,10 +460,10 @@
//we now summarize the chat msgs collected
if(!(mat_container_flags & MATCONTAINER_SILENT))
for(var/status as anything in chat_msgs)
for(var/status in chat_msgs)
var/list/status_data = chat_msgs[status]
for(var/item_name as anything in status_data)
for(var/item_name in status_data)
//read the params
var/list/chat_data = status_data[item_name]
var/count = chat_data["count"]
@@ -52,7 +52,7 @@
SIGNAL_HANDLER
RegisterSignal(new_friend, COMSIG_KB_LIVING_VIEW_PET_COMMANDS, PROC_REF(on_key_pressed))
RegisterSignal(new_friend, DEACTIVATE_KEYBIND(COMSIG_KB_LIVING_VIEW_PET_COMMANDS), PROC_REF(on_key_unpressed))
for (var/command_name as anything in available_commands)
for (var/command_name in available_commands)
var/datum/pet_command/command = available_commands[command_name]
INVOKE_ASYNC(command, TYPE_PROC_REF(/datum/pet_command, add_new_friend), new_friend)
@@ -71,7 +71,7 @@
COMSIG_KB_LIVING_VIEW_PET_COMMANDS,
DEACTIVATE_KEYBIND(COMSIG_KB_LIVING_VIEW_PET_COMMANDS),
))
for (var/command_name as anything in available_commands)
for (var/command_name in available_commands)
var/datum/pet_command/command = available_commands[command_name]
INVOKE_ASYNC(command, TYPE_PROC_REF(/datum/pet_command, remove_friend), old_friend)
@@ -116,7 +116,7 @@
/// Actually display the radial menu and then do something with the result
/datum/component/obeys_commands/proc/display_radial_menu(mob/living/friend)
var/list/radial_options = list()
for (var/command_name as anything in available_commands)
for (var/command_name in available_commands)
var/datum/pet_command/command = available_commands[command_name]
var/datum/radial_menu_choice/choice = command.provide_radial_data()
if (!choice)
@@ -107,7 +107,7 @@
* if check_verbosity is true, skip the match if there spoken_text is way longer than the match
*/
/datum/pet_command/proc/find_command_in_text(spoken_text, check_verbosity = FALSE)
for (var/command as anything in speech_commands)
for (var/command in speech_commands)
if (!findtext(spoken_text, command))
continue
if(check_verbosity && length(spoken_text) > length(command) + MAX_NAME_LEN)
@@ -220,5 +220,3 @@
return FALSE
parent.visible_message(span_warning("[parent] follows [friend]'s gesture towards [potential_target] [pointed_reaction]!"))
return TRUE
@@ -19,7 +19,7 @@
src.regeneration_time = regeneration_time
var/atom/movable/living_parent = parent
for(var/type_path as anything in shield_overlays)
for(var/type_path in shield_overlays)
if(!ispath(type_path))
continue
var/obj/effect/overlay/new_effect = new type_path()
+2 -1
View File
@@ -185,7 +185,8 @@
if(seat.buckle_lying && rider.body_position == LYING_DOWN)
y_offset += (-1 * PIXEL_Y_OFFSET_LYING)
rider.add_offsets(RIDING_SOURCE, x_add = x_offset, y_add = y_offset, animate = animate)
// Rider uses pixel_z offsets as they're above the turf, not up north on the turf
rider.add_offsets(RIDING_SOURCE, x_add = x_offset, z_add = y_offset, animate = animate)
rider.layer = layer
#undef GET_X_OFFSET
+1 -1
View File
@@ -210,7 +210,7 @@
))
var/list/remaining_stock = list()
for(var/item as anything in stock_list)
for(var/item in stock_list)
remaining_stock[item] = stock_list[item]
data["extra_purchasable"] = extra_purchasable
data["extra_purchasable_stock"] = extra_purchasable_stock
+113 -69
View File
@@ -55,9 +55,12 @@
*/
var/list/cooldowns
/// List for handling persistent filters.
var/list/filter_data
/// An accursed beast of a list that contains our filters. Why? Because var/list/filters on atoms/images isn't actually a list
/// but a snowflaked skinwalker pretending to be one, which doesn't support half the list procs/operations and the other half behaves weirdly
/// so we cut down on filter creation and appearance update costs by editing *this* list, and then assigning ours to it
var/list/filter_cache
#ifdef REFERENCE_TRACKING
/// When was this datum last touched by a reftracker?
@@ -321,38 +324,67 @@
* * name - Filter name
* * priority - Priority used when sorting the filter.
* * params - Parameters of the filter.
* * update - If we should update our actual filters list, or wait until something updates it later
*/
/datum/proc/add_filter(name, priority, list/params)
LAZYINITLIST(filter_data)
var/list/copied_parameters = params.Copy()
copied_parameters["priority"] = priority
filter_data[name] = copied_parameters
update_filters()
///A version of add_filter that takes a list of filters to add rather than being individual, to limit calls to update_filters().
/datum/proc/add_filters(list/list/filters)
LAZYINITLIST(filter_data)
for(var/list/individual_filter as anything in filters)
var/list/params = individual_filter["params"]
var/list/copied_parameters = params.Copy()
copied_parameters["priority"] = individual_filter["priority"]
filter_data[individual_filter["name"]] = copied_parameters
update_filters()
/// Reapplies all the filters.
/datum/proc/update_filters()
/datum/proc/add_filter(name, priority, list/params, update = TRUE)
ASSERT(isatom(src) || isimage(src))
var/atom/atom_cast = src // filters only work with images or atoms.
atom_cast.filters = null
sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE)
for(var/filter_raw in filter_data)
var/list/data = filter_data[filter_raw]
var/list/arguments = data.Copy()
LAZYINITLIST(filter_data)
LAZYINITLIST(filter_cache)
var/list/copied_parameters = params.Copy()
copied_parameters["name"] = name
copied_parameters["priority"] = priority
for (var/list/filter_info as anything in filter_data)
if (filter_info["name"] == name)
filter_data -= filter_info
filter_cache -= name
break
BINARY_INSERT_DEFINE(list(copied_parameters), filter_data, SORT_VAR_NO_TYPE, copied_parameters, SORT_PRIORITY_INDEX, COMPARE_KEY)
for (var/index in 1 to length(filter_data))
var/list/filter_info = filter_data[index]
if (filter_info["name"] != name)
continue
var/list/arguments = filter_info.Copy()
arguments -= "priority"
atom_cast.filters += filter(arglist(arguments))
filter_cache.Insert(index, filter(arglist(arguments)))
break
if (update)
atom_cast.filters = filter_cache
/// A version of add_filter that takes a list of filters to add rather than being individual, to limit appearance updates
/datum/proc/add_filters(list/list/filters, update = TRUE)
ASSERT(isatom(src) || isimage(src))
var/atom/atom_cast = src // filters only work with images or atoms.
for (var/list/individual_filter as anything in filters)
add_filter(individual_filter["name"], individual_filter["priority"], individual_filter["params"], update = FALSE)
if (update)
atom_cast.filters = filter_cache
/// Reapplies all the filters. If start_index is passed, only a portion of all filters are reapplied starting from said index
/datum/proc/update_filters(start_index = null)
ASSERT(isatom(src) || isimage(src))
var/atom/atom_cast = src // filters only work with images or atoms.
if (start_index)
filter_cache.Cut(start_index)
else
atom_cast.filters = null
filter_cache.Cut()
for (var/index in start_index || 1 to length(filter_data))
var/list/filter_info = filter_data[index]
var/list/arguments = filter_info.Copy()
arguments -= "priority"
if (start_index) // See https://www.byond.com/forum/post/2980598 as to why we cannot just override the existing filter
atom_cast.filters -= filter_info["name"] // We're trapped in the belly of this horrible machine
filter_cache += filter(arglist(arguments)) // And the machine is bleeding to death
atom_cast.filters = filter_cache
UNSETEMPTY(filter_data)
/obj/item/update_filters()
/obj/item/update_filters(start_index = null)
. = ..()
update_item_action_buttons()
@@ -362,17 +394,29 @@
* * name - Filter name
* * new_params - New parameters of the filter
* * overwrite - TRUE means we replace the parameter list completely. FALSE means we only replace the things on new_params.
* * update - If we should apply our filter cache to our actual filters
*/
/datum/proc/modify_filter(name, list/new_params, overwrite = FALSE)
var/filter = get_filter(name)
if(!filter)
/datum/proc/modify_filter(name, list/new_params, overwrite = FALSE, update = TRUE)
ASSERT(isatom(src) || isimage(src))
var/atom/atom_cast = src // filters only work with images or atoms.
for (var/index in 1 to length(filter_data))
var/list/filter_info = filter_data[index]
if (filter_info["name"] != name)
continue
if (overwrite)
filter_data[index] = new_params
else
for (var/thing in new_params)
filter_info[thing] = new_params[thing]
var/list/arguments = filter_info.Copy()
arguments -= "priority"
filter_cache[index] = filter(arglist(arguments))
if (update)
atom_cast.filters = filter_cache
return
if(overwrite)
filter_data[name] = new_params
else
for(var/thing in new_params)
filter_data[name][thing] = new_params[thing]
update_filters()
/** Update a filter's parameter and animate this change. If the filter doesn't exist we won't do anything.
* Basically a [datum/proc/modify_filter] call but with animations. Unmodified filter parameters are kept.
@@ -386,7 +430,7 @@
*/
/datum/proc/transition_filter(name, list/new_params, time, easing, loop)
var/filter = get_filter(name)
if(!filter)
if (!filter)
return
// This can get injected by the filter procs, we want to support them so bye byeeeee
new_params -= "type"
@@ -399,75 +443,75 @@
* * duration - the time it takes to animate this step
* * easing - the type of easing this step has
*/
/proc/FilterChainStep(params, duration, easing)
/proc/filter_chain_step(params, duration, easing, flags)
params -= "type"
return list("params"= params, "duration"=duration, "easing"=easing)
return list("params" = params, "duration" = duration, "easing" = easing, "flags" = flags)
/** Similar to transition_filter(), except it creates an animation chain that moves between a list of states.
* Arguments:
* * name - Filter name
* * num_loops - Amount of times the chain loops. INDEFINITE = Infinite
* * ... - a list of each link in the animation chain. Use FilterChainStep(params, duration, easing) for each link
* * ... - a list of each link in the animation chain. Use filter_chain_step(params, duration, easing) for each link
* Example use:
* * add_filter("blue_pulse", 1, color_matrix_filter(COLOR_WHITE))
* * transition_filter_chain(src, "blue_pulse", INDEFINITE,\
* * FilterChainStep(color_matrix_filter(COLOR_BLUE), 10 SECONDS, CUBIC_EASING),\
* * FilterChainStep(color_matrix_filter(COLOR_WHITE), 10 SECONDS, CUBIC_EASING))
* * filter_chain_step(color_matrix_filter(COLOR_BLUE), 10 SECONDS, CUBIC_EASING),\
* * filter_chain_step(color_matrix_filter(COLOR_WHITE), 10 SECONDS, CUBIC_EASING))
* The above code would edit a color_matrix_filter() to slowly turn blue over 10 seconds before returning back to white 10 seconds after, repeating this chain forever.
*/
/datum/proc/transition_filter_chain(name, num_loops, ...)
var/list/transition_steps = args.Copy(3)
var/filter = get_filter(name)
if(!filter)
if (!filter)
return
var/list/first_step = transition_steps[1]
animate(filter, first_step["params"], time = first_step["duration"], easing = first_step["easing"], loop = num_loops)
for(var/transition_step in 2 to length(transition_steps))
animate(filter, first_step["params"], time = first_step["duration"], easing = first_step["easing"], flags = first_step["flags"], loop = num_loops)
for (var/transition_step in 2 to length(transition_steps))
var/list/this_step = transition_steps[transition_step]
animate(this_step["params"], time = this_step["duration"], easing = this_step["easing"])
animate(this_step["params"], time = this_step["duration"], easing = this_step["easing"], flags = this_step["flags"])
/// Updates the priority of the passed filter key
/datum/proc/change_filter_priority(name, new_priority)
if(!filter_data || !filter_data[name])
return
for (var/list/filter_info as anything in filter_data)
if (filter_info["name"] != name)
continue
filter_data[name]["priority"] = new_priority
update_filters()
remove_filter(name, update = FALSE)
add_filter(name, new_priority, filter_info)
return
/// Returns the filter associated with the passed key
/datum/proc/get_filter(name)
ASSERT(isatom(src) || isimage(src))
if(filter_data && filter_data[name])
var/atom/atom_cast = src // filters only work with images or atoms.
return atom_cast.filters[filter_data.Find(name)]
/// Returns the indice in filters of the given filter name.
/// If it is not found, returns null.
/datum/proc/get_filter_index(name)
return filter_data?.Find(name)
var/atom/atom_cast = src // filters only work with images or atoms.
return atom_cast.filters[name]
/// Removes the passed filter, or multiple filters, if supplied with a list.
/datum/proc/remove_filter(name_or_names)
/datum/proc/remove_filter(name_or_names, update = TRUE)
ASSERT(isatom(src) || isimage(src))
if(!filter_data)
return
var/atom/atom_cast = src // filters only work with images or atoms.
var/list/names = islist(name_or_names) ? name_or_names : list(name_or_names)
. = FALSE
for(var/name in names)
if(filter_data[name])
filter_data -= name
. = TRUE
if(.)
update_filters()
var/list/new_data = list()
var/list/new_cache = list()
for (var/index in 1 to length(filter_data))
var/list/filter_info = filter_data[index]
if (!(filter_info["name"] in names))
new_data += list(filter_info)
new_cache += filter_cache[index]
filter_data = new_data
filter_cache = new_cache
if (update)
atom_cast.filters = filter_cache
return .
/datum/proc/clear_filters()
ASSERT(isatom(src) || isimage(src))
var/atom/atom_cast = src // filters only work with images or atoms.
filter_data = null
filter_cache = null
atom_cast.filters = null
/// Calls qdel on itself, because signals dont allow callbacks
+1 -1
View File
@@ -70,7 +70,7 @@
/datum/element/art/commoner/apply_moodlet(atom/source, mob/living/user, impress)
var/msg
var/list/haters = list()
for(var/hater_department_type as anything in list(/datum/job_department/security, /datum/job_department/command))
for(var/hater_department_type in list(/datum/job_department/security, /datum/job_department/command))
var/datum/job_department/hater_department = SSjob.get_department_type(hater_department_type)
for(var/datum/job/hater_job as anything in hater_department.department_jobs)
haters += hater_job.title
+158 -263
View File
@@ -5,61 +5,31 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list(
/obj/projectile,
)))
/**
* A visual element that makes movables entering the attached turfs look immersed into that turf.
*
* Abandon all hope, ye who read forth, for this immerse works on mind-numbing workarounds,
*/
/// A visual element that makes movables entering the attached turfs look immersed into that turf.
/// May the gods forgive me for the bullshit you're about to witness
/datum/element/immerse
element_flags = ELEMENT_DETACH_ON_HOST_DESTROY | ELEMENT_BESPOKE
argument_hash_start_idx = 2
///An association list of turfs that have this element attached and their affected contents.
var/list/attached_turfs_and_movables = list()
///A list of icons generated from a target and a mask, later used as appearances for the overlays.
var/static/list/generated_immerse_icons = list()
///A list of instances of /atom/movable/immerse_overlay then used as visual overlays for the immersed movables.
/// An association list of turfs that have this element attached and their affected contents.
var/list/attached_turf_contents = list()
/// A list of generated immersion masks based on object width, height and whever they're fully immersed underwater
var/list/immersion_masks = list()
/// An assoc list of instances of /atom/movable/immerse_mask used as abstract effect relays, because god is dead
var/list/generated_visual_overlays = list()
///An association list of movables as key and overlays as assoc.
var/list/immersed_movables
/// icon_state used as a mask by our turf
var/mask_icon = "immerse"
/// Alpha of the mask, to make the liquid partially transparent
var/alpha = 180
var/icon
var/icon_state
var/mask_icon
var/color
var/alpha
/datum/element/immerse/Attach(turf/target, icon, icon_state, mask_icon, color = "#777777", alpha = 180)
/datum/element/immerse/Attach(turf/target, mask_icon = "immerse", alpha = 180)
. = ..()
if(!isturf(target) || !icon || !icon_state || !mask_icon)
if(!isturf(target) || !mask_icon)
return ELEMENT_INCOMPATIBLE
src.icon = icon
src.icon_state = icon_state
src.color = color
src.alpha = alpha
src.mask_icon = mask_icon
/**
* Hello, you may be wondering why we're blending icons and not simply
* overlaying one mutable appearance with the blend multiply on another.
* Well, the latter option doesn't work as neatly when added
* to an atom with the KEEP_TOGETHER appearance flag, with the mask icon also
* showing on said atom, while we don't want it to.
*
* Also using KEEP_APART isn't an option, because unless it's drawn as one with
* its visual loation, the whole plane the atom belongs to will count as part of the
* mask of the final visual overlay since that's how the BLEND_INSET_OVERLAY blend mode works here.
* In layman terms, with KEEP_APART on, if a flying monkey gets nears an immersed
* human, the visual overlay will appear on the flying monkey even if it shouldn't.
*/
var/icon/immerse_icon = generated_immerse_icons["[icon]-[icon_state]-[mask_icon]"]
if(!immerse_icon)
immerse_icon = icon(icon, icon_state)
var/icon/sub_mask = icon('icons/effects/effects.dmi', mask_icon)
immerse_icon.Blend(sub_mask, ICON_MULTIPLY)
immerse_icon = fcopy_rsc(immerse_icon)
generated_immerse_icons["[icon]-[icon_state]-[mask_icon]"] = immerse_icon
src.alpha = alpha
RegisterSignal(target, SIGNAL_ADDTRAIT(TRAIT_IMMERSE_STOPPED), PROC_REF(stop_immersion))
RegisterSignal(target, SIGNAL_REMOVETRAIT(TRAIT_IMMERSE_STOPPED), PROC_REF(start_immersion))
@@ -73,29 +43,30 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list(
stop_immersion(source)
return ..()
///Makes the element start affecting the turf and its contents. Called on Attach() or when TRAIT_IMMERSE_STOPPED is removed.
/// Makes the element start affecting the turf and its contents. Called on Attach() or when TRAIT_IMMERSE_STOPPED is removed.
/datum/element/immerse/proc/start_immersion(turf/source)
SIGNAL_HANDLER
RegisterSignals(source, list(COMSIG_ATOM_ABSTRACT_ENTERED, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON), PROC_REF(on_init_or_entered))
RegisterSignal(source, COMSIG_ATOM_ABSTRACT_EXITED, PROC_REF(on_atom_exited))
attached_turfs_and_movables += source
attached_turf_contents += source
for(var/atom/movable/movable as anything in source)
if(!(movable.flags_1 & INITIALIZED_1) || movable.invisibility >= INVISIBILITY_OBSERVER)
continue
on_init_or_entered(source, movable)
///Stops the element from affecting on the turf and its contents. Called on Detach() or when TRAIT_IMMERSE_STOPPED is added.
/// Stops the element from affecting on the turf and its contents. Called on Detach() or when TRAIT_IMMERSE_STOPPED is added.
/datum/element/immerse/proc/stop_immersion(turf/source)
SIGNAL_HANDLER
UnregisterSignal(source, list(COMSIG_ATOM_ABSTRACT_ENTERED, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, COMSIG_ATOM_ABSTRACT_EXITED))
for(var/atom/movable/movable as anything in attached_turfs_and_movables[source])
for(var/atom/movable/movable as anything in attached_turf_contents[source])
remove_from_element(source, movable)
attached_turfs_and_movables -= source
attached_turf_contents -= source
/**
* If the movable is within the right layers and planes, not in the list of movable types to ignore,
* or already affected by the element for that matter, Signals will be registered and,
* unless the movable (or whatever it's buckled to) is flying, it'll appear as if immersed in that water.
* or already affected by the element for that matter, signals will be registered and,
* unless the movable is flying, it'll appear as if immersed in that water.
*/
/datum/element/immerse/proc/on_init_or_entered(turf/source, atom/movable/movable)
SIGNAL_HANDLER
@@ -103,123 +74,34 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list(
return
if(HAS_TRAIT(movable, TRAIT_IMMERSED) || HAS_TRAIT(movable, TRAIT_WALLMOUNTED))
return
if(!ISINRANGE(movable.plane, MUTATE_PLANE(FLOOR_PLANE, source), MUTATE_PLANE(GAME_PLANE, source)))
if(!ISINRANGE(PLANE_TO_TRUE(movable.plane), FLOOR_PLANE, GAME_PLANE))
return
// First, floor plane objects use TOPDOWN_LAYER, second this check shouldn't apply to them anyway.
var/layer_to_check = IS_TOPDOWN_PLANE(source.plane) ? TOPDOWN_ABOVE_WATER_LAYER : ABOVE_ALL_MOB_LAYER
//First, floor plane objects use TOPDOWN_LAYER, second this check shouldn't apply to them anyway.
if(movable.layer >= layer_to_check)
return
if(is_type_in_typecache(movable, GLOB.immerse_ignored_movable))
return
var/atom/movable/buckled
var/atom/movable/buckled = null
if(isliving(movable))
var/mob/living/living_mob = movable
RegisterSignal(living_mob, COMSIG_LIVING_SET_BUCKLED, PROC_REF(on_set_buckled))
buckled = living_mob.buckled
RegisterSignal(living_mob, COMSIG_LIVING_SET_BUCKLED, PROC_REF(on_set_buckled))
RegisterSignal(living_mob, COMSIG_LIVING_UPDATE_OFFSETS, PROC_REF(on_update_offsets))
RegisterSignal(movable, COMSIG_LIVING_POST_UPDATE_TRANSFORM, PROC_REF(on_update_transform))
try_immerse(movable, buckled)
RegisterSignal(movable, COMSIG_ATOM_SPIN_ANIMATION, PROC_REF(on_spin_animation))
RegisterSignal(movable, COMSIG_QDELETING, PROC_REF(on_movable_qdel))
LAZYADD(attached_turfs_and_movables[source], movable)
try_immerse(movable, buckled)
LAZYADD(attached_turf_contents[source], movable)
ADD_TRAIT(movable, TRAIT_IMMERSED, ELEMENT_TRAIT(src))
/datum/element/immerse/proc/on_movable_qdel(atom/movable/source)
SIGNAL_HANDLER
remove_from_element(source.loc, source)
/**
* The main proc, which adds a visual overlay to the movable that has entered the turf to make it look immersed.
* It's kind of iffy but basically, we want the overlay to cover as much area as needed to
* avoid the movable's icon from spilling horizontally or below.
* Also, while these visual overlays are mainly cached movables, for certain movables, such as living mobs,
* we want them to have their own unique vis overlay with additional signals registered.
* This allows the vis overlay to look more or less unchanged while its owner is spinning or resting
* without otherwise affecting other movables with identical overlays.
*/
/datum/element/immerse/proc/add_immerse_overlay(atom/movable/movable)
var/list/icon_dimensions = get_icon_dimensions(movable.icon)
var/width = icon_dimensions["width"] || ICON_SIZE_X
var/height = icon_dimensions["height"] || ICON_SIZE_Y
///This determines if the overlay should cover the entire surface of the object or not
var/layer_to_check = IS_TOPDOWN_PLANE(movable.plane) ? TOPDOWN_WATER_LEVEL_LAYER : WATER_LEVEL_LAYER
var/is_below_water = (movable.layer < layer_to_check) ? "underwater-" : ""
var/atom/movable/immerse_overlay/vis_overlay = generated_visual_overlays["[is_below_water][width]x[height]"]
if(!vis_overlay) //create the overlay if not already done.
vis_overlay = generate_vis_overlay(width, height, is_below_water)
ADD_KEEP_TOGETHER(movable, ELEMENT_TRAIT(src))
/**
* Let's give an unique immerse visual only to those movables that would
* benefit from this the most, for the sake of a smidge of lightweightness.
*/
if(HAS_TRAIT(movable, TRAIT_UNIQUE_IMMERSE))
var/atom/movable/immerse_overlay/original_vis_overlay = vis_overlay
vis_overlay = new(null)
vis_overlay.appearance = original_vis_overlay
vis_overlay.extra_width = original_vis_overlay.extra_width
vis_overlay.extra_height = original_vis_overlay.extra_height
vis_overlay.overlay_appearance = original_vis_overlay.overlay_appearance
SEND_SIGNAL(movable, COMSIG_MOVABLE_EDIT_UNIQUE_IMMERSE_OVERLAY, vis_overlay)
RegisterSignal(movable, COMSIG_ATOM_SPIN_ANIMATION, PROC_REF(on_spin_animation))
RegisterSignal(movable, COMSIG_LIVING_POST_UPDATE_TRANSFORM, PROC_REF(on_update_transform))
movable.vis_contents |= vis_overlay
LAZYSET(immersed_movables, movable, vis_overlay)
///Initializes and caches a new visual overlay given parameters such as width, height and whether it should appear fully underwater.
/datum/element/immerse/proc/generate_vis_overlay(width, height, is_below_water)
var/atom/movable/immerse_overlay/vis_overlay = new(null, src)
/**
* vis contents spin around the center of the icon of their vis locs
* but since we want the appearance to stay where it should be,
* we have to counteract this one.
*/
var/extra_width = (width - ICON_SIZE_X) * 0.5
var/extra_height = (height - ICON_SIZE_Y) * 0.5
var/mutable_appearance/overlay_appearance = new()
var/icon/immerse_icon = generated_immerse_icons["[icon]-[icon_state]-[mask_icon]"]
var/last_i = width/ICON_SIZE_X
for(var/i in -1 to last_i)
var/mutable_appearance/underwater = mutable_appearance(icon, icon_state)
underwater.pixel_w = ICON_SIZE_X * i - extra_width
underwater.pixel_z = -ICON_SIZE_Y - extra_height
overlay_appearance.overlays += underwater
var/mutable_appearance/water_level = is_below_water ? underwater : mutable_appearance(immerse_icon)
water_level.pixel_w = ICON_SIZE_X * i - extra_width
water_level.pixel_z = -extra_height
overlay_appearance.overlays += water_level
vis_overlay.color = color
vis_overlay.alpha = alpha
vis_overlay.overlays = list(overlay_appearance)
vis_overlay.extra_width = extra_width
vis_overlay.extra_height = extra_height
vis_overlay.overlay_appearance = overlay_appearance
generated_visual_overlays["[is_below_water][width]x[height]"] = vis_overlay
return vis_overlay
///This proc removes the vis_overlay, the keep together trait and some signals from the movable.
/datum/element/immerse/proc/remove_immerse_overlay(atom/movable/movable)
var/atom/movable/immerse_overlay/vis_overlay = LAZYACCESS(immersed_movables, movable)
LAZYREMOVE(immersed_movables, movable)
REMOVE_KEEP_TOGETHER(movable, ELEMENT_TRAIT(src))
movable.vis_contents -= vis_overlay
if(HAS_TRAIT(movable, TRAIT_UNIQUE_IMMERSE))
UnregisterSignal(movable, list(COMSIG_ATOM_SPIN_ANIMATION, COMSIG_LIVING_POST_UPDATE_TRANSFORM, COMSIG_QDELETING))
if(!QDELETED(vis_overlay))
qdel(vis_overlay)
/**
* Called by init_or_entered() and on_set_buckled().
* This applies the overlay if neither the movable or whatever is buckled to (exclusive to living mobs) are flying
@@ -229,29 +111,34 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list(
var/atom/movable/to_check = buckled || movable
if(!(to_check.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) && !movable.throwing)
add_immerse_overlay(movable)
if(!buckled)
RegisterSignal(movable, COMSIG_MOVETYPE_FLAG_ENABLED, PROC_REF(on_move_flag_enabled))
RegisterSignal(movable, COMSIG_MOVETYPE_FLAG_DISABLED, PROC_REF(on_move_flag_disabled))
RegisterSignal(movable, COMSIG_MOVABLE_POST_THROW, PROC_REF(on_throw))
RegisterSignal(movable, COMSIG_MOVABLE_THROW_LANDED, PROC_REF(on_throw_landed))
if(buckled)
return
RegisterSignal(movable, COMSIG_MOVETYPE_FLAG_ENABLED, PROC_REF(on_move_flag_enabled))
RegisterSignal(movable, COMSIG_MOVETYPE_FLAG_DISABLED, PROC_REF(on_move_flag_disabled))
RegisterSignal(movable, COMSIG_MOVABLE_POST_THROW, PROC_REF(on_throw))
RegisterSignal(movable, COMSIG_MOVABLE_THROW_LANDED, PROC_REF(on_throw_landed))
/**
* Called by on_set_buckled() and remove_from_element().
* This removes the filter and signals from the movable unless it doesn't have them.
*/
/// Called by on_set_buckled() and remove_from_element().
/// This removes the filter and signals from the movable unless it doesn't have them.
/datum/element/immerse/proc/try_unimmerse(atom/movable/movable, atom/movable/buckled)
var/atom/movable/to_check = buckled || movable
if(!(to_check.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) && !movable.throwing)
remove_immerse_overlay(movable)
if(!buckled)
UnregisterSignal(movable, list(COMSIG_MOVETYPE_FLAG_ENABLED, COMSIG_MOVETYPE_FLAG_DISABLED, COMSIG_MOVABLE_POST_THROW, COMSIG_MOVABLE_THROW_LANDED))
if(buckled)
return
UnregisterSignal(movable, list(
COMSIG_MOVETYPE_FLAG_ENABLED,
COMSIG_MOVETYPE_FLAG_DISABLED,
COMSIG_MOVABLE_POST_THROW,
COMSIG_MOVABLE_THROW_LANDED
))
/datum/element/immerse/proc/on_set_buckled(mob/living/source, atom/movable/new_buckled)
SIGNAL_HANDLER
try_unimmerse(source, source.buckled)
try_immerse(source, new_buckled)
///Removes the overlay from mob and bucklees is flying.
/// Removes the overlay from mob and bucklees is flying.
/datum/element/immerse/proc/on_move_flag_enabled(atom/movable/source, flag, old_movement_type)
SIGNAL_HANDLER
if(!(flag & MOVETYPES_NOT_TOUCHING_GROUND) || (old_movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || source.throwing)
@@ -260,7 +147,7 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list(
for(var/mob/living/buckled_mob as anything in source.buckled_mobs)
remove_immerse_overlay(buckled_mob)
///Works just like on_move_flag_enabled, except it only has to check that movable isn't flying
/// Works just like on_move_flag_enabled, except it only has to check that movable isn't flying
/datum/element/immerse/proc/on_throw(atom/movable/source)
SIGNAL_HANDLER
if(source.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)
@@ -269,7 +156,7 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list(
for(var/mob/living/buckled_mob as anything in source.buckled_mobs)
remove_immerse_overlay(buckled_mob)
///Readds the overlay to the mob and bucklees if no longer flying.
/// Readds the overlay to the mob and bucklees if no longer flying.
/datum/element/immerse/proc/on_move_flag_disabled(atom/movable/source, flag, old_movement_type)
SIGNAL_HANDLER
if(!(flag & MOVETYPES_NOT_TOUCHING_GROUND) || (source.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || source.throwing)
@@ -278,7 +165,7 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list(
for(var/mob/living/buckled_mob as anything in source.buckled_mobs)
add_immerse_overlay(buckled_mob)
///Works just like on_move_flag_disabled, except it only has to check that movable isn't flying
/// Works just like on_move_flag_disabled, except it only has to check that movable isn't flying
/datum/element/immerse/proc/on_throw_landed(atom/movable/source)
SIGNAL_HANDLER
if(source.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)
@@ -287,123 +174,131 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list(
for(var/mob/living/buckled_mob as anything in source.buckled_mobs)
add_immerse_overlay(buckled_mob)
/**
* Called when a movable exits the turf. If its new location is not in the list of turfs with this element,
* Remove the movable from the element.
*/
/// Called when a movable exits the turf. If its new location is not in the list of turfs with this element,
/// remove the movable from the element.
/datum/element/immerse/proc/on_atom_exited(turf/source, atom/movable/exited, direction)
SIGNAL_HANDLER
if(!(exited.loc in attached_turfs_and_movables))
if(!attached_turf_contents[exited.loc])
remove_from_element(source, exited)
else
LAZYREMOVE(attached_turfs_and_movables[source], exited)
LAZYADD(attached_turfs_and_movables[exited.loc], exited)
return
LAZYREMOVE(attached_turf_contents[source], exited)
LAZYADD(attached_turf_contents[exited.loc], exited)
///Remove any signal, overlay, trait given to the movable and reference to it within the element.
//// Remove any signal, overlay, trait given to the movable and reference to it within the element.
/datum/element/immerse/proc/remove_from_element(turf/source, atom/movable/movable)
var/atom/movable/buckled
var/atom/movable/buckled = null
if(isliving(movable))
var/mob/living/living_mob = movable
buckled = living_mob.buckled
try_unimmerse(movable, buckled)
LAZYREMOVE(attached_turfs_and_movables[source], movable)
UnregisterSignal(movable, list(COMSIG_LIVING_SET_BUCKLED, COMSIG_QDELETING))
try_unimmerse(movable, buckled)
LAZYREMOVE(attached_turf_contents[source], movable)
UnregisterSignal(movable, list(COMSIG_LIVING_SET_BUCKLED, COMSIG_QDELETING, COMSIG_LIVING_UPDATE_OFFSETS, COMSIG_ATOM_SPIN_ANIMATION, COMSIG_LIVING_POST_UPDATE_TRANSFORM))
REMOVE_TRAIT(movable, TRAIT_IMMERSED, ELEMENT_TRAIT(src))
/// Generate a mask filter mutable to use as render_source for the alpha filter based on provided width, height and immersion state
/datum/element/immerse/proc/generate_immerse_mask(width, height, is_below_water)
var/clean_height = height
width = ceil(width / ICON_SIZE_X) * ICON_SIZE_X
height = ceil(height / ICON_SIZE_Y) * ICON_SIZE_Y
var/mask_key = "[width]-[height]-[is_below_water]"
var/mutable_appearance/target_mask = immersion_masks[mask_key]
if (target_mask)
return target_mask
if (width == ICON_SIZE_X && height == ICON_SIZE_Y)
target_mask = mutable_appearance('icons/effects/effects.dmi', mask_icon, alpha = alpha)
immersion_masks[mask_key] = target_mask
return target_mask
var/icon/column_icon = icon('icons/effects/effects.dmi', mask_icon)
var/y_tiles = 1
if (height != ICON_SIZE_Y)
column_icon.Crop(1, 1, ICON_SIZE_X, ICON_SIZE_Y) // Use base icon and crop it out so animation frames respect dmi's delays
y_tiles = ceil((height / ICON_SIZE_Y - 1) / 2) + 1
column_icon.Scale(ICON_SIZE_X, y_tiles * ICON_SIZE_Y)
var/icon/effect_icon = icon('icons/effects/effects.dmi', mask_icon)
var/icon/fill_icon = icon('icons/effects/alphacolors.dmi', "white")
for (var/y_tile in 1 to y_tiles - 1)
column_icon.Blend(fill_icon, ICON_OVERLAY, 1, 1 + (y_tile - 1) * ICON_SIZE_Y)
column_icon.Blend(effect_icon, ICON_OVERLAY, 1, 1 + (y_tiles - 1) * ICON_SIZE_Y)
var/icon/immerse_icon = null
if (width == ICON_SIZE_X)
immerse_icon = column_icon
else
immerse_icon = icon('icons/effects/effects.dmi', mask_icon) // Use base icon and crop it out so animation frames respect dmi's delays
immerse_icon.Crop(1, 1, ICON_SIZE_X, ICON_SIZE_Y)
immerse_icon.Scale(ceil(width / ICON_SIZE_X) * ICON_SIZE_X, ceil(height / ICON_SIZE_Y) * ICON_SIZE_Y)
for (var/x_tile in 1 to ceil(width / ICON_SIZE_X))
immerse_icon.Blend(column_icon, ICON_OVERLAY, 1 + (x_tile - 1) * ICON_SIZE_X, 1)
target_mask = mutable_appearance(immerse_icon)
target_mask.alpha = alpha
target_mask.pixel_y = -(y_tiles - 1) * ICON_SIZE_Y + floor((clean_height - ICON_SIZE_Y) / 2)
immersion_masks[mask_key] = target_mask
return target_mask
/datum/element/immerse/proc/add_immerse_overlay(atom/movable/movable)
// This determines if the overlay should cover the entire surface of the object or not
var/layer_to_check = IS_TOPDOWN_PLANE(movable.plane) ? TOPDOWN_WATER_LEVEL_LAYER : WATER_LEVEL_LAYER
var/is_below_water = (movable.layer < layer_to_check) ? "underwater-" : ""
// Tall mobs still only get covered to their feet, unless they're offset down
var/mutable_appearance/immerse_mask = generate_immerse_mask(movable.get_cached_width(), max(ICON_SIZE_Y - movable.pixel_z, ICON_SIZE_Y), is_below_water)
var/atom/movable/immerse_mask/effect_relay = generated_visual_overlays[movable]
if (!effect_relay)
effect_relay = new(movable)
movable.vis_contents += effect_relay
generated_visual_overlays[movable] = effect_relay
var/mutable_appearance/mask_copy = new(immerse_mask)
effect_relay.appearance = mask_copy
effect_relay.render_target = "*immerse_[REF(movable)]"
SEND_SIGNAL(movable, COMSIG_MOVABLE_EDIT_UNIQUE_IMMERSE_OVERLAY, effect_relay)
// Should always render above any other filters that could be adding visuals
movable.add_filter("immerse_mask", INFINITY, alpha_mask_filter(y = -floor((movable.get_cached_height() - ICON_SIZE_Y) / 2) - movable.pixel_z, render_source = effect_relay.render_target, flags = MASK_INVERSE))
/datum/element/immerse/proc/remove_immerse_overlay(atom/movable/movable, deleting = TRUE)
movable.remove_filter("immerse_mask")
if (!deleting)
return
var/atom/movable/immerse_mask/mask = generated_visual_overlays[movable]
movable.vis_contents -= mask
generated_visual_overlays -= movable
QDEL_NULL(mask)
/// A band-aid to keep the (unique) visual overlay from scaling and rotating along with its owner. I'm sorry.
/datum/element/immerse/proc/on_update_transform(mob/living/source, resize, new_lying_angle, is_opposite_angle)
SIGNAL_HANDLER
var/matrix/new_transform = matrix()
new_transform.Scale(1/source.current_size)
new_transform.Scale(1 / source.current_size)
new_transform.Turn(-new_lying_angle)
var/atom/movable/immerse_mask/effect_relay = generated_visual_overlays[source]
var/mutable_appearance/relay_appearance = new(effect_relay.appearance)
relay_appearance.transform = new_transform
effect_relay.appearance = relay_appearance
var/atom/movable/immerse_overlay/vis_overlay = immersed_movables[source]
if(is_opposite_angle)
vis_overlay.transform = new_transform
vis_overlay.adjust_living_overlay_offset(source)
return
/**
* Here, we temporarily switch from the offset of the mutable appearance to one for movable used as visual overlay.
* Why? While visual overlays can be animated, their fixed point stays at the center of the icon of the atom
* they're attached to and not theirs, which can make manipulating the transform var a pain, but because
* we cannot do that with normal overlay or filters (reliably), we have to bend a knee and try to compensate it.
*/
vis_overlay.overlays = list(vis_overlay.overlay_appearance)
/// Oh, yeah, didn't I mention turning a visual overlay affects its pixel x/y/w/z too? Yeah, it sucks.
var/new_x = vis_overlay.extra_width
var/new_y = vis_overlay.extra_height
var/old_div = source.current_size / resize
var/offset_lying = source.rotate_on_lying ? PIXEL_Y_OFFSET_LYING : source.get_transform_translation_size(old_div)
switch(source.lying_prev)
if(270)
vis_overlay.pixel_x += -offset_lying / old_div
if(90)
vis_overlay.pixel_x += offset_lying / old_div
if(0)
vis_overlay.pixel_y += -source.get_transform_translation_size(old_div) / old_div
switch(new_lying_angle)
if(270)
new_x += -offset_lying / source.current_size
if(90)
new_x += offset_lying / source.current_size
if(0)
new_y += -source.get_transform_translation_size(old_div) / old_div
animate(vis_overlay, transform = new_transform, pixel_x = new_x, pixel_y = new_y, time = UPDATE_TRANSFORM_ANIMATION_TIME, easing = (EASE_IN|EASE_OUT))
addtimer(CALLBACK(vis_overlay, TYPE_PROC_REF(/atom/movable/immerse_overlay, adjust_living_overlay_offset), source), UPDATE_TRANSFORM_ANIMATION_TIME)
///Spin the overlay in the opposite direction so it doesn't look like it's spinning at all.
/// Spin the overlay in the opposite direction so it doesn't look like it's spinning at all.
/datum/element/immerse/proc/on_spin_animation(atom/source, speed, loops, segments, segment)
SIGNAL_HANDLER
var/atom/movable/immerse_overlay/vis_overlay = immersed_movables[source]
vis_overlay.do_spin_animation(speed, loops, segments, -segment)
var/atom/movable/immerse_mask/immerse_mask = generated_visual_overlays[source]
immerse_mask.do_spin_animation(speed, loops, segments, -segment)
///We need to make sure to remove hard refs from the element when deleted.
/datum/element/immerse/proc/clear_overlay_refs(atom/movable/immerse_overlay/source)
//Assume that every vis loc is also in the immersed_movables list
for(var/atom/movable/vis_loc as anything in source.vis_locs)
remove_from_element(vis_loc.loc, vis_loc)
LAZYREMOVE(generated_visual_overlays, source)
source.overlay_appearance = null
/datum/element/immerse/proc/on_update_offsets(mob/living/source, new_x, new_y, new_w, new_z, animate)
SIGNAL_HANDLER
var/old_height = ceil(max(ICON_SIZE_Y - source.pixel_z, ICON_SIZE_Y) / ICON_SIZE_Y)
var/new_height = ceil(max(ICON_SIZE_Y - new_z, ICON_SIZE_Y) / ICON_SIZE_Y)
if (old_height != new_height)
remove_immerse_overlay(source, FALSE)
add_immerse_overlay(source)
///The not-quite-perfect movable used by the immerse element for its nefarious deeds.
/atom/movable/immerse_overlay
appearance_flags = RESET_TRANSFORM|RESET_COLOR|RESET_ALPHA|KEEP_TOGETHER
vis_flags = VIS_INHERIT_PLANE|VIS_INHERIT_ID
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
blend_mode = BLEND_INSET_OVERLAY
layer = WATER_VISUAL_OVERLAY_LAYER
plane = FLOAT_PLANE
/**
* The actual overlay used to make the mob look like it's half-covered in water.
*
* For visual overlays, pixel y/x/w/z are amplified by the a, b, d, e variables
* of the transform matrix of the movable they're attached to.
* For example, if a mob is twice its normal size (a = 2, e = 2),
* offsetting the movable used as visual overlay by 4 pixels to the right will result
* in the visual overlay moving 8 pixels to the right.
*
* This however, doesn't extend to the overlays of our visual overlay. which is why there's
* a mutable appearance variable that we use for those pixel offsets that really shouldn't be affected
* by the transform of our vis loc(s) in the first place.
*/
var/mutable_appearance/overlay_appearance
///The base pixel x offset of this movable
var/extra_width = 0
///The base pixel y offset of this movable
var/extra_height = 0
if (source.pixel_z == new_z)
return
/atom/movable/immerse_overlay/Initialize(mapload, datum/element/immerse/element)
. = ..()
verbs.Cut() //"Cargo cultttttt" or something. Either way, they're better off without verbs.
element?.RegisterSignal(src, COMSIG_QDELETING, TYPE_PROC_REF(/datum/element/immerse, clear_overlay_refs))
if (animate)
source.transition_filter("immerse_mask", list("y" = -floor((source.get_cached_height() - ICON_SIZE_Y) / 2) - new_z), time = UPDATE_TRANSFORM_ANIMATION_TIME)
else
source.modify_filter("immerse_mask", list("y" = -floor((source.get_cached_height() - ICON_SIZE_Y) / 2) - new_z))
///Called by COMSIG_MOVABLE_EDIT_UNIQUE_IMMERSE_OVERLAY for living mobs and a few procs from the immerse element.
/atom/movable/immerse_overlay/proc/adjust_living_overlay_offset(mob/living/source)
pixel_x = extra_width
pixel_y = extra_height
overlays = list(overlay_appearance)
/atom/movable/immerse_mask
appearance_flags = RESET_TRANSFORM|RESET_COLOR|RESET_ALPHA|KEEP_APART
vis_flags = VIS_HIDE
+1 -4
View File
@@ -19,10 +19,7 @@
#define POSITIVE_INSTABILITY_MAJOR 35
/datum/mutation
var/name
/datum/mutation
name = "mutation"
var/name = "mutation"
/// Description of the mutation
var/desc = "A mutation."
/// Is this mutation currently locked?
+4 -27
View File
@@ -13,7 +13,8 @@
var/scream_delay = 50
var/last_scream = 0
var/bodypart_color = COLOR_DARK_LIME
/// List of traits to add/remove when someone gets this mutation.
/// Determines whether or not our version of hulk breaks their arm when destroying walls.
var/no_recoil = TRUE
mutation_traits = list(
TRAIT_CHUNKYFINGERS,
TRAIT_HULK,
@@ -61,30 +62,6 @@
/datum/mutation/hulk/proc/scream_attack(mob/living/carbon/human/source)
source.say("WAAAAAAAAAAAAAAGH!", forced="hulk")
/**
*Checks damage of a hulk's arm and applies bone wounds as necessary.
*
*Called by specific atoms being attacked, such as walls. If an atom
*does not call this proc, than punching that atom will not cause
*arm breaking (even if the atom deals recoil damage to hulks).
*Arguments:
*arg1 is the arm to evaluate damage of and possibly break.
*/
/datum/mutation/hulk/proc/break_an_arm(obj/item/bodypart/arm)
var/severity
switch(arm.brute_dam)
if(45 to 50)
severity = WOUND_SEVERITY_CRITICAL
if(41 to 45)
severity = WOUND_SEVERITY_SEVERE
if(35 to 41)
severity = WOUND_SEVERITY_MODERATE
if (isnull(severity))
return
owner.cause_wound_of_type_and_severity(WOUND_BLUNT, arm, severity, wound_source = "hulk smashing")
/datum/mutation/hulk/on_life(seconds_per_tick, times_fired)
if(owner.health < owner.crit_threshold)
on_losing(owner)
@@ -264,7 +241,7 @@
health_req = 0
instability = 0
scream_delay = 2.5 SECONDS // halved to be more annoying (spell doesn't last long anyways)
/// List of traits to add/remove when someone gets this mutation.
no_recoil = FALSE
mutation_traits = list(
TRAIT_HULK,
TRAIT_PUSHIMMUNE,
@@ -275,7 +252,7 @@
name = "Hulk (Super)"
health_req = 0
instability = 0
/// List of traits to add/remove when someone gets this mutation.
no_recoil = FALSE
mutation_traits = list(
TRAIT_CHUNKYFINGERS,
TRAIT_HULK,
+1 -2
View File
@@ -45,7 +45,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)
"trim" = trim,
)
continue
for(var/department_type as anything in job.departments_list)
for(var/department_type in job.departments_list)
//Jobs under multiple departments should only be displayed if this is their first department or the command department
if(job.departments_list[1] != department_type && !(job.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND))
continue
@@ -238,4 +238,3 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)
"manifest" = get_manifest(),
"positions" = positions
)
@@ -33,11 +33,11 @@
return
var/final_phrase = ""
var/original_char = ""
for(var/i = 1, i <= length(phrase), i += length(original_char))
original_char = phrase[i]
final_phrase += apply_speech(original_char)
var/list/words = splittext(phrase, " ")
var/list/new_words = list()
for(var/i in 1 to length(words))
new_words += apply_speech(words[i], i)
final_phrase = jointext(new_words, " ")
if(final_phrase == phrase)
return // No change was done, whatever
@@ -51,13 +51,13 @@
/**
* Applies the speech effects on the past character, changing
* the original_char into the modified_char.
* the original_word into some modified_word
*
* Return the modified_char to be reapplied to the message.
* Return the newly modified word
*/
/datum/status_effect/speech/proc/apply_speech(original_char)
/datum/status_effect/speech/proc/apply_speech(original_word, index)
stack_trace("[type] didn't implement apply_speech.")
return original_char
return original_word
/datum/status_effect/speech/stutter
id = "stutter"
@@ -65,33 +65,41 @@
tts_filter = "tremolo=f=10:d=0.8,rubberband=tempo=0.5"
/// The probability of adding a stutter to any character
var/stutter_prob = 80
var/stutter_prob = 75
/// The chance of a four character stutter
var/four_char_chance = 10
/// The chance of a three character stutter
var/three_char_chance = 20
/// The chance of a two character stutter
var/two_char_chance = 95
/// Regex of characters we won't apply a stutter to
var/static/regex/no_stutter
var/two_char_chance = 90
/// Regex to apply generically to stuttered words
/// * 1st capture group is any leading invalid characters (can be empty)
/// * 2nd capture group is either a digraph (th, qu, ch) or a consonant
/// * 3rd capture group is the rest of the word (can be empty)
VAR_FINAL/static/regex/stutter_regex
/datum/status_effect/speech/stutter/on_creation(mob/living/new_owner, ...)
. = ..()
if(!.)
return
if(!no_stutter)
no_stutter = regex(@@[aeiouAEIOU ""''()[\]{}.!?,:;_`~-]@)
stutter_regex ||= regex(@@^([\s"'()[\]{}.!?,:;_`~-]*\b)([^aeoiuh\d]h|qu|[^\d])(.*)@, "i")
return ..()
/datum/status_effect/speech/stutter/apply_speech(original_char)
if(prob(stutter_prob) && !no_stutter.Find(original_char))
if(prob(four_char_chance))
return "[original_char]-[original_char]-[original_char]-[original_char]"
if(prob(three_char_chance))
return "[original_char]-[original_char]-[original_char]"
if(prob(two_char_chance))
return "[original_char]-[original_char]"
/datum/status_effect/speech/stutter/apply_speech(original_word, index)
if(!prob(stutter_prob))
return original_word
return original_char
if(stutter_regex.Find(original_word))
return "[stutter_regex.group[1]][stutter_char(stutter_regex.group[2])][stutter_regex.group[3]]"
return original_word // i give up
/datum/status_effect/speech/stutter/proc/stutter_char(some_char)
if(prob(four_char_chance))
return "[some_char]-[some_char]-[some_char]-[some_char]"
if(prob(three_char_chance))
return "[some_char]-[some_char]-[some_char]"
if(prob(two_char_chance))
return "[some_char]-[some_char]"
return some_char
/datum/status_effect/speech/stutter/anxiety
id = "anxiety_stutter"
@@ -133,7 +141,7 @@
if(prob(capitalize_prob))
var/exclamation = pick("!", "!!", "!!!")
message = uppertext(message)
message += "[apply_speech(exclamation, exclamation)]"
message += "[stutter_char(exclamation)]"
message_args[TREAT_MESSAGE_ARG] = message
@@ -170,6 +178,12 @@
/// Strings that are appended to a character - populated in on_creation
var/list/string_additions
/// Regex for characters we won't apply any slurring to
var/static/regex/no_slur
/// If the last character we processed was a replacement, don't do another replacement right after it
VAR_PRIVATE/replacement_dupe_check = FALSE
/datum/status_effect/speech/slurring/on_creation(mob/living/new_owner, duration = 10 SECONDS)
. = ..()
if(!.)
@@ -184,46 +198,57 @@
string_replacements = speech_changes["string_replacements"]
string_additions = speech_changes["string_additions"]
/datum/status_effect/speech/slurring/apply_speech(original_char)
no_slur ||= regex(@@[ "'()[\]{}.!?,:;_`~-]@)
/datum/status_effect/speech/slurring/apply_speech(original_word, index)
var/original_char = ""
var/modified_word = ""
for(var/i = 1, i <= length(original_word), i += length(original_char))
original_char = original_word[i]
modified_word += slur_character(original_char, i)
return modified_word
/datum/status_effect/speech/slurring/proc/slur_character(original_char, index)
var/modified_char = original_char
var/allow_slurring = index != 1 && !no_slur.Find(modified_char)
var/lower_char = LOWER_TEXT(modified_char)
if(prob(common_prob) && (lower_char in common_replacements))
var/to_replace = common_replacements[lower_char]
if(islist(to_replace))
modified_char = pick(to_replace)
else
modified_char = to_replace
modified_char = islist(to_replace) ? pick(to_replace) : to_replace
replacement_dupe_check = FALSE
if(prob(uncommon_prob) && (modified_char in uncommon_replacements))
else if(prob(uncommon_prob) && (modified_char in uncommon_replacements))
var/to_replace = uncommon_replacements[modified_char]
if(islist(to_replace))
modified_char = pick(to_replace)
else
modified_char = to_replace
modified_char = islist(to_replace) ? pick(to_replace) : to_replace
replacement_dupe_check = FALSE
if(prob(replacement_prob))
var/replacements_len = length(string_replacements)
var/additions_len = length(string_additions)
if(replacements_len && additions_len)
// Calculate the probability of grabbing a replacement vs an addition
var/weight = (replacements_len + additions_len) / replacements_len * 100
if(prob(weight))
else if(allow_slurring) // Don't do replacements on the first character, or punctuation
if(!replacement_dupe_check && prob(replacement_prob))
var/replacements_len = length(string_replacements)
var/additions_len = length(string_additions)
if(replacements_len && additions_len)
// Calculate the probability of grabbing a replacement vs an addition
var/weight = (replacements_len + additions_len) / replacements_len * 100
if(prob(weight))
modified_char = pick(string_replacements)
else
modified_char += pick(string_additions)
else if(replacements_len)
modified_char = pick(string_replacements)
else
else if(additions_len)
modified_char += pick(string_additions)
replacement_dupe_check = TRUE
else if(replacements_len)
modified_char = pick(string_replacements)
else if(prob(doubletext_prob))
modified_char += "[modified_char][prob(50) ? "" : modified_char]"
replacement_dupe_check = FALSE
else if(additions_len)
modified_char += pick(string_additions)
if(prob(doubletext_prob))
if(prob(50))
modified_char += "[modified_char]"
else
modified_char += "[modified_char][modified_char]"
else
// If we don't allow replacements we don't want the next character to be a replacement either
// This makes some more coherent speech by disallowing structures like "Y'''e"
replacement_dupe_check = TRUE
return modified_char
@@ -231,8 +256,8 @@
id = "generic_slurring"
common_prob = 33
uncommon_prob = 0
replacement_prob = 5
doubletext_prob = 10
replacement_prob = 24
doubletext_prob = 40
text_modification_file = "slurring_drunk_text.json"
/datum/status_effect/speech/slurring/drunk
@@ -248,13 +273,13 @@
var/current_drunkness = owner.get_drunk_amount()
// These numbers are arbitarily picked
// Common replacements start at about 20, and maxes out at about 85
common_prob = clamp((current_drunkness * 0.8) - 16, 0, 50)
common_prob = clamp((current_drunkness * 0.8) - 16, 4, 50)
// Uncommon replacements (burping) start at 50 and max out at 110 (when you are dying)
uncommon_prob = clamp((current_drunkness * 0.2) - 10, 0, 12)
uncommon_prob = clamp((current_drunkness * 0.3) - 10, 0, 12)
// Replacements start at 20 and max out at about 60
replacement_prob = clamp((current_drunkness * 0.4) - 8, 0, 12)
replacement_prob = clamp((current_drunkness * 0.6) - 8, 0, 12)
// Double texting start out at about 25 and max out at about 60
doubletext_prob = clamp((current_drunkness * 0.5) - 12, 0, 20)
doubletext_prob = clamp((current_drunkness * 0.8) - 8, 2, 50)
return ..()
/datum/status_effect/speech/slurring/cult
+1 -1
View File
@@ -340,7 +340,7 @@
/datum/storage/unfathomable_curio/New(atom/parent, max_slots, max_specific_storage, max_total_storage, rustle_sound, remove_rustle_sound)
. = ..()
set_holdable(list(
/obj/item/ammo_box/strilka310/lionhunter,
/obj/item/ammo_box/speedloader/strilka310/lionhunter,
/obj/item/heretic_labyrinth_handbook,
/obj/item/bodypart, // Bodyparts are often used in rituals.
/obj/item/clothing/neck/eldritch_amulet,
+3 -9
View File
@@ -55,9 +55,7 @@
/obj/item/ammo_box/magazine/m45,
/obj/item/ammo_box/magazine/m50,
/obj/item/gun/ballistic/revolver,
/obj/item/ammo_box/c38, // Revolver speedloaders.
/obj/item/ammo_box/a357,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader, // Speedloaders, which includes stripper clips on a technicality.
/obj/item/ammo_box/magazine/toy/pistol,
/obj/item/gun/energy/e_gun/mini,
/obj/item/gun/energy/disabler,
@@ -84,9 +82,7 @@
/obj/item/ammo_box/magazine/m45,
/obj/item/ammo_box/magazine/m50,
/obj/item/gun/ballistic/revolver,
/obj/item/ammo_box/c38,
/obj/item/ammo_box/a357,
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader,
/obj/item/ammo_box/magazine/toy/pistol,
/obj/item/gun/energy/recharge/ebow,
/obj/item/gun/energy/e_gun/mini,
@@ -107,9 +103,7 @@
holdables = list(
/obj/item/gun, // ALL guns.
/obj/item/ammo_box/magazine, // ALL magazines.
/obj/item/ammo_box/c38, //There isn't a speedloader parent type, so I just put these three here by hand.
/obj/item/ammo_box/a357, //I didn't want to just use /obj/item/ammo_box, because then this could hold huge boxes of ammo.
/obj/item/ammo_box/strilka310,
/obj/item/ammo_box/speedloader, // ALL speedloaders (there's 3 types at time of writing so it's probably fine)
/obj/item/ammo_casing, // For shotgun shells, rockets, launcher grenades, and a few other things.
/obj/item/grenade, // All regular grenades, the big grenade launcher fires these.
)
+2 -2
View File
@@ -216,7 +216,7 @@
/obj/item/reagent_containers/cup/glass/bottle/vodka,
/obj/item/reagent_containers/cup/glass/bottle/molotov,
/obj/item/reagent_containers/cup/glass/drinkingglass,
/obj/item/ammo_box/strilka310
/obj/item/ammo_box/speedloader/strilka310
))
///Void cloak pocket
@@ -234,7 +234,7 @@
. = ..()
set_holdable(
can_hold_list = list(
/obj/item/ammo_box/strilka310/lionhunter,
/obj/item/ammo_box/speedloader/strilka310/lionhunter,
/obj/item/bodypart, // Bodyparts are often used in rituals. They're also often normal sized, so you can only fit one.
/obj/item/clothing/neck/eldritch_amulet,
/obj/item/clothing/neck/heretic_focus,
+1 -1
View File
@@ -158,7 +158,7 @@
if (!length(suggested_wounding_types))
return FALSE
for (var/iter_wounding_type as anything in suggested_wounding_types)
for (var/iter_wounding_type in suggested_wounding_types)
if (!(iter_wounding_type in required_wounding_types))
if (match_all_wounding_types)
return FALSE
+1 -1
View File
@@ -725,7 +725,7 @@
// fleshy burns will look for flesh then bone
// dislocations will look for flesh, then bone, then metal
var/file = default_scar_file
for (var/biotype as anything in pregen_data.scar_priorities)
for (var/biotype in pregen_data.scar_priorities)
if (scarred_limb.biological_state & text2num(biotype))
file = GLOB.biotypes_to_scar_file[biotype]
break
+8 -3
View File
@@ -162,7 +162,12 @@
/atom/proc/get_name_chaser(mob/user, list/name_chaser = list())
return name_chaser
/// Used by mobs to determine the name for someone wearing a mask, or with a disfigured or missing face. By default just returns the atom's name. add_id_name will control whether or not we append "(as [id_name])".
/// force_real_name will always return real_name and add (as face_name/id_name) if it doesn't match their appearance
/atom/proc/get_visible_name(add_id_name, force_real_name)
/**
* Used by mobs to determine the name for someone wearing a mask, or with a disfigured or missing face.
* By default just returns the atom's name.
*
* * add_id_name - If TRUE, ID information such as honorifics or name (if mismatched) are appended
* * force_real_name - If TRUE, will always return real_name and add (as face_name/id_name) if it doesn't match their appearance
*/
/atom/proc/get_visible_name(add_id_name = TRUE, force_real_name = FALSE)
return name
+2 -2
View File
@@ -1056,7 +1056,7 @@
var/list/part_list = replacer_tool.get_sorted_parts(ignore_stacks = TRUE)
if(!part_list.len)
return FALSE
for(var/primary_part_base as anything in component_parts)
for(var/primary_part_base in component_parts)
//we exchanged all we could time to bail
if(!part_list.len)
break
@@ -1156,7 +1156,7 @@
// we infer the required stack stuff inside the machine from the circuitboards requested components
if(istype(component_ref, /obj/item/circuitboard/machine))
var/obj/item/circuitboard/machine/board = component_ref
for(var/component as anything in board.req_components)
for(var/component in board.req_components)
if(!ispath(component, /obj/item/stack))
continue
part_count[component] = board.req_components[component]
@@ -391,7 +391,7 @@
data["enemy_mp"] = enemy_mp
data["equipped_gear"] = list()
for(var/gear_slot as anything in equipped_gear)
for(var/gear_slot in equipped_gear)
var/datum/battle_arcade_gear/user_gear = equipped_gear[gear_slot]
if(!istype(user_gear))
continue
+1 -1
View File
@@ -44,7 +44,7 @@
/obj/machinery/door/password/get_save_vars()
return ..() + NAMEOF(src, password)
/obj/machinery/door/password/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods = list(), message_range)
/obj/machinery/door/password/Hear(atom/movable/speaker, message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods = list(), message_range)
. = ..()
if(!density || !voice_activated || radio_freq)
return
+28 -24
View File
@@ -19,16 +19,22 @@
/// The current deconstruction step
var/deconstruction = BLASTDOOR_FINISHED
/// The door's ID (used for buttons, etc to control the door)
var/id = 1
var/id = null
/// The sound that plays when the door opens/closes
var/animation_sound = 'sound/machines/blastdoor.ogg'
var/show_nav_computer_icon = TRUE
///The mob who crafted this blastdoor
var/datum/weakref/owner
/obj/machinery/door/poddoor/Initialize(mapload)
. = ..()
if(show_nav_computer_icon)
AddElement(/datum/element/nav_computer_icon, 'icons/effects/nav_computer_indicators.dmi', "airlock", TRUE)
/obj/machinery/door/poddoor/Destroy()
owner = null
return ..()
/datum/armor/door_poddoor
melee = 50
bullet = 100
@@ -46,7 +52,7 @@
if(panel_open)
if(deconstruction == BLASTDOOR_FINISHED)
. += span_notice("The maintenance panel is opened and the electronics could be <b>pried</b> out.")
. += span_notice("\The [src] could be calibrated to a blast door controller ID with a <b>multitool</b> or a <b>blast door controller</b>.")
. += span_notice("\The [src] could be calibrated to a blast door controller ID with a <b>blast door controller</b>.")
else if(deconstruction == BLASTDOOR_NEEDS_ELECTRONICS)
. += span_notice("The <i>electronics</i> are missing and there are some <b>wires</b> sticking out.")
else if(deconstruction == BLASTDOOR_NEEDS_WIRES)
@@ -71,9 +77,6 @@
if(TOOL_SCREWDRIVER)
context[SCREENTIP_CONTEXT_LMB] = "Open panel"
return CONTEXTUAL_SCREENTIP_SET
if(TOOL_MULTITOOL)
context[SCREENTIP_CONTEXT_LMB] = "Calibrate ID"
return CONTEXTUAL_SCREENTIP_SET
if(TOOL_CROWBAR)
context[SCREENTIP_CONTEXT_LMB] = "Remove electronics"
return CONTEXTUAL_SCREENTIP_SET
@@ -84,6 +87,10 @@
context[SCREENTIP_CONTEXT_LMB] = "Disassemble"
return CONTEXTUAL_SCREENTIP_SET
/obj/machinery/door/poddoor/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter)
. = ..()
owner = WEAKREF(crafter)
/obj/machinery/door/poddoor/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(deconstruction == BLASTDOOR_NEEDS_WIRES && istype(tool, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/coil = tool
@@ -117,8 +124,22 @@
balloon_alert(user, "open the panel first!")
return ITEM_INTERACT_BLOCKING
var/obj/item/assembly/control/controller_item = tool
if(controller_item.id == -1)
//collect existing ids
var/list/door_ids = list()
for(var/obj/machinery/door/poddoor/M as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door/poddoor))
if(!M.id || (M.id in door_ids))
continue
door_ids += "[M.id]"
//create new id
var/new_id = 0
while("[new_id]" in door_ids)
new_id += 1
controller_item.id = "[new_id]"
id = controller_item.id
balloon_alert(user, "id changed")
owner = WEAKREF(user)
balloon_alert(user, "id changed to [id]")
return ITEM_INTERACT_SUCCESS
return NONE
@@ -131,24 +152,6 @@
else if (default_deconstruction_screwdriver(user, icon_state, icon_state, tool))
return ITEM_INTERACT_SUCCESS
/obj/machinery/door/poddoor/multitool_act(mob/living/user, obj/item/tool)
. = ..()
if (density)
balloon_alert(user, "open the door first!")
return ITEM_INTERACT_SUCCESS
if (!panel_open)
balloon_alert(user, "open the panel first!")
return ITEM_INTERACT_SUCCESS
if (deconstruction != BLASTDOOR_FINISHED)
return
var/change_id = tgui_input_number(user, "Set the door controllers ID (Current: [id])", "Door Controller ID", isnum(id) ? id : null, 100)
if(!change_id || QDELETED(usr) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
id = change_id
to_chat(user, span_notice("You change the ID to [id]."))
balloon_alert(user, "id changed")
return ITEM_INTERACT_SUCCESS
/obj/machinery/door/poddoor/crowbar_act(mob/living/user, obj/item/tool)
. = ..()
if(machine_stat & NOPOWER)
@@ -166,6 +169,7 @@
if(tool.use_tool(src, user, 10 SECONDS, volume = 50))
new /obj/item/electronics/airlock(loc)
id = null
owner = null
deconstruction = BLASTDOOR_NEEDS_ELECTRONICS
balloon_alert(user, "removed airlock electronics")
return ITEM_INTERACT_SUCCESS
+2 -2
View File
@@ -212,7 +212,7 @@
if(energy_used)
use_energy(energy_used)
for(var/spawnable_item as anything in dispense_type)
for(var/spawnable_item in dispense_type)
var/atom/spawned_atom = new spawnable_item(loc)
spawned_atom.flags_1 |= (flags_1 & ADMIN_SPAWNED_1)
@@ -237,7 +237,7 @@
/obj/machinery/drone_dispenser/proc/count_shells()
. = 0
for(var/actual_shell in loc)
for(var/potential_item as anything in dispense_type)
for(var/potential_item in dispense_type)
if(istype(actual_shell, potential_item))
.++
@@ -69,10 +69,10 @@
dna.copy_dna(subject.dna, COPY_DNA_SE|COPY_DNA_SPECIES)
for (var/quirk_type as anything in quirks)
for (var/quirk_type in quirks)
subject.add_quirk(quirk_type, add_unique = FALSE, announce = FALSE)
for (var/trauma_type as anything in brain_traumas)
for (var/trauma_type in brain_traumas)
subject.gain_trauma(trauma_type)
for (var/obj/item/bodypart/limb as anything in subject.bodyparts)
+1 -1
View File
@@ -235,7 +235,7 @@
inserted_board = attacking_item
//compute the needed mats from its stock parts
for(var/type as anything in inserted_board.req_components)
for(var/type in inserted_board.req_components)
//these don't count to the final cost as they have to inserted manually
if(type in inserted_board.flatpack_components)
continue
+3 -3
View File
@@ -577,19 +577,19 @@ Possible to do for anyone motivated enough:
/*This is the proc for special two-way communication between AI and holopad/people talking near holopad.
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods = list(), message_range)
/obj/machinery/holopad/Hear(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods = list(), message_range)
. = ..()
if(speaker && LAZYLEN(masters) && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
for(var/mob/living/silicon/ai/master in masters)
if(masters[master] && speaker != master)
master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
master.relay_speech(speaker, message_language, raw_message, radio_freq, spans, message_mods)
for(var/datum/holocall/holocall_to_update as anything in holo_calls)
if(holocall_to_update.connected_holopad == src)//if we answered this call originating from another holopad
if(speaker == holocall_to_update.hologram && holocall_to_update.user.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat))
holocall_to_update.user.create_chat_message(speaker, message_language, raw_message, spans)
else
holocall_to_update.user.Hear(message, speaker, message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, spans, message_mods, message_range = INFINITY)
holocall_to_update.user.Hear(speaker, message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, spans, message_mods, message_range = INFINITY)
if(outgoing_call?.hologram && speaker == outgoing_call.user)
outgoing_call.hologram.say(raw_message, spans = spans, sanitize = FALSE, language = message_language, message_mods = message_mods)
+4 -2
View File
@@ -92,8 +92,10 @@
return ..()
/obj/machinery/quantumpad/interact(mob/user, obj/machinery/quantumpad/target_pad = linked_pad)
if(!target_pad || QDELETED(target_pad))
if(!map_pad_link_id || !initMappedLink())
if(QDELETED(target_pad))
if(map_pad_link_id && initMappedLink())
target_pad = linked_pad
else
to_chat(user, span_warning("Target pad not found!"))
return
//SKYRAT EDIT ADDITION
@@ -174,14 +174,13 @@
// Always call this on the virtualspeaker to avoid issues.
var/spans = data["spans"]
var/list/message_mods = data["mods"]
var/rendered = virt.compose_message(virt, language, message, frequency, data["frequency_name"], data["frequency_color"], spans)
for(var/atom/movable/hearer as anything in receive)
if(!hearer)
stack_trace("null found in the hearers list returned by the spatial grid. this is bad")
continue
spans -= blacklisted_spans
hearer.Hear(rendered, virt, language, message, frequency, data["frequency_name"], data["frequency_color"], spans, message_mods, message_range = INFINITY)
hearer.Hear(virt, language, message, frequency, data["frequency_name"], data["frequency_color"], spans, message_mods, message_range = INFINITY)
// This following recording is intended for research and feedback in the use of department radio channels
if(length(receive))
@@ -27,8 +27,8 @@
new /obj/effect/temp_visual/circle_wave/bluespace(get_turf(src))
playsound(src, 'sound/effects/magic/cosmic_energy.ogg', vol = 50)
var/turf/T = pick(get_area_turfs(impact_area))
if(!T)
var/turf/impact_turf = pick(get_area_turfs(impact_area))
if(!impact_turf)
return
// Calculate new position (searches through beacons in world)
@@ -51,39 +51,31 @@
return
// Calculate previous position for transition
var/turf/FROM = T // the turf of origin we're travelling FROM
var/turf/TO = get_turf(chosen) // the turf of origin we're travelling TO
var/turf/beacon_turf = get_turf(chosen) // the turf of origin we're travelling TO
playsound(TO, 'sound/effects/phasein.ogg', 100, TRUE)
playsound(beacon_turf, 'sound/effects/phasein.ogg', 100, TRUE)
priority_announce("Massive bluespace translocation detected.", "Anomaly Alert")
var/list/flashers = list()
for(var/mob/living/carbon/C in viewers(TO, null))
if(C.flash_act())
flashers += C
for(var/mob/living/living in viewers(beacon_turf, null))
if(living.flash_act(affect_silicon = TRUE, visual = TRUE, type = /atom/movable/screen/fullscreen/bluespace_sparkle, length = 2 SECONDS))
flashers += living
var/y_distance = TO.y - FROM.y
var/x_distance = TO.x - FROM.x
for (var/atom/movable/A in urange(12, FROM )) // iterate thru list of mobs in the area
if(istype(A, /obj/item/beacon))
continue // don't teleport beacons because that's just insanely stupid
if(iseyemob(A))
continue // Don't mess with AI eye, blob eye, xenobio or advanced cameras
if(A.anchored)
continue
var/y_distance = beacon_turf.y - impact_turf.y
var/x_distance = beacon_turf.x - impact_turf.x
var/list/available_turfs = RANGE_TURFS(12, beacon_turf)
for (var/atom/movable/movable in urange(12, impact_turf )) // iterate thru list of mobs in the area
if(istype(movable, /obj/item/beacon) || iseffect(movable) || iseyemob(movable))
continue // Don't mess with beacons, effects or camera mobs (blob, AI eye etc...)
if(movable.anchored)
continue // do_teleport doesn't check if the item is anchored or not.
var/turf/newloc = locate(A.x + x_distance, A.y + y_distance, TO.z) // calculate the new place
if(!A.Move(newloc) && newloc) // if the atom, for some reason, can't move, FORCE them to move! :) We try Move() first to invoke any movement-related checks the atom needs to perform after moving
A.forceMove(newloc)
var/turf/newloc = locate(movable.x + x_distance, movable.y + y_distance, beacon_turf.z) || pick(available_turfs) // calculate the new place, or pick a random one as fallback
do_teleport(movable, newloc, no_effects = TRUE)
if(ismob(A) && !(A in flashers)) // don't flash if we're already doing an effect
var/mob/give_sparkles = A
if(give_sparkles.client)
blue_effect(give_sparkles)
/obj/effect/anomaly/bluespace/proc/blue_effect(mob/make_sparkle)
make_sparkle.overlay_fullscreen("bluespace_flash", /atom/movable/screen/fullscreen/bluespace_sparkle, 1)
addtimer(CALLBACK(make_sparkle, TYPE_PROC_REF(/mob/, clear_fullscreen), "bluespace_flash"), 2 SECONDS)
if(isliving(movable) && !(movable in flashers)) // don't flash if we're already doing an effect
var/mob/living/give_sparkles = movable
give_sparkles.flash_act(affect_silicon = TRUE, visual = TRUE, type = /atom/movable/screen/fullscreen/bluespace_sparkle, length = 2 SECONDS)
/obj/effect/anomaly/bluespace/stabilize(anchor, has_core)
. = ..()
@@ -10,7 +10,7 @@
/obj/effect/spawner/random/sakhno/ammo
name = ".310 Strilka stripper clip spawner"
loot = list(
/obj/item/ammo_box/strilka310/surplus = 80,
/obj/item/ammo_box/strilka310 = 10,
/obj/item/ammo_box/speedloader/strilka310/surplus = 80,
/obj/item/ammo_box/speedloader/strilka310 = 10,
/obj/item/food/rationpack = 1,
)
@@ -102,6 +102,9 @@
/obj/item/radio/intercom/attack_ai(mob/user)
interact(user)
/obj/item/radio/intercom/attack_robot(mob/user)
interact(user)
/obj/item/radio/intercom/attack_hand(mob/user, list/modifiers)
. = ..()
if(.)
@@ -123,7 +126,7 @@
return TRUE
/obj/item/radio/intercom/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods = list(), message_range)
/obj/item/radio/intercom/Hear(atom/movable/speaker, message_langs, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods = list(), message_range)
if(message_mods[RADIO_EXTENSION] == MODE_INTERCOM)
return // Avoid hearing the same thing twice
return ..()
@@ -381,7 +381,7 @@
signal.levels = SSmapping.get_connected_levels(T)
signal.broadcast()
/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods = list(), message_range)
/obj/item/radio/Hear(atom/movable/speaker, message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods = list(), message_range)
. = ..()
if(radio_freq || !broadcasting || get_dist(src, speaker) > canhear_range || message_mods[MODE_RELAY])
return
@@ -190,7 +190,17 @@
render_list += "<span class='alert ml-1'>Fatigue level: [target.getStaminaLoss()]%.</span><br>"
else
render_list += "<span class='alert ml-1'>Subject appears to be suffering from fatigue.</span><br>"
if (!target.get_organ_slot(ORGAN_SLOT_BRAIN)) // kept exclusively for soul purposes
// Check for brain - both organic (carbon) and synthetic (cyborg MMI)
var/has_brain = FALSE
if(target.get_organ_slot(ORGAN_SLOT_BRAIN))
has_brain = TRUE
else if(iscyborg(target))
var/mob/living/silicon/robot/cyborg_target = target
if(cyborg_target.mmi?.brain)
has_brain = TRUE
if(!has_brain) // kept exclusively for soul purposes
render_list += "<span class='alert ml-1'>Subject lacks a brain.</span><br>"
if(iscarbon(target))
@@ -153,7 +153,7 @@
return ..()
/obj/item/taperecorder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, radio_freq_name, radio_freq_color, spans, list/message_mods = list(), message_range)
/obj/item/taperecorder/Hear(atom/movable/speaker, message_langs, raw_message, radio_freq, radio_freq_name, radio_freq_color, spans, list/message_mods = list(), message_range)
. = ..()
if(message_mods[MODE_RELAY] || !mytape || istype(speaker, /obj/item/taperecorder))
return
+5 -10
View File
@@ -165,8 +165,8 @@
//check if we can build our window on the grill
if(target_turf.is_blocked_turf(exclude_mobs = !is_full_tile, source_atom = null, ignore_atoms = structures_to_ignore, type_list = TRUE))
playsound(get_turf(user), SFX_TOOL_SWITCH, 20, TRUE)
balloon_alert(user, "something is blocking the turf")
playsound(user, SFX_TOOL_SWITCH, 20, TRUE)
balloon_alert(user, "tile is blocked!")
return FALSE
/**
@@ -344,7 +344,7 @@
data["selected_root"] = root_category
data["categories"] = list()
for(var/sub_category as anything in GLOB.rcd_designs[root_category])
for(var/sub_category in GLOB.rcd_designs[root_category])
var/list/target_category = GLOB.rcd_designs[root_category][sub_category]
if(!length(target_category))
continue
@@ -529,15 +529,10 @@
/obj/item/construction/rcd/ce
name = "professional RCD"
desc = "A higher-end model of the rapid construction device, prefitted with improved cooling and disruption prevention. Provided to the chief engineer."
icon_state = "cercd"
inhand_icon_state = "cercd"
construction_upgrades = RCD_UPGRADE_ANTI_INTERRUPT | RCD_UPGRADE_NO_FREQUENT_USE_COOLDOWN
matter = 160
color = list(
0.3, 0.3, 0.7, 0.0,
1.0, 1.0, 0.2, 0.0,
-0.2, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
0.0, 0.0, 0.0, 0.0,
)
/obj/item/construction/rcd/combat
name = "industrial RCD"
+2 -2
View File
@@ -206,13 +206,13 @@
var/is_allowed = TRUE
if(!checkResource(cost, user) || !(is_allowed = canPlace(destination)))
if(!is_allowed)
balloon_alert(user, "turf is blocked!")
balloon_alert(user, "tile is blocked!")
return FALSE
if(!build_delay(user, cost, target = destination))
return FALSE
if(!checkResource(cost, user) || !(is_allowed = canPlace(destination)))
if(!is_allowed)
balloon_alert(user, "turf is blocked!")
balloon_alert(user, "tile is blocked!")
return FALSE
if(!useResource(cost, user))
+1 -1
View File
@@ -160,7 +160,7 @@
data["selected_root"] = root_category
data["categories"] = list()
for(var/sub_category as anything in GLOB.floor_designs[root_category])
for(var/sub_category in GLOB.floor_designs[root_category])
var/list/target_category = GLOB.floor_designs[root_category][sub_category]
var/list/designs = list() //initialize all designs under this category
@@ -22,16 +22,6 @@
icon_state = "securityhudnight"
sight_mode = BORGXRAY
/obj/item/borg/sight/thermal
name = "\proper thermal vision"
sight_mode = BORGTHERM
icon_state = "thermal"
/obj/item/borg/sight/meson
name = "\proper meson vision"
sight_mode = BORGMESON
icon_state = "meson"
/obj/item/borg/sight/material
name = "\proper material vision"
sight_mode = BORGMATERIAL
+1 -1
View File
@@ -132,7 +132,7 @@
/obj/item/borg/projectile_dampen/proc/process_usage(seconds_per_tick)
var/usage = 0
for(var/projectile as anything in tracked_bullet_cost)
for(var/projectile in tracked_bullet_cost)
usage += projectile_tick_speed_ecost * seconds_per_tick
usage += tracked_bullet_cost[projectile] * projectile_damage_tick_ecost_coefficient * seconds_per_tick
energy = clamp(energy - usage, 0, maxenergy)
+2 -2
View File
@@ -57,7 +57,7 @@
/obj/item/storage/belt/holster/detective/full/PopulateContents()
generate_items_inside(list(
/obj/item/ammo_box/c38 = 2,
/obj/item/ammo_box/speedloader/c38 = 2,
/obj/item/gun/ballistic/revolver/c38/detective = 1,
), src)
@@ -99,7 +99,7 @@
/obj/item/storage/belt/holster/nukie/cowboy/full/PopulateContents()
generate_items_inside(list(
/obj/item/ammo_box/a357 = 2,
/obj/item/ammo_box/speedloader/c357 = 2,
/obj/item/gun/ballistic/revolver/cowboy/nuclear = 1,
), src)

Some files were not shown because too many files have changed in this diff Show More