Merge branch 'master' into glassware

This commit is contained in:
TrilbySpaceClone
2019-12-07 12:50:32 -05:00
932 changed files with 16815 additions and 10794 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -103794,10 +103794,10 @@
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
"dsI" = (
/obj/structure/sign/warning/nosmoking,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/obj/machinery/smartfridge/organ/preloaded,
/turf/closed/wall,
/area/medical/surgery)
"dsJ" = (
@@ -127428,6 +127428,10 @@
/obj/item/assembly/signaler,
/turf/open/floor/plating,
/area/crew_quarters/abandoned_gambling_den)
"mMC" = (
/obj/structure/sign/warning/nosmoking,
/turf/closed/wall,
/area/medical/surgery)
"mQE" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -174919,7 +174923,7 @@ dkv
dma
dma
dma
dma
mMC
dsI
dro
dvz

View File

@@ -62776,6 +62776,9 @@
"cro" = (
/obj/structure/bed/roller,
/obj/machinery/iv_drip,
/obj/structure/sign/warning/nosmoking{
pixel_x = -28
},
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"crq" = (
@@ -63296,9 +63299,6 @@
dir = 1;
pixel_y = -22
},
/obj/structure/sign/warning/nosmoking{
pixel_x = -28
},
/obj/machinery/iv_drip,
/obj/effect/turf_decal/tile/blue,
/obj/effect/turf_decal/tile/blue{
@@ -83997,6 +83997,10 @@
},
/turf/open/floor/plating,
/area/maintenance/port)
"qnB" = (
/obj/machinery/smartfridge/organ/preloaded,
/turf/closed/wall,
/area/medical/surgery)
"qqg" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 6
@@ -104229,7 +104233,7 @@ cia
cia
cpX
cia
cia
qnB
cia
ceu
dyg

View File

@@ -42880,6 +42880,12 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/r_wall,
/area/maintenance/disposal/incinerator)
"uvp" = (
/obj/machinery/smartfridge/organ/preloaded{
pixel_y = 2
},
/turf/closed/wall,
/area/medical/medbay/zone3)
"uxJ" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/public/glass{
@@ -81595,7 +81601,7 @@ aSh
bcf
bcW
blt
aSh
uvp
aOL
bfA
bfX

View File

@@ -37749,6 +37749,9 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
/obj/machinery/light_switch{
pixel_x = -22
},
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"bIp" = (
@@ -38828,10 +38831,6 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 1
},
/obj/machinery/firealarm{
dir = 8;
pixel_x = -26
},
/obj/effect/turf_decal/tile/blue{
dir = 1
},
@@ -39305,15 +39304,16 @@
/obj/item/clothing/gloves/color/latex,
/obj/item/clothing/mask/surgical,
/obj/item/clothing/suit/apron/surgical,
/obj/machinery/light_switch{
pixel_x = -22
},
/obj/effect/turf_decal/tile/blue{
dir = 1
},
/obj/effect/turf_decal/tile/blue{
dir = 8
},
/obj/machinery/firealarm{
dir = 8;
pixel_x = -26
},
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"bLN" = (
@@ -55674,6 +55674,10 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
"jdA" = (
/obj/machinery/smartfridge/organ/preloaded,
/turf/closed/wall,
/area/medical/surgery)
"jeq" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -92221,7 +92225,7 @@ bFU
bFU
bIn
bJt
bFU
jdA
bFU
bFU
bFU

View File

@@ -379,15 +379,6 @@
/obj/item/camera,
/turf/open/indestructible/clock_spawn_room,
/area/reebe/city_of_cogs)
"Nz" = (
/obj/structure/table/bronze,
/obj/item/implantcase,
/obj/item/implantcase,
/obj/item/implantcase,
/obj/item/implanter,
/obj/item/storage/backpack/duffelbag/sec/surgery,
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
"NH" = (
/obj/structure/table/bronze,
/obj/item/taperecorder,
@@ -409,10 +400,6 @@
"WT" = (
/turf/closed/wall/clockwork,
/area/reebe)
"Yy" = (
/obj/structure/table/optable,
/turf/open/floor/clockwork/reebe,
/area/reebe/city_of_cogs)
(1,1,1) = {"
zb
@@ -33918,7 +33905,7 @@ ab
ai
bE
aj
Yy
aj
aj
aj
aA
@@ -34175,7 +34162,7 @@ ab
ah
al
aj
Nz
aj
aj
aC
ah

View File

@@ -41,6 +41,12 @@
//Create a list global that is initialized as an empty list
#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list())
// Create a typed list global with an initializer expression
#define GLOBAL_LIST_INIT_TYPED(X, Typepath, InitValue) GLOBAL_RAW(/list##Typepath/X); GLOBAL_MANAGED(X, InitValue)
// Create a typed list global that is initialized as an empty list
#define GLOBAL_LIST_EMPTY_TYPED(X, Typepath) GLOBAL_LIST_INIT_TYPED(X, Typepath, list())
//Create a typed global with an initializer expression
#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue)

View File

@@ -69,6 +69,7 @@
#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device"
#define ADMIN_PUNISHMENT_FIREBALL "Fireball"
#define ADMIN_PUNISHMENT_ROD "Immovable Rod"
#define ADMIN_PUNISHMENT_SUPPLYPOD_QUICK "Supply Pod (Quick)"
#define ADMIN_PUNISHMENT_SUPPLYPOD "Supply Pod"
#define ADMIN_PUNISHMENT_MAZING "Puzzle"
#define ADMIN_PUNISHMENT_PIE "Cream Pie"

View File

@@ -147,6 +147,20 @@
#define CANATMOSPASS(A, O) ( A.CanAtmosPass == ATMOS_PASS_PROC ? A.CanAtmosPass(O) : ( A.CanAtmosPass == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPass ) )
#define CANVERTICALATMOSPASS(A, O) ( A.CanAtmosPassVertical == ATMOS_PASS_PROC ? A.CanAtmosPass(O, TRUE) : ( A.CanAtmosPassVertical == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPassVertical ) )
//OPEN TURF ATMOS
#define OPENTURF_DEFAULT_ATMOS "o2=22;n2=82;TEMP=293.15" //the default air mix that open turfs spawn
#define TCOMMS_ATMOS "n2=100;TEMP=80" //-193,15°C telecommunications. also used for xenobiology slime killrooms
#define AIRLESS_ATMOS "TEMP=2.7" //space
#define FROZEN_ATMOS "o2=22;n2=82;TEMP=180" //-93.15°C snow and ice turfs
#define BURNMIX_ATMOS "o2=2500;plasma=5000;TEMP=370" //used in the holodeck burn test program
//ATMOSPHERICS DEPARTMENT GAS TANK TURFS
#define ATMOS_TANK_N2O "n2o=6000;TEMP=293.15"
#define ATMOS_TANK_CO2 "co2=50000;TEMP=293.15"
#define ATMOS_TANK_PLASMA "plasma=70000;TEMP=293.15"
#define ATMOS_TANK_O2 "o2=100000;TEMP=293.15"
#define ATMOS_TANK_N2 "n2=100000;TEMP=293.15"
#define ATMOS_TANK_AIRMIX "o2=2644;n2=10580;TEMP=293.15"
//LAVALAND
#define LAVALAND_EQUIPMENT_EFFECT_PRESSURE 50 //what pressure you have to be under to increase the effect of equipment meant for lavaland
#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=23;TEMP=300"

View File

@@ -11,6 +11,7 @@
#define STYLE_FRUIT 11
#define STYLE_INVISIBLE 12
#define STYLE_GONDOLA 13
#define STYLE_SEETHROUGH 14
#define POD_ICON_STATE 1
#define POD_NAME 2
@@ -29,5 +30,6 @@
list("honkpod", "\improper HONK pod", "A brightly-colored supply pod. It likely originated from the Clown Federation."),\
list("fruitpod", "\improper Orange", "An angry orange."),\
list("", "\improper S.T.E.A.L.T.H. pod MKVII", "A supply pod that, under normal circumstances, is completely invisible to conventional methods of detection. How are you even seeing this?"),\
list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency.")\
list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency."),\
list("", "", "")\
)

View File

@@ -98,6 +98,7 @@
//the define for visible message range in combat
#define COMBAT_MESSAGE_RANGE 3
#define DEFAULT_MESSAGE_RANGE 7
//Shove knockdown lengths (deciseconds)
#define SHOVE_KNOCKDOWN_SOLID 30

View File

@@ -5,6 +5,17 @@
#define COMPONENT_INCOMPATIBLE 1
#define COMPONENT_NOTRANSFER 2
#define ELEMENT_INCOMPATIBLE 1 // Return value to cancel attaching
// /datum/element flags
/// Causes the detach proc to be called when the host object is being deleted
#define ELEMENT_DETACH (1 << 0)
/**
* Only elements created with the same arguments given after `id_arg_index` share an element instance
* The arguments are the same when the text and number values are the same and all other values have the same ref
*/
#define ELEMENT_BESPOKE (1 << 1)
// How multiple components of the exact same type are handled in the same datum
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
@@ -28,7 +39,7 @@
#define COMSIG_COMPONENT_ADDED "component_added" //when a component is added to a datum: (/datum/component)
#define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (/datum/component)
#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted" //before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation
#define COMSIG_PARENT_QDELETED "parent_qdeleted" //after a datum's Destroy() is called: (force, qdel_hint), at this point none of the other components chose to interrupt qdel and Destroy has been called
#define COMSIG_PARENT_QDELETING "parent_qdeleting" //just before a datum's Destroy() is called: (force), at this point none of the other components chose to interrupt qdel and Destroy will be called
// /atom signals
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
@@ -121,7 +132,15 @@
#define COMPONENT_CANCEL_THROW 1
#define COMSIG_MOVABLE_POST_THROW "movable_post_throw" //from base of atom/movable/throw_at(): (datum/thrownthing, spin)
#define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" //from base of atom/movable/onTransitZ(): (old_z, new_z)
#define COMSIG_MOVABLE_SECLUDED_LOCATION "movable_secluded" //called when the movable is placed in an unaccessible area, used for stationloving: ()
#define COMSIG_MOVABLE_HEAR "movable_hear" //from base of atom/movable/Hear(): (message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
#define HEARING_MESSAGE 1
#define HEARING_SPEAKER 2
// #define HEARING_LANGUAGE 3
#define HEARING_RAW_MESSAGE 4
/* #define HEARING_RADIO_FREQ 5
#define HEARING_SPANS 6
#define HEARING_MESSAGE_MODE 7 */
#define COMSIG_MOVABLE_DISPOSING "movable_disposing" //called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source)
#define COMSIG_MOVABLE_TELEPORTED "movable_teleported" //from base of do_teleport(): (channel, turf/origin, turf/destination)
@@ -140,6 +159,7 @@
#define COMSIG_MOB_HUD_CREATED "mob_hud_created" //from base of mob/create_mob_hud(): ()
#define COMSIG_MOB_ATTACK_HAND "mob_attack_hand" //from base of
#define COMSIG_MOB_ITEM_ATTACK "mob_item_attack" //from base of /obj/item/attack(): (mob/M, mob/user)
#define COMPONENT_ITEM_NO_ATTACK 1
#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged" //from base of mob/RangedAttack(): (atom/A, params)
#define COMSIG_MOB_THROW "mob_throw" //from base of /mob/throw_item(): (atom/target)
@@ -305,3 +325,11 @@
//Ouch my toes!
#define CALTROP_BYPASS_SHOES 1
#define CALTROP_IGNORE_WALKERS 2
//Xenobio hotkeys
#define COMSIG_XENO_SLIME_CLICK_CTRL "xeno_slime_click_ctrl" //from slime CtrlClickOn(): (/mob)
#define COMSIG_XENO_SLIME_CLICK_ALT "xeno_slime_click_alt" //from slime AltClickOn(): (/mob)
#define COMSIG_XENO_SLIME_CLICK_SHIFT "xeno_slime_click_shift" //from slime ShiftClickOn(): (/mob)
#define COMSIG_XENO_TURF_CLICK_SHIFT "xeno_turf_click_shift" //from turf ShiftClickOn(): (/mob)
#define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt" //from turf AltClickOn(): (/mob)
#define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl" //from monkey CtrlClickOn(): (/mob)

View File

@@ -1,10 +1,10 @@
#define DONATOR_GROUP_TIER_1_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_1_donators
#define DONATOR_GROUP_TIER_2_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_2_donators
#define DONATOR_GROUP_TIER_3_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_3_donators
#define DONATOR_GROUP_TIER_1_CONFIG_PATH /datum/config_entry/multi_keyed_flag/donator_group/tier_1_donators
#define DONATOR_GROUP_TIER_2_CONFIG_PATH /datum/config_entry/multi_keyed_flag/donator_group/tier_2_donators
#define DONATOR_GROUP_TIER_3_CONFIG_PATH /datum/config_entry/multi_keyed_flag/donator_group/tier_3_donators
#define DONATOR_GROUP_TIER_1_CONFIG_SUBPATH keyed_list/donator_group/tier_1_donators
#define DONATOR_GROUP_TIER_2_CONFIG_SUBPATH keyed_list/donator_group/tier_2_donators
#define DONATOR_GROUP_TIER_3_CONFIG_SUBPATH keyed_list/donator_group/tier_3_donators
#define DONATOR_GROUP_TIER_1_CONFIG_SUBPATH multi_keyed_flag/donator_group/tier_1_donators
#define DONATOR_GROUP_TIER_2_CONFIG_SUBPATH multi_keyed_flag/donator_group/tier_2_donators
#define DONATOR_GROUP_TIER_3_CONFIG_SUBPATH multi_keyed_flag/donator_group/tier_3_donators
#define TIER_1_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_1_CONFIG_SUBPATH)
#define TIER_2_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_2_CONFIG_SUBPATH)

View File

@@ -32,6 +32,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define TESLA_IGNORE_1 (1<<13) // TESLA_IGNORE grants immunity from being targeted by tesla-style electricity
#define INITIALIZED_1 (1<<14) //Whether /atom/Initialize() has already run for the object
#define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff.
#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16) /// should not get harmed if this gets caught by an explosion?
//turf-only flags
#define NOJAUNT_1 (1<<0)

View File

@@ -4,9 +4,9 @@
#define WEIGHT_CLASS_TINY 1 //Usually items smaller then a human hand, ex: Playing Cards, Lighter, Scalpel, Coins/Money
#define WEIGHT_CLASS_SMALL 2 //Pockets can hold small and tiny items, ex: Flashlight, Multitool, Grenades, GPS Device
#define WEIGHT_CLASS_NORMAL 3 //Standard backpacks can carry tiny, small & normal items, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets
#define WEIGHT_CLASS_BULKY 4 //Items that can be weilded or equipped but not stored in an inventory, ex: Defibrillator, Backpack, Space Suits
#define WEIGHT_CLASS_HUGE 5 //Usually represents objects that require two hands to operate, ex: Shotgun, Two Handed Melee Weapons
#define WEIGHT_CLASS_GIGANTIC 6 //Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe
#define WEIGHT_CLASS_BULKY 4 //Items that can be weilded or equipped but not stored in a normal bag, ex: Defibrillator, Backpack, Space Suits
#define WEIGHT_CLASS_HUGE 5 //Usually represents objects that require two hands to operate, ex: Shotgun, Two Handed Melee Weapons - Can not fit in Boh
#define WEIGHT_CLASS_GIGANTIC 6 //Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe - Can not fit in Boh
//Inventory depth: limits how many nested storage items you can access directly.
//1: stuff in mob, 2: stuff in backpack, 3: stuff in box in backpack, etc

View File

@@ -100,3 +100,8 @@
#define NUKE_OFF_UNLOCKED 1
#define NUKE_ON_TIMING 2
#define NUKE_ON_EXPLODING 3
//these flags are used to tell the DNA modifier if a plant gene cannot be extracted or modified.
#define PLANT_GENE_REMOVABLE (1<<0)
#define PLANT_GENE_EXTRACTABLE (1<<1)

View File

@@ -25,23 +25,22 @@
#define NO_MAT_REDEMPTION (1<<5) //Stops you from putting things like an RCD or other items into an ORM or protolathe for materials.
#define DROPDEL (1<<6) //When dropped, it calls qdel on itself
#define NOBLUDGEON (1<<7) //when an item has this it produces no "X has been hit by Y with Z" message in the default attackby()
#define ABSTRACT (1<<8) //for all things that are technically items but used for various different stuff
#define ABSTRACT (1<<8) //for all things that are technically items but used for various different stuff
#define IMMUTABLE_SLOW (1<<9) //When players should not be able to change the slowdown of the item (Speed potions, ect)
#define SURGICAL_TOOL (1<<10) //Tool commonly used for surgery: won't attack targets in an active surgical operation on help intent (in case of mistakes)
#define NO_UNIFORM_REQUIRED (1<<11) //Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
#define NO_UNIFORM_REQUIRED (1<<11) //Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
// Flags for the clothing_flags var on /obj/item/clothing
#define LAVAPROTECT (1<<0)
#define STOPSPRESSUREDAMAGE (1<<1) //SUIT and HEAD items which stop pressure damage. To stop you taking all pressure damage you must have both a suit and head item with this flag.
#define BLOCK_GAS_SMOKE_EFFECT (1<<2) //blocks the effect that chemical clouds would have on a mob --glasses, mask and helmets ONLY!
#define ALLOWINTERNALS (1<<3) //mask allows internals
#define ALLOWINTERNALS (1<<3) //mask allows internals
#define NOSLIP (1<<4) //prevents from slipping on wet floors, in space etc
#define THICKMATERIAL (1<<5) //prevents syringes, parapens and hypos if the external suit or helmet (if targeting head) has this flag. Example: space suits, biosuit, bombsuits, thick suits that cover your body.
#define VOICEBOX_TOGGLABLE (1<<6) //The voicebox in this clothing can be toggled.
#define VOICEBOX_DISABLED (1<<7) //The voicebox is currently turned off.
#define SNUG_FIT (1<<8) //Prevents knock-off from things like hat-throwing.
#define ANTI_TINFOIL_MANEUVER (1<<9) //Hats with negative effects when worn (i.e the tinfoil hat).
#define IGNORE_HAT_TOSS (1<<8) //Hats with negative effects when worn (i.e the tinfoil hat).
// Flags for the organ_flags var on /obj/item/organ
@@ -50,4 +49,4 @@
#define ORGAN_FAILING (1<<2) //Failing organs perform damaging effects until replaced or fixed
#define ORGAN_EXTERNAL (1<<3) //Was this organ implanted/inserted/etc, if true will not be removed during species change.
#define ORGAN_VITAL (1<<4) //Currently only the brain
#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances

View File

@@ -75,8 +75,16 @@
#define LINGHIVE_LING 2
#define LINGHIVE_LINK 3
//whether the emote is visible or audible.
#define EMOTE_VISIBLE 1
#define EMOTE_AUDIBLE 2
//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam
#define MAX_MESSAGE_LEN 2048 //Citadel edit: What's the WORST that could happen?
#define MAX_NAME_LEN 42
#define MAX_BROADCAST_LEN 512
#define MAX_CHARTER_LEN 80
// Audio/Visual Flags. Used to determine what sense are required to notice a message.
#define MSG_VISUAL (1<<0)
#define MSG_AUDIBLE (1<<1)

View File

@@ -7,6 +7,8 @@
#define STATUS_EFFECT_REPLACE 2 //if it allows only one, but new instances replace
#define STATUS_EFFECT_REFRESH 3 // if it only allows one, and new instances just instead refresh the timer
///////////
// BUFFS //
///////////
@@ -56,6 +58,8 @@
#define MAX_MANIA_SEVERITY 100 //how high the mania severity can go
#define MANIA_DAMAGE_TO_CONVERT 90 //how much damage is required before it'll convert affected targets
#define STATUS_EFFECT_CHOKINGSTRAND /datum/status_effect/strandling //Choking Strand
#define STATUS_EFFECT_HISWRATH /datum/status_effect/his_wrath //His Wrath.
#define STATUS_EFFECT_SUMMONEDGHOST /datum/status_effect/cultghost //is a cult ghost and can't use manifest runes
@@ -74,6 +78,8 @@
#define STATUS_EFFECT_ICHORIAL_STAIN /datum/status_effect/ichorial_stain //Prevents a servant from being revived by vitality matrices for one minute.
#define STATUS_EFFECT_SPASMS /datum/status_effect/spasms //causes random muscle spasms
#define STATUS_EFFECT_BREASTS_ENLARGEMENT /datum/status_effect/chem/breast_enlarger //Applied slowdown due to the ominous bulk.
#define STATUS_EFFECT_PENIS_ENLARGEMENT /datum/status_effect/chem/penis_enlarger //More applied slowdown, just like the above.

View File

@@ -109,6 +109,7 @@
#define TRAIT_NOHARDCRIT "nohardcrit"
#define TRAIT_NOSOFTCRIT "nosoftcrit"
#define TRAIT_MINDSHIELD "mindshield"
#define TRAIT_SIXTHSENSE "sixthsense"
#define TRAIT_DISSECTED "dissected"
#define TRAIT_FEARLESS "fearless"
#define TRAIT_UNSTABLE "unstable"
@@ -117,9 +118,11 @@
#define TRAIT_PARALYSIS_L_LEG "para-l-leg"
#define TRAIT_PARALYSIS_R_LEG "para-r-leg"
#define TRAIT_UNINTELLIGIBLE_SPEECH "unintelligible-speech"
#define TRAIT_SOOTHED_THROAT "soothed-throat"
#define TRAIT_LAW_ENFORCEMENT_METABOLISM "law-enforcement-metabolism"
#define TRAIT_STRONG_GRABBER "strong_grabber"
#define TRAIT_CALCIUM_HEALER "calcium_healer"
#define TRAIT_STRONG_GRABBER "strong_grabber"
#define TRAIT_CALCIUM_HEALER "calcium_healer"
#define TRAIT_MAGIC_CHOKE "magic_choke"
#define TRAIT_CAPTAIN_METABOLISM "captain-metabolism"
#define TRAIT_ABDUCTOR_TRAINING "abductor-training"
#define TRAIT_ABDUCTOR_SCIENTIST_TRAINING "abductor-scientist-training"
@@ -160,6 +163,7 @@
#define TRAIT_FRIENDLY "friendly"
#define TRAIT_ASSBLASTUSA "assblastusa"
#define TRAIT_CULT_EYES "cult_eyes"
#define TRAIT_FREESPRINT "free_sprinting"
// common trait sources
@@ -179,6 +183,7 @@
#define CULT_TRAIT "cult"
#define CURSED_ITEM_TRAIT "cursed-item" // The item is magically cursed
#define ABSTRACT_ITEM_TRAIT "abstract-item"
#define STATUS_EFFECT_TRAIT "status-effect"
#define ROUNDSTART_TRAIT "roundstart" //cannot be removed without admin intervention
// unique trait sources, still defines

View File

@@ -84,3 +84,12 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_job_display_asc(datum/job/A, datum/job/B)
return A.display_order - B.display_order
/proc/cmp_uplink_items_dsc(datum/uplink_item/A, datum/uplink_item/B)
return sorttext(initial(B.name), initial(A.name))
/proc/cmp_numbered_displays_name_asc(datum/numbered_display/A, datum/numbered_display/B)
return sorttext(A.sample_object.name, B.sample_object.name)
/proc/cmp_numbered_displays_name_dsc(datum/numbered_display/A, datum/numbered_display/B)
return sorttext(B.sample_object.name, A.sample_object.name)

View File

@@ -97,6 +97,16 @@
var/datum/emote/E = new path()
E.emote_list[E.key] = E
//Uplink Items
for(var/path in subtypesof(/datum/uplink_item))
var/datum/uplink_item/I = path
if(!initial(I.item)) //We add categories to a separate list.
GLOB.uplink_categories |= initial(I.category)
continue
GLOB.uplink_items += path
//(sub)typesof entries are listed by the order they are loaded in the code, so we'll have to rearrange them here.
GLOB.uplink_items = sortList(GLOB.uplink_items, /proc/cmp_uplink_items_dsc)
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
//creates every subtype of prototype (excluding prototype) and adds it to list L.

View File

@@ -522,12 +522,14 @@ GLOBAL_LIST_EMPTY(species_list)
else
prefs = new
var/adminoverride = 0
var/override = FALSE
if(M.client && M.client.holder && (prefs.chat_toggles & CHAT_DEAD))
adminoverride = 1
if(isnewplayer(M) && !adminoverride)
override = TRUE
if(HAS_TRAIT(M, TRAIT_SIXTHSENSE))
override = TRUE
if(isnewplayer(M) && !override)
continue
if(M.stat != DEAD && !adminoverride)
if(M.stat != DEAD && !override)
continue
if(speaker_key && speaker_key in prefs.ignoring)
continue

View File

@@ -313,14 +313,13 @@
parts += "[FOURSPACES]Threat level: [mode.threat_level]"
parts += "[FOURSPACES]Threat left: [mode.threat]"
parts += "[FOURSPACES]Executed rules:"
for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat"
parts += "[FOURSPACES]Other threat changes:"
for(var/str in mode.threat_log)
parts += "[FOURSPACES][FOURSPACES][str]"
for(var/entry in mode.threat_tallies)
parts += "[FOURSPACES][FOURSPACES][entry] added [mode.threat_tallies[entry]]"
/*
for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat"
*/
return parts.Join("<br>")
/client/proc/roundend_report_file()

View File

@@ -142,8 +142,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"THICKMATERIAL" = THICKMATERIAL,
"VOICEBOX_TOGGLABLE" = VOICEBOX_TOGGLABLE,
"VOICEBOX_DISABLED" = VOICEBOX_DISABLED,
"SNUG_FIT" = SNUG_FIT,
"ANTI_TINFOIL_MANEUVER" = ANTI_TINFOIL_MANEUVER,
"IGNORE_HAT_TOSS" = IGNORE_HAT_TOSS,
),
"tesla_flags" = list(
"TESLA_MOB_DAMAGE" = TESLA_MOB_DAMAGE,

View File

@@ -7,15 +7,15 @@ GLOBAL_LIST_EMPTY(facial_hair_styles_list) //stores /datum/sprite_accessory/faci
GLOBAL_LIST_EMPTY(facial_hair_styles_male_list) //stores only hair names
GLOBAL_LIST_EMPTY(facial_hair_styles_female_list) //stores only hair names
//Underwear
GLOBAL_LIST_EMPTY(underwear_list) //stores /datum/sprite_accessory/underwear/bottom indexed by name
GLOBAL_LIST_EMPTY_TYPED(underwear_list, /datum/sprite_accessory/underwear/bottom) //stores bottoms indexed by name
GLOBAL_LIST_EMPTY(underwear_m) //stores only underwear name
GLOBAL_LIST_EMPTY(underwear_f) //stores only underwear name
//Undershirts
GLOBAL_LIST_EMPTY(undershirt_list) //stores /datum/sprite_accessory/underwear/top indexed by name
GLOBAL_LIST_EMPTY_TYPED(undershirt_list, /datum/sprite_accessory/underwear/top) //stores tops indexed by name
GLOBAL_LIST_EMPTY(undershirt_m) //stores only undershirt name
GLOBAL_LIST_EMPTY(undershirt_f) //stores only undershirt name
//Socks
GLOBAL_LIST_EMPTY(socks_list) //stores /datum/sprite_accessory/underwear/socks indexed by name
GLOBAL_LIST_EMPTY_TYPED(socks_list, /datum/sprite_accessory/underwear/socks) //stores socks indexed by name
//Lizard Bits (all datum lists indexed by name)
GLOBAL_LIST_EMPTY(body_markings_list)
GLOBAL_LIST_EMPTY(tails_list_lizard)
@@ -46,10 +46,15 @@ GLOBAL_LIST_INIT(ai_core_display_screens, list(
":thinking:",
"Alien",
"Angel",
"Angryface",
"AtlantisCZE",
"Banned",
"Bliss",
"Blue",
"Clown",
"Boy",
"Boy-Malf",
"Girl",
"Girl-Malf",
"Database",
"Dorf",
"Firewall",
@@ -61,26 +66,44 @@ GLOBAL_LIST_INIT(ai_core_display_screens, list(
"Hades",
"Heartline",
"Helios",
"Hotdog",
"Hourglass",
"House",
"Inverted",
"Jack",
"Matrix",
"Monochrome",
"Mothman",
"Murica",
"Nanotrasen",
"Not Malf",
"Patriot",
"Pirate",
"President",
"Random",
"Rainbow",
"Red",
"Clown",
"Random",
"Ravensdale",
"Red October",
"Red",
"Royal",
"Searif",
"Serithi",
"SilveryFerret",
"Smiley",
"Static",
"Syndicat Meow",
"TechDemon",
"Terminal",
"Text",
"Too Deep",
"Triumvirate",
"Triumvirate-M",
"Weird"))
"Wasp",
"Weird",
"Xerxes",
"Yes-Man"
))
/proc/resolve_ai_icon(input)
if(!input || !(input in GLOB.ai_core_display_screens))

View File

@@ -45,6 +45,6 @@ GLOBAL_LIST_EMPTY(vr_spawnpoints)
//used by jump-to-area etc. Updated by area/updateName()
GLOBAL_LIST_EMPTY(sortedAreas)
/// An association from typepath to area instance. Only includes areas with `unique` set.
GLOBAL_LIST_EMPTY(areas_by_type)
GLOBAL_LIST_EMPTY_TYPED(areas_by_type, /area)
GLOBAL_LIST_EMPTY(all_abstract_markers)

View File

@@ -19,6 +19,8 @@ GLOBAL_LIST(chemical_reagents_list) //list of all /datum/reagent datums index
GLOBAL_LIST_EMPTY(materials_list) //list of all /datum/material datums indexed by material id.
GLOBAL_LIST_EMPTY(tech_list) //list of all /datum/tech datums indexed by id.
GLOBAL_LIST_EMPTY(surgeries_list) //list of all surgeries by name, associated with their path.
GLOBAL_LIST_EMPTY(uplink_items) //list of all uplink item typepaths, ascendingly sorted by their initial name.
GLOBAL_LIST_EMPTY(uplink_categories) //list of all uplink categories, listed by the order they are loaded in code. Be careful.
GLOBAL_LIST_EMPTY(crafting_recipes) //list of all table craft recipes
GLOBAL_LIST_EMPTY(rcd_list) //list of Rapid Construction Devices.
GLOBAL_LIST_EMPTY(apcs_list) //list of all Area Power Controller machines, separate from machines for powernet speeeeeeed.

View File

@@ -13,6 +13,10 @@
#define POLL_IGNORE_GOLEM "golem"
#define POLL_IGNORE_SWARMER "swarmer"
#define POLL_IGNORE_DRONE "drone"
#define POLL_IGNORE_IMAGINARYFRIEND "imaginary_friend"
#define POLL_IGNORE_SPLITPERSONALITY "split_personality"
#define POLL_IGNORE_DEMON "demon"
#define POLL_IGNORE_WIZARD "wizard"
#define POLL_IGNORE_CLONE "clone"
GLOBAL_LIST_INIT(poll_ignore_desc, list(
@@ -29,6 +33,10 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list(
POLL_IGNORE_GOLEM = "Golems",
POLL_IGNORE_SWARMER = "Swarmer shells",
POLL_IGNORE_DRONE = "Drone shells",
POLL_IGNORE_IMAGINARYFRIEND = "Imaginary Friend",
POLL_IGNORE_SPLITPERSONALITY = "Split Personality",
POLL_IGNORE_DEMON = "Demons",
POLL_IGNORE_WIZARD = "Wizards",
POLL_IGNORE_CLONE = "Defective/SDGF clones"
))
GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore())

View File

@@ -10,3 +10,5 @@ GLOBAL_LIST_INIT(typecache_living, typecacheof(/mob/living))
GLOBAL_LIST_INIT(typecache_stack, typecacheof(/obj/item/stack))
GLOBAL_LIST_INIT(typecache_machine_or_structure, typecacheof(list(/obj/machinery, /obj/structure)))
GLOBAL_LIST_INIT(freezing_objects, typecacheof(list(/obj/structure/closet/crate/freezer, /obj/structure/closet/secure_closet/freezer, /obj/structure/bodycontainer, /obj/item/autosurgeon, /obj/machinery/smartfridge/organ))) //list of all cold objects, that freeze organs when inside

View File

@@ -213,6 +213,12 @@ or something covering your eyes."
desc = "Whoa man, you're tripping balls! Careful you don't get addicted... if you aren't already."
icon_state = "high"
/obj/screen/alert/hypnosis
name = "Hypnosis"
desc = "Something's hypnotizing you, but you're not really sure about what."
icon_state = "hypnosis"
var/phrase
/obj/screen/alert/drunk //Not implemented
name = "Drunk"
desc = "All that alcohol you've been drinking is impairing your speech, motor skills, and mental cognition. Make sure to act like it."

View File

@@ -25,7 +25,7 @@
return ..()
/obj/screen/examine(mob/user)
return
return list()
/obj/screen/orbit()
return

View File

@@ -39,23 +39,12 @@
if(..())
return TRUE
user.changeNext_move(CLICK_CD_MELEE)
if(user.a_intent == INTENT_HARM && stat == DEAD && (butcher_results || guaranteed_butcher_results)) //can we butcher it?
var/datum/component/butchering/butchering = I.GetComponent(/datum/component/butchering)
if(butchering && butchering.butchering_enabled)
to_chat(user, "<span class='notice'>You begin to butcher [src]...</span>")
playsound(loc, butchering.butcher_sound, 50, TRUE, -1)
if(do_mob(user, src, butchering.speed) && Adjacent(I))
butchering.Butcher(user, src)
return 1
else if(I.get_sharpness() && !butchering) //give sharp objects butchering functionality, for consistency
I.AddComponent(/datum/component/butchering, 80 * I.toolspeed)
attackby(I, user, params) //call the attackby again to refresh and do the butchering check again
return
return I.attack(src, user)
/obj/item/proc/attack(mob/living/M, mob/living/user)
SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_ITEM_NO_ATTACK)
return
SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user)
if(item_flags & NOBLUDGEON)
return

View File

@@ -106,9 +106,8 @@
/obj/item/tk_grab/examine(user)
if (focus)
focus.examine(user)
else
..()
return focus.examine(user)
return ..()
/obj/item/tk_grab/attack_self(mob/user)
if(!focus)

View File

@@ -211,3 +211,27 @@
/datum/config_entry/keyed_list/vv_edit_var(var_name, var_value)
return var_name != "splitter" && ..()
//snowflake for donator things being on one line smh
/datum/config_entry/multi_keyed_flag
vv_VAS = FALSE
abstract_type = /datum/config_entry/multi_keyed_flag
config_entry_value = list()
var/delimiter = "|"
/datum/config_entry/multi_keyed_flag/vv_edit_var(var_name, var_value)
if(var_name == NAMEOF(src, delimiter))
return FALSE
return ..()
/datum/config_entry/multi_keyed_flag/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
str_val = trim(str_val)
var/list/keys = splittext(str_val, delimiter)
for(var/i in keys)
config_entry_value[process_key(i)] = TRUE
return length(keys)? TRUE : FALSE
/datum/config_entry/multi_keyed_flag/proc/process_key(key)
return trim(key)

View File

@@ -1,22 +1,23 @@
/datum/config_entry/keyed_list/donator_group
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_FLAG
abstract_type = /datum/config_entry/keyed_list/donator_group
/datum/config_entry/multi_keyed_flag/donator_group
abstract_type = /datum/config_entry/multi_keyed_flag/donator_group
//If we're in the middle of a config load, only do the regeneration afterwards to prevent this from wasting a massive amount of CPU for list regenerations.
/datum/config_entry/keyed_list/donator_group/ValidateAndSet(str_val, during_load)
/datum/config_entry/multi_keyed_flag/donator_group/ValidateAndSet(str_val, during_load)
. = ..()
if(. && during_load)
if(. && !during_load)
regenerate_donator_grouping_list()
/datum/config_entry/keyed_list/donator_group/OnPostload()
/datum/config_entry/multi_keyed_flag/donator_group/process_key(key)
return ckey(key)
/datum/config_entry/multi_keyed_flag/donator_group/OnPostload()
. = ..()
regenerate_donator_grouping_list()
//This is kinda weird in that the config entries are defined here but all the handling/calculations are in __HELPERS/donator_groupings.dm
/datum/config_entry/keyed_list/donator_group/tier_1_donators
/datum/config_entry/multi_keyed_flag/donator_group/tier_1_donators
/datum/config_entry/keyed_list/donator_group/tier_2_donators
/datum/config_entry/multi_keyed_flag/donator_group/tier_2_donators
/datum/config_entry/keyed_list/donator_group/tier_3_donators
/datum/config_entry/multi_keyed_flag/donator_group/tier_3_donators

View File

@@ -81,42 +81,6 @@
/datum/config_entry/number/dynamic_assassinate_cost
config_entry_value = 2
/datum/config_entry/number/dynamic_summon_guns_requirement
config_entry_value = 10
min_val = 0
/datum/config_entry/number/dynamic_summon_guns_cost
config_entry_value = 5
min_val = 0
/datum/config_entry/number/dynamic_summon_magic_requirement
config_entry_value = 10
min_val = 0
/datum/config_entry/number/dynamic_summon_magic_cost
config_entry_value = 5
min_val = 0
/datum/config_entry/number/dynamic_summon_events_requirement
config_entry_value = 20
min_val = 0
/datum/config_entry/number/dynamic_summon_events_cost
config_entry_value = 10
min_val = 0
/datum/config_entry/number/dynamic_staff_of_change_requirement
config_entry_value = 20
min_val = 0
/datum/config_entry/number/dynamic_staff_of_change_cost
config_entry_value = 10
min_val = 0
/datum/config_entry/number/dynamic_apprentice_cost
config_entry_value = 10
min_val = 0
/datum/config_entry/number/dynamic_warops_requirement
config_entry_value = 60
min_val = 0

View File

@@ -29,6 +29,7 @@ SUBSYSTEM_DEF(chat)
target = GLOB.clients
//Some macros remain in the string even after parsing and fuck up the eventual output
var/original_message = message
message = replacetext(message, "\improper", "")
message = replacetext(message, "\proper", "")
if(handle_whitespace)
@@ -45,6 +46,12 @@ SUBSYSTEM_DEF(chat)
for(var/I in target)
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
if(!C)
return
//Send it to the old style output window.
SEND_TEXT(C, original_message)
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
continue
@@ -57,6 +64,12 @@ SUBSYSTEM_DEF(chat)
else
var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
if(!C)
return
//Send it to the old style output window.
SEND_TEXT(C, original_message)
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
return

View File

@@ -1,6 +1,27 @@
SUBSYSTEM_DEF(dcs)
PROCESSING_SUBSYSTEM_DEF(dcs)
name = "Datum Component System"
flags = SS_NO_INIT | SS_NO_FIRE
flags = SS_NO_INIT
var/list/elements_by_type = list()
/datum/controller/subsystem/dcs/Recover()
/datum/controller/subsystem/processing/dcs/Recover()
comp_lookup = SSdcs.comp_lookup
/datum/controller/subsystem/processing/dcs/proc/GetElement(datum/element/eletype, ...)
var/element_id = eletype
if(initial(eletype.element_flags) & ELEMENT_BESPOKE)
var/list/fullid = list("[eletype]")
for(var/i in initial(eletype.id_arg_index) to length(args))
var/argument = args[i]
if(istext(argument) || isnum(argument))
fullid += "[argument]"
else
fullid += "[REF(argument)]"
element_id = fullid.Join("&")
. = elements_by_type[element_id]
if(.)
return
if(!ispath(eletype, /datum/element))
CRASH("Attempted to instantiate [eletype] as a /datum/element")
. = elements_by_type[element_id] = new eletype

View File

@@ -98,7 +98,7 @@ SUBSYSTEM_DEF(garbage)
state = SS_RUNNING
break
/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK)
@@ -266,8 +266,8 @@ SUBSYSTEM_DEF(garbage)
D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
var/start_time = world.time
var/start_tick = world.tick_usage
SEND_SIGNAL(D, COMSIG_PARENT_QDELETING, force) // Let the (remaining) components know about the result of Destroy
var/hint = D.Destroy(arglist(args.Copy(2))) // Let our friend know they're about to get fucked up.
SEND_SIGNAL(D, COMSIG_PARENT_QDELETED, force, hint) // Let the (remaining) components know about the result of Destroy
if(world.time != start_time)
I.slept_destroy++
else

View File

@@ -444,7 +444,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
GLOB.the_gateway.wait = world.time
/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override, border_type_override)
UNTIL(reservation_ready["[z]"] && !clearing_reserved_turfs)
UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs)
var/datum/turf_reservation/reserve = new type
if(turf_type_override)
reserve.turf_type = turf_type_override

View File

@@ -12,6 +12,7 @@ SUBSYSTEM_DEF(persistence)
var/list/obj/structure/chisel_message/chisel_messages = list()
var/list/saved_messages = list()
var/list/saved_modes = list(1,2,3)
var/list/saved_threat_levels = list(1,1,1)
var/list/saved_maps
var/list/saved_trophies = list()
var/list/spawned_objects = list()
@@ -27,6 +28,7 @@ SUBSYSTEM_DEF(persistence)
LoadChiselMessages()
LoadTrophies()
LoadRecentModes()
LoadRecentThreats()
LoadRecentMaps()
LoadPhotoPersistence()
if(CONFIG_GET(flag/use_antag_rep))
@@ -166,6 +168,15 @@ SUBSYSTEM_DEF(persistence)
return
saved_modes = json["data"]
/datum/controller/subsystem/persistence/proc/LoadRecentThreats()
var/json_file = file("data/RecentThreatLevels.json")
if(!fexists(json_file))
return
var/list/json = json_decode(file2text(json_file))
if(!json)
return
saved_threat_levels = json["data"]
/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
var/json_file = file("data/RecentMaps.json")
if(!fexists(json_file))
@@ -216,6 +227,7 @@ SUBSYSTEM_DEF(persistence)
CollectSecretSatchels()
CollectTrophies()
CollectRoundtype()
CollectThreatLevel()
RecordMaps()
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
if(CONFIG_GET(flag/use_antag_rep))
@@ -372,6 +384,18 @@ SUBSYSTEM_DEF(persistence)
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/CollectThreatLevel()
if(istype(SSticker.mode, /datum/game_mode/dynamic))
var/datum/game_mode/dynamic/mode = SSticker.mode
saved_threat_levels[3] = saved_threat_levels[2]
saved_threat_levels[2] = saved_threat_levels [1]
saved_threat_levels[1] = mode.threat_level
var/json_file = file("data/RecentThreatLevels.json")
var/list/file_data = list()
file_data["data"] = saved_threat_levels
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/RecordMaps()
saved_maps = saved_maps?.len ? list("[SSmapping.config.map_name]") | saved_maps : list("[SSmapping.config.map_name]")
var/json_file = file("data/RecentMaps.json")

View File

@@ -87,7 +87,7 @@ SUBSYSTEM_DEF(traumas)
"skeletons" = typecacheof(list(/obj/item/organ/tongue/bone, /obj/item/clothing/suit/armor/bone, /obj/item/stack/sheet/bone,
/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton,
/obj/effect/decal/remains/human)),
"conspiracies" = typecacheof(list(/obj/item/clothing/under/rank/captain, /obj/item/clothing/under/rank/head_of_security,
"conspiracies" = typecacheof(list(/obj/item/clothing/under/rank/captain, /obj/item/clothing/under/rank/head_of_security,
/obj/item/clothing/under/rank/chief_engineer, /obj/item/clothing/under/rank/chief_medical_officer,
/obj/item/clothing/under/rank/head_of_personnel, /obj/item/clothing/under/rank/research_director,
/obj/item/clothing/under/rank/head_of_security/grey, /obj/item/clothing/under/rank/head_of_security/alt,

View File

@@ -29,8 +29,8 @@ SUBSYSTEM_DEF(vis_overlays)
return
//the "thing" var can be anything with vis_contents which includes images
/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha=255)
. = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]"
/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE)
. = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
var/obj/effect/overlay/vis/overlay = vis_overlay_cache[.]
if(!overlay)
overlay = new
@@ -40,6 +40,7 @@ SUBSYSTEM_DEF(vis_overlays)
overlay.plane = plane
overlay.dir = dir
overlay.alpha = alpha
overlay.appearance_flags |= add_appearance_flags
vis_overlay_cache[.] = overlay
else
overlay.unused = 0
@@ -64,10 +65,12 @@ SUBSYSTEM_DEF(vis_overlays)
UnregisterSignal(thing, COMSIG_ATOM_DIR_CHANGE)
/datum/controller/subsystem/vis_overlays/proc/rotate_vis_overlay(atom/thing, old_dir, new_dir)
if(old_dir == new_dir)
return
var/rotation = dir2angle(old_dir) - dir2angle(new_dir)
var/list/overlays_to_remove = list()
for(var/i in thing.managed_vis_overlays)
var/obj/effect/overlay/vis/overlay = i
add_vis_overlay(thing, overlay.icon, overlay.icon_state, overlay.layer, overlay.plane, turn(overlay.dir, rotation))
add_vis_overlay(thing, overlay.icon, overlay.icon_state, overlay.layer, overlay.plane, turn(overlay.dir, rotation), overlay.alpha, overlay.appearance_flags)
overlays_to_remove += overlay
remove_vis_overlay(thing, overlays_to_remove)

View File

@@ -153,6 +153,10 @@ SUBSYSTEM_DEF(vote)
if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started.
return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
GLOB.master_mode = "dynamic"
if("extended" in choices)
if(. == "extended")
GLOB.dynamic_forced_extended = TRUE // we still do the rest of the stuff
choices[PEACE] += choices["extended"]
var/mean = 0
var/voters = 0
for(var/client/c in GLOB.clients)
@@ -253,7 +257,11 @@ SUBSYSTEM_DEF(vote)
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
choices.Add("secret", "extended")
if("dynamic")
choices.Add(PEACE,CHAOS)
var/saved_threats = SSpersistence.saved_threat_levels
if((saved_threats[1]+saved_threats[2]+saved_threats[3])>150)
choices.Add("extended",PEACE,CHAOS)
else
choices.Add(PEACE,CHAOS)
if("custom")
question = stripped_input(usr,"What is the vote for?")
if(!question)

View File

@@ -1,10 +1,12 @@
//Brain Traumas are the new actual brain damage. Brain damage itself acts as a way to acquire traumas: every time brain damage is dealt, there's a chance of receiving a trauma.
//This chance gets higher the higher the mob's brainloss is. Removing traumas is a separate thing from removing brain damage: you can get restored to full brain operativity,
//but keep the quirks, until repaired by mannitol (for mild/special ones) or brain surgery (for severe ones).
// but keep the quirks, until repaired by neurine, surgery, lobotomy or magic; depending on the resilience
// of the trauma.
/datum/brain_trauma
var/name = "Brain Trauma"
var/desc = "A trauma caused by brain damage, which causes issues to the patient."
var/scan_desc = "a generic brain trauma" //description when detected by a health scanner
var/scan_desc = "generic brain trauma" //description when detected by a health scanner
var/mob/living/carbon/owner //the poor bastard
var/obj/item/organ/brain/brain //the poor bastard's brain
var/gain_text = "<span class='notice'>You feel traumatized.</span>"
@@ -12,15 +14,21 @@
var/can_gain = TRUE
var/random_gain = TRUE //can this be gained through random traumas?
var/resilience = TRAUMA_RESILIENCE_BASIC //how hard is this to cure?
var/clonable = TRUE // will this transfer if the brain is cloned?
/datum/brain_trauma/Destroy()
brain.traumas -= src
if(brain && brain.traumas)
brain.traumas -= src
if(owner)
on_lose()
brain = null
owner = null
return ..()
/datum/brain_trauma/proc/on_clone()
if(clonable)
return new type
//Called on life ticks
/datum/brain_trauma/proc/on_life()
return
@@ -33,17 +41,24 @@
/datum/brain_trauma/proc/on_gain()
to_chat(owner, gain_text)
RegisterSignal(owner, COMSIG_MOB_SAY, .proc/handle_speech)
RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/handle_hearing)
//Called when removed from a mob
/datum/brain_trauma/proc/on_lose(silent)
if(!silent)
to_chat(owner, lose_text)
UnregisterSignal(owner, COMSIG_MOB_SAY)
UnregisterSignal(owner, COMSIG_MOVABLE_HEAR)
//Called when hearing a spoken message
/datum/brain_trauma/proc/on_hear(message, speaker, message_language, raw_message, radio_freq)
return message
/datum/brain_trauma/proc/handle_hearing(datum/source, list/hearing_args)
UnregisterSignal(owner, COMSIG_MOVABLE_HEAR)
//Called when speaking
/datum/brain_trauma/proc/handle_speech(datum/source, list/speech_args)
UnregisterSignal(owner, COMSIG_MOB_SAY)
//Called when hugging. expand into generally interacting, where future coders could switch the intent?
/datum/brain_trauma/proc/on_hug(mob/living/hugger, mob/living/hugged)
return

View File

@@ -5,6 +5,7 @@
gain_text = ""
lose_text = ""
resilience = TRAUMA_RESILIENCE_SURGERY
var/hypnotic_phrase = ""
var/regex/target_phrase
@@ -44,18 +45,17 @@
"You feel a part of your mind repeating this over and over. You need to follow these words.",\
"Something about this sounds... right, for some reason. You feel like you should follow these words.",\
"These words keep echoing in your mind. You find yourself completely fascinated by them.")]</span>")
if(!HAS_TRAIT(owner, "hypnotherapy"))
to_chat(owner, "<span class='boldwarning'>You've been hypnotized by this sentence. You must follow these words. If it isn't a clear order, you can freely interpret how to do so,\
to_chat(owner, "<span class='boldwarning'>You've been hypnotized by this sentence. You must follow these words. If it isn't a clear order, you can freely interpret how to do so,\
as long as you act like the words are your highest priority.</span>")
else
to_chat(owner, "<span class='boldwarning'>You've been hypnotized by this sentence. You feel an incredible desire to follow these words, but are able to resist it somewhat. If it isn't a clear order, you can freely interpret how to do so,\
however this does not take precedence over your other objectives.</span>")
var/obj/screen/alert/hypnosis/hypno_alert = owner.throw_alert("hypnosis", /obj/screen/alert/hypnosis)
hypno_alert.desc = "\"[hypnotic_phrase]\"... your mind seems to be fixated on this concept."
..()
/datum/brain_trauma/hypnosis/on_lose()
message_admins("[ADMIN_LOOKUPFLW(owner)] is no longer hypnotized with the phrase '[hypnotic_phrase]'.")
log_game("[key_name(owner)] is no longer hypnotized with the phrase '[hypnotic_phrase]'.")
to_chat(owner, "<span class='userdanger'>You suddenly snap out of your fixation. The phrase '[hypnotic_phrase]' no longer feels important to you.</span>")
to_chat(owner, "<span class='userdanger'>You suddenly snap out of your hypnosis. The phrase '[hypnotic_phrase]' no longer feels important to you.</span>")
owner.clear_alert("hypnosis")
..()
/datum/brain_trauma/hypnosis/on_life()
@@ -67,6 +67,5 @@
if(2)
new /datum/hallucination/chat(owner, TRUE, FALSE, "<span class='hypnophrase'>[hypnotic_phrase]</span>")
/datum/brain_trauma/hypnosis/on_hear(message, speaker, message_language, raw_message, radio_freq)
message = target_phrase.Replace(message, "<span class='hypnophrase'>$1</span>")
return message
/datum/brain_trauma/hypnosis/handle_hearing(datum/source, list/hearing_args)
hearing_args[HEARING_RAW_MESSAGE] = target_phrase.Replace(hearing_args[HEARING_RAW_MESSAGE], "<span class='hypnophrase'>$1</span>")

View File

@@ -8,6 +8,10 @@
var/friend_initialized = FALSE
/datum/brain_trauma/special/imaginary_friend/on_gain()
var/mob/living/M = owner
if(M.stat == DEAD || !M.client)
qdel(src)
return
..()
make_friend()
get_ghost()
@@ -43,7 +47,7 @@
/datum/brain_trauma/special/imaginary_friend/proc/get_ghost()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend)
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend, POLL_IGNORE_IMAGINARYFRIEND)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
C.transfer_ckey(friend, FALSE)
@@ -74,26 +78,34 @@
/mob/camera/imaginary_friend/Login()
..()
to_chat(src, "<span class='notice'><b>You are the imaginary friend of [owner]!</b></span>")
to_chat(src, "<span class='notice'>You are absolutely loyal to your friend, no matter what.</span>")
to_chat(src, "<span class='notice'>You cannot directly influence the world around you, but you can see what [owner] cannot.</span>")
greet()
Show()
/mob/camera/imaginary_friend/proc/greet()
to_chat(src, "<span class='notice'><b>You are the imaginary friend of [owner]!</b></span>")
to_chat(src, "<span class='notice'>You are absolutely loyal to your friend, no matter what.</span>")
to_chat(src, "<span class='notice'>You cannot directly influence the world around you, but you can see what [owner] cannot.</span>")
/mob/camera/imaginary_friend/Initialize(mapload, _trauma)
. = ..()
var/gender = pick(MALE, FEMALE)
real_name = random_unique_name(gender)
name = real_name
trauma = _trauma
owner = trauma.owner
copy_known_languages_from(owner, TRUE)
human_image = get_flat_human_icon(null, pick(SSjob.occupations))
setup_friend()
join = new
join.Grant(src)
hide = new
hide.Grant(src)
/mob/camera/imaginary_friend/proc/setup_friend()
var/gender = pick(MALE, FEMALE)
real_name = random_unique_name(gender)
name = real_name
human_image = get_flat_human_icon(null, pick(SSjob.occupations))
/mob/camera/imaginary_friend/proc/Show()
if(!client) //nobody home
return
@@ -132,7 +144,7 @@
if(client.prefs.muted & MUTE_IC)
to_chat(src, "You cannot send IC messages (muted).")
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
if (!(ignore_spam || forced) && src.client.handle_spam_prevention(message,MUTE_IC))
return
friend_talk(message)
@@ -218,4 +230,42 @@
var/mob/camera/imaginary_friend/I = owner
I.hidden = !I.hidden
I.Show()
update_status()
update_status()
//down here is the trapped mind
//like imaginary friend but a lot less imagination and more like mind prison//
/datum/brain_trauma/special/imaginary_friend/trapped_owner
name = "Trapped Victim"
desc = "Patient appears to be targeted by an invisible entity."
gain_text = ""
lose_text = ""
random_gain = FALSE
/datum/brain_trauma/special/imaginary_friend/trapped_owner/make_friend()
friend = new /mob/camera/imaginary_friend/trapped(get_turf(owner), src)
/datum/brain_trauma/special/imaginary_friend/trapped_owner/reroll_friend() //no rerolling- it's just the last owner's hell
if(friend.client) //reconnected
return
friend_initialized = FALSE
QDEL_NULL(friend)
qdel(src)
/datum/brain_trauma/special/imaginary_friend/trapped_owner/get_ghost() //no randoms
return
/mob/camera/imaginary_friend/trapped
name = "figment of imagination?"
real_name = "figment of imagination?"
desc = "The previous host of this body."
/mob/camera/imaginary_friend/trapped/greet()
to_chat(src, "<span class='notice'><b>You have managed to hold on as a figment of the new host's imagination!</b></span>")
to_chat(src, "<span class='notice'>All hope is lost for you, but at least you may interact with your host. You do not have to be loyal to them.</span>")
to_chat(src, "<span class='notice'>You cannot directly influence the world around you, but you can see what the host cannot.</span>")
/mob/camera/imaginary_friend/trapped/setup_friend()
real_name = "[owner.real_name]?"
name = real_name
human_image = icon('icons/mob/lavaland/lavaland_monsters.dmi', icon_state = "curseblob")

View File

@@ -64,21 +64,21 @@
name = "Speech Impediment"
desc = "Patient is unable to form coherent sentences."
scan_desc = "communication disorder"
gain_text = "" //mutation will handle the text
lose_text = ""
gain_text = "<span class='danger'>You can't seem to form any coherent thoughts!</span>"
lose_text = "<span class='danger'>Your mind feels more clear.</span>"
/datum/brain_trauma/mild/speech_impediment/on_gain()
ADD_TRAIT(owner, TRAIT_UNINTELLIGIBLE_SPEECH, TRAUMA_TRAIT)
. = ..()
..()
/datum/brain_trauma/mild/speech_impediment/on_lose()
REMOVE_TRAIT(owner, TRAIT_UNINTELLIGIBLE_SPEECH, TRAUMA_TRAIT)
. = ..()
..()
/datum/brain_trauma/mild/concussion
name = "Concussion"
desc = "Patient's brain is concussed."
scan_desc = "a concussion"
scan_desc = "concussion"
gain_text = "<span class='warning'>Your head hurts!</span>"
lose_text = "<span class='notice'>The pressure inside your head starts fading.</span>"
@@ -157,54 +157,108 @@
gain_text = "<span class='warning'>Your muscles feel oddly faint.</span>"
lose_text = "<span class='notice'>You feel in control of your muscles again.</span>"
/datum/brain_trauma/mild/muscle_spasms/on_life()
if(prob(7))
switch(rand(1,5))
if(1)
if(owner.canmove && !isspaceturf(owner.loc))
to_chat(owner, "<span class='warning'>Your leg spasms!</span>")
step(owner, pick(GLOB.cardinals))
if(2)
if(owner.incapacitated())
return
var/obj/item/I = owner.get_active_held_item()
if(I)
to_chat(owner, "<span class='warning'>Your fingers spasm!</span>")
owner.log_message("used [I] due to a Muscle Spasm", LOG_ATTACK)
I.attack_self(owner)
if(3)
var/prev_intent = owner.a_intent
owner.a_intent = INTENT_HARM
var/range = 1
if(istype(owner.get_active_held_item(), /obj/item/gun)) //get targets to shoot at
range = 7
var/list/mob/living/targets = list()
for(var/mob/M in oview(owner, range))
if(isliving(M))
targets += M
if(LAZYLEN(targets))
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
owner.log_message(" attacked someone due to a Muscle Spasm") //the following attack will log itself
owner.ClickOn(pick(targets))
owner.a_intent = prev_intent
if(4)
var/prev_intent = owner.a_intent
owner.a_intent = INTENT_HARM
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
owner.log_message("attacked [owner.p_them()]self to a Muscle Spasm", LOG_ATTACK)
owner.ClickOn(owner)
owner.a_intent = prev_intent
if(5)
if(owner.incapacitated())
return
var/obj/item/I = owner.get_active_held_item()
var/list/turf/targets = list()
for(var/turf/T in oview(owner, 3))
targets += T
if(LAZYLEN(targets) && I)
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
owner.log_message("threw [I] due to a Muscle Spasm", LOG_ATTACK)
owner.throw_item(pick(targets))
/datum/brain_trauma/mild/muscle_spasms/on_gain()
owner.apply_status_effect(STATUS_EFFECT_SPASMS)
..()
/datum/brain_trauma/mild/muscle_spasms/on_lose()
owner.remove_status_effect(STATUS_EFFECT_SPASMS)
..()
/datum/brain_trauma/mild/nervous_cough
name = "Nervous Cough"
desc = "Patient feels a constant need to cough."
scan_desc = "nervous cough"
gain_text = "<span class='warning'>Your throat itches incessantly...</span>"
lose_text = "<span class='notice'>Your throat stops itching.</span>"
/datum/brain_trauma/mild/nervous_cough/on_life()
if(prob(12) && !HAS_TRAIT(owner, TRAIT_SOOTHED_THROAT))
if(prob(5))
to_chat(owner, "<span notice='warning'>[pick("You have a coughing fit!", "You can't stop coughing!")]</span>")
owner.Stun(20)
owner.emote("cough")
addtimer(CALLBACK(owner, /mob/.proc/emote, "cough"), 6)
addtimer(CALLBACK(owner, /mob/.proc/emote, "cough"), 12)
owner.emote("cough")
..()
/datum/brain_trauma/mild/expressive_aphasia
name = "Expressive Aphasia"
desc = "Patient is affected by partial loss of speech leading to a reduced vocabulary."
scan_desc = "inability to form complex sentences"
gain_text = "<span class='warning'>You lose your grasp on complex words.</span>"
lose_text = "<span class='notice'>You feel your vocabulary returning to normal again.</span>"
var/static/list/common_words = world.file2list("strings/1000_most_common.txt")
/datum/brain_trauma/mild/expressive_aphasia/handle_speech(datum/source, list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
if(message)
var/list/message_split = splittext(message, " ")
var/list/new_message = list()
for(var/word in message_split)
var/suffix = copytext(word,-1)
// Check if we have a suffix and break it out of the word
if(suffix in list("." , "," , ";" , "!" , ":" , "?"))
word = copytext(word,1,-1)
else
suffix = ""
word = html_decode(word)
if(lowertext(word) in common_words)
new_message += word + suffix
else
if(prob(30) && message_split.len > 2)
new_message += pick("uh","erm")
break
else
var/list/charlist = string2charlist(word) // Stupid shit code
shuffle_inplace(charlist)
charlist.len = round(charlist.len * 0.5,1)
new_message += html_encode(jointext(charlist,"")) + suffix
message = jointext(new_message, " ")
speech_args[SPEECH_MESSAGE] = trim(message)
/datum/brain_trauma/mild/mind_echo
name = "Mind Echo"
desc = "Patient's language neurons do not terminate properly, causing previous speech patterns to occasionally resurface spontaneously."
scan_desc = "looping neural pattern"
gain_text = "<span class='warning'>You feel a faint echo of your thoughts...</span>"
lose_text = "<span class='notice'>The faint echo fades away.</span>"
var/list/hear_dejavu = list()
var/list/speak_dejavu = list()
/datum/brain_trauma/mild/mind_echo/handle_hearing(datum/source, list/hearing_args)
if(owner == hearing_args[HEARING_SPEAKER])
return
if(hear_dejavu.len >= 5)
if(prob(25))
var/deja_vu = pick_n_take(hear_dejavu)
var/static/regex/quoted_spoken_message = regex("\".+\"", "gi")
hearing_args[HEARING_RAW_MESSAGE] = quoted_spoken_message.Replace(hearing_args[HEARING_RAW_MESSAGE], "\"[deja_vu]\"") //Quotes included to avoid cases where someone says part of their name
return
if(hear_dejavu.len >= 15)
if(prob(50))
popleft(hear_dejavu) //Remove the oldest
hear_dejavu += hearing_args[HEARING_RAW_MESSAGE]
else
hear_dejavu += hearing_args[HEARING_RAW_MESSAGE]
/datum/brain_trauma/mild/mind_echo/handle_speech(datum/source, list/speech_args)
if(speak_dejavu.len >= 5)
if(prob(25))
var/deja_vu = pick_n_take(speak_dejavu)
speech_args[SPEECH_MESSAGE] = deja_vu
return
if(speak_dejavu.len >= 15)
if(prob(50))
popleft(speak_dejavu) //Remove the oldest
speak_dejavu += speech_args[SPEECH_MESSAGE]
else
speak_dejavu += speech_args[SPEECH_MESSAGE]

View File

@@ -2,8 +2,8 @@
name = "Phobia"
desc = "Patient is unreasonably afraid of something."
scan_desc = "phobia"
gain_text = ""
lose_text = ""
gain_text = "<span class='warning'>You start finding default values very unnerving...</span>"
lose_text = "<span class='notice'>You no longer feel afraid of default values.</span>"
var/phobia_type
var/next_check = 0
var/next_scare = 0
@@ -14,8 +14,10 @@
var/list/trigger_turfs
var/list/trigger_species
/datum/brain_trauma/mild/phobia/New(specific_type)
phobia_type = specific_type
/datum/brain_trauma/mild/phobia/New(new_phobia_type)
if(new_phobia_type)
phobia_type = new_phobia_type
if(!phobia_type)
phobia_type = pick(SStraumas.phobia_types)
@@ -29,6 +31,11 @@
trigger_species = SStraumas.phobia_species[phobia_type]
..()
/datum/brain_trauma/mild/phobia/on_clone()
if(clonable)
return new type(phobia_type)
/datum/brain_trauma/mild/phobia/on_life()
..()
if(HAS_TRAIT(owner, TRAIT_FEARLESS))
@@ -44,6 +51,12 @@
if(is_type_in_typecache(O, trigger_objs))
freak_out(O)
return
for(var/mob/living/carbon/human/HU in seen_atoms) //check equipment for trigger items
for(var/X in HU.get_all_slots() | HU.held_items)
var/obj/I = X
if(!QDELETED(I) && is_type_in_typecache(I, trigger_objs))
freak_out(I)
return
if(LAZYLEN(trigger_turfs))
for(var/turf/T in seen_atoms)
@@ -51,45 +64,41 @@
freak_out(T)
return
if(LAZYLEN(trigger_mobs) || LAZYLEN(trigger_objs))
seen_atoms -= owner //make sure they aren't afraid of themselves.
if(LAZYLEN(trigger_mobs) || LAZYLEN(trigger_species))
for(var/mob/M in seen_atoms)
if(is_type_in_typecache(M, trigger_mobs))
freak_out(M)
return
else if(ishuman(M)) //check their equipment for trigger items
else if(ishuman(M)) //check their species
var/mob/living/carbon/human/H = M
if(LAZYLEN(trigger_species) && H.dna && H.dna.species && is_type_in_typecache(H.dna.species, trigger_species))
freak_out(H)
return
for(var/X in H.get_all_slots() | H.held_items)
var/obj/I = X
if(!QDELETED(I) && is_type_in_typecache(I, trigger_objs))
freak_out(I)
return
/datum/brain_trauma/mild/phobia/on_hear(message, speaker, message_language, raw_message, radio_freq)
/datum/brain_trauma/mild/phobia/handle_hearing(datum/source, list/hearing_args)
if(!owner.can_hear() || world.time < next_scare) //words can't trigger you if you can't hear them *taps head*
return message
return
if(HAS_TRAIT(owner, TRAIT_FEARLESS))
return message
return
for(var/word in trigger_words)
var/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i")
var/regex/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i")
if(findtext(raw_message, reg))
if(findtext(hearing_args[HEARING_RAW_MESSAGE], reg))
addtimer(CALLBACK(src, .proc/freak_out, null, word), 10) //to react AFTER the chat message
hearing_args[HEARING_RAW_MESSAGE] = reg.Replace(hearing_args[HEARING_RAW_MESSAGE], "<span class='phobia'>$1</span>")
break
return message
/datum/brain_trauma/mild/phobia/handle_speech(datum/source, list/speech_args)
if(HAS_TRAIT(owner, TRAIT_FEARLESS))
return
for(var/word in trigger_words)
var/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i")
var/regex/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i")
if(findtext(speech_args[SPEECH_MESSAGE], reg))
to_chat(owner, "<span class='warning'>You can't bring yourself to say the word \"[word]\"!</span>")
to_chat(owner, "<span class='warning'>You can't bring yourself to say the word \"<span class='phobia'>[word]</span>\"!</span>")
speech_args[SPEECH_MESSAGE] = ""
/datum/brain_trauma/mild/phobia/proc/freak_out(atom/reason, trigger_word)
@@ -125,6 +134,76 @@
owner.Jitter(10)
owner.stuttering += 10
// Defined phobia types for badminry, not included in the RNG trauma pool to avoid diluting.
/datum/brain_trauma/mild/phobia/spiders
phobia_type = "spiders"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/space
phobia_type = "space"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/security
phobia_type = "security"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/clowns
phobia_type = "clowns"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/greytide
phobia_type = "greytide"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/lizards
phobia_type = "lizards"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/skeletons
phobia_type = "skeletons"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/snakes
phobia_type = "snakes"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/robots
phobia_type = "robots"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/doctors
phobia_type = "doctors"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/authority
phobia_type = "authority"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/supernatural
phobia_type = "the supernatural"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/aliens
phobia_type = "aliens"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/strangers
phobia_type = "strangers"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/birds
phobia_type = "birds"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/falling
phobia_type = "falling"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/anime
phobia_type = "anime"
random_gain = FALSE
/datum/brain_trauma/mild/phobia/conspiracies
phobia_type = "conspiracies"
random_gain = FALSE

View File

@@ -119,7 +119,7 @@
owner.update_disabled_bodyparts()
/datum/brain_trauma/severe/paralysis/paraplegic
//can_gain = FALSE maybe breaks.
random_gain = FALSE
paralysis_type = "legs"
resilience = TRAUMA_RESILIENCE_ABSOLUTE
@@ -149,7 +149,7 @@
/datum/brain_trauma/severe/monophobia
name = "Monophobia"
desc = "Patient feels sick and distressed when not around other people, leading to potentially lethal levels of stress."
scan_desc = "severe monophobia"
scan_desc = "monophobia"
gain_text = ""
lose_text = "<span class='notice'>You feel like you could be safe on your own.</span>"
var/stress = 0
@@ -168,7 +168,7 @@
if(stress > 10 && (prob(5)))
stress_reaction()
else
stress -= 4
stress = max(stress - 4, 0)
/datum/brain_trauma/severe/monophobia/proc/check_alone()
if(HAS_TRAIT(owner, TRAIT_BLIND))

View File

@@ -22,6 +22,14 @@
else
speak("neutral", prob(25))
/datum/brain_trauma/special/godwoken/on_gain()
ADD_TRAIT(owner, TRAIT_HOLY, TRAUMA_TRAIT)
..()
/datum/brain_trauma/special/godwoken/on_lose()
REMOVE_TRAIT(owner, TRAIT_HOLY, TRAUMA_TRAIT)
..()
/datum/brain_trauma/special/godwoken/proc/speak(type, include_owner = FALSE)
var/message
switch(type)
@@ -36,7 +44,7 @@
else
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral")
playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 200, 1, 5)
playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 200, TRUE, 5)
voice_of_god(message, owner, list("colossus","yell"), 2.5, include_owner, FALSE)
/datum/brain_trauma/special/bluespace_prophet
@@ -134,7 +142,101 @@
/datum/brain_trauma/special/psychotic_brawling/bath_salts
name = "Chemical Violent Psychosis"
random_gain = FALSE
clonable = FALSE
/datum/brain_trauma/special/tenacity
name = "Tenacity"
desc = "Patient is psychologically unaffected by pain and injuries, and can remain standing far longer than a normal person."
scan_desc = "traumatic neuropathy"
gain_text = "<span class='warning'>You suddenly stop feeling pain.</span>"
lose_text = "<span class='warning'>You realize you can feel pain again.</span>"
/datum/brain_trauma/special/tenacity/on_gain()
ADD_TRAIT(owner, TRAIT_NOSOFTCRIT, TRAUMA_TRAIT)
ADD_TRAIT(owner, TRAIT_NOHARDCRIT, TRAUMA_TRAIT)
..()
/datum/brain_trauma/special/tenacity/on_lose()
REMOVE_TRAIT(owner, TRAIT_NOSOFTCRIT, TRAUMA_TRAIT)
REMOVE_TRAIT(owner, TRAIT_NOHARDCRIT, TRAUMA_TRAIT)
..()
/datum/brain_trauma/special/death_whispers
name = "Functional Cerebral Necrosis"
desc = "Patient's brain is stuck in a functional near-death state, causing occasional moments of lucid hallucinations, which are often interpreted as the voices of the dead."
scan_desc = "chronic functional necrosis"
gain_text = "<span class='warning'>You feel dead inside.</span>"
lose_text = "<span class='notice'>You feel alive again.</span>"
var/active = FALSE
/datum/brain_trauma/special/death_whispers/on_life()
..()
if(!active && prob(2))
whispering()
/datum/brain_trauma/special/death_whispers/on_lose()
if(active)
cease_whispering()
..()
/datum/brain_trauma/special/death_whispers/proc/whispering()
ADD_TRAIT(owner, TRAIT_SIXTHSENSE, TRAUMA_TRAIT)
active = TRUE
addtimer(CALLBACK(src, .proc/cease_whispering), rand(50, 300))
/datum/brain_trauma/special/death_whispers/proc/cease_whispering()
REMOVE_TRAIT(owner, TRAIT_SIXTHSENSE, TRAUMA_TRAIT)
active = FALSE
/datum/brain_trauma/special/existential_crisis
name = "Existential Crisis"
desc = "Patient's hold on reality becomes faint, causing occasional bouts of non-existence."
scan_desc = "existential crisis"
gain_text = "<span class='notice'>You feel less real.</span>"
lose_text = "<span class='warning'>You feel more substantial again.</span>"
var/obj/effect/abstract/sync_holder/veil/veil
var/next_crisis = 0
/datum/brain_trauma/special/existential_crisis/on_life()
..()
if(!veil && world.time > next_crisis && prob(3))
if(isturf(owner.loc))
fade_out()
/datum/brain_trauma/special/existential_crisis/on_lose()
if(veil)
fade_in()
..()
/datum/brain_trauma/special/existential_crisis/proc/fade_out()
if(veil)
return
var/duration = rand(50, 450)
veil = new(owner.drop_location())
to_chat(owner, "<span class='warning'>[pick("You stop thinking for a moment. Therefore you are not.",\
"To be or not to be...",\
"Why exist?",\
"You stop keeping it real.",\
"Your grip on existence slips.",\
"Do you even exist?",\
"You simply fade away.")]</span>")
owner.forceMove(veil)
SEND_SIGNAL(owner, COMSIG_MOVABLE_SECLUDED_LOCATION)
for(var/thing in owner)
var/atom/movable/AM = thing
SEND_SIGNAL(AM, COMSIG_MOVABLE_SECLUDED_LOCATION)
next_crisis = world.time + 600
addtimer(CALLBACK(src, .proc/fade_in), duration)
/datum/brain_trauma/special/existential_crisis/proc/fade_in()
QDEL_NULL(veil)
to_chat(owner, "<span class='notice'>You fade back into reality.</span>")
next_crisis = world.time + 600
//base sync holder is in desynchronizer.dm
/obj/effect/abstract/sync_holder/veil
name = "non-existence"
desc = "Existence is just a state of mind."
/datum/brain_trauma/special/beepsky
name = "Criminal"
@@ -142,6 +244,7 @@
scan_desc = "criminal mind"
gain_text = "<span class='warning'>Justice is coming for you.</span>"
lose_text = "<span class='notice'>You were absolved for your crimes.</span>"
clonable = FALSE
random_gain = FALSE
var/obj/effect/hallucination/simple/securitron/beepsky
@@ -201,4 +304,4 @@
/obj/effect/hallucination/simple/securitron/Destroy()
STOP_PROCESSING(SSfastprocess,src)
return ..()
return ..()

View File

@@ -13,6 +13,10 @@
var/mob/living/split_personality/owner_backseat
/datum/brain_trauma/severe/split_personality/on_gain()
var/mob/living/M = owner
if(M.stat == DEAD) //No use assigning people to a corpse
qdel(src)
return
..()
make_backseats()
get_ghost()
@@ -23,7 +27,7 @@
/datum/brain_trauma/severe/split_personality/proc/get_ghost()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat)
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat, POLL_IGNORE_SPLITPERSONALITY)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
C.transfer_ckey(stranger_backseat, FALSE)
@@ -191,13 +195,13 @@
/datum/brain_trauma/severe/split_personality/brainwashing/on_life()
return //no random switching
/datum/brain_trauma/severe/split_personality/brainwashing/on_hear(message, speaker, message_language, raw_message, radio_freq)
if(HAS_TRAIT(owner, TRAIT_DEAF) || owner == speaker)
return message
/datum/brain_trauma/severe/split_personality/brainwashing/handle_hearing(datum/source, list/hearing_args)
if(HAS_TRAIT(owner, TRAIT_DEAF) || owner == hearing_args[HEARING_SPEAKER])
return
var/message = hearing_args[HEARING_RAW_MESSAGE]
if(findtext(message, codeword))
message = replacetext(message, codeword, "<span class='warning'>[codeword]</span>")
hearing_args[HEARING_RAW_MESSAGE] = replacetext(message, codeword, "<span class='warning'>[codeword]</span>")
addtimer(CALLBACK(src, /datum/brain_trauma/severe/split_personality.proc/switch_personalities), 10)
return message
/datum/brain_trauma/severe/split_personality/brainwashing/handle_speech(datum/source, list/speech_args)
if(findtext(speech_args[SPEECH_MESSAGE], codeword))

View File

@@ -184,6 +184,7 @@
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
/datum/proc/GetComponent(datum/component/c_type)
RETURN_TYPE(c_type)
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED)
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components

View File

@@ -29,21 +29,21 @@
var/obj/item/typecast = upgrade_item
upgrade_name = initial(typecast.name)
/datum/component/armor_plate/proc/examine(datum/source, mob/user)
/datum/component/armor_plate/proc/examine(datum/source, mob/user, list/examine_list)
//upgrade_item could also be typecast here instead
if(ismecha(parent))
if(amount)
if(amount < maxamount)
to_chat(user, "<span class='notice'>Its armor is enhanced with [amount] [upgrade_name].</span>")
examine_list += "<span class='notice'>Its armor is enhanced with [amount] [upgrade_name].</span>"
else
to_chat(user, "<span class='notice'>It's wearing a fearsome carapace entirely composed of [upgrade_name] - its pilot must be an experienced monster hunter.</span>")
examine_list += "<span class='notice'>It's wearing a fearsome carapace entirely composed of [upgrade_name] - its pilot must be an experienced monster hunter.</span>"
else
to_chat(user, "<span class='notice'>It has attachment points for strapping monster hide on for added protection.</span>")
examine_list += "<span class='notice'>It has attachment points for strapping monster hide on for added protection.</span>"
else
if(amount)
to_chat(user, "<span class='notice'>It has been strengthened with [amount]/[maxamount] [upgrade_name].</span>")
examine_list += "<span class='notice'>It has been strengthened with [amount]/[maxamount] [upgrade_name].</span>"
else
to_chat(user, "<span class='notice'>It can be strengthened with up to [maxamount] [upgrade_name].</span>")
examine_list += "<span class='notice'>It can be strengthened with up to [maxamount] [upgrade_name].</span>"
/datum/component/armor_plate/proc/applyplate(datum/source, obj/item/I, mob/user, params)
if(!istype(I,upgrade_item))

View File

@@ -4,8 +4,9 @@
var/bonus_modifier = 0 //percentage increase to bonus item chance
var/butcher_sound = 'sound/weapons/slice.ogg' //sound played when butchering
var/butchering_enabled = TRUE
var/can_be_blunt = FALSE
/datum/component/butchering/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled)
/datum/component/butchering/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled, _can_be_blunt)
if(_speed)
speed = _speed
if(_effectiveness)
@@ -16,6 +17,22 @@
butcher_sound = _butcher_sound
if(disabled)
butchering_enabled = FALSE
if(_can_be_blunt)
can_be_blunt = _can_be_blunt
if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/onItemAttack)
/datum/component/butchering/proc/onItemAttack(obj/item/source, mob/living/M, mob/living/user)
if(user.a_intent == INTENT_HARM && M.stat == DEAD && (M.butcher_results || M.guaranteed_butcher_results)) //can we butcher it?
if(butchering_enabled && (can_be_blunt || source.get_sharpness()))
INVOKE_ASYNC(src, .proc/startButcher, source, M, user)
return COMPONENT_ITEM_NO_ATTACK
/datum/component/butchering/proc/startButcher(obj/item/source, mob/living/M, mob/living/user)
to_chat(user, "<span class='notice'>You begin to butcher [M]...</span>")
playsound(M.loc, butcher_sound, 50, TRUE, -1)
if(do_mob(user, M, speed) && M.Adjacent(source))
Butcher(user, M)
/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
var/turf/T = meat.drop_location()
@@ -50,3 +67,23 @@
/datum/component/butchering/proc/ButcherEffects(mob/living/meat) //extra effects called on butchering, override this via subtypes
return
///Special snowflake component only used for the recycler.
/datum/component/butchering/recycler
/datum/component/butchering/recycler/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled, _can_be_blunt)
if(!istype(parent, /obj/machinery/recycler)) //EWWW
return COMPONENT_INCOMPATIBLE
. = ..()
if(. == COMPONENT_INCOMPATIBLE)
return
RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, .proc/onCrossed)
/datum/component/butchering/recycler/proc/onCrossed(datum/source, mob/living/L)
if(!istype(L))
return
var/obj/machinery/recycler/eater = parent
if(eater.safety_mode || (eater.stat & (BROKEN|NOPOWER))) //I'm so sorry.
return
if(L.stat == DEAD && (L.butcher_results || L.guaranteed_butcher_results))
Butcher(parent, L)

View File

@@ -19,9 +19,9 @@
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY,.proc/action)
update_parent(index)
/datum/component/construction/proc/examine(datum/source, mob/user)
/datum/component/construction/proc/examine(datum/source, mob/user, list/examine_list)
if(desc)
to_chat(user, desc)
examine_list += desc
/datum/component/construction/proc/on_step()
if(index > steps.len)

View File

@@ -71,5 +71,5 @@
if(strength >= cleanable)
qdel(src)
/datum/component/decal/proc/examine(datum/source, mob/user)
to_chat(user, description)
/datum/component/decal/proc/examine(datum/source, mob/user, list/examine_list)
examine_list += description

View File

@@ -1,30 +0,0 @@
// An item worn in the ear slot with this component will heal your ears each
// Life() tick, even if normally your ears would be too damaged to heal.
/datum/component/earhealing
var/mob/living/carbon/wearer
/datum/component/earhealing/Initialize()
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED), .proc/equippedChanged)
/datum/component/earhealing/proc/equippedChanged(datum/source, mob/living/carbon/user, slot)
if (slot == SLOT_EARS && istype(user))
if (!wearer)
START_PROCESSING(SSobj, src)
wearer = user
else
if (wearer)
STOP_PROCESSING(SSobj, src)
wearer = null
/datum/component/earhealing/process()
if (!wearer)
STOP_PROCESSING(SSobj, src)
return
if(!HAS_TRAIT(wearer, TRAIT_DEAF))
var/obj/item/organ/ears/ears = wearer.getorganslot(ORGAN_SLOT_EARS)
if (ears)
ears.deaf = max(ears.deaf - 1, (ears.damage < ears.maxHealth ? 0 : 1)) // Do not clear deafness if our ears are too damaged
ears.damage = max(ears.damage - 0.1, 0)

View File

@@ -15,8 +15,8 @@
for(var/i in parent)
RegisterSignal(i, COMSIG_MOVABLE_PRE_THROW, .proc/throw_react)
/datum/component/magnetic_catch/proc/examine(datum/source, mob/user)
to_chat(user, "It has been installed with inertia dampening to prevent coffee spills.")
/datum/component/magnetic_catch/proc/examine(datum/source, mob/user, list/examine_list)
examine_list += "It has been installed with inertia dampening to prevent coffee spills."
/datum/component/magnetic_catch/proc/crossed_react(datum/source, atom/movable/thing)
RegisterSignal(thing, COMSIG_MOVABLE_PRE_THROW, .proc/throw_react, TRUE)

View File

@@ -49,13 +49,13 @@
var/mat_path = possible_mats[id]
materials[id] = new mat_path()
/datum/component/material_container/proc/OnExamine(datum/source, mob/user)
/datum/component/material_container/proc/OnExamine(datum/source, mob/user, list/examine_list)
if(show_on_examine)
for(var/I in materials)
var/datum/material/M = materials[I]
var/amt = amount(M.id)
if(amt)
to_chat(user, "<span class='notice'>It has [amt] units of [lowertext(M.name)] stored.</span>")
examine_list += "<span class='notice'>It has [amt] units of [lowertext(M.name)] stored.</span>"
/datum/component/material_container/proc/OnAttackBy(datum/source, obj/item/I, mob/living/user)
var/list/tc = allowed_typecache

View File

@@ -248,7 +248,7 @@
var/datum/hud/hud = owner.hud_used
screen_obj = new
hud.infodisplay += screen_obj
RegisterSignal(hud, COMSIG_PARENT_QDELETED, .proc/unmodify_hud)
RegisterSignal(hud, COMSIG_PARENT_QDELETING, .proc/unmodify_hud)
RegisterSignal(screen_obj, COMSIG_CLICK, .proc/hud_click)
/datum/component/mood/proc/unmodify_hud(datum/source)

View File

@@ -53,7 +53,6 @@
RegisterSignal(parent, COMSIG_MOB_ALLOWED, .proc/check_access)
RegisterSignal(parent, COMSIG_LIVING_ELECTROCUTE_ACT, .proc/on_shock)
RegisterSignal(parent, COMSIG_LIVING_MINOR_SHOCK, .proc/on_minor_shock)
RegisterSignal(parent, COMSIG_MOVABLE_HEAR, .proc/on_hear)
RegisterSignal(parent, COMSIG_SPECIES_GAIN, .proc/check_viable_biotype)
RegisterSignal(parent, COMSIG_NANITE_SIGNAL, .proc/receive_signal)
@@ -191,11 +190,6 @@
var/datum/nanite_program/NP = X
NP.on_death(gibbed)
/datum/component/nanites/proc/on_hear(datum/source, message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
/datum/component/nanites/proc/receive_signal(datum/source, code, source = "an unidentified source")
for(var/X in programs)
var/datum/nanite_program/NP = X

View File

@@ -18,7 +18,7 @@
hl3_release_date = _half_life
can_contaminate = _can_contaminate
if(istype(parent, /atom))
if(istype(parent, /atom))
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/rad_examine)
if(istype(parent, /obj/item))
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/rad_attack)
@@ -58,7 +58,7 @@
else
strength = max(strength, arguments[1])
/datum/component/radioactive/proc/rad_examine(datum/source, mob/user, atom/thing)
/datum/component/radioactive/proc/rad_examine(datum/source, mob/user, list/examine_list)
var/atom/master = parent
var/list/out = list()
if(get_dist(master, user) <= 1)
@@ -72,7 +72,7 @@
out += "[out ? " and it " : "[master] "]hurts to look at."
else
out += "."
to_chat(user, out.Join())
examine_list += out.Join()
/datum/component/radioactive/proc/rad_attack(datum/source, atom/movable/target, mob/living/user)
radiation_pulse(parent, strength/20)

View File

@@ -98,9 +98,9 @@
remove_verbs()
. = ..()
/datum/component/simple_rotation/proc/ExamineMessage(datum/source, mob/user)
/datum/component/simple_rotation/proc/ExamineMessage(datum/source, mob/user, list/examine_list)
if(rotation_flags & ROTATION_ALTCLICK)
to_chat(user, "<span class='notice'>Alt-click to rotate it clockwise.</span>")
examine_list += "<span class='notice'>Alt-click to rotate it clockwise.</span>"
/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction)
if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation))

View File

@@ -8,6 +8,7 @@
if(!ismovableatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, list(COMSIG_MOVABLE_Z_CHANGED), .proc/check_in_bounds)
RegisterSignal(parent, list(COMSIG_MOVABLE_SECLUDED_LOCATION), .proc/relocate)
RegisterSignal(parent, list(COMSIG_PARENT_PREQDELETED), .proc/check_deletion)
RegisterSignal(parent, list(COMSIG_ITEM_IMBUE_SOUL), .proc/check_soul_imbue)
src.inform_admins = inform_admins
@@ -32,6 +33,7 @@
var/atom/movable/AM = parent
AM.forceMove(targetturf)
to_chat(get(parent, /mob), "<span class='danger'>You can't help but feel that you just lost something back there...</span>")
// move the disc, so ghosts remain orbiting it even if it's "destroyed"
return targetturf
@@ -40,7 +42,6 @@
return
else
var/turf/currentturf = get_turf(src)
to_chat(get(parent, /mob), "<span class='danger'>You can't help but feel that you just lost something back there...</span>")
var/turf/targetturf = relocate()
log_game("[parent] has been moved out of bounds in [loc_name(currentturf)]. Moving it to [loc_name(targetturf)].")
if(inform_admins)

View File

@@ -57,7 +57,7 @@
var/screen_start_x = 4 //These two are where the storage starts being rendered, screen_loc wise.
var/screen_start_y = 2
//End
var/limited_random_access = FALSE //Quick if statement in accessible_items to determine if we care at all about what people can access at once.
var/limited_random_access_stack_position = 0 //If >0, can only access top <x> items
var/limited_random_access_stack_bottom_up = FALSE //If TRUE, above becomes bottom <x> items
@@ -309,6 +309,7 @@
else
var/datum/numbered_display/ND = .[I.type]
ND.number++
. = sortTim(., /proc/cmp_numbered_displays_name_asc, associative = TRUE)
//This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing.
/datum/component/storage/proc/orient2hud(mob/user, maxcolumns)
@@ -646,9 +647,9 @@
if(M == viewing)
to_chat(usr, "<span class='notice'>You put [I] [insert_preposition]to [parent].</span>")
else if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is...
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", 1)
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", MSG_VISUAL)
else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance...
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", 1)
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", MSG_VISUAL)
/datum/component/storage/proc/update_icon()
if(isobj(parent))

View File

@@ -12,7 +12,7 @@
return COMPONENT_INCOMPATIBLE
var/mob/vr_M = parent
mastermind = M.mind
RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETED), .proc/game_over)
RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING), .proc/game_over)
RegisterSignal(M, COMSIG_MOB_KEY_CHANGE, .proc/switch_player)
RegisterSignal(mastermind, COMSIG_MIND_TRANSFER, .proc/switch_player)
you_die_in_the_game_you_die_for_real = yolo
@@ -32,7 +32,7 @@
current_mind = M.mind
quit_action.Grant(M)
RegisterSignal(quit_action, COMSIG_ACTION_TRIGGER, .proc/revert_to_reality)
RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETED), .proc/game_over)
RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING), .proc/game_over)
RegisterSignal(M, COMSIG_MOB_GHOSTIZE, .proc/be_a_quitter)
RegisterSignal(M, COMSIG_MOB_KEY_CHANGE, .proc/pass_me_the_remote)
RegisterSignal(current_mind, COMSIG_MIND_TRANSFER, .proc/pass_me_the_remote)
@@ -42,7 +42,7 @@
/datum/component/virtual_reality/UnregisterFromParent()
quit_action.Remove(parent)
UnregisterSignal(parent, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETED, COMSIG_MOB_KEY_CHANGE, COMSIG_MOB_GHOSTIZE))
UnregisterSignal(parent, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING, COMSIG_MOB_KEY_CHANGE, COMSIG_MOB_GHOSTIZE))
UnregisterSignal(current_mind, COMSIG_MIND_TRANSFER)
UnregisterSignal(quit_action, COMSIG_ACTION_TRIGGER)
current_mind = null

View File

@@ -174,3 +174,13 @@
/datum/dog_fashion/back/deathsquad
name = "Trooper REAL_NAME"
desc = "That's not red paint. That's real corgi blood."
/datum/dog_fashion/head/colour
name = "Stylish REAL_NAME"
desc = "From the tips of their paws to the top of their head, they look like a made bed."
emote_see = list("tries to tap dances.","looks sadly at others outfits...","barks at bad fashion!")
/datum/dog_fashion/head/telegram
name = "Messenger REAL_NAME"
desc = "Dont shoot the messenger..."
emote_see = list("licks an envelope.","looks ready to set off to send a letter...","works on barking!")

View File

@@ -0,0 +1,39 @@
/datum/element
var/element_flags = NONE
/**
* The index of the first attach argument to consider for duplicate elements
* Is only used when flags contains ELEMENT_BESPOKE
* This is infinity so you must explicitly set this
*/
var/id_arg_index = INFINITY
/datum/element/proc/Attach(datum/target)
if(type == /datum/element)
return ELEMENT_INCOMPATIBLE
if(element_flags & ELEMENT_DETACH)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach)
/datum/element/proc/Detach(datum/source, force)
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
/datum/element/Destroy(force)
if(!force)
return QDEL_HINT_LETMELIVE
SSdcs.elements_by_type -= type
return ..()
//DATUM PROCS
/datum/proc/AddElement(eletype, ...)
var/datum/element/ele = SSdcs.GetElement(arglist(args))
args[1] = src
if(ele.Attach(arglist(args)) == ELEMENT_INCOMPATIBLE)
CRASH("Incompatible [eletype] assigned to a [type]! args: [json_encode(args)]")
/**
* Finds the singleton for the element type given and detaches it from src
* You only need additional arguments beyond the type if you're using ELEMENT_BESPOKE
*/
/datum/proc/RemoveElement(eletype, ...)
var/datum/element/ele = SSdcs.GetElement(arglist(args))
ele.Detach(src)

View File

@@ -1,13 +1,15 @@
/datum/component/cleaning
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/datum/element/cleaning/Attach(datum/target)
. = ..()
if(!ismovableatom(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/Clean)
/datum/component/cleaning/Initialize()
if(!ismovableatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/Clean)
/datum/element/cleaning/Detach(datum/target)
. = ..()
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
/datum/component/cleaning/proc/Clean()
var/atom/movable/AM = parent
/datum/element/cleaning/proc/Clean(datum/source)
var/atom/movable/AM = source
var/turf/T = AM.loc
SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
for(var/A in T)
@@ -43,4 +45,4 @@
cleaned_human.clean_blood()
cleaned_human.wash_cream()
cleaned_human.regenerate_icons()
to_chat(cleaned_human, "<span class='danger'>[src] cleans your face!</span>")
to_chat(cleaned_human, "<span class='danger'>[src] cleans your face!</span>")

View File

@@ -0,0 +1,37 @@
/datum/element/earhealing
element_flags = ELEMENT_DETACH
var/list/user_by_item = list()
/datum/element/earhealing/New()
START_PROCESSING(SSdcs, src)
/datum/element/earhealing/Attach(datum/target)
. = ..()
if(!isitem(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED), .proc/equippedChanged)
/datum/element/earhealing/Detach(datum/target)
. = ..()
UnregisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED))
user_by_item -= target
/datum/element/earhealing/proc/equippedChanged(datum/source, mob/living/carbon/user, slot)
if(slot == SLOT_EARS && istype(user))
user_by_item[source] = user
else
user_by_item -= source
/datum/element/earhealing/process()
for(var/i in user_by_item)
var/mob/living/carbon/user = user_by_item[i]
if(HAS_TRAIT(user, TRAIT_DEAF))
continue
var/obj/item/organ/ears/ears = user.getorganslot(ORGAN_SLOT_EARS)
if(!ears)
continue
ears.deaf = max(ears.deaf - 0.25, (ears.damage < ears.maxHealth ? 0 : 1)) // Do not clear deafness if our ears are too damaged
ears.damage = max(ears.damage - 0.025, 0)
CHECK_TICK

View File

@@ -1,6 +1,3 @@
#define EMOTE_VISIBLE 1
#define EMOTE_AUDIBLE 2
/datum/emote
var/key = "" //What calls the emote
var/key_third_person = "" //This will also call the emote

View File

@@ -198,7 +198,7 @@ GLOBAL_LIST_EMPTY(explosions)
var/list/items = list()
for(var/I in T)
var/atom/A = I
if (!A.prevent_content_explosion()) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't.
if (!(A.flags_1 & PREVENT_CONTENTS_EXPLOSION_1)) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't.
items += A.GetAllContents()
for(var/O in items)
var/atom/A = O

View File

@@ -11,6 +11,7 @@
var/restraining = 0 //used in cqc's disarm_act to check if the disarmed is being restrained and so whether they should be put in a chokehold or not
var/help_verb
var/no_guns = FALSE
var/pacifism_check = TRUE //are the martial arts combos/attacks unable to be used by pacifist.
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
/datum/martial_art/proc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)

View File

@@ -1,6 +1,7 @@
/datum/martial_art/boxing
name = "Boxing"
id = MARTIALART_BOXING
pacifism_check = FALSE //Let's pretend pacifists can boxe the heck out of other people, it only deals stamina damage right now.
/datum/martial_art/boxing/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
to_chat(A, "<span class='warning'>Can't disarm while boxing!</span>")
@@ -16,14 +17,15 @@
var/atk_verb = pick("left hook","right hook","straight punch")
var/damage = rand(5, 8) + A.dna.species.punchdamagelow
if(!damage)
var/damage = rand(10, 13)
var/extra_damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
if(extra_damage == A.dna.species.punchdamagelow)
playsound(D.loc, A.dna.species.miss_sound, 25, 1, -1)
D.visible_message("<span class='warning'>[A] has attempted to [atk_verb] [D]!</span>", \
"<span class='userdanger'>[A] has attempted to [atk_verb] [D]!</span>", null, COMBAT_MESSAGE_RANGE)
log_combat(A, D, "attempted to hit", atk_verb)
return 0
return TRUE
damage += extra_damage
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
var/armor_block = D.run_armor_check(affecting, "melee")

View File

@@ -124,6 +124,8 @@
add_to_streak("G",D)
if(check_streak(A,D))
return TRUE
if(A == D) // no self grab.
return FALSE
if(A.grab_state >= GRAB_AGGRESSIVE)
D.grabbedby(A, 1)
else

View File

@@ -19,6 +19,9 @@
owner.visible_message("<span class='danger'>[owner] assumes a neutral stance.</span>", "<b><i>Your next attack is cleared.</i></b>")
H.mind.martial_art.streak = ""
else
if(HAS_TRAIT(H, TRAIT_PACIFISM))
to_chat(H, "<span class='warning'>You don't want to harm other people!</span>")
return
owner.visible_message("<span class='danger'>[owner] assumes the Neck Chop stance!</span>", "<b><i>Your next attack will be a Neck Chop.</i></b>")
H.mind.martial_art.streak = "neck_chop"
@@ -36,6 +39,9 @@
owner.visible_message("<span class='danger'>[owner] assumes a neutral stance.</span>", "<b><i>Your next attack is cleared.</i></b>")
H.mind.martial_art.streak = ""
else
if(HAS_TRAIT(H, TRAIT_PACIFISM))
to_chat(H, "<span class='warning'>You don't want to harm other people!</span>")
return
owner.visible_message("<span class='danger'>[owner] assumes the Leg Sweep stance!</span>", "<b><i>Your next attack will be a Leg Sweep.</i></b>")
H.mind.martial_art.streak = "leg_sweep"
@@ -53,6 +59,9 @@
owner.visible_message("<span class='danger'>[owner] assumes a neutral stance.</span>", "<b><i>Your next attack is cleared.</i></b>")
H.mind.martial_art.streak = ""
else
if(HAS_TRAIT(H, TRAIT_PACIFISM))
to_chat(H, "<span class='warning'>You don't want to harm other people!</span>")
return
owner.visible_message("<span class='danger'>[owner] assumes the Lung Punch stance!</span>", "<b><i>Your next attack will be a Lung Punch.</i></b>")
H.mind.martial_art.streak = "quick_choke"//internal name for lung punch
@@ -145,8 +154,6 @@
return 1
/datum/martial_art/krav_maga/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
if(check_streak(A,D))
return 1
var/obj/item/I = null
if(prob(60))
I = D.get_active_held_item()

View File

@@ -1,6 +1,7 @@
/datum/martial_art/psychotic_brawling
name = "Psychotic Brawling"
id = MARTIALART_PSYCHOBRAWL
pacifism_check = FALSE //Quite uncontrollable and unpredictable, people will still end up harming others with it.
/datum/martial_art/psychotic_brawling/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
return psycho_attack(A,D)

View File

@@ -105,6 +105,8 @@
add_to_streak("G",D)
if(check_streak(A,D))
return 1
if(A == D) //no self grab stun
return FALSE
if(A.grab_state >= GRAB_AGGRESSIVE)
D.grabbedby(A, 1)
else

View File

@@ -49,6 +49,9 @@
if(owner.incapacitated())
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
return
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
return
owner.visible_message("<span class='danger'>[owner] prepares to BODY SLAM!</span>", "<b><i>Your next attack will be a BODY SLAM.</i></b>")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "slam"
@@ -61,6 +64,9 @@
if(owner.incapacitated())
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
return
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
return
owner.visible_message("<span class='danger'>[owner] prepares to THROW!</span>", "<b><i>Your next attack will be a THROW.</i></b>")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "throw"
@@ -73,6 +79,9 @@
if(owner.incapacitated())
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
return
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
return
owner.visible_message("<span class='danger'>[owner] prepares to KICK!</span>", "<b><i>Your next attack will be a KICK.</i></b>")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "kick"
@@ -85,6 +94,9 @@
if(owner.incapacitated())
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
return
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
return
owner.visible_message("<span class='danger'>[owner] prepares to STRIKE!</span>", "<b><i>Your next attack will be a STRIKE.</i></b>")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "strike"
@@ -97,6 +109,9 @@
if(owner.incapacitated())
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
return
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
return
owner.visible_message("<span class='danger'>[owner] prepares to LEG DROP!</span>", "<b><i>Your next attack will be a LEG DROP.</i></b>")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "drop"
@@ -433,8 +448,8 @@
/datum/martial_art/wrestling/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(check_streak(A,D))
return 1
if(A.pulling == D)
return 1
if(A.pulling == D || A == D) // don't stun grab yoursel
return FALSE
A.start_pulling(D)
D.visible_message("<span class='danger'>[A] gets [D] in a cinch!</span>", \
"<span class='userdanger'>[A] gets [D] in a cinch!</span>")

View File

@@ -91,7 +91,10 @@
if(current) // remove ourself from our old body's mind variable
current.mind = null
SStgui.on_transfer(current, new_character)
if(iscarbon(current))
var/mob/living/carbon/C = current
if(C.combatmode)
C.toggle_combat_mode(TRUE, TRUE)
if(!language_holder)
var/datum/language_holder/mob_holder = new_character.get_language_holder(shadow = FALSE)
language_holder = mob_holder.copy(src)

View File

@@ -53,3 +53,63 @@
mood_change = -20
timeout = 300
//special_screen_obj = "mood_happiness_bad" Originally in tg
/datum/mood_event/eigenstate
mood_change = -3
description = "<span class='warning'>Where the hell am I? Is this an alternative dimension ?</span>\n"
/datum/mood_event/enthrall
mood_change = 5
/datum/mood_event/enthrall/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/enthrallpraise
mood_change = 10
timeout = 1 MINUTES
/datum/mood_event/enthrallpraise/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/enthrallscold
mood_change = -10
timeout = 1 MINUTES
/datum/mood_event/enthrallscold/add_effects(message)
description = "<span class='warning'>[message]</span>\n"//aaa I'm not kinky enough for this
/datum/mood_event/enthrallmissing1
mood_change = -5
/datum/mood_event/enthrallmissing1/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing2
mood_change = -10
/datum/mood_event/enthrallmissing2/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing3
mood_change = -15
/datum/mood_event/enthrallmissing3/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing4
mood_change = -25
/datum/mood_event/enthrallmissing4/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/InLove
mood_change = 10
/datum/mood_event/InLove/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/MissingLove
mood_change = -10
/datum/mood_event/MissingLove/add_effects(message)
description = "<span class='warning'>[message]</span>\n"

View File

@@ -176,3 +176,25 @@
/datum/mood_event/revenant_blight/add_effects()
description = "<span class='umbra'>Just give up, [pick("no one will miss you", "there is nothing you can do to help", "even a clown would be more useful than you", "does it even matter in the end?")]...</span>\n"
/datum/mood_event/plushjack
description = "<span class='warning'>I have butchered a plush recently.</span>\n"
mood_change = -1
timeout = 2 MINUTES
/datum/mood_event/plush_nostuffing
description = "<span class='warning'>A plush I tried to pet had no stuffing...</span>\n"
mood_change = -1
timeout = 2 MINUTES
//Cursed stuff below
/datum/mood_event/emptypred
description = "<span class='nicegreen'>I had to let someone out.</span>\n"
mood_change = -2
timeout = 1 MINUTES
/datum/mood_event/emptyprey
description = "<span class='nicegreen'>It feels quite cold out here.</span>\n"
mood_change = -2
timeout = 1 MINUTES

View File

@@ -113,3 +113,38 @@
/datum/mood_event/happy_empath/add_effects(var/mob/happytarget)
description = "<span class='nicegreen'>[happytarget.name]'s happiness is infectious!</span>\n"
/datum/mood_event/headpat
description = "<span class='nicegreen'>Headpats are nice.</span>\n"
mood_change = 2
timeout = 2 MINUTES
/datum/mood_event/hugbox
description = "<span class='nicegreen'>I hugged a box of hugs recently.</span>\n"
mood_change = 1
timeout = 2 MINUTES
/datum/mood_event/plushpet
description = "<span class='nicegreen'>I pet a plush recently.</span>\n"
mood_change = 1
timeout = 3000
/datum/mood_event/plushplay
description = "<span class='nicegreen'>I've played with plushes recently.</span>\n"
mood_change = 3
timeout = 3000
//Cursed stuff below.
/datum/mood_event/orgasm
description = "<span class='userlove'>I came!</span>\n" //funny meme haha
mood_change = 3
timeout = 100 SECONDS
/datum/mood_event/fedpred
description = "<span class='nicegreen'>I've devoured someone!</span>\n"
mood_change = 3
/datum/mood_event/fedprey
description = "<span class='nicegreen'>It feels quite cozy in here.</span>\n"
mood_change = 3

View File

@@ -28,16 +28,16 @@
var/can_be_admin_equipped = TRUE // Set to FALSE if your outfit requires runtime parameters
var/list/chameleon_extras //extra types for chameleon outfit changes, mostly guns
/datum/outfit/proc/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
/datum/outfit/proc/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
//to be overridden for customization depending on client prefs,species etc
return
/datum/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
/datum/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
//to be overridden for toggling internals, id binding, access etc
return
/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE)
pre_equip(H, visualsOnly)
/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
pre_equip(H, visualsOnly, preference_source)
//Start with uniform,suit,backpack for additional slots
if(uniform)
@@ -103,7 +103,7 @@
var/obj/item/clothing/suit/space/hardsuit/HS = H.wear_suit
HS.ToggleHelmet()
post_equip(H, visualsOnly)
post_equip(H, visualsOnly, preference_source)
if(!visualsOnly)
apply_fingerprints(H)

View File

@@ -541,6 +541,38 @@
icon_state = "ichorial_stain"
alerttooltipstyle = "clockcult"
//GOLEM GANG
/datum/status_effect/strandling //get it, strand as in durathread strand + strangling = strandling hahahahahahahahahahhahahaha i want to die
id = "strandling"
status_type = STATUS_EFFECT_UNIQUE
alert_type = /obj/screen/alert/status_effect/strandling
/datum/status_effect/strandling/on_apply()
ADD_TRAIT(owner, TRAIT_MAGIC_CHOKE, "dumbmoron")
return ..()
/datum/status_effect/strandling/on_remove()
REMOVE_TRAIT(owner, TRAIT_MAGIC_CHOKE, "dumbmoron")
return ..()
/obj/screen/alert/status_effect/strandling
name = "Choking strand"
desc = "A magical strand of Durathread is wrapped around your neck, preventing you from breathing! Click this icon to remove the strand."
icon_state = "his_grace"
alerttooltipstyle = "hisgrace"
/obj/screen/alert/status_effect/strandling/Click(location, control, params)
. = ..()
to_chat(mob_viewer, "<span class='notice'>You attempt to remove the durathread strand from around your neck.</span>")
if(do_after(mob_viewer, 35, null, mob_viewer))
if(isliving(mob_viewer))
var/mob/living/L = mob_viewer
to_chat(mob_viewer, "<span class='notice'>You succesfuly remove the durathread strand.</span>")
L.remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND)
datum/status_effect/pacify
id = "pacify"
status_type = STATUS_EFFECT_REPLACE
@@ -567,8 +599,7 @@ datum/status_effect/pacify
tick_interval = 10
examine_text = "<span class='warning'>SUBJECTPRONOUN seems slow and unfocused.</span>"
var/stun = TRUE
var/triggered = FALSE
alert_type = null
alert_type = /obj/screen/alert/status_effect/trance
/obj/screen/alert/status_effect/trance
name = "Trance"
@@ -576,17 +607,6 @@ datum/status_effect/pacify
icon_state = "high"
/datum/status_effect/trance/tick()
if(HAS_TRAIT(owner, "hypnotherapy"))
if(triggered == TRUE)
UnregisterSignal(owner, COMSIG_MOVABLE_HEAR)
RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/hypnotize)
ADD_TRAIT(owner, TRAIT_MUTE, "trance")
if(!owner.has_quirk(/datum/quirk/monochromatic))
owner.add_client_colour(/datum/client_colour/monochrome)
to_chat(owner, "<span class='warning'>[pick("You feel your thoughts slow down...", "You suddenly feel extremely dizzy...", "You feel like you're in the middle of a dream...","You feel incredibly relaxed...")]</span>")
triggered = FALSE
else
return
if(stun)
owner.Stun(60, TRUE, TRUE)
owner.dizziness = 20
@@ -594,47 +614,88 @@ datum/status_effect/pacify
/datum/status_effect/trance/on_apply()
if(!iscarbon(owner))
return FALSE
if(HAS_TRAIT(owner, "hypnotherapy"))
RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/listen)
return TRUE
alert_type = /obj/screen/alert/status_effect/trance
RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/hypnotize)
ADD_TRAIT(owner, TRAIT_MUTE, "trance")
if(!owner.has_quirk(/datum/quirk/monochromatic))
owner.add_client_colour(/datum/client_colour/monochrome)
owner.add_client_colour(/datum/client_colour/monochrome/trance)
owner.visible_message("[stun ? "<span class='warning'>[owner] stands still as [owner.p_their()] eyes seem to focus on a distant point.</span>" : ""]", \
"<span class='warning'>[pick("You feel your thoughts slow down...", "You suddenly feel extremely dizzy...", "You feel like you're in the middle of a dream...","You feel incredibly relaxed...")]</span>")
return TRUE
/datum/status_effect/trance/on_creation(mob/living/new_owner, _duration, _stun = TRUE, source_quirk = FALSE)//hypnoquirk makes no visible message, prevents self antag messages, and places phrase below objectives.
/datum/status_effect/trance/on_creation(mob/living/new_owner, _duration, _stun = TRUE)
duration = _duration
stun = _stun
if(source_quirk == FALSE && HAS_TRAIT(owner, "hypnotherapy"))
REMOVE_TRAIT(owner, "hypnotherapy", ROUNDSTART_TRAIT)
return ..()
/datum/status_effect/trance/on_remove()
UnregisterSignal(owner, COMSIG_MOVABLE_HEAR)
REMOVE_TRAIT(owner, TRAIT_MUTE, "trance")
owner.dizziness = 0
if(!owner.has_quirk(/datum/quirk/monochromatic))
owner.remove_client_colour(/datum/client_colour/monochrome)
owner.remove_client_colour(/datum/client_colour/monochrome/trance)
to_chat(owner, "<span class='warning'>You snap out of your trance!</span>")
/datum/status_effect/trance/proc/listen(datum/source, message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
to_chat(owner, "<span class='notice'><i>[speaker] accidentally sets off your implanted trigger, sending you into a hypnotic daze!</i></span>")
triggered = TRUE
/datum/status_effect/trance/proc/hypnotize(datum/source, message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
/datum/status_effect/trance/proc/hypnotize(datum/source, list/hearing_args)
if(!owner.can_hear())
return
if(speaker == owner)
if(hearing_args[HEARING_SPEAKER] == owner)
return
var/mob/living/carbon/C = owner
C.cure_trauma_type(/datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY) //clear previous hypnosis
if(HAS_TRAIT(C, "hypnotherapy"))
addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, raw_message, TRUE), 10)
else
addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, raw_message), 10)
addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hearing_args[HEARING_RAW_MESSAGE]), 10)
addtimer(CALLBACK(C, /mob/living.proc/Stun, 60, TRUE, TRUE), 15) //Take some time to think about it
qdel(src)
/datum/status_effect/spasms
id = "spasms"
status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
/datum/status_effect/spasms/tick()
if(prob(15))
switch(rand(1,5))
if(1)
if((!owner.lying && !owner.buckled) && isturf(owner.loc))
to_chat(owner, "<span class='warning'>Your leg spasms!</span>")
step(owner, pick(GLOB.cardinals))
if(2)
if(owner.incapacitated())
return
var/obj/item/I = owner.get_active_held_item()
if(I)
to_chat(owner, "<span class='warning'>Your fingers spasm!</span>")
owner.log_message("used [I] due to a Muscle Spasm", LOG_ATTACK)
I.attack_self(owner)
if(3)
var/prev_intent = owner.a_intent
owner.a_intent = INTENT_HARM
var/range = 1
if(istype(owner.get_active_held_item(), /obj/item/gun)) //get targets to shoot at
range = 7
var/list/mob/living/targets = list()
for(var/mob/M in oview(owner, range))
if(isliving(M))
targets += M
if(LAZYLEN(targets))
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
owner.log_message(" attacked someone due to a Muscle Spasm", LOG_ATTACK) //the following attack will log itself
owner.ClickOn(pick(targets))
owner.a_intent = prev_intent
if(4)
var/prev_intent = owner.a_intent
owner.a_intent = INTENT_HARM
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
owner.log_message("attacked [owner.p_them()]self to a Muscle Spasm", LOG_ATTACK)
owner.ClickOn(owner)
owner.a_intent = prev_intent
if(5)
if(owner.incapacitated())
return
var/obj/item/I = owner.get_active_held_item()
var/list/turf/targets = list()
for(var/turf/T in oview(owner, 3))
targets += T
if(LAZYLEN(targets) && I)
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
owner.log_message("threw [I] due to a Muscle Spasm", LOG_ATTACK)
owner.throw_item(pick(targets))

View File

@@ -69,3 +69,17 @@
/datum/status_effect/in_love/tick()
if(date)
new /obj/effect/temp_visual/love_heart/invisible(get_turf(date.loc), owner)
/datum/status_effect/throat_soothed
id = "throat_soothed"
duration = 60 SECONDS
status_type = STATUS_EFFECT_REFRESH
alert_type = null
/datum/status_effect/throat_soothed/on_apply()
. = ..()
ADD_TRAIT(owner, TRAIT_SOOTHED_THROAT, "[STATUS_EFFECT_TRAIT]_[id]")
/datum/status_effect/throat_soothed/on_remove()
. = ..()
REMOVE_TRAIT(owner, TRAIT_SOOTHED_THROAT, "[STATUS_EFFECT_TRAIT]_[id]")

View File

@@ -64,6 +64,12 @@
owner = null
qdel(src)
/datum/status_effect/proc/refresh()
var/original_duration = initial(duration)
if(original_duration == -1)
return
duration = world.time + original_duration
//clickdelay/nextmove modifiers!
/datum/status_effect/proc/nextmove_modifier()
return 1
@@ -92,6 +98,9 @@
if(S.id == initial(S1.id) && S.status_type)
if(S.status_type == STATUS_EFFECT_REPLACE)
S.be_replaced()
else if(S.status_type == STATUS_EFFECT_REFRESH)
S.refresh()
return
else
return
var/list/arguments = args.Copy()

View File

@@ -280,35 +280,35 @@
///Generate the full examine string of this atom (including icon for goonchat)
/atom/proc/get_examine_string(mob/user, thats = FALSE)
. = "[icon2html(src, user)] [thats? "That's ":""][get_examine_name(user)]"
return "[icon2html(src, user)] [thats? "That's ":""][get_examine_name(user)]"
/atom/proc/examine(mob/user)
to_chat(user, "[get_examine_string(user, TRUE)].")
. = list("[get_examine_string(user, TRUE)].")
if(desc)
to_chat(user, desc)
. += desc
if(reagents)
if(reagents.reagents_holder_flags & TRANSPARENT)
to_chat(user, "It contains:")
if(reagents.reagent_list.len)
. += "It contains:"
if(length(reagents.reagent_list))
if(user.can_see_reagents()) //Show each individual reagent
for(var/datum/reagent/R in reagents.reagent_list)
to_chat(user, "[R.volume] units of [R.name]")
. += "[R.volume] units of [R.name]"
else //Otherwise, just show the total volume
var/total_volume = 0
for(var/datum/reagent/R in reagents.reagent_list)
total_volume += R.volume
to_chat(user, "[total_volume] units of various reagents")
. += "[total_volume] units of various reagents"
else
to_chat(user, "Nothing.")
. += "Nothing."
else if(reagents.reagents_holder_flags & AMOUNT_VISIBLE)
if(reagents.total_volume)
to_chat(user, "<span class='notice'>It has [reagents.total_volume] unit\s left.</span>")
. += "<span class='notice'>It has [reagents.total_volume] unit\s left.</span>"
else
to_chat(user, "<span class='danger'>It's empty.</span>")
. += "<span class='danger'>It's empty.</span>"
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user)
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
/atom/proc/relaymove(mob/user)
if(buckle_message_cooldown <= world.time)
@@ -316,9 +316,6 @@
to_chat(user, "<span class='warning'>You can't move while buckled to [src]!</span>")
return
/atom/proc/prevent_content_explosion()
return FALSE
/atom/proc/contents_explosion(severity, target)
return //For handling the effects of explosions on contents that would not normally be effected
@@ -660,7 +657,7 @@
var/atom/L = loc
if(!L)
return null
return L.AllowDrop() ? L : get_turf(L)
return L.AllowDrop() ? L : L.drop_location()
/atom/Entered(atom/movable/AM, atom/oldLoc)
SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, AM, oldLoc)

View File

@@ -189,7 +189,13 @@
if(tod)
var/tdelta = round(world.time - timeofdeath)
if(tdelta < (DEFIB_TIME_LIMIT * 10))
holder.icon_state = "huddefib"
var/obj/item/organ/heart/He = getorgan(/obj/item/organ/heart)
if(He)
holder.icon_state = "huddefib"
if(He.organ_flags & ORGAN_FAILING)
holder.icon_state = "huddefibheart"
else
holder.icon_state = "huddefibheart"
return
holder.icon_state = "huddead"
else

View File

@@ -339,10 +339,6 @@ Credit where due:
CLOCKCULTCHANGELOG\
</ul>\
<hr>\
<li><b>Zelus oil:</b> A new reagent. It can be used to heal the faithful to Ratvar, or kill heretics and moreso stun blood cultists,\
or splashed onto metal sheets to make brass. This chemical can be found in minimal quantities by grinding brass sheets.\
<li><b>Brass Flasks:</b>Intended to store Zelus Oil in, but can also be used as fragile single use throwing weapons in a pinch! \
These are crafted with a single sheet of brass and fit in the Clockwork Cuirass' suit storage.\
<b>Good luck!</b>"
/obj/item/paper/servant_primer/Initialize()
@@ -353,7 +349,7 @@ Credit where due:
changelog_contents += "<li>[entry]</li>"
info = replacetext(info, "CLOCKCULTCHANGELOG", changelog_contents)
/obj/item/paper/servant_primer/examine(mob/user)
if(!is_servant_of_ratvar(user) && !isobserver(user))
to_chat(user, "<span class='danger'>You can't understand any of the words on [src].</span>")
..()
/obj/item/paper/servant_primer/oui_getcontent(mob/target)
if(!is_servant_of_ratvar(target) && !isobserver(target))
return "<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)]<HR>[stamps]</BODY></HTML>"
return ..()

View File

@@ -53,7 +53,7 @@
/datum/outfit/syndicate/clownop/no_crystals
tc = 0
/datum/outfit/syndicate/clownop/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
/datum/outfit/syndicate/clownop/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
..()
if(visualsOnly)
return

View File

@@ -409,7 +409,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
message_admins("Drafting players for forced ruleset [rule.name].")
log_game("DYNAMIC: Drafting players for forced ruleset [rule.name].")
rule.mode = src
rule.acceptable(GLOB.player_list.len, threat_level) // Assigns some vars in the modes, running it here for consistency
rule.acceptable(roundstart_pop_ready, threat_level) // Assigns some vars in the modes, running it here for consistency
rule.candidates = candidates.Copy()
rule.trim_candidates()
if (rule.ready(TRUE))
@@ -421,7 +421,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
return TRUE
var/list/drafted_rules = list()
for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules)
if (rule.acceptable(GLOB.player_list.len, threat_level) && threat >= rule.cost) // If we got the population and threat required
if (rule.acceptable(roundstart_pop_ready, threat_level) && threat >= rule.cost) // If we got the population and threat required
rule.candidates = candidates.Copy()
rule.trim_candidates()
if (rule.ready() && rule.candidates.len > 0)
@@ -429,12 +429,12 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
if(!drafted_rules.len)
message_admins("Not enough threat level for roundstart antags!")
log_game("DYNAMIC: Not enough threat level for roundstart antags!")
var/indice_pop = min(10,round(GLOB.player_list.len/pop_per_requirement)+1)
var/indice_pop = min(10,round(roundstart_pop_ready/pop_per_requirement)+1)
extra_rulesets_amount = 0
if (GLOB.dynamic_classic_secret)
extra_rulesets_amount = 0
else
if (GLOB.player_list.len > GLOB.dynamic_high_pop_limit)
if (roundstart_pop_ready > GLOB.dynamic_high_pop_limit)
message_admins("High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.")
log_game("DYNAMIC: High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.")
if (threat_level > high_pop_second_rule_req)
@@ -510,7 +510,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
var/added_threat = starting_rule.scale_up(extra_rulesets_amount, threat)
if (starting_rule.pre_execute())
spend_threat(starting_rule.cost + added_threat)
log_threat("[starting_rule.ruletype] - <b>[starting_rule.name]</b> -[starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat")
log_threat("[starting_rule.ruletype] - <b>[starting_rule.name]</b> -[starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat", verbose = TRUE)
if(starting_rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
else if(starting_rule.flags & ONLY_RULESET)
@@ -605,7 +605,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
new_rule.trim_candidates()
if (new_rule.ready(forced))
spend_threat(new_rule.cost)
log_threat("[new_rule.ruletype] - <b>[new_rule.name]</b> -[new_rule.cost] threat")
log_threat("[new_rule.ruletype] - <b>[new_rule.name]</b> -[new_rule.cost] threat", verbose = TRUE)
if (new_rule.execute()) // This should never fail since ready() returned 1
if(new_rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
@@ -626,7 +626,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
if (rule.execute())
log_game("DYNAMIC: Injected a [rule.ruletype == "latejoin" ? "latejoin" : "midround"] ruleset [rule.name].")
spend_threat(rule.cost)
log_threat("[rule.ruletype] [rule.name] spent [rule.cost]")
log_threat("[rule.ruletype] [rule.name] spent [rule.cost]", verbose = TRUE)
if(rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
else if(rule.flags & ONLY_RULESET)
@@ -815,16 +815,19 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
/// Refund threat, but no more than threat_level.
/datum/game_mode/dynamic/proc/refund_threat(regain)
threat = min(threat_level,threat+regain)
log_threat("[regain] refunded. Threat is now [threat].", verbose = TRUE)
/// Generate threat and increase the threat_level if it goes beyond, capped at 100
/datum/game_mode/dynamic/proc/create_threat(gain)
threat = min(100, threat+gain)
if(threat > threat_level)
threat_level = threat
log_threat("[gain] created. Threat is now [threat] and threat level is now [threat_level].", verbose = TRUE)
/// Expend threat, can't fall under 0.
/datum/game_mode/dynamic/proc/spend_threat(cost)
threat = max(threat-cost,0)
log_threat("[cost] spent. Threat is now [threat].", verbose = TRUE)
/// Turns the value generated by lorentz distribution to threat value between 0 and 100.
/datum/game_mode/dynamic/proc/lorentz_to_threat(x)

View File

@@ -143,7 +143,6 @@
repeatable_weight_decrease = 2
requirements = list(60,50,40,30,30,30,30,30,30,30)
high_population_requirement = 30
repeatable = TRUE
/datum/dynamic_ruleset/event/meteor_wave/ready()
if(mode.threat_level > 40 && mode.threat >= 25 && prob(20))
@@ -270,7 +269,7 @@
repeatable = TRUE
/datum/dynamic_ruleset/event/processor_overload
name = "Processer Overload"
name = "Processor Overload"
config_tag = "processor_overload"
typepath = /datum/round_event/processor_overload
cost = 4

View File

@@ -41,6 +41,9 @@
if (!istype(M, required_type))
trimmed_list.Remove(M)
continue
if (M.GetComponent(/datum/component/virtual_reality))
trimmed_list.Remove(M)
continue
if (!M.client) // Are they connected?
trimmed_list.Remove(M)
continue
@@ -107,11 +110,11 @@
candidates = pollGhostCandidates("The mode is looking for volunteers to become a [name]", antag_flag, SSticker.mode, antag_flag, poll_time = 300)
if(!candidates || candidates.len <= 0)
message_admins("The ruleset [name] received no applications.")
log_game("DYNAMIC: The ruleset [name] received no applications.")
if(!candidates || candidates.len <= required_candidates)
message_admins("The ruleset [name] did not receive enough applications.")
log_game("DYNAMIC: The ruleset [name] did not receive enough applications.")
mode.refund_threat(cost)
mode.log_threat("Rule [name] refunded [cost] (no applications)",verbose=TRUE)
mode.log_threat("Rule [name] refunded [cost] (not receive enough applications)",verbose=TRUE)
mode.executed_rules -= src
return
@@ -150,7 +153,7 @@
finish_setup(new_character, i)
assigned += applicant
notify_ghosts("[new_character] has been picked for the ruleset [name]!", source = new_character, action = NOTIFY_ORBIT, header="Something Interesting!")
notify_ghosts("[new_character] has been picked for the ruleset [name]!", source = new_character, action = NOTIFY_ORBIT)
/datum/dynamic_ruleset/midround/from_ghosts/proc/generate_ruleset_body(mob/applicant)
var/mob/living/carbon/human/new_character = makeBody(applicant)
@@ -283,6 +286,7 @@
/datum/dynamic_ruleset/midround/from_ghosts/wizard
name = "Wizard"
config_tag = "midround_wizard"
persistent = TRUE
antag_datum = /datum/antagonist/wizard
antag_flag = ROLE_WIZARD
enemy_roles = list("Security Officer","Detective","Head of Security", "Captain")
@@ -293,6 +297,7 @@
requirements = list(90,90,70,50,50,50,50,40,30,30)
high_population_requirement = 30
repeatable = TRUE
var/datum/mind/wizard
/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE)
if (required_candidates > (dead_players.len + list_observers.len))
@@ -307,6 +312,20 @@
..()
new_character.forceMove(pick(GLOB.wizardstart))
/datum/dynamic_ruleset/midround/from_ghosts/wizard/rule_process() // i can literally copy this from are_special_antags_dead it's great
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
return FALSE
for(var/obj/item/phylactery/P in GLOB.poi_list) //TODO : IsProperlyDead()
if(P.mind && P.mind.has_antag_datum(/datum/antagonist/wizard))
return FALSE
if(SSevents.wizardmode) //If summon events was active, turn it off
SSevents.toggleWizardmode()
SSevents.resetFrequency()
return RULESET_STOP_PROCESSING
//////////////////////////////////////////////
// //
// NUCLEAR OPERATIVES (MIDROUND) //

View File

@@ -149,6 +149,7 @@
/datum/dynamic_ruleset/roundstart/wizard
name = "Wizard"
config_tag = "wizard"
persistent = TRUE
antag_flag = ROLE_WIZARD
antag_datum = /datum/antagonist/wizard
minimum_required_age = 14
@@ -183,8 +184,25 @@
for(var/datum/mind/M in assigned)
M.current.forceMove(pick(GLOB.wizardstart))
M.add_antag_datum(new antag_datum())
roundstart_wizards += M
return TRUE
/datum/dynamic_ruleset/roundstart/wizard/rule_process() // i can literally copy this from are_special_antags_dead it's great
for(var/datum/mind/wizard in roundstart_wizards)
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
return FALSE
for(var/obj/item/phylactery/P in GLOB.poi_list) //TODO : IsProperlyDead()
if(P.mind && P.mind.has_antag_datum(/datum/antagonist/wizard))
return FALSE
if(SSevents.wizardmode) //If summon events was active, turn it off
SSevents.toggleWizardmode()
SSevents.resetFrequency()
return RULESET_STOP_PROCESSING
//////////////////////////////////////////////
// //
// BLOOD CULT //
@@ -263,7 +281,7 @@
requirements = list(100,90,80,70,60,50,50,50,50,50)
high_population_requirement = 50
flags = HIGHLANDER_RULESET
antag_cap = list(2,2,2,3,3,3,4,4,5,5)
antag_cap = list(1,1,2,3,4,5,5,5,5,5)
var/datum/team/nuclear/nuke_team
/datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE)

View File

@@ -167,7 +167,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
/obj/effect/meteor/examine(mob/user)
if(!(flags_1 & ADMIN_SPAWNED_1) && isliving(user))
SSmedals.UnlockMedal(MEDAL_METEOR, user.client)
..()
return ..()
/obj/effect/meteor/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_MINING)

View File

@@ -144,7 +144,7 @@
/datum/outfit/syndicate/no_crystals
tc = 0
/datum/outfit/syndicate/post_equip(mob/living/carbon/human/H)
/datum/outfit/syndicate/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
var/obj/item/radio/R = H.ears
R.set_frequency(FREQ_SYNDICATE)
R.freqlock = TRUE

View File

@@ -12,6 +12,7 @@
density = FALSE
state_open = TRUE
circuit = /obj/item/circuitboard/machine/sleeper
req_access = list(ACCESS_CMO) //Used for reagent deletion and addition of non medicines
var/efficiency = 1
var/min_health = -25
var/list/available_chems
@@ -28,9 +29,27 @@
/obj/machinery/sleeper/Initialize()
. = ..()
create_reagents(500, NO_REACT)
occupant_typecache = GLOB.typecache_living
update_icon()
reset_chem_buttons()
RefreshParts()
add_inital_chems()
/obj/machinery/sleeper/on_deconstruction()
var/obj/item/reagent_containers/sleeper_buffer/buffer = new (loc)
buffer.volume = reagents.maximum_volume
buffer.reagents.maximum_volume = reagents.maximum_volume
reagents.trans_to(buffer.reagents, reagents.total_volume)
/obj/machinery/sleeper/proc/add_inital_chems()
for(var/i in available_chems)
var/datum/reagent/R = reagents.has_reagent(i)
if(!R)
reagents.add_reagent(i, (20))
continue
if(R.volume < 20)
reagents.add_reagent(i, (20 - R.volume))
/obj/machinery/sleeper/RefreshParts()
var/E
@@ -47,6 +66,11 @@
available_chems |= possible_chems[i]
reset_chem_buttons()
//Total container size 500 - 2000u
if(reagents)
reagents.maximum_volume = (500*E)
/obj/machinery/sleeper/update_icon()
icon_state = initial(icon_state)
if(state_open)
@@ -81,7 +105,42 @@
if (. & EMP_PROTECT_SELF)
return
if(is_operational() && occupant)
var/datum/reagent/R = pick(reagents.reagent_list)
inject_chem(R.id, occupant)
open_machine()
//Is this too much?
if(severity == EMP_HEAVY)
var/chem = pick(available_chems)
available_chems -= chem
available_chems += get_random_reagent_id()
reset_chem_buttons()
/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/reagent_containers/sleeper_buffer))
var/obj/item/reagent_containers/sleeper_buffer/SB = I
if((SB.reagents.total_volume + reagents.total_volume) < reagents.maximum_volume)
SB.reagents.trans_to(reagents, SB.reagents.total_volume)
visible_message("[user] places the [SB] into the [src].")
qdel(SB)
return
else
SB.reagents.trans_to(reagents, SB.reagents.total_volume)
visible_message("[user] adds as much as they can to the [src] from the [SB].")
return
if(istype(I, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = I
if(RC.reagents.total_volume == 0)
to_chat(user, "<span class='notice'>The [I] is empty!</span>")
for(var/datum/reagent/R in RC.reagents.reagent_list)
if((obj_flags & EMAGGED) || (allowed(usr)))
break
if(!istype(R, /datum/reagent/medicine))
visible_message("The [src] gives out a hearty boop and rejects the [I]. The Sleeper's screen flashes with a pompous \"Medicines only, please.\"")
return
RC.reagents.trans_to(reagents, 1000)
visible_message("[user] adds as much as they can to the [src] from the [I].")
return
/obj/machinery/sleeper/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
@@ -130,8 +189,8 @@
open_machine()
/obj/machinery/sleeper/examine(mob/user)
..()
to_chat(user, "<span class='notice'>Alt-click [src] to [state_open ? "close" : "open"] it.</span>")
. = ..()
. += "<span class='notice'>Alt-click [src] to [state_open ? "close" : "open"] it.</span>"
/obj/machinery/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
@@ -141,18 +200,24 @@
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "sleeper", name, 375, 550, master_ui, state)
ui = new(user, src, ui_key, "sleeper", name, 550, 700, master_ui, state)
ui.open()
/obj/machinery/sleeper/ui_data()
var/list/data = list()
data["occupied"] = occupant ? 1 : 0
data["open"] = state_open
data["efficiency"] = efficiency
data["current_vol"] = reagents.total_volume
data["tot_capacity"] = reagents.maximum_volume
data["chems"] = list()
for(var/chem in available_chems)
var/datum/reagent/R = GLOB.chemical_reagents_list[chem]
data["chems"] += list(list("name" = R.name, "id" = R.id, "allowed" = chem_allowed(chem)))
var/datum/reagent/R = reagents.has_reagent(chem)
R = GLOB.chemical_reagents_list[chem]
data["synthchems"] += list(list("name" = R.name, "id" = R.id, "synth_allowed" = synth_allowed(chem)))
for(var/datum/reagent/R in reagents.reagent_list)
data["chems"] += list(list("name" = R.name, "id" = R.id, "vol" = R.volume, "purity" = R.purity, "allowed" = chem_allowed(R.id)))
data["occupant"] = list()
var/mob/living/mob_occupant = occupant
@@ -184,8 +249,15 @@
if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len)
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume))
data["occupant"]["failing_organs"] = list()
var/mob/living/carbon/C = mob_occupant
if(C)
for(var/obj/item/organ/Or in C.getFailingOrgans())
if(istype(Or, /obj/item/organ/brain))
continue
data["occupant"]["failing_organs"] += list(list("name" = Or.name))
if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner.
var/mob/living/carbon/C = mob_occupant
var/blood_id = C.get_blood_id()
if(blood_id)
data["occupant"]["blood"] = list() // We can start populating this list.
@@ -196,7 +268,7 @@
blood_type = R.name
else
blood_type = blood_id
data["occupant"]["blood"]["maxBloodVolume"] = BLOOD_VOLUME_NORMAL
data["occupant"]["blood"]["maxBloodVolume"] = (BLOOD_VOLUME_NORMAL*C.blood_ratio)
data["occupant"]["blood"]["currentBloodVolume"] = C.blood_volume
data["occupant"]["blood"]["dangerBloodVolume"] = BLOOD_VOLUME_SAFE
data["occupant"]["blood"]["bloodType"] = blood_type
@@ -216,24 +288,49 @@
. = TRUE
if("inject")
var/chem = params["chem"]
var/amount = text2num(params["volume"])
if(!is_operational() || !mob_occupant)
return
if(mob_occupant.health < min_health && chem != "epinephrine")
return
if(inject_chem(chem, usr))
if(inject_chem(chem, usr, amount))
. = TRUE
if(scrambled_chems && prob(5))
to_chat(usr, "<span class='warning'>Chemical system re-route detected, results may not be as expected!</span>")
if("synth")
var/chem = params["chem"]
if(!is_operational())
return
reagents.add_reagent(chem_buttons[chem], 10) //other_purity = 0.75 for when the mechanics are in
if("purge")
var/chem = params["chem"]
if(allowed(usr))
if(!is_operational())
return
reagents.remove_reagent(chem, 10)
return
if(chem in available_chems)
if(!is_operational())
return
/*var/datum/reagent/R = reagents.has_reagent(chem) //For when purity effects are in
if(R.purity < 0.8)*/
reagents.remove_reagent(chem, 10)
else
visible_message("<span class='warning'>Access Denied.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
/obj/machinery/sleeper/emag_act(mob/user)
. = ..()
obj_flags |= EMAGGED
scramble_chem_buttons()
to_chat(user, "<span class='warning'>You scramble the sleeper's user interface!</span>")
return TRUE
/obj/machinery/sleeper/proc/inject_chem(chem, mob/user)
if((chem in available_chems) && chem_allowed(chem))
occupant.reagents.add_reagent(chem_buttons[chem], 10) //emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU
//trans to
/obj/machinery/sleeper/proc/inject_chem(chem, mob/user, volume = 10)
if(chem_allowed(chem))
reagents.trans_id_to(occupant, chem, volume)//emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU
if(user)
log_combat(user, occupant, "injected [chem] into", addition = "via [src]")
return TRUE
@@ -246,6 +343,14 @@
var/occ_health = mob_occupant.health > min_health || chem == "epinephrine"
return amount && occ_health
/obj/machinery/sleeper/proc/synth_allowed(chem)
var/datum/reagent/R = reagents.has_reagent(chem)
if(!R)
return TRUE
if(R.volume < 50)
return TRUE
return FALSE
/obj/machinery/sleeper/proc/reset_chem_buttons()
scrambled_chems = FALSE
LAZYINITLIST(chem_buttons)

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