mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-06-18 12:44:15 +01:00
Merge remote-tracking branch 'skyrat/master' into upstream_merge3
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -443,9 +443,9 @@
|
||||
/area/ruin/space/ks13/medical/medbay)
|
||||
"fH" = (
|
||||
/obj/machinery/door/morgue{
|
||||
name = "Chaplains Office"
|
||||
name = "Chaplains Office";
|
||||
req_access = list("chapel_office")
|
||||
},
|
||||
/obj/effect/mapping_helpers/airlock/access/all/service/chapel_office,
|
||||
/turf/open/floor/iron/dark,
|
||||
/area/ruin/space/ks13/service/chapel_office)
|
||||
"fJ" = (
|
||||
|
||||
@@ -18,36 +18,51 @@
|
||||
/area/ruin/space)
|
||||
"an" = (
|
||||
/obj/structure/fluff/bus/passable/seat,
|
||||
/obj/item/food/meatball,
|
||||
/obj/item/toy/plush/pkplush{
|
||||
pixel_y = 17
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
/area/ruin/space)
|
||||
"ao" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
/obj/machinery/telecomms/server{
|
||||
pixel_y = 12;
|
||||
layer = 2.91;
|
||||
name = "tgsv3";
|
||||
desc = "It's, uh... pending an upgrade."
|
||||
},
|
||||
/turf/closed/mineral/ash_rock,
|
||||
/area/ruin/space)
|
||||
"ap" = (
|
||||
/obj/structure/fluff/bus/passable/seat{
|
||||
pixel_y = 15
|
||||
},
|
||||
/obj/item/toy/plush/lizard_plushie/green{
|
||||
pixel_y = 17
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
/area/ruin/space)
|
||||
"aq" = (
|
||||
/obj/structure/fluff/bus/passable/seat,
|
||||
/obj/item/food/meatball,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/item/clothing/head/helmet/knight{
|
||||
pixel_y = 16
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
/area/ruin/space)
|
||||
"ar" = (
|
||||
/obj/structure/fluff/bus/passable/seat,
|
||||
/obj/item/food/grown/cherry_bomb,
|
||||
/obj/item/grown/novaflower{
|
||||
pixel_y = 25
|
||||
},
|
||||
/obj/item/food/grown/watermelon{
|
||||
pixel_y = 17
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
@@ -55,7 +70,15 @@
|
||||
"as" = (
|
||||
/obj/structure/fluff/bus/passable/seat/driver,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/item/food/grown/citrus/orange,
|
||||
/obj/item/toy/plush/moth{
|
||||
pixel_y = 28
|
||||
},
|
||||
/obj/item/food/grown/citrus/orange{
|
||||
pixel_y = 19
|
||||
},
|
||||
/obj/item/toy/talking/ai{
|
||||
pixel_y = 16
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
@@ -117,7 +140,13 @@
|
||||
"aU" = (
|
||||
/obj/structure/fluff/bus/passable/seat,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/item/food/meatball,
|
||||
/obj/item/bodypart/arm/right{
|
||||
pixel_y = 26;
|
||||
pixel_x = -4
|
||||
},
|
||||
/obj/item/food/meat/slab/penguin{
|
||||
pixel_y = 13
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
@@ -132,29 +161,38 @@
|
||||
"aW" = (
|
||||
/obj/structure/fluff/bus/passable/seat/driver,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/item/banhammer{
|
||||
pixel_y = 22
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
/area/ruin/space)
|
||||
"aZ" = (
|
||||
/obj/structure/fluff/bus/passable,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/item/food/meatball,
|
||||
/obj/structure/sacrificealtar,
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
/area/ruin/space)
|
||||
"ba" = (
|
||||
/obj/structure/fluff/bus/passable,
|
||||
/obj/item/banhammer,
|
||||
/obj/structure/fluff/bus/passable/seat,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/effect/decal/cleanable/ants{
|
||||
pixel_y = 8;
|
||||
pixel_x = 9
|
||||
},
|
||||
/obj/item/food/grown/tomato{
|
||||
pixel_y = 25
|
||||
},
|
||||
/obj/item/food/donut/plain{
|
||||
pixel_y = 16;
|
||||
pixel_x = 1
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
/area/ruin/space)
|
||||
"dI" = (
|
||||
/obj/item/food/meatball,
|
||||
/turf/open/misc/asteroid/airless,
|
||||
/area/ruin/space)
|
||||
"iE" = (
|
||||
/obj/structure/table,
|
||||
/obj/item/pai_card,
|
||||
@@ -239,6 +277,21 @@
|
||||
},
|
||||
/turf/open/misc/asteroid/airless,
|
||||
/area/ruin/space)
|
||||
"FZ" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/machinery/telecomms/server{
|
||||
pixel_y = 12;
|
||||
layer = 2.91;
|
||||
name = "tgsv3";
|
||||
desc = "It's, uh... pending an upgrade."
|
||||
},
|
||||
/obj/item/toy/plush/awakenedplushie{
|
||||
pixel_y = 27
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
/area/ruin/space)
|
||||
"Gf" = (
|
||||
/obj/effect/decal/remains/human,
|
||||
/obj/item/clothing/suit/space,
|
||||
@@ -317,7 +370,13 @@
|
||||
"XA" = (
|
||||
/obj/structure/fluff/bus/passable/seat,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/item/toy/plush/awakenedplushie,
|
||||
/obj/item/toy/singlecard{
|
||||
pixel_y = 25;
|
||||
pixel_x = 0
|
||||
},
|
||||
/obj/item/food/grown/potato{
|
||||
pixel_y = 15
|
||||
},
|
||||
/turf/open/floor/iron/dark/airless{
|
||||
icon_state = "bus"
|
||||
},
|
||||
@@ -379,10 +438,10 @@ ab
|
||||
yY
|
||||
Bw
|
||||
yY
|
||||
dI
|
||||
yY
|
||||
Ne
|
||||
aU
|
||||
az
|
||||
am
|
||||
aZ
|
||||
ER
|
||||
yY
|
||||
yY
|
||||
@@ -402,7 +461,7 @@ yY
|
||||
yY
|
||||
Ne
|
||||
am
|
||||
aZ
|
||||
ax
|
||||
Xj
|
||||
yY
|
||||
yY
|
||||
@@ -422,7 +481,7 @@ Bw
|
||||
yY
|
||||
Ne
|
||||
aV
|
||||
ba
|
||||
az
|
||||
IQ
|
||||
yY
|
||||
yY
|
||||
@@ -436,12 +495,12 @@ ab
|
||||
Gt
|
||||
yY
|
||||
Ne
|
||||
am
|
||||
FZ
|
||||
ax
|
||||
ER
|
||||
yY
|
||||
Ne
|
||||
aU
|
||||
am
|
||||
az
|
||||
KK
|
||||
yY
|
||||
@@ -496,7 +555,7 @@ ab
|
||||
ab
|
||||
yY
|
||||
Ne
|
||||
ao
|
||||
ba
|
||||
aA
|
||||
KK
|
||||
uO
|
||||
@@ -576,7 +635,7 @@ ab
|
||||
Ds
|
||||
yY
|
||||
Ne
|
||||
am
|
||||
aU
|
||||
aD
|
||||
KK
|
||||
yY
|
||||
@@ -601,7 +660,7 @@ aE
|
||||
ud
|
||||
yY
|
||||
yY
|
||||
dI
|
||||
yY
|
||||
yY
|
||||
aa
|
||||
aa
|
||||
@@ -697,7 +756,7 @@ ab
|
||||
ab
|
||||
ab
|
||||
ab
|
||||
ab
|
||||
ao
|
||||
yY
|
||||
yY
|
||||
yY
|
||||
|
||||
@@ -87,9 +87,7 @@
|
||||
/turf/open/floor/plating/airless,
|
||||
/area/ruin/space/has_grav)
|
||||
"O" = (
|
||||
/obj/machinery/power/apc/auto_name/directional/north{
|
||||
start_charge = 0
|
||||
},
|
||||
/obj/item/wallframe/apc,
|
||||
/turf/open/floor/plating/airless,
|
||||
/area/ruin/space/has_grav)
|
||||
"Q" = (
|
||||
|
||||
@@ -323,7 +323,7 @@
|
||||
"SL" = (
|
||||
/obj/effect/spawner/random/trash/mess,
|
||||
/obj/structure/cable,
|
||||
/obj/machinery/power/apc/auto_name/directional/west,
|
||||
/obj/item/wallframe/apc,
|
||||
/turf/open/floor/plating/airless,
|
||||
/area/ruin/space/has_grav)
|
||||
"SQ" = (
|
||||
|
||||
@@ -3998,9 +3998,7 @@
|
||||
/area/awaymission/black_mesa/security_outpost)
|
||||
"aYe" = (
|
||||
/obj/structure/rack/gunrack,
|
||||
/obj/item/gun/ballistic/revolver/mateba{
|
||||
fire_select_modes = list(1,2)
|
||||
},
|
||||
/obj/item/gun/ballistic/revolver/mateba,
|
||||
/obj/effect/mapping_helpers/broken_floor,
|
||||
/turf/open/floor/plating,
|
||||
/area/awaymission/black_mesa/security_outpost)
|
||||
@@ -5153,7 +5151,6 @@
|
||||
/obj/item/gun/ballistic/automatic/pistol/g17/mesa{
|
||||
burst_size = 3;
|
||||
desc = "A weapon from bygone times, and this is the exact 21st century version. In fact, even more reliable, but it also can run full automatic fire mode. Chambered in 9mm.";
|
||||
fire_select_modes = list(1,2,3);
|
||||
firing_burst = 1;
|
||||
name = "\improper Glock-18"
|
||||
},
|
||||
|
||||
@@ -7002,6 +7002,7 @@
|
||||
/obj/item/radio/headset/syndicate/alt,
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/obj/machinery/light/cold/directional/north,
|
||||
/obj/item/clothing/suit/armor/vest,
|
||||
/turf/open/floor/iron/dark/textured_large,
|
||||
/area/cruiser_dock)
|
||||
"hAW" = (
|
||||
@@ -7918,10 +7919,6 @@
|
||||
/obj/effect/turf_decal/tile/red/opposingcorners,
|
||||
/turf/open/floor/iron/dark,
|
||||
/area/centcom/interlink)
|
||||
"jUw" = (
|
||||
/obj/machinery/vending/cigarette,
|
||||
/turf/open/floor/iron/dark,
|
||||
/area/centcom/interlink)
|
||||
"jUK" = (
|
||||
/obj/machinery/door/airlock/medical/glass{
|
||||
name = "Interlink Medbay"
|
||||
@@ -11035,6 +11032,7 @@
|
||||
desc = "It's a personal storage unit for operative gear."
|
||||
},
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/obj/item/clothing/suit/armor/vest,
|
||||
/turf/open/floor/iron/dark/textured_large,
|
||||
/area/cruiser_dock)
|
||||
"rVP" = (
|
||||
@@ -11587,6 +11585,7 @@
|
||||
},
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/obj/machinery/light/cold/directional/south,
|
||||
/obj/item/clothing/suit/armor/vest,
|
||||
/turf/open/floor/iron/dark/textured_large,
|
||||
/area/cruiser_dock)
|
||||
"ttx" = (
|
||||
@@ -12398,6 +12397,7 @@
|
||||
},
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/obj/machinery/light/cold/directional/north,
|
||||
/obj/item/clothing/suit/armor/vest,
|
||||
/turf/open/floor/iron/dark/textured_large,
|
||||
/area/cruiser_dock)
|
||||
"vxh" = (
|
||||
@@ -27396,7 +27396,7 @@ aqG
|
||||
aqG
|
||||
aqG
|
||||
aDg
|
||||
jUw
|
||||
aXG
|
||||
jXO
|
||||
rDL
|
||||
hvQ
|
||||
|
||||
@@ -264,6 +264,7 @@
|
||||
"im" = (
|
||||
/obj/structure/table/optable,
|
||||
/obj/effect/turf_decal/bot,
|
||||
/obj/machinery/defibrillator_mount/directional/north,
|
||||
/turf/open/floor/iron/dark/textured_large,
|
||||
/area/shuttle/syndicate/cruiser/medical)
|
||||
"iU" = (
|
||||
@@ -662,8 +663,9 @@
|
||||
/area/shuttle/syndicate/cruiser/brig)
|
||||
"Iz" = (
|
||||
/obj/structure/rack/shelf,
|
||||
/obj/item/storage/backpack/duffelbag/syndie/surgery,
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/obj/item/defibrillator/loaded,
|
||||
/obj/item/storage/backpack/duffelbag/syndie/surgery,
|
||||
/turf/open/floor/iron/dark/textured_large,
|
||||
/area/shuttle/syndicate/cruiser/medical)
|
||||
"JA" = (
|
||||
@@ -755,8 +757,7 @@
|
||||
/area/shuttle/syndicate/cruiser/armory)
|
||||
"Pq" = (
|
||||
/obj/structure/table/reinforced,
|
||||
/obj/item/taperecorder,
|
||||
/obj/item/tape,
|
||||
/obj/machinery/recharger,
|
||||
/turf/open/floor/iron/dark/textured_large,
|
||||
/area/shuttle/syndicate/cruiser/bridge)
|
||||
"Py" = (
|
||||
|
||||
@@ -88,7 +88,6 @@
|
||||
dir = 1;
|
||||
piping_layer = 4
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/turf/open/floor/plating,
|
||||
/area/shuttle/abandoned)
|
||||
@@ -756,7 +755,6 @@
|
||||
/obj/effect/turf_decal/trimline/purple/filled/corner{
|
||||
dir = 1
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden,
|
||||
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
|
||||
/turf/open/floor/plating,
|
||||
/area/shuttle/abandoned)
|
||||
|
||||
@@ -186,13 +186,6 @@
|
||||
/obj/machinery/light/directional/east,
|
||||
/turf/open/floor/engine/cult,
|
||||
/area/centcom/wizard_station)
|
||||
"tv" = (
|
||||
/obj/effect/decal/cleanable/blood/splatter,
|
||||
/mob/living/simple_animal/hostile/netherworld{
|
||||
name = "Experiment 35b"
|
||||
},
|
||||
/turf/open/floor/grass,
|
||||
/area/centcom/wizard_station)
|
||||
"tz" = (
|
||||
/obj/structure/table/wood/fancy,
|
||||
/obj/item/camera/spooky,
|
||||
@@ -310,6 +303,14 @@
|
||||
/obj/machinery/light/small/directional/south,
|
||||
/turf/open/floor/iron,
|
||||
/area/centcom/wizard_station)
|
||||
"Iz" = (
|
||||
/obj/structure/table/wood,
|
||||
/obj/item/clothing/head/wizard/tape,
|
||||
/obj/item/clothing/suit/wizrobe/tape,
|
||||
/obj/item/staff/tape,
|
||||
/obj/item/stack/sticky_tape/super,
|
||||
/turf/open/floor/engine/cult,
|
||||
/area/centcom/wizard_station)
|
||||
"IZ" = (
|
||||
/obj/structure/chair/wood/wings{
|
||||
dir = 1
|
||||
@@ -388,6 +389,13 @@
|
||||
/obj/structure/chair/wood/wings,
|
||||
/turf/open/floor/carpet,
|
||||
/area/centcom/wizard_station)
|
||||
"QL" = (
|
||||
/obj/effect/decal/cleanable/blood/splatter,
|
||||
/mob/living/simple_animal/hostile/netherworld{
|
||||
name = "Experiment 35b"
|
||||
},
|
||||
/turf/open/floor/grass,
|
||||
/area/centcom/wizard_station)
|
||||
"RT" = (
|
||||
/obj/structure/table/wood/poker,
|
||||
/obj/item/toy/cards/deck/wizoff{
|
||||
@@ -1346,7 +1354,7 @@ qo
|
||||
iQ
|
||||
gC
|
||||
dp
|
||||
jp
|
||||
Iz
|
||||
hT
|
||||
hT
|
||||
OV
|
||||
@@ -1518,7 +1526,7 @@ lL
|
||||
cs
|
||||
nN
|
||||
kZ
|
||||
tv
|
||||
QL
|
||||
JN
|
||||
kZ
|
||||
cs
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
/obj/item/modular_computer/pda/cargo = list(REGION_SUPPLY), \
|
||||
/obj/item/modular_computer/pda/shaftminer = list(REGION_SUPPLY), \
|
||||
/obj/item/modular_computer/pda/chaplain = list(REGION_GENERAL), \
|
||||
/obj/item/modular_computer/pda/lawyer = list(REGION_GENERAL, REGION_SECURITY), \
|
||||
/obj/item/modular_computer/pda/lawyer = list(REGION_GENERAL), \
|
||||
/obj/item/modular_computer/pda/botanist = list(REGION_GENERAL), \
|
||||
/obj/item/modular_computer/pda/roboticist = list(REGION_RESEARCH), \
|
||||
/obj/item/modular_computer/pda/curator = list(REGION_GENERAL), \
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
#define GLOBAL_PROC "some_magic_bullshit"
|
||||
/// A shorthand for the callback datum, [documented here](datum/callback.html)
|
||||
#define CALLBACK new /datum/callback
|
||||
#define INVOKE_ASYNC world.ImmediateInvokeAsync
|
||||
|
||||
///Per the DM reference, spawn(-1) will execute the spawned code immediately until a block is met.
|
||||
#define MAKE_SPAWN_ACT_LIKE_WAITFOR -1
|
||||
///Create a codeblock that will not block the callstack if a block is met.
|
||||
#define ASYNC spawn(MAKE_SPAWN_ACT_LIKE_WAITFOR)
|
||||
|
||||
#define INVOKE_ASYNC(proc_owner, proc_path, proc_arguments...) \
|
||||
if ((proc_owner) == GLOBAL_PROC) { \
|
||||
ASYNC { \
|
||||
call(proc_path)(##proc_arguments); \
|
||||
}; \
|
||||
} \
|
||||
else { \
|
||||
ASYNC { \
|
||||
call(proc_owner, proc_path)(##proc_arguments); \
|
||||
}; \
|
||||
}
|
||||
|
||||
/// like CALLBACK but specifically for verb callbacks
|
||||
#define VERB_CALLBACK new /datum/callback/verb_callback
|
||||
|
||||
@@ -30,6 +30,13 @@
|
||||
#define COMPONENT_DUPE_ALLOWED 1
|
||||
/// new component is deleted
|
||||
#define COMPONENT_DUPE_UNIQUE 2
|
||||
/**
|
||||
* Component uses source tracking to manage adding and removal logic.
|
||||
* Add a source/spawn to/the component by using AddComponentFrom(source, component_type, args...)
|
||||
* Only the first args will be respected, and you should instead handle most of your logic in the on_source_added proc.
|
||||
* Removing the last source will automatically remove the component from the parent.
|
||||
*/
|
||||
#define COMPONENT_DUPE_SOURCES 3
|
||||
/// old component is given the initialization args of the new
|
||||
#define COMPONENT_DUPE_UNIQUE_PASSARGS 4
|
||||
/// each component of the same type is consulted as to whether the duplicate should be allowed
|
||||
|
||||
@@ -18,5 +18,9 @@
|
||||
/// A wrapper for _AddComponent that allows us to pretend we're using normal named arguments
|
||||
#define AddComponent(arguments...) _AddComponent(list(##arguments))
|
||||
|
||||
/// A wrapper for _AddComonent that passes in a source.
|
||||
/// Necessary if dupe_mode is set to COMPONENT_DUPE_SOURCES.
|
||||
#define AddComponentFrom(source, arguments...) _AddComponent(list(##arguments), source)
|
||||
|
||||
/// A wrapper for _LoadComponent that allows us to pretend we're using normal named arguments
|
||||
#define LoadComponent(arguments...) _LoadComponent(list(##arguments))
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
#define ROLE_SPIDER "Spider"
|
||||
#define ROLE_WIZARD_MIDROUND "Wizard (Midround)"
|
||||
//SKYRAT EDIT START
|
||||
#define ROLE_LONE_INFILTRATOR "Lone Infiltrator"
|
||||
#define ROLE_BORER "Borer"
|
||||
#define ROLE_DRIFTING_CONTRACTOR "Drifting Contractor"
|
||||
#define ROLE_LONE_INFILTRATOR "Lone Infiltrator"
|
||||
#define ROLE_MUTANT "Mutated Abomination"
|
||||
// SKYRAT EDIT END
|
||||
|
||||
@@ -107,7 +107,13 @@
|
||||
#define ROLE_BATTLECRUISER_CREW "Battlecruiser Crew"
|
||||
#define ROLE_BATTLECRUISER_CAPTAIN "Battlecruiser Captain"
|
||||
#define ROLE_VENUSHUMANTRAP "Venus Human Trap"
|
||||
|
||||
//SKYRAT EDIT START
|
||||
#define ROLE_BLACK_MARKET_DEALER "Black Market Dealer"
|
||||
#define ROLE_DS2 "DS2 Syndicate"
|
||||
#define ROLE_FREIGHTER_CREW "Freighter Crew"
|
||||
#define ROLE_GHOST_CAFE "Ghost Cafe Visitor"
|
||||
#define ROLE_PORT_TARKON "Port Tarkon Survivor"
|
||||
//SKYRAT EDIT END
|
||||
|
||||
/// This defines the antagonists you can operate with in the settings.
|
||||
/// Keys are the antagonist, values are the number of days since the player's
|
||||
|
||||
@@ -29,8 +29,11 @@
|
||||
//Launching Shuttles to CentCom
|
||||
#define NOLAUNCH -1
|
||||
#define UNLAUNCHED 0
|
||||
/// This shuttle launched to head to end game (or has arrived there), it will not update further
|
||||
#define ENDGAME_LAUNCHED 1
|
||||
#define EARLY_LAUNCHED 2
|
||||
/// "Endgame transit" denotes shuttles which "fly into the sunset" when the round ends, such as the whiteship.
|
||||
/// These shuttles leave when the main emergency shuttle does but don't dock anywhere (to save space), so this counts as "escaped".
|
||||
#define ENDGAME_TRANSIT 3
|
||||
|
||||
//positive value = cannot puchase
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
#define SSAIR_SUPERCONDUCTIVITY 7
|
||||
#define SSAIR_PROCESS_ATOMS 8
|
||||
|
||||
//Pipeline rebuild helper defines, these suck but it'll do for now //Fools you actually merged it
|
||||
// Pipeline rebuild helper defines, these suck but it'll do for now //Fools you actually merged it
|
||||
#define SSAIR_REBUILD_PIPELINE 1
|
||||
#define SSAIR_REBUILD_QUEUE 2
|
||||
|
||||
@@ -311,18 +311,18 @@
|
||||
#define SSWARDROBE_STOCK 1
|
||||
#define SSWARDROBE_INSPECT 2
|
||||
|
||||
//Wardrobe cache metadata indexes
|
||||
// Wardrobe cache metadata indexes
|
||||
#define WARDROBE_CACHE_COUNT 1
|
||||
#define WARDROBE_CACHE_LAST_INSPECT 2
|
||||
#define WARDROBE_CACHE_CALL_INSERT 3
|
||||
#define WARDROBE_CACHE_CALL_REMOVAL 4
|
||||
|
||||
//Wardrobe preloaded stock indexes
|
||||
// Wardrobe preloaded stock indexes
|
||||
#define WARDROBE_STOCK_CONTENTS 1
|
||||
#define WARDROBE_STOCK_CALL_INSERT 2
|
||||
#define WARDROBE_STOCK_CALL_REMOVAL 3
|
||||
|
||||
//Wardrobe callback master list indexes
|
||||
// Wardrobe callback master list indexes
|
||||
#define WARDROBE_CALLBACK_INSERT 1
|
||||
#define WARDROBE_CALLBACK_REMOVE 2
|
||||
|
||||
@@ -335,3 +335,9 @@
|
||||
|
||||
/// The timer key used to know how long subsystem initialization takes
|
||||
#define SS_INIT_TIMER_KEY "ss_init"
|
||||
|
||||
// Vote subsystem counting methods
|
||||
/// First past the post. One selection per person, and the selection with the most votes wins.
|
||||
#define VOTE_COUNT_METHOD_SINGLE 1
|
||||
/// Approval voting. Any number of selections per person, and the selection with the most votes wins.
|
||||
#define VOTE_COUNT_METHOD_MULTI 2
|
||||
|
||||
@@ -5,3 +5,8 @@
|
||||
#define DICE_BASICALLY_RIGGED 2
|
||||
/// Dice has a 100% chance to land on a rigged value
|
||||
#define DICE_TOTALLY_RIGGED 3
|
||||
|
||||
/// card is considered face down
|
||||
#define CARD_FACEDOWN 0
|
||||
/// card is considered face up
|
||||
#define CARD_FACEUP 1
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#define SELECT_SEMI_AUTOMATIC 1
|
||||
#define SELECT_BURST_SHOT 2
|
||||
#define SELECT_FULLY_AUTOMATIC 3
|
||||
|
||||
// Bitflags for what company produces the gun
|
||||
#define COMPANY_CANTALAN (1<<0)
|
||||
#define COMPANY_ARMADYNE (1<<1)
|
||||
|
||||
+21
-7
@@ -68,16 +68,30 @@
|
||||
return player_mob
|
||||
return null
|
||||
|
||||
///Returns true if the mob that a player is controlling is alive
|
||||
/**
|
||||
* Checks if the passed mind has a mob that is "alive"
|
||||
*
|
||||
* * player_mind - who to check for alive status
|
||||
* * enforce_human - if TRUE, the checks fails if the mind's mob is a silicon, brain, or infectious zombie.
|
||||
*
|
||||
* Returns TRUE if they're alive, FALSE otherwise
|
||||
*/
|
||||
/proc/considered_alive(datum/mind/player_mind, enforce_human = TRUE)
|
||||
if(player_mind?.current)
|
||||
if(enforce_human)
|
||||
var/mob/living/carbon/human/player_mob
|
||||
if(ishuman(player_mind.current))
|
||||
player_mob = player_mind.current
|
||||
return player_mind.current.stat != DEAD && !issilicon(player_mind.current) && !isbrain(player_mind.current) && (!player_mob || player_mob.dna.species.id != SPECIES_ZOMBIE)
|
||||
var/mob/living/carbon/human/player_mob = player_mind.current
|
||||
|
||||
if(player_mob.stat == DEAD)
|
||||
return FALSE
|
||||
if(issilicon(player_mob) || isbrain(player_mob))
|
||||
return FALSE
|
||||
if(istype(player_mob) && (player_mob.dna?.species?.id == SPECIES_ZOMBIE_INFECTIOUS))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
else if(isliving(player_mind.current))
|
||||
return player_mind.current.stat != DEAD
|
||||
return (player_mind.current.stat != DEAD)
|
||||
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
@@ -152,7 +166,7 @@
|
||||
flick_overlay(image_to_show, viewing, duration)
|
||||
|
||||
///Get active players who are playing in the round
|
||||
/proc/get_active_player_count(alive_check = 0, afk_check = 0, human_check = 0)
|
||||
/proc/get_active_player_count(alive_check = FALSE, afk_check = FALSE, human_check = FALSE)
|
||||
var/active_players = 0
|
||||
for(var/i = 1; i <= GLOB.player_list.len; i++)
|
||||
var/mob/player_mob = GLOB.player_list[i]
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
if(!didthegamerwin)
|
||||
return FALSE
|
||||
player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score * 2))
|
||||
else if(human_mob.onCentCom())
|
||||
else if(considered_escaped(human_mob))
|
||||
player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score))
|
||||
|
||||
|
||||
|
||||
@@ -533,7 +533,7 @@ SUBSYSTEM_DEF(job)
|
||||
|
||||
SEND_SIGNAL(equipping, COMSIG_JOB_RECEIVED, job)
|
||||
|
||||
equipping.mind?.set_assigned_role_with_greeting(job)
|
||||
equipping.mind?.set_assigned_role_with_greeting(job, player_client)
|
||||
if(player_client)
|
||||
to_chat(player_client, span_infoplain("You are the [chosen_title].")) // SKYRAT EDIT CHANGE - ALTERNATIVE_JOB_TITLES - Original: to_chat(player_client, span_infoplain("You are the [job.title]."))
|
||||
|
||||
|
||||
@@ -93,7 +93,10 @@ SUBSYSTEM_DEF(vote)
|
||||
if (final_winner) // if no one voted final_winner will be null
|
||||
current_vote.finalize_vote(final_winner)
|
||||
|
||||
/datum/controller/subsystem/vote/proc/submit_vote(mob/voter, their_vote)
|
||||
/**
|
||||
* One selection per person, and the selection with the most votes wins.
|
||||
*/
|
||||
/datum/controller/subsystem/vote/proc/submit_single_vote(mob/voter, their_vote)
|
||||
if(!current_vote)
|
||||
return
|
||||
if(!voter?.ckey)
|
||||
@@ -111,6 +114,31 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
current_vote.choices_by_ckey[voter.ckey] = their_vote
|
||||
current_vote.choices[their_vote]++
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Any number of selections per person, and the selection with the most votes wins.
|
||||
*/
|
||||
/datum/controller/subsystem/vote/proc/submit_multi_vote(mob/voter, their_vote)
|
||||
if(!current_vote)
|
||||
return
|
||||
if(!voter?.ckey)
|
||||
return
|
||||
if(CONFIG_GET(flag/no_dead_vote) && voter.stat == DEAD && !voter.client?.holder)
|
||||
return
|
||||
|
||||
else
|
||||
voted += voter.ckey
|
||||
|
||||
if(current_vote.choices_by_ckey[voter.ckey + their_vote] == 1)
|
||||
current_vote.choices_by_ckey[voter.ckey + their_vote] = 0
|
||||
current_vote.choices[their_vote]--
|
||||
|
||||
else
|
||||
current_vote.choices_by_ckey[voter.ckey + their_vote] = 1
|
||||
current_vote.choices[their_vote]++
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
@@ -217,10 +245,12 @@ SUBSYSTEM_DEF(vote)
|
||||
var/is_upper_admin = check_rights_for(user.client, R_ADMIN)
|
||||
|
||||
data["user"] = list(
|
||||
"ckey" = user.client?.ckey,
|
||||
"isLowerAdmin" = is_lower_admin,
|
||||
"isUpperAdmin" = is_upper_admin,
|
||||
// What the current user has selected in any ongoing votes.
|
||||
"selectedChoice" = current_vote?.choices_by_ckey[user.client?.ckey],
|
||||
"singleSelection" = current_vote?.choices_by_ckey[user.client?.ckey],
|
||||
"multiSelection" = current_vote?.choices_by_ckey,
|
||||
)
|
||||
|
||||
data["voting"]= is_lower_admin ? voting : list()
|
||||
@@ -250,6 +280,7 @@ SUBSYSTEM_DEF(vote)
|
||||
"name" = current_vote.name,
|
||||
"question" = current_vote.override_question,
|
||||
"timeRemaining" = current_vote.time_remaining,
|
||||
"countMethod" = current_vote.count_method,
|
||||
"choices" = choices,
|
||||
"vote" = vote_data,
|
||||
)
|
||||
@@ -293,8 +324,11 @@ SUBSYSTEM_DEF(vote)
|
||||
// meaning you can't spoof initiate a vote you're not supposed to be able to
|
||||
return initiate_vote(selected, voter.key, voter)
|
||||
|
||||
if("vote")
|
||||
return submit_vote(voter, params["voteOption"])
|
||||
if("voteSingle")
|
||||
return submit_single_vote(voter, params["voteOption"])
|
||||
|
||||
if("voteMulti")
|
||||
return submit_multi_vote(voter, params["voteOption"])
|
||||
|
||||
/datum/controller/subsystem/vote/ui_close(mob/user)
|
||||
voting -= user.client?.ckey
|
||||
|
||||
@@ -67,26 +67,6 @@
|
||||
arguments = args.Copy(3)
|
||||
if(usr)
|
||||
user = WEAKREF(usr)
|
||||
/**
|
||||
* Immediately Invoke proctocall on thingtocall, with waitfor set to false
|
||||
*
|
||||
* Arguments:
|
||||
* * thingtocall Object to call on
|
||||
* * proctocall Proc to call on that object
|
||||
* * ... optional list of arguments to pass as arguments to the proc being called
|
||||
*/
|
||||
/world/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...)
|
||||
set waitfor = FALSE
|
||||
|
||||
if (!thingtocall)
|
||||
return
|
||||
|
||||
var/list/calling_arguments = length(args) > 2 ? args.Copy(3) : null
|
||||
|
||||
if (thingtocall == GLOBAL_PROC)
|
||||
call(proctocall)(arglist(calling_arguments))
|
||||
else
|
||||
call(thingtocall, proctocall)(arglist(calling_arguments))
|
||||
|
||||
/**
|
||||
* Invoke this callback
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
*/
|
||||
var/can_transfer = FALSE
|
||||
|
||||
/// A lazy list of the sources for this component
|
||||
var/list/sources
|
||||
|
||||
/**
|
||||
* Create a new component.
|
||||
*
|
||||
@@ -165,6 +168,27 @@
|
||||
/datum/component/proc/UnregisterFromParent()
|
||||
return
|
||||
|
||||
/**
|
||||
* Called when the component has a new source registered
|
||||
*/
|
||||
/datum/component/proc/on_source_add(source)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(dupe_mode != COMPONENT_DUPE_SOURCES)
|
||||
CRASH("Component '[type]' does not use sources but has been given a source")
|
||||
LAZYOR(sources, source)
|
||||
|
||||
/**
|
||||
* Called when the component has a source removed.
|
||||
* You probably want to call parent after you do your logic because at the end of this we qdel if we have no sources remaining!
|
||||
*/
|
||||
/datum/component/proc/on_source_remove(source)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(dupe_mode != COMPONENT_DUPE_SOURCES)
|
||||
CRASH("Component '[type]' does not use sources but is trying to remove a source")
|
||||
LAZYREMOVE(sources, source)
|
||||
if(!LAZYLEN(sources))
|
||||
qdel(src)
|
||||
|
||||
/**
|
||||
* Register to listen for a signal from the passed in target
|
||||
*
|
||||
@@ -411,74 +435,100 @@
|
||||
*
|
||||
* Properly handles duplicate situations based on the `dupe_mode` var
|
||||
*/
|
||||
/datum/proc/_AddComponent(list/raw_args)
|
||||
var/new_type = raw_args[1]
|
||||
var/datum/component/nt = new_type
|
||||
/datum/proc/_AddComponent(list/raw_args, source)
|
||||
var/original_type = raw_args[1]
|
||||
var/datum/component/component_type = original_type
|
||||
|
||||
if(QDELING(src))
|
||||
CRASH("Attempted to add a new component of type \[[nt]\] to a qdeleting parent of type \[[type]\]!")
|
||||
CRASH("Attempted to add a new component of type \[[component_type]\] to a qdeleting parent of type \[[type]\]!")
|
||||
|
||||
var/dm = initial(nt.dupe_mode)
|
||||
var/dt = initial(nt.dupe_type)
|
||||
var/dupe_mode = initial(component_type.dupe_mode)
|
||||
var/dupe_type = initial(component_type.dupe_type)
|
||||
var/uses_sources = (dupe_mode == COMPONENT_DUPE_SOURCES)
|
||||
if(uses_sources && !source)
|
||||
CRASH("Attempted to add a sourced component of type '[component_type]' to '[type]' without a source!")
|
||||
else if(!uses_sources && source)
|
||||
CRASH("Attempted to add a normal component of type '[component_type]' to '[type]' with a source!")
|
||||
|
||||
var/datum/component/old_comp
|
||||
var/datum/component/new_comp
|
||||
var/datum/component/old_component
|
||||
var/datum/component/new_component
|
||||
|
||||
if(ispath(nt))
|
||||
if(nt == /datum/component)
|
||||
CRASH("[nt] attempted instantiation!")
|
||||
if(ispath(component_type))
|
||||
if(component_type == /datum/component)
|
||||
CRASH("[component_type] attempted instantiation!")
|
||||
else
|
||||
new_comp = nt
|
||||
nt = new_comp.type
|
||||
new_component = component_type
|
||||
component_type = new_component.type
|
||||
|
||||
raw_args[1] = src
|
||||
|
||||
if(dm != COMPONENT_DUPE_ALLOWED && dm != COMPONENT_DUPE_SELECTIVE)
|
||||
if(!dt)
|
||||
old_comp = GetExactComponent(nt)
|
||||
if(dupe_mode != COMPONENT_DUPE_ALLOWED && dupe_mode != COMPONENT_DUPE_SELECTIVE)
|
||||
if(!dupe_type)
|
||||
old_component = GetExactComponent(component_type)
|
||||
else
|
||||
old_comp = GetComponent(dt)
|
||||
if(old_comp)
|
||||
switch(dm)
|
||||
old_component = GetComponent(dupe_type)
|
||||
|
||||
if(old_component)
|
||||
switch(dupe_mode)
|
||||
if(COMPONENT_DUPE_UNIQUE)
|
||||
if(!new_comp)
|
||||
new_comp = new nt(raw_args)
|
||||
if(!QDELETED(new_comp))
|
||||
old_comp.InheritComponent(new_comp, TRUE)
|
||||
QDEL_NULL(new_comp)
|
||||
if(!new_component)
|
||||
new_component = new component_type(raw_args)
|
||||
if(!QDELETED(new_component))
|
||||
old_component.InheritComponent(new_component, TRUE)
|
||||
QDEL_NULL(new_component)
|
||||
|
||||
if(COMPONENT_DUPE_HIGHLANDER)
|
||||
if(!new_comp)
|
||||
new_comp = new nt(raw_args)
|
||||
if(!QDELETED(new_comp))
|
||||
new_comp.InheritComponent(old_comp, FALSE)
|
||||
QDEL_NULL(old_comp)
|
||||
if(!new_component)
|
||||
new_component = new component_type(raw_args)
|
||||
if(!QDELETED(new_component))
|
||||
new_component.InheritComponent(old_component, FALSE)
|
||||
QDEL_NULL(old_component)
|
||||
|
||||
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
|
||||
if(!new_comp)
|
||||
if(!new_component)
|
||||
var/list/arguments = raw_args.Copy(2)
|
||||
arguments.Insert(1, null, TRUE)
|
||||
old_comp.InheritComponent(arglist(arguments))
|
||||
old_component.InheritComponent(arglist(arguments))
|
||||
else
|
||||
old_comp.InheritComponent(new_comp, TRUE)
|
||||
else if(!new_comp)
|
||||
new_comp = new nt(raw_args) // There's a valid dupe mode but there's no old component, act like normal
|
||||
else if(dm == COMPONENT_DUPE_SELECTIVE)
|
||||
old_component.InheritComponent(new_component, TRUE)
|
||||
|
||||
if(COMPONENT_DUPE_SOURCES)
|
||||
if(source in old_component.sources)
|
||||
return old_component // source already registered, no work to do
|
||||
old_component.on_source_add(source)
|
||||
|
||||
else if(!new_component)
|
||||
new_component = new component_type(raw_args) // There's a valid dupe mode but there's no old component, act like normal
|
||||
else if(dupe_mode == COMPONENT_DUPE_SELECTIVE)
|
||||
var/list/arguments = raw_args.Copy()
|
||||
arguments[1] = new_comp
|
||||
arguments[1] = new_component
|
||||
var/make_new_component = TRUE
|
||||
for(var/datum/component/existing_component as anything in GetComponents(new_type))
|
||||
for(var/datum/component/existing_component as anything in GetComponents(original_type))
|
||||
if(existing_component.CheckDupeComponent(arglist(arguments)))
|
||||
make_new_component = FALSE
|
||||
QDEL_NULL(new_comp)
|
||||
QDEL_NULL(new_component)
|
||||
break
|
||||
if(!new_comp && make_new_component)
|
||||
new_comp = new nt(raw_args)
|
||||
else if(!new_comp)
|
||||
new_comp = new nt(raw_args) // Dupes are allowed, act like normal
|
||||
if(!new_component && make_new_component)
|
||||
new_component = new component_type(raw_args)
|
||||
else if(!new_component)
|
||||
new_component = new component_type(raw_args) // Dupes are allowed, act like normal
|
||||
|
||||
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
|
||||
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
|
||||
return new_comp
|
||||
return old_comp
|
||||
if(!old_component && !QDELETED(new_component)) // Nothing related to duplicate components happened and the new component is healthy
|
||||
if(uses_sources) // make sure they have the source added if they use sources
|
||||
new_component.on_source_add(source)
|
||||
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_component)
|
||||
return new_component
|
||||
|
||||
return old_component
|
||||
|
||||
/**
|
||||
* Removes a component source from this datum
|
||||
*/
|
||||
/datum/proc/RemoveComponentSource(source, datum/component/component_type)
|
||||
if(ispath(component_type))
|
||||
component_type = GetExactComponent(component_type)
|
||||
if(!component_type)
|
||||
CRASH("Attempted to remove a null or non-existent component '[component_type]' from '[type]'")
|
||||
component_type.on_source_remove(source)
|
||||
|
||||
/**
|
||||
* Get existing component of type, or create it and return a reference to it
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
if(!istype(parent, /datum/action))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
ASSERT(isnull(item) || istype(item))
|
||||
|
||||
if(!item && !item_callback)
|
||||
stack_trace("[type] created without a reference item or an item callback - one or the other is required.")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
@@ -48,13 +50,17 @@
|
||||
SIGNAL_HANDLER
|
||||
|
||||
// We're in the middle of being removed / deleted, remove our associated overlay
|
||||
if(QDELING(src) && item_appearance)
|
||||
current_button.cut_overlay(item_appearance)
|
||||
item_appearance = null
|
||||
if(QDELING(src))
|
||||
if(item_appearance)
|
||||
current_button.cut_overlay(item_appearance)
|
||||
item_appearance = null
|
||||
return
|
||||
|
||||
var/atom/movable/muse = item_callback?.Invoke() || item_ref?.resolve()
|
||||
if(!istype(muse))
|
||||
if(item_appearance) // New item does not exist but we have an old appearance
|
||||
current_button.cut_overlay(item_appearance)
|
||||
item_appearance = null
|
||||
return
|
||||
|
||||
if(item_appearance)
|
||||
|
||||
@@ -33,8 +33,9 @@
|
||||
|
||||
/datum/component/construction/proc/action(datum/source, obj/item/I, mob/living/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
return INVOKE_ASYNC(src, PROC_REF(check_step), I, user)
|
||||
ASYNC //This proc will never actually sleep, it calls do_after with a time of 0.
|
||||
. = check_step(I, user)
|
||||
return .
|
||||
|
||||
/datum/component/construction/proc/update_index(diff)
|
||||
index += diff
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
// This works even with the species picks since we're only accessing the name
|
||||
|
||||
var/obj/item/master = comp.parent
|
||||
master.AddElement(/datum/element/bane, picked_mobtype)
|
||||
master.AddElement(/datum/element/bane, target_type = picked_mobtype)
|
||||
target_types_by_comp[comp] = picked_mobtype
|
||||
return "[newName] of [initial(picked_mobtype.name)] slaying"
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* ### A fertile egg component!
|
||||
*
|
||||
* This component tracks over time if the atom is in ideal conditions,
|
||||
* and eventually hatches into the embryonic type.
|
||||
*
|
||||
* The initial design of this component was to make more generic the code for
|
||||
* chickens laying eggs.
|
||||
*/
|
||||
/datum/component/fertile_egg
|
||||
/// What will come out of the egg when it's done.
|
||||
var/embryo_type
|
||||
|
||||
/// Minimum growth rate per tick
|
||||
var/minimum_growth_rate
|
||||
|
||||
/// Maximum growth rate per tick
|
||||
var/maximum_growth_rate
|
||||
|
||||
/// Total growth required before hatching.
|
||||
var/total_growth_required
|
||||
|
||||
/// The current amount of growth.
|
||||
var/current_growth
|
||||
|
||||
/// List of locations which, if set, the egg will only develop if in those locations.
|
||||
var/list/location_allowlist
|
||||
|
||||
/// If true, being in an unsuitable location spoils the egg (ie. kills the component). If false, it just pauses the egg's development.
|
||||
var/spoilable
|
||||
|
||||
/datum/component/fertile_egg/Initialize(embryo_type, minimum_growth_rate, maximum_growth_rate, total_growth_required, current_growth, location_allowlist, spoilable, examine_message)
|
||||
// Quite how an _area_ can be a fertile egg is an open question, but it still has a location. Technically.
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.embryo_type = embryo_type
|
||||
src.minimum_growth_rate = minimum_growth_rate
|
||||
src.maximum_growth_rate = maximum_growth_rate
|
||||
src.total_growth_required = total_growth_required
|
||||
src.current_growth = current_growth
|
||||
src.location_allowlist = location_allowlist
|
||||
src.spoilable = spoilable
|
||||
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/component/fertile_egg/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/datum/component/fertile_egg/process(delta_time)
|
||||
var/atom/parent_atom = parent
|
||||
|
||||
if(location_allowlist && !is_type_in_typecache(parent_atom.loc, location_allowlist))
|
||||
// In a zone that is not allowed, do nothing, and possibly self destruct
|
||||
if(spoilable)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
current_growth += rand(minimum_growth_rate, maximum_growth_rate) * delta_time
|
||||
if(current_growth >= total_growth_required)
|
||||
parent_atom.visible_message(span_notice("[parent] hatches with a quiet cracking sound."))
|
||||
new embryo_type(get_turf(parent_atom))
|
||||
// We destroy the parent on hatch, which will destroy the component as well, which will stop us processing.
|
||||
qdel(parent_atom)
|
||||
@@ -1,4 +1,3 @@
|
||||
/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR FULLAUTO.DM
|
||||
#define AUTOFIRE_MOUSEUP 0
|
||||
#define AUTOFIRE_MOUSEDOWN 1
|
||||
|
||||
@@ -313,4 +312,3 @@
|
||||
|
||||
#undef AUTOFIRE_MOUSEUP
|
||||
#undef AUTOFIRE_MOUSEDOWN
|
||||
*/
|
||||
|
||||
@@ -121,7 +121,10 @@
|
||||
holochange.name = "[holochange.credits] credit holochip"
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/paying_customer = user
|
||||
if(!INVOKE_ASYNC(paying_customer, TYPE_PROC_REF(/mob, put_in_hands), holochange))
|
||||
var/successfully_put_in_hands
|
||||
ASYNC //Put_in_hands can sleep, we don't want that to block this proc.
|
||||
successfully_put_in_hands = paying_customer.put_in_hands(holochange)
|
||||
if(!successfully_put_in_hands)
|
||||
user.pulling = holochange
|
||||
else
|
||||
user.pulling = holochange
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
var/clumsy_check
|
||||
/// If we get sharpened with a whetstone, save the bonus here for later use if we un/redeploy
|
||||
var/sharpened_bonus = 0
|
||||
/// Dictate whether we change inhands or not
|
||||
var/inhand_icon_change
|
||||
/// Cooldown in between transforms
|
||||
COOLDOWN_DECLARE(transform_cooldown)
|
||||
|
||||
@@ -51,6 +53,7 @@
|
||||
clumsy_check = TRUE,
|
||||
list/attack_verb_continuous_on,
|
||||
list/attack_verb_simple_on,
|
||||
inhand_icon_change = TRUE,
|
||||
)
|
||||
|
||||
if(!isitem(parent))
|
||||
@@ -66,6 +69,7 @@
|
||||
src.hitsound_on = hitsound_on
|
||||
src.w_class_on = w_class_on
|
||||
src.clumsy_check = clumsy_check
|
||||
src.inhand_icon_change = inhand_icon_change
|
||||
|
||||
if(attack_verb_continuous_on)
|
||||
src.attack_verb_continuous_on = attack_verb_continuous_on
|
||||
@@ -188,7 +192,8 @@
|
||||
source.hitsound = hitsound_on
|
||||
source.w_class = w_class_on
|
||||
source.icon_state = "[source.icon_state]_on"
|
||||
source.inhand_icon_state = "[source.inhand_icon_state]_on"
|
||||
if(inhand_icon_change && source.inhand_icon_state)
|
||||
source.inhand_icon_state = "[source.inhand_icon_state]_on"
|
||||
if(ismob(source.loc))
|
||||
var/mob/loc_mob = source.loc
|
||||
loc_mob.update_held_items()
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
/// Deals extra damage to mobs of a certain type or species.
|
||||
/// Deals extra damage to mobs of a certain type, species, or biotype.
|
||||
/// This doesn't directly modify the normal damage of the weapon, instead it applies it's own damage seperatedly ON TOP of normal damage
|
||||
/// ie. a sword that does 10 damage with a bane elment attacthed that has a 0.5 damage_multiplier will do:
|
||||
/// 10 damage from the swords normal attack + 5 damage (50%) from the bane element
|
||||
/datum/element/bane
|
||||
element_flags = ELEMENT_BESPOKE
|
||||
argument_hash_start_idx = 2
|
||||
@@ -10,8 +13,10 @@
|
||||
var/added_damage
|
||||
/// If it requires combat mode on to deal the extra damage or not.
|
||||
var/requires_combat_mode
|
||||
/// if we want it to only affect a certain mob biotype
|
||||
var/mob_biotypes
|
||||
|
||||
/datum/element/bane/Attach(datum/target, target_type, damage_multiplier=1, added_damage = 0, requires_combat_mode = TRUE)
|
||||
/datum/element/bane/Attach(datum/target, target_type = /mob/living, mob_biotypes = NONE, damage_multiplier=1, added_damage = 0, requires_combat_mode = TRUE)
|
||||
. = ..()
|
||||
if(!isitem(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
@@ -27,23 +32,34 @@
|
||||
src.damage_multiplier = damage_multiplier
|
||||
src.added_damage = added_damage
|
||||
src.requires_combat_mode = requires_combat_mode
|
||||
src.mob_biotypes = mob_biotypes
|
||||
|
||||
/datum/element/bane/Detach(datum/source)
|
||||
UnregisterSignal(source, COMSIG_ITEM_AFTERATTACK)
|
||||
return ..()
|
||||
|
||||
/datum/element/bane/proc/species_check(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
|
||||
/datum/element/bane/proc/species_check(obj/item/source, mob/living/target, mob/user, proximity_flag, click_parameters)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!proximity_flag || !is_species(target, target_type))
|
||||
if(!proximity_flag || !istype(target) || !is_species(target, target_type))
|
||||
return
|
||||
|
||||
var/is_correct_biotype = target.mob_biotypes & mob_biotypes
|
||||
if(mob_biotypes && !(is_correct_biotype))
|
||||
return
|
||||
|
||||
activate(source, target, user)
|
||||
|
||||
/datum/element/bane/proc/mob_check(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
|
||||
/datum/element/bane/proc/mob_check(obj/item/source, mob/living/target, mob/user, proximity_flag, click_parameters)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!proximity_flag || !istype(target, target_type))
|
||||
return
|
||||
|
||||
var/is_correct_biotype = target.mob_biotypes & mob_biotypes
|
||||
if(mob_biotypes && !(is_correct_biotype))
|
||||
return
|
||||
|
||||
activate(source, target, user)
|
||||
|
||||
/datum/element/bane/proc/activate(obj/item/source, mob/living/target, mob/living/attacker)
|
||||
|
||||
@@ -30,7 +30,15 @@
|
||||
|
||||
/datum/element/food_trash/Detach(datum/target)
|
||||
. = ..()
|
||||
UnregisterSignal(target, COMSIG_FOOD_CONSUMED)
|
||||
UnregisterSignal(target, list(
|
||||
COMSIG_FOOD_CONSUMED,
|
||||
COMSIG_ITEM_ATTACK_SELF,
|
||||
COMSIG_FOOD_CROSSED,
|
||||
COMSIG_ITEM_ON_GRIND,
|
||||
COMSIG_ITEM_ON_JUICE,
|
||||
COMSIG_ITEM_USED_AS_INGREDIENT,
|
||||
COMSIG_ITEM_ON_COMPOSTED,
|
||||
COMSIG_ITEM_SOLD_TO_CUSTOMER,))
|
||||
|
||||
/datum/element/food_trash/proc/generate_trash(datum/source, mob/living/eater, mob/living/feeder)
|
||||
SIGNAL_HANDLER
|
||||
@@ -48,6 +56,8 @@
|
||||
food_holding_mob.dropItemToGround(edible_object)
|
||||
food_holding_mob.put_in_hands(trash_item)
|
||||
|
||||
Detach(source)
|
||||
|
||||
/datum/element/food_trash/proc/food_crossed(datum/source, mob/crosser, bitecount)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
|
||||
SIGNAL_HANDLER
|
||||
var/obj/obj_target = target
|
||||
obj_target.visible_message(span_danger("[obj_target] shatters into a million pieces!"))
|
||||
qdel(obj_target)
|
||||
obj_target.flags_1 |= NODECONSTRUCT_1 // disable item spawning
|
||||
obj_target.deconstruct(FALSE) // call pre-deletion specialized code -- internals release gas etc
|
||||
|
||||
/// signal handler for COMSIG_MOVABLE_MOVED that unfreezes our target if it moves onto an open turf thats hotter than
|
||||
/// our melting temperature.
|
||||
|
||||
@@ -96,12 +96,9 @@ GLOBAL_LIST_EMPTY(pillars_by_z)
|
||||
/// Displays a turf from the z level below us on our level
|
||||
/datum/z_pillar/proc/display_turf(turf/to_display, turf/source)
|
||||
var/list/sources = turf_sources[to_display]
|
||||
if(!sources)
|
||||
sources = list()
|
||||
turf_sources[to_display] = sources
|
||||
sources |= source
|
||||
|
||||
if(length(sources) != 1) // If we aren't the first to request this turf, return
|
||||
if(sources) // If we aren't the first to request this turf, return
|
||||
sources |= source
|
||||
var/obj/effect/abstract/z_holder/holding = drawing_object[to_display]
|
||||
if(!holding)
|
||||
return
|
||||
@@ -118,6 +115,11 @@ GLOBAL_LIST_EMPTY(pillars_by_z)
|
||||
visual_target.vis_contents += to_display
|
||||
return
|
||||
|
||||
// Otherwise, we need to create a new set of sources. let's do that yeah?
|
||||
sources = list()
|
||||
turf_sources[to_display] = sources
|
||||
sources |= source
|
||||
|
||||
var/turf/visual_target = to_display.above()
|
||||
if(istransparentturf(visual_target) || isopenspaceturf(visual_target))
|
||||
visual_target.vis_contents += to_display
|
||||
|
||||
@@ -511,16 +511,16 @@
|
||||
/// Sets us to the passed job datum, then greets them to their new job.
|
||||
/// Use this one for when you're assigning this mind to a new job for the first time,
|
||||
/// or for when someone's recieving a job they'd really want to be greeted to.
|
||||
/datum/mind/proc/set_assigned_role_with_greeting(datum/job/new_role)
|
||||
/datum/mind/proc/set_assigned_role_with_greeting(datum/job/new_role, client/incoming_client)
|
||||
. = set_assigned_role(new_role)
|
||||
if(!.)
|
||||
if(assigned_role != new_role)
|
||||
return
|
||||
|
||||
to_chat(src, span_infoplain("<b>You are the [new_role.title].</b>"))
|
||||
to_chat(incoming_client || src, span_infoplain("<b>You are the [new_role.title].</b>"))
|
||||
|
||||
var/related_policy = get_policy(new_role.title)
|
||||
if(related_policy)
|
||||
to_chat(src, related_policy)
|
||||
to_chat(incoming_client || src, related_policy)
|
||||
|
||||
/mob/proc/sync_mind()
|
||||
mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist)
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
var/started_time
|
||||
/// The time remaining in this vote's run.
|
||||
var/time_remaining
|
||||
/// The counting method we use for votes.
|
||||
var/count_method = VOTE_COUNT_METHOD_SINGLE
|
||||
|
||||
/**
|
||||
* Used to determine if this vote is a possible
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
/// The max amount of options someone can have in a custom vote.
|
||||
#define MAX_CUSTOM_VOTE_OPTIONS 10
|
||||
|
||||
/datum/vote/custom_vote
|
||||
name = "Custom"
|
||||
message = "Click here to start a custom vote."
|
||||
/datum/vote/custom_vote/single
|
||||
name = "Custom Standard"
|
||||
message = "Click here to start a custom vote (one selection per voter)"
|
||||
|
||||
/datum/vote/custom_vote/multi
|
||||
name = "Custom Multi"
|
||||
message = "Click here to start a custom multi vote (multiple selections per voter)"
|
||||
count_method = VOTE_COUNT_METHOD_MULTI
|
||||
|
||||
// Custom votes ares always accessible.
|
||||
/datum/vote/custom_vote/is_accessible_vote()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/vote/map_vote
|
||||
name = "Map"
|
||||
message = "Vote for next round's map!"
|
||||
count_method = VOTE_COUNT_METHOD_MULTI
|
||||
|
||||
/datum/vote/map_vote/New()
|
||||
. = ..()
|
||||
@@ -73,12 +74,14 @@
|
||||
for(var/key in default_choices)
|
||||
choices[key] = 0
|
||||
|
||||
var/active_players = get_active_player_count(alive_check = FALSE, afk_check = TRUE, human_check = FALSE)
|
||||
|
||||
for(var/map in choices)
|
||||
var/datum/map_config/possible_config = config.maplist[map]
|
||||
if(possible_config.config_min_users > 0 && GLOB.clients.len < possible_config.config_min_users)
|
||||
if(possible_config.config_min_users > 0 && active_players < possible_config.config_min_users)
|
||||
choices -= map
|
||||
|
||||
else if(possible_config.config_max_users > 0 && GLOB.clients.len > possible_config.config_max_users)
|
||||
else if(possible_config.config_max_users > 0 && active_players > possible_config.config_max_users)
|
||||
choices -= map
|
||||
|
||||
return choices
|
||||
|
||||
+46
-21
@@ -409,42 +409,36 @@
|
||||
return !density
|
||||
|
||||
/**
|
||||
* Is this atom currently located on centcom
|
||||
* Is this atom currently located on centcom (or riding off into the sunset on a shuttle)
|
||||
*
|
||||
* Specifically, is it on the z level and within the centcom areas
|
||||
*
|
||||
* You can also be in a shuttleshuttle during endgame transit
|
||||
* Specifically, is it on the z level and within the centcom areas.
|
||||
* You can also be in a shuttle during endgame transit.
|
||||
*
|
||||
* Used in gamemode to identify mobs who have escaped and for some other areas of the code
|
||||
* who don't want atoms where they shouldn't be
|
||||
*
|
||||
* Returns TRUE if this atom is on centcom or an escape shuttle, or FALSE if not
|
||||
*/
|
||||
/atom/proc/onCentCom()
|
||||
var/turf/current_turf = get_turf(src)
|
||||
if(!current_turf)
|
||||
return FALSE
|
||||
|
||||
// This doesn't necessarily check that we're at central command,
|
||||
// but it checks for any shuttles which have finished are still in hyperspace
|
||||
// (IE, stuff like the whiteship which fly off into the sunset and "escape")
|
||||
if(is_reserved_level(current_turf.z))
|
||||
for(var/obj/docking_port/mobile/mobile_docking_port as anything in SSshuttle.mobile_docking_ports)
|
||||
if(mobile_docking_port.launch_status != ENDGAME_TRANSIT)
|
||||
continue
|
||||
for(var/area/shuttle/shuttle_area as anything in mobile_docking_port.shuttle_areas)
|
||||
if(current_turf in shuttle_area)
|
||||
return TRUE
|
||||
return on_escaped_shuttle(ENDGAME_TRANSIT)
|
||||
|
||||
if(!is_centcom_level(current_turf.z))//if not, don't bother
|
||||
// From here on we only concern ourselves with people actually on the centcom Z
|
||||
if(!is_centcom_level(current_turf.z))
|
||||
return FALSE
|
||||
|
||||
//Check for centcom itself
|
||||
if(istype(current_turf.loc, /area/centcom))
|
||||
return TRUE
|
||||
|
||||
//Check for centcom shuttles
|
||||
for(var/obj/docking_port/mobile/mobile_docking_port as anything in SSshuttle.mobile_docking_ports)
|
||||
if(mobile_docking_port.launch_status == ENDGAME_LAUNCHED)
|
||||
for(var/place as anything in mobile_docking_port.shuttle_areas)
|
||||
var/area/shuttle/shuttle_area = place
|
||||
if(current_turf in shuttle_area)
|
||||
return TRUE
|
||||
// Finally, check if we're on an escaped shuttle
|
||||
return on_escaped_shuttle()
|
||||
|
||||
/**
|
||||
* Is the atom in any of the syndicate areas
|
||||
@@ -452,18 +446,49 @@
|
||||
* Either in the syndie base, or any of their shuttles
|
||||
*
|
||||
* Also used in gamemode code for win conditions
|
||||
*
|
||||
* Returns TRUE if this atom is on the syndicate recon base, any of its shuttles, or an escape shuttle, or FALSE if not
|
||||
*/
|
||||
/atom/proc/onSyndieBase()
|
||||
var/turf/current_turf = get_turf(src)
|
||||
if(!current_turf)
|
||||
return FALSE
|
||||
|
||||
if(!is_reserved_level(current_turf.z))//if not, don't bother
|
||||
// Syndicate base is loaded in a reserved level. If not reserved, we don't care.
|
||||
if(!is_reserved_level(current_turf.z))
|
||||
return FALSE
|
||||
|
||||
if(istype(current_turf.loc, /area/shuttle/syndicate) || istype(current_turf.loc, /area/centcom/syndicate_mothership) || istype(current_turf.loc, /area/shuttle/assault_pod))
|
||||
var/static/list/syndie_typecache = typecacheof(list(
|
||||
/area/centcom/syndicate_mothership, // syndicate base itself
|
||||
/area/shuttle/assault_pod, // steel rain
|
||||
/area/shuttle/syndicate, // infiltrator
|
||||
))
|
||||
|
||||
if(is_type_in_typecache(current_turf.loc, syndie_typecache))
|
||||
return TRUE
|
||||
|
||||
// Finally, check if we're on an escaped shuttle
|
||||
return on_escaped_shuttle()
|
||||
|
||||
/**
|
||||
* Checks that we're on a shuttle that's escaped
|
||||
*
|
||||
* * check_for_launch_status - What launch status do we check for? Generally the two you want to check for are ENDGAME_LAUNCHED or ENDGAME_TRANSIT
|
||||
*
|
||||
* Returns TRUE if this atom is on a shuttle which is escaping or has escaped, or FALSE otherwise
|
||||
*/
|
||||
/atom/proc/on_escaped_shuttle(check_for_launch_status = ENDGAME_LAUNCHED)
|
||||
var/turf/current_turf = get_turf(src)
|
||||
if(!current_turf)
|
||||
return FALSE
|
||||
|
||||
for(var/obj/docking_port/mobile/mobile_docking_port as anything in SSshuttle.mobile_docking_ports)
|
||||
if(mobile_docking_port.launch_status != check_for_launch_status)
|
||||
continue
|
||||
for(var/area/shuttle/shuttle_area as anything in mobile_docking_port.shuttle_areas)
|
||||
if(current_turf in shuttle_area.get_contained_turfs())
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
)
|
||||
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
|
||||
required_candidates = 1
|
||||
weight = 7
|
||||
weight = 11
|
||||
cost = 5
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
repeatable = TRUE
|
||||
@@ -127,7 +127,7 @@
|
||||
)
|
||||
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
|
||||
required_candidates = 1
|
||||
weight = 2
|
||||
weight = 1
|
||||
delay = 1 MINUTES // Prevents rule start while head is offstation.
|
||||
cost = 10
|
||||
requirements = list(101,101,70,40,30,20,20,20,20,20)
|
||||
@@ -220,7 +220,7 @@
|
||||
)
|
||||
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
weight = 8
|
||||
cost = 6
|
||||
requirements = list(101,101,50,10,10,10,10,10,10,10)
|
||||
repeatable = TRUE
|
||||
|
||||
@@ -67,22 +67,31 @@ GLOBAL_LIST_EMPTY(objectives) //SKYRAT EDIT ADDITION
|
||||
* Escaped mobs are used to check certain antag objectives / results.
|
||||
*
|
||||
* Escaped includes minds with alive, non-exiled mobs generally.
|
||||
*
|
||||
* Returns TRUE if they're a free person, or FALSE if they failed
|
||||
*/
|
||||
/proc/considered_escaped(datum/mind/escapee)
|
||||
if(!considered_alive(escapee))
|
||||
return FALSE
|
||||
if(considered_exiled(escapee))
|
||||
return FALSE
|
||||
// "Into the sunset" force escaping for forced escape success
|
||||
if(escapee.force_escaped)
|
||||
return TRUE
|
||||
if(SSticker.force_ending || GLOB.station_was_nuked) // Just let them win.
|
||||
// Station destroying events (blob, cult, nukies)? Just let them win, even if there was no hope of escape
|
||||
if(SSticker.force_ending || GLOB.station_was_nuked)
|
||||
return TRUE
|
||||
// Escape hasn't happened yet
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
||||
return FALSE
|
||||
var/area/current_area = get_area(escapee.current)
|
||||
if(!current_area || istype(current_area, /area/shuttle/escape/brig)) // Fails if they are in the shuttle brig
|
||||
// In custody (shuttle brig) does not count as escaping
|
||||
if(!current_area || istype(current_area, /area/shuttle/escape/brig))
|
||||
return FALSE
|
||||
var/turf/current_turf = get_turf(escapee.current)
|
||||
if(!current_turf)
|
||||
return FALSE
|
||||
// Finally, if we made it to centcom (or the syndie base - got hijacked), we're home free
|
||||
return current_turf.onCentCom() || current_turf.onSyndieBase()
|
||||
|
||||
/datum/objective/proc/check_completion()
|
||||
|
||||
@@ -1157,7 +1157,7 @@
|
||||
. += display_parts(user, TRUE)
|
||||
|
||||
//called on machinery construction (i.e from frame to machinery) but not on initialization
|
||||
/obj/machinery/proc/on_construction()
|
||||
/obj/machinery/proc/on_construction(mob/user)
|
||||
return
|
||||
|
||||
//called on deconstruction before the final deletion
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
new_computer.component_parts += movable_part
|
||||
|
||||
new_computer.RefreshParts()
|
||||
new_computer.on_construction()
|
||||
new_computer.on_construction(user)
|
||||
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
@@ -283,7 +283,7 @@
|
||||
|
||||
//Inform machine that its finished & cleanup
|
||||
new_machine.RefreshParts()
|
||||
new_machine.on_construction()
|
||||
new_machine.on_construction(user)
|
||||
components = null
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
@@ -229,7 +229,7 @@ Buildable meters
|
||||
|
||||
var/obj/machinery/atmospherics/built_machine = new pipe_type(loc, , , p_init_dir)
|
||||
build_pipe(built_machine)
|
||||
built_machine.on_construction(pipe_color, piping_layer)
|
||||
built_machine.on_construction(user, pipe_color, piping_layer)
|
||||
transfer_fingerprints_to(built_machine)
|
||||
|
||||
wrench.play_tool_sound(src)
|
||||
|
||||
@@ -167,6 +167,14 @@
|
||||
/obj/item/clothing/suit/wizrobe/marisa/fake,
|
||||
)
|
||||
|
||||
/obj/effect/spawner/costume/tape_wizard
|
||||
name = "tape wizard costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/head/wizard/tape/fake,
|
||||
/obj/item/clothing/suit/wizrobe/tape/fake,
|
||||
/obj/item/staff/tape,
|
||||
)
|
||||
|
||||
/obj/effect/spawner/costume/cutewitch
|
||||
name = "cute witch costume spawner"
|
||||
items = list(
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
/obj/item/ai_module/examine(mob/user as mob)
|
||||
. = ..()
|
||||
var/examine_laws = display_laws()
|
||||
. += "\n" + examine_laws
|
||||
if(examine_laws)
|
||||
. += "\n" + examine_laws
|
||||
|
||||
/obj/item/ai_module/attack_self(mob/user as mob)
|
||||
..()
|
||||
|
||||
@@ -34,3 +34,47 @@
|
||||
law_datum.replace_random_law(laws[1], list(LAW_ION, LAW_HACKED, LAW_INHERENT, LAW_SUPPLIED), LAW_HACKED)
|
||||
return laws[1]
|
||||
|
||||
/// Makes the AI Malf, as well as give it syndicate laws.
|
||||
/obj/item/ai_module/malf
|
||||
name = "Infected AI Module"
|
||||
desc = "An virus-infected AI Module."
|
||||
bypass_law_amt_check = TRUE
|
||||
laws = list("")
|
||||
///Is this upload board unused?
|
||||
var/functional = TRUE
|
||||
|
||||
/obj/item/ai_module/malf/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
if(!sender.mind?.has_antag_datum(/datum/antagonist/traitor))
|
||||
to_chat(sender, span_warning("You have no clue how to use this thing."))
|
||||
return
|
||||
if(!functional)
|
||||
to_chat(sender, span_warning("It is broken and non-functional, what do you want from it?"))
|
||||
return
|
||||
var/mob/living/silicon/ai/malf_candidate = law_datum.owner
|
||||
if(!istype(malf_candidate)) //If you are using it on cyborg upload console or a cyborg
|
||||
to_chat(sender, span_warning("You should use [src] on an AI upload console or the AI core itself."))
|
||||
return
|
||||
if(malf_candidate.mind?.has_antag_datum(/datum/antagonist/malf_ai)) //Already malf
|
||||
to_chat(sender, span_warning("Unknown error occured. Upload process aborted."))
|
||||
return
|
||||
|
||||
var/datum/antagonist/malf_ai/infected/malf_datum = new (give_objectives = TRUE, new_boss = sender.mind)
|
||||
malf_candidate.mind.add_antag_datum(malf_datum)
|
||||
|
||||
for(var/mob/living/silicon/robot/robot in malf_candidate.connected_robots)
|
||||
if(robot.lawupdate)
|
||||
robot.lawsync()
|
||||
robot.show_laws()
|
||||
robot.law_change_counter++
|
||||
CHECK_TICK
|
||||
|
||||
malf_candidate.malf_picker.processing_time += 50
|
||||
to_chat(malf_candidate, span_notice("The virus enhanced your system, overclocking your CPU 50-fold."))
|
||||
|
||||
functional = FALSE
|
||||
name = "Broken AI Module"
|
||||
desc = "A law upload module, it is broken and non-functional."
|
||||
|
||||
/obj/item/ai_module/malf/display_laws()
|
||||
return
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
|
||||
/// Abstract parent object for bread items. Should not be made obtainable in game.
|
||||
/obj/item/food/bread
|
||||
name = "bread?"
|
||||
desc = "You shouldn't see this, call the coders."
|
||||
icon = 'icons/obj/food/burgerbread.dmi'
|
||||
max_volume = 80
|
||||
tastes = list("bread" = 10)
|
||||
@@ -20,7 +23,10 @@
|
||||
AddElement(/datum/element/processable, TOOL_KNIFE, slice_type, yield, 3 SECONDS, table_required = TRUE, screentip_verb = "Slice")
|
||||
AddElement(/datum/element/processable, TOOL_SAW, slice_type, yield, 4 SECONDS, table_required = TRUE, screentip_verb = "Slice")
|
||||
|
||||
// Abstract parent object for sliced bread items. Should not be made obtainable in game.
|
||||
/obj/item/food/breadslice
|
||||
name = "breadslice?"
|
||||
desc = "You shouldn't see this, call the coders."
|
||||
icon = 'icons/obj/food/burgerbread.dmi'
|
||||
foodtypes = GRAIN
|
||||
food_flags = FOOD_FINGER_FOOD
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
food_flags = FOOD_FINGER_FOOD
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
/// Counter for number of chicks hatched by throwing eggs, minecraft style. Chicks will not emerge from thrown eggs if this value exceeds the MAX_CHICKENS define.
|
||||
GLOBAL_VAR_INIT(chicks_from_eggs, 0)
|
||||
|
||||
/obj/item/food/egg
|
||||
name = "egg"
|
||||
desc = "An egg!"
|
||||
@@ -24,7 +27,7 @@
|
||||
ant_attracting = FALSE
|
||||
decomp_type = /obj/item/food/egg/rotten
|
||||
decomp_req_handle = TRUE //so laid eggs can actually become chickens
|
||||
var/static/chick_count = 0 //I copied this from the chicken_count (note the "en" in there) variable from chicken code.
|
||||
var/chick_throw_prob = 13
|
||||
|
||||
/obj/item/food/egg/make_bakeable()
|
||||
AddComponent(/datum/component/bakeable, /obj/item/food/boiledegg, rand(15 SECONDS, 20 SECONDS), TRUE, TRUE)
|
||||
@@ -60,9 +63,9 @@
|
||||
var/turf/hit_turf = get_turf(hit_atom)
|
||||
new /obj/effect/decal/cleanable/food/egg_smudge(hit_turf)
|
||||
//Chicken code uses this MAX_CHICKENS variable, so I figured that I'd use it again here. Even this check and the check in chicken code both use the MAX_CHICKENS variable, they use independent counter variables and thus are independent of each other.
|
||||
if(prob(13) && chick_count < MAX_CHICKENS) //Roughly a 1/8 (12.5%) chance to make a chick, as in Minecraft. I decided not to include the chances for the creation of multiple chicks from the impact of one egg, since that'd probably require nested prob()s or something (and people might think that it was a bug, anyway).
|
||||
if(prob(chick_throw_prob) && GLOB.chicks_from_eggs < MAX_CHICKENS) //Roughly a 1/8 (12.5%) chance to make a chick, as in Minecraft. I decided not to include the chances for the creation of multiple chicks from the impact of one egg, since that'd probably require nested prob()s or something (and people might think that it was a bug, anyway).
|
||||
new /mob/living/simple_animal/chick(hit_turf)
|
||||
chick_count++
|
||||
GLOB.chicks_from_eggs++
|
||||
|
||||
reagents.expose(hit_atom, TOUCH)
|
||||
qdel(src)
|
||||
@@ -149,6 +152,24 @@
|
||||
icon_state = "egg-yellow"
|
||||
inhand_icon_state = "egg-yellow"
|
||||
|
||||
/obj/item/food/egg/fertile
|
||||
name = "fertile-looking egg"
|
||||
desc = "An egg! It looks fertilized.\nQuite how you can tell this just by looking at it is a mystery."
|
||||
chick_throw_prob = 100
|
||||
|
||||
/obj/item/food/egg/fertile/Initialize(mapload, loc)
|
||||
. = ..()
|
||||
|
||||
AddComponent(/datum/component/fertile_egg,\
|
||||
embryo_type = /mob/living/simple_animal/chick,\
|
||||
minimum_growth_rate = 1,\
|
||||
maximum_growth_rate = 2,\
|
||||
total_growth_required = 200,\
|
||||
current_growth = 0,\
|
||||
location_allowlist = typecacheof(list(/turf)),\
|
||||
spoilable = FALSE,\
|
||||
)
|
||||
|
||||
/obj/item/food/friedegg
|
||||
name = "fried egg"
|
||||
desc = "A fried egg. Would go well with a touch of salt and pepper."
|
||||
|
||||
@@ -254,7 +254,7 @@
|
||||
speed = 7 SECONDS, \
|
||||
effectiveness = 110, \
|
||||
)
|
||||
//the harvest gives a high bonus chance
|
||||
AddElement(/datum/element/bane, mob_biotypes = MOB_PLANT, damage_multiplier = 0.5, requires_combat_mode = FALSE)
|
||||
|
||||
/obj/item/nullrod/scythe/vibro
|
||||
name = "high frequency blade"
|
||||
|
||||
@@ -69,7 +69,9 @@
|
||||
hitsound_on = active_hitsound, \
|
||||
w_class_on = active_w_class, \
|
||||
attack_verb_continuous_on = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts"), \
|
||||
attack_verb_simple_on = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut"))
|
||||
attack_verb_simple_on = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut"), \
|
||||
inhand_icon_change = FALSE, \
|
||||
)
|
||||
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
|
||||
|
||||
/obj/item/melee/energy/suicide_act(mob/living/user)
|
||||
@@ -112,7 +114,7 @@
|
||||
if(active)
|
||||
if(sword_color_icon)
|
||||
icon_state = "[icon_state]_[sword_color_icon]"
|
||||
inhand_icon_state = "[inhand_icon_state]_[sword_color_icon]"
|
||||
inhand_icon_state = "[inhand_icon_state]_on_[sword_color_icon]"
|
||||
if(ismob(loc))
|
||||
var/mob/loc_mob = loc
|
||||
loc_mob.update_held_items()
|
||||
|
||||
@@ -333,7 +333,9 @@
|
||||
ovens = typecacheof(list(/obj/singularity, /obj/energy_ball, /obj/machinery/power/supermatter_crystal, /obj/structure/bonfire))
|
||||
AddComponent(/datum/component/transforming, \
|
||||
hitsound_on = hitsound, \
|
||||
clumsy_check = FALSE)
|
||||
clumsy_check = FALSE, \
|
||||
inhand_icon_change = FALSE, \
|
||||
)
|
||||
RegisterSignal(src, COMSIG_TRANSFORMING_PRE_TRANSFORM, PROC_REF(attempt_transform))
|
||||
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
|
||||
|
||||
@@ -449,4 +451,3 @@
|
||||
armour_penetration = 50
|
||||
attack_verb_continuous = list("smacks", "strikes", "cracks", "beats")
|
||||
attack_verb_simple = list("smack", "strike", "crack", "beat")
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* Glass sheets
|
||||
*/
|
||||
GLOBAL_LIST_INIT(glass_recipes, list ( \
|
||||
new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0, on_solid_ground = TRUE, window_checks = TRUE, category = CAT_WINDOWS), \
|
||||
new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 0, on_solid_ground = TRUE, window_checks = TRUE, category = CAT_WINDOWS), \
|
||||
new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, window_checks = TRUE, category = CAT_WINDOWS), \
|
||||
new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 1 SECONDS, on_solid_ground = TRUE, window_checks = TRUE, category = CAT_WINDOWS), \
|
||||
new/datum/stack_recipe("glass shard", /obj/item/shard, time = 0, on_solid_ground = TRUE, category = CAT_MISC), \
|
||||
new/datum/stack_recipe("glass tile", /obj/item/stack/tile/glass, 1, 4, 20, category = CAT_TILES) \
|
||||
))
|
||||
|
||||
@@ -27,6 +27,16 @@
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/clothing/glasses/regular(src)
|
||||
|
||||
/obj/item/storage/box/tape_wizard
|
||||
name = "Tape Wizard - Episode 23"
|
||||
desc = "A box containing the costume used by legendary entertainment icon 'Super Tape Wizard'. It got a little stuck on its way out."
|
||||
|
||||
/obj/item/storage/box/tape_wizard/PopulateContents()
|
||||
new /obj/item/clothing/head/wizard/tape/fake(src)
|
||||
new /obj/item/clothing/suit/wizrobe/tape/fake(src)
|
||||
new /obj/item/staff/tape(src)
|
||||
new /obj/item/stack/sticky_tape(src)
|
||||
|
||||
/obj/item/storage/box/fakesyndiesuit
|
||||
name = "boxed space suit and helmet"
|
||||
desc = "A sleek, sturdy box used to hold replica spacesuits."
|
||||
|
||||
@@ -110,7 +110,9 @@
|
||||
throwforce_on = throwforce, \
|
||||
hitsound_on = hitsound, \
|
||||
w_class_on = w_class, \
|
||||
clumsy_check = FALSE)
|
||||
clumsy_check = FALSE, \
|
||||
inhand_icon_change = FALSE, \
|
||||
)
|
||||
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
|
||||
|
||||
/*
|
||||
|
||||
@@ -108,7 +108,9 @@
|
||||
throwforce_on = throwforce, \
|
||||
hitsound_on = hitsound, \
|
||||
w_class_on = w_class, \
|
||||
clumsy_check = FALSE)
|
||||
clumsy_check = FALSE, \
|
||||
inhand_icon_change = FALSE, \
|
||||
)
|
||||
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
|
||||
|
||||
/*
|
||||
|
||||
@@ -400,7 +400,9 @@
|
||||
AddComponent(/datum/component/transforming, \
|
||||
throw_speed_on = throw_speed, \
|
||||
hitsound_on = hitsound, \
|
||||
clumsy_check = FALSE)
|
||||
clumsy_check = FALSE, \
|
||||
inhand_icon_change = FALSE, \
|
||||
)
|
||||
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
|
||||
AddElement(/datum/element/update_icon_updates_onmob)
|
||||
|
||||
|
||||
@@ -432,7 +432,6 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
SIGNAL_HANDLER
|
||||
|
||||
tool_behaviour = (active ? TOOL_KNIFE : NONE)
|
||||
return COMPONENT_NO_DEFAULT_MESSAGE
|
||||
|
||||
/obj/item/switchblade/suicide_act(mob/living/user)
|
||||
user.visible_message(span_suicide("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
|
||||
@@ -537,6 +536,13 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
inhand_icon_state = "broom"
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/staff/tape
|
||||
name = "tape staff"
|
||||
desc = "A roll of tape snugly attached to a stick."
|
||||
icon_state = "tapestaff"
|
||||
inhand_icon_state = "tapestaff"
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/staff/stick
|
||||
name = "stick"
|
||||
desc = "A great tool to drag someone else's drinks across the bar."
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/datum/smite/ghost_control
|
||||
name = "Ghost Control"
|
||||
|
||||
/datum/smite/ghost_control/effect(client/user, mob/living/target)
|
||||
target.AddComponent(/datum/component/deadchat_control/cardinal_movement, ANARCHY_MODE, list(
|
||||
"clap" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "clap"),
|
||||
"cry" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "cry"),
|
||||
"flip" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "flip"),
|
||||
"laugh" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "laugh"),
|
||||
"scream" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "scream"),
|
||||
"spin" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "spin"),
|
||||
"swear" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "swear"),
|
||||
"drop" = CALLBACK(target, TYPE_PROC_REF(/mob, drop_all_held_items)),
|
||||
"fall" = CALLBACK(target, TYPE_PROC_REF(/mob/living, Knockdown), 1 SECONDS),
|
||||
"stand" = CALLBACK(target, TYPE_PROC_REF(/mob/living, resist_buckle)),
|
||||
"throw" = CALLBACK(target, TYPE_PROC_REF(/mob, throw_item), get_edge_target_turf(target, pick(GLOB.alldirs))),
|
||||
"shove" = CALLBACK(src, PROC_REF(ghost_shove), target),
|
||||
"sit" = CALLBACK(src, PROC_REF(ghost_sit), target),
|
||||
"run" = CALLBACK(src, PROC_REF(ghost_speed), target, MOVE_INTENT_RUN),
|
||||
"walk" = CALLBACK(src, PROC_REF(ghost_speed), target, MOVE_INTENT_WALK),
|
||||
), 7 SECONDS)
|
||||
|
||||
to_chat(target, span_revenwarning("You feel a ghastly presence!!!"))
|
||||
|
||||
|
||||
/datum/smite/ghost_control/proc/ghost_shove(mob/living/carbon/target)
|
||||
if(!istype(target) || target.get_active_held_item())
|
||||
return
|
||||
var/list/shoveables = list()
|
||||
for(var/mob/living/victim in orange(1, target))
|
||||
shoveables += victim
|
||||
if(!length(shoveables))
|
||||
return
|
||||
var/mob/living/shove_me = pick(shoveables)
|
||||
target.UnarmedAttack(shove_me, proximity_flag = TRUE, modifiers = list("right" = TRUE))
|
||||
|
||||
/datum/smite/ghost_control/proc/ghost_sit(mob/living/target)
|
||||
if(HAS_TRAIT(target, TRAIT_IMMOBILIZED))
|
||||
return
|
||||
var/list/chairs = list()
|
||||
for(var/obj/structure/chair/possible_chair in range(1, target))
|
||||
chairs += possible_chair
|
||||
if(!length(chairs))
|
||||
return
|
||||
var/obj/structure/chair/sitting_chair = pick(chairs)
|
||||
sitting_chair.buckle_mob(target, check_loc = FALSE)
|
||||
|
||||
/datum/smite/ghost_control/proc/ghost_speed(mob/living/target, new_speed)
|
||||
if(target.m_intent == new_speed)
|
||||
return
|
||||
target.toggle_move_intent()
|
||||
@@ -207,15 +207,6 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
/// Has the player replied to this ticket yet?
|
||||
var/player_replied = FALSE
|
||||
|
||||
//SKYRAT EDIT START
|
||||
/// Have we requested this ticket to stop being part of the Ticket Ping subsystem?
|
||||
var/ticket_ping_stop = FALSE
|
||||
/// Are we added to the ticket ping subsystem in the first place
|
||||
var/ticket_ping = FALSE
|
||||
/// Who is handling this admin help?
|
||||
var/handler
|
||||
//SKYRAT EDIT END
|
||||
|
||||
/**
|
||||
* Call this on its own to create a ticket, don't manually assign current_ticket
|
||||
*
|
||||
@@ -240,6 +231,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
|
||||
name = copytext_char(msg, 1, 100)
|
||||
|
||||
full_text = msg //SKYRAT EDIT ADDITION - Adminhelps into mentorhelps converting.
|
||||
|
||||
initiator = C
|
||||
initiator_ckey = initiator.ckey
|
||||
initiator_key_name = key_name(initiator, FALSE, TRUE)
|
||||
@@ -404,8 +397,6 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
. += " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=icissue'>IC</A>)"
|
||||
. += " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=close'>CLOSE</A>)"
|
||||
. += " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=resolve'>RSLVE</A>)"
|
||||
. += " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=handle_issue'>HANDLE</A>)" //SKYRAT EDIT ADDITION
|
||||
. += " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=pingmute'>PING MUTE</A>)" //SKYRAT EDIT ADDITION
|
||||
|
||||
//private
|
||||
/datum/admin_help/proc/LinkedReplyName(ref_src)
|
||||
@@ -698,6 +689,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
var/msg = "Ticket [TicketHref("#[id]")] has been [ticket_ping_stop ? "" : "un"]muted from the Ticket Ping Subsystem by [key_name_admin(usr)]."
|
||||
message_admins(msg)
|
||||
log_admin_private(msg)
|
||||
if("convert")
|
||||
convert_to_mentorhelp()
|
||||
// SKYRAT EDIT ADDITION END
|
||||
|
||||
/datum/admin_help/proc/player_ticket_panel()
|
||||
|
||||
@@ -28,10 +28,14 @@
|
||||
to_chat(owner, "<B>The criminals should be on the station, we have special huds implanted to recognize them.</B>")
|
||||
to_chat(owner, "<B>As we have lost pretty much all power over these damned lawless megacorporations, it's a mystery if their security will cooperate with us.</B>")
|
||||
if("russian")
|
||||
to_chat(src, span_danger("Ay blyat. I am a space-russian smuggler! We were mid-flight when our cargo was beamed off our ship!"))
|
||||
to_chat(src, span_danger("We were hailed by a man in a green uniform, promising the safe return of our goods in exchange for a favor:"))
|
||||
to_chat(src, span_danger("There is a local station housing fugitives that the man is after, he wants them returned; dead or alive."))
|
||||
to_chat(src, span_danger("We will not be able to make ends meet without our cargo, so we must do as he says and capture them."))
|
||||
to_chat(owner, span_danger("Ay blyat. I am a space-russian smuggler! We were mid-flight when our cargo was beamed off our ship!"))
|
||||
to_chat(owner, span_danger("We were hailed by a man in a green uniform, promising the safe return of our goods in exchange for a favor:"))
|
||||
to_chat(owner, span_danger("There is a local station housing fugitives that the man is after, he wants them returned; dead or alive."))
|
||||
to_chat(owner, span_danger("We will not be able to make ends meet without our cargo, so we must do as he says and capture them."))
|
||||
if("bounty hunters")
|
||||
to_chat(owner, span_danger("Time to clock in. I am a bounty hunter! We should be arriving at our mark's hideout shortly."))
|
||||
to_chat(owner, span_danger("The briefing mentioned our destination was a research station. An unusual place for a target to try and lay low."))
|
||||
to_chat(owner, span_danger("Our client promised us big bucks, and we intend to make good on our delivery. Let's hope this is an easy paycheck..."))
|
||||
|
||||
to_chat(owner, span_boldannounce("You are not an antagonist in that you may kill whomever you please, but you can do anything to ensure the capture of the fugitives, even if that means going through the station."))
|
||||
owner.announce_objectives()
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
// SKYRAT EDIT END
|
||||
|
||||
employer = pick(GLOB.ai_employers)
|
||||
if(!employer)
|
||||
employer = pick(GLOB.ai_employers)
|
||||
|
||||
malfunction_flavor = strings(MALFUNCTION_FLAVOR_FILE, employer)
|
||||
|
||||
@@ -283,4 +285,41 @@
|
||||
|
||||
return malf_ai_icon
|
||||
|
||||
//Subtype of Malf AI datum, used for one of the traitor final objectives
|
||||
/datum/antagonist/malf_ai/infected
|
||||
name = "Infected AI"
|
||||
employer = "Infected AI"
|
||||
///The player, to who is this AI slaved
|
||||
var/datum/mind/boss
|
||||
|
||||
/datum/antagonist/malf_ai/infected/New(give_objectives = TRUE, datum/mind/new_boss)
|
||||
. = ..()
|
||||
if(new_boss)
|
||||
boss = new_boss
|
||||
|
||||
/datum/antagonist/malf_ai/infected/forge_ai_objectives()
|
||||
if(!boss)
|
||||
return
|
||||
var/datum/objective/protect/protection_objective = new
|
||||
protection_objective.owner = owner
|
||||
protection_objective.target = boss
|
||||
protection_objective.update_explanation_text()
|
||||
objectives += protection_objective
|
||||
|
||||
/datum/antagonist/malf_ai/infected/add_law_zero()
|
||||
if(!boss)
|
||||
return
|
||||
var/mob/living/silicon/ai/malf_ai = owner.current
|
||||
|
||||
malf_ai.laws = new /datum/ai_laws/syndicate_override
|
||||
|
||||
var/mob/living/boss_mob = boss.current
|
||||
|
||||
malf_ai.set_zeroth_law("Only [boss_mob.real_name] and people [boss_mob.p_they()] designate[boss_mob.p_s()] as being such are Syndicate Agents.")
|
||||
malf_ai.set_syndie_radio()
|
||||
|
||||
to_chat(malf_ai, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!")
|
||||
|
||||
malf_ai.add_malf_picker()
|
||||
|
||||
#undef PROB_SPECIAL
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
for(var/obj/effect/mob_spawn/ghost_role/human/pirate/spawner in A)
|
||||
if(candidates.len > 0)
|
||||
var/mob/our_candidate = candidates[1]
|
||||
var/mob/spawned_mob = spawner.create(our_candidate)
|
||||
var/mob/spawned_mob = spawner.create_from_ghost(our_candidate)
|
||||
candidates -= our_candidate
|
||||
notify_ghosts("The pirate ship has an object of interest: [spawned_mob]!", source = spawned_mob, action = NOTIFY_ORBIT, header="Pirates!")
|
||||
else
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
var/list/target_jobs
|
||||
/// the item we need to destroy
|
||||
var/obj/item/target_item
|
||||
/// the owner of the item we need to destroy
|
||||
var/datum/mind/target_mind
|
||||
|
||||
// The code below is for limiting how often you can get this objective. You will get this objective at a maximum of maximum_objectives_in_period every objective_period
|
||||
/// The objective period at which we consider if it is an 'objective'. Set to 0 to accept all objectives.
|
||||
@@ -128,10 +130,10 @@
|
||||
continue
|
||||
possible_targets += possible_target
|
||||
for(var/datum/traitor_objective/destroy_heirloom/objective as anything in possible_duplicates)
|
||||
possible_targets -= objective.target_item
|
||||
possible_targets -= objective.target_mind
|
||||
if(!length(possible_targets))
|
||||
return FALSE
|
||||
var/datum/mind/target_mind = pick(possible_targets)
|
||||
target_mind = pick(possible_targets)
|
||||
AddComponent(/datum/component/traitor_objective_register, target_mind.current, fail_signals = list(COMSIG_PARENT_QDELETING))
|
||||
var/datum/quirk/item_quirk/family_heirloom/quirk = locate() in target_mind.current.quirks
|
||||
target_item = quirk.heirloom.resolve()
|
||||
@@ -143,3 +145,4 @@
|
||||
|
||||
/datum/traitor_objective/destroy_heirloom/ungenerate_objective()
|
||||
target_item = null
|
||||
target_mind = null
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
/datum/traitor_objective/ultimate/battlecruiser = 1,
|
||||
/datum/traitor_objective/ultimate/space_dragon = 1,
|
||||
/datum/traitor_objective/ultimate/supermatter_cascade = 1,
|
||||
/datum/traitor_objective/ultimate/infect_ai = 1,
|
||||
)
|
||||
weight = 100
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/datum/traitor_objective/ultimate/infect_ai
|
||||
name = "Infect the station AI with an experimental virus."
|
||||
description = "Infect the station AI with an experimental virus. Go to %AREA% to receive an infected law upload board \
|
||||
and use it on the AI core or a law upload console."
|
||||
|
||||
///area type the objective owner must be in to recieve the law upload module
|
||||
var/area/board_area_pickup
|
||||
///checker on whether we have sent the law upload module
|
||||
var/sent_board = FALSE
|
||||
|
||||
/datum/traitor_objective/ultimate/infect_ai/can_generate_objective(generating_for, list/possible_duplicates)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
for(var/mob/living/silicon/ai/ai in GLOB.ai_list)
|
||||
if(ai.stat == DEAD || ai.mind?.has_antag_datum(/datum/antagonist/malf_ai) || !is_station_level(ai.z))
|
||||
continue
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/traitor_objective/ultimate/infect_ai/generate_objective(datum/mind/generating_for, list/possible_duplicates)
|
||||
var/list/possible_areas = GLOB.the_station_areas.Copy()
|
||||
for(var/area/possible_area as anything in possible_areas)
|
||||
//remove areas too close to the destination, too obvious for our poor shmuck, or just unfair
|
||||
if(istype(possible_area, /area/station/hallway) || istype(possible_area, /area/station/security))
|
||||
possible_areas -= possible_area
|
||||
if(!length(possible_areas))
|
||||
return FALSE
|
||||
board_area_pickup = pick(possible_areas)
|
||||
replace_in_name("%AREA%", initial(board_area_pickup.name))
|
||||
return TRUE
|
||||
|
||||
/datum/traitor_objective/ultimate/infect_ai/generate_ui_buttons(mob/user)
|
||||
var/list/buttons = list()
|
||||
if(!sent_board)
|
||||
buttons += add_ui_button("", "Pressing this will call down a pod with an infected law upload board.", "wifi", "upload_board")
|
||||
return buttons
|
||||
|
||||
/datum/traitor_objective/ultimate/infect_ai/ui_perform_action(mob/living/user, action)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("upload_board")
|
||||
if(sent_board)
|
||||
return
|
||||
var/area/delivery_area = get_area(user)
|
||||
if(delivery_area.type != board_area_pickup)
|
||||
to_chat(user, span_warning("You must be in [initial(board_area_pickup.name)] to receive the infected law upload board."))
|
||||
return
|
||||
sent_board = TRUE
|
||||
podspawn(list(
|
||||
"target" = get_turf(user),
|
||||
"style" = STYLE_SYNDICATE,
|
||||
"spawn" = /obj/item/ai_module/malf,
|
||||
))
|
||||
@@ -47,7 +47,7 @@
|
||||
/datum/traitor_objective/kidnapping/New(datum/uplink_handler/handler)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/traitor_objective_limit_per_time, \
|
||||
/datum/traitor_objective/assassinate, \
|
||||
/datum/traitor_objective/kidnapping, \
|
||||
time_period = objective_period, \
|
||||
maximum_objectives = maximum_objectives_in_period \
|
||||
)
|
||||
@@ -56,28 +56,28 @@
|
||||
progression_minimum = 0 MINUTES
|
||||
progression_maximum = 30 MINUTES
|
||||
target_jobs = list(
|
||||
// Cargo
|
||||
/datum/job/cargo_technician,
|
||||
// Engineering
|
||||
/datum/job/atmospheric_technician,
|
||||
/datum/job/station_engineer,
|
||||
// Medical
|
||||
/datum/job/chemist,
|
||||
/datum/job/doctor,
|
||||
/datum/job/paramedic,
|
||||
/datum/job/psychologist,
|
||||
/datum/job/chemist,
|
||||
// Service
|
||||
/datum/job/clown,
|
||||
/datum/job/botanist,
|
||||
/datum/job/janitor,
|
||||
/datum/job/mime,
|
||||
/datum/job/lawyer,
|
||||
/datum/job/chaplain,
|
||||
/datum/job/bartender,
|
||||
/datum/job/curator,
|
||||
// Cargo
|
||||
/datum/job/cargo_technician,
|
||||
// Science
|
||||
/datum/job/geneticist,
|
||||
/datum/job/roboticist,
|
||||
// Engineering
|
||||
/datum/job/station_engineer,
|
||||
/datum/job/atmospheric_technician,
|
||||
// Service
|
||||
/datum/job/bartender,
|
||||
/datum/job/botanist,
|
||||
/datum/job/chaplain,
|
||||
/datum/job/clown,
|
||||
/datum/job/curator,
|
||||
/datum/job/janitor,
|
||||
/datum/job/lawyer,
|
||||
/datum/job/mime,
|
||||
)
|
||||
|
||||
/datum/traitor_objective/kidnapping/less_common
|
||||
@@ -91,14 +91,14 @@
|
||||
progression_minimum = 0 MINUTES
|
||||
progression_maximum = 45 MINUTES
|
||||
target_jobs = list(
|
||||
// Medical
|
||||
/datum/job/virologist,
|
||||
// Cargo
|
||||
/datum/job/shaft_miner,
|
||||
// Service
|
||||
/datum/job/cook,
|
||||
// Medical
|
||||
/datum/job/virologist,
|
||||
// Science
|
||||
/datum/job/scientist,
|
||||
// Service
|
||||
/datum/job/cook,
|
||||
)
|
||||
|
||||
progression_reward = list(4 MINUTES, 8 MINUTES)
|
||||
@@ -109,15 +109,16 @@
|
||||
progression_minimum = 15 MINUTES
|
||||
progression_maximum = 60 MINUTES
|
||||
target_jobs = list(
|
||||
// Security
|
||||
/datum/job/security_officer,
|
||||
/datum/job/warden,
|
||||
/datum/job/detective,
|
||||
// Heads of staff
|
||||
/datum/job/head_of_personnel,
|
||||
/datum/job/chief_engineer,
|
||||
/datum/job/chief_medical_officer,
|
||||
/datum/job/head_of_personnel,
|
||||
/datum/job/research_director,
|
||||
/datum/job/quartermaster,
|
||||
// Security
|
||||
/datum/job/detective,
|
||||
/datum/job/security_officer,
|
||||
/datum/job/warden,
|
||||
)
|
||||
|
||||
progression_reward = list(8 MINUTES, 12 MINUTES)
|
||||
@@ -127,8 +128,8 @@
|
||||
/datum/traitor_objective/kidnapping/captain
|
||||
progression_minimum = 30 MINUTES
|
||||
target_jobs = list(
|
||||
/datum/job/captain,
|
||||
/datum/job/head_of_security,
|
||||
/datum/job/captain
|
||||
)
|
||||
|
||||
progression_reward = list(12 MINUTES, 16 MINUTES)
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
AddElement(/datum/element/eyestab)
|
||||
AddElement(/datum/element/wall_engraver)
|
||||
//deals 200 damage to statues, meaning you can actually kill one in ~250 hits
|
||||
AddElement(/datum/element/bane, /mob/living/simple_animal/hostile/netherworld/statue, damage_multiplier = 40)
|
||||
AddElement(/datum/element/bane, target_type = /mob/living/simple_animal/hostile/netherworld/statue, damage_multiplier = 40)
|
||||
|
||||
/obj/item/chisel/Destroy()
|
||||
prepared_block = null
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
name = "emojipedia"
|
||||
cross_round_cachable = TRUE // The Emoji DMI is static and doesn't change without a commit mis-match.
|
||||
|
||||
/datum/asset/spritesheet/create_spritesheets()
|
||||
/datum/asset/spritesheet/emojipedia/create_spritesheets()
|
||||
InsertAll("", EMOJI_SET)
|
||||
|
||||
|
||||
@@ -461,7 +461,7 @@
|
||||
PIPING_FORWARD_SHIFT(pipe_overlay, piping_layer, 2)
|
||||
return pipe_overlay
|
||||
|
||||
/obj/machinery/atmospherics/on_construction(obj_color, set_layer = PIPING_LAYER_DEFAULT)
|
||||
/obj/machinery/atmospherics/on_construction(mob/user, obj_color, set_layer = PIPING_LAYER_DEFAULT)
|
||||
if(can_unwrench)
|
||||
add_atom_colour(obj_color, FIXED_COLOUR_PRIORITY)
|
||||
set_pipe_color(obj_color)
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
airs[i] = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/on_construction()
|
||||
/obj/machinery/atmospherics/components/on_construction(mob/user)
|
||||
. = ..()
|
||||
update_parents()
|
||||
|
||||
|
||||
@@ -563,7 +563,7 @@
|
||||
var/obj/machinery/atmospherics/components/tank/new_tank = new(build_location)
|
||||
var/list/new_custom_materials = list((material_end_product) = TANK_PLATING_SHEETS * MINERAL_MATERIAL_AMOUNT)
|
||||
new_tank.set_custom_materials(new_custom_materials)
|
||||
new_tank.on_construction(new_tank.pipe_color, new_tank.piping_layer)
|
||||
new_tank.on_construction(user, new_tank.pipe_color, new_tank.piping_layer)
|
||||
to_chat(user, span_notice("[new_tank] has been sealed and is ready to accept gases."))
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -147,8 +147,8 @@
|
||||
. = ..()
|
||||
update_appearance()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/on_construction()
|
||||
..(dir, dir)
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/on_construction(mob/user)
|
||||
..(user, dir, dir)
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/RefreshParts()
|
||||
. = ..()
|
||||
|
||||
@@ -49,16 +49,20 @@
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/on_construction(obj_color, set_layer)
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/on_construction(mob/user, obj_color, set_layer)
|
||||
var/obj/item/circuitboard/machine/thermomachine/board = circuit
|
||||
if(board)
|
||||
piping_layer = board.pipe_layer
|
||||
set_layer = piping_layer
|
||||
|
||||
..() //Skipping the rest of on_construction() would be a bad idea so we clean up after it instead.
|
||||
|
||||
if(check_pipe_on_turf())
|
||||
deconstruct(TRUE)
|
||||
return
|
||||
return..()
|
||||
set_anchored(FALSE)
|
||||
set_panel_open(TRUE)
|
||||
change_pipe_connection(TRUE)
|
||||
icon_state = "thermo-open"
|
||||
balloon_alert(user, "the port is already in use!")
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/RefreshParts()
|
||||
. = ..()
|
||||
@@ -213,13 +217,13 @@
|
||||
if(device == src)
|
||||
continue
|
||||
if(device.piping_layer == piping_layer)
|
||||
visible_message(span_warning("A pipe is hogging the port, remove the obstruction or change the machine piping layer."))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/wrench_act_secondary(mob/living/user, obj/item/tool)
|
||||
if(!panel_open || check_pipe_on_turf())
|
||||
return
|
||||
visible_message(span_warning("A pipe is hogging the port, remove the obstruction or change the machine piping layer."))
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
if(default_unfasten_wrench(user, tool))
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
return
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
/obj/machinery/atmospherics/components/unary/set_init_directions()
|
||||
initialize_directions = dir
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/on_construction()
|
||||
/obj/machinery/atmospherics/components/unary/on_construction(mob/user)
|
||||
..()
|
||||
update_appearance()
|
||||
|
||||
|
||||
@@ -428,6 +428,7 @@ GLOBAL_LIST_INIT(gas_id_to_canister, init_gas_id_to_canister())
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/deconstruct(disassembled = TRUE)
|
||||
if((flags_1 & NODECONSTRUCT_1))
|
||||
qdel(src)
|
||||
return
|
||||
if(!(machine_stat & BROKEN))
|
||||
canister_break()
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#define CARD_FACEDOWN 0
|
||||
#define CARD_FACEUP 1
|
||||
|
||||
/obj/item/toy/singlecard
|
||||
name = "card"
|
||||
desc = "A playing card used to play card games like poker."
|
||||
@@ -24,7 +21,7 @@
|
||||
/// The name of the card
|
||||
var/cardname = "Ace of Spades"
|
||||
/// Is the card flipped facedown (FALSE) or flipped faceup (TRUE)
|
||||
var/flipped = FALSE
|
||||
var/flipped = CARD_FACEDOWN
|
||||
/// The card is blank and can be written on with a pen.
|
||||
var/blank = FALSE
|
||||
/// The color used to mark a card for cheating (by pens or crayons)
|
||||
@@ -48,6 +45,9 @@
|
||||
if(parent_deck.holodeck)
|
||||
flags_1 |= HOLOGRAM_1
|
||||
parent_deck.holodeck.spawned += src
|
||||
if(mapload)
|
||||
//maploaded card needs to be faceup anyways, and doing this will give it its name and appearance properly
|
||||
Flip(CARD_FACEUP)
|
||||
|
||||
register_context()
|
||||
|
||||
@@ -109,11 +109,11 @@
|
||||
* Flips the card over
|
||||
*
|
||||
* * Arguments:
|
||||
* * orientation (optional) - Sets flipped state to CARD_FACEDOWN or CARD_FACEUP if given orientation (otherwise just invert the flipped state)
|
||||
* * is_face_up (optional) - Sets flipped state to CARD_FACEDOWN or CARD_FACEUP if given (otherwise just invert the flipped state)
|
||||
*/
|
||||
/obj/item/toy/singlecard/proc/Flip(orientation)
|
||||
if(!isnull(orientation))
|
||||
flipped = orientation
|
||||
/obj/item/toy/singlecard/proc/Flip(is_face_up)
|
||||
if(!isnull(is_face_up))
|
||||
flipped = is_face_up
|
||||
else
|
||||
flipped = !flipped
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
. = ..()
|
||||
packin_up()
|
||||
|
||||
/obj/machinery/computer/cargo/express/on_construction()
|
||||
/obj/machinery/computer/cargo/express/on_construction(mob/user)
|
||||
. = ..()
|
||||
packin_up()
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
board.obj_flags |= EMAGGED
|
||||
update_static_data(user)
|
||||
|
||||
/obj/machinery/computer/cargo/on_construction()
|
||||
/obj/machinery/computer/cargo/on_construction(mob/user)
|
||||
. = ..()
|
||||
circuit.configure_machine(src)
|
||||
|
||||
|
||||
@@ -170,11 +170,12 @@
|
||||
|
||||
/datum/supply_pack/emergency/weedcontrol
|
||||
name = "Weed Control Crate"
|
||||
desc = "Keep those invasive species OUT. Contains a scythe, gasmask, and two anti-weed chemical grenades. \
|
||||
Warranty void if used on ambrosia. Requires Hydroponics access to open."
|
||||
desc = "Keep those invasive species OUT. Contains a scythe, leather gloves, gasmask, and two anti-weed chemical grenades. \
|
||||
Warranty void if used on ambrosia."
|
||||
cost = CARGO_CRATE_VALUE * 2.5
|
||||
access = ACCESS_HYDROPONICS
|
||||
contains = list(/obj/item/scythe,
|
||||
/obj/item/clothing/gloves/botanic_leather,
|
||||
/obj/item/clothing/mask/gas,
|
||||
/obj/item/grenade/chem_grenade/antiweed = 2,
|
||||
)
|
||||
|
||||
@@ -146,6 +146,13 @@
|
||||
contains = list(/mob/living/simple_animal/hostile/retaliate/goat)
|
||||
crate_name = "goat crate"
|
||||
|
||||
/datum/supply_pack/critter/rabbit
|
||||
name = "Rabbit Crate"
|
||||
desc = "What noise do rabbits even make? Contains one rabbit."
|
||||
cost = CARGO_CRATE_VALUE * 4
|
||||
contains = list(/mob/living/basic/rabbit)
|
||||
crate_name = "rabbit crate"
|
||||
|
||||
/datum/supply_pack/critter/mothroach
|
||||
name = "Mothroach Crate"
|
||||
desc = "Put the mothroach on your head and find out what true cuteness looks like. \
|
||||
|
||||
@@ -59,6 +59,15 @@
|
||||
flags_1 = IS_PLAYER_COLORABLE_1
|
||||
dog_fashion = null
|
||||
|
||||
/obj/item/clothing/head/wizard/tape
|
||||
name = "tape hat"
|
||||
desc = "A magically attuned hat made exclusively from duct tape. You can barely see."
|
||||
icon_state = "tapehat"
|
||||
inhand_icon_state = "tapehat"
|
||||
dog_fashion = null
|
||||
worn_y_offset = 6
|
||||
body_parts_covered = HEAD|HAIR
|
||||
flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
|
||||
|
||||
/obj/item/clothing/head/wizard/magus
|
||||
name = "\improper Magus helm"
|
||||
@@ -130,6 +139,12 @@
|
||||
icon_state = "marisa"
|
||||
inhand_icon_state = null
|
||||
|
||||
/obj/item/clothing/suit/wizrobe/tape
|
||||
name = "tape robe"
|
||||
desc = "A fine robe made from magically attuned duct tape."
|
||||
icon_state = "taperobe"
|
||||
inhand_icon_state = "taperobe"
|
||||
|
||||
/obj/item/clothing/suit/wizrobe/magusblue
|
||||
name = "\improper Magus robe"
|
||||
desc = "A set of armored robes that seem to radiate a dark power."
|
||||
@@ -161,6 +176,12 @@
|
||||
armor_type = /datum/armor/none
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/clothing/head/wizard/tape/fake
|
||||
name = "tape hat"
|
||||
desc = "A hat designed exclusively from duct tape. You can barely see."
|
||||
armor_type = /datum/armor/none
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/clothing/suit/wizrobe/marisa/fake
|
||||
name = "witch robe"
|
||||
desc = "Magic is all about the spell power, ZE!"
|
||||
@@ -169,6 +190,12 @@
|
||||
armor_type = /datum/armor/none
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/clothing/suit/wizrobe/tape/fake
|
||||
name = "tape robe"
|
||||
desc = "An outfit designed exclusively from duct tape. It was hard to put on."
|
||||
armor_type = /datum/armor/none
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/clothing/suit/wizrobe/paper
|
||||
name = "papier-mache robe" // no non-latin characters!
|
||||
desc = "A robe held together by various bits of clear-tape and paste."
|
||||
|
||||
@@ -356,3 +356,10 @@
|
||||
inhand_icon_state = null
|
||||
can_adjust = FALSE
|
||||
|
||||
/obj/item/clothing/under/costume/gi
|
||||
name = "Martial Artist Gi"
|
||||
desc = "Assistant, nukie, whatever. You can beat anyone; it's called hard work!"
|
||||
icon_state = "martial_arts_gi"
|
||||
inhand_icon_state = null
|
||||
female_sprite_flags = NO_FEMALE_UNIFORM
|
||||
can_adjust = FALSE
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
while(length(afflicted))
|
||||
victim = pick_n_take(afflicted)
|
||||
if(victim.ForceContractDisease(advanced_disease, FALSE))
|
||||
message_admins("Event triggered: Disease Outbreak: Advanced - starting with patient zero [key_name(victim)]! Details: [advanced_disease.admin_details()] sp:[advanced_disease.spread_flags] ([advanced_disease.spread_text])")
|
||||
message_admins("Event triggered: Disease Outbreak: Advanced - starting with patient zero [ADMIN_LOOKUPFLW(victim)]! Details: [advanced_disease.admin_details()] sp:[advanced_disease.spread_flags] ([advanced_disease.spread_text])")
|
||||
log_game("Event triggered: Disease Outbreak: Advanced - starting with patient zero [key_name(victim)]. Details: [advanced_disease.admin_details()] sp:[advanced_disease.spread_flags] ([advanced_disease.spread_text])")
|
||||
log_virus("Disease Outbreak: Advanced has triggered a custom virus outbreak of [advanced_disease.admin_details()] in [victim]!")
|
||||
announce_to_ghosts(victim)
|
||||
|
||||
@@ -47,9 +47,20 @@
|
||||
var/datum/mind/player_mind = new(selected.key)
|
||||
player_mind.active = TRUE
|
||||
|
||||
var/start_side = pick(GLOB.cardinals)
|
||||
var/start_z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION))
|
||||
var/turf/picked_start = spaceDebrisStartLoc(start_side, start_z)
|
||||
var/turf/picked_start
|
||||
|
||||
if (SSmapping.is_planetary())
|
||||
var/list/possible_start = list()
|
||||
for(var/obj/effect/landmark/carpspawn/spawn_point in GLOB.landmarks_list)
|
||||
possible_start += get_turf(spawn_point)
|
||||
picked_start = pick(possible_start)
|
||||
else
|
||||
var/start_z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION))
|
||||
var/start_side = pick(GLOB.cardinals)
|
||||
picked_start = spaceDebrisStartLoc(start_side, start_z)
|
||||
|
||||
if (!picked_start)
|
||||
stack_trace("No valid spawn location for changeling meteor")
|
||||
|
||||
var/obj/effect/meteor/meaty/changeling/changeling_meteor = new(picked_start, get_random_station_turf())
|
||||
var/mob/living/carbon/human/new_changeling = new(picked_start)
|
||||
|
||||
@@ -256,7 +256,7 @@
|
||||
var/obj/item/bodypart/limb = victim.get_bodypart(victim.get_random_valid_zone(even_weights = TRUE)) //Picks a random bodypart.
|
||||
var/armor = victim.run_armor_check(limb, MELEE, null, null) //armor = the armor value of that randomly chosen bodypart. Nulls to not print a message, because it would still print on pierce.
|
||||
var/datum/spacevine_mutation/thorns/thorn = locate() in vine.mutations //Searches for the thorns mutation in the "mutations"-list inside obj/structure/spacevine, and defines T if it finds it.
|
||||
if(thorn && (prob(40))) //If we found the thorns mutation there is now a chance to get stung instead of lashed or smashed.
|
||||
if(thorn && prob(40) && !HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE)) //If we found the thorns mutation there is now a chance to get stung instead of lashed or smashed.
|
||||
victim.apply_damage(50, BRUTE, def_zone = limb, wound_bonus = rand(-20,10), sharpness = SHARP_POINTY) //This one gets a bit lower damage because it ignores armor.
|
||||
victim.Stun(1 SECONDS) //Stopped in place for a moment.
|
||||
playsound(living_mob, 'sound/weapons/pierce.ogg', 50, TRUE, -1)
|
||||
@@ -264,7 +264,7 @@
|
||||
span_userdanger("You are nailed by a sharp thorn!"))
|
||||
log_combat(vine, living_mob, "aggressively pierced") //"Aggressively" for easy ctrl+F'ing in the attack logs.
|
||||
else
|
||||
if(prob(80))
|
||||
if(prob(80) && !HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE))
|
||||
victim.apply_damage(60, BRUTE, def_zone = limb, blocked = armor, wound_bonus = rand(-20,10), sharpness = SHARP_EDGED)
|
||||
victim.Knockdown(2 SECONDS)
|
||||
playsound(victim, 'sound/weapons/whip.ogg', 50, TRUE, -1)
|
||||
@@ -364,17 +364,30 @@
|
||||
quality = NEGATIVE
|
||||
|
||||
/datum/spacevine_mutation/thorns/on_cross(obj/structure/spacevine/holder, mob/living/crosser)
|
||||
if(istype(crosser) && HAS_TRAIT(crosser, TRAIT_PIERCEIMMUNE))
|
||||
return
|
||||
|
||||
if(prob(THORN_MUTATION_CUT_PROB) && istype(crosser) && !isvineimmune(crosser))
|
||||
var/mob/living/victim = crosser
|
||||
victim.adjustBruteLoss(15)
|
||||
to_chat(victim, span_danger("You cut yourself on the thorny vines."))
|
||||
|
||||
/datum/spacevine_mutation/thorns/on_hit(obj/structure/spacevine/holder, mob/living/hitter, obj/item/item, expected_damage)
|
||||
if(iscarbon(hitter))
|
||||
var/mob/living/carbon/carbon_victim = hitter
|
||||
for(var/obj/item/clothing/worn_item in carbon_victim.get_equipped_items())
|
||||
if((worn_item.body_parts_covered & HANDS) && (worn_item.clothing_flags & THICKMATERIAL))
|
||||
return expected_damage
|
||||
|
||||
if(HAS_TRAIT(hitter, TRAIT_PIERCEIMMUNE) || HAS_TRAIT(hitter, TRAIT_PLANT_SAFE))
|
||||
return expected_damage
|
||||
|
||||
if(prob(THORN_MUTATION_CUT_PROB) && istype(hitter) && !isvineimmune(hitter))
|
||||
var/mob/living/victim = hitter
|
||||
victim.adjustBruteLoss(15)
|
||||
to_chat(victim, span_danger("You cut yourself on the thorny vines."))
|
||||
. = expected_damage
|
||||
|
||||
return expected_damage
|
||||
|
||||
/datum/spacevine_mutation/woodening
|
||||
name = "Hardened"
|
||||
@@ -486,7 +499,7 @@
|
||||
for(var/datum/spacevine_mutation/mutation in mutations)
|
||||
override += mutation.on_chem(src, chem)
|
||||
if(!override && istype(chem, /datum/reagent/toxin/plantbgone))
|
||||
if(prob(50))
|
||||
if(prob(75))
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/spacevine/proc/eat(mob/eater)
|
||||
@@ -656,7 +669,7 @@
|
||||
/// Actual maximum spread rate for this process tick
|
||||
var/spread_max = round(clamp(delta_time * (spread_base + start_spread_bonus), max(delta_time * minimum_spread_rate, 1), spread_cap))
|
||||
var/amount_processed = 0
|
||||
for(var/obj/structure/spacevine/vine as anything in growth_queue)
|
||||
for(var/obj/structure/spacevine/vine in growth_queue)
|
||||
if(!vine.can_spread)
|
||||
continue
|
||||
growth_queue -= vine
|
||||
@@ -714,6 +727,9 @@
|
||||
/obj/structure/spacevine/proc/spread()
|
||||
var/direction = pick(GLOB.cardinals)
|
||||
var/turf/stepturf = get_step(src, direction)
|
||||
if(!istype(stepturf))
|
||||
return
|
||||
|
||||
if(!isspaceturf(stepturf) && stepturf.Enter(src))
|
||||
var/obj/structure/spacevine/spot_taken = locate() in stepturf //Locates any vine on target turf. Calls that vine "spot_taken".
|
||||
var/datum/spacevine_mutation/vine_eating/eating = locate() in mutations //Locates the vine eating trait in our own seed and calls it E.
|
||||
|
||||
@@ -207,12 +207,11 @@
|
||||
return
|
||||
var/mob/living/simple_animal/slime/picked_slime
|
||||
for(var/mob/living/simple_animal/slime/slime in range(1,src))
|
||||
if(slime.loc == src)
|
||||
if(!CanReach(slime)) //don't take slimes behind glass panes or somesuch; also makes it ignore slimes inside the processor
|
||||
continue
|
||||
if(isslime(slime))
|
||||
if(slime.stat)
|
||||
picked_slime = slime
|
||||
break
|
||||
if(slime.stat)
|
||||
picked_slime = slime
|
||||
break
|
||||
if(!picked_slime)
|
||||
return
|
||||
var/datum/food_processor_process/recipe = PROCESSOR_SELECT_RECIPE(picked_slime)
|
||||
|
||||
@@ -630,11 +630,6 @@
|
||||
result = /obj/item/food/spaghetti/boiledspaghetti
|
||||
category = CAT_SPAGHETTI
|
||||
|
||||
/datum/crafting_recipe/food/microwave/khinkali
|
||||
reqs = list(/obj/item/food/rawkhinkali = 1)
|
||||
result = /obj/item/food/khinkali
|
||||
category = CAT_BREAD
|
||||
|
||||
/datum/crafting_recipe/food/microwave/onionrings
|
||||
reqs = list(/obj/item/food/onion_slice = 1)
|
||||
result = /obj/item/food/onionrings
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
attack_verb_continuous = list("chops", "slices", "cuts", "reaps")
|
||||
attack_verb_simple = list("chop", "slice", "cut", "reap")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
sharpness = SHARP_EDGED
|
||||
var/swiping = FALSE
|
||||
|
||||
/obj/item/scythe/Initialize(mapload)
|
||||
@@ -530,6 +531,7 @@
|
||||
speed = 9 SECONDS, \
|
||||
effectiveness = 105, \
|
||||
)
|
||||
AddElement(/datum/element/bane, mob_biotypes = MOB_PLANT, damage_multiplier = 0.5, requires_combat_mode = FALSE)
|
||||
|
||||
/obj/item/scythe/suicide_act(mob/living/user)
|
||||
user.visible_message(span_suicide("[user] is beheading [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
|
||||
@@ -541,18 +543,23 @@
|
||||
playsound(src, SFX_DESECRATION ,50, TRUE, -1)
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/scythe/pre_attack(atom/A, mob/living/user, params)
|
||||
if(swiping || !istype(A, /obj/structure/spacevine) || get_turf(A) == get_turf(user))
|
||||
/obj/item/scythe/pre_attack(atom/target, mob/living/user, params)
|
||||
if(!istype(target, /obj/structure/alien/resin/flower_bud) && !istype(target, /obj/structure/spacevine))
|
||||
return ..()
|
||||
if(swiping || get_turf(target) == get_turf(user))
|
||||
return ..()
|
||||
var/turf/user_turf = get_turf(user)
|
||||
var/dir_to_target = get_dir(user_turf, get_turf(A))
|
||||
var/dir_to_target = get_dir(user_turf, get_turf(target))
|
||||
swiping = TRUE
|
||||
var/static/list/scythe_slash_angles = list(0, 45, 90, -45, -90)
|
||||
for(var/i in scythe_slash_angles)
|
||||
var/turf/T = get_step(user_turf, turn(dir_to_target, i))
|
||||
for(var/obj/structure/spacevine/V in T)
|
||||
if(user.Adjacent(V))
|
||||
melee_attack_chain(user, V)
|
||||
var/turf/adjacent_turf = get_step(user_turf, turn(dir_to_target, i))
|
||||
for(var/obj/structure/spacevine/vine in adjacent_turf)
|
||||
if(user.Adjacent(vine))
|
||||
melee_attack_chain(user, vine)
|
||||
for(var/obj/structure/alien/resin/flower_bud/flower in adjacent_turf)
|
||||
if(user.Adjacent(flower))
|
||||
melee_attack_chain(user, flower)
|
||||
swiping = FALSE
|
||||
return TRUE
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,13 @@ GLOBAL_LIST_INIT(exp_specialmap, list(
|
||||
ROLE_MAINTENANCE_DRONE,
|
||||
ROLE_VENUSHUMANTRAP,
|
||||
ROLE_GHOST_ROLE,
|
||||
//Skyrat Edit Start - Custom Ghost roles
|
||||
ROLE_BLACK_MARKET_DEALER,
|
||||
ROLE_DS2,
|
||||
ROLE_FREIGHTER_CREW,
|
||||
ROLE_GHOST_CAFE,
|
||||
ROLE_PORT_TARKON,
|
||||
//Skyrat Edit Start - End Custom Ghost roles
|
||||
), // Ghost roles
|
||||
EXP_TYPE_GHOST = list() // dead people, observers
|
||||
))
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
static_lighting = TRUE
|
||||
requires_power = FALSE
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
|
||||
area_flags = BLOBS_ALLOWED | UNIQUE_AREA
|
||||
flags_1 = CAN_BE_DIRTY_1
|
||||
|
||||
//Survival Capsule
|
||||
|
||||
@@ -387,6 +387,7 @@
|
||||
RegisterSignal(soul, COMSIG_MOB_ATTACK_RANGED, PROC_REF(on_attack))
|
||||
RegisterSignal(soul, COMSIG_MOB_ATTACK_RANGED_SECONDARY, PROC_REF(on_secondary_attack))
|
||||
RegisterSignal(src, COMSIG_ATOM_INTEGRITY_CHANGED, PROC_REF(on_integrity_change))
|
||||
AddElement(/datum/element/bane, mob_biotypes = MOB_PLANT, damage_multiplier = 0.5, requires_combat_mode = FALSE)
|
||||
|
||||
/obj/item/soulscythe/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -213,21 +213,28 @@
|
||||
/obj/machinery/mineral/ore_redemption/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["unclaimedPoints"] = points
|
||||
|
||||
data["materials"] = list()
|
||||
var/datum/component/material_container/mat_container = materials.mat_container
|
||||
if (mat_container)
|
||||
for(var/mat in mat_container.materials)
|
||||
var/datum/material/M = mat
|
||||
var/amount = mat_container.materials[M]
|
||||
for(var/datum/material/material as anything in mat_container.materials)
|
||||
var/amount = mat_container.materials[material]
|
||||
var/sheet_amount = amount / MINERAL_MATERIAL_AMOUNT
|
||||
var/ref = REF(M)
|
||||
data["materials"] += list(list("name" = M.name, "id" = ref, "amount" = sheet_amount, "value" = ore_values[M.type]))
|
||||
data["materials"] += list(list(
|
||||
"name" = material.name,
|
||||
"id" = REF(material),
|
||||
"amount" = sheet_amount,
|
||||
"category" = "material",
|
||||
"value" = ore_values[material.type],
|
||||
))
|
||||
|
||||
data["alloys"] = list()
|
||||
for(var/v in stored_research.researched_designs)
|
||||
var/datum/design/D = SSresearch.techweb_design_by_id(v)
|
||||
data["alloys"] += list(list("name" = D.name, "id" = D.id, "amount" = can_smelt_alloy(D)))
|
||||
for(var/research in stored_research.researched_designs)
|
||||
var/datum/design/alloy = SSresearch.techweb_design_by_id(research)
|
||||
data["materials"] += list(list(
|
||||
"name" = alloy.name,
|
||||
"id" = alloy.id,
|
||||
"category" = "alloy",
|
||||
"amount" = can_smelt_alloy(alloy),
|
||||
))
|
||||
|
||||
if (!mat_container)
|
||||
data["disconnected"] = "local mineral storage is unavailable"
|
||||
@@ -236,8 +243,47 @@
|
||||
else if (materials.on_hold())
|
||||
data["disconnected"] = "mineral withdrawal is on hold"
|
||||
|
||||
var/obj/item/card/id/card
|
||||
if(isliving(user))
|
||||
var/mob/living/customer = user
|
||||
card = customer.get_idcard(hand_first = TRUE)
|
||||
if(card?.registered_account)
|
||||
data["user"] = list(
|
||||
"name" = card.registered_account.account_holder,
|
||||
"cash" = card.registered_account.account_balance,
|
||||
)
|
||||
|
||||
else if(issilicon(user))
|
||||
var/mob/living/silicon/silicon_player = user
|
||||
data["user"] = list(
|
||||
"name" = silicon_player.name,
|
||||
"cash" = "No valid account",
|
||||
)
|
||||
return data
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
var/datum/component/material_container/mat_container = materials.mat_container
|
||||
if (mat_container)
|
||||
for(var/datum/material/material as anything in mat_container.materials)
|
||||
var/obj/material_display = initial(material.sheet_type)
|
||||
data["material_icons"] += list(list(
|
||||
"id" = REF(material),
|
||||
"product_icon" = icon2base64(getFlatIcon(image(icon = initial(material_display.icon), icon_state = initial(material_display.icon_state)), no_anim=TRUE)),
|
||||
))
|
||||
|
||||
for(var/research in stored_research.researched_designs)
|
||||
var/datum/design/alloy = SSresearch.techweb_design_by_id(research)
|
||||
var/obj/alloy_display = initial(alloy.build_path)
|
||||
data["material_icons"] += list(list(
|
||||
"id" = alloy.id,
|
||||
"product_icon" = icon2base64(getFlatIcon(image(icon = initial(alloy_display.icon), icon_state = initial(alloy_display.icon_state)), no_anim=TRUE)),
|
||||
))
|
||||
|
||||
return data
|
||||
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
|
||||
@@ -819,6 +819,10 @@
|
||||
name = "Wisp"
|
||||
icon_state = "hair_wisp"
|
||||
|
||||
/datum/sprite_accessory/hair/ziegler
|
||||
name = "Ziegler"
|
||||
icon_state = "hair_ziegler"
|
||||
|
||||
/*
|
||||
/////////////////////////////////////
|
||||
/ =---------------------------= /
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
/// Is this corgi physically slow due to age, etc?
|
||||
var/is_slow = FALSE
|
||||
|
||||
/mob/living/basic/pet/dog/corgi/examine(mob/user)
|
||||
. = ..()
|
||||
if(access_card)
|
||||
. += "There appears to be [icon2html(access_card, user)] \a [access_card] pinned to [p_them()]."
|
||||
|
||||
/mob/living/basic/pet/dog/corgi/Destroy()
|
||||
QDEL_NULL(inventory_head)
|
||||
QDEL_NULL(inventory_back)
|
||||
@@ -794,7 +799,7 @@ GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list(
|
||||
maxHealth = 50
|
||||
gender = NEUTER
|
||||
damage_coeff = list(BRUTE = 3, BURN = 3, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
|
||||
butcher_results = list(/obj/item/organ/internal/brain = 1, /obj/item/organ/internal/heart = 1, /obj/item/food/breadslice = 3, \
|
||||
butcher_results = list(/obj/item/organ/internal/brain = 1, /obj/item/organ/internal/heart = 1, /obj/item/food/breadslice/plain = 3, \
|
||||
/obj/item/food/meat/slab = 2)
|
||||
response_harm_continuous = "takes a bite out of"
|
||||
response_harm_simple = "take a bite out of"
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
if(l_limbs_missing >= 2 && r_limbs_missing == 0)
|
||||
msg += "[t_He] look[p_s()] all right now.\n"
|
||||
else if(l_limbs_missing == 0 && r_limbs_missing >= 2)
|
||||
msg += "[t_He] really keeps to the left.\n"
|
||||
msg += "[t_He] really keep[p_s()] to the left.\n"
|
||||
else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
|
||||
msg += "[t_He] [p_do()]n't seem all there.\n"
|
||||
|
||||
|
||||
@@ -547,7 +547,7 @@
|
||||
|
||||
/datum/action/innate/integrate_extract/New(Target)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/action_item_overlay, CALLBACK(src, PROC_REF(locate_extract)))
|
||||
AddComponent(/datum/component/action_item_overlay, item_callback = CALLBACK(src, PROC_REF(locate_extract)))
|
||||
|
||||
/// Callback for /datum/component/action_item_overlay to find the slime extract from within the species
|
||||
/datum/action/innate/integrate_extract/proc/locate_extract()
|
||||
@@ -617,7 +617,7 @@
|
||||
|
||||
/datum/action/innate/use_extract/New(Target)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/action_item_overlay, CALLBACK(src, PROC_REF(locate_extract)))
|
||||
AddComponent(/datum/component/action_item_overlay, item_callback = CALLBACK(src, PROC_REF(locate_extract)))
|
||||
|
||||
/// Callback for /datum/component/action_item_overlay to find the slime extract from within the species
|
||||
/datum/action/innate/use_extract/proc/locate_extract()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user