Revert "Revert "Merge upstream""

This reverts commit e6bb4098c4.

# Conflicts:
#	_maps/RandomRuins/LavaRuins/skyrat/lavaland_surface_syndicate_base1_skyrat.dmm
#	_maps/RandomRuins/SpaceRuins/bus.dmm
#	_maps/RandomZLevels/blackmesa.dmm
#	_maps/map_files/generic/CentCom_skyrat_z2.dmm
#	_maps/shuttles/skyrat/goldeneye_cruiser.dmm
#	_maps/templates/lazy_templates/wizard_den.dmm
#	code/__DEFINES/callbacks.dm
#	code/datums/components/transforming.dm
#	code/datums/elements/bane.dm
#	code/datums/votes/map_vote.dm
#	code/game/objects/items/AI_modules/hacked.dm
#	code/game/objects/items/food/egg.dm
#	code/game/objects/items/stacks/sheets/glass.dm
#	code/modules/antagonists/fugitive/hunters/hunter.dm
#	code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm
#	code/modules/antagonists/traitor/objectives/kidnapping.dm
#	code/modules/art/statues.dm
#	code/modules/events/ghost_role/changeling_event.dm
#	code/modules/events/spacevine.dm
#	code/modules/mining/machine_redemption.dm
#	code/modules/mob/living/simple_animal/friendly/farm_animals.dm
#	code/modules/mob_spawn/mob_spawn.dm
#	code/modules/projectiles/guns/ballistic/pistol.dm
#	code/modules/projectiles/guns/ballistic/rifle.dm
#	code/modules/uplink/uplink_items.dm
#	code/modules/vending/autodrobe.dm
#	html/changelogs/archive/2023-03.yml
#	icons/mob/clothing/feet.dmi
#	icons/mob/clothing/under/costume.dmi
#	icons/mob/inhands/clothing/shoes_lefthand.dmi
#	icons/mob/inhands/clothing/shoes_righthand.dmi
#	icons/mob/inhands/clothing/suits_lefthand.dmi
#	icons/mob/inhands/clothing/suits_righthand.dmi
#	icons/mob/species/human/human_face.dmi
#	icons/obj/clothing/shoes.dmi
#	icons/obj/clothing/under/costume.dmi
#	modular_skyrat/master_files/code/datums/components/fullauto.dm
#	modular_skyrat/master_files/code/modules/clothing/under/jobs/security.dm
#	modular_skyrat/master_files/code/modules/projectiles/guns/gun.dm
#	modular_skyrat/master_files/icons/mob/clothing/under/civilian.dmi
#	modular_skyrat/master_files/icons/mob/clothing/under/civilian_digi.dmi
#	modular_skyrat/modules/aesthetics/guns/code/guns.dm
#	modular_skyrat/modules/aesthetics/guns/icons/guns.dmi
#	modular_skyrat/modules/blueshield/code/blueshield.dm
#	modular_skyrat/modules/customization/modules/clothing/under/misc.dm
#	modular_skyrat/modules/ghostcafe/code/ghost_role_spawners.dm
#	modular_skyrat/modules/gunsgalore/icons/guns/gunsgalore_guns40x32.dmi
#	modular_skyrat/modules/manufacturer_examine/code/gun_company_additions.dm
#	modular_skyrat/modules/manufacturer_examine/code/manufacturer_component.dm
#	modular_skyrat/modules/mapping/code/mob_spawns.dm
#	modular_skyrat/modules/modular_weapons/code/rifle.dm
#	modular_skyrat/modules/novaya_ert/code/automatic.dm
#	modular_skyrat/modules/sec_haul/code/guns/guns.dm
#	modular_skyrat/modules/tribal_extended/code/weapons/bow.dm
#	tgstation.dme
#	tgui/packages/tgui/interfaces/OreRedemptionMachine.js
#	tgui/packages/tgui/interfaces/VotePanel.tsx
This commit is contained in:
nevimer
2023-05-20 22:06:42 -04:00
parent 759c2dd73a
commit 424ed3d160
200 changed files with 1355 additions and 928 deletions
+1 -3
View File
@@ -83,9 +83,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
@@ -305,7 +305,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" = (
@@ -438,9 +438,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" = (
-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)
@@ -755,7 +754,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)
+1 -1
View File
@@ -550,7 +550,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), \
+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"
#define ROLE_CLOCK_CULTIST "Clock Cultist"
// SKYRAT EDIT END
@@ -109,7 +109,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
@@ -278,7 +278,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
@@ -291,18 +291,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
@@ -315,3 +315,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
+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
@@ -535,7 +535,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
@@ -26,8 +26,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
+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
@@ -59,7 +59,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
@@ -510,16 +510,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()
+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
@@ -1134,7 +1134,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
@@ -291,7 +291,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)
..()
+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
+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
@@ -340,7 +340,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))
@@ -457,4 +459,3 @@
armour_penetration = 50
attack_verb_continuous = list("smacks", "strikes", "cracks", "beats")
attack_verb_simple = list("smack", "strike", "crack", "beat")
@@ -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
@@ -412,7 +412,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
@@ -440,7 +440,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!"))
@@ -545,6 +544,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()
@@ -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)
@@ -284,4 +286,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
@@ -78,7 +78,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
@@ -21,6 +21,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.
@@ -131,10 +133,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()
@@ -146,3 +148,4 @@
/datum/traitor_objective/destroy_heirloom/ungenerate_objective()
target_item = null
target_mind = null
@@ -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,
))
@@ -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)
@@ -496,7 +496,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 * SHEET_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)
@@ -146,8 +146,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()
. = ..()
@@ -67,16 +67,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()
. = ..()
@@ -245,13 +249,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
@@ -24,7 +24,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
@@ -78,7 +78,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
@@ -140,11 +140,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
@@ -240,7 +240,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)
@@ -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)
@@ -642,11 +642,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
@@ -524,6 +524,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)
@@ -532,6 +533,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!"))
@@ -543,18 +545,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
*/
@@ -266,7 +266,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"
+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
@@ -389,6 +389,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)
. = ..()
@@ -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
@@ -83,6 +83,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)
@@ -797,7 +802,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"
@@ -215,7 +215,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"
@@ -572,7 +572,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()
@@ -642,7 +642,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()
+1
View File
@@ -591,6 +591,7 @@
return
if(new_resting == resting)
return
. = resting
resting = new_resting
if(new_resting)
+11 -10
View File
@@ -871,16 +871,17 @@
var/hrefpart = "<a href='?src=[REF(src)];track=[html_encode(namepart)]'>"
var/jobpart = "Unknown"
if (isliving(speaker))
var/mob/living/living_speaker = speaker
if(living_speaker.job)
jobpart = "[living_speaker.job]"
if (istype(speaker, /obj/effect/overlay/holo_pad_hologram))
var/obj/effect/overlay/holo_pad_hologram/holo = speaker
if(holo.Impersonation?.job)
jobpart = "[holo.Impersonation.job]"
else if(usr?.job) // not great, but AI holograms have no other usable ref
jobpart = "[usr.job]"
if(!HAS_TRAIT(speaker, TRAIT_UNKNOWN)) //don't fetch the speaker's job in case they have something that conseals their identity completely
if (isliving(speaker))
var/mob/living/living_speaker = speaker
if(living_speaker.job)
jobpart = "[living_speaker.job]"
if (istype(speaker, /obj/effect/overlay/holo_pad_hologram))
var/obj/effect/overlay/holo_pad_hologram/holo = speaker
if(holo.Impersonation?.job)
jobpart = "[holo.Impersonation.job]"
else if(usr?.job) // not great, but AI holograms have no other usable ref
jobpart = "[usr.job]"
var/rendered = "<i><span class='game say'>[start][span_name("[hrefpart][namepart] ([jobpart])</a> ")]<span class='message'>[treated_message]</span></span></i>"
@@ -14,7 +14,7 @@
lighting_cutoff_green = 8
lighting_cutoff_blue = 5
obj_damage = 10
butcher_results = list(/obj/item/clothing/head/costume/crown = 1,)
butcher_results = list(/obj/item/food/meat/slab/mouse = 2, /obj/item/clothing/head/costume/crown = 1)
response_help_continuous = "glares at"
response_help_simple = "glare at"
response_disarm_continuous = "skoffs at"
@@ -20,6 +20,7 @@
opacity = FALSE
canSmoothWith = null
smoothing_flags = NONE
density = FALSE
/// The amount of time it takes to create a venus human trap.
var/growth_time = 120 SECONDS
var/growth_icon = 0
@@ -59,6 +60,15 @@
damage_amount = 0
. = ..()
/obj/structure/alien/resin/flower_bud/attacked_by(obj/item/item, mob/living/user)
var/damage_dealt = item.force
if(item.damtype == BURN)
damage_dealt *= 4
if(item.get_sharpness())
damage_dealt *= 16 // alien resin applies 75% reduction to brute damage so this actually x4 damage
take_damage(damage_dealt, item.damtype, MELEE, 1)
/obj/structure/alien/resin/flower_bud/Destroy()
QDEL_LIST(vines)
QDEL_NULL(countdown)
@@ -5,6 +5,7 @@
icon = 'icons/effects/spacevines.dmi'
icon_state = "bud0"
mob_type = /mob/living/simple_animal/hostile/venus_human_trap
density = FALSE
prompt_name = "venus human trap"
you_are_text = "You are a venus human trap."
flavour_text = "You are a venus human trap! Protect the kudzu at all costs, and feast on those who oppose you!"
@@ -300,6 +300,7 @@
/obj/item/modular_computer/pda/bar
name = "bartender PDA"
greyscale_colors = "#333333#C7C7C7"
inserted_item = /obj/item/pen/fountain
/obj/item/modular_computer/pda/clown
name = "clown PDA"
+3 -3
View File
@@ -548,7 +548,7 @@
playsound(src, 'sound/items/handling/standard_stamp.ogg', 50, vary = TRUE)
update_appearance()
update_static_data(user, ui)
update_static_data_for_all_viewers()
return TRUE
if("add_text")
var/paper_input = params["text"]
@@ -594,7 +594,7 @@
log_paper("[key_name(user)] wrote to [name]: \"[paper_input]\"")
to_chat(user, "You have added to your paper masterpiece!");
update_static_data(user, ui)
update_static_data_for_all_viewers()
update_appearance()
return TRUE
if("fill_input_field")
@@ -635,7 +635,7 @@
if(!add_field_input(field_key, field_text, writing_implement_data["font"], writing_implement_data["color"], writing_implement_data["use_bold"], user.real_name))
log_paper("[key_name(user)] tried to write to field [field_key] when it already has data, with the following text: [field_text]")
update_static_data(user, ui)
update_static_data_for_all_viewers()
return TRUE
/obj/item/paper/proc/get_input_field_count(raw_text)
+8 -3
View File
@@ -279,7 +279,9 @@
throwforce_on = 35, \
throw_speed_on = 4, \
sharpness_on = SHARP_EDGED, \
w_class_on = WEIGHT_CLASS_NORMAL)
w_class_on = WEIGHT_CLASS_NORMAL, \
inhand_icon_change = FALSE, \
)
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
RegisterSignal(src, COMSIG_DETECTIVE_SCANNED, PROC_REF(on_scan))
@@ -366,7 +368,9 @@
AddComponent(/datum/component/transforming, \
throwforce_on = 5, \
w_class_on = WEIGHT_CLASS_SMALL, \
sharpness_on = TRUE)
sharpness_on = TRUE, \
inhand_icon_change = FALSE, \
)
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(toggle_screwdriver))
AddElement(/datum/element/update_icon_updates_onmob)
@@ -385,7 +389,8 @@
SIGNAL_HANDLER
extended = active
if(user)
balloon_alert(user, "[extended ? "extended" : "retracted"]!")
balloon_alert(user, "[extended ? "extended" : "retracted"]")
playsound(src, 'sound/weapons/batonextend.ogg', 50, TRUE)
if(!extended)
tool_behaviour = initial(tool_behaviour)
+1 -1
View File
@@ -102,7 +102,7 @@
DropFuel()
return ..()
/obj/machinery/power/port_gen/pacman/on_construction()
/obj/machinery/power/port_gen/pacman/on_construction(mob/user)
var/obj/item/circuitboard/machine/pacman/our_board = circuit
if(our_board.high_production_profile)
icon_state = "portgen1_0"
+2 -2
View File
@@ -1,4 +1,3 @@
/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR GUN.DM
#define DUALWIELD_PENALTY_EXTRA_MULTIPLIER 1.4
#define FIRING_PIN_REMOVAL_DELAY 50
@@ -75,6 +74,8 @@
pin = new pin(src)
add_seclight_point()
give_gun_safeties() // SKYRAT EDIT ADDITION - GUN SAFETIES
give_manufacturer_examine() // SKYRAT EDIT ADDITON - MANUFACTURER EXAMINE
/obj/item/gun/Destroy()
if(isobj(pin)) //Can still be the initial path, then we skip
@@ -576,4 +577,3 @@
#undef FIRING_PIN_REMOVAL_DELAY
#undef DUALWIELD_PENALTY_EXTRA_MULTIPLIER
*/
@@ -1,4 +1,3 @@
/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR AUTOMATIC.DM
/obj/item/gun/ballistic/automatic
w_class = WEIGHT_CLASS_NORMAL
can_suppress = TRUE
@@ -356,4 +355,3 @@
actions_types = list()
fire_sound = 'sound/weapons/laser.ogg'
casing_ejector = FALSE
*/
@@ -11,7 +11,6 @@
w_class = WEIGHT_CLASS_NORMAL
pin = /obj/item/firing_pin/implant/pindicate
bolt_type = BOLT_TYPE_NO_BOLT
has_gun_safety = FALSE //SKYRAT EDIT
/obj/item/gun/ballistic/revolver/grenadelauncher/unrestricted
pin = /obj/item/firing_pin
@@ -40,7 +39,6 @@
mag_type = /obj/item/ammo_box/magazine/m75
burst_size = 1
fire_delay = 0
fire_select_modes = list(SELECT_SEMI_AUTOMATIC) //SKYRAT EDIT CHANGE
casing_ejector = FALSE
/obj/item/gun/ballistic/rocketlauncher
@@ -145,7 +145,6 @@
fire_delay = 10 //Skyrat edit - Original: 0
pin = /obj/item/firing_pin/implant/pindicate
fire_sound = 'sound/weapons/gun/shotgun/shot_alt.ogg'
fire_select_modes = list(SELECT_SEMI_AUTOMATIC) //SKYRAT EDIT CHANGE
mag_display = TRUE
empty_indicator = TRUE
empty_alarm = TRUE
@@ -113,15 +113,13 @@
item_flags = NEEDS_PERMIT | SLOWS_WHILE_IN_HAND
can_charge = FALSE
var/obj/item/minigunpack/ammo_pack
fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)//SKYRAT EDIT ADDITION
/obj/item/gun/energy/minigun/Initialize(mapload)
if(!istype(loc, /obj/item/minigunpack)) //We should spawn inside an ammo pack so let's use that one.
return INITIALIZE_HINT_QDEL //No pack, no gun
ammo_pack = loc
AddElement(/datum/element/update_icon_blocker)
//AddComponent(/datum/component/automatic_fire, 0.2 SECONDS) SKYRAT EDIT REMOVAL
AddComponent(/datum/component/automatic_fire, 0.2 SECONDS)
return ..()
/obj/item/gun/energy/minigun/Destroy()
@@ -381,7 +381,7 @@
/obj/item/gun/energy/tesla_cannon/Initialize(mapload)
. = ..()
//AddComponent(/datum/component/automatic_fire, 0.1 SECONDS) SKYRAT EDIT REMOVAL
AddComponent(/datum/component/automatic_fire, 0.1 SECONDS)
/obj/item/gun/energy/marksman_revolver
name = "marksman revolver"
@@ -194,7 +194,6 @@
pixel_x = 0
force = 4
trigger_guard = TRIGGER_GUARD_ALLOW_ALL
has_gun_safety = FALSE // SKYRAT EDIT
/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
visible_message(span_danger("[user] shoots the blowgun!"))
@@ -73,7 +73,7 @@
return
mytray.mutation_roll(user)
mytray.adjust_toxic(3) //It is still toxic, mind you, but not to the same degree.
#define LIQUID_PLASMA_BP (50+T0C)
@@ -366,7 +366,10 @@
. = ..()
if(istype(exposed_obj, /obj/structure/alien/weeds))
var/obj/structure/alien/weeds/alien_weeds = exposed_obj
alien_weeds.take_damage(rand(15,35), BRUTE, 0) // Kills alien weeds pretty fast
alien_weeds.take_damage(rand(15, 35), BRUTE, 0) // Kills alien weeds pretty fast
if(istype(exposed_obj, /obj/structure/alien/resin/flower_bud))
var/obj/structure/alien/resin/flower_bud/flower = exposed_obj
flower.take_damage(rand(30, 50), BRUTE, 0)
else if(istype(exposed_obj, /obj/structure/glowshroom)) //even a small amount is enough to kill it
qdel(exposed_obj)
else if(istype(exposed_obj, /obj/structure/spacevine))
@@ -377,9 +380,13 @@
. = ..()
var/damage = min(round(0.4 * reac_volume, 0.1), 10)
if(exposed_mob.mob_biotypes & MOB_PLANT)
exposed_mob.adjustToxLoss(damage, required_biotype = affected_biotype)
// spray bottle emits 5u so it's dealing ~15 dmg per spray
exposed_mob.adjustToxLoss(damage * 20, required_biotype = affected_biotype)
return
if(!(methods & VAPOR) || !iscarbon(exposed_mob))
return
var/mob/living/carbon/exposed_carbon = exposed_mob
if(!exposed_carbon.wear_mask)
exposed_carbon.adjustToxLoss(damage, required_biotype = affected_biotype)
@@ -165,7 +165,7 @@
spawner.antag_team = team
if(candidates.len > 0)
var/mob/our_candidate = candidates[1]
spawner.create(our_candidate)
spawner.create_from_ghost(our_candidate)
spawner.antag_team.players_spawned += (our_candidate.ckey)
candidates.Splice(1, 2)
notify_ghosts(
+2 -3
View File
@@ -544,9 +544,8 @@
if(time_left <= 0)
//move each escape pod to its corresponding escape dock
for(var/A in SSshuttle.mobile_docking_ports)
var/obj/docking_port/mobile/M = A
M.on_emergency_dock()
for(var/obj/docking_port/mobile/port as anything in SSshuttle.mobile_docking_ports)
port.on_emergency_dock()
// now move the actual emergency shuttle to centcom
// unless the shuttle is "hijacked"
+2 -1
View File
@@ -1164,7 +1164,8 @@
//Called when emergency shuttle docks at centcom
/obj/docking_port/mobile/proc/on_emergency_dock()
//Mapping a new docking point for each ship mappers could potentially want docking with centcom would take up lots of space, just let them keep flying off into the sunset for their greentext
// Mapping a new docking point for each ship mappers could potentially want docking with centcom would take up lots of space,
// just let them keep flying off "into the sunset" for their greentext.
if(launch_status == ENDGAME_LAUNCHED)
launch_status = ENDGAME_TRANSIT
+3 -3
View File
@@ -540,14 +540,14 @@
var/selected_reagent = tgui_input_list(usr, "Select reagent to filter", "Whitelist reagent", GLOB.chemical_name_list)
if(!selected_reagent)
return TRUE
var/chem_id = get_chem_id(selected_reagent)
if(!chem_id)
return TRUE
if(!(chem_id in whitelist))
whitelist[chem_id] = selected_reagent
if("remove")

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