Merge remote-tracking branch 'skyrat/master' into upstream_merge3

This commit is contained in:
Cyprex
2023-03-08 18:51:21 +01:00
258 changed files with 3117 additions and 2833 deletions
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -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" = (
+87 -28
View File
@@ -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
+1 -3
View File
@@ -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" = (
+1 -1
View File
@@ -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" = (
+1 -4
View File
@@ -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
+4 -3
View File
@@ -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" = (
-2
View File
@@ -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)
+17 -9
View File
@@ -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
+1 -1
View File
@@ -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), \
+18 -1
View File
@@ -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
+7
View File
@@ -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
+4
View File
@@ -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))
+8 -2
View File
@@ -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
+3
View File
@@ -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
+10 -4
View File
@@ -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
View File
@@ -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
-4
View File
@@ -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
View File
@@ -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]
+1 -1
View File
@@ -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))
+1 -1
View File
@@ -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]."))
+38 -4
View File
@@ -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
-20
View File
@@ -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
+97 -47
View File
@@ -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)
+3 -2
View File
@@ -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
+1 -1
View File
@@ -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"
+65
View File
@@ -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)
-2
View File
@@ -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
*/
+4 -1
View File
@@ -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
+6 -1
View File
@@ -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()
+21 -5
View File
@@ -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)
+11 -1
View File
@@ -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
+2 -1
View File
@@ -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.
+7 -5
View File
@@ -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
+4 -4
View File
@@ -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)
+2
View File
@@ -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
+8 -3
View File
@@ -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()
+5 -2
View File
@@ -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
View File
@@ -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
+11 -2
View File
@@ -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()
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+6
View File
@@ -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
+24 -3
View File
@@ -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."
+1 -1
View File
@@ -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"
+4 -2
View File
@@ -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()
+3 -2
View File
@@ -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."
+3 -1
View File
@@ -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))
/*
+3 -1
View File
@@ -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))
/*
+3 -1
View File
@@ -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)
+7 -1
View File
@@ -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()
+4 -11
View File
@@ -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()
+8 -4
View File
@@ -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)
+1 -1
View File
@@ -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()
+8 -8
View File
@@ -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
+1 -1
View File
@@ -32,7 +32,7 @@
. = ..()
packin_up()
/obj/machinery/computer/cargo/express/on_construction()
/obj/machinery/computer/cargo/express/on_construction(mob/user)
. = ..()
packin_up()
+1 -1
View File
@@ -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)
+3 -2
View File
@@ -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,
)
+7
View File
@@ -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. \
+27
View File
@@ -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."
+7
View File
@@ -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
+1 -1
View File
@@ -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)
+21 -5
View File
@@ -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
+14 -7
View File
@@ -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
*/
+7
View File
@@ -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)
. = ..()
+56 -10
View File
@@ -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"
/*
/////////////////////////////////////
/ =---------------------------= /
+6 -1
View File
@@ -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