Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit265
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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("", "", "")\
|
||||
)
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -210,6 +210,8 @@ GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list(
|
||||
|
||||
#define isitem(A) (istype(A, /obj/item))
|
||||
|
||||
#define isidcard(I) (istype(I, /obj/item/card/id))
|
||||
|
||||
#define isstructure(A) (istype(A, /obj/structure))
|
||||
|
||||
#define ismachinery(A) (istype(A, /obj/machinery))
|
||||
|
||||
@@ -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)
|
||||
@@ -485,6 +485,11 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
|
||||
#define AREASELECT_CORNERA "corner A"
|
||||
#define AREASELECT_CORNERB "corner B"
|
||||
|
||||
#define VARSET_FROM_LIST(L, V) if(L && L[#V]) V = L[#V]
|
||||
#define VARSET_FROM_LIST_IF(L, V, C...) if(L && L[#V] && (C)) V = L[#V]
|
||||
#define VARSET_TO_LIST(L, V) if(L) L[#V] = V
|
||||
#define VARSET_TO_LIST_IF(L, V, C...) if(L && (C)) L[#V] = V
|
||||
|
||||
#define PREF_SAVELOAD_COOLDOWN 5
|
||||
|
||||
#define VOMIT_TOXIC 1
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -75,3 +75,10 @@
|
||||
#define JP_LOW 1
|
||||
#define JP_MEDIUM 2
|
||||
#define JP_HIGH 3
|
||||
|
||||
//Chaos levels for dynamic voting
|
||||
#define CHAOS_NONE "None (Extended)"
|
||||
#define CHAOS_LOW "Low"
|
||||
#define CHAOS_MED "Medium"
|
||||
#define CHAOS_HIGH "High"
|
||||
#define CHAOS_MAX "Maximum"
|
||||
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -213,3 +218,4 @@
|
||||
#define NINJA_SUIT_TRAIT "ninja-suit"
|
||||
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
|
||||
#define ABDUCTOR_ANTAGONIST "abductor-antagonist"
|
||||
#define MADE_UNCLONEABLE "made-uncloneable"
|
||||
|
||||
@@ -573,4 +573,10 @@
|
||||
if(key in L1)
|
||||
L1[key] += other_value
|
||||
else
|
||||
L1[key] = other_value
|
||||
L1[key] = other_value
|
||||
|
||||
/proc/assoc_list_strip_value(list/input)
|
||||
var/list/ret = list()
|
||||
for(var/key in input)
|
||||
ret += key
|
||||
return ret
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -314,7 +314,12 @@
|
||||
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] threat"
|
||||
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]]"
|
||||
return parts.Join("<br>")
|
||||
|
||||
/client/proc/roundend_report_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,
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/screen/examine(mob/user)
|
||||
return
|
||||
return list()
|
||||
|
||||
/obj/screen/orbit()
|
||||
return
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/datum/config_entry/flag/dynamic_voting
|
||||
|
||||
/datum/config_entry/number/dynamic_high_pop_limit
|
||||
config_entry_value = 55
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_pop_per_requirement
|
||||
config_entry_value = 6
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_min
|
||||
config_entry_value = 15
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_max
|
||||
config_entry_value = 35
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_min
|
||||
config_entry_value = 5
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_max
|
||||
config_entry_value = 25
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_midround_delay_min
|
||||
config_entry_value = 20
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_midround_delay_max
|
||||
config_entry_value = 40
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_latejoin_delay_min
|
||||
config_entry_value = 10
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_latejoin_delay_max
|
||||
config_entry_value = 30
|
||||
min_val = 1
|
||||
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_cost
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_weight
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_requirements
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM_LIST
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_high_population_requirement
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/number_list/dynamic_second_rule_requirements
|
||||
|
||||
/datum/config_entry/number_list/dynamic_third_rule_requirements
|
||||
|
||||
/datum/config_entry/number/dynamic_second_rule_high_pop_requirement
|
||||
config_entry_value = 50
|
||||
|
||||
/datum/config_entry/number/dynamic_third_rule_high_pop_requirement
|
||||
config_entry_value = 70
|
||||
|
||||
/datum/config_entry/number_list/dynamic_hijack_requirements
|
||||
|
||||
/datum/config_entry/number/dynamic_hijack_high_population_requirement
|
||||
config_entry_value = 25
|
||||
|
||||
/datum/config_entry/number/dynamic_hijack_cost
|
||||
config_entry_value = 5
|
||||
|
||||
/datum/config_entry/number/dynamic_glorious_death_cost
|
||||
config_entry_value = 5
|
||||
|
||||
/datum/config_entry/number/dynamic_assassinate_cost
|
||||
config_entry_value = 2
|
||||
|
||||
/datum/config_entry/number/dynamic_warops_requirement
|
||||
config_entry_value = 60
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/dynamic_warops_cost
|
||||
config_entry_value = 10
|
||||
min_val = 0
|
||||
@@ -379,43 +379,3 @@
|
||||
/datum/config_entry/number/auto_transfer_delay
|
||||
config_entry_value = 72000
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/dynamic_high_pop_limit
|
||||
config_entry_value = 55
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_pop_per_requirement
|
||||
config_entry_value = 6
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_min
|
||||
config_entry_value = 15
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_max
|
||||
config_entry_value = 35
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_min
|
||||
config_entry_value = 5
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_max
|
||||
config_entry_value = 25
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_cost
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_weight
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_requirements
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM_LIST
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_high_population_requirement
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -4,24 +4,32 @@ SUBSYSTEM_DEF(research)
|
||||
priority = FIRE_PRIORITY_RESEARCH
|
||||
wait = 10
|
||||
init_order = INIT_ORDER_RESEARCH
|
||||
//TECHWEB STATIC
|
||||
var/list/techweb_nodes = list() //associative id = node datum
|
||||
var/list/techweb_designs = list() //associative id = node datum
|
||||
var/list/datum/techweb/techwebs = list()
|
||||
var/datum/techweb/science/science_tech
|
||||
var/datum/techweb/admin/admin_tech
|
||||
var/datum/techweb_node/error_node/error_node //These two are what you get if a node/design is deleted and somehow still stored in a console.
|
||||
var/datum/design/error_design/error_design
|
||||
|
||||
//ERROR LOGGING
|
||||
var/list/invalid_design_ids = list() //associative id = number of times
|
||||
var/list/invalid_node_ids = list() //associative id = number of times
|
||||
var/list/invalid_node_boost = list() //associative id = error message
|
||||
|
||||
var/list/obj/machinery/rnd/server/servers = list()
|
||||
var/datum/techweb/science/science_tech
|
||||
var/datum/techweb/admin/admin_tech
|
||||
var/list/techweb_nodes = list() //associative id = node datum
|
||||
var/list/techweb_categories = list() //category name = list(node.id = node)
|
||||
var/list/techweb_designs = list() //associative id = node datum
|
||||
var/list/techweb_nodes_starting = list() //associative id = node datum
|
||||
|
||||
var/list/techweb_nodes_starting = list() //associative id = TRUE
|
||||
var/list/techweb_categories = list() //category name = list(node.id = TRUE)
|
||||
var/list/techweb_boost_items = list() //associative double-layer path = list(id = list(point_type = point_discount))
|
||||
var/list/techweb_nodes_hidden = list() //Nodes that should be hidden by default.
|
||||
var/list/techweb_nodes_hidden = list() //Node ids that should be hidden by default.
|
||||
var/list/techweb_point_items = list( //path = list(point type = value)
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 2500),
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 5000), // Cit three more anomalys anomalys
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 7500),
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 10000),
|
||||
// - Slime Extracts! -
|
||||
// - Slime Extracts! -
|
||||
/obj/item/slime_extract/grey = list(TECHWEB_POINT_TYPE_GENERIC = 500), // Adds in slime core deconing
|
||||
/obj/item/slime_extract/metal = list(TECHWEB_POINT_TYPE_GENERIC = 750),
|
||||
/obj/item/slime_extract/purple = list(TECHWEB_POINT_TYPE_GENERIC = 750),
|
||||
@@ -294,6 +302,8 @@ SUBSYSTEM_DEF(research)
|
||||
science_tech = new /datum/techweb/science
|
||||
admin_tech = new /datum/techweb/admin
|
||||
autosort_categories()
|
||||
error_design = new
|
||||
error_node = new
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/research/fire()
|
||||
@@ -330,6 +340,191 @@ SUBSYSTEM_DEF(research)
|
||||
for(var/i in techweb_nodes)
|
||||
var/datum/techweb_node/I = techweb_nodes[i]
|
||||
if(techweb_categories[I.category])
|
||||
techweb_categories[I.category][I.id] = I
|
||||
techweb_categories[I.category][I.id] = TRUE
|
||||
else
|
||||
techweb_categories[I.category] = list(I.id = I)
|
||||
techweb_categories[I.category] = list(I.id = TRUE)
|
||||
|
||||
/datum/controller/subsystem/research/proc/techweb_node_by_id(id)
|
||||
return techweb_nodes[id] || error_node
|
||||
|
||||
/datum/controller/subsystem/research/proc/techweb_design_by_id(id)
|
||||
return techweb_designs[id] || error_design
|
||||
|
||||
/datum/controller/subsystem/research/proc/on_design_deletion(datum/design/D)
|
||||
for(var/i in techweb_nodes)
|
||||
var/datum/techweb_node/TN = techwebs[i]
|
||||
TN.on_design_deletion(TN)
|
||||
for(var/i in techwebs)
|
||||
var/datum/techweb/T = i
|
||||
T.recalculate_nodes(TRUE)
|
||||
|
||||
/datum/controller/subsystem/research/proc/on_node_deletion(datum/techweb_node/TN)
|
||||
for(var/i in techweb_nodes)
|
||||
var/datum/techweb_node/TN2 = techwebs[i]
|
||||
TN2.on_node_deletion(TN)
|
||||
for(var/i in techwebs)
|
||||
var/datum/techweb/T = i
|
||||
T.recalculate_nodes(TRUE)
|
||||
|
||||
/datum/controller/subsystem/research/proc/initialize_all_techweb_nodes(clearall = FALSE)
|
||||
if(islist(techweb_nodes) && clearall)
|
||||
QDEL_LIST(techweb_nodes)
|
||||
if(islist(techweb_nodes_starting && clearall))
|
||||
techweb_nodes_starting.Cut()
|
||||
var/list/returned = list()
|
||||
for(var/path in subtypesof(/datum/techweb_node))
|
||||
var/datum/techweb_node/TN = path
|
||||
if(isnull(initial(TN.id)))
|
||||
continue
|
||||
TN = new path
|
||||
if(returned[initial(TN.id)])
|
||||
stack_trace("WARNING: Techweb node ID clash with ID [initial(TN.id)] detected! Path: [path]")
|
||||
errored_datums[TN] = initial(TN.id)
|
||||
continue
|
||||
returned[initial(TN.id)] = TN
|
||||
if(TN.starting_node)
|
||||
techweb_nodes_starting[TN.id] = TRUE
|
||||
for(var/id in techweb_nodes)
|
||||
var/datum/techweb_node/TN = techweb_nodes[id]
|
||||
TN.Initialize()
|
||||
techweb_nodes = returned
|
||||
if (!verify_techweb_nodes()) //Verify all nodes have ids and such.
|
||||
stack_trace("Invalid techweb nodes detected")
|
||||
calculate_techweb_nodes()
|
||||
calculate_techweb_boost_list()
|
||||
if (!verify_techweb_nodes()) //Verify nodes and designs have been crosslinked properly.
|
||||
CRASH("Invalid techweb nodes detected")
|
||||
|
||||
/datum/controller/subsystem/research/proc/initialize_all_techweb_designs(clearall = FALSE)
|
||||
if(islist(techweb_designs) && clearall)
|
||||
QDEL_LIST(techweb_designs)
|
||||
var/list/returned = list()
|
||||
for(var/path in subtypesof(/datum/design))
|
||||
var/datum/design/DN = path
|
||||
if(isnull(initial(DN.id)))
|
||||
stack_trace("WARNING: Design with null ID detected. Build path: [initial(DN.build_path)]")
|
||||
continue
|
||||
else if(initial(DN.id) == DESIGN_ID_IGNORE)
|
||||
continue
|
||||
DN = new path
|
||||
if(returned[initial(DN.id)])
|
||||
stack_trace("WARNING: Design ID clash with ID [initial(DN.id)] detected! Path: [path]")
|
||||
errored_datums[DN] = initial(DN.id)
|
||||
continue
|
||||
returned[initial(DN.id)] = DN
|
||||
techweb_designs = returned
|
||||
verify_techweb_designs()
|
||||
|
||||
/datum/controller/subsystem/research/proc/verify_techweb_nodes()
|
||||
. = TRUE
|
||||
for(var/n in techweb_nodes)
|
||||
var/datum/techweb_node/N = techweb_nodes[n]
|
||||
if(!istype(N))
|
||||
WARNING("Invalid research node with ID [n] detected and removed.")
|
||||
techweb_nodes -= n
|
||||
research_node_id_error(n)
|
||||
. = FALSE
|
||||
for(var/p in N.prereq_ids)
|
||||
var/datum/techweb_node/P = techweb_nodes[p]
|
||||
if(!istype(P))
|
||||
WARNING("Invalid research prerequisite node with ID [p] detected in node [N.display_name]\[[N.id]\] removed.")
|
||||
N.prereq_ids -= p
|
||||
research_node_id_error(p)
|
||||
. = FALSE
|
||||
for(var/d in N.design_ids)
|
||||
var/datum/design/D = techweb_designs[d]
|
||||
if(!istype(D))
|
||||
WARNING("Invalid research design with ID [d] detected in node [N.display_name]\[[N.id]\] removed.")
|
||||
N.design_ids -= d
|
||||
design_id_error(d)
|
||||
. = FALSE
|
||||
for(var/u in N.unlock_ids)
|
||||
var/datum/techweb_node/U = techweb_nodes[u]
|
||||
if(!istype(U))
|
||||
WARNING("Invalid research unlock node with ID [u] detected in node [N.display_name]\[[N.id]\] removed.")
|
||||
N.unlock_ids -= u
|
||||
research_node_id_error(u)
|
||||
. = FALSE
|
||||
for(var/p in N.boost_item_paths)
|
||||
if(!ispath(p))
|
||||
N.boost_item_paths -= p
|
||||
WARNING("[p] is not a valid path.")
|
||||
node_boost_error(N.id, "[p] is not a valid path.")
|
||||
. = FALSE
|
||||
var/list/points = N.boost_item_paths[p]
|
||||
if(islist(points))
|
||||
for(var/i in points)
|
||||
if(!isnum(points[i]))
|
||||
WARNING("[points[i]] is not a valid number.")
|
||||
node_boost_error(N.id, "[points[i]] is not a valid number.")
|
||||
. = FALSE
|
||||
else if(!point_types[i])
|
||||
WARNING("[i] is not a valid point type.")
|
||||
node_boost_error(N.id, "[i] is not a valid point type.")
|
||||
. = FALSE
|
||||
else if(!isnull(points))
|
||||
N.boost_item_paths -= p
|
||||
node_boost_error(N.id, "No valid list.")
|
||||
WARNING("No valid list.")
|
||||
. = FALSE
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/research/proc/verify_techweb_designs()
|
||||
for(var/d in techweb_designs)
|
||||
var/datum/design/D = techweb_designs[d]
|
||||
if(!istype(D))
|
||||
stack_trace("WARNING: Invalid research design with ID [d] detected and removed.")
|
||||
techweb_designs -= d
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/research/proc/research_node_id_error(id)
|
||||
if(invalid_node_ids[id])
|
||||
invalid_node_ids[id]++
|
||||
else
|
||||
invalid_node_ids[id] = 1
|
||||
|
||||
/datum/controller/subsystem/research/proc/design_id_error(id)
|
||||
if(invalid_design_ids[id])
|
||||
invalid_design_ids[id]++
|
||||
else
|
||||
invalid_design_ids[id] = 1
|
||||
|
||||
/datum/controller/subsystem/research/proc/calculate_techweb_nodes()
|
||||
for(var/design_id in techweb_designs)
|
||||
var/datum/design/D = techweb_designs[design_id]
|
||||
D.unlocked_by.Cut()
|
||||
for(var/node_id in techweb_nodes)
|
||||
var/datum/techweb_node/node = techweb_nodes[node_id]
|
||||
node.unlock_ids = list()
|
||||
for(var/i in node.design_ids)
|
||||
var/datum/design/D = techweb_designs[i]
|
||||
node.design_ids[i] = TRUE
|
||||
D.unlocked_by += node.id
|
||||
if(node.hidden)
|
||||
techweb_nodes_hidden[node.id] = TRUE
|
||||
CHECK_TICK
|
||||
generate_techweb_unlock_linking()
|
||||
|
||||
/datum/controller/subsystem/research/proc/generate_techweb_unlock_linking()
|
||||
for(var/node_id in techweb_nodes) //Clear all unlock links to avoid duplication.
|
||||
var/datum/techweb_node/node = techweb_nodes[node_id]
|
||||
node.unlock_ids = list()
|
||||
for(var/node_id in techweb_nodes)
|
||||
var/datum/techweb_node/node = techweb_nodes[node_id]
|
||||
for(var/prereq_id in node.prereq_ids)
|
||||
var/datum/techweb_node/prereq_node = techweb_node_by_id(prereq_id)
|
||||
prereq_node.unlock_ids[node.id] = node
|
||||
|
||||
/datum/controller/subsystem/research/proc/calculate_techweb_boost_list(clearall = FALSE)
|
||||
if(clearall)
|
||||
techweb_boost_items = list()
|
||||
for(var/node_id in techweb_nodes)
|
||||
var/datum/techweb_node/node = techweb_nodes[node_id]
|
||||
for(var/path in node.boost_item_paths)
|
||||
if(!ispath(path))
|
||||
continue
|
||||
if(length(techweb_boost_items[path]))
|
||||
techweb_boost_items[path][node.id] = node.boost_item_paths[path]
|
||||
else
|
||||
techweb_boost_items[path] = list(node.id = node.boost_item_paths[path])
|
||||
CHECK_TICK
|
||||
|
||||
@@ -479,7 +479,8 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(SSticker.timeLeft < 900)
|
||||
SSticker.timeLeft = 900
|
||||
SSticker.modevoted = TRUE
|
||||
SSvote.initiate_vote("roundtype","server",TRUE)
|
||||
var/dynamic = CONFIG_GET(flag/dynamic_voting)
|
||||
SSvote.initiate_vote(dynamic ? "dynamic" : "roundtype","server",TRUE)
|
||||
|
||||
/datum/controller/subsystem/ticker/Recover()
|
||||
current_state = SSticker.current_state
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -87,7 +87,7 @@ SUBSYSTEM_DEF(vote)
|
||||
/datum/controller/subsystem/vote/proc/announce_result()
|
||||
var/list/winners = get_result()
|
||||
var/text
|
||||
var/was_roundtype_vote = mode == "roundtype"
|
||||
var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic"
|
||||
if(winners.len > 0)
|
||||
if(question)
|
||||
text += "<b>[question]</b>"
|
||||
@@ -124,6 +124,9 @@ SUBSYSTEM_DEF(vote)
|
||||
message_admins(admintext)
|
||||
return .
|
||||
|
||||
#define PEACE "calm"
|
||||
#define CHAOS "chaotic"
|
||||
|
||||
/datum/controller/subsystem/vote/proc/result()
|
||||
. = announce_result()
|
||||
var/restart = 0
|
||||
@@ -146,6 +149,36 @@ SUBSYSTEM_DEF(vote)
|
||||
restart = 1
|
||||
else
|
||||
GLOB.master_mode = .
|
||||
if("dynamic")
|
||||
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)
|
||||
var/vote = c.prefs.preferred_chaos
|
||||
if(vote)
|
||||
voters += 1
|
||||
switch(vote)
|
||||
if(CHAOS_NONE)
|
||||
mean -= 0.1
|
||||
if(CHAOS_LOW)
|
||||
mean -= 0.05
|
||||
if(CHAOS_HIGH)
|
||||
mean += 0.05
|
||||
if(CHAOS_MAX)
|
||||
mean += 0.1
|
||||
mean/=voters
|
||||
if(voted.len != 0)
|
||||
mean += (choices[PEACE]*-1+choices[CHAOS])/voted.len
|
||||
GLOB.dynamic_curve_centre = mean*20
|
||||
GLOB.dynamic_curve_width = CLAMP(2-abs(mean*5),0.5,4)
|
||||
to_chat(world,"<span class='boldannounce'>Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width].</span>")
|
||||
log_admin("Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width]")
|
||||
if("map")
|
||||
var/datum/map_config/VM = config.maplist[.]
|
||||
message_admins("The map has been voted for and will change to: [VM.map_name]")
|
||||
@@ -223,6 +256,12 @@ SUBSYSTEM_DEF(vote)
|
||||
choices |= M
|
||||
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
|
||||
choices.Add("secret", "extended")
|
||||
if("dynamic")
|
||||
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)
|
||||
@@ -379,4 +418,7 @@ SUBSYSTEM_DEF(vote)
|
||||
else if(owner.ckey)
|
||||
var/datum/player_details/P = GLOB.player_details[owner.ckey]
|
||||
if(P)
|
||||
P.player_actions -= src
|
||||
P.player_actions -= src
|
||||
|
||||
#undef PEACE
|
||||
#undef CHAOS
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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]
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
/datum/component/lockon_aiming
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
var/lock_icon = 'icons/mob/blob.dmi'
|
||||
var/lock_icon = 'icons/mob/cameramob.dmi'
|
||||
var/lock_icon_state = "marker"
|
||||
var/mutable_appearance/lock_appearance
|
||||
var/list/image/lock_images
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -125,6 +125,9 @@
|
||||
screen_obj.icon_state = "mood[mood_level]"
|
||||
|
||||
/datum/component/mood/process() //Called on SSmood process
|
||||
if(QDELETED(parent)) // workaround to an obnoxious sneaky periodical runtime.
|
||||
qdel(src)
|
||||
return
|
||||
var/mob/living/owner = parent
|
||||
|
||||
switch(mood_level)
|
||||
@@ -245,11 +248,11 @@
|
||||
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)
|
||||
if(!screen_obj)
|
||||
if(!screen_obj || !parent)
|
||||
return
|
||||
var/mob/living/owner = parent
|
||||
var/datum/hud/hud = owner.hud_used
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -310,10 +310,10 @@
|
||||
if(!user.put_in_hands(inhand, TRUE))
|
||||
qdel(inhand) // it isn't going to be added to offhands anyway
|
||||
break
|
||||
LAZYADD(equipped, src)
|
||||
LAZYADD(equipped, inhand)
|
||||
var/amount_equipped = LAZYLEN(equipped)
|
||||
if(amount_equipped)
|
||||
LAZYADD(offhands[L], amount_equipped)
|
||||
LAZYADD(offhands[L], equipped)
|
||||
if(amount_equipped >= amount_required)
|
||||
return TRUE
|
||||
unequip_buckle_inhands(L)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!")
|
||||
|
||||
@@ -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)
|
||||
@@ -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>")
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>")
|
||||
|
||||
+4
-1
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
@@ -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]")
|
||||
@@ -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()
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
|
||||
var/parallax_movedir = 0
|
||||
|
||||
var/global/global_uid = 0
|
||||
var/uid
|
||||
var/list/ambientsounds = GENERIC
|
||||
flags_1 = CAN_BE_DIRTY_1
|
||||
|
||||
@@ -96,7 +94,6 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
/area/Initialize()
|
||||
icon_state = ""
|
||||
layer = AREA_LAYER
|
||||
uid = ++global_uid
|
||||
map_name = name // Save the initial (the name set in the map) name of the area.
|
||||
canSmoothWithAreas = typecacheof(canSmoothWithAreas)
|
||||
|
||||
|
||||
+12
-15
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,15 +11,26 @@
|
||||
#define RULESET_STOP_PROCESSING 1
|
||||
|
||||
// -- Injection delays
|
||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (5 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (25 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (10 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (30 MINUTES))
|
||||
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_min, (15 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_max, (35 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_min, (10 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_max, (30 MINUTES))
|
||||
|
||||
GLOBAL_VAR_INIT(dynamic_event_delay_min, (10 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_event_delay_max, (30 MINUTES)) // this is on top of regular events, so can't be quite as often
|
||||
|
||||
|
||||
// -- Roundstart injection delays
|
||||
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_min, (2 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_max, (30 MINUTES))
|
||||
|
||||
GLOBAL_VAR_INIT(dynamic_first_midround_delay_min, (20 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_first_midround_delay_max, (30 MINUTES))
|
||||
|
||||
// Are HIGHLANDER_RULESETs allowed to stack?
|
||||
GLOBAL_VAR_INIT(dynamic_no_stacking, TRUE)
|
||||
// A number between -5 and +5.
|
||||
// A number between -5 and +5.
|
||||
// A negative value will give a more peaceful round and
|
||||
// a positive value will give a round with higher threat.
|
||||
GLOBAL_VAR_INIT(dynamic_curve_centre, 0)
|
||||
@@ -27,7 +38,7 @@ GLOBAL_VAR_INIT(dynamic_curve_centre, 0)
|
||||
// Higher value will favour extreme rounds and
|
||||
// lower value rounds closer to the average.
|
||||
GLOBAL_VAR_INIT(dynamic_curve_width, 1.8)
|
||||
// If enabled only picks a single starting rule and executes only autotraitor midround ruleset.
|
||||
// If enabled only picks a single starting rule and executes only autotraitor midround ruleset.
|
||||
GLOBAL_VAR_INIT(dynamic_classic_secret, FALSE)
|
||||
// How many roundstart players required for high population override to take effect.
|
||||
GLOBAL_VAR_INIT(dynamic_high_pop_limit, 55)
|
||||
@@ -38,7 +49,7 @@ GLOBAL_VAR_INIT(dynamic_forced_extended, FALSE)
|
||||
GLOBAL_VAR_INIT(dynamic_stacking_limit, 90)
|
||||
// List of forced roundstart rulesets.
|
||||
GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset)
|
||||
// Forced threat level, setting this to zero or higher forces the roundstart threat to the value.
|
||||
// Forced threat level, setting this to zero or higher forces the roundstart threat to the value.
|
||||
GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
|
||||
/datum/game_mode/dynamic
|
||||
@@ -49,20 +60,28 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
announce_text = "Dynamic mode!" // This needs to be changed maybe
|
||||
|
||||
reroll_friendly = FALSE;
|
||||
|
||||
|
||||
// Threat logging vars
|
||||
/// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations
|
||||
var/threat_level = 0
|
||||
var/threat_level = 0
|
||||
/// Set at the beginning of the round. Spent by the mode to "purchase" rules.
|
||||
var/threat = 0
|
||||
/// Starting threat level, for things that increase it but can bring it back down.
|
||||
var/initial_threat_level = 0
|
||||
/// Things that cause a rolling threat adjustment to be displayed at roundend.
|
||||
var/list/threat_tallies = list()
|
||||
/// Running information about the threat. Can store text or datum entries.
|
||||
var/list/threat_log = list()
|
||||
/// As above, but with info such as refunds.
|
||||
var/list/threat_log_verbose = list()
|
||||
/// List of roundstart rules used for selecting the rules.
|
||||
var/list/roundstart_rules = list()
|
||||
/// List of latejoin rules used for selecting the rules.
|
||||
var/list/latejoin_rules = list()
|
||||
/// List of midround rules used for selecting the rules.
|
||||
var/list/midround_rules = list()
|
||||
/// List of events used for reducing threat without causing antag injection (necessarily).
|
||||
var/list/events = list()
|
||||
/** # Pop range per requirement.
|
||||
* If the value is five the range is:
|
||||
* 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+
|
||||
@@ -71,15 +90,21 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
* If it is seven the range is:
|
||||
* 0-6, 7-13, 14-20, 21-27, 28-34, 35-41, 42-48, 49-55, 56-62, 63+
|
||||
*/
|
||||
var/pop_per_requirement = 6
|
||||
/// The requirement used for checking if a second rule should be selected.
|
||||
var/pop_per_requirement = 9
|
||||
/// The requirement used for checking if a second rule should be selected. Index based on pop_per_requirement.
|
||||
var/list/second_rule_req = list(100, 100, 80, 70, 60, 50, 30, 20, 10, 0)
|
||||
/// The requirement used for checking if a third rule should be selected.
|
||||
/// The probability for a second ruleset with index being every ten threat.
|
||||
var/list/second_rule_prob = list(0,0,60,80,80,80,100,100,100,100)
|
||||
/// The requirement used for checking if a third rule should be selected. Index based on pop_per_requirement.
|
||||
var/list/third_rule_req = list(100, 100, 100, 90, 80, 70, 60, 50, 40, 30)
|
||||
/// Threat requirement for a second ruleset when high pop override is in effect.
|
||||
/// The probability for a third ruleset with index being every ten threat.
|
||||
var/list/third_rule_prob = list(0,0,0,0,60,60,80,90,100,100)
|
||||
/// Threat requirement for a second ruleset when high pop override is in effect.
|
||||
var/high_pop_second_rule_req = 40
|
||||
/// Threat requirement for a third ruleset when high pop override is in effect.
|
||||
/// Threat requirement for a third ruleset when high pop override is in effect.
|
||||
var/high_pop_third_rule_req = 60
|
||||
/// The amount of additional rulesets waiting to be picked.
|
||||
var/extra_rulesets_amount = 0
|
||||
/// Number of players who were ready on roundstart.
|
||||
var/roundstart_pop_ready = 0
|
||||
/// List of candidates used on roundstart rulesets.
|
||||
@@ -94,6 +119,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
var/latejoin_injection_cooldown = 0
|
||||
/// When world.time is over this number the mode tries to inject a midround ruleset.
|
||||
var/midround_injection_cooldown = 0
|
||||
/// When wor.dtime is over this number the mode tries to do an event.
|
||||
var/event_injection_cooldown = 0
|
||||
/// When TRUE GetInjectionChance returns 100.
|
||||
var/forced_injection = FALSE
|
||||
/// Forced ruleset to be executed for the next latejoin.
|
||||
@@ -106,19 +133,33 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
var/highlander_executed = FALSE
|
||||
/// If a only ruleset has been executed.
|
||||
var/only_ruleset_executed = FALSE
|
||||
/// Antags rolled by rules so far, to keep track of and discourage scaling past a certain ratio of crew/antags especially on lowpop.
|
||||
var/antags_rolled = 0
|
||||
|
||||
/datum/game_mode/dynamic/New() // i have NO IDEA if this is the proper way to do this.
|
||||
..()
|
||||
pop_per_requirement = CONFIG_GET(number/dynamic_pop_per_requirement)
|
||||
second_rule_req = CONFIG_GET(number_list/dynamic_second_rule_requirements)
|
||||
third_rule_req = CONFIG_GET(number_list/dynamic_third_rule_requirements)
|
||||
if(second_rule_req.len<10)
|
||||
second_rule_req = list(101, 101, 101, 101, 100, 90, 80, 70, 60, 50)
|
||||
if(third_rule_req.len<10)
|
||||
third_rule_req = list(101, 101, 101, 101, 101, 100, 90, 80, 70, 60)
|
||||
high_pop_second_rule_req = CONFIG_GET(number/dynamic_second_rule_high_pop_requirement)
|
||||
high_pop_third_rule_req = CONFIG_GET(number/dynamic_third_rule_high_pop_requirement)
|
||||
GLOB.dynamic_high_pop_limit = CONFIG_GET(number/dynamic_high_pop_limit)
|
||||
GLOB.dynamic_latejoin_delay_min = CONFIG_GET(number/dynamic_latejoin_delay_min)*600
|
||||
GLOB.dynamic_latejoin_delay_max = CONFIG_GET(number/dynamic_latejoin_delay_max)*600
|
||||
GLOB.dynamic_midround_delay_min = CONFIG_GET(number/dynamic_midround_delay_min)*600
|
||||
GLOB.dynamic_midround_delay_max = CONFIG_GET(number/dynamic_midround_delay_max)*600
|
||||
GLOB.dynamic_first_latejoin_delay_min = CONFIG_GET(number/dynamic_first_latejoin_delay_min)*600
|
||||
GLOB.dynamic_first_latejoin_delay_max = CONFIG_GET(number/dynamic_first_latejoin_delay_max)*600
|
||||
GLOB.dynamic_first_midround_delay_min = CONFIG_GET(number/dynamic_first_midround_delay_min)*600
|
||||
GLOB.dynamic_first_midround_delay_max = CONFIG_GET(number/dynamic_first_midround_delay_max)*600
|
||||
|
||||
/datum/game_mode/dynamic/admin_panel()
|
||||
var/list/dat = list("<html><head><title>Game Mode Panel</title></head><body><h1><B>Game Mode Panel</B></h1>")
|
||||
dat += "Dynamic Mode <a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</A><BR>"
|
||||
dat += "Dynamic Mode <a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</A><a href='?src=\ref[src];[HrefToken()]'>\[Refresh\]</A><BR>"
|
||||
dat += "Threat Level: <b>[threat_level]</b><br/>"
|
||||
|
||||
dat += "Threat to Spend: <b>[threat]</b> <a href='?src=\ref[src];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='?src=\ref[src];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>"
|
||||
@@ -140,6 +181,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
dat += "<br>Injection Timers: (<b>[get_injection_chance(TRUE)]%</b> chance)<BR>"
|
||||
dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
|
||||
dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
|
||||
dat += "Event: [(event_injection_cooldown-world.time)>60*10 ? "[round((event_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(event_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];forceevent=1'>\[Now!\]</a><BR>"
|
||||
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
|
||||
|
||||
/datum/game_mode/dynamic/Topic(href, href_list)
|
||||
@@ -171,11 +213,15 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
midround_injection_cooldown = 0
|
||||
forced_injection = TRUE
|
||||
message_admins("[key_name(usr)] forced a midround injection.", 1)
|
||||
else if (href_list["forceevent"])
|
||||
event_injection_cooldown = 0
|
||||
// events always happen anyway
|
||||
message_admins("[key_name(usr)] forced an event.", 1)
|
||||
else if (href_list["threatlog"])
|
||||
show_threatlog(usr)
|
||||
else if (href_list["stacking_limit"])
|
||||
GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num
|
||||
|
||||
|
||||
admin_panel() // Refreshes the window
|
||||
|
||||
// Checks if there are HIGHLANDER_RULESETs and calls the rule's round_result() proc
|
||||
@@ -193,30 +239,33 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
/datum/game_mode/dynamic/send_intercept()
|
||||
. = "<b><i>Central Command Status Summary</i></b><hr>"
|
||||
switch(round(threat_level))
|
||||
if(0 to 19)
|
||||
update_playercounts()
|
||||
if(!current_players[CURRENT_LIVING_ANTAGS].len)
|
||||
. += "<b>Peaceful Waypoint</b></center><BR>"
|
||||
. += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive."
|
||||
else
|
||||
if(0 to 20)
|
||||
. += "<b>Peaceful Waypoint</b></center><BR>"
|
||||
. += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive. However, even deep in our territory there may be subversive elements, especially for such a high-value target as your station. Keep an eye out, but don't expect much trouble."
|
||||
set_security_level(SEC_LEVEL_GREEN)
|
||||
if(21 to 79)
|
||||
var/perc_green = 100-round(100*((threat_level-21)/(79-21)))
|
||||
if(prob(perc_green))
|
||||
. += "<b>Core Territory</b></center><BR>"
|
||||
. += "Your station orbits within reliably mundane, secure space. Although Nanotrasen has a firm grip on security in your region, the valuable resources and strategic position aboard your station make it a potential target for infiltrations. Monitor crew for non-loyal behavior, but expect a relatively tame shift free of large-scale destruction. We expect great things from your station."
|
||||
if(20 to 39)
|
||||
. += "<b>Anomalous Exogeology</b></center><BR>"
|
||||
. += "Although your station lies within what is generally considered Nanotrasen-controlled space, the course of its orbit has caused it to cross unusually close to exogeological features with anomalous readings. Although these features offer opportunities for our research department, it is known that these little understood readings are often correlated with increased activity from competing interstellar organizations and individuals, among them the Wizard Federation and Cult of the Geometer of Blood - all known competitors for Anomaly Type B sites. Exercise elevated caution."
|
||||
if(40 to 65)
|
||||
. += "<b>Contested System</b></center><BR>"
|
||||
. += "Your station's orbit passes along the edge of Nanotrasen's sphere of influence. While subversive elements remain the most likely threat against your station, hostile organizations are bolder here, where our grip is weaker. Exercise increased caution against elite Syndicate strike forces, or Executives forbid, some kind of ill-conceived unionizing attempt."
|
||||
if(66 to 79)
|
||||
. += "<b>Uncharted Space</b></center><BR>"
|
||||
. += "Congratulations and thank you for participating in the NT 'Frontier' space program! Your station is actively orbiting a high value system far from the nearest support stations. Little is known about your region of space, and the opportunity to encounter the unknown invites greater glory. You are encouraged to elevate security as necessary to protect Nanotrasen assets."
|
||||
set_security_level(SEC_LEVEL_GREEN)
|
||||
else if(prob(perc_green))
|
||||
. += "<b>Contested System</b></center><BR>"
|
||||
. += "Your station's orbit passes along the edge of Nanotrasen's sphere of influence. While subversive elements remain the most likely threat against your station, hostile organizations are bolder here, where our grip is weaker. Exercise increased caution against elite Syndicate strike forces, or Executives forbid, some kind of ill-conceived unionizing attempt."
|
||||
set_security_level(SEC_LEVEL_BLUE)
|
||||
else
|
||||
. += "<b>Uncharted Space</b></center><BR>"
|
||||
. += "Congratulations and thank you for participating in the NT 'Frontier' space program! Your station is actively orbiting a high value system far from the nearest support stations. Little is known about your region of space, and the opportunity to encounter the unknown invites greater glory. You are encouraged to elevate security as necessary to protect Nanotrasen assets."
|
||||
set_security_level(SEC_LEVEL_BLUE)
|
||||
if(80 to 99)
|
||||
. += "<b>Black Orbit</b></center><BR>"
|
||||
. += "As part of a mandatory security protocol, we are required to inform you that as a result of your orbital pattern directly behind an astrological body (oriented from our nearest observatory), your station will be under decreased monitoring and support. It is anticipated that your extreme location and decreased surveillance could pose security risks. Avoid unnecessary risks and attempt to keep your station in one piece."
|
||||
set_security_level(SEC_LEVEL_AMBER)
|
||||
if(100)
|
||||
. += "<b>Impending Doom</b></center><BR>"
|
||||
. += "Your station is somehow in the middle of hostile territory, in clear view of any enemy of the corporation. Your likelihood to survive is low, and station destruction is expected and almost inevitable. Secure any sensitive material and neutralize any enemy you will come across. It is important that you at least try to maintain the station.<BR>"
|
||||
. += "Good luck."
|
||||
set_security_level(SEC_LEVEL_RED)
|
||||
|
||||
if(station_goals.len)
|
||||
. += "<hr><b>Special Orders for [station_name()]:</b>"
|
||||
@@ -225,9 +274,10 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
. += G.get_report()
|
||||
|
||||
print_command_report(., "Central Command Status Summary", announce=FALSE)
|
||||
priority_announce("A summary has been copied and printed to all communications consoles.", "Security level elevated.", "intercept")
|
||||
if(GLOB.security_level < SEC_LEVEL_BLUE)
|
||||
set_security_level(SEC_LEVEL_BLUE)
|
||||
if(GLOB.security_level >= SEC_LEVEL_BLUE)
|
||||
priority_announce("A summary has been copied and printed to all communications consoles.", "Security level elevated.", "intercept")
|
||||
else
|
||||
priority_announce("Thanks to the tireless efforts of our security and intelligence divisions, there are currently no likely threats to [station_name()]. Have a secure shift!", "Security Report", "commandreport")
|
||||
|
||||
// Yes, this is copy pasted from game_mode
|
||||
/datum/game_mode/dynamic/check_finished(force_ending)
|
||||
@@ -245,6 +295,11 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if(rule.flags & HIGHLANDER_RULESET)
|
||||
return rule.check_finished()
|
||||
|
||||
/datum/game_mode/dynamic/proc/log_threat(var/log_str,var/verbose = FALSE)
|
||||
threat_log_verbose += ("[worldtime2text()]: "+log_str)
|
||||
if(!verbose)
|
||||
threat_log += log_str
|
||||
|
||||
/datum/game_mode/dynamic/proc/show_threatlog(mob/admin)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
alert("The round hasn't started yet!")
|
||||
@@ -253,9 +308,9 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
var/list/out = list("<TITLE>Threat Log</TITLE><B><font size='3'>Threat Log</font></B><br><B>Starting Threat:</B> [threat_level]<BR>")
|
||||
var/list/out = list("<TITLE>Threat Log</TITLE><B><font size='3'>Threat Log</font></B><br><B>Starting Threat:</B> [initial_threat_level]<BR>")
|
||||
|
||||
for(var/entry in threat_log)
|
||||
for(var/entry in threat_log_verbose)
|
||||
if(istext(entry))
|
||||
out += "[entry]<BR>"
|
||||
|
||||
@@ -273,15 +328,6 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
threat = threat_level
|
||||
|
||||
/datum/game_mode/dynamic/can_start()
|
||||
/* Disabled for now, had some changes that need to be tested and this might interfere with that.
|
||||
if(GLOB.dynamic_curve_centre == 0)
|
||||
// 10 is when the centre starts to decrease
|
||||
// 6 is just 1 + 5 (from the maximum value and the one decreased)
|
||||
// 1 just makes the curve look better, I don't know.
|
||||
// Limited between 1 and 5 then inverted and rounded
|
||||
// With this you get a centre curve that stays at -5 until 10 then first rapidly decreases but slows down at the end
|
||||
GLOB.dynamic_curve_centre = round(-CLAMP((10*6/GLOB.player_list.len)-1, 0, 5), 0.5)
|
||||
*/
|
||||
message_admins("Dynamic mode parameters for the round:")
|
||||
message_admins("Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].")
|
||||
message_admins("Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].")
|
||||
@@ -294,12 +340,17 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
else
|
||||
generate_threat()
|
||||
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
|
||||
latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_latejoin_delay_max + GLOB.dynamic_first_latejoin_delay_min)
|
||||
latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_first_latejoin_delay_min, GLOB.dynamic_first_latejoin_delay_max)) + world.time
|
||||
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
|
||||
midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
|
||||
midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
|
||||
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
|
||||
|
||||
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
|
||||
initial_threat_level = threat_level
|
||||
return TRUE
|
||||
|
||||
/datum/game_mode/dynamic/pre_setup()
|
||||
@@ -316,24 +367,30 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if ("Midround")
|
||||
if (ruleset.weight)
|
||||
midround_rules += ruleset
|
||||
if("Event")
|
||||
if(ruleset.weight)
|
||||
events += ruleset
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
|
||||
roundstart_pop_ready++
|
||||
candidates.Add(player)
|
||||
log_game("DYNAMIC: Listing [roundstart_rules.len] round start rulesets, and [candidates.len] players ready.")
|
||||
if (candidates.len <= 0)
|
||||
log_game("DYNAMIC: [candidates.len] candidates.")
|
||||
return TRUE
|
||||
if (roundstart_rules.len <= 0)
|
||||
log_game("DYNAMIC: [roundstart_rules.len] rules.")
|
||||
return TRUE
|
||||
|
||||
|
||||
if(GLOB.dynamic_forced_roundstart_ruleset.len > 0)
|
||||
rigged_roundstart()
|
||||
else
|
||||
else
|
||||
roundstart()
|
||||
|
||||
var/starting_rulesets = ""
|
||||
for (var/datum/dynamic_ruleset/roundstart/DR in executed_rules)
|
||||
starting_rulesets += "[DR.name], "
|
||||
log_game("DYNAMIC: Picked the following roundstart rules: [starting_rulesets]")
|
||||
candidates.Cut()
|
||||
return TRUE
|
||||
|
||||
@@ -341,9 +398,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
update_playercounts()
|
||||
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules)
|
||||
rule.candidates.Cut() // The rule should not use candidates at this point as they all are null.
|
||||
if(!rule.execute())
|
||||
stack_trace("The starting rule \"[rule.name]\" failed to execute.")
|
||||
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_roundstart_rule, rule), rule.delay)
|
||||
..()
|
||||
|
||||
/// A simple roundstart proc used when dynamic_forced_roundstart_ruleset has rules in it.
|
||||
@@ -354,6 +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(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))
|
||||
@@ -370,9 +426,11 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
rule.trim_candidates()
|
||||
if (rule.ready() && rule.candidates.len > 0)
|
||||
drafted_rules[rule] = rule.weight
|
||||
|
||||
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(roundstart_pop_ready/pop_per_requirement)+1)
|
||||
var/extra_rulesets_amount = 0
|
||||
extra_rulesets_amount = 0
|
||||
if (GLOB.dynamic_classic_secret)
|
||||
extra_rulesets_amount = 0
|
||||
else
|
||||
@@ -384,23 +442,28 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if (threat_level > high_pop_third_rule_req)
|
||||
extra_rulesets_amount++
|
||||
else
|
||||
if (threat_level >= second_rule_req[indice_pop])
|
||||
var/threat_indice = min(10, max(round(threat_level ? threat_level/10 : 1), 1)) // 0-9 threat = 1, 10-19 threat = 2 ...
|
||||
if (threat_level >= second_rule_req[indice_pop] && prob(second_rule_prob[threat_indice]))
|
||||
extra_rulesets_amount++
|
||||
if (threat_level >= third_rule_req[indice_pop])
|
||||
if (threat_level >= third_rule_req[indice_pop] && prob(third_rule_prob[threat_indice]))
|
||||
extra_rulesets_amount++
|
||||
log_game("DYNAMIC: Trying to roll [extra_rulesets_amount + 1] roundstart rulesets. Picking from [drafted_rules.len] eligible rulesets.")
|
||||
|
||||
if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules))
|
||||
if (extra_rulesets_amount > 0) // We've got enough population and threat for a second rulestart rule
|
||||
log_game("DYNAMIC: First ruleset picked successfully. [extra_rulesets_amount] remaining.")
|
||||
while(extra_rulesets_amount > 0 && drafted_rules.len > 0) // We had enough threat for one or two more rulesets
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules)
|
||||
if (rule.cost > threat)
|
||||
drafted_rules -= rule
|
||||
if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules))
|
||||
if (extra_rulesets_amount > 1) // We've got enough population and threat for a third rulestart rule
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules)
|
||||
if (rule.cost > threat)
|
||||
drafted_rules -= rule
|
||||
picking_roundstart_rule(drafted_rules)
|
||||
if(drafted_rules.len)
|
||||
picking_roundstart_rule(drafted_rules)
|
||||
extra_rulesets_amount--
|
||||
log_game("DYNAMIC: Additional ruleset picked successfully, now [executed_rules.len] picked. [extra_rulesets_amount] remaining.")
|
||||
else
|
||||
|
||||
if(threat >= 50)
|
||||
message_admins("DYNAMIC: Picking first roundstart ruleset failed. You should report this.")
|
||||
log_game("DYNAMIC: Picking first roundstart ruleset failed. drafted_rules.len = [drafted_rules.len] and threat = [threat]/[threat_level]")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -408,68 +471,74 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
/datum/game_mode/dynamic/proc/picking_roundstart_rule(list/drafted_rules = list(), forced = FALSE)
|
||||
var/datum/dynamic_ruleset/roundstart/starting_rule = pickweight(drafted_rules)
|
||||
if(!starting_rule)
|
||||
log_game("DYNAMIC: Couldn't pick a starting ruleset. No rulesets available")
|
||||
return FALSE
|
||||
|
||||
if(!forced)
|
||||
if(only_ruleset_executed)
|
||||
return FALSE
|
||||
// Check if a blocking ruleset has been executed.
|
||||
else if(check_blocking(starting_rule.blocking_rules, executed_rules))
|
||||
else if(check_blocking(starting_rule.blocking_rules, executed_rules)) // Should already be filtered out, but making sure. Check filtering at end of proc if reported.
|
||||
drafted_rules -= starting_rule
|
||||
if(drafted_rules.len <= 0)
|
||||
log_game("DYNAMIC: Picking [starting_rule.name] failed due to blocking_rules and no more rulesets available. Report this.")
|
||||
return FALSE
|
||||
starting_rule = pickweight(drafted_rules)
|
||||
// Check if the ruleset is highlander and if a highlander ruleset has been executed
|
||||
else if(starting_rule.flags & HIGHLANDER_RULESET)
|
||||
if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
else if(starting_rule.flags & HIGHLANDER_RULESET) // Should already be filtered out, but making sure. Check filtering at end of proc if reported.
|
||||
if(threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(highlander_executed)
|
||||
drafted_rules -= starting_rule
|
||||
if(drafted_rules.len <= 0)
|
||||
log_game("DYNAMIC: Picking [starting_rule.name] failed due to no highlander stacking and no more rulesets available. Report this.")
|
||||
return FALSE
|
||||
starting_rule = pickweight(drafted_rules)
|
||||
// With low pop and high threat there might be rulesets that get executed with no valid candidates.
|
||||
else if(!starting_rule.ready()) // Should already be filtered out, but making sure. Check filtering at end of proc if reported.
|
||||
drafted_rules -= starting_rule
|
||||
if(drafted_rules.len <= 0)
|
||||
log_game("DYNAMIC: Picking [starting_rule.name] failed because there were not enough candidates and no more rulesets available. Report this.")
|
||||
return FALSE
|
||||
starting_rule = pickweight(drafted_rules)
|
||||
|
||||
log_game("DYNAMIC: Picking a [istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/) ? " delayed " : ""] ruleset [starting_rule.name]")
|
||||
log_game("DYNAMIC: Picked a ruleset: [starting_rule.name]")
|
||||
|
||||
roundstart_rules -= starting_rule
|
||||
drafted_rules -= starting_rule
|
||||
|
||||
if (istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/))
|
||||
var/datum/dynamic_ruleset/roundstart/delayed/rule = starting_rule
|
||||
addtimer(CALLBACK(src, .proc/execute_delayed, rule), rule.delay)
|
||||
|
||||
starting_rule.trim_candidates()
|
||||
var/added_threat = starting_rule.scale_up(extra_rulesets_amount, threat)
|
||||
if (starting_rule.pre_execute())
|
||||
spend_threat(starting_rule.cost)
|
||||
threat_log += "[worldtime2text()]: Roundstart [starting_rule.name] spent [starting_rule.cost]"
|
||||
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", verbose = TRUE)
|
||||
if(starting_rule.flags & HIGHLANDER_RULESET)
|
||||
highlander_executed = TRUE
|
||||
else if(starting_rule.flags & ONLY_RULESET)
|
||||
only_ruleset_executed = TRUE
|
||||
executed_rules += starting_rule
|
||||
if (starting_rule.persistent)
|
||||
current_rules += starting_rule
|
||||
for(var/mob/M in starting_rule.assigned)
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules)
|
||||
if (!rule.ready())
|
||||
drafted_rules -= rule // And removing rules that are no longer elligible
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in drafted_rules)
|
||||
if(check_blocking(rule.blocking_rules, executed_rules))
|
||||
drafted_rules -= rule
|
||||
if(highlander_executed && rule.flags & HIGHLANDER_RULESET)
|
||||
drafted_rules -= rule
|
||||
if(!rule.ready())
|
||||
drafted_rules -= rule // And removing rules that are no longer eligible
|
||||
return TRUE
|
||||
else
|
||||
stack_trace("The starting rule \"[starting_rule.name]\" failed to pre_execute.")
|
||||
return FALSE
|
||||
|
||||
/// Executes delayed roundstart rules and has a hack in it.
|
||||
/datum/game_mode/dynamic/proc/execute_delayed(datum/dynamic_ruleset/roundstart/delayed/rule)
|
||||
update_playercounts()
|
||||
rule.candidates = current_players[CURRENT_LIVING_PLAYERS].Copy()
|
||||
rule.trim_candidates()
|
||||
/// Mainly here to facilitate delayed rulesets. All roundstart rulesets are executed with a timered callback to this proc.
|
||||
/datum/game_mode/dynamic/proc/execute_roundstart_rule(sent_rule)
|
||||
var/datum/dynamic_ruleset/rule = sent_rule
|
||||
if(rule.execute())
|
||||
executed_rules += rule
|
||||
if (rule.persistent)
|
||||
if(rule.persistent)
|
||||
current_rules += rule
|
||||
return TRUE
|
||||
else
|
||||
stack_trace("The delayed roundstart rule \"[rule.name]\" failed to execute.")
|
||||
return FALSE
|
||||
rule.clean_up() // Refund threat, delete teams and so on.
|
||||
executed_rules -= rule
|
||||
stack_trace("The starting rule \"[rule.name]\" failed to execute.")
|
||||
return FALSE
|
||||
|
||||
/// Picks a random midround OR latejoin rule from the list given as an argument and executes it.
|
||||
/// Also this could be named better.
|
||||
@@ -477,7 +546,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
var/datum/dynamic_ruleset/rule = pickweight(drafted_rules)
|
||||
if(!rule)
|
||||
return FALSE
|
||||
|
||||
|
||||
if(!forced)
|
||||
if(only_ruleset_executed)
|
||||
return FALSE
|
||||
@@ -489,23 +558,75 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
rule = pickweight(drafted_rules)
|
||||
// Check if the ruleset is highlander and if a highlander ruleset has been executed
|
||||
else if(rule.flags & HIGHLANDER_RULESET)
|
||||
if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(highlander_executed)
|
||||
drafted_rules -= rule
|
||||
if(drafted_rules.len <= 0)
|
||||
return FALSE
|
||||
rule = pickweight(drafted_rules)
|
||||
|
||||
|
||||
if(!rule.repeatable)
|
||||
if(rule.ruletype == "Latejoin")
|
||||
latejoin_rules = remove_from_list(latejoin_rules, rule.type)
|
||||
else if(rule.type == "Midround")
|
||||
else if(rule.ruletype == "Midround")
|
||||
midround_rules = remove_from_list(midround_rules, rule.type)
|
||||
|
||||
else if(rule.ruletype == "Event")
|
||||
events = remove_from_list(events,rule.type)
|
||||
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_midround_latejoin_rule, rule), rule.delay)
|
||||
return TRUE
|
||||
|
||||
/// An experimental proc to allow admins to call rules on the fly or have rules call other rules.
|
||||
/datum/game_mode/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE)
|
||||
var/datum/dynamic_ruleset/midround/new_rule
|
||||
if(ispath(ruletype))
|
||||
new_rule = new ruletype() // You should only use it to call midround rules though.
|
||||
else if(istype(ruletype, /datum/dynamic_ruleset))
|
||||
new_rule = ruletype
|
||||
else
|
||||
return FALSE
|
||||
|
||||
if(!new_rule)
|
||||
return FALSE
|
||||
|
||||
if(!forced)
|
||||
if(only_ruleset_executed)
|
||||
return FALSE
|
||||
// Check if a blocking ruleset has been executed.
|
||||
else if(check_blocking(new_rule.blocking_rules, executed_rules))
|
||||
return FALSE
|
||||
// Check if the ruleset is highlander and if a highlander ruleset has been executed
|
||||
else if(new_rule.flags & HIGHLANDER_RULESET)
|
||||
if(threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(highlander_executed)
|
||||
return FALSE
|
||||
|
||||
update_playercounts()
|
||||
if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat)))
|
||||
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", verbose = TRUE)
|
||||
if (new_rule.execute()) // This should never fail since ready() returned 1
|
||||
if(new_rule.flags & HIGHLANDER_RULESET)
|
||||
highlander_executed = TRUE
|
||||
else if(new_rule.flags & ONLY_RULESET)
|
||||
only_ruleset_executed = TRUE
|
||||
log_game("DYNAMIC: Making a call to a specific ruleset...[new_rule.name]!")
|
||||
executed_rules += new_rule
|
||||
if (new_rule.persistent)
|
||||
current_rules += new_rule
|
||||
return TRUE
|
||||
else if (forced)
|
||||
log_game("DYNAMIC: The ruleset [new_rule.name] couldn't be executed due to lack of eligible players.")
|
||||
return FALSE
|
||||
|
||||
/// Mainly here to facilitate delayed rulesets. All midround/latejoin rulesets are executed with a timered callback to this proc.
|
||||
/datum/game_mode/dynamic/proc/execute_midround_latejoin_rule(sent_rule)
|
||||
var/datum/dynamic_ruleset/rule = sent_rule
|
||||
if (rule.execute())
|
||||
log_game("DYNAMIC: Injected a [rule.ruletype == "latejoin" ? "latejoin" : "midround"] ruleset [rule.name].")
|
||||
spend_threat(rule.cost)
|
||||
threat_log += "[worldtime2text()]: [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)
|
||||
@@ -519,54 +640,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if (rule.persistent)
|
||||
current_rules += rule
|
||||
return TRUE
|
||||
else
|
||||
stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.")
|
||||
return FALSE
|
||||
|
||||
/// An experimental proc to allow admins to call rules on the fly or have rules call other rules.
|
||||
/datum/game_mode/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE)
|
||||
var/datum/dynamic_ruleset/midround/new_rule
|
||||
if(ispath(ruletype))
|
||||
new_rule = new ruletype() // You should only use it to call midround rules though.
|
||||
else if(istype(ruletype, /datum/dynamic_ruleset))
|
||||
new_rule = ruletype
|
||||
else
|
||||
return FALSE
|
||||
|
||||
if(!new_rule)
|
||||
return FALSE
|
||||
|
||||
if(!forced)
|
||||
if(only_ruleset_executed)
|
||||
return FALSE
|
||||
// Check if a blocking ruleset has been executed.
|
||||
else if(check_blocking(new_rule.blocking_rules, executed_rules))
|
||||
return FALSE
|
||||
// Check if the ruleset is highlander and if a highlander ruleset has been executed
|
||||
else if(new_rule.flags & HIGHLANDER_RULESET)
|
||||
if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(highlander_executed)
|
||||
return FALSE
|
||||
|
||||
update_playercounts()
|
||||
if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat)))
|
||||
new_rule.candidates = current_players.Copy()
|
||||
new_rule.trim_candidates()
|
||||
if (new_rule.ready(forced))
|
||||
spend_threat(new_rule.cost)
|
||||
threat_log += "[worldtime2text()]: Forced rule [new_rule.name] spent [new_rule.cost]"
|
||||
if (new_rule.execute()) // This should never fail since ready() returned 1
|
||||
if(new_rule.flags & HIGHLANDER_RULESET)
|
||||
highlander_executed = TRUE
|
||||
else if(new_rule.flags & ONLY_RULESET)
|
||||
only_ruleset_executed = TRUE
|
||||
log_game("DYNAMIC: Making a call to a specific ruleset...[new_rule.name]!")
|
||||
executed_rules += new_rule
|
||||
if (new_rule.persistent)
|
||||
current_rules += new_rule
|
||||
return TRUE
|
||||
else if (forced)
|
||||
log_game("DYNAMIC: The ruleset [new_rule.name] couldn't be executed due to lack of elligible players.")
|
||||
rule.clean_up()
|
||||
stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.")
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/dynamic/process()
|
||||
@@ -581,35 +656,54 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if (midround_injection_cooldown < world.time)
|
||||
if (GLOB.dynamic_forced_extended)
|
||||
return
|
||||
|
||||
// Somehow it manages to trigger midround multiple times so this was moved here.
|
||||
|
||||
// Somehow it managed to trigger midround multiple times so this was moved here.
|
||||
// There is no way this should be able to trigger an injection twice now.
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
|
||||
midround_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time)
|
||||
|
||||
|
||||
// Time to inject some threat into the round
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone
|
||||
return
|
||||
message_admins("DYNAMIC: Checking for midround injection.")
|
||||
log_game("DYNAMIC: Checking for midround injection.")
|
||||
|
||||
log_game("DYNAMIC: Checking state of the round.")
|
||||
|
||||
update_playercounts()
|
||||
|
||||
if (prob(get_injection_chance()))
|
||||
if (get_injection_chance())
|
||||
var/cur_threat_frac = threat/threat_level
|
||||
var/list/drafted_rules = list()
|
||||
var/antag_num = current_players[CURRENT_LIVING_ANTAGS].len
|
||||
for (var/datum/dynamic_ruleset/midround/rule in midround_rules)
|
||||
// if there are antags OR the rule is an antag rule, antag_acceptable will be true.
|
||||
if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
continue
|
||||
rule.candidates = list()
|
||||
rule.candidates = current_players.Copy()
|
||||
rule.trim_candidates()
|
||||
if (rule.ready() && rule.candidates.len > 0)
|
||||
drafted_rules[rule] = rule.get_weight()
|
||||
if (rule.ready())
|
||||
if(!antag_num)
|
||||
drafted_rules[rule] = round(rule.get_weight() + (rule.cost * cur_threat_frac))
|
||||
else
|
||||
drafted_rules[rule] = rule.get_weight()
|
||||
if (drafted_rules.len > 0)
|
||||
picking_midround_latejoin_rule(drafted_rules)
|
||||
|
||||
else
|
||||
midround_injection_cooldown = (midround_injection_cooldown + world.time)/2
|
||||
|
||||
if(event_injection_cooldown < world.time)
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
|
||||
message_admins("DYNAMIC: Doing event injection.")
|
||||
log_game("DYNAMIC: Doing event injection.")
|
||||
update_playercounts()
|
||||
var/list/drafted_rules = list()
|
||||
for(var/datum/dynamic_ruleset/event/rule in events)
|
||||
if(rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
|
||||
if(rule.ready())
|
||||
drafted_rules[rule] = rule.get_weight()
|
||||
if(drafted_rules.len > 0)
|
||||
picking_midround_latejoin_rule(drafted_rules)
|
||||
|
||||
/// Updates current_players.
|
||||
/datum/game_mode/dynamic/proc/update_playercounts()
|
||||
current_players[CURRENT_LIVING_PLAYERS] = list()
|
||||
@@ -641,7 +735,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
var/high_pop_factor = (current_players[CURRENT_LIVING_PLAYERS].len >= GLOB.dynamic_high_pop_limit)
|
||||
var/max_pop_per_antag = max(5,15 - round(threat_level/10) - round(current_players[CURRENT_LIVING_PLAYERS].len/(high_pop_factor ? 10 : 5)))
|
||||
if (!current_players[CURRENT_LIVING_ANTAGS].len)
|
||||
chance += 50 // No antags at all? let's boost those odds!
|
||||
chance += 80 // No antags at all? let's boost those odds!
|
||||
else
|
||||
var/current_pop_per_antag = current_players[CURRENT_LIVING_PLAYERS].len / current_players[CURRENT_LIVING_ANTAGS].len
|
||||
if (current_pop_per_antag > max_pop_per_antag)
|
||||
@@ -704,11 +798,11 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
continue
|
||||
// No stacking : only one round-enter, unless > stacking_limit threat.
|
||||
if (threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
// No stacking : only one round-ender, unless threat level > stacking_limit.
|
||||
if (threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(rule.flags & HIGHLANDER_RULESET && highlander_executed)
|
||||
continue
|
||||
|
||||
|
||||
rule.candidates = list(newPlayer)
|
||||
rule.trim_candidates()
|
||||
if (rule.ready())
|
||||
@@ -721,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)
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
#define EXTRA_RULESET_PENALTY 20 // Changes how likely a gamemode is to scale based on how many other roundstart rulesets are waiting to be rolled.
|
||||
#define POP_SCALING_PENALTY 50 // Discourages scaling up rulesets if ratio of antags to crew is high.
|
||||
|
||||
#define REVOLUTION_VICTORY 1
|
||||
#define STATION_VICTORY 2
|
||||
|
||||
/datum/dynamic_ruleset
|
||||
/// For admin logging and round end screen.
|
||||
var/name = ""
|
||||
/// For admin logging and round end screen, do not change this unless making a new rule type.
|
||||
var/ruletype = ""
|
||||
var/ruletype = ""
|
||||
/// For config purposes, similar to config_tag for secret game modes.
|
||||
var/config_tag = null
|
||||
/// If set to TRUE, the rule won't be discarded after being executed, and dynamic will call rule_process() every time it ticks.
|
||||
var/persistent = FALSE
|
||||
var/persistent = FALSE
|
||||
/// If set to TRUE, dynamic mode will be able to draft this ruleset again later on. (doesn't apply for roundstart rules)
|
||||
var/repeatable = FALSE
|
||||
var/repeatable = FALSE
|
||||
/// If set higher than 0 decreases weight by itself causing the ruleset to appear less often the more it is repeated.
|
||||
var/repeatable_weight_decrease = 2
|
||||
var/repeatable_weight_decrease = 2
|
||||
/// List of players that are being drafted for this rule
|
||||
var/list/mob/candidates = list()
|
||||
var/list/mob/candidates = list()
|
||||
/// List of players that were selected for this rule
|
||||
var/list/datum/mind/assigned = list()
|
||||
var/list/datum/mind/assigned = list()
|
||||
/// Preferences flag such as ROLE_WIZARD that need to be turned on for players to be antag
|
||||
var/antag_flag = null
|
||||
var/antag_flag = null
|
||||
/// The antagonist datum that is assigned to the mobs mind on ruleset execution.
|
||||
var/datum/antagonist/antag_datum = null
|
||||
/// The required minimum account age for this ruleset.
|
||||
@@ -24,19 +30,25 @@
|
||||
/// If set, and config flag protect_roles_from_antagonist is false, then the rule will not pick players from these roles.
|
||||
var/list/protected_roles = list()
|
||||
/// If set, rule will deny candidates from those roles always.
|
||||
var/list/restricted_roles = list()
|
||||
var/list/restricted_roles = list()
|
||||
/// If set, rule will only accept candidates from those roles, IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS.
|
||||
var/list/exclusive_roles = list()
|
||||
var/list/exclusive_roles = list()
|
||||
/// If set, there needs to be a certain amount of players doing those roles (among the players who won't be drafted) for the rule to be drafted IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS.
|
||||
var/list/enemy_roles = list()
|
||||
var/list/enemy_roles = list()
|
||||
/// If enemy_roles was set, this is the amount of enemy job workers needed per threat_level range (0-10,10-20,etc) IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS.
|
||||
var/required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
||||
var/required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
||||
/// The rule needs this many candidates (post-trimming) to be executed (example: Cult needs 4 players at round start)
|
||||
var/required_candidates = 0
|
||||
var/required_candidates = 0
|
||||
/// 1 -> 9, probability for this rule to be picked against other rules
|
||||
var/weight = 5
|
||||
var/weight = 5
|
||||
/// Threat cost for this rule, this is decreased from the mode's threat when the rule is executed.
|
||||
var/cost = 0
|
||||
var/cost = 0
|
||||
/// Cost per level the rule scales up.
|
||||
var/scaling_cost = 0
|
||||
/// How many times a rule has scaled up upon getting picked.
|
||||
var/scaled_times = 0
|
||||
/// Used for the roundend report
|
||||
var/total_cost = 0
|
||||
/// A flag that determines how the ruleset is handled
|
||||
/// HIGHLANDER_RULESET are rulesets can end the round.
|
||||
/// TRAITOR_RULESET and MINOR_RULESET can't end the round and have no difference right now.
|
||||
@@ -46,20 +58,28 @@
|
||||
/// Requirements are the threat level requirements per pop range.
|
||||
/// With the default values, The rule will never get drafted below 10 threat level (aka: "peaceful extended"), and it requires a higher threat level at lower pops.
|
||||
var/list/requirements = list(40,30,20,10,10,10,10,10,10,10)
|
||||
/// An alternative, static requirement used instead when pop is over mode's high_pop_limit.
|
||||
/// An alternative, static requirement used instead when pop is over mode's high_pop_limit.
|
||||
var/high_population_requirement = 10
|
||||
/// Reference to the mode, use this instead of SSticker.mode.
|
||||
var/datum/game_mode/dynamic/mode = null
|
||||
/// If a role is to be considered another for the purpose of banning.
|
||||
var/antag_flag_override = null
|
||||
var/antag_flag_override = null
|
||||
/// If a ruleset type which is in this list has been executed, then the ruleset will not be executed.
|
||||
var/list/blocking_rules = list()
|
||||
/// The minimum amount of players required for the rule to be considered.
|
||||
/// The minimum amount of players required for the rule to be considered.
|
||||
var/minimum_players = 0
|
||||
/// The maximum amount of players required for the rule to be considered.
|
||||
/// Anything below zero or exactly zero is ignored.
|
||||
/// Anything below zero or exactly zero is ignored.
|
||||
var/maximum_players = 0
|
||||
|
||||
/// Calculated during acceptable(), used in scaling and team sizes.
|
||||
var/indice_pop = 0
|
||||
/// Population scaling. Used by team antags and scaling for solo antags.
|
||||
var/list/antag_cap = list()
|
||||
/// Base probability used in scaling. The higher it is, the more likely to scale. Kept as a var to allow for config editing._SendSignal(sigtype, list/arguments)
|
||||
var/base_prob = 60
|
||||
/// Delay for when execute will get called from the time of post_setup (roundstart) or process (midround/latejoin).
|
||||
/// Make sure your ruleset works with execute being called during the game when using this, and that the clean_up proc reverts it properly in case of faliure.
|
||||
var/delay = 0
|
||||
|
||||
/datum/dynamic_ruleset/New()
|
||||
..()
|
||||
@@ -87,10 +107,6 @@
|
||||
/datum/dynamic_ruleset/roundstart // One or more of those drafted at roundstart
|
||||
ruletype = "Roundstart"
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/delayed/ // Executed with a 30 seconds delay
|
||||
var/delay = 30 SECONDS
|
||||
var/required_type = /mob/living/carbon/human // No ghosts, new players or silicons allowed.
|
||||
|
||||
// Can be drafted when a player joins the server
|
||||
/datum/dynamic_ruleset/latejoin
|
||||
ruletype = "Latejoin"
|
||||
@@ -103,17 +119,48 @@
|
||||
if(maximum_players > 0 && population > maximum_players)
|
||||
return FALSE
|
||||
if (population >= GLOB.dynamic_high_pop_limit)
|
||||
return (threat_level >= high_population_requirement)
|
||||
indice_pop = 10
|
||||
if(threat_level < high_population_requirement)
|
||||
log_game("DYNAMIC: [name] did not reach threat level threshold: [threat_level]/[high_population_requirement]")
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
else
|
||||
pop_per_requirement = pop_per_requirement > 0 ? pop_per_requirement : mode.pop_per_requirement
|
||||
var/indice_pop = min(10,round(population/pop_per_requirement)+1)
|
||||
return (threat_level >= requirements[indice_pop])
|
||||
if(antag_cap.len && requirements.len != antag_cap.len)
|
||||
message_admins("DYNAMIC: requirements and antag_cap lists have different lengths in ruleset [name]. Likely config issue, report this.")
|
||||
log_game("DYNAMIC: requirements and antag_cap lists have different lengths in ruleset [name]. Likely config issue, report this.")
|
||||
indice_pop = min(requirements.len,round(population/pop_per_requirement)+1)
|
||||
if(threat_level < requirements[indice_pop])
|
||||
log_game("DYNAMIC: [name] did not reach threat level threshold: [threat_level]/[requirements[indice_pop]]")
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
/// Called when a suitable rule is picked during roundstart(). Will some times attempt to scale a rule up when there is threat remaining. Returns the amount of scaled steps.
|
||||
/datum/dynamic_ruleset/proc/scale_up(extra_rulesets = 0, remaining_threat_level = 0)
|
||||
remaining_threat_level -= cost
|
||||
if(scaling_cost && scaling_cost <= remaining_threat_level) // Only attempts to scale the modes with a scaling cost explicitly set.
|
||||
var/new_prob
|
||||
var/pop_to_antags = (mode.antags_rolled + (antag_cap[indice_pop] * (scaled_times + 1))) / mode.roundstart_pop_ready
|
||||
log_game("DYNAMIC: [name] roundstart ruleset attempting to scale up with [extra_rulesets] rulesets waiting and [remaining_threat_level] threat remaining.")
|
||||
for(var/i in 1 to 3) //Can scale a max of 3 times
|
||||
if(remaining_threat_level >= scaling_cost && pop_to_antags < 0.25)
|
||||
new_prob = base_prob + (remaining_threat_level) - (scaled_times * scaling_cost) - (extra_rulesets * EXTRA_RULESET_PENALTY) - (pop_to_antags * POP_SCALING_PENALTY)
|
||||
if (!prob(new_prob))
|
||||
break
|
||||
remaining_threat_level -= scaling_cost
|
||||
scaled_times++
|
||||
pop_to_antags = (mode.antags_rolled + (antag_cap[indice_pop] * (scaled_times + 1))) / mode.roundstart_pop_ready
|
||||
log_game("DYNAMIC: [name] roundstart ruleset failed scaling up at [new_prob ? new_prob : 0]% chance after [scaled_times]/3 successful scaleups. [remaining_threat_level] threat remaining, antag to crew ratio: [pop_to_antags*100]%.")
|
||||
mode.antags_rolled += (1 + scaled_times) * antag_cap[indice_pop]
|
||||
return scaled_times * scaling_cost
|
||||
|
||||
/// This is called if persistent variable is true everytime SSTicker ticks.
|
||||
/datum/dynamic_ruleset/proc/rule_process()
|
||||
return
|
||||
|
||||
/// Called on game mode pre_setup, used for non-delayed roundstart rulesets only.
|
||||
/// Called on game mode pre_setup for roundstart rulesets.
|
||||
/// Do everything you need to do before job is assigned here.
|
||||
/// IMPORTANT: ASSIGN special_role HERE
|
||||
/datum/dynamic_ruleset/proc/pre_execute()
|
||||
@@ -126,20 +173,20 @@
|
||||
M.add_antag_datum(antag_datum)
|
||||
return TRUE
|
||||
|
||||
/// Called after delay set in ruleset.
|
||||
/// Give your candidates or assignees equipment and antag datum here.
|
||||
/datum/dynamic_ruleset/roundstart/delayed/execute()
|
||||
if (SSticker && SSticker.current_state < GAME_STATE_PLAYING)
|
||||
CRASH("The delayed ruleset [name] executed before the round started.")
|
||||
|
||||
/// Here you can perform any additional checks you want. (such as checking the map etc)
|
||||
/// Remember that on roundstart no one knows what their job is at this point.
|
||||
/// IMPORTANT: If ready() returns TRUE, that means pre_execute() or execute() should never fail!
|
||||
/datum/dynamic_ruleset/proc/ready(forced = 0)
|
||||
if (required_candidates > candidates.len)
|
||||
/datum/dynamic_ruleset/proc/ready(forced = 0)
|
||||
if (required_candidates > candidates.len)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// Runs from gamemode process() if ruleset fails to start, like delayed rulesets not getting valid candidates.
|
||||
/// This one only handles refunding the threat, override in ruleset to clean up the rest.
|
||||
/datum/dynamic_ruleset/proc/clean_up()
|
||||
mode.refund_threat(cost + (scaled_times * scaling_cost))
|
||||
mode.log_threat("[ruletype] [name] refunded [cost + (scaled_times * scaling_cost)]",verbose=TRUE)
|
||||
|
||||
/// Gets weight of the ruleset
|
||||
/// Note that this decreases weight if repeatable is TRUE and repeatable_weight_decrease is higher than 0
|
||||
/// Note: If you don't want repeatable rulesets to decrease their weight use the weight variable directly
|
||||
@@ -156,14 +203,6 @@
|
||||
/datum/dynamic_ruleset/proc/trim_candidates()
|
||||
return
|
||||
|
||||
/// Counts how many players are ready at roundstart.
|
||||
/// Used only by non-delayed roundstart rulesets.
|
||||
/datum/dynamic_ruleset/proc/num_players()
|
||||
. = 0
|
||||
for(var/mob/dead/new_player/P in GLOB.player_list)
|
||||
if(P.client && P.ready == PLAYER_READY_TO_PLAY)
|
||||
. ++
|
||||
|
||||
/// Set mode result and news report here.
|
||||
/// Only called if ruleset is flagged as HIGHLANDER_RULESET
|
||||
/datum/dynamic_ruleset/proc/round_result()
|
||||
@@ -191,32 +230,14 @@
|
||||
if(P.mind.special_role) // We really don't want to give antag to an antag.
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
|
||||
/// Checks if candidates are required mob type, connected, banned and if the job is exclusive to the role.
|
||||
/datum/dynamic_ruleset/roundstart/delayed/trim_candidates()
|
||||
. = ..()
|
||||
for (var/mob/P in candidates)
|
||||
if (!istype(P, required_type))
|
||||
candidates.Remove(P) // Can be a new_player, etc.
|
||||
continue
|
||||
if(!mode.check_age(P.client, minimum_required_age))
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if(P.mind.special_role || P.mind.antag_datums?.len > 0) // Are they an antag already?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if(antag_flag_override)
|
||||
if(!(antag_flag_override in P.client.prefs.be_special) || jobban_isbanned(P.ckey, antag_flag_override))
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
else
|
||||
if(!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, antag_flag))
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
|
||||
/// Do your checks if the ruleset is ready to be executed here.
|
||||
/// Should ignore certain checks if forced is TRUE
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
/datum/dynamic_ruleset/event
|
||||
ruletype = "Event"
|
||||
var/typepath // typepath of the event
|
||||
var/triggering
|
||||
|
||||
/datum/dynamic_ruleset/event/execute()
|
||||
var/datum/round_event/E = new typepath()
|
||||
E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
|
||||
// E.control = src // can't be done! we just don't use events that require these, those can be from_ghost almost always
|
||||
|
||||
testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
|
||||
deadchat_broadcast("<span class='deadsay'><b>[name]</b> has just been triggered by dynamic!</span>")
|
||||
log_game("Random Event triggering: [name] ([typepath])")
|
||||
|
||||
return E
|
||||
|
||||
/datum/dynamic_ruleset/event/ready(forced = FALSE) // same as midround cause we're still using enemy system
|
||||
if (!forced)
|
||||
var/job_check = 0
|
||||
if (enemy_roles.len > 0)
|
||||
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
|
||||
if (M.stat == DEAD)
|
||||
continue // Dead players cannot count as opponents
|
||||
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles))
|
||||
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
|
||||
|
||||
var/threat = round(mode.threat_level/10)
|
||||
if (job_check < required_enemies[threat])
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// PIRATES //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/pirates
|
||||
name = "Space Pirates"
|
||||
config_tag = "pirates"
|
||||
typepath = /datum/round_event/pirates
|
||||
antag_flag = ROLE_TRAITOR
|
||||
enemy_roles = list("AI","Security Officer","Head of Security","Captain")
|
||||
required_enemies = list(2,2,1,1,0,0,0,0,0,0)
|
||||
weight = 5
|
||||
cost = 10
|
||||
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
|
||||
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
||||
high_population_requirement = 15
|
||||
|
||||
/datum/dynamic_ruleset/event/pirates/ready(forced = FALSE)
|
||||
if (!SSmapping.empty_space)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// SPIDERS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/spiders
|
||||
name = "Spider Infestation"
|
||||
config_tag = "spiders"
|
||||
typepath = /datum/round_event/spider_infestation
|
||||
enemy_roles = list("AI","Security Officer","Head of Security","Captain")
|
||||
required_enemies = list(2,2,1,1,0,0,0,0,0,0)
|
||||
weight = 5
|
||||
cost = 10
|
||||
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
||||
high_population_requirement = 15
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// CLOGGED VENTS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/ventclog
|
||||
name = "Clogged Vents"
|
||||
config_tag = "ventclog"
|
||||
typepath = /datum/round_event/vent_clog
|
||||
enemy_roles = list("Chemist","Medical Doctor","Chief Medical Officer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
cost = 2
|
||||
weight = 4
|
||||
repeatable_weight_decrease = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5) // yes, can happen on fake-extended
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/ventclog/ready()
|
||||
if(mode.threat_level > 30 && mode.threat >= 5 && prob(20))
|
||||
name = "Clogged Vents: Threatening"
|
||||
cost = 5
|
||||
required_enemies = list(3,3,3,2,2,2,1,1,1,1)
|
||||
typepath = /datum/round_event/vent_clog/threatening
|
||||
else if(mode.threat_level > 15 && mode.threat > 15 && prob(30))
|
||||
name = "Clogged Vents: Catastrophic"
|
||||
cost = 15
|
||||
required_enemies = list(2,2,1,1,1,1,0,0,0,0)
|
||||
typepath = /datum/round_event/vent_clog/catastrophic
|
||||
else
|
||||
cost = 2
|
||||
name = "Clogged Vents: Normal"
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
typepath = /datum/round_event/vent_clog
|
||||
return ..()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// ION STORM //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/ion_storm
|
||||
name = "Ion Storm"
|
||||
config_tag = "ion_storm"
|
||||
typepath = /datum/round_event/ion_storm
|
||||
enemy_roles = list("Research Director","Captain","Chief Engineer")
|
||||
required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
||||
weight = 4
|
||||
// no repeatable weight decrease. too variable to be unfun multiple times in one round
|
||||
cost = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// METEORS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/meteor_wave
|
||||
name = "Meteor Wave"
|
||||
config_tag = "meteor_wave"
|
||||
typepath = /datum/round_event/meteor_wave
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Captain","Cyborg")
|
||||
required_enemies = list(3,3,3,3,3,3,3,3,3,3)
|
||||
cost = 15
|
||||
weight = 3
|
||||
repeatable_weight_decrease = 2
|
||||
requirements = list(60,50,40,30,30,30,30,30,30,30)
|
||||
high_population_requirement = 30
|
||||
|
||||
/datum/dynamic_ruleset/event/meteor_wave/ready()
|
||||
if(mode.threat_level > 40 && mode.threat >= 25 && prob(20))
|
||||
cost = 25
|
||||
typepath = /datum/round_event/meteor_wave/threatening
|
||||
else if(mode.threat_level > 50 && mode.threat >= 40 && prob(30))
|
||||
cost = 40
|
||||
typepath = /datum/round_event/meteor_wave/catastrophic
|
||||
else
|
||||
cost = 15
|
||||
typepath = /datum/round_event/meteor_wave
|
||||
return ..()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// ANOMALIES //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_bluespace
|
||||
name = "Anomaly: Bluespace"
|
||||
config_tag = "anomaly_bluespace"
|
||||
typepath = /datum/round_event/anomaly/anomaly_bluespace
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_flux
|
||||
name = "Anomaly: Hyper-Energetic Flux"
|
||||
config_tag = "anomaly_flux"
|
||||
typepath = /datum/round_event/anomaly/anomaly_flux
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 5
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_gravitational
|
||||
name = "Anomaly: Gravitational"
|
||||
config_tag = "anomaly_gravitational"
|
||||
typepath = /datum/round_event/anomaly/anomaly_grav
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_pyroclastic
|
||||
name = "Anomaly: Pyroclastic"
|
||||
config_tag = "anomaly_pyroclastic"
|
||||
typepath = /datum/round_event/anomaly/anomaly_pyro
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 5
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_vortex
|
||||
name = "Anomaly: Vortex"
|
||||
config_tag = "anomaly_vortex"
|
||||
typepath = /datum/round_event/anomaly/anomaly_vortex
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 5
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// WOW THAT'S A LOT OF EVENTS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/brand_intelligence
|
||||
name = "Brand Intelligence"
|
||||
config_tag = "brand_intelligence"
|
||||
typepath = /datum/round_event/brand_intelligence
|
||||
weight = 1
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 2
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
|
||||
required_enemies = list(1,1,1,1,0,0,0,0,0,0)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/carp_migration
|
||||
name = "Carp Migration"
|
||||
config_tag = "carp_migration"
|
||||
typepath = /datum/round_event/carp_migration
|
||||
weight = 7
|
||||
repeatable_weight_decrease = 3
|
||||
cost = 4
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/communications_blackout
|
||||
name = "Communications Blackout"
|
||||
config_tag = "communications_blackout"
|
||||
typepath = /datum/round_event/communications_blackout
|
||||
cost = 4
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 3
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/processor_overload
|
||||
name = "Processor Overload"
|
||||
config_tag = "processor_overload"
|
||||
typepath = /datum/round_event/processor_overload
|
||||
cost = 4
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 3
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/space_dust
|
||||
name = "Minor Space Dust"
|
||||
config_tag = "space_dust"
|
||||
typepath = /datum/round_event/space_dust
|
||||
cost = 2
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/major_dust
|
||||
name = "Major Space Dust"
|
||||
config_tag = "major_dust"
|
||||
typepath = /datum/round_event/meteor_wave/major_dust
|
||||
cost = 4
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/electrical_storm
|
||||
name = "Electrical Storm"
|
||||
config_tag = "electrical_storm"
|
||||
typepath = /datum/round_event/electrical_storm
|
||||
cost = 1
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/heart_attack
|
||||
name = "Random Heart Attack"
|
||||
config_tag = "heart_attack"
|
||||
typepath = /datum/round_event/heart_attack
|
||||
cost = 3
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Medical Doctor","Chief Medical Officer")
|
||||
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
|
||||
requirements = list(101,101,101,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/radiation_storm
|
||||
name = "Radiation Storm"
|
||||
config_tag = "radiation_storm"
|
||||
typepath = /datum/round_event/radiation_storm
|
||||
cost = 3
|
||||
weight = 1
|
||||
enemy_roles = list("Chemist","Chief Medical Officer","Geneticist","Medical Doctor","AI","Captain")
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user