This commit is contained in:
Navier
2020-08-15 23:13:41 -04:00
1991 changed files with 81350 additions and 60294 deletions
+8 -1
View File
@@ -108,6 +108,8 @@
#define TR_KEEPSE (1<<5) // changelings shouldn't edit the DNA's SE when turning into a monkey
#define TR_DEFAULTMSG (1<<6)
#define TR_KEEPORGANS (1<<8)
#define TR_KEEPREAGENTS (1<<10)
#define TR_KEEPSTUNS (1<<9)
#define CLONER_FRESH_CLONE "fresh"
@@ -140,6 +142,11 @@
#define CUSTOM_SKINTONE 24 //adds a "_g" suffix to bodypart overlays icon states if a custom skintone is used.
#define HORNCOLOR 25
#define WINGCOLOR 26
#define CAN_SCAR 27 // If this species can be scarred (fleshy)
/// Used for determining which wounds are applicable to this species.
#define HAS_FLESH 28 /// if we have flesh (can suffer slash/piercing/burn wounds, requires they don't have NOBLOOD)
#define HAS_BONE 29 /// if we have bones (can suffer bone wounds)
//organ slots
#define ORGAN_SLOT_BRAIN "brain"
@@ -184,4 +191,4 @@
#define G_MALE 1
#define G_FEMALE 2
#define G_PLURAL 3
#define G_NEUTER 4
#define G_NEUTER 4
-4
View File
@@ -138,10 +138,6 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define MOBILITY_FLAGS_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_PICKUP | MOBILITY_USE | MOBILITY_UI | MOBILITY_STORAGE | MOBILITY_PULL | MOBILITY_RESIST)
#define MOBILITY_FLAGS_ANY_INTERACTION (MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_UI | MOBILITY_STORAGE)
// melee_attack_chain() attackchain_flags
/// The attack is from a parry counterattack.
#define ATTACKCHAIN_PARRY_COUNTERATTACK (1<<0)
/// If the thing can reflect light (lasers/energy)
#define RICOCHET_SHINY (1<<0)
/// If the thing can reflect matter (bullets/bomb shrapnel)
+1 -1
View File
@@ -52,4 +52,4 @@
#define ORGAN_VITAL (1<<4) //Currently only the brain
#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
#define ORGAN_NO_DISMEMBERMENT (1<<6) //Immune to disembowelment.
#define ORGAN_EDIBLE (1<<5) //is a snack? :D
#define ORGAN_EDIBLE (1<<7) //is a snack? :D
+5
View File
@@ -12,4 +12,9 @@
#define SHOVABLE_ONTO (1<<9) //called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check.
#define BLOCK_Z_FALL (1<<10)
/// Integrity defines for clothing (not flags but close enough)
#define CLOTHING_PRISTINE 0 // We have no damage on the clothing
#define CLOTHING_DAMAGED 1 // There's some damage on the clothing but it still has at least one functioning bodypart and can be equipped
#define CLOTHING_SHREDDED 2 // The clothing is useless and cannot be equipped unless repaired first
// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
+22
View File
@@ -0,0 +1,22 @@
/////////// ATTACKCHAIN_FLAGS ////////////
// melee_attack_chain(), attackby(), pre_attack(), afterattack(), and tool_act(), attack() and **anything that is called by ClickOn()** return values.
// These are all passed down through the attack chain and are binary OR'd into each other!
/// Stop the attack chain if still in melee_attack_chain()
#define STOP_ATTACK_PROC_CHAIN (1<<0)
/// This attack should discard last_action instead of flushing (storing) it). You should probably know what you're doing if you use this considering this is how clickdelay is enforced.
#define DISCARD_LAST_ACTION (1<<1)
/// There are a number of "safety nets" intended to default-handle clickdelay. Return this flag to bypass ALL of them. Be sure
/// you know EXACTLY what you are doing!
#define NO_AUTO_CLICKDELAY_HANDLING (1<<2)
/// Only used with UnarmedAttack(). Interrupts unarmed attack from progressing.
#define INTERRUPT_UNARMED_ATTACK (1<<3)
/// Attack should not set next action even if the atom wants it to be an action
#define ATTACK_IGNORE_ACTION (1<<4)
/// Attack should not at all check last_action/attack_hand_speed even if the atom wants to
#define ATTACK_IGNORE_CLICKDELAY (1<<5)
/// This attack is from a parry counterattack
#define ATTACK_IS_PARRY_COUNTERATTACK (1<<6)
// obj/item/dropped()
/// dropped() relocated this item, return FALSE for doUnEquip.
#define ITEM_RELOCATED_BY_DROPPED "relocated_by_dropped"
+7
View File
@@ -74,6 +74,13 @@
#define ADMIN_PUNISHMENT_MAZING "Puzzle"
#define ADMIN_PUNISHMENT_PIE "Cream Pie"
#define ADMIN_PUNISHMENT_CUSTOM_PIE "Custom Cream Pie"
#define ADMIN_PUNISHMENT_SHOES "Knot Shoes"
#define ADMIN_PUNISHMENT_CRACK ":B:oneless"
#define ADMIN_PUNISHMENT_BLEED ":B:loodless"
#define ADMIN_PUNISHMENT_SCARIFY "Scarify"
#define ADMIN_PUNISHMENT_PICKLE "Pickle-ify"
#define ADMIN_PUNISHMENT_FRY "Fry"
#define ADMIN_PUNISHMENT_PERFORATE ":B:erforate"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
+1 -1
View File
@@ -1,6 +1,6 @@
// Defines for managed input/keybinding system.
/// Max length of a keypress command before it's considered to be a forged packet/bogus command
#define MAX_KEYPRESS_COMMANDLENGTH 16
#define MAX_KEYPRESS_COMMANDLENGTH 32
/// Maximum keys that can be bound to one button
#define MAX_COMMANDS_PER_KEY 5
/// Maximum keys per keybind
+4
View File
@@ -0,0 +1,4 @@
// Reaction priorities, higher makes it checked first. Otherwise, it goes based on reaction temperature requirements.
#define CHEMICAL_REACTION_PRIORITY_DEFAULT 100
#define CHEMICAL_REACTION_PRIORITY_SMOKE 1000
+1
View File
@@ -98,6 +98,7 @@
#define NO_APHRO (1<<9)
#define NO_ASS_SLAP (1<<10)
#define BIMBOFICATION (1<<11)
#define NO_AUTO_WAG (1<<12)
#define TOGGLES_CITADEL 0
+16 -9
View File
@@ -8,6 +8,7 @@
GLOBAL_VAR_INIT(clockwork_construction_value, 0) //The total value of all structures built by the clockwork cult
GLOBAL_VAR_INIT(clockwork_vitality, 0) //How much Vitality is stored, total
GLOBAL_VAR_INIT(clockwork_power, 0) //How many watts of power are globally available to the clockwork cult
GLOBAL_LIST_EMPTY(active_daemons) //A list of all active tinkerer's daemons
GLOBAL_VAR_INIT(neovgre_exists, 0) //Does neovgre exist?
GLOBAL_LIST_EMPTY(all_clockwork_objects) //All clockwork items, structures, and effects in existence
@@ -19,21 +20,23 @@ GLOBAL_VAR_INIT(ark_of_the_clockwork_justiciar, FALSE) //The Ark on the Reebe z-
GLOBAL_VAR_INIT(clockwork_gateway_activated, FALSE) //if a gateway to the celestial derelict has ever been successfully activated
GLOBAL_VAR_INIT(script_scripture_unlocked, FALSE) //If script scripture is available, through converting at least one crewmember
GLOBAL_VAR_INIT(application_scripture_unlocked, FALSE) //If script scripture is available
GLOBAL_VAR_INIT(application_scripture_unlocked, FALSE) //If application scripture is available
GLOBAL_VAR_INIT(judgement_scripture_unlocked, FALSE) //If judgement scripture is available
GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not used to track existing scripture
GLOBAL_LIST_EMPTY(all_clockwork_rites) //a list containing all clockwork rites. Filled the first time any cultist interacts with a sigil of rites.
//Scripture tiers and requirements; peripherals should never be used
#define SCRIPTURE_PERIPHERAL "Peripheral"
#define SCRIPTURE_DRIVER "Driver"
#define SCRIPTURE_SCRIPT "Script"
#define SCRIPTURE_APPLICATION "Application"
#define SCRIPTURE_JUDGEMENT "Judgement"
//Various costs related to power.
#define MAX_CLOCKWORK_POWER 80000 //The max power in W that the cult can stockpile
#define SCRIPT_UNLOCK_THRESHOLD 35000 //Scripts will unlock if the total power reaches this amount
#define APPLICATION_UNLOCK_THRESHOLD 50000 //Applications will unlock if the total powre reaches this amount
#define ABSCOND_ABDUCTION_COST 95
#define APPLICATION_UNLOCK_THRESHOLD 50000 //Applications will unlock if the total power reaches this amount
#define JUDGEMENT_UNLOCK_THRESHOLD 80000 //might as well have this unlock at a power amount like the other scriptures, Judgement unlocks at this amount.
//clockcult power defines
#define MIN_CLOCKCULT_POWER 25 //the minimum amount of power clockcult machines will handle gracefully
@@ -59,11 +62,11 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
//Ark defines
#define GATEWAY_SUMMON_RATE 1 //the time amount the Gateway to the Celestial Derelict gets each process tick; defaults to 1 per tick
#define GATEWAY_REEBE_FOUND 240 //when progress is at or above this, the gateway finds reebe and begins drawing power
#define GATEWAY_REEBE_FOUND 120 //when progress is at or above this, the gateway finds reebe and begins drawing power
#define GATEWAY_RATVAR_COMING 480 //when progress is at or above this, ratvar has entered and is coming through the gateway
#define GATEWAY_RATVAR_COMING 240 //when progress is at or above this, ratvar has entered and is coming through the gateway
#define GATEWAY_RATVAR_ARRIVAL 600 //when progress is at or above this, game over ratvar's here everybody go home
#define GATEWAY_RATVAR_ARRIVAL 300 //when progress is at or above this, game over ratvar's here everybody go home
//Objective text define
#define CLOCKCULT_OBJECTIVE "Construct the Ark of the Clockwork Justicar and free Ratvar."
@@ -81,7 +84,7 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
#define CLOCKWORK_ARMOR_COOLDOWN 1800 //The cooldown period between summoning suits of clockwork armor
#define RATVARIAN_SPEAR_COOLDOWN 300 //The cooldown period between summoning another Ratvarian spear
#define RATVARIAN_WEAPON_COOLDOWN 300 //The cooldown period between summoning another Ratvarian spear
#define MARAUDER_SCRIPTURE_SCALING_THRESHOLD 600 //The amount of deciseconds that must pass before marauder scripture will not gain a recital penalty
@@ -89,4 +92,8 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
#define MARAUDER_SCRIPTURE_SCALING_MAX 300 //The maximum extra time applied to the marauder scripture
#define ARK_SCREAM_COOLDOWN 600 //This much time has to pass between instances of the Ark taking damage before it will "scream" again
#define GUARDIAN_EMERGE_THRESHOLD 65 //guardian cannot emerge unless host is at this% or less health
#define ARK_SCREAM_COOLDOWN 300 //This much time has to pass between instances of the Ark taking damage before it will "scream" again
#define PRISM_DELAY_DURATION 1200 //how long prolonging prisms delay the shuttle for; defaults to 2 minutes
+8 -8
View File
@@ -108,7 +108,6 @@
#define CLICK_CD_RANGE 4
#define CLICK_CD_RAPID 2
#define CLICK_CD_CLICK_ABILITY 6
#define CLICK_CD_BREAKOUT 100
#define CLICK_CD_HANDCUFFED 10
#define CLICK_CD_RESIST 20
#define CLICK_CD_GRABBING 10
@@ -155,9 +154,10 @@
#define SHOVE_KNOCKDOWN_HUMAN 30
#define SHOVE_KNOCKDOWN_TABLE 30
#define SHOVE_KNOCKDOWN_COLLATERAL 10
//for the shove slowdown, see __DEFINES/movespeed_modification.dm
#define SHOVE_SLOWDOWN_LENGTH 30
#define SHOVE_SLOWDOWN_STRENGTH 0.85 //multiplier
/// how long they're staggered for
#define SHOVE_STAGGER_DURATION 35
/// how long they're off balance for
#define SHOVE_OFFBALANCE_DURATION 30
//Shove disarming item list
GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
/obj/item/gun)))
@@ -209,9 +209,9 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define GUN_AIMING_TIME (2 SECONDS)
//Object/Item sharpness
#define IS_BLUNT 0
#define IS_SHARP 1
#define IS_SHARP_ACCURATE 2
#define SHARP_NONE 0
#define SHARP_EDGED 1
#define SHARP_POINTY 2
//His Grace.
#define HIS_GRACE_SATIATED 0 //He hungers not. If bloodthirst is set to this, His Grace is asleep.
@@ -281,7 +281,7 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
/// changeNext_move penalty multiplier of the above.
#define STAM_CRIT_ITEM_ATTACK_DELAY 1.75
/// Damage penalty when fighting prone.
#define LYING_DAMAGE_PENALTY 0.5
#define LYING_DAMAGE_PENALTY 0.7
/// Added delay when firing guns stam-softcritted. Summed with a hardset CLICK_CD_RANGE delay, similar to STAM_CRIT_DAMAGE_DELAY otherwise.
#define STAM_CRIT_GUN_DELAY 2.75
+19 -4
View File
@@ -32,6 +32,8 @@
#define COMSIG_ELEMENT_DETACH "element_detach"
// /atom signals
//from base of atom/proc/Initialize(): sent any time a new atom is created
#define COMSIG_ATOM_CREATED "atom_created"
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
@@ -207,6 +209,8 @@
#define COMSIG_MOB_SWAP_HANDS "mob_swap_hands" //from base of mob/swap_hand(): (obj/item)
#define COMPONENT_BLOCK_SWAP 1
#define COMSIG_PROCESS_BORGCHARGER_OCCUPANT "living_charge"
// /client signals
#define COMSIG_MOB_CLIENT_LOGIN "mob_client_login" //sent when a mob/login() finishes: (client)
#define COMSIG_MOB_CLIENT_LOGOUT "mob_client_logout" //sent when a mob/logout() starts: (client)
@@ -250,7 +254,14 @@
#define COMPONENT_INTERRUPT_LIFE_BIOLOGICAL 1 // interrupt biological processes
#define COMPONENT_INTERRUPT_LIFE_PHYSICAL 2 // interrupt physical handling
// /mob/living/carbon signals
// /mob/living/carbon physiology signals
#define COMSIG_CARBON_GAIN_WOUND "carbon_gain_wound" //from /datum/wound/proc/apply_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L)
#define COMSIG_CARBON_LOSE_WOUND "carbon_lose_wound" //from /datum/wound/proc/remove_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L)
///from base of /obj/item/bodypart/proc/attach_limb(): (new_limb, special) allows you to fail limb attachment
#define COMSIG_CARBON_ATTACH_LIMB "carbon_attach_limb"
#define COMPONENT_NO_ATTACH (1<<0)
#define COMSIG_CARBON_REMOVE_LIMB "carbon_remove_limb" //from base of /obj/item/bodypart/proc/drop_limb(special, dismembered)
#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
#define COMSIG_CARBON_IDENTITY_TRANSFERRED_TO "carbon_id_transferred_to" //from datum/dna/transfer_identity(): (datum/dna, transfer_SE)
#define COMSIG_CARBON_TACKLED "carbon_tackled" //sends from tackle.dm on tackle completion
@@ -347,10 +358,10 @@
#define COMSIG_PEN_ROTATED "pen_rotated" //called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
// /obj/item/projectile signals (sent to the firer)
#define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" // from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" // from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
#define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" ///from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle, hit_limb)
#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" ///from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle, hit_limb)
#define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" // from base of /obj/item/projectile/proc/fire(): (obj/item/projectile, atom/original_target)
#define COMSIG_PROJECTILE_FIRE "projectile_fire" ///from the base of /obj/projectile/proc/fire(): ()
#define COMSIG_PROJECTILE_FIRE "projectile_fire" ///from the base of /obj/item/projectile/proc/fire(): ()
#define COMSIG_PROJECTILE_RANGE_OUT "projectile_range_out" // sent to targets during the process_hit proc of projectiles
#define COMSIG_EMBED_TRY_FORCE "item_try_embed" // sent when trying to force an embed (mainly for projectiles, only used in the embed element)
#define COMSIG_PROJECTILE_PREHIT "com_proj_prehit" ///sent to targets during the process_hit proc of projectiles
@@ -360,6 +371,7 @@
// /mob/living/carbon/human signals
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
#define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack"
#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" //Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
#define COMSIG_HUMAN_PREFS_COPIED_TO "human_prefs_copied_to" //from datum/preferences/copy_to(): (datum/preferences, icon_updates, roundstart_checks)
#define COMSIG_HUMAN_HARDSET_DNA "human_hardset_dna" //from mob/living/carbon/human/hardset_dna(): (ui, list/mutation_index, newreal_name, newblood_type, datum/species, newfeatures)
@@ -442,6 +454,9 @@
#define COMPONENT_TWOHANDED_BLOCK_WIELD 1
#define COMSIG_TWOHANDED_UNWIELD "twohanded_unwield" //from base of datum/component/two_handed/proc/unwield(mob/living/carbon/user): (/mob/user)
// /datum/component/squeak signals
#define COMSIG_CROSS_SQUEAKED "cross_squeaked" // sent when a squeak component squeaks from crossing something, to delay anything else crossing that might squeak to prevent ear hurt.
// /datum/action signals
#define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action)
#define COMPONENT_ACTION_BLOCK_TRIGGER 1
+35
View File
@@ -0,0 +1,35 @@
/// Module is compatible with Security Cyborg models
#define BORG_MODULE_SECURITY (1<<0)
/// Module is compatible with Miner Cyborg models
#define BORG_MODULE_MINER (1<<1)
/// Module is compatible with Janitor Cyborg models
#define BORG_MODULE_JANITOR (1<<2)
/// Module is compatible with Medical Cyborg models
#define BORG_MODULE_MEDICAL (1<<3)
/// Module is compatible with Engineering Cyborg models
#define BORG_MODULE_ENGINEERING (1<<4)
/// Module is compatible with Ripley Exosuit models
#define EXOSUIT_MODULE_RIPLEY (1<<0)
/// Module is compatible with Odyseeus Exosuit models
#define EXOSUIT_MODULE_ODYSSEUS (1<<1)
/// Module is compatible with Clarke Exosuit models. Rebranded to firefighter because tg nerfed it to this.
#define EXOSUIT_MODULE_FIREFIGHTER (1<<2)
// #define EXOSUIT_MODULE_CLARKE (1<<2)
/// Module is compatible with Gygax Exosuit models
#define EXOSUIT_MODULE_GYGAX (1<<3)
/// Module is compatible with Durand Exosuit models
#define EXOSUIT_MODULE_DURAND (1<<4)
/// Module is compatible with H.O.N.K Exosuit models
#define EXOSUIT_MODULE_HONK (1<<5)
/// Module is compatible with Phazon Exosuit models
#define EXOSUIT_MODULE_PHAZON (1<<6)
/// Module is compatable with N models
#define EXOSUIT_MODULE_GYGAX_MED (1<<7)
/// Module is compatible with "Working" Exosuit models - Ripley and Clarke
#define EXOSUIT_MODULE_WORKING EXOSUIT_MODULE_RIPLEY | EXOSUIT_MODULE_FIREFIGHTER // | EXOSUIT_MODULE_CLARKE
/// Module is compatible with "Combat" Exosuit models - Gygax, H.O.N.K, Durand and Phazon
#define EXOSUIT_MODULE_COMBAT EXOSUIT_MODULE_GYGAX | EXOSUIT_MODULE_HONK | EXOSUIT_MODULE_DURAND | EXOSUIT_MODULE_PHAZON
/// Module is compatible with "Medical" Exosuit modelsm - Odysseus
#define EXOSUIT_MODULE_MEDICAL EXOSUIT_MODULE_ODYSSEUS | EXOSUIT_MODULE_GYGAX_MED
+2 -2
View File
@@ -7,10 +7,10 @@
#define PULSE_CHANNEL "pulse channel"
// Methods of obtaining a circuit.
#define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box and able to be printed in the IC printer.
#define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box and is able to be printed in the IC printer.
#define IC_SPAWN_RESEARCH 2 // If the circuit design will be available in the IC printer after upgrading it.
// Categories that help differentiate circuits that can do different tipes of actions
// Categories that help differentiate circuits that can do different types of actions
#define IC_ACTION_MOVEMENT (1<<0) // If the circuit can move the assembly
#define IC_ACTION_COMBAT (1<<1) // If the circuit can cause harm
#define IC_ACTION_LONG_RANGE (1<<2) // If the circuit communicate with something outside of the assembly
+3 -13
View File
@@ -65,9 +65,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isslimeperson(A) (is_species(A, /datum/species/jelly/slime))
#define isluminescent(A) (is_species(A, /datum/species/jelly/luminescent))
#define iszombie(A) (is_species(A, /datum/species/zombie))
#define ismoth(A) (is_species(A, /datum/species/insect))
#define ishumanbasic(A) (is_species(A, /datum/species/human))
#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) )
#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid))
#define isdwarf(A) (is_species(A, /datum/species/dwarf))
#define isdullahan(A) (is_species(A, /datum/species/dullahan))
#define isangel(A) (is_species(A, /datum/species/angel))
@@ -75,13 +74,12 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define ismush(A) (is_species(A, /datum/species/mush))
#define isshadow(A) (is_species(A, /datum/species/shadow))
#define isskeleton(A) (is_species(A, /datum/species/skeleton))
#define isethereal(A) (is_species(A, /datum/species/ethereal))
// Citadel specific species
#define isipcperson(A) (is_species(A, /datum/species/ipc))
#define issynthliz(A) (is_species(A, /datum/species/synthliz))
#define ismammal(A) (is_species(A, /datum/species/mammal))
#define isavian(A) (is_species(A, /datum/species/avian))
#define isaquatic(A) (is_species(A, /datum/species/aquatic))
#define isinsect(A) (is_species(A, /datum/species/insect))
#define isxenoperson(A) (is_species(A, /datum/species/xeno))
#define isstartjelly(A) (is_species(A, /datum/species/jelly/roundstartslime))
@@ -202,21 +200,13 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isclothing(A) (istype(A, /obj/item/clothing))
GLOBAL_LIST_INIT(pointed_types, typecacheof(list(
/obj/item/pen,
/obj/item/screwdriver,
/obj/item/reagent_containers/syringe,
/obj/item/kitchen/fork)))
#define is_pointed(W) (is_type_in_typecache(W, GLOB.pointed_types))
#define isbodypart(A) (istype(A, /obj/item/bodypart))
#define isprojectile(A) (istype(A, /obj/item/projectile))
#define isgun(A) (istype(A, /obj/item/gun))
#define isfood(A) (istype(A, /obj/item/reagent_containers/food))
#define isfood(A) (istype(A, /obj/item/reagent_containers/food/snacks))
//Assemblies
#define isassembly(O) (istype(O, /obj/item/assembly))
+2
View File
@@ -131,6 +131,8 @@
#define LIGHTING_LAYER 15
#define LIGHTING_RENDER_TARGET "LIGHT_PLANE"
#define RAD_TEXT_LAYER 15.1
#define ABOVE_LIGHTING_PLANE 16
#define ABOVE_LIGHTING_LAYER 16
#define ABOVE_LIGHTING_RENDER_TARGET "ABOVE_LIGHTING_PLANE"
+56
View File
@@ -0,0 +1,56 @@
//defines for loadout categories
//no category defines
#define LOADOUT_CATEGORY_NONE "ERROR"
#define LOADOUT_SUBCATEGORY_NONE "Miscellaneous"
#define LOADOUT_SUBCATEGORIES_NONE list("Miscellaneous")
//backpack
#define LOADOUT_CATEGORY_BACKPACK "In backpack"
#define LOADOUT_SUBCATEGORY_BACKPACK_GENERAL "General" //basically anything that there's not enough of to have its own subcategory
#define LOADOUT_SUBCATEGORY_BACKPACK_TOYS "Toys"
//neck
#define LOADOUT_CATEGORY_NECK "Neck"
#define LOADOUT_SUBCATEGORY_NECK_GENERAL "General"
#define LOADOUT_SUBCATEGORY_NECK_TIE "Ties"
#define LOADOUT_SUBCATEGORY_NECK_SCARVES "Scarves"
//mask
#define LOADOUT_CATEGORY_MASK "Mask"
//hands
#define LOADOUT_CATEGORY_HANDS "Hands"
//uniform
#define LOADOUT_CATEGORY_UNIFORM "Uniform" //there's so many types of uniform it's best to have lots of categories
#define LOADOUT_SUBCATEGORY_UNIFORM_GENERAL "General"
#define LOADOUT_SUBCATEGORY_UNIFORM_JOBS "Jobs"
#define LOADOUT_SUBCATEGORY_UNIFORM_SUITS "Suits"
#define LOADOUT_SUBCATEGORY_UNIFORM_SKIRTS "Skirts"
#define LOADOUT_SUBCATEGORY_UNIFORM_DRESSES "Dresses"
#define LOADOUT_SUBCATEGORY_UNIFORM_SWEATERS "Sweaters"
#define LOADOUT_SUBCATEGORY_UNIFORM_PANTS "Pants"
#define LOADOUT_SUBCATEGORY_UNIFORM_SHORTS "Shorts"
//suit
#define LOADOUT_CATEGORY_SUIT "Suit"
#define LOADOUT_SUBCATEGORY_SUIT_GENERAL "General"
#define LOADOUT_SUBCATEGORY_SUIT_COATS "Coats"
#define LOADOUT_SUBCATEGORY_SUIT_JACKETS "Jackets"
#define LOADOUT_SUBCATEGORY_SUIT_JOBS "Jobs"
//head
#define LOADOUT_CATEGORY_HEAD "Head"
#define LOADOUT_SUBCATEGORY_HEAD_GENERAL "General"
#define LOADOUT_SUBCATEGORY_HEAD_JOBS "Jobs"
//shoes
#define LOADOUT_CATEGORY_SHOES "Shoes"
//gloves
#define LOADOUT_CATEGORY_GLOVES "Gloves"
//glasses
#define LOADOUT_CATEGORY_GLASSES "Glasses"
//donator items
#define LOADOUT_CATEGORY_DONATOR "Donator"
+1
View File
@@ -38,6 +38,7 @@
#define LOG_ADMIN_PRIVATE (1 << 14)
#define LOG_ASAY (1 << 15)
#define LOG_VIRUS (1 << 16)
#define LOG_SHUTTLE (1 << 18)
//Individual logging panel pages
#define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK)
+15 -4
View File
@@ -341,10 +341,11 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define COLOUR_PRIORITY_AMOUNT 4 //how many priority levels there are.
//Endgame Results
#define NUKE_MISS_STATION 1
#define NUKE_SYNDICATE_BASE 2
#define STATION_DESTROYED_NUKE 3
#define STATION_EVACUATED 4
#define NUKE_NEAR_MISS 1
#define NUKE_MISS_STATION 2
#define NUKE_SYNDICATE_BASE 3
#define STATION_DESTROYED_NUKE 4
#define STATION_EVACUATED 5
#define BLOB_WIN 8
#define BLOB_NUKE 9
#define BLOB_DESTROYED 10
@@ -434,6 +435,9 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define ION_FILE "ion_laws.json"
#define REDPILL_FILE "redpill.json"
#define PIRATE_NAMES_FILE "pirates.json"
#define FLESH_SCAR_FILE "wounds/flesh_scar_desc.json"
#define BONE_SCAR_FILE "wounds/bone_scar_desc.json"
#define SCAR_LOC_FILE "wounds/scar_loc.json"
//Fullscreen overlay resolution in tiles.
@@ -534,3 +538,10 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define LOOT_RESTRICTION_CKEY 2
#define LOOT_RESTRICTION_MIND_PILE 3 //limited to the current pile.
#define LOOT_RESTRICTION_CKEY_PILE 4 //Idem
//stages of shoe tying-ness
#define SHOES_UNTIED 0
#define SHOES_TIED 1
#define SHOES_KNOTTED 2
#define WANTED_FILE "wanted_message.json"
-3
View File
@@ -1,3 +0,0 @@
// obj/item/dropped
/// dropped() relocated this item, return FALSE for doUnEquip.
#define ITEM_RELOCATED_BY_DROPPED "relocated_by_dropped"
+19 -3
View File
@@ -12,6 +12,8 @@
#define MOVE_INTENT_RUN "run"
//Blood levels
#define BLOOD_VOLUME_MAX_LETHAL 2150
#define BLOOD_VOLUME_EXCESS 2100
#define BLOOD_VOLUME_MAXIMUM 2000
#define BLOOD_VOLUME_SLIME_SPLIT 1120
#define BLOOD_VOLUME_NORMAL 560
@@ -57,6 +59,7 @@
#define BODYPART_NOT_DISABLED 0
#define BODYPART_DISABLED_DAMAGE 1
#define BODYPART_DISABLED_PARALYSIS 2
#define BODYPART_DISABLED_WOUND 3
#define DEFAULT_BODYPART_ICON 'icons/mob/human_parts.dmi'
#define DEFAULT_BODYPART_ICON_ORGANIC 'icons/mob/human_parts_greyscale.dmi'
@@ -103,12 +106,14 @@
#define TRAUMA_RESILIENCE_BASIC 1 //Curable with chems
#define TRAUMA_RESILIENCE_SURGERY 2 //Curable with brain surgery
#define TRAUMA_RESILIENCE_LOBOTOMY 3 //Curable with lobotomy
#define TRAUMA_RESILIENCE_MAGIC 4 //Curable only with magic
#define TRAUMA_RESILIENCE_ABSOLUTE 5 //This is here to stay
#define TRAUMA_RESILIENCE_WOUND 4 //Curable by healing the head wound
#define TRAUMA_RESILIENCE_MAGIC 5 //Curable only with magic
#define TRAUMA_RESILIENCE_ABSOLUTE 6 //This is here to stay
//Limit of traumas for each resilience tier
#define TRAUMA_LIMIT_BASIC 3
#define TRAUMA_LIMIT_SURGERY 2
#define TRAUMA_LIMIT_WOUND 2
#define TRAUMA_LIMIT_LOBOTOMY 3
#define TRAUMA_LIMIT_MAGIC 3
#define TRAUMA_LIMIT_ABSOLUTE INFINITY
@@ -171,6 +176,15 @@
#define DISGUST_LEVEL_VERYGROSS 50
#define DISGUST_LEVEL_GROSS 25
//Charge levels for Ethereals
#define ETHEREAL_CHARGE_NONE 0
#define ETHEREAL_CHARGE_LOWPOWER 20
#define ETHEREAL_CHARGE_NORMAL 50
#define ETHEREAL_CHARGE_ALMOSTFULL 75
#define ETHEREAL_CHARGE_FULL 100
#define ETHEREAL_CHARGE_OVERLOAD 125
#define ETHEREAL_CHARGE_DANGEROUS 150
//Slime evolution threshold. Controls how fast slimes can split/grow
#define SLIME_EVOLUTION_THRESHOLD 10
@@ -279,6 +293,7 @@
#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
#define HUNGER_FACTOR 0.1 //factor at which mob nutrition decreases
#define ETHEREAL_CHARGE_FACTOR 0.08 //factor at which ethereal's charge decreases
#define REAGENTS_METABOLISM 0.4 //How many units of reagent are consumed per tick, by default.
#define REAGENTS_EFFECT_MULTIPLIER (REAGENTS_METABOLISM / 0.4) // By defining the effect multiplier this way, it'll exactly adjust all effects according to how they originally were with the 0.4 metabolism
@@ -305,6 +320,7 @@
#define GRAB_PIXEL_SHIFT_NECK 16
#define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return;
#define INTERACTING_WITH(X, Y) (Y in X.do_afters)
/// Field of vision defines.
#define FOV_90_DEGREES 90
@@ -315,4 +331,4 @@
#define EYE_CONTACT_RANGE 5
/// If you examine the same atom twice in this timeframe, we call examine_more() instead of examine()
#define EXAMINE_MORE_TIME 1 SECONDS
#define EXAMINE_MORE_TIME 1 SECONDS
-1
View File
@@ -63,7 +63,6 @@
#define MOVESPEED_ID_TASED_STATUS "TASED"
#define MOVESPEED_ID_ELECTROSTAFF "ELECTROSTAFF"
#define MOVESPEED_ID_SHOVE "SHOVE"
#define MOVESPEED_ID_FAT "FAT"
#define MOVESPEED_ID_COLD "COLD"
#define MOVESPEED_ID_HUNGRY "HUNGRY"
-1
View File
@@ -8,6 +8,5 @@
GLOBAL_LIST_INIT(blacklisted_pool_reagents, list(
/datum/reagent/toxin/plasma, /datum/reagent/oxygen, /datum/reagent/nitrous_oxide, /datum/reagent/nitrogen, //gases
/datum/reagent/fermi, //blanket fermichem ban sorry. this also covers mkultra, genital enlargers, etc etc.
/datum/reagent/drug/aphrodisiac, /datum/reagent/drug/anaphrodisiac, /datum/reagent/drug/aphrodisiacplus, /datum/reagent/drug/anaphrodisiacplus, //literally asking for prefbreaks
/datum/reagent/consumable/femcum, /datum/reagent/consumable/semen //NO.
))
+2 -4
View File
@@ -6,7 +6,7 @@
#define RUSTG_JOB_ERROR "JOB PANICKED"
#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname)
#define rustg_dmi_create_png(fname,width,height,data) call(RUST_G, "dmi_create_png")(fname,width,height,data)
#define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data)
#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev)
#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev)
@@ -14,14 +14,12 @@
#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format)
/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
// RUST-G defines & procs for HTTP component
#define RUSTG_HTTP_METHOD_GET "get"
#define RUSTG_HTTP_METHOD_POST "post"
#define RUSTG_HTTP_METHOD_PUT "put"
#define RUSTG_HTTP_METHOD_DELETE "delete"
#define RUSTG_HTTP_METHOD_PATCH "patch"
#define RUSTG_HTTP_METHOD_HEAD "head"
#define RUSTG_HTTP_METHOD_POST "post"
#define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers)
#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers)
#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id)
+7
View File
@@ -36,6 +36,8 @@
#define STATUS_EFFECT_REGENERATIVE_CORE /datum/status_effect/regenerative_core //removes damage slowdown while giving a slow regenerating effect
#define STATUS_EFFECT_DETERMINED /datum/status_effect/determined //currently in a combat high from being seriously wounded
/////////////
// DEBUFFS //
/////////////
@@ -107,6 +109,11 @@
#define STATUS_EFFECT_ELECTROSTAFF /datum/status_effect/electrostaff //slows down victim
#define STATUS_EFFECT_LIMP /datum/status_effect/limp //For when you have a busted leg (or two!) and want additional slowdown when walking on that leg
/// shoves inflict this to indicate the next shove while this is in effect should disarm guns
#define STATUS_EFFECT_OFF_BALANCE /datum/status_effect/off_balance
/////////////
// NEUTRAL //
/////////////
+1 -1
View File
@@ -19,7 +19,7 @@
/// Size of EACH left/right border icon for volumetric boxes
#define VOLUMETRIC_STORAGE_BOX_BORDER_SIZE 1
/// Minimum pixels an item must have in volumetric scaled storage UI
#define MINIMUM_PIXELS_PER_ITEM 8
#define MINIMUM_PIXELS_PER_ITEM 16
/// Maximum number of objects that will be allowed to be displayed using the volumetric display system. Arbitrary number to prevent server lockups.
#define MAXIMUM_VOLUMETRIC_ITEMS 256
/// How much padding to give between items
+6 -2
View File
@@ -107,6 +107,7 @@
#define FIRE_PRIORITY_INSTRUMENTS 30
#define FIRE_PRIORITY_FIELDS 30
#define FIRE_PRIOTITY_SMOOTHING 35
#define FIRE_PRIORITY_HUDS 40
#define FIRE_PRIORITY_NETWORKS 40
#define FIRE_PRIORITY_OBJ 40
#define FIRE_PRIORITY_ACID 40
@@ -152,14 +153,17 @@
var/list/po = A.priority_overlays;\
if(LAZYLEN(rm)){\
A.overlays -= rm;\
rm.Cut();\
A.remove_overlays = null;\
}\
if(LAZYLEN(ad)){\
A.overlays |= ad;\
ad.Cut();\
A.add_overlays = null;\
}\
if(LAZYLEN(po)){\
A.overlays |= po;\
}\
else{\
A.priority_overlays = null;\
}\
A.flags_1 &= ~OVERLAY_QUEUED_1;\
}
+28 -4
View File
@@ -1,4 +1,28 @@
#define UI_INTERACTIVE 2 // Green/Interactive
#define UI_UPDATE 1 // Orange/Updates Only
#define UI_DISABLED 0 // Red/Disabled
#define UI_CLOSE -1 // Closed
/// Green eye; fully interactive
#define UI_INTERACTIVE 2
/// Orange eye; updates but is not interactive
#define UI_UPDATE 1
/// Red eye; disabled, does not update
#define UI_DISABLED 0
/// UI Should close
#define UI_CLOSE -1
/// Maximum number of windows that can be suspended/reused
#define TGUI_WINDOW_SOFT_LIMIT 5
/// Maximum number of open windows
#define TGUI_WINDOW_HARD_LIMIT 9
/// Maximum ping timeout allowed to detect zombie windows
#define TGUI_PING_TIMEOUT 4 SECONDS
/// Window does not exist
#define TGUI_WINDOW_CLOSED 0
/// Window was just opened, but is still not ready to be sent data
#define TGUI_WINDOW_LOADING 1
/// Window is free and ready to receive data
#define TGUI_WINDOW_READY 2
/// Get a window id based on the provided pool index
#define TGUI_WINDOW_ID(index) "tgui-window-[index]"
/// Get a pool index of the provided window id
#define TGUI_WINDOW_INDEX(window_id) text2num(copytext(window_id, 13))
+1
View File
@@ -17,6 +17,7 @@
//Glasswork Tools
#define TOOL_BLOW "blowing_rod"
#define TOOL_GLASS_CUT "glasskit"
#define TOOL_BONESET "bonesetter"
// If delay between the start and the end of tool operation is less than MIN_TOOL_SOUND_DELAY,
// tool sound is only played when op is started. If not, it's played twice.
+3 -2
View File
@@ -178,6 +178,7 @@
#define TRAIT_FREERUNNING "freerunning"
#define TRAIT_SKITTISH "skittish"
#define TRAIT_POOR_AIM "poor_aim"
#define TRAIT_INSANE_AIM "insane_aim" //they don't miss. they never miss. it was all part of their immaculate plan.
#define TRAIT_PROSOPAGNOSIA "prosopagnosia"
#define TRAIT_DRUNK_HEALING "drunk_healing"
#define TRAIT_TAGGER "tagger"
@@ -202,7 +203,7 @@
#define TRAIT_NO_ALCOHOL "alcohol_intolerance"
#define TRAIT_MUTATION_STASIS "mutation_stasis" //Prevents processed genetics mutations from processing.
#define TRAIT_FAST_PUMP "fast_pump"
#define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good....
#define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good...
// mobility flag traits
// IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it)
@@ -228,7 +229,7 @@
#define TRAIT_SPRINT_LOCKED "sprint_locked"
//non-mob traits
#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
#define VEHICLE_TRAIT "vehicle" // inherited from riding vehicles
#define INNATE_TRAIT "innate"
+7
View File
@@ -76,6 +76,13 @@
#define VV_HK_ADDCOMPONENT "addcomponent"
#define VV_HK_MODIFY_TRAITS "modtraits"
// /datum/gas_mixture
#define VV_HK_SET_MOLES "set_moles"
#define VV_HK_EMPTY "empty"
#define VV_HK_SET_TEMPERATURE "set_temp"
#define VV_HK_PARSE_GASSTRING "parse_gasstring"
#define VV_HK_SET_VOLUME "set_volume"
// /atom
#define VV_HK_MODIFY_TRANSFORM "atom_transform"
#define VV_HK_ADD_REAGENT "addreagent"
+119
View File
@@ -0,0 +1,119 @@
#define WOUND_DAMAGE_EXPONENT 1.225
/// an attack must do this much damage after armor in order to roll for being a wound (incremental pressure damage need not apply)
#define WOUND_MINIMUM_DAMAGE 5
/// an attack must do this much damage after armor in order to be eliigible to dismember a suitably mushed bodypart
#define DISMEMBER_MINIMUM_DAMAGE 10
/// any damage dealt over this is ignored for damage rolls unless the target has the frail quirk (35^1.4=145)
#define WOUND_MAX_CONSIDERED_DAMAGE 35
#define WOUND_SEVERITY_TRIVIAL 0 // for jokey/meme wounds like stubbed toe, no standard messages/sounds or second winds
#define WOUND_SEVERITY_MODERATE 1
#define WOUND_SEVERITY_SEVERE 2
#define WOUND_SEVERITY_CRITICAL 3
#define WOUND_SEVERITY_LOSS 4 // theoretical total limb loss, like dismemberment for cuts
/// any brute weapon/attack that doesn't have sharpness. rolls for blunt bone wounds
#define WOUND_BLUNT 1
/// any brute weapon/attack with sharpness = SHARP_EDGED. rolls for slash wounds
#define WOUND_SLASH 2
/// any brute weapon/attack with sharpness = SHARP_POINTY. rolls for piercing wounds
#define WOUND_PIERCE 3
/// any concentrated burn attack (lasers really). rolls for burning wounds
#define WOUND_BURN 4
// How much determination reagent to add each time someone gains a new wound in [/datum/wound/proc/second_wind()]
#define WOUND_DETERMINATION_MODERATE 1
#define WOUND_DETERMINATION_SEVERE 2.5
#define WOUND_DETERMINATION_CRITICAL 5
#define WOUND_DETERMINATION_LOSS 7.5
/// the max amount of determination you can have
#define WOUND_DETERMINATION_MAX 10
/// set wound_bonus on an item or attack to this to disable checking wounding for the attack
#define CANT_WOUND -100
// list in order of highest severity to lowest
GLOBAL_LIST_INIT(global_wound_types, list(WOUND_BLUNT = list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate),
WOUND_SLASH = list(/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate),
WOUND_PIERCE = list(/datum/wound/pierce/critical, /datum/wound/pierce/severe, /datum/wound/pierce/moderate),
WOUND_BURN = list(/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate)
))
GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate,
/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate,
/datum/wound/pierce/critical, /datum/wound/pierce/severe, /datum/wound/pierce/moderate,
/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate))
// Thresholds for infection for burn wounds, once infestation hits each threshold, things get steadily worse
/// below this has no ill effects from infection
#define WOUND_INFECTION_MODERATE 4
/// then below here, you ooze some pus and suffer minor tox damage, but nothing serious
#define WOUND_INFECTION_SEVERE 8
/// then below here, your limb occasionally locks up from damage and infection and briefly becomes disabled. Things are getting really bad
#define WOUND_INFECTION_CRITICAL 12
/// below here, your skin is almost entirely falling off and your limb locks up more frequently. You are within a stone's throw of septic paralysis and losing the limb
#define WOUND_INFECTION_SEPTIC 20
// above WOUND_INFECTION_SEPTIC, your limb is completely putrid and you start rolling to lose the entire limb by way of paralyzation. After 3 failed rolls (~4-5% each probably), the limb is paralyzed
/// how quickly sanitization removes infestation and decays per tick
#define WOUND_BURN_SANITIZATION_RATE 0.15
/// how much blood you can lose per tick per slash max. 8 is a LOT of blood for one cut so don't worry about hitting it easily
#define WOUND_SLASH_MAX_BLOODFLOW 8
/// dead people don't bleed, but they can clot! this is the minimum amount of clotting per tick on dead people, so even critical cuts will slowly clot in dead people
#define WOUND_SLASH_DEAD_CLOT_MIN 0.05
/// if we suffer a bone wound to the head that creates brain traumas, the timer for the trauma cycle is +/- by this percent (0-100)
#define WOUND_BONE_HEAD_TIME_VARIANCE 20
// The following are for persistent scar save formats
/// The version number of the scar we're saving
#define SCAR_SAVE_VERS 1
/// The body_zone we're applying to on granting
#define SCAR_SAVE_ZONE 2
/// The description we're loading
#define SCAR_SAVE_DESC 3
/// The precise location we're loading
#define SCAR_SAVE_PRECISE_LOCATION 4
/// The severity the scar had
#define SCAR_SAVE_SEVERITY 5
///how many fields there are above (NOT INCLUDING THIS OBVIOUSLY)
#define SCAR_SAVE_LENGTH 5
// increment this number when you update the persistent scarring format in a way that invalidates previous saved scars (new fields, reordering, etc)
/// saved scars with a version lower than this will be discarded
#define SCAR_CURRENT_VERSION 1
// With the wounds pt. 2 update, general dismemberment now requires 2 things for a limb to be dismemberable (bone only creatures just need the second):
// 1. Skin is mangled: A critical slash or pierce wound on that limb
// 2. Bone is mangled: At least a severe bone wound on that limb
// see [/obj/item/bodypart/proc/get_mangled_state] for more information
#define BODYPART_MANGLED_NONE 0
#define BODYPART_MANGLED_BONE 1
#define BODYPART_MANGLED_FLESH 2
#define BODYPART_MANGLED_BOTH 3
// What kind of biology we have, and what wounds we can suffer, mostly relies on the HAS_FLESH and HAS_BONE species traits on human species
/// golems and androids, cannot suffer any wounds
#define BIO_INORGANIC 0
/// skeletons and plasmemes, can only suffer bone wounds, only needs mangled bone to be able to dismember
#define BIO_JUST_BONE 1
/// nothing right now, maybe slimepeople in the future, can only suffer slashing, piercing, and burn wounds
#define BIO_JUST_FLESH 2
/// standard humanoids, can suffer all wounds, needs mangled bone and flesh to dismember
#define BIO_FLESH_BONE 3
/// If this wound requires having the HAS_FLESH flag for humanoids
#define FLESH_WOUND (1<<0)
/// If this wound requires having the HAS_BONE flag for humanaoids
#define BONE_WOUND (1<<1)
/// If having this wound counts as mangled flesh for dismemberment
#define MANGLES_FLESH (1<<2)
/// If having this wound counts as mangled bone for dismemberment
#define MANGLES_BONE (1<<3)
/// If this wound marks the limb as being allowed to have gauze applied
#define ACCEPTS_GAUZE (1<<4)
+23 -3
View File
@@ -81,6 +81,10 @@
if (CONFIG_GET(flag/log_attack))
WRITE_LOG(GLOB.world_attack_log, "ATTACK: [text]")
/proc/log_wounded(text)
if (CONFIG_GET(flag/log_attack))
WRITE_LOG(GLOB.world_attack_log, "WOUND: [text]")
/proc/log_manifest(ckey, datum/mind/mind,mob/body, latejoin = FALSE)
if (CONFIG_GET(flag/log_manifest))
WRITE_LOG(GLOB.world_manifest_log, "[ckey] \\ [body.real_name] \\ [mind.assigned_role] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]")
@@ -118,6 +122,9 @@
//reusing the PDA option because I really don't think news comments are worth a config option
WRITE_LOG(GLOB.world_pda_log, "COMMENT: [text]")
/proc/log_paper(text)
WRITE_LOG(GLOB.world_paper_log, "PAPER: [text]")
/proc/log_telecomms(text)
if (CONFIG_GET(flag/log_telecomms))
WRITE_LOG(GLOB.world_telecomms_log, "TCOMMS: [text]")
@@ -131,6 +138,10 @@
if (CONFIG_GET(flag/log_vote))
WRITE_LOG(GLOB.world_game_log, "VOTE: [text]")
/proc/log_shuttle(text)
if (CONFIG_GET(flag/log_shuttle))
WRITE_LOG(GLOB.world_shuttle_log, "SHUTTLE: [text]")
/proc/log_craft(text)
if (CONFIG_GET(flag/log_craft))
WRITE_LOG(GLOB.world_crafting_log, "CRAFT: [text]")
@@ -190,9 +201,18 @@
WRITE_LOG(log, "Starting up round ID [GLOB.round_id].\n-------------------------")
/* ui logging */
/proc/log_tgui(text)
WRITE_LOG(GLOB.tgui_log, text)
/proc/log_tgui(user_or_client, text)
var/entry = ""
if(!user_or_client)
entry += "no user"
else if(istype(user_or_client, /mob))
var/mob/user = user_or_client
entry += "[user.ckey] (as [user])"
else if(istype(user_or_client, /client))
var/client/client = user_or_client
entry += "[client.ckey]"
entry += ":\n[text]"
WRITE_LOG(GLOB.tgui_log, entry)
/* Close open log handles. This should be called as late as possible, and no logging should hapen after. */
/proc/shutdown_logging()
+1
View File
@@ -1,4 +1,5 @@
#define pick_list(FILE, KEY) (pick(strings(FILE, KEY)))
#define pick_list_weighted(FILE, KEY) (pickweight(strings(FILE, KEY)))
#define pick_list_replacements(FILE, KEY) (strings_replacement(FILE, KEY))
#define json_load(FILE) (json_decode(file2text(FILE)))
+17 -6
View File
@@ -85,9 +85,6 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B)
return A.totalResistance() - B.totalResistance()
/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))
@@ -97,9 +94,6 @@ GLOBAL_VAR_INIT(cmp_field, "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)
/proc/cmp_reagents_asc(datum/reagent/a, datum/reagent/b)
return sorttext(initial(b.name),initial(a.name))
/proc/cmp_quirk_asc(datum/quirk/A, datum/quirk/B)
var/a_sign = num2sign(initial(A.value) * -1)
var/b_sign = num2sign(initial(B.value) * -1)
@@ -125,3 +119,20 @@ GLOBAL_VAR_INIT(cmp_field, "name")
if(A.ui_category == B.ui_category)
return sorttext(A.name, B.name)
return sorttext(A.ui_category, B.ui_category)
/proc/cmp_chemical_reactions_default(datum/chemical_reaction/A, datum/chemical_reaction/B)
if(A.priority != B.priority)
return B.priority - A.priority
else if(A.is_cold_recipe)
return A.required_temp - B.required_temp //return coldest
else
return B.required_temp - A.required_temp //return hottest
/proc/cmp_job_display_asc(datum/job/A, datum/job/B)
return A.display_order - B.display_order
/proc/cmp_reagents_asc(datum/reagent/a, datum/reagent/b)
return sorttext(initial(b.name),initial(a.name))
/proc/cmp_typepaths_asc(A, B)
return sorttext("[B]","[A]")
+2 -1
View File
@@ -5,8 +5,9 @@
#define GET_INITIALIZED_MUTATION(A) GLOB.all_mutations[A]
#define GET_GENE_STRING(A, B) (B.mutation_index[A])
#define GET_SEQUENCE(A) (GLOB.full_sequences[A])
#define GET_MUTATION_TYPE_FROM_ALIAS(A) (GLOB.alias_mutations[A])
#define GET_MUTATION_STABILIZER(A) ((A.stabilizer_coeff < 0) ? 1 : A.stabilizer_coeff)
#define GET_MUTATION_SYNCHRONIZER(A) ((A.synchronizer_coeff < 0) ? 1 : A.synchronizer_coeff)
#define GET_MUTATION_POWER(A) ((A.power_coeff < 0) ? 1 : A.power_coeff)
#define GET_MUTATION_ENERGY(A) ((A.energy_coeff < 0) ? 1 : A.energy_coeff)
#define GET_MUTATION_ENERGY(A) ((A.energy_coeff < 0) ? 1 : A.energy_coeff)
+37 -3
View File
@@ -166,6 +166,9 @@
var/target_loc = target.loc
LAZYADD(user.do_afters, target)
LAZYADD(target.targeted_by, user)
var/holding = user.get_active_held_item()
var/datum/progressbar/progbar
if (progress)
@@ -183,6 +186,13 @@
break
if(uninterruptible)
continue
if(!(target in user.do_afters))
. = FALSE
break
if(!(target in user.do_afters))
. = FALSE
break
if(drifting && !user.inertia_dir)
drifting = 0
@@ -191,13 +201,16 @@
if((!drifting && user.loc != user_loc) || target.loc != target_loc || (!ignorehelditem && user.get_active_held_item() != holding) || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke()))
. = 0
break
if (progress)
if(progress)
qdel(progbar)
if(!QDELETED(target))
LAZYREMOVE(user.do_afters, target)
LAZYREMOVE(target.targeted_by, user)
//some additional checks as a callback for for do_afters that want to break on losing health or on the mob taking action
/mob/proc/break_do_after_checks(list/checked_health, check_clicks)
if(check_clicks && next_move > world.time)
if(check_clicks && !CheckActionCooldown())
return FALSE
return TRUE
@@ -216,6 +229,10 @@
if(target && !isturf(target))
Tloc = target.loc
if(target)
LAZYADD(user.do_afters, target)
LAZYADD(target.targeted_by, user)
var/atom/Uloc = user.loc
var/drifting = 0
@@ -260,6 +277,10 @@
. = 0
break
if(target && !(target in user.do_afters))
. = FALSE
break
if(needhand)
//This might seem like an odd check, but you can still need a hand even when it's empty
//i.e the hand is used to pull some item/tool out of the construction
@@ -270,8 +291,14 @@
if(user.get_active_held_item() != holding)
. = 0
break
if (progress)
if(progress)
qdel(progbar)
if(!QDELETED(target))
LAZYREMOVE(user.do_afters, target)
if(!QDELETED(target))
LAZYREMOVE(user.do_afters, target)
LAZYREMOVE(target.targeted_by, user)
/mob/proc/do_after_coefficent() // This gets added to the delay on a do_after, default 1
. = 1
@@ -291,6 +318,8 @@
var/list/originalloc = list()
for(var/atom/target in targets)
originalloc[target] = target.loc
LAZYADD(user.do_afters, target)
LAZYADD(target.targeted_by, user)
var/holding = user.get_active_held_item()
var/datum/progressbar/progbar
@@ -321,3 +350,8 @@
break mainloop
if(progbar)
qdel(progbar)
for(var/thing in targets)
var/atom/target = thing
if(!QDELETED(target))
LAZYREMOVE(user.do_afters, target)
LAZYREMOVE(target.targeted_by, user)
+21
View File
@@ -53,6 +53,27 @@
for(var/I in adjacent_turfs)
. |= get_area(I)
/**
* Get a bounding box of a list of atoms.
*
* Arguments:
* - atoms - List of atoms. Can accept output of view() and range() procs.
*
* Returns: list(x1, y1, x2, y2)
*/
/proc/get_bbox_of_atoms(list/atoms)
var/list/list_x = list()
var/list/list_y = list()
for(var/_a in atoms)
var/atom/a = _a
list_x += a.x
list_y += a.y
return list(
min(list_x),
min(list_y),
max(list_x),
max(list_y))
// Like view but bypasses luminosity check
/proc/get_hear(range, atom/source)
-22
View File
@@ -90,7 +90,6 @@
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
INVOKE_ASYNC(GLOBAL_PROC, /proc/init_ref_coin_values) //so the current procedure doesn't sleep because of UNTIL()
INVOKE_ASYNC(GLOBAL_PROC, /proc/setupGenetics)
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
@@ -117,24 +116,3 @@
GLOB.coin_values[path] = C.value
qdel(C)
/proc/setupGenetics()
var/list/mutations = subtypesof(/datum/mutation/human)
shuffle_inplace(mutations)
for(var/A in subtypesof(/datum/generecipe))
var/datum/generecipe/GR = A
GLOB.mutation_recipes[initial(GR.required)] = initial(GR.result)
for(var/i in 1 to LAZYLEN(mutations))
var/path = mutations[i] //byond gets pissy when we do it in one line
var/datum/mutation/human/B = new path ()
B.alias = "Mutation #[i]"
GLOB.all_mutations[B.type] = B
GLOB.full_sequences[B.type] = generate_gene_sequence(B.blocks)
if(B.locked)
continue
if(B.quality == POSITIVE)
GLOB.good_mutations |= B
else if(B.quality == NEGATIVE)
GLOB.bad_mutations |= B
else if(B.quality == MINOR_NEGATIVE)
GLOB.not_good_mutations |= B
CHECK_TICK
+10 -3
View File
@@ -145,9 +145,9 @@
continue
if(!S.ckeys_allowed)
snowflake_ipc_antenna_list[S.name] = mspath
var/color1 = random_short_color()
var/color2 = random_short_color()
var/color3 = random_short_color()
var/color1 = random_color()
var/color2 = random_color()
var/color3 = random_color()
var/body_model = MALE
switch(intended_gender)
@@ -264,6 +264,13 @@
if(!findname(.))
break
/proc/random_unique_ethereal_name(attempts_to_find_unique_name=10)
for(var/i in 1 to attempts_to_find_unique_name)
. = capitalize(ethereal_name())
if(!findname(.))
break
/proc/random_unique_moth_name(attempts_to_find_unique_name=10)
for(var/i in 1 to attempts_to_find_unique_name)
. = capitalize(pick(GLOB.moth_first)) + " " + capitalize(pick(GLOB.moth_last))
+6
View File
@@ -4,6 +4,12 @@
else
return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
/proc/ethereal_name()
var/tempname = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
if(prob(65))
tempname += random_capital_letter()
return tempname
/proc/plasmaman_name()
return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
+96 -25
View File
@@ -51,40 +51,111 @@
return default
return default
/proc/sanitize_hexcolor(color, desired_format=3, include_crunch=0, default)
#define RGB_FORMAT_INVALID 0
#define RGB_FORMAT_SHORT 1
#define RGB_FORMAT_LONG 2
/**
* Sanitizes a hexadecimal color. Always outputs lowercase.
*
* @params
* * color - input color, 3 or 6 characters without the #.
* * desired_format - 3 or 6 characters without the potential #. can only put in 3 or 6 here.
* * include_crunch - do we put a # at the start
* * default - default color. must be 3 or 6 characters with or without #.
* * default_replacement - what we replace broken letters with.
*/
/proc/sanitize_hexcolor(color, desired_format = 3, include_crunch = 0, default = rgb(218, 72, 255), default_replacement = "f")
if(!istext(default) || (length(default) < 3))
CRASH("Default should be a text string of RGB format, with or without the crunch, 3 or 6 characters. Default was instead [default]")
if(!istext(default_replacement) || (length(default_replacement) != 1))
CRASH("Invalid default_replacement: [default_replacement]")
default_replacement = lowertext(default_replacement)
switch(text2ascii(default_replacement))
if(48 to 57)
if(97 to 102)
if(65 to 70)
else // yeah yeah i know 3 empty if's..
CRASH("Invalid default_replacement: [default_replacement]")
var/crunch = include_crunch ? "#" : ""
if(!istext(color))
color = ""
color = default
var/start = 1 + (text2ascii(color, 1) == 35)
var/len = length(color)
var/char = ""
// RRGGBB -> RGB but awful
var/convert_to_shorthand = desired_format == 3 && length_char(color) > 3
// get rid of crunch
if(len && color[1] == "#")
if(len >= 2)
color = copytext(color, 2)
else
color = ""
len = length(color)
. = ""
var/i = start
while(i <= len)
switch(desired_format)
if(3)
desired_format = RGB_FORMAT_SHORT
if(6)
desired_format = RGB_FORMAT_LONG
else
CRASH("Invalid desired_format: [desired_format]. Must be 3 or 6.")
var/current_format = RGB_FORMAT_INVALID
switch(length(color))
if(3)
current_format = RGB_FORMAT_SHORT
if(6)
current_format = RGB_FORMAT_LONG
else
current_format = RGB_FORMAT_INVALID
if(current_format == RGB_FORMAT_INVALID) // nah
color = default // process default
if(color[1] == "#") // we checked default was at least 3 chars long earlier
color = copytext(color, 2)
len = length(color)
switch(len)
if(3)
current_format = RGB_FORMAT_SHORT
if(6)
current_format = RGB_FORMAT_LONG
else
CRASH("Default was not 3 or 6 RGB hexadecimal characters: [default]")
var/sanitized = ""
var/char = ""
// first, sanitize hex
for(var/i in 1 to len)
char = color[i]
switch(text2ascii(char))
if(48 to 57) //numbers 0 to 9
. += char
if(97 to 102) //letters a to f
. += char
if(65 to 70) //letters A to F
. += lowertext(char)
if(48 to 57) // 0 to 9
sanitized += char
if(97 to 102) // a to f
sanitized += char
if(65 to 70) // A to F (capitalized!)
sanitized += lowertext(char)
else
break
i += length(char)
if(convert_to_shorthand && i <= len) //skip next one
i += length(color[i])
sanitized += default_replacement
// do we need to convert?
if(desired_format == current_format)
return crunch + sanitized // no
// yes
if((desired_format == RGB_FORMAT_SHORT) && (current_format == RGB_FORMAT_LONG)) // downconvert
var/temp = ""
// we could do some math but we're lazy and in practice floor()ing this.
for(var/i in 1 to 6 step 2)
temp += sanitized[i]
sanitized = temp
else if((desired_format == RGB_FORMAT_LONG) && (current_format == RGB_FORMAT_SHORT)) // upconvert
var/temp = ""
for(var/i in 1 to 3)
temp += sanitized[i]
temp += sanitized[i]
sanitized = temp
else
CRASH("Invalid desired_format and current_format pair: [desired_format], [current_format]. Could not determine which way to convert.")
return crunch + sanitized
if(length_char(.) != desired_format)
if(default)
return default
return crunch + repeat_string(desired_format, "0")
return crunch + .
#undef RGB_FORMAT_INVALID
#undef RGB_FORMAT_SHORT
#undef RGB_FORMAT_LONG
/proc/sanitize_ooccolor(color)
if(length(color) != length_char(color))
+21 -1
View File
@@ -113,6 +113,22 @@
else
return trim(html_encode(name), max_length)
/**
* stripped_multiline_input but reflects to the user instead if it's too big and returns null.
*/
/proc/stripped_multiline_input_or_reflect(mob/user, message = "", title = "", default = "", max_length=MAX_MESSAGE_LEN, no_trim=FALSE)
var/name = input(user, message, title, default) as message|null
if(isnull(name)) // Return null if canceled.
return null
if(length(name) > max_length)
to_chat(user, name)
to_chat(user, "<span class='danger'>^^^----- The preceeding message has been DISCARDED for being over the maximum length of [max_length]. It has NOT been sent! -----^^^</span>")
return null
if(no_trim)
return copytext(html_encode(name), 1, max_length)
else
return trim(html_encode(name), max_length)
#define NO_CHARS_DETECTED 0
#define SPACES_DETECTED 1
#define SYMBOLS_DETECTED 2
@@ -760,6 +776,10 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
else
return "[number]\th"
/proc/random_capital_letter()
return uppertext(pick(GLOB.alphabet))
/proc/unintelligize(message)
var/regex/word_boundaries = regex(@"\b[\S]+\b", "g")
var/prefix = message[1]
@@ -811,4 +831,4 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
corrupted_text += pick(corruption_options)
if(prob(15))
corrupted_text += pick(corruption_options)
return corrupted_text
return corrupted_text
+16 -2
View File
@@ -339,10 +339,24 @@
/proc/isLeap(y)
return ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
/// For finding out what body parts a body zone covers, the inverse of the below basically
/proc/zone2body_parts_covered(def_zone)
switch(def_zone)
if(BODY_ZONE_CHEST)
return list(CHEST, GROIN)
if(BODY_ZONE_HEAD)
return list(HEAD)
if(BODY_ZONE_L_ARM)
return list(ARM_LEFT, HAND_LEFT)
if(BODY_ZONE_R_ARM)
return list(ARM_RIGHT, HAND_RIGHT)
if(BODY_ZONE_L_LEG)
return list(LEG_LEFT, FOOT_LEFT)
if(BODY_ZONE_R_LEG)
return list(LEG_RIGHT, FOOT_RIGHT)
//Turns a Body_parts_covered bitfield into a list of organ/limb names.
//(I challenge you to find a use for this)
//(I challenge you to find a use for this) -I found a use for it!!
/proc/body_parts_covered2organ_names(bpc)
var/list/covered_parts = list()
+2 -1
View File
@@ -1437,7 +1437,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
/obj/item/reagent_containers/food/snacks/grown,
/obj/item/reagent_containers/food/snacks/grown/mushroom,
/obj/item/reagent_containers/food/snacks/grown/nettle, // base type
/obj/item/reagent_containers/food/snacks/deepfryholder,
/obj/item/reagent_containers/food/snacks/grown/shell,
/obj/item/reagent_containers/food/snacks/clothing,
/obj/item/reagent_containers/food/snacks/store/bread
@@ -1509,6 +1508,8 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
set waitfor = FALSE
return call(source, proctype)(arglist(arguments))
#define TURF_FROM_COORDS_LIST(List) (locate(List[1], List[2], List[3]))
/proc/num2sign(numeric)
if(numeric > 0)
return 1
+2 -1
View File
@@ -27,5 +27,6 @@ GLOBAL_LIST_EMPTY(full_sequences)
GLOBAL_LIST_EMPTY(bad_mutations)
GLOBAL_LIST_EMPTY(good_mutations)
GLOBAL_LIST_EMPTY(not_good_mutations)
GLOBAL_LIST_EMPTY(alias_mutations) //alias = type
GLOBAL_LIST_EMPTY(mutation_recipes)
GLOBAL_LIST_EMPTY(mutation_recipes)
+7 -6
View File
@@ -116,15 +116,16 @@ GLOBAL_LIST_INIT(ai_core_display_screens, list(
GLOBAL_LIST_INIT(security_depts_prefs, list(SEC_DEPT_RANDOM, SEC_DEPT_NONE, SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
//Backpacks
#define GBACKPACK "Grey Backpack"
#define GSATCHEL "Grey Satchel"
#define GDUFFELBAG "Grey Duffel Bag"
#define LSATCHEL "Leather Satchel"
//Backpacks
#define DBACKPACK "Department Backpack"
#define DSATCHEL "Department Satchel"
#define DDUFFELBAG "Department Duffel Bag"
GLOBAL_LIST_INIT(backbaglist, list(DBACKPACK, DSATCHEL, DDUFFELBAG, GBACKPACK, GSATCHEL, GDUFFELBAG, LSATCHEL))
GLOBAL_LIST_INIT(backbaglist, list(DBACKPACK, DSATCHEL, DDUFFELBAG, //everything after this point is a non-department backpack
"Grey Backpack" = /obj/item/storage/backpack,
"Grey Satchel" = /obj/item/storage/backpack/satchel,
"Grey Duffel Bag" = /obj/item/storage/backpack/duffelbag,
"Leather Satchel" = /obj/item/storage/backpack/satchel/leather,
"Snail Shell" = /obj/item/storage/backpack/snail))
//Suit/Skirt
#define PREF_SUIT "Jumpsuit"
@@ -0,0 +1,13 @@
GLOBAL_LIST_INIT(loadout_categories, list(
LOADOUT_CATEGORY_BACKPACK = list(LOADOUT_SUBCATEGORY_BACKPACK_GENERAL, LOADOUT_SUBCATEGORY_BACKPACK_TOYS),
LOADOUT_CATEGORY_NECK = list(LOADOUT_SUBCATEGORY_NECK_GENERAL, LOADOUT_SUBCATEGORY_NECK_TIE, LOADOUT_SUBCATEGORY_NECK_SCARVES),
LOADOUT_CATEGORY_MASK = LOADOUT_SUBCATEGORIES_NONE,
LOADOUT_CATEGORY_HANDS = LOADOUT_SUBCATEGORIES_NONE,
LOADOUT_CATEGORY_UNIFORM = list(LOADOUT_SUBCATEGORY_UNIFORM_GENERAL, LOADOUT_SUBCATEGORY_UNIFORM_JOBS, LOADOUT_SUBCATEGORY_UNIFORM_SUITS, LOADOUT_SUBCATEGORY_UNIFORM_SKIRTS, LOADOUT_SUBCATEGORY_UNIFORM_DRESSES, LOADOUT_SUBCATEGORY_UNIFORM_SWEATERS, LOADOUT_SUBCATEGORY_UNIFORM_PANTS, LOADOUT_SUBCATEGORY_UNIFORM_SHORTS),
LOADOUT_CATEGORY_SUIT = list(LOADOUT_SUBCATEGORY_SUIT_GENERAL, LOADOUT_SUBCATEGORY_SUIT_COATS, LOADOUT_SUBCATEGORY_SUIT_JACKETS, LOADOUT_SUBCATEGORY_SUIT_JOBS),
LOADOUT_CATEGORY_HEAD = list(LOADOUT_SUBCATEGORY_HEAD_GENERAL, LOADOUT_SUBCATEGORY_HEAD_JOBS),
LOADOUT_CATEGORY_SHOES = LOADOUT_SUBCATEGORIES_NONE,
LOADOUT_CATEGORY_GLOVES = LOADOUT_SUBCATEGORIES_NONE,
LOADOUT_CATEGORY_GLASSES = LOADOUT_SUBCATEGORIES_NONE,
LOADOUT_CATEGORY_DONATOR = LOADOUT_SUBCATEGORIES_NONE
))
+1 -2
View File
@@ -38,8 +38,7 @@ GLOBAL_LIST_EMPTY(servant_spawns) //Servants of Ratvar spawn here
GLOBAL_LIST_EMPTY(city_of_cogs_spawns) //Anyone entering the City of Cogs spawns here
GLOBAL_LIST_EMPTY(ruin_landmarks)
//away missions
GLOBAL_LIST_EMPTY(awaydestinations) //a list of landmarks that the warpgate can take you to
//away missions
GLOBAL_LIST_EMPTY(vr_spawnpoints)
//used by jump-to-area etc. Updated by area/updateName()
+1
View File
@@ -23,6 +23,7 @@ GLOBAL_LIST_EMPTY(joined_player_list) //all clients that have joined the game a
GLOBAL_LIST_EMPTY(silicon_mobs) //all silicon mobs
GLOBAL_LIST_EMPTY(mob_living_list) //all instances of /mob/living and subtypes
GLOBAL_LIST_EMPTY(carbon_list) //all instances of /mob/living/carbon and subtypes, notably does not contain brains or simple animals
GLOBAL_LIST_EMPTY(human_list) //all instances of /mob/living/carbon/human and subtypes
GLOBAL_LIST_EMPTY(ai_list)
GLOBAL_LIST_EMPTY(pai_list)
GLOBAL_LIST_EMPTY(available_ai_shells)
+1
View File
@@ -17,6 +17,7 @@ GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt"))
GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt"))
GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt"))
GLOBAL_LIST_INIT(plasmaman_names, world.file2list("strings/names/plasmaman.txt"))
GLOBAL_LIST_INIT(ethereal_names, world.file2list("strings/names/ethereal.txt"))
GLOBAL_LIST_INIT(posibrain_names, world.file2list("strings/names/posibrain.txt"))
GLOBAL_LIST_INIT(nightmare_names, world.file2list("strings/names/nightmare.txt"))
GLOBAL_LIST_INIT(megacarp_first_names, world.file2list("strings/names/megacarp1.txt"))
+4 -2
View File
@@ -32,6 +32,8 @@ GLOBAL_VAR(world_asset_log)
GLOBAL_PROTECT(world_asset_log)
GLOBAL_VAR(world_map_error_log)
GLOBAL_PROTECT(world_map_error_log)
GLOBAL_VAR(world_paper_log)
GLOBAL_PROTECT(world_paper_log)
GLOBAL_VAR(subsystem_log)
GLOBAL_PROTECT(subsystem_log)
GLOBAL_VAR(reagent_log)
@@ -49,10 +51,10 @@ GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src]
GLOBAL_PROTECT(lastsignalers)
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
GLOBAL_PROTECT(lawchanges)
GLOBAL_VAR(tgui_log)
GLOBAL_PROTECT(tgui_log)
GLOBAL_VAR(world_shuttle_log)
GLOBAL_PROTECT(world_shuttle_log)
GLOBAL_LIST_EMPTY(combatlog)
GLOBAL_PROTECT(combatlog)
GLOBAL_LIST_EMPTY(IClog)
+6 -9
View File
@@ -19,10 +19,6 @@
A.move_camera_by_click()
/mob/living/silicon/ai/ClickOn(var/atom/A, params)
if(world.time <= next_click)
return
next_click = world.time + 1
if(!can_interact_with(A))
return
@@ -74,16 +70,16 @@
CtrlClickOn(A)
return
if(world.time <= next_move)
if(!CheckActionCooldown(immediate = TRUE))
return
if(aicamera.in_camera_mode)
aicamera.camera_mode_off()
aicamera.captureimage(pixel_turf, usr)
INVOKE_ASYNC(aicamera, /obj/item/camera.proc/captureimage, pixel_turf, usr)
return
if(waypoint_mode)
waypoint_mode = 0
set_waypoint(A)
waypoint_mode = FALSE
INVOKE_ASYNC(src, .proc/set_waypoint, A)
return
A.attack_ai(src)
@@ -94,8 +90,9 @@
The below is only really for safety, or you can alter the way
it functions and re-insert it above.
*/
/mob/living/silicon/ai/UnarmedAttack(atom/A)
/mob/living/silicon/ai/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_ai(src)
/mob/living/silicon/ai/RangedAttack(atom/A)
A.attack_ai(src)
+56 -92
View File
@@ -1,38 +1,3 @@
/*
Click code cleanup
~Sayu
*/
// 1 decisecond click delay (above and beyond mob/next_move)
//This is mainly modified by click code, to modify click delays elsewhere, use next_move and changeNext_move()
/mob/var/next_click = 0
// THESE DO NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
/mob/var/next_move_adjust = 0 //Amount to adjust action/click delays by, + or -
/mob/var/next_move_modifier = 1 //Value to multiply action/click delays by
//Delays the mob's next click/action by num deciseconds
// eg: 10-3 = 7 deciseconds of delay
// eg: 10*0.5 = 5 deciseconds of delay
// DOES NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
/mob/proc/timeToNextMove()
return max(0, next_move - world.time)
/mob/proc/changeNext_move(num)
next_move = world.time + ((num+next_move_adjust)*next_move_modifier)
/mob/living/changeNext_move(num)
last_click_move = next_move
var/mod = next_move_modifier
var/adj = next_move_adjust
for(var/i in status_effects)
var/datum/status_effect/S = i
mod *= S.nextmove_modifier()
adj += S.nextmove_adjust()
next_move = world.time + ((num + adj)*mod)
/*
Before anything else, defer these calls to a per-mobtype handler. This allows us to
remove istype() spaghetti code, but requires the addition of other handler procs to simplify it.
@@ -45,7 +10,7 @@
/atom/Click(location,control,params)
if(flags_1 & INITIALIZED_1)
SEND_SIGNAL(src, COMSIG_CLICK, location, control, params, usr)
usr.ClickOn(src, params)
usr.CommonClickOn(src, params)
/atom/DblClick(location,control,params)
if(flags_1 & INITIALIZED_1)
@@ -55,6 +20,21 @@
if(flags_1 & INITIALIZED_1)
usr.MouseWheelOn(src, delta_x, delta_y, params)
/**
* Common mob click code
*/
/mob/proc/CommonClickOn(atom/A, params)
SHOULD_NOT_SLEEP(TRUE)
if(mob_transforming)
return
if(SEND_SIGNAL(src, COMSIG_MOB_CLICKON, A, params) & COMSIG_MOB_CANCEL_CLICKON)
return
. = ClickOn(A, params)
if(!(. & DISCARD_LAST_ACTION))
FlushCurrentAction()
else
DiscardCurrentAction()
/*
Standard mob ClickOn()
Handles exceptions: Buildmode, middle click, modified clicks, mech actions
@@ -68,50 +48,34 @@
* item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent
* mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed
*/
/mob/proc/ClickOn( atom/A, params )
if(world.time <= next_click)
return
next_click = world.time + world.tick_lag
/mob/proc/ClickOn(atom/A, params)
SHOULD_NOT_SLEEP(TRUE)
if(check_click_intercept(params,A))
return
if(mob_transforming)
return
if(SEND_SIGNAL(src, COMSIG_MOB_CLICKON, A, params) & COMSIG_MOB_CANCEL_CLICKON)
return
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["middle"])
ShiftMiddleClickOn(A)
return
return ShiftMiddleClickOn(A)
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
return
return CtrlShiftClickOn(A)
if(modifiers["middle"])
MiddleClickOn(A)
return
return MiddleClickOn(A)
if(modifiers["shift"] && (client && client.show_popup_menus || modifiers["right"])) //CIT CHANGE - makes shift-click examine use right click instead of left click in combat mode
ShiftClickOn(A)
return
return ShiftClickOn(A)
if(modifiers["alt"]) // alt and alt-gr (rightalt)
AltClickOn(A)
return
return AltClickOn(A)
if(modifiers["ctrl"])
CtrlClickOn(A)
return
return CtrlClickOn(A)
if(modifiers["right"]) //CIT CHANGE - allows right clicking to perform actions
RightClickOn(A,params) //CIT CHANGE - ditto
return //CIT CHANGE - ditto
return RightClickOn(A, params) //CIT CHANGE - ditto
if(incapacitated(ignore_restraints = 1))
return
face_atom(A)
if(next_move > world.time) // in the year 2000...
if(!CheckActionCooldown(immediate = TRUE))
return
if(!modifiers["catcher"] && A.IsObscured())
@@ -119,12 +83,12 @@
if(ismecha(loc))
var/obj/mecha/M = loc
return M.click_action(A,src,params)
M.click_action(A,src,params)
return TRUE
if(restrained())
changeNext_move(CLICK_CD_HANDCUFFED) //Doing shit in cuffs shall be vey slow
RestrainedClickOn(A)
return
DelayNextAction(CLICK_CD_HANDCUFFED)
return RestrainedClickOn(A)
if(in_throw_mode)
throw_item(A)
@@ -141,12 +105,12 @@
//User itself, current loc, and user inventory
if(A in DirectAccess())
if(W)
W.melee_attack_chain(src, A, params)
return W.melee_attack_chain(src, A, params)
else
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
UnarmedAttack(A)
return
. = UnarmedAttack(A, TRUE, a_intent)
if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
DelayNextAction(CLICK_CD_MELEE)
return
//Can't reach anything else in lockers or other weirdness
if(!loc.AllowClick())
@@ -155,16 +119,17 @@
//Standard reach turf to turf or reaching inside storage
if(CanReach(A,W))
if(W)
W.melee_attack_chain(src, A, params)
return W.melee_attack_chain(src, A, params)
else
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
UnarmedAttack(A, 1)
. = UnarmedAttack(A, TRUE, a_intent)
if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
DelayNextAction(CLICK_CD_MELEE)
return
else
if(W)
W.ranged_attack_chain(src, A, params)
return W.ranged_attack_chain(src, A, params)
else
RangedAttack(A,params)
return RangedAttack(A,params)
//Is the atom obscured by a PREVENT_CLICK_UNDER_1 object above it
/atom/proc/IsObscured()
@@ -269,10 +234,7 @@
proximity_flag is not currently passed to attack_hand, and is instead used
in human click code to allow glove touches only at melee range.
*/
/mob/proc/UnarmedAttack(atom/A, proximity_flag)
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
return
/mob/proc/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
/*
Ranged unarmed attack:
@@ -305,7 +267,6 @@
var/datum/antagonist/changeling/C = mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.chosen_sting)
C.chosen_sting.try_to_sting(src,A)
next_click = world.time + 5
return
swap_hand()
@@ -338,24 +299,24 @@
*/
/mob/proc/CtrlClickOn(atom/A)
A.CtrlClick(src)
return
return A.CtrlClick(src)
/atom/proc/CtrlClick(mob/user)
SEND_SIGNAL(src, COMSIG_CLICK_CTRL, user)
var/mob/living/ML = user
if(istype(ML))
ML.pulled(src)
INVOKE_ASYNC(ML, /mob/living.verb/pulled, src)
/mob/living/carbon/human/CtrlClick(mob/user)
if(ishuman(user) && Adjacent(user) && !user.incapacitated())
if(world.time < user.next_move)
if(!user.CheckActionCooldown())
return FALSE
var/mob/living/carbon/human/H = user
H.dna.species.grab(H, src, H.mind.martial_art)
H.changeNext_move(CLICK_CD_MELEE)
H.DelayNextAction(CLICK_CD_MELEE)
return TRUE
else
..()
return ..()
/*
Alt click
Unused except for AI
@@ -378,8 +339,8 @@
var/datum/antagonist/changeling/C = mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.chosen_sting)
C.chosen_sting.try_to_sting(src,A)
next_click = world.time + 5
return
DelayNextAction(CLICK_CD_RANGE)
return TRUE
..()
/atom/proc/AltClick(mob/user)
@@ -414,9 +375,11 @@
return
/mob/living/LaserEyes(atom/A, params)
changeNext_move(CLICK_CD_RANGE)
if(!CheckActionCooldown(CLICK_CD_RANGE))
return
DelayNextAction()
var/obj/item/projectile/beam/LE = new /obj/item/projectile/beam( loc )
var/obj/item/projectile/beam/LE = new /obj/item/projectile/beam(loc)
LE.icon = 'icons/effects/genetics.dmi'
LE.icon_state = "eyelasers"
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
@@ -425,6 +388,7 @@
LE.def_zone = get_organ_target()
LE.preparePixelProjectile(A, src, params)
LE.fire()
return TRUE
// Simple helper to face what you clicked on, in case it should be needed in more than one place
/mob/proc/face_atom(atom/A, ismousemovement = FALSE)
+19 -30
View File
@@ -7,10 +7,6 @@
*/
/mob/living/silicon/robot/ClickOn(var/atom/A, var/params)
if(world.time <= next_click)
return
next_click = world.time + 1
if(check_click_intercept(params,A))
return
@@ -19,25 +15,19 @@
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
return
return CtrlShiftClickOn(A)
if(modifiers["shift"] && modifiers["middle"])
ShiftMiddleClickOn(A)
return
return ShiftMiddleClickOn(A)
if(modifiers["middle"])
MiddleClickOn(A)
return
return MiddleClickOn(A)
if(modifiers["shift"])
ShiftClickOn(A)
return
return ShiftClickOn(A)
if(modifiers["alt"]) // alt and alt-gr (rightalt)
AltClickOn(A)
return
return AltClickOn(A)
if(modifiers["ctrl"])
CtrlClickOn(A)
return
return CtrlClickOn(A)
if(next_move >= world.time)
if(!CheckActionCooldown(immediate = TRUE))
return
face_atom(A) // change direction to face what you clicked on
@@ -50,7 +40,7 @@
*/
if(aicamera.in_camera_mode) //Cyborg picture taking
aicamera.camera_mode_off()
aicamera.captureimage(A, usr)
INVOKE_ASYNC(aicamera, /obj/item/camera.proc/captureimage, A, usr)
return
var/obj/item/W = get_active_held_item()
@@ -58,13 +48,8 @@
if(!W && A.Adjacent(src) && (isobj(A) || ismob(A)))
var/atom/movable/C = A
if(C.can_buckle && C.has_buckled_mobs())
if(C.buckled_mobs.len > 1)
var/unbuckled = input(src, "Who do you wish to unbuckle?","Unbuckle Who?") as null|mob in C.buckled_mobs
if(C.user_unbuckle_mob(unbuckled,src))
return
else
if(C.user_unbuckle_mob(C.buckled_mobs[1],src))
return
INVOKE_ASYNC(C, /atom/movable.proc/precise_user_unbuckle_mob, src)
return
if(!W && (get_dist(src,A) <= interaction_range))
A.attack_robot(src)
@@ -81,7 +66,9 @@
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc in contents)
if(A == loc || (A in loc) || (A in contents))
W.melee_attack_chain(src, A, params)
. = W.melee_attack_chain(src, A, params)
if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
DelayNextAction(CLICK_CD_MELEE)
return
if(!isturf(loc))
@@ -90,11 +77,12 @@
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc && isturf(A.loc.loc))
if(isturf(A) || isturf(A.loc))
if(A.Adjacent(src)) // see adjacent.dm
W.melee_attack_chain(src, A, params)
. = W.melee_attack_chain(src, A, params)
if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
DelayNextAction(CLICK_CD_MELEE)
return
else
W.afterattack(A, src, 0, params)
return
return W.afterattack(A, src, 0, params)
//Middle click cycles through selected modules.
/mob/living/silicon/robot/MiddleClickOn(atom/A)
@@ -175,8 +163,9 @@
clicks, you can do so here, but you will have to
change attack_robot() above to the proper function
*/
/mob/living/silicon/robot/UnarmedAttack(atom/A)
/mob/living/silicon/robot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_robot(src)
/mob/living/silicon/robot/RangedAttack(atom/A)
A.attack_robot(src)
+2
View File
@@ -168,6 +168,8 @@
//UI position overrides for 1:1 screen layout. (default is 7:5)
#define ui_stamina "EAST-1:28,CENTER:17" // replacing internals button
#define ui_overridden_resist "EAST-3:24,SOUTH+1:7"
#define ui_clickdelay "CENTER,SOUTH+1:-31"
#define ui_resistdelay "EAST-3:24,SOUTH+1:4"
#define ui_combat_toggle "EAST-4:22,SOUTH:5"
#define ui_boxcraft "EAST-4:22,SOUTH+1:6"
-3
View File
@@ -56,9 +56,6 @@
if(id && usr.client) //try to (un)remember position
usr.client.prefs.action_buttons_screen_locs["[name]_[id]"] = locked ? moved : null
return TRUE
if(usr.next_click > world.time)
return
usr.next_click = world.time + 1
linked_action.Trigger()
return TRUE
+34 -11
View File
@@ -22,7 +22,7 @@
if(alerts[category])
thealert = alerts[category]
if(thealert.override_alerts)
return 0
return thealert
if(new_master && new_master != thealert.master)
WARNING("[src] threw alert [category] with new_master [new_master] while already having that alert with master [thealert.master]")
@@ -36,7 +36,7 @@
clear_alert(category)
return .()
else //no need to update
return 0
return thealert
else
thealert = new type()
thealert.override_alerts = override
@@ -272,7 +272,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
var/mob/living/L = usr
if(!istype(L) || !L.can_resist())
return
L.changeNext_move(CLICK_CD_RESIST)
L.MarkResistTime()
if(CHECK_MOBILITY(L, MOBILITY_MOVE))
return L.resist_fire() //I just want to start a flame in your hearrrrrrtttttt.
@@ -447,8 +447,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
var/time_name
if(G.seconds_until_activation)
time_name = "until the Ark activates"
else if(G.grace_period)
time_name = "of grace period remaining"
else if(G.progress_in_seconds)
time_name = "until the Ark finishes summoning"
if(time_info)
@@ -495,6 +493,16 @@ Recharging stations are available in robotics, the dormitory bathrooms, and the
desc = "Unit's power cell is running low. Recharging stations are available in robotics, the dormitory bathrooms, and the AI satellite."
icon_state = "lowcell"
/obj/screen/alert/etherealcharge
name = "Low Blood Charge"
desc = "Your blood's electric charge is running low, find a source of charge for your blood. Use a recharging station found in robotics or the dormitory bathrooms, or eat some Ethereal-friendly food."
icon_state = "etherealcharge"
/obj/screen/alert/ethereal_overcharge
name = "Blood Overcharge"
desc = "Your blood's electric charge is becoming dangerously high, find an outlet for your energy. Use Grab Intent on an APC to channel your energy into it."
icon_state = "ethereal_overcharge"
//Need to cover all use cases - emag, illegal upgrade module, malf AI hack, traitor cyborg
/obj/screen/alert/hacked
name = "Hacked"
@@ -600,17 +608,32 @@ so as to remain in compliance with the most up-to-date laws."
var/mob/living/L = usr
if(!istype(L) || !L.can_resist())
return
L.changeNext_move(CLICK_CD_RESIST)
if(CHECK_MOBILITY(L, MOBILITY_MOVE) && (L.last_special <= world.time))
return L.resist_restraints()
L.MarkResistTime()
return L.resist_restraints()
/obj/screen/alert/restrained/buckled/Click()
var/mob/living/L = usr
if(!istype(L) || !L.can_resist())
return
L.changeNext_move(CLICK_CD_RESIST)
if(L.last_special <= world.time)
return L.resist_buckle()
L.MarkResistTime()
return L.resist_buckle()
/obj/screen/alert/shoes/untied
name = "Untied Shoes"
desc = "Your shoes are untied! Click the alert or your shoes to tie them."
icon_state = "shoealert"
/obj/screen/alert/shoes/knotted
name = "Knotted Shoes"
desc = "Someone tied your shoelaces together! Click the alert or your shoes to undo the knot."
icon_state = "shoealert"
/obj/screen/alert/shoes/Click()
var/mob/living/carbon/C = usr
if(!istype(C) || !C.can_resist() || C != mob_viewer || !C.shoes)
return
C.MarkResistTime()
C.shoes.handle_tying(C)
// PRIVATE = only edit, use, or override these if you're editing the system as a whole
+45
View File
@@ -0,0 +1,45 @@
/datum/hud/marauder
var/obj/screen/hosthealth
var/obj/screen/blockchance
var/obj/screen/counterchance
/datum/hud/marauder/New(mob/living/simple_animal/hostile/clockwork/marauder/guardian/owner)
..()
var/obj/screen/using
healths = new /obj/screen/healths/clock()
infodisplay += healths
hosthealth = new /obj/screen/healths/clock()
hosthealth.screen_loc = ui_internal
infodisplay += hosthealth
using = new /obj/screen/marauder/emerge()
using.screen_loc = ui_zonesel
static_inventory += using
/datum/hud/marauder/Destroy()
blockchance = null
counterchance = null
hosthealth = null
return ..()
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/create_mob_hud()
if(client && !hud_used)
hud_used = new /datum/hud/marauder(src, ui_style2icon(client.prefs.UI_style))
/obj/screen/marauder
icon = 'icons/mob/clockwork_mobs.dmi'
/obj/screen/marauder/emerge
icon_state = "clockguard_emerge"
name = "Emerge/Return"
desc = "Emerge or Return."
/obj/screen/marauder/emerge/Click()
if(istype(usr, /mob/living/simple_animal/hostile/clockwork/marauder/guardian))
var/mob/living/simple_animal/hostile/clockwork/marauder/guardian/G = usr
if(G.is_in_host())
G.try_emerge()
else
G.return_to_host()
+11
View File
@@ -140,6 +140,17 @@
sprint_buffer.hud = src
static_inventory += sprint_buffer
// clickdelay
clickdelay = new
clickdelay.hud = src
clickdelay.screen_loc = ui_clickdelay
static_inventory += clickdelay
// resistdelay
resistdelay = new
resistdelay.hud = src
resistdelay.screen_loc = ui_resistdelay
static_inventory += resistdelay
using = new /obj/screen/drop()
using.icon = ui_style
+165
View File
@@ -0,0 +1,165 @@
/client
/**
* Assoc list with all the active maps - when a screen obj is added to
* a map, it's put in here as well.
*
* Format: list(<mapname> = list(/obj/screen))
*/
var/list/screen_maps = list()
/**
* A screen object, which acts as a container for turfs and other things
* you want to show on the map, which you usually attach to "vis_contents".
*/
/obj/screen
/**
* Map name assigned to this object.
* Automatically set by /client/proc/add_obj_to_map.
*/
var/assigned_map
/**
* Mark this object as garbage-collectible after you clean the map
* it was registered on.
*
* This could probably be changed to be a proc, for conditional removal.
* But for now, this works.
*/
var/del_on_map_removal = TRUE
/**
* A generic background object.
* It is also implicitly used to allocate a rectangle on the map, which will
* be used for auto-scaling the map.
*/
/obj/screen/background
name = "background"
icon = 'icons/mob/map_backgrounds.dmi'
icon_state = "clear"
layer = GAME_PLANE
plane = GAME_PLANE
/**
* Sets screen_loc of this screen object, in form of point coordinates,
* with optional pixel offset (px, py).
*
* If applicable, "assigned_map" has to be assigned before this proc call.
*/
/obj/screen/proc/set_position(x, y, px = 0, py = 0)
if(assigned_map)
screen_loc = "[assigned_map]:[x]:[px],[y]:[py]"
else
screen_loc = "[x]:[px],[y]:[py]"
/**
* Sets screen_loc to fill a rectangular area of the map.
*
* If applicable, "assigned_map" has to be assigned before this proc call.
*/
/obj/screen/proc/fill_rect(x1, y1, x2, y2)
if(assigned_map)
screen_loc = "[assigned_map]:[x1],[y1] to [x2],[y2]"
else
screen_loc = "[x1],[y1] to [x2],[y2]"
/**
* Registers screen obj with the client, which makes it visible on the
* assigned map, and becomes a part of the assigned map's lifecycle.
*/
/client/proc/register_map_obj(obj/screen/screen_obj)
if(!screen_obj.assigned_map)
CRASH("Can't register [screen_obj] without 'assigned_map' property.")
if(!screen_maps[screen_obj.assigned_map])
screen_maps[screen_obj.assigned_map] = list()
// NOTE: Possibly an expensive operation
var/list/screen_map = screen_maps[screen_obj.assigned_map]
if(!screen_map.Find(screen_obj))
screen_map += screen_obj
if(!screen.Find(screen_obj))
screen += screen_obj
/**
* Clears the map of registered screen objects.
*
* Not really needed most of the time, as the client's screen list gets reset
* on relog. any of the buttons are going to get caught by garbage collection
* anyway. they're effectively qdel'd.
*/
/client/proc/clear_map(map_name)
if(!map_name || !(map_name in screen_maps))
return FALSE
for(var/obj/screen/screen_obj in screen_maps[map_name])
screen_maps[map_name] -= screen_obj
if(screen_obj.del_on_map_removal)
qdel(screen_obj)
screen_maps -= map_name
/**
* Clears all the maps of registered screen objects.
*/
/client/proc/clear_all_maps()
for(var/map_name in screen_maps)
clear_map(map_name)
/**
* Creates a popup window with a basic map element in it, without any
* further initialization.
*
* Ratio is how many pixels by how many pixels (keep it simple).
*
* Returns a map name.
*/
/client/proc/create_popup(name, ratiox = 100, ratioy = 100)
winclone(src, "popupwindow", name)
var/list/winparams = list()
winparams["size"] = "[ratiox]x[ratioy]"
winparams["on-close"] = "handle-popup-close [name]"
winset(src, "[name]", list2params(winparams))
winshow(src, "[name]", 1)
var/list/params = list()
params["parent"] = "[name]"
params["type"] = "map"
params["size"] = "[ratiox]x[ratioy]"
params["anchor1"] = "0,0"
params["anchor2"] = "[ratiox],[ratioy]"
winset(src, "[name]_map", list2params(params))
return "[name]_map"
/**
* Create the popup, and get it ready for generic use by giving
* it a background.
*
* Width and height are multiplied by 64 by default.
*/
/client/proc/setup_popup(popup_name, width = 9, height = 9, \
tilesize = 2, bg_icon)
if(!popup_name)
return
clear_map("[popup_name]_map")
var/x_value = world.icon_size * tilesize * width
var/y_value = world.icon_size * tilesize * height
var/map_name = create_popup(popup_name, x_value, y_value)
var/obj/screen/background/background = new
background.assigned_map = map_name
background.fill_rect(1, 1, width, height)
if(bg_icon)
background.icon_state = bg_icon
register_map_obj(background)
return map_name
/**
* Closes a popup.
*/
/client/proc/close_popup(popup)
winshow(src, popup, 0)
handle_popup_close(popup)
/**
* When the popup closes in any way (player or proc call) it calls this.
*/
/client/verb/handle_popup_close(window_id as text)
set hidden = TRUE
clear_map("[window_id]_map")
+2 -1
View File
@@ -128,7 +128,7 @@
deltimer(C.parallax_animate_timer)
var/datum/callback/CB = CALLBACK(src, .proc/update_parallax_motionblur, C, animatedir, new_parallax_movedir, newtransform)
if(skip_windups)
CB.Invoke()
CB.InvokeAsync()
else
C.parallax_animate_timer = addtimer(CB, min(shortesttimer, PARALLAX_LOOP_TIME), TIMER_CLIENT_TIME|TIMER_STOPPABLE)
@@ -219,6 +219,7 @@
L.screen_loc = "CENTER-7:[round(L.offset_x,1)],CENTER-7:[round(L.offset_y,1)]"
/atom/movable/proc/update_parallax_contents()
set waitfor = FALSE
if(length(client_mobs_in_contents))
for(var/thing in client_mobs_in_contents)
var/mob/M = thing
+8 -31
View File
@@ -47,17 +47,7 @@
name = "swap hand"
/obj/screen/swap_hand/Click()
// At this point in client Click() code we have passed the 1/10 sec check and little else
// We don't even know if it's a middle click
if(world.time <= usr.next_move)
return 1
if(usr.incapacitated())
return 1
if(ismob(usr))
var/mob/M = usr
M.swap_hand()
usr.swap_hand()
return 1
/obj/screen/craft
@@ -101,15 +91,9 @@
plane = HUD_PLANE
/obj/screen/inventory/Click(location, control, params)
// At this point in client Click() code we have passed the 1/10 sec check and little else
// We don't even know if it's a middle click
if(world.time <= usr.next_move)
return TRUE
if(usr.incapacitated())
return TRUE
if(ismecha(usr.loc)) // stops inventory actions in a mech
return TRUE
if(hud?.mymob && (hud.mymob != usr))
return
// just redirect clicks
if(hud?.mymob && slot_id)
var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id)
@@ -190,17 +174,10 @@
/obj/screen/inventory/hand/Click(location, control, params)
// At this point in client Click() code we have passed the 1/10 sec check and little else
// We don't even know if it's a middle click
var/mob/user = hud?.mymob
if(usr != user)
return TRUE
if(world.time <= user.next_move)
return TRUE
if(user.incapacitated())
return TRUE
if (ismecha(user.loc)) // stops inventory actions in a mech
return TRUE
if(hud?.mymob && (hud.mymob != usr))
return
var/mob/user = hud.mymob
// just redirect clicks
if(user.active_hand_index == held_index)
var/obj/item/I = user.get_active_held_item()
@@ -0,0 +1,58 @@
/obj/screen/action_bar
/obj/screen/action_bar/Destroy()
STOP_PROCESSING(SShuds, src)
return ..()
/obj/screen/action_bar/proc/mark_dirty()
var/mob/living/L = hud?.mymob
if(L?.client && update_to_mob(L))
START_PROCESSING(SShuds, src)
/obj/screen/action_bar/process()
var/mob/living/L = hud?.mymob
if(!L?.client || !update_to_mob(L))
return PROCESS_KILL
/obj/screen/action_bar/proc/update_to_mob(mob/living/L)
return FALSE
/datum/hud/var/obj/screen/action_bar/clickdelay/clickdelay
/obj/screen/action_bar/clickdelay
name = "click delay"
icon = 'icons/effects/progessbar.dmi'
icon_state = "prog_bar_100"
layer = 20 // under hand buttons
/obj/screen/action_bar/clickdelay/Initialize()
. = ..()
var/matrix/M = new
M.Scale(2, 1)
transform = M
/obj/screen/action_bar/clickdelay/update_to_mob(mob/living/L)
var/estimated = L.EstimatedNextActionTime()
var/diff = estimated - L.last_action
var/left = estimated - world.time
if(left < 0 || diff < 0)
icon_state = "prog_bar_100"
return FALSE
icon_state = "prog_bar_[round(clamp(((diff - left)/diff) * 100, 0, 100), 5)]"
return TRUE
/datum/hud/var/obj/screen/action_bar/resistdelay/resistdelay
/obj/screen/action_bar/resistdelay
name = "resist delay"
icon = 'icons/effects/progessbar.dmi'
icon_state = "prog_bar_100"
/obj/screen/action_bar/resistdelay/update_to_mob(mob/living/L)
var/diff = L.next_resist - L.last_resist
var/left = L.next_resist - world.time
if(left < 0 || diff < 0)
icon_state = "prog_bar_100"
return FALSE
icon_state = "prog_bar_[round(clamp(((diff - left)/diff) * 100, 0, 100), 5)]"
return TRUE
@@ -0,0 +1,58 @@
/obj/screen/mov_intent
icon = 'modular_citadel/icons/ui/screen_midnight.dmi'
/obj/screen/sprintbutton
name = "toggle sprint"
icon = 'modular_citadel/icons/ui/screen_midnight.dmi'
icon_state = "act_sprint"
layer = ABOVE_HUD_LAYER - 0.1
var/mutable_appearance/flashy
/obj/screen/sprintbutton/Click()
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
H.default_toggle_sprint()
/obj/screen/sprintbutton/update_icon_state()
var/mob/living/user = hud?.mymob
if(!istype(user))
return
if(user.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE)
icon_state = "act_sprint_on"
else if(HAS_TRAIT(user, TRAIT_SPRINT_LOCKED))
icon_state = "act_sprint_locked"
else
icon_state = "act_sprint"
/obj/screen/sprintbutton/update_overlays()
. = ..()
var/mob/living/carbon/user = hud?.mymob
if(!istype(user) || !user.client)
return
if((user.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && user.client.prefs.hud_toggle_flash)
if(!flashy)
flashy = mutable_appearance('icons/mob/screen_gen.dmi', "togglehalf_flash")
if(flashy.color != user.client.prefs.hud_toggle_color)
flashy.color = user.client.prefs.hud_toggle_color
. += flashy
//Sprint buffer onscreen code.
/datum/hud/var/obj/screen/sprint_buffer/sprint_buffer
/obj/screen/sprint_buffer
name = "sprint buffer"
icon = 'icons/effects/progessbar.dmi'
icon_state = "prog_bar_100"
/obj/screen/sprint_buffer/Click()
if(isliving(usr))
var/mob/living/L = usr
to_chat(L, "<span class='boldnotice'>Your sprint buffer's maximum capacity is [L.sprint_buffer_max]. It is currently at [L.sprint_buffer], regenerating at [L.sprint_buffer_regen_ds * 10] per second. \
Sprinting while this is empty will incur a [L.sprint_stamina_cost] stamina cost per tile.</span>")
/obj/screen/sprint_buffer/proc/update_to_mob(mob/living/L)
var/amount = 0
if(L.sprint_buffer_max > 0)
amount = round(clamp((L.sprint_buffer / L.sprint_buffer_max) * 100, 0, 100), 5)
icon_state = "prog_bar_[amount]"
@@ -0,0 +1,61 @@
/datum/hud/var/obj/screen/staminas/staminas
/datum/hud/var/obj/screen/staminabuffer/staminabuffer
/obj/screen/staminas
icon = 'modular_citadel/icons/ui/screen_gen.dmi'
name = "stamina"
icon_state = "stamina0"
screen_loc = ui_stamina
mouse_opacity = 1
/obj/screen/staminas/Click(location,control,params)
if(isliving(usr))
var/mob/living/L = usr
to_chat(L, "<span class='notice'>You have <b>[L.getStaminaLoss()]</b> stamina loss.<br>Your stamina buffer can take <b>[L.stambuffer]</b> stamina loss, and recharges at no cost.<br>Your stamina buffer is <b>[(L.stambuffer*(100/L.stambuffer))-(L.bufferedstam*(100/L.stambuffer))]%</b> full.</span>")
/obj/screen/staminas/update_icon_state()
var/mob/living/carbon/user = hud?.mymob
if(!user)
return
if(user.stat == DEAD || (user.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (user.hal_screwyhud in 1 to 2))
icon_state = "staminacrit"
else if(user.hal_screwyhud == 5)
icon_state = "stamina0"
else
icon_state = "stamina[clamp(FLOOR(user.getStaminaLoss() /20, 1), 0, 6)]"
//stam buffer
/obj/screen/staminabuffer
icon = 'modular_citadel/icons/ui/screen_gen.dmi'
name = "stamina buffer"
icon_state = "stambuffer0"
screen_loc = ui_stamina
layer = ABOVE_HUD_LAYER + 0.1
mouse_opacity = 0
/obj/screen/staminabuffer/update_icon_state()
var/mob/living/carbon/user = hud?.mymob
if(!user)
return
if(user.stat == DEAD || (user.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (user.hal_screwyhud in 1 to 2))
icon_state = "stambuffer7"
else if(user.hal_screwyhud == 5)
icon_state = "stambuffer0"
else
switch(user.bufferedstam / user.stambuffer)
if(0.95 to INFINITY)
icon_state = "stambuffer7"
if(0.9 to 0.95)
icon_state = "stambuffer6"
if(0.8 to 0.9)
icon_state = "stambuffer5"
if(0.6 to 0.8)
icon_state = "stambuffer4"
if(0.4 to 0.6)
icon_state = "stambuffer3"
if(0.2 to 0.4)
icon_state = "stambuffer2"
if(0.05 to 0.2)
icon_state = "stambuffer1"
else
icon_state = "stambuffer0"
+3 -6
View File
@@ -9,12 +9,9 @@
/obj/screen/storage/Click(location, control, params)
if(!insertion_click)
return ..()
if(world.time <= usr.next_move)
return TRUE
if(usr.incapacitated())
return TRUE
if (ismecha(usr.loc)) // stops inventory actions in a mech
return TRUE
if(hud?.mymob && (hud.mymob != usr))
return
// just redirect clicks
if(master)
var/obj/item/I = usr.get_active_held_item()
if(I)
+22
View File
@@ -0,0 +1,22 @@
/obj/screen/voretoggle
name = "toggle vore mode"
icon = 'modular_citadel/icons/ui/screen_midnight.dmi'
icon_state = "nom_off"
/obj/screen/voretoggle/Click()
if(usr != hud.mymob)
return
var/mob/living/carbon/C = usr
if(SEND_SIGNAL(usr, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
to_chat(usr, "<span class='warning'>Disable combat mode first.</span>")
return
C.toggle_vore_mode()
/obj/screen/voretoggle/update_icon_state()
var/mob/living/carbon/user = hud?.mymob
if(!istype(user))
return
if(user.voremode)
icon_state = "nom"
else
icon_state = "nom_off"
+74 -47
View File
@@ -7,21 +7,22 @@
*and lastly
*afterattack. The return value does not matter.
*/
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params, flags, damage_multiplier = 1)
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params, attackchain_flags, damage_multiplier = 1)
if(isliving(user))
var/mob/living/L = user
if(!CHECK_MOBILITY(L, MOBILITY_USE) && !(flags & ATTACKCHAIN_PARRY_COUNTERATTACK))
if(!CHECK_MOBILITY(L, MOBILITY_USE) && !(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK))
to_chat(L, "<span class='warning'>You are unable to swing [src] right now!</span>")
return
if(tool_behaviour && target.tool_act(user, src, tool_behaviour))
. = attackchain_flags
if(tool_behaviour && ((. = target.tool_act(user, src, tool_behaviour)) & STOP_ATTACK_PROC_CHAIN))
return
if(pre_attack(target, user, params))
if((. |= pre_attack(target, user, params, ., damage_multiplier)) & STOP_ATTACK_PROC_CHAIN)
return
if(target.attackby(src, user, params, flags, damage_multiplier))
if((. |= target.attackby(src, user, params, ., damage_multiplier)) & STOP_ATTACK_PROC_CHAIN)
return
if(QDELETED(src) || QDELETED(target))
return
afterattack(target, user, TRUE, params)
. |= afterattack(target, user, TRUE, params)
/// Like melee_attack_chain but for ranged.
/obj/item/proc/ranged_attack_chain(mob/user, atom/target, params)
@@ -30,7 +31,7 @@
if(!CHECK_MOBILITY(L, MOBILITY_USE))
to_chat(L, "<span class='warning'>You are unable to raise [src] right now!</span>")
return
afterattack(target, user, FALSE, params)
return afterattack(target, user, FALSE, params)
// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
/obj/item/proc/attack_self(mob/user)
@@ -38,28 +39,43 @@
return
interact(user)
/obj/item/proc/pre_attack(atom/A, mob/living/user, params) //do stuff before attackby!
/obj/item/proc/pre_attack(atom/A, mob/living/user, params, attackchain_flags, damage_multiplier) //do stuff before attackby!
if(SEND_SIGNAL(src, COMSIG_ITEM_PRE_ATTACK, A, user, params) & COMPONENT_NO_ATTACK)
return TRUE
return FALSE //return TRUE to avoid calling attackby after this proc does stuff
return STOP_ATTACK_PROC_CHAIN
if(!(attackchain_flags & ATTACK_IGNORE_CLICKDELAY) && !CheckAttackCooldown(user, A))
return STOP_ATTACK_PROC_CHAIN
// No comment
/atom/proc/attackby(obj/item/W, mob/user, params)
if(SEND_SIGNAL(src, COMSIG_PARENT_ATTACKBY, W, user, params) & COMPONENT_NO_AFTERATTACK)
return TRUE
return FALSE
return STOP_ATTACK_PROC_CHAIN
/obj/attackby(obj/item/I, mob/living/user, params)
return ..() || ((obj_flags & CAN_BE_HIT) && I.attack_obj(src, user))
. = ..()
if(. & STOP_ATTACK_PROC_CHAIN)
return
if(obj_flags & CAN_BE_HIT)
. |= I.attack_obj(src, user)
/mob/living/attackby(obj/item/I, mob/living/user, params, attackchain_flags, damage_multiplier)
if(..())
return TRUE
I.attack_delay_done = FALSE //Should be set TRUE in pre_attacked_by()
. = I.attack(src, user, attackchain_flags, damage_multiplier)
if(!I.attack_delay_done) //Otherwise, pre_attacked_by() should handle it.
user.changeNext_move(I.click_delay)
. = ..()
if(. & STOP_ATTACK_PROC_CHAIN)
return
. |= I.attack(src, user, attackchain_flags, damage_multiplier)
if(!(. & NO_AUTO_CLICKDELAY_HANDLING)) // SAFETY NET - unless the proc tells us we should not handle this, give them the basic melee cooldown!
I.ApplyAttackCooldown(user, src, attackchain_flags)
/**
* Called when someone uses us to attack a mob in melee combat.
*
* This proc respects CheckAttackCooldown() default clickdelay handling.
*
* @params
* * mob/living/M - target
* * mob/living/user - attacker
* * attackchain_Flags - see [code/__DEFINES/_flags/return_values.dm]
* * damage_multiplier - what to multiply the damage by
*/
/obj/item/proc/attack(mob/living/M, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_ITEM_NO_ATTACK)
return
@@ -88,6 +104,17 @@
if(weight)
user.adjustStaminaLossBuffered(weight)
// CIT SCREENSHAKE
if(force >= 15)
shake_camera(user, ((force - 10) * 0.01 + 1), ((force - 10) * 0.01))
if(M.client)
switch (M.client.prefs.damagescreenshake)
if (1)
shake_camera(M, ((force - 10) * 0.015 + 1), ((force - 10) * 0.015))
if (2)
if(!CHECK_MOBILITY(M, MOBILITY_MOVE))
shake_camera(M, ((force - 10) * 0.015 + 1), ((force - 10) * 0.015))
//the equivalent of the standard version of attack() but for object targets.
/obj/item/proc/attack_obj(obj/O, mob/living/user)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_NO_ATTACK_OBJ)
@@ -95,8 +122,7 @@
if(item_flags & NOBLUDGEON)
return
user.do_attack_animation(O)
if(!O.attacked_by(src, user))
user.changeNext_move(click_delay)
O.attacked_by(src, user)
var/weight = getweight(user, STAM_COST_ATTACK_OBJ_MULT)
if(weight)
user.adjustStaminaLossBuffered(weight)//CIT CHANGE - makes attacking things cause stamina loss
@@ -109,12 +135,9 @@
var/bad_trait
var/stamloss = user.getStaminaLoss()
var/next_move_mult = 1
if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
totitemdamage *= 1 - penalty
next_move_mult += penalty*STAM_CRIT_ITEM_ATTACK_DELAY
user.changeNext_move(I.click_delay*next_move_mult)
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
@@ -126,18 +149,18 @@
if(!(SKILL_TRAIN_ATTACK_OBJ in I.used_skills[skill]))
continue
user.mind.auto_gain_experience(skill, I.skill_gain)
if(!(attackchain_flags & NO_AUTO_CLICKDELAY_HANDLING))
I.ApplyAttackCooldown(user, src, attackchain_flags)
if(totitemdamage)
visible_message("<span class='danger'>[user] has hit [src] with [I]!</span>", null, null, COMBAT_MESSAGE_RANGE)
//only witnesses close by and the victim see a hit message.
log_combat(user, src, "attacked", I)
take_damage(totitemdamage, I.damtype, "melee", 1)
return TRUE
/mob/living/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
var/list/block_return = list()
var/totitemdamage = pre_attacked_by(I, user) * damage_multiplier
if((user != src) && mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, null, block_return) & BLOCK_SUCCESS)
if((user != src) && mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_IS_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, null, block_return) & BLOCK_SUCCESS)
return FALSE
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
send_item_attack_message(I, user, null, totitemdamage)
@@ -155,8 +178,7 @@
/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
if(I.force < force_threshold || I.damtype == STAMINA)
playsound(loc, 'sound/weapons/tap.ogg', I.get_clamped_volume(), 1, -1)
user.changeNext_move(I.click_delay) //pre_attacked_by not called
playsound(src, 'sound/weapons/tap.ogg', I.get_clamped_volume(), 1, -1)
else
return ..()
@@ -167,25 +189,21 @@
var/stamloss = user.getStaminaLoss()
var/stam_mobility_mult = 1
var/next_move_mult = 1
if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
stam_mobility_mult -= penalty
next_move_mult += penalty*STAM_CRIT_ITEM_ATTACK_DELAY
if(stam_mobility_mult > LYING_DAMAGE_PENALTY && !CHECK_MOBILITY(user, MOBILITY_STAND)) //damage penalty for fighting prone, doesn't stack with the above.
stam_mobility_mult = LYING_DAMAGE_PENALTY
. *= stam_mobility_mult
user.changeNext_move(I.click_delay*next_move_mult)
I.attack_delay_done = TRUE
var/bad_trait
if(!(I.item_flags & NO_COMBAT_MODE_FORCE_MODIFIER))
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
. *= 0.5
. *= 0.8
else if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
. *= 1.5
. *= 1.2
if(!user.mind || !I.used_skills)
return
@@ -197,8 +215,18 @@
var/datum/skill/S = GLOB.skill_datums[skill]
user.mind.auto_gain_experience(skill, I.skill_gain*S.item_skill_gain_multi)
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
// Click parameters is the params string from byond Click() code, see that documentation.
/**
* Called after attacking something if the melee attack chain isn't interrupted before.
* Also called when clicking on something with an item without being in melee range
*
* WARNING: This does not automatically check clickdelay if not in a melee attack! Be sure to account for this!
*
* @params
* * target - The thing we clicked
* * user - mob of person clicking
* * proximity_flag - are we in melee range/doing it in a melee attack
* * click_parameters - mouse control parameters, check BYOND ref.
*/
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK, target, user, proximity_flag, click_parameters)
SEND_SIGNAL(user, COMSIG_MOB_ITEM_AFTERATTACK, target, user, proximity_flag, click_parameters)
@@ -210,25 +238,24 @@
else
return clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area, current_force)
/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area, obj/item/bodypart/hit_bodypart)
var/message_verb = "attacked"
if(I.attack_verb && I.attack_verb.len)
if(length(I.attack_verb))
message_verb = "[pick(I.attack_verb)]"
if(current_force < I.force * FEEBLE_ATTACK_MSG_THRESHOLD)
message_verb = "[pick("feebly", "limply", "saplessly")] [message_verb]"
else if(!I.force)
return
var/message_hit_area = ""
if(hit_area)
message_hit_area = " in the [hit_area]"
var/attack_message = "[src] has been [message_verb][message_hit_area] with [I]."
var/attack_message = "[src] is [message_verb][message_hit_area] with [I]!"
var/attack_message_local = "You're [message_verb][message_hit_area] with [I]!"
if(user in viewers(src, null))
attack_message = "[user] has [message_verb] [src][message_hit_area] with [I]!"
attack_message = "[user] [message_verb] [src][message_hit_area] with [I]!"
attack_message_local = "[user] [message_verb] you[message_hit_area] with [I]!"
if(user == src)
attack_message_local = "You [message_verb] yourself[message_hit_area] with [I]"
visible_message("<span class='danger'>[attack_message]</span>",\
"<span class='userdanger'>[attack_message]</span>", null, COMBAT_MESSAGE_RANGE)
if(hit_area == BODY_ZONE_HEAD)
if(prob(2))
playsound(src, 'sound/weapons/dink.ogg', 30, 1)
"<span class='userdanger'>[attack_message_local]</span>", null, COMBAT_MESSAGE_RANGE)
return 1
/// How much stamina this takes to swing this is not for realism purposes hecc off.
+4 -13
View File
@@ -37,7 +37,7 @@
CtrlClickOn(A)
return
if(world.time <= next_move)
if(!CheckActionCooldown())
return
// You are responsible for checking config.ghost_interaction when you override this function
// Not all of them require checking, see below
@@ -63,18 +63,9 @@
// And here are some good things for free:
// Now you can click through portals, wormholes, gateways, and teleporters while observing. -Sayu
/obj/machinery/gateway/centerstation/attack_ghost(mob/user)
if(awaygate)
user.forceMove(awaygate.loc)
else
to_chat(user, "[src] has no destination.")
return ..()
/obj/machinery/gateway/centeraway/attack_ghost(mob/user)
if(stationgate)
user.forceMove(stationgate.loc)
else
to_chat(user, "[src] has no destination.")
/obj/effect/gateway_portal_bumper/attack_ghost(mob/user)
if(gateway)
gateway.Transfer(user)
return ..()
/obj/machinery/teleport/hub/attack_ghost(mob/user)
+67 -51
View File
@@ -4,39 +4,57 @@
Otherwise pretty standard.
*/
/mob/living/carbon/human/UnarmedAttack(atom/A, proximity)
/mob/living/carbon/human/UnarmedAttack(atom/A, proximity, intent = a_intent, attackchain_flags = NONE)
if(!has_active_hand()) //can't attack without a hand.
to_chat(src, "<span class='notice'>You look at your arm and sigh.</span>")
return
var/obj/item/bodypart/check_arm = get_active_hand()
if(check_arm && check_arm.is_disabled() == BODYPART_DISABLED_WOUND)
to_chat(src, "<span class='warning'>The damage in your [check_arm.name] is preventing you from using it! Get it fixed, or at least splinted!</span>")
return
. = attackchain_flags
// Special glove functions:
// If the gloves do anything, have them return 1 to stop
// normal attack_hand() here.
var/obj/item/clothing/gloves/G = gloves // not typecast specifically enough in defines
if(proximity && istype(G) && G.Touch(A,1))
return
var/override = 0
if(proximity && istype(G))
. |= G.Touch(A, TRUE)
if(. & INTERRUPT_UNARMED_ATTACK)
return
for(var/datum/mutation/human/HM in dna.mutations)
override += HM.on_attack_hand(A, proximity)
. |= HM.on_attack_hand(A, proximity, intent, .)
if(override)
if(. & INTERRUPT_UNARMED_ATTACK)
return
SEND_SIGNAL(src, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, A)
A.attack_hand(src)
return . | A.attack_hand(src, intent, .)
//Return TRUE to cancel other attack hand effects that respect it.
/atom/proc/attack_hand(mob/user)
. = FALSE
/atom/proc/attack_hand(mob/user, act_intent = user.a_intent, attackchain_flags)
SHOULD_NOT_SLEEP(TRUE)
if(!(interaction_flags_atom & INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND))
add_fingerprint(user)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_HAND, user) & COMPONENT_NO_ATTACK_HAND)
. = TRUE
return
. = attackchain_flags
if(attack_hand_speed && !(. & ATTACK_IGNORE_CLICKDELAY))
if(!user.CheckActionCooldown(attack_hand_speed))
return
if(interaction_flags_atom & INTERACT_ATOM_ATTACK_HAND)
. = _try_interact(user)
INVOKE_ASYNC(src, .proc/on_attack_hand, user, act_intent, .)
if(!(. & ATTACK_IGNORE_ACTION))
if(attack_hand_unwieldlyness)
user.DelayNextAction(attack_hand_unwieldlyness, considered_action = attack_hand_is_action)
else if(attack_hand_is_action)
user.DelayNextAction()
/atom/proc/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
//Return a non FALSE value to cancel whatever called this from propagating, if it respects it.
/atom/proc/_try_interact(mob/user)
@@ -44,7 +62,6 @@
return interact(user)
if(can_interact(user))
return interact(user)
return FALSE
/atom/proc/can_interact(mob/user)
if(!user.can_interact_with(src))
@@ -74,8 +91,7 @@
else
add_fingerprint(user)
if(interaction_flags_atom & INTERACT_ATOM_UI_INTERACT)
return ui_interact(user)
return FALSE
ui_interact(user)
/*
/mob/living/carbon/human/RestrainedClickOn(var/atom/A) ---carbons will handle this
@@ -89,13 +105,19 @@
. = ..()
if(gloves)
var/obj/item/clothing/gloves/G = gloves
if(istype(G) && G.Touch(A,0)) // for magic gloves
. |= G.Touch(A, FALSE)
if(. & INTERRUPT_UNARMED_ATTACK)
return
if(istype(glasses))
. |= glasses.ranged_attack(src, A, mouseparams)
if(. & INTERRUPT_UNARMED_ATTACK)
return
if (istype(glasses) && glasses.ranged_attack(src,A,mouseparams))
return
for(var/datum/mutation/human/HM in dna.mutations)
HM.on_ranged_attack(A, mouseparams)
. |= HM.on_ranged_attack(A, mouseparams)
if(. & INTERRUPT_UNARMED_ATTACK)
return
if(isturf(A) && get_dist(src,A) <= 1)
src.Move_Pulled(A)
@@ -104,8 +126,8 @@
/*
Animals & All Unspecified
*/
/mob/living/UnarmedAttack(atom/A)
A.attack_animal(src)
/mob/living/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_animal(src, intent, flags)
/atom/proc/attack_animal(mob/user)
SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_ANIMAL, user)
@@ -116,8 +138,10 @@
/*
Monkeys
*/
/mob/living/carbon/monkey/UnarmedAttack(atom/A)
A.attack_paw(src)
/mob/living/carbon/monkey/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(!CheckActionCooldown(CLICK_CD_MELEE))
return
return !isnull(A.attack_paw(src, intent, flags))
/atom/proc/attack_paw(mob/user)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_PAW, user) & COMPONENT_NO_ATTACK_HAND)
@@ -138,6 +162,8 @@
return
if(is_muzzled())
return
if(!CheckActionCooldown(CLICK_CD_MELEE))
return
var/mob/living/carbon/ML = A
if(istype(ML))
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
@@ -157,13 +183,14 @@
ML.ForceContractDisease(D)
else
ML.visible_message("<span class='danger'>[src] has attempted to bite [ML]!</span>")
DelayNextAction()
/*
Aliens
Defaults to same as monkey in most places
*/
/mob/living/carbon/alien/UnarmedAttack(atom/A)
A.attack_alien(src)
/mob/living/carbon/alien/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_alien(src, intent, flags)
/atom/proc/attack_alien(mob/living/carbon/alien/user)
attack_paw(user)
@@ -173,29 +200,29 @@
return
// Babby aliens
/mob/living/carbon/alien/larva/UnarmedAttack(atom/A)
A.attack_larva(src)
/mob/living/carbon/alien/larva/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_larva(src, intent, flags)
/atom/proc/attack_larva(mob/user)
return
/*
Slimes
Nothing happening here
*/
/mob/living/simple_animal/slime/UnarmedAttack(atom/A)
A.attack_slime(src)
/mob/living/simple_animal/slime/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_slime(src, intent, flags)
/atom/proc/attack_slime(mob/user)
return
/mob/living/simple_animal/slime/RestrainedClickOn(atom/A)
return
/*
Drones
*/
/mob/living/simple_animal/drone/UnarmedAttack(atom/A)
A.attack_drone(src)
/mob/living/simple_animal/drone/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_drone(src, intent, flags)
/atom/proc/attack_drone(mob/living/simple_animal/drone/user)
attack_hand(user) //defaults to attack_hand. Override it when you don't want drones to do same stuff as humans.
@@ -203,55 +230,44 @@
/mob/living/simple_animal/slime/RestrainedClickOn(atom/A)
return
/*
True Devil
*/
/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity)
/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_hand(src)
/*
Brain
*/
/mob/living/brain/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default
/mob/living/brain/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
return
/*
pAI
*/
/mob/living/silicon/pai/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default
/mob/living/silicon/pai/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
return
/*
Simple animals
*/
/mob/living/simple_animal/UnarmedAttack(atom/A, proximity)
/mob/living/simple_animal/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(!dextrous)
return ..()
if(!ismob(A))
A.attack_hand(src)
A.attack_hand(src, intent, flags)
update_inv_hands()
/*
Hostile animals
*/
/mob/living/simple_animal/hostile/UnarmedAttack(atom/A)
/mob/living/simple_animal/hostile/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
target = A
if(dextrous && !ismob(A))
..()
return ..()
else
AttackingTarget()
/*
New Players:
Have no reason to click on anything at all.
+76
View File
@@ -0,0 +1,76 @@
/mob/proc/RightClickOn(atom/A, params) //mostly a copy-paste from ClickOn()
var/list/modifiers = params2list(params)
if(incapacitated(ignore_restraints = 1))
return
face_atom(A)
if(!CheckActionCooldown())
return
if(!modifiers["catcher"] && A.IsObscured())
return
if(ismecha(loc))
var/obj/mecha/M = loc
return M.click_action(A,src,params)
if(restrained())
DelayNextAction(CLICK_CD_HANDCUFFED)
return RestrainedClickOn(A)
if(in_throw_mode)
throw_item(A)//todo: make it plausible to lightly toss items via right-click
return
var/obj/item/W = get_active_held_item()
if(W == A)
if(!W.rightclick_attack_self(src))
W.attack_self(src)
update_inv_hands()
return
//These are always reachable.
//User itself, current loc, and user inventory
if(A in DirectAccess())
if(W)
return W.rightclick_melee_attack_chain(src, A, params)
else
if(!AltUnarmedAttack(A, TRUE))
. = UnarmedAttack(A, TRUE, a_intent)
if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
DelayNextAction(CLICK_CD_MELEE)
return
return
//Can't reach anything else in lockers or other weirdness
if(!loc.AllowClick())
return
//Standard reach turf to turf or reaching inside storage
if(CanReach(A,W))
if(W)
return W.rightclick_melee_attack_chain(src, A, params)
else
if(!AltUnarmedAttack(A, TRUE))
. = UnarmedAttack(A, TRUE, a_intent)
if(!(. & NO_AUTO_CLICKDELAY_HANDLING) && ismob(A))
DelayNextAction(CLICK_CD_MELEE)
return
return
else
if(W)
if(!W.altafterattack(A, src, FALSE, params))
return W.afterattack(A, src, FALSE, params)
else
if(!AltRangedAttack(A, params))
return RangedAttack(A, params)
/mob/proc/AltUnarmedAttack(atom/A, proximity_flag)
if(ismob(A))
DelayNextAction(CLICK_CD_MELEE)
return FALSE
/mob/proc/AltRangedAttack(atom/A, params)
return FALSE
+19
View File
@@ -0,0 +1,19 @@
/obj/item/proc/rightclick_melee_attack_chain(mob/user, atom/target, params)
if(!alt_pre_attack(target, user, params)) //Hey, does this item have special behavior that should override all normal right-click functionality?
if(!target.altattackby(src, user, params)) //Does the target do anything special when we right-click on it?
. = melee_attack_chain(user, target, params) //Ugh. Lame! I'm filing a legal complaint about the discrimination against the right mouse button!
else
. = altafterattack(target, user, TRUE, params)
/obj/item/proc/alt_pre_attack(atom/A, mob/living/user, params)
return FALSE //return something other than false if you wanna override attacking completely
/atom/proc/altattackby(obj/item/W, mob/user, params)
return FALSE //return something other than false if you wanna add special right-click behavior to objects.
/obj/item/proc/rightclick_attack_self(mob/user)
return FALSE
/obj/item/proc/altafterattack(atom/target, mob/user, proximity_flag, click_parameters)
SEND_SIGNAL(src, COMSIG_ITEM_ALT_AFTERATTACK, target, user, proximity_flag, click_parameters)
return FALSE
+50
View File
@@ -0,0 +1,50 @@
/mob/living/carbon/human/AltUnarmedAttack(atom/A, proximity)
if(!has_active_hand())
to_chat(src, "<span class='notice'>You look at the state of the universe and sigh.</span>") //lets face it, people rarely ever see this message in its intended condition.
return TRUE
return A.alt_attack_hand(src)
/mob/living/carbon/human/AltRangedAttack(atom/A, params)
if(isturf(A) || incapacitated()) // pretty annoying to wave your fist at floors and walls. And useless.
return
if(!CheckActionCooldown(CLICK_CD_RANGE))
return
DelayNextAction()
var/list/target_viewers = fov_viewers(11, A) //doesn't check for blindness.
if(!(src in target_viewers)) //click catcher issuing calls for out of view objects.
return TRUE
if(!has_active_hand())
to_chat(src, "<span class='notice'>You ponder your life choices and sigh.</span>")
return TRUE
var/list/src_viewers = viewers(DEFAULT_MESSAGE_RANGE, src) - src // src has a different message.
var/the_action = "waves to [A]"
var/what_action = "waves to something you can't see"
var/self_action = "wave to [A]"
switch(a_intent)
if(INTENT_DISARM)
the_action = "shoos away [A]"
what_action = "shoo away something out of your vision"
self_action = "shoo away [A]"
if(INTENT_GRAB)
the_action = "beckons [A] to come"
what_action = "beckons something out of your vision to come"
self_action = "beckon [A] to come"
if(INTENT_HARM)
var/pronoun = "[p_their()]"
the_action = "shakes [pronoun] fist at [A]"
what_action = "shakes [pronoun] fist at something out of your vision"
self_action = "shake your fist at [A]"
if(!eye_blind)
to_chat(src, "You [self_action].")
for(var/B in src_viewers)
var/mob/M = B
if(!M.eye_blind)
var/message = (M in target_viewers) ? the_action : what_action
to_chat(M, "[src] [message].")
return TRUE
/atom/proc/alt_attack_hand(mob/user)
return FALSE
+3 -2
View File
@@ -123,7 +123,8 @@
. = ..()
if(!target || !user)
return
if(!user.CheckActionCooldown(CLICK_CD_MELEE))
return
if(!focus)
focus_object(target)
return
@@ -145,7 +146,7 @@
else
apply_focus_overlay()
focus.throw_at(target, 10, 1,user)
user.changeNext_move(CLICK_CD_MELEE)
user.DelayNextAction(considered_action = TRUE, flush = TRUE)
update_icon()
/proc/tkMaxRangeCheck(mob/user, atom/target)
@@ -83,7 +83,7 @@
var/auto_trim = TRUE
/datum/config_entry/string/vv_edit_var(var_name, var_value)
return var_name != "auto_trim" && ..()
return var_name != NAMEOF(src, auto_trim) && ..()
/datum/config_entry/string/ValidateAndSet(str_val, during_load)
if(!VASProcCallGuard(str_val))
@@ -110,7 +110,7 @@
return FALSE
/datum/config_entry/number/vv_edit_var(var_name, var_value)
var/static/list/banned_edits = list("max_val", "min_val", "integer")
var/static/list/banned_edits = list(NAMEOF(src, max_val), NAMEOF(src, min_val), NAMEOF(src, integer))
return !(var_name in banned_edits) && ..()
/datum/config_entry/flag
@@ -216,7 +216,7 @@
return FALSE
/datum/config_entry/keyed_list/vv_edit_var(var_name, var_value)
return var_name != "splitter" && ..()
return var_name != NAMEOF(src, splitter) && ..()
/datum/config_entry/keyed_list/proc/preprocess_key(key)
return key
@@ -56,6 +56,8 @@
/datum/config_entry/flag/log_adminchat // log admin chat messages
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/log_shuttle // log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console
/datum/config_entry/flag/log_pda // log pda messages
/datum/config_entry/flag/log_telecomms // log telecomms messages
@@ -468,3 +470,5 @@
/datum/config_entry/flag/minimaps_enabled
config_entry_value = TRUE
/datum/config_entry/string/centcom_ban_db // URL for the CentCom Galactic Ban DB API
+3 -3
View File
@@ -210,10 +210,10 @@
/datum/controller/subsystem/vv_edit_var(var_name, var_value)
switch (var_name)
if ("can_fire")
if (NAMEOF(src, can_fire))
//this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag
if (var_value)
next_fire = world.time + wait
if ("queued_priority") //editing this breaks things.
return 0
if (NAMEOF(src, queued_priority)) //editing this breaks things.
return FALSE
. = ..()
+24
View File
@@ -16,6 +16,7 @@ SUBSYSTEM_DEF(atoms)
/datum/controller/subsystem/atoms/Initialize(timeofday)
GLOB.fire_overlay.appearance_flags = RESET_COLOR
setupGenetics()
initialized = INITIALIZATION_INNEW_MAPLOAD
InitializeAtoms()
return ..()
@@ -106,6 +107,29 @@ SUBSYSTEM_DEF(atoms)
old_initialized = SSatoms.old_initialized
BadInitializeCalls = SSatoms.BadInitializeCalls
/datum/controller/subsystem/atoms/proc/setupGenetics()
var/list/mutations = subtypesof(/datum/mutation/human)
shuffle_inplace(mutations)
for(var/A in subtypesof(/datum/generecipe))
var/datum/generecipe/GR = A
GLOB.mutation_recipes[initial(GR.required)] = initial(GR.result)
for(var/i in 1 to LAZYLEN(mutations))
var/path = mutations[i] //byond gets pissy when we do it in one line
var/datum/mutation/human/B = new path ()
B.alias = "Mutation [i]"
GLOB.all_mutations[B.type] = B
GLOB.full_sequences[B.type] = generate_gene_sequence(B.blocks)
GLOB.alias_mutations[B.alias] = B.type
if(B.locked)
continue
if(B.quality == POSITIVE)
GLOB.good_mutations |= B
else if(B.quality == NEGATIVE)
GLOB.bad_mutations |= B
else if(B.quality == MINOR_NEGATIVE)
GLOB.not_good_mutations |= B
CHECK_TICK
/datum/controller/subsystem/atoms/proc/InitLog()
. = ""
for(var/path in BadInitializeCalls)
+2 -2
View File
@@ -60,9 +60,9 @@ SUBSYSTEM_DEF(blackbox)
/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
switch(var_name)
if("feedback")
if(NAMEOF(src, feedback))
return FALSE
if("sealed")
if(NAMEOF(src, sealed))
if(var_value)
return Seal()
return FALSE
+22 -8
View File
@@ -31,19 +31,13 @@ SUBSYSTEM_DEF(chat)
//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)
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
if (trailing_newline)
message += "<br>"
//url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
//Do the double-encoding here to save nanoseconds
var/twiceEncoded = url_encode(url_encode(message))
var/twiceEncoded
if(islist(target))
var/sanitized_message = FALSE
for(var/I in target)
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
@@ -55,6 +49,17 @@ SUBSYSTEM_DEF(chat)
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
continue
if(!sanitized_message)
message = replacetext(message, "\improper", "")
message = replacetext(message, "\proper", "")
if(handle_whitespace)
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
if (trailing_newline)
message += "<br>"
twiceEncoded = url_encode(url_encode(message))
sanitized_message = TRUE
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
C.chatOutput.messageQueue += message
@@ -74,6 +79,15 @@ SUBSYSTEM_DEF(chat)
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
return
message = replacetext(message, "\improper", "")
message = replacetext(message, "\proper", "")
if(handle_whitespace)
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
if (trailing_newline)
message += "<br>"
twiceEncoded = url_encode(url_encode(message))
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
C.chatOutput.messageQueue += message
return
+4 -4
View File
@@ -674,7 +674,7 @@ SUBSYSTEM_DEF(job)
return
for(var/i in the_mob.client.prefs.chosen_gear)
var/datum/gear/G = i
G = GLOB.loadout_items[slot_to_string(initial(G.category))][initial(G.name)]
G = GLOB.loadout_items[initial(G.category)][initial(G.subcategory)][initial(G.name)]
if(!G)
continue
var/permitted = TRUE
@@ -682,14 +682,14 @@ SUBSYSTEM_DEF(job)
permitted = FALSE
if(G.donoritem && !G.donator_ckey_check(the_mob.client.ckey))
permitted = FALSE
if(!equipbackpackstuff && G.category == SLOT_IN_BACKPACK)//snowflake check since plopping stuff in the backpack doesnt work for pre-job equip loadout stuffs
if(!equipbackpackstuff && G.slot == SLOT_IN_BACKPACK)//snowflake check since plopping stuff in the backpack doesnt work for pre-job equip loadout stuffs
permitted = FALSE
if(equipbackpackstuff && G.category != SLOT_IN_BACKPACK)//ditto
if(equipbackpackstuff && G.slot != SLOT_IN_BACKPACK)//ditto
permitted = FALSE
if(!permitted)
continue
var/obj/item/I = new G.path
if(!M.equip_to_slot_if_possible(I, G.category, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // If the job's dresscode compliant, try to put it in its slot, first
if(!M.equip_to_slot_if_possible(I, G.slot, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // If the job's dresscode compliant, try to put it in its slot, first
if(iscarbon(M))
var/mob/living/carbon/C = M
var/obj/item/storage/backpack/B = C.back
+15 -27
View File
@@ -334,6 +334,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
for (var/map in mapvotes)
if (!map)
mapvotes.Remove(map)
continue
if (!(map in global.config.maplist))
mapvotes.Remove(map)
continue
@@ -468,11 +469,10 @@ GLOBAL_LIST_EMPTY(the_station_areas)
else
return
possible_options += "Custom"
var/lvl_name
var/datum/space_level/level
var/away_name
var/datum/space_level/away_level
var/answer = input("What kind ? ","Away/VR") as null|anything in possible_options
var/answer = input("What kind ? ","Away/VR") as null|anything in list(possible_options + "Custom")
switch(answer)
if(null)
return
@@ -480,34 +480,22 @@ GLOBAL_LIST_EMPTY(the_station_areas)
var/mapfile = input("Pick file:", "File") as null|file
if(!mapfile)
return
lvl_name = "[mapfile] custom"
to_chat(usr,"<span class='notice'>Loading [lvl_name]...</span>")
away_name = "[mapfile] custom"
to_chat(usr,"<span class='notice'>Loading [away_name]...</span>")
var/datum/map_template/template = new(mapfile, choice, ztraits)
level = template.load_new_z(ztraits)
away_level = template.load_new_z(ztraits)
else
lvl_name = answer
to_chat(usr,"<span class='notice'>Loading [lvl_name]...</span>")
var/datum/map_template/template = new(lvl_name, choice)
level = template.load_new_z(ztraits)
away_name = answer
to_chat(usr,"<span class='notice'>Loading [away_name]...</span>")
var/datum/map_template/template = new(away_name, choice)
away_level = template.load_new_z(ztraits)
message_admins("Admin [key_name_admin(usr)] has loaded [lvl_name] [choice].")
log_admin("Admin [key_name(usr)] has loaded [lvl_name] [choice].")
if(!level)
message_admins("Loading [lvl_name] failed!")
message_admins("Admin [key_name_admin(usr)] has loaded [away_name] away mission.")
log_admin("Admin [key_name(usr)] has loaded [away_name] away mission.")
if(!away_level)
message_admins("Loading [away_name] failed!")
return
if(choice == AWAY_MISSION_NAME && GLOB.the_gateway)
//Link any found away gate with station gate
var/obj/machinery/gateway/centeraway/new_gate
for(var/obj/machinery/gateway/centeraway/G in GLOB.machines)
if(G.z == level.z_value) //I'll have to refactor gateway shitcode before multi-away support.
new_gate = G
break
//Link station gate with away gate and remove wait time.
GLOB.the_gateway.awaygate = new_gate
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((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs)
var/datum/turf_reservation/reserve = new type
+22
View File
@@ -268,6 +268,7 @@ SUBSYSTEM_DEF(persistence)
SaveRandomizedRecipes()
SavePanicBunker()
SavePaintings()
SaveScars()
/datum/controller/subsystem/persistence/proc/LoadPanicBunker()
var/bunker_path = file("data/bunker_passthrough.json")
@@ -547,3 +548,24 @@ SUBSYSTEM_DEF(persistence)
var/json_file = file("data/paintings.json")
fdel(json_file)
WRITE_FILE(json_file, json_encode(paintings))
/datum/controller/subsystem/persistence/proc/SaveScars()
for(var/i in GLOB.joined_player_list)
var/mob/living/carbon/human/ending_human = get_mob_by_ckey(i)
if(!istype(ending_human) || !ending_human.mind || !ending_human.client || !ending_human.client.prefs || !ending_human.client.prefs.persistent_scars)
continue
var/mob/living/carbon/human/original_human = ending_human.mind.original_character
if(!original_human || original_human.stat == DEAD || !original_human.all_scars || !(original_human == ending_human))
if(ending_human.client) // i was told if i don't check this every step of the way byond might decide a client ceases to exist mid proc so here we go
ending_human.client.prefs.scars_list["[ending_human.client.prefs.scars_index]"] = ""
else
for(var/k in ending_human.all_wounds)
var/datum/wound/iter_wound = k
iter_wound.remove_wound() // so we can get the scars for open wounds
if(!ending_human.client)
return
ending_human.client.prefs.scars_list["[ending_human.client.prefs.scars_index]"] = ending_human.format_scars()
if(!ending_human.client)
return
ending_human.client.prefs.save_character()
@@ -50,20 +50,17 @@ PROCESSING_SUBSYSTEM_DEF(circuit)
/obj/item/electronic_assembly/simple,
/obj/item/electronic_assembly/hook,
/obj/item/electronic_assembly/pda,
/obj/item/electronic_assembly/dildo,
/obj/item/electronic_assembly/small/default,
/obj/item/electronic_assembly/small/cylinder,
/obj/item/electronic_assembly/small/scanner,
/obj/item/electronic_assembly/small/hook,
/obj/item/electronic_assembly/small/box,
/obj/item/electronic_assembly/small/dildo,
/obj/item/electronic_assembly/medium/default,
/obj/item/electronic_assembly/medium/box,
/obj/item/electronic_assembly/medium/clam,
/obj/item/electronic_assembly/medium/medical,
/obj/item/electronic_assembly/medium/gun,
/obj/item/electronic_assembly/medium/radio,
/obj/item/electronic_assembly/medium/dildo,
/obj/item/electronic_assembly/large/default,
/obj/item/electronic_assembly/large/scope,
/obj/item/electronic_assembly/large/terminal,
@@ -0,0 +1,6 @@
// Smooth HUD updates, but low priority
PROCESSING_SUBSYSTEM_DEF(huds)
name = "HUD updates"
wait = 0.5
priority = FIRE_PRIORITY_HUDS
stat_tag = "HUDS"
+312 -39
View File
@@ -7,10 +7,9 @@ SUBSYSTEM_DEF(shuttle)
flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK
runlevels = RUNLEVEL_SETUP | RUNLEVEL_GAME
var/obj/machinery/shuttle_manipulator/manipulator
var/list/mobile = list()
var/list/stationary = list()
var/list/beacons = list()
var/list/transit = list()
var/list/transit_requesters = list()
@@ -57,6 +56,15 @@ SUBSYSTEM_DEF(shuttle)
var/realtimeofstart = 0
var/datum/map_template/shuttle/selected
var/obj/docking_port/mobile/existing_shuttle
var/obj/docking_port/mobile/preview_shuttle
var/datum/map_template/shuttle/preview_template
var/datum/turf_reservation/preview_reservation
/datum/controller/subsystem/shuttle/Initialize(timeofday)
ordernum = rand(1, 9000)
@@ -76,13 +84,10 @@ SUBSYSTEM_DEF(shuttle)
WARNING("No /obj/docking_port/mobile/emergency/backup placed on the map!")
if(!supply)
WARNING("No /obj/docking_port/mobile/supply placed on the map!")
realtimeofstart = world.realtime
realtimeofstart = world.realtime
return ..()
/datum/controller/subsystem/shuttle/proc/initial_load()
if(!istype(manipulator))
CRASH("No shuttle manipulator found.")
for(var/s in stationary)
var/obj/docking_port/stationary/S = s
S.load_roundstart()
@@ -143,11 +148,13 @@ SUBSYSTEM_DEF(shuttle)
++alive
var/total = GLOB.joined_player_list.len
if(total <= 0)
return //no players no autoevac
if(alive / total <= threshold)
var/msg = "Automatically dispatching shuttle due to crew death."
var/msg = "Automatically dispatching emergency shuttle due to crew death."
message_admins(msg)
log_game("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]")
log_shuttle("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]")
emergencyNoRecall = TRUE
priority_announce("Catastrophic casualties detected: crisis shuttle protocols activated - jamming recall signals across all frequencies.")
if(emergency.timeLeft(1) > emergencyCallTime * 0.4)
@@ -172,6 +179,34 @@ SUBSYSTEM_DEF(shuttle)
return S
WARNING("couldn't find dock with id: [id]")
/datum/controller/subsystem/shuttle/proc/canEvac(mob/user)
var/srd = CONFIG_GET(number/shuttle_refuel_delay)
if(world.time - SSticker.round_start_time < srd)
to_chat(user, "<span class='alert'>The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before trying again.</span>")
return FALSE
switch(emergency.mode)
if(SHUTTLE_RECALL)
to_chat(user, "<span class='alert'>The emergency shuttle may not be called while returning to CentCom.</span>")
return FALSE
if(SHUTTLE_CALL)
to_chat(user, "<span class='alert'>The emergency shuttle is already on its way.</span>")
return FALSE
if(SHUTTLE_DOCKED)
to_chat(user, "<span class='alert'>The emergency shuttle is already here.</span>")
return FALSE
if(SHUTTLE_IGNITING)
to_chat(user, "<span class='alert'>The emergency shuttle is firing its engines to leave.</span>")
return FALSE
if(SHUTTLE_ESCAPE)
to_chat(user, "<span class='alert'>The emergency shuttle is moving away to a safe distance.</span>")
return FALSE
if(SHUTTLE_STRANDED)
to_chat(user, "<span class='alert'>The emergency shuttle has been disabled by CentCom.</span>")
return FALSE
return TRUE
/datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason)
if(!emergency)
WARNING("requestEvac(): There is no emergency shuttle, but the \
@@ -185,35 +220,14 @@ SUBSYSTEM_DEF(shuttle)
manually, and then calling register() on the mobile docking port. \
Good luck.")
emergency = backup_shuttle
var/srd = CONFIG_GET(number/shuttle_refuel_delay)
if(world.time - SSticker.round_start_time < srd)
to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before trying again.")
return
switch(emergency.mode)
if(SHUTTLE_RECALL)
to_chat(user, "The emergency shuttle may not be called while returning to CentCom.")
return
if(SHUTTLE_CALL)
to_chat(user, "The emergency shuttle is already on its way.")
return
if(SHUTTLE_DOCKED)
to_chat(user, "The emergency shuttle is already here.")
return
if(SHUTTLE_IGNITING)
to_chat(user, "The emergency shuttle is firing its engines to leave.")
return
if(SHUTTLE_ESCAPE)
to_chat(user, "The emergency shuttle is moving away to a safe distance.")
return
if(SHUTTLE_STRANDED)
to_chat(user, "The emergency shuttle has been disabled by CentCom.")
return
if(!canEvac(user))
return
call_reason = trim(html_encode(call_reason))
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH && GLOB.security_level > SEC_LEVEL_GREEN)
to_chat(user, "You must provide a reason.")
to_chat(user, "<span class='alert'>You must provide a reason.</span>")
return
var/area/signal_origin = get_area(user)
@@ -235,11 +249,11 @@ SUBSYSTEM_DEF(shuttle)
var/area/A = get_area(user)
log_game("[key_name(user)] has called the shuttle.")
deadchat_broadcast("<span class='deadsay'><span class='name'>[user.real_name]</span> has called the shuttle at <span class='name'>[A.name]</span>.</span>", user)
log_shuttle("[key_name(user)] has called the emergency shuttle.")
deadchat_broadcast(" has called the shuttle at <span class='name'>[A.name]</span>.", "<span class='name'>[user.real_name]</span>", user)
if(call_reason)
SSblackbox.record_feedback("text", "shuttle_reason", 1, "[call_reason]")
log_game("Shuttle call reason: [call_reason]")
log_shuttle("Shuttle call reason: [call_reason]")
message_admins("[ADMIN_LOOKUPFLW(user)] has called the shuttle. (<A HREF='?_src_=holder;[HrefToken()];trigger_centcom_recall=1'>TRIGGER CENTCOM RECALL</A>)")
/datum/controller/subsystem/shuttle/proc/centcom_recall(old_timer, admiral_message)
@@ -272,9 +286,9 @@ SUBSYSTEM_DEF(shuttle)
/datum/controller/subsystem/shuttle/proc/cancelEvac(mob/user)
if(canRecall())
emergency.cancel(get_area(user))
log_game("[key_name(user)] has recalled the shuttle.")
log_shuttle("[key_name(user)] has recalled the shuttle.")
message_admins("[ADMIN_LOOKUPFLW(user)] has recalled the shuttle.")
deadchat_broadcast("<span class='deadsay'><span class='name'>[user.real_name]</span> has recalled the shuttle from <span class='name'>[get_area_name(user, TRUE)]</span>.</span>", user)
deadchat_broadcast(" has recalled the shuttle from <span class='name'>[get_area_name(user, TRUE)]</span>.", "<span class='name'>[user.real_name]</span>", user)
return 1
/datum/controller/subsystem/shuttle/proc/canRecall()
@@ -294,7 +308,7 @@ SUBSYSTEM_DEF(shuttle)
else
if(emergency.timeLeft(1) < emergencyCallTime * 0.25)
return
return 1
return TRUE
/datum/controller/subsystem/shuttle/proc/autoEvac()
if (!SSticker.IsRoundInProgress())
@@ -322,7 +336,7 @@ SUBSYSTEM_DEF(shuttle)
if(callShuttle)
if(EMERGENCY_IDLE_OR_RECALLED)
emergency.request(null, set_coefficient = 2.5)
log_game("There is no means of calling the shuttle anymore. Shuttle automatically called.")
log_shuttle("There is no means of calling the emergency shuttle anymore. Shuttle automatically called.")
message_admins("All the communications consoles were destroyed and all AIs are inactive. Shuttle called.")
/datum/controller/subsystem/shuttle/proc/registerHostileEnvironment(datum/bad)
@@ -559,6 +573,14 @@ SUBSYSTEM_DEF(shuttle)
shuttle_purchased = SSshuttle.shuttle_purchased
lockdown = SSshuttle.lockdown
selected = SSshuttle.selected
existing_shuttle = SSshuttle.existing_shuttle
preview_shuttle = SSshuttle.preview_shuttle
preview_template = SSshuttle.preview_template
preview_reservation = SSshuttle.preview_reservation
/datum/controller/subsystem/shuttle/proc/is_in_shuttle_bounds(atom/A)
var/area/current = get_area(A)
@@ -641,3 +663,254 @@ SUBSYSTEM_DEF(shuttle)
message_admins("Round end vote passed. Shuttle has been auto-called.")
emergencyNoRecall = TRUE
endvote_passed = TRUE
/datum/controller/subsystem/shuttle/proc/action_load(datum/map_template/shuttle/loading_template, obj/docking_port/stationary/destination_port)
// Check for an existing preview
if(preview_shuttle && (loading_template != preview_template))
preview_shuttle.jumpToNullSpace()
preview_shuttle = null
preview_template = null
QDEL_NULL(preview_reservation)
if(!preview_shuttle)
if(load_template(loading_template))
preview_shuttle.linkup(loading_template, destination_port)
preview_template = loading_template
// get the existing shuttle information, if any
var/timer = 0
var/mode = SHUTTLE_IDLE
var/obj/docking_port/stationary/D
if(istype(destination_port))
D = destination_port
else if(existing_shuttle)
timer = existing_shuttle.timer
mode = existing_shuttle.mode
D = existing_shuttle.get_docked()
if(!D)
D = generate_transit_dock(preview_shuttle)
if(!D)
CRASH("No dock found for preview shuttle ([preview_template.name]), aborting.")
var/result = preview_shuttle.canDock(D)
// truthy value means that it cannot dock for some reason
// but we can ignore the someone else docked error because we'll
// be moving into their place shortly
if((result != SHUTTLE_CAN_DOCK) && (result != SHUTTLE_SOMEONE_ELSE_DOCKED))
WARNING("Template shuttle [preview_shuttle] cannot dock at [D] ([result]).")
return
if(existing_shuttle)
existing_shuttle.jumpToNullSpace()
var/list/force_memory = preview_shuttle.movement_force
preview_shuttle.movement_force = list("KNOCKDOWN" = 0, "THROW" = 0)
preview_shuttle.initiate_docking(D)
preview_shuttle.movement_force = force_memory
. = preview_shuttle
// Shuttle state involves a mode and a timer based on world.time, so
// plugging the existing shuttles old values in works fine.
preview_shuttle.timer = timer
preview_shuttle.mode = mode
preview_shuttle.register()
// TODO indicate to the user that success happened, rather than just
// blanking the modification tab
preview_shuttle = null
preview_template = null
existing_shuttle = null
selected = null
QDEL_NULL(preview_reservation)
/datum/controller/subsystem/shuttle/proc/load_template(datum/map_template/shuttle/S)
. = FALSE
// load shuttle template, centred at shuttle import landmark,
preview_reservation = SSmapping.RequestBlockReservation(S.width, S.height, SSmapping.transit.z_value, /datum/turf_reservation/transit)
if(!preview_reservation)
CRASH("failed to reserve an area for shuttle template loading")
var/turf/BL = TURF_FROM_COORDS_LIST(preview_reservation.bottom_left_coords)
S.load(BL, centered = FALSE, register = FALSE)
var/affected = S.get_affected_turfs(BL, centered=FALSE)
var/found = 0
// Search the turfs for docking ports
// - We need to find the mobile docking port because that is the heart of
// the shuttle.
// - We need to check that no additional ports have slipped in from the
// template, because that causes unintended behaviour.
for(var/T in affected)
for(var/obj/docking_port/P in T)
if(istype(P, /obj/docking_port/mobile))
found++
if(found > 1)
qdel(P, force=TRUE)
log_world("Map warning: Shuttle Template [S.mappath] has multiple mobile docking ports.")
else
preview_shuttle = P
if(istype(P, /obj/docking_port/stationary))
log_world("Map warning: Shuttle Template [S.mappath] has a stationary docking port.")
if(!found)
var/msg = "load_template(): Shuttle Template [S.mappath] has no mobile docking port. Aborting import."
for(var/T in affected)
var/turf/T0 = T
T0.empty()
message_admins(msg)
WARNING(msg)
return
//Everything fine
S.post_load(preview_shuttle)
return TRUE
/datum/controller/subsystem/shuttle/proc/unload_preview()
if(preview_shuttle)
preview_shuttle.jumpToNullSpace()
preview_shuttle = null
/datum/controller/subsystem/shuttle/ui_state(mob/user)
return GLOB.admin_state
/datum/controller/subsystem/shuttle/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ShuttleManipulator")
ui.open()
/datum/controller/subsystem/shuttle/ui_data(mob/user)
var/list/data = list()
data["tabs"] = list("Status", "Templates", "Modification")
// Templates panel
data["templates"] = list()
var/list/templates = data["templates"]
data["templates_tabs"] = list()
data["selected"] = list()
for(var/shuttle_id in SSmapping.shuttle_templates)
var/datum/map_template/shuttle/S = SSmapping.shuttle_templates[shuttle_id]
if(!templates[S.port_id])
data["templates_tabs"] += S.port_id
templates[S.port_id] = list(
"port_id" = S.port_id,
"templates" = list())
var/list/L = list()
L["name"] = S.name
L["shuttle_id"] = S.shuttle_id
L["port_id"] = S.port_id
L["description"] = S.description
L["admin_notes"] = S.admin_notes
if(selected == S)
data["selected"] = L
templates[S.port_id]["templates"] += list(L)
data["templates_tabs"] = sortList(data["templates_tabs"])
data["existing_shuttle"] = null
// Status panel
data["shuttles"] = list()
for(var/i in mobile)
var/obj/docking_port/mobile/M = i
var/timeleft = M.timeLeft(1)
var/list/L = list()
L["name"] = M.name
L["id"] = M.id
L["timer"] = M.timer
L["timeleft"] = M.getTimerStr()
if (timeleft > 1 HOURS)
L["timeleft"] = "Infinity"
L["can_fast_travel"] = M.timer && timeleft >= 50
L["can_fly"] = TRUE
if(istype(M, /obj/docking_port/mobile/emergency))
L["can_fly"] = FALSE
else if(!M.destination)
L["can_fast_travel"] = FALSE
if (M.mode != SHUTTLE_IDLE)
L["mode"] = capitalize(M.mode)
L["status"] = M.getDbgStatusText()
if(M == existing_shuttle)
data["existing_shuttle"] = L
data["shuttles"] += list(L)
return data
/datum/controller/subsystem/shuttle/ui_act(action, params)
if(..())
return
var/mob/user = usr
// Preload some common parameters
var/shuttle_id = params["shuttle_id"]
var/datum/map_template/shuttle/S = SSmapping.shuttle_templates[shuttle_id]
switch(action)
if("select_template")
if(S)
existing_shuttle = getShuttle(S.port_id)
selected = S
. = TRUE
if("jump_to")
if(params["type"] == "mobile")
for(var/i in mobile)
var/obj/docking_port/mobile/M = i
if(M.id == params["id"])
user.forceMove(get_turf(M))
. = TRUE
break
if("fly")
for(var/i in mobile)
var/obj/docking_port/mobile/M = i
if(M.id == params["id"])
. = TRUE
M.admin_fly_shuttle(user)
break
if("fast_travel")
for(var/i in mobile)
var/obj/docking_port/mobile/M = i
if(M.id == params["id"] && M.timer && M.timeLeft(1) >= 50)
M.setTimer(50)
. = TRUE
message_admins("[key_name_admin(usr)] fast travelled [M]")
log_admin("[key_name(usr)] fast travelled [M]")
SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[M.name]")
break
if("preview")
if(S)
. = TRUE
unload_preview()
load_template(S)
if(preview_shuttle)
preview_template = S
user.forceMove(get_turf(preview_shuttle))
if("load")
if(existing_shuttle == backup_shuttle)
// TODO make the load button disabled
WARNING("The shuttle that the selected shuttle will replace \
is the backup shuttle. Backup shuttle is required to be \
intact for round sanity.")
else if(S)
. = TRUE
// If successful, returns the mobile docking port
var/obj/docking_port/mobile/mdp = action_load(S)
if(mdp)
user.forceMove(get_turf(mdp))
message_admins("[key_name_admin(usr)] loaded [mdp] with the shuttle manipulator.")
log_admin("[key_name(usr)] loaded [mdp] with the shuttle manipulator.</span>")
SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]")
+330 -16
View File
@@ -1,3 +1,12 @@
/**
* tgui subsystem
*
* Contains all tgui state and subsystem code.
*
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
SUBSYSTEM_DEF(tgui)
name = "tgui"
wait = 9
@@ -5,33 +14,338 @@ SUBSYSTEM_DEF(tgui)
priority = FIRE_PRIORITY_TGUI
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/list/currentrun = list()
var/list/open_uis = list() // A list of open UIs, grouped by src_object and ui_key.
var/list/processing_uis = list() // A list of processing UIs, ungrouped.
var/basehtml // The HTML base used for all UIs.
/// A list of UIs scheduled to process
var/list/current_run = list()
/// A list of open UIs
var/list/open_uis = list()
/// A list of open UIs, grouped by src_object.
var/list/open_uis_by_src = list()
/// The HTML base used for all UIs.
var/basehtml
/datum/controller/subsystem/tgui/PreInit()
basehtml = file2text('tgui-next/packages/tgui/public/tgui-main.html')
basehtml = file2text('tgui/packages/tgui/public/tgui.html')
/datum/controller/subsystem/tgui/Shutdown()
close_all_uis()
/datum/controller/subsystem/tgui/stat_entry()
..("P:[processing_uis.len]")
..("P:[open_uis.len]")
/datum/controller/subsystem/tgui/fire(resumed = 0)
if (!resumed)
src.currentrun = processing_uis.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/datum/tgui/ui = currentrun[currentrun.len]
currentrun.len--
if(!resumed)
src.current_run = open_uis.Copy()
// Cache for sanic speed (lists are references anyways)
var/list/current_run = src.current_run
while(current_run.len)
var/datum/tgui/ui = current_run[current_run.len]
current_run.len--
// TODO: Move user/src_object check to process()
if(ui && ui.user && ui.src_object)
ui.process()
else
processing_uis.Remove(ui)
if (MC_TICK_CHECK)
open_uis.Remove(ui)
if(MC_TICK_CHECK)
return
/**
* public
*
* Requests a usable tgui window from the pool.
* Returns null if pool was exhausted.
*
* required user mob
* return datum/tgui
*/
/datum/controller/subsystem/tgui/proc/request_pooled_window(mob/user)
if(!user.client)
return null
var/list/windows = user.client.tgui_windows
var/window_id
var/datum/tgui_window/window
var/window_found = FALSE
// Find a usable window
for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT)
window_id = TGUI_WINDOW_ID(i)
window = windows[window_id]
// As we are looping, create missing window datums
if(!window)
window = new(user.client, window_id, pooled = TRUE)
// Skip windows with acquired locks
if(window.locked)
continue
if(window.status == TGUI_WINDOW_READY)
return window
if(window.status == TGUI_WINDOW_CLOSED)
window.status = TGUI_WINDOW_LOADING
window_found = TRUE
break
if(!window_found)
log_tgui(user, "Error: Pool exhausted")
return null
return window
/**
* public
*
* Force closes all tgui windows.
*
* required user mob
*/
/datum/controller/subsystem/tgui/proc/force_close_all_windows(mob/user)
log_tgui(user, "force_close_all_windows")
if(user.client)
user.client.tgui_windows = list()
for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT)
var/window_id = TGUI_WINDOW_ID(i)
user << browse(null, "window=[window_id]")
/**
* public
*
* Force closes the tgui window by window_id.
*
* required user mob
* required window_id string
*/
/datum/controller/subsystem/tgui/proc/force_close_window(mob/user, window_id)
log_tgui(user, "force_close_window")
// Close all tgui datums based on window_id.
for(var/datum/tgui/ui in user.tgui_open_uis)
if(ui.window && ui.window.id == window_id)
ui.close(can_be_suspended = FALSE)
// Unset machine just to be sure.
user.unset_machine()
// Close window directly just to be sure.
user << browse(null, "window=[window_id]")
/**
* public
*
* Try to find an instance of a UI, and push an update to it.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional force_open bool If the UI should be re-opened instead of updated.
*
* return datum/tgui The found UI.
*/
/datum/controller/subsystem/tgui/proc/try_update_ui(
mob/user,
datum/src_object,
datum/tgui/ui)
// Look up a UI if it wasn't passed
if(isnull(ui))
ui = get_open_ui(user, src_object)
// Couldn't find a UI.
if(isnull(ui))
return null
ui.process_status()
// UI ended up with the closed status
// or is actively trying to close itself.
// FIXME: Doesn't actually fix the paper bug.
if(ui.status <= UI_CLOSE)
ui.close()
return null
ui.send_update()
return ui
/**
* public
*
* Get a open UI given a user and src_object.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
*
* return datum/tgui The found UI.
*/
/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object)
var/key = "[REF(src_object)]"
// No UIs opened for this src_object
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
return null
for(var/datum/tgui/ui in open_uis_by_src[key])
// Make sure we have the right user
if(ui.user == user)
return ui
return null
/**
* public
*
* Update all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs updated.
*/
/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
var/count = 0
var/key = "[REF(src_object)]"
// No UIs opened for this src_object
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
return count
for(var/datum/tgui/ui in open_uis_by_src[key])
// Check if UI is valid.
if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user))
ui.process(force = 1)
count++
return count
/**
* public
*
* Close all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object)
var/count = 0
var/key = "[REF(src_object)]"
// No UIs opened for this src_object
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
return count
for(var/datum/tgui/ui in open_uis_by_src[key])
// Check if UI is valid.
if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user))
ui.close()
count++
return count
/**
* public
*
* Close all UIs regardless of their attachment to src_object.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/tgui/proc/close_all_uis()
var/count = 0
for(var/key in open_uis_by_src)
for(var/datum/tgui/ui in open_uis_by_src[key])
// Check if UI is valid.
if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user))
ui.close()
count++
return count
/**
* public
*
* Update all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only update UIs belonging this src_object.
*
* return int The number of UIs updated.
*/
/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object)
var/count = 0
if(length(user?.tgui_open_uis) == 0)
return count
for(var/datum/tgui/ui in user.tgui_open_uis)
if(isnull(src_object) || ui.src_object == src_object)
ui.process(force = 1)
count++
return count
/**
* public
*
* Close all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only close UIs belonging this src_object.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object)
var/count = 0
if(length(user?.tgui_open_uis) == 0)
return count
for(var/datum/tgui/ui in user.tgui_open_uis)
if(isnull(src_object) || ui.src_object == src_object)
ui.close()
count++
return count
/**
* private
*
* Add a UI to the list of open UIs.
*
* required ui datum/tgui The UI to be added.
*/
/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui)
var/key = "[REF(ui.src_object)]"
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
open_uis_by_src[key] = list()
ui.user.tgui_open_uis |= ui
var/list/uis = open_uis_by_src[key]
uis |= ui
open_uis |= ui
/**
* private
*
* Remove a UI from the list of open UIs.
*
* required ui datum/tgui The UI to be removed.
*
* return bool If the UI was removed or not.
*/
/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui)
var/key = "[REF(ui.src_object)]"
if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
return FALSE
// Remove it from the list of processing UIs.
open_uis.Remove(ui)
// If the user exists, remove it from them too.
if(ui.user)
ui.user.tgui_open_uis.Remove(ui)
var/list/uis = open_uis_by_src[key]
uis.Remove(ui)
if(length(uis) == 0)
open_uis_by_src.Remove(key)
return TRUE
/**
* private
*
* Handle client logout, by closing all their UIs.
*
* required user mob The mob which logged out.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/tgui/proc/on_logout(mob/user)
close_user_uis(user)
/**
* private
*
* Handle clients switching mobs, by transferring their UIs.
*
* required user source The client's original mob.
* required user target The client's new mob.
*
* return bool If the UIs were transferred.
*/
/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target)
// The old mob had no open UIs.
if(length(source?.tgui_open_uis) == 0)
return FALSE
if(isnull(target.tgui_open_uis) || !istype(target.tgui_open_uis, /list))
target.tgui_open_uis = list()
// Transfer all the UIs.
for(var/datum/tgui/ui in source.tgui_open_uis)
// Inform the UIs of their new owner.
ui.user = target
target.tgui_open_uis.Add(ui)
// Clear the old list.
source.tgui_open_uis.Cut()
return TRUE
+2 -1
View File
@@ -711,7 +711,8 @@ SUBSYSTEM_DEF(ticker)
'sound/roundend/yeehaw.ogg',
'sound/roundend/disappointed.ogg',
'sound/roundend/gondolabridge.ogg',
'sound/roundend/haveabeautifultime.ogg'\
'sound/roundend/haveabeautifultime.ogg',
'sound/roundend/CitadelStationHasSeenBetterDays.ogg'\
)
SEND_SOUND(world, sound(round_end_sound))
+2 -2
View File
@@ -47,7 +47,7 @@ SUBSYSTEM_DEF(title)
. = ..()
if(.)
switch(var_name)
if("icon")
if(NAMEOF(src, icon))
if(splash_turf)
splash_turf.icon = icon
@@ -66,4 +66,4 @@ SUBSYSTEM_DEF(title)
icon = SStitle.icon
splash_turf = SStitle.splash_turf
file_path = SStitle.file_path
previous_icon = SStitle.previous_icon
previous_icon = SStitle.previous_icon
+52 -1
View File
@@ -15,6 +15,8 @@ SUBSYSTEM_DEF(vote)
var/vote_system = PLURALITY_VOTING
var/question = null
var/list/choices = list()
/// List of choice = object for statclick objects for statpanel voting
var/list/choice_statclicks = list()
var/list/scores = list()
var/list/choice_descs = list() // optional descriptions
var/list/voted = list()
@@ -47,7 +49,33 @@ SUBSYSTEM_DEF(vote)
client_popup.open(0)
next_pop = world.time+VOTE_COOLDOWN
/**
* Renders a statpanel. Directly uses statpanel/stat calls since this is called from base of mob/Stat().
*/
/datum/controller/subsystem/vote/proc/render_statpanel(mob/M)
if(!mode) // check if vote is running
return
if(!statpanel("Status")) // don't bother if they're not focused on this panel
return
var/static/list/supported = list(PLURALITY_VOTING, APPROVAL_VOTING)
stat("Vote active!", "There is currently a vote running. Question: [question]")
if(!(vote_system in supported))
stat("<STATPANEL VOTING DISABLED>", "The current vote system is not supported by statpanel rendering. Please vote manually by opening the vote popup using the action button or chat link.")
return
stat("Time Left:", "[round(end_time - world.time)] seconds")
stat(null, null)
stat("Choices:", null)
stat(null, null)
for(var/i in 1 to choice_statclicks.len)
var/choice = choice_statclicks[i]
var/ivotedforthis = FALSE
switch(vote_system)
if(APPROVAL_VOTING)
ivotedforthis = voted[usr.ckey] && (i in voted[usr.ckey])
if(PLURALITY_VOTING)
ivotedforthis = voted[usr.ckey] == i
stat(ivotedforthis? "\[X\]" : "\[ \]", choice_statclicks[choice])
stat(null, null)
/datum/controller/subsystem/vote/proc/reset()
initiator = null
@@ -59,9 +87,26 @@ SUBSYSTEM_DEF(vote)
voted.Cut()
voting.Cut()
scores.Cut()
cleanup_statclicks()
display_votes = initial(display_votes) //CIT CHANGE - obfuscated votes
remove_action_buttons()
/datum/controller/subsystem/vote/proc/cleanup_statclicks()
for(var/choice in choice_statclicks)
qdel(choice_statclicks[choice])
choice_statclicks = list()
/obj/effect/statclick/vote
name = "ERROR"
var/choice
/obj/effect/statclick/vote/Click()
SSvote.submit_vote(choice)
/obj/effect/statclick/vote/New(loc, choice, name)
src.choice = choice
src.name = name
/datum/controller/subsystem/vote/proc/get_result()
//get the highest number of votes
var/greatest_votes = 0
@@ -536,6 +581,12 @@ SUBSYSTEM_DEF(vote)
vp = CONFIG_GET(number/vote_period)
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=[REF(src)]'>here</a> to place your votes.\nYou have [DisplayTimeText(vp)] to vote.</font>")
end_time = started_time+vp
// generate statclick list
cleanup_statclicks()
for(var/i in 1 to choices.len)
var/choice = choices[i]
choice_statclicks[choice] = new /obj/effect/statclick/vote(null, i, choice)
//
for(var/c in GLOB.clients)
SEND_SOUND(c, sound('sound/misc/server-ready.ogg'))
var/client/C = c
+17 -10
View File
@@ -431,25 +431,31 @@
if(!owner)
owner = M
/datum/ai_laws/proc/get_law_list(include_zeroth = 0, show_numbers = 1)
/**
* Generates a list of all laws on this datum, including rendered HTML tags if required
*
* Arguments:
* * include_zeroth - Operator that controls if law 0 or law 666 is returned in the set
* * show_numbers - Operator that controls if law numbers are prepended to the returned laws
* * render_html - Operator controlling if HTML tags are rendered on the returned laws
*/
/datum/ai_laws/proc/get_law_list(include_zeroth = FALSE, show_numbers = TRUE, render_html = TRUE)
var/list/data = list()
if (include_zeroth && devillaws && devillaws.len)
for(var/i in devillaws)
data += "[show_numbers ? "666:" : ""] <font color='#cc5500'>[i]</font>"
if (include_zeroth && devillaws)
for(var/law in devillaws)
data += "[show_numbers ? "666:" : ""] [render_html ? "<font color='#cc5500'>[law]</font>" : law]"
if (include_zeroth && zeroth)
data += "[show_numbers ? "0:" : ""] <font color='#ff0000'><b>[zeroth]</b></font>"
data += "[show_numbers ? "0:" : ""] [render_html ? "<font color='#ff0000'><b>[zeroth]</b></font>" : zeroth]"
for(var/law in hacked)
if (length(law) > 0)
var/num = ionnum()
data += "[show_numbers ? "[num]:" : ""] <font color='#660000'>[law]</font>"
data += "[show_numbers ? "[ionnum()]:" : ""] [render_html ? "<font color='#660000'>[law]</font>" : law]"
for(var/law in ion)
if (length(law) > 0)
var/num = ionnum()
data += "[show_numbers ? "[num]:" : ""] <font color='#547DFE'>[law]</font>"
data += "[show_numbers ? "[ionnum()]:" : ""] [render_html ? "<font color='#547DFE'>[law]</font>" : law]"
var/number = 1
for(var/law in inherent)
@@ -459,6 +465,7 @@
for(var/law in supplied)
if (length(law) > 0)
data += "[show_numbers ? "[number]:" : ""] <font color='#990099'>[law]</font>"
data += "[show_numbers ? "[number]:" : ""] [render_html ? "<font color='#990099'>[law]</font>" : law]"
number++
return data
+15 -12
View File
@@ -1,9 +1,9 @@
#define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]-[magic]"
#define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]-[magic]-[wound]"
/proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
/proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, wound = 0)
. = locate(ARMORID)
if (!.)
. = new /datum/armor(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic)
. = new /datum/armor(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic, wound)
/datum/armor
datum_flags = DF_USE_TAG
@@ -17,8 +17,9 @@
var/fire
var/acid
var/magic
var/wound
/datum/armor/New(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
/datum/armor/New(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, wound = 0)
src.melee = melee
src.bullet = bullet
src.laser = laser
@@ -29,15 +30,16 @@
src.fire = fire
src.acid = acid
src.magic = magic
src.wound = wound
tag = ARMORID
/datum/armor/proc/modifyRating(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
return getArmor(src.melee+melee, src.bullet+bullet, src.laser+laser, src.energy+energy, src.bomb+bomb, src.bio+bio, src.rad+rad, src.fire+fire, src.acid+acid, src.magic+magic)
/datum/armor/proc/modifyRating(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, wound = 0)
return getArmor(src.melee+melee, src.bullet+bullet, src.laser+laser, src.energy+energy, src.bomb+bomb, src.bio+bio, src.rad+rad, src.fire+fire, src.acid+acid, src.magic+magic, src.wound+wound)
/datum/armor/proc/modifyAllRatings(modifier = 0)
return getArmor(melee+modifier, bullet+modifier, laser+modifier, energy+modifier, bomb+modifier, bio+modifier, rad+modifier, fire+modifier, acid+modifier, magic+modifier)
return getArmor(melee+modifier, bullet+modifier, laser+modifier, energy+modifier, bomb+modifier, bio+modifier, rad+modifier, fire+modifier, acid+modifier, magic+modifier, wound+modifier)
/datum/armor/proc/setRating(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic)
/datum/armor/proc/setRating(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic, wound)
return getArmor((isnull(melee) ? src.melee : melee),\
(isnull(bullet) ? src.bullet : bullet),\
(isnull(laser) ? src.laser : laser),\
@@ -47,19 +49,20 @@
(isnull(rad) ? src.rad : rad),\
(isnull(fire) ? src.fire : fire),\
(isnull(acid) ? src.acid : acid),\
(isnull(magic) ? src.magic : magic))
(isnull(magic) ? src.magic : magic),\
(isnull(wound) ? src.wound : wound))
/datum/armor/proc/getRating(rating)
return vars[rating]
/datum/armor/proc/getList()
return list("melee" = melee, "bullet" = bullet, "laser" = laser, "energy" = energy, "bomb" = bomb, "bio" = bio, "rad" = rad, "fire" = fire, "acid" = acid, "magic" = magic)
return list("melee" = melee, "bullet" = bullet, "laser" = laser, "energy" = energy, "bomb" = bomb, "bio" = bio, "rad" = rad, "fire" = fire, "acid" = acid, "magic" = magic, "wound" = wound)
/datum/armor/proc/attachArmor(datum/armor/AA)
return getArmor(melee+AA.melee, bullet+AA.bullet, laser+AA.laser, energy+AA.energy, bomb+AA.bomb, bio+AA.bio, rad+AA.rad, fire+AA.fire, acid+AA.acid, magic+AA.magic)
return getArmor(melee+AA.melee, bullet+AA.bullet, laser+AA.laser, energy+AA.energy, bomb+AA.bomb, bio+AA.bio, rad+AA.rad, fire+AA.fire, acid+AA.acid, magic+AA.magic, wound+AA.wound)
/datum/armor/proc/detachArmor(datum/armor/AA)
return getArmor(melee-AA.melee, bullet-AA.bullet, laser-AA.laser, energy-AA.energy, bomb-AA.bomb, bio-AA.bio, rad-AA.rad, fire-AA.fire, acid-AA.acid, magic-AA.magic)
return getArmor(melee-AA.melee, bullet-AA.bullet, laser-AA.laser, energy-AA.energy, bomb-AA.bomb, bio-AA.bio, rad-AA.rad, fire-AA.fire, acid-AA.acid, magic-AA.magic, wound-AA.wound)
/datum/armor/vv_edit_var(var_name, var_value)
if (var_name == NAMEOF(src, tag))
+221
View File
@@ -0,0 +1,221 @@
//similar to dog_fashion, but for beepsky, who has far more refined fashion tastes
/datum/beepsky_fashion
var/name //not setting the name and desc makes them go to the default
var/desc
var/icon_file = 'icons/mob/secbot_accessories.dmi' //we sell secbots and secbot accessories
var/obj_icon_state
var/obj_alpha
var/obj_color
var/list/stun_sounds //sound that replaces the stun attack when set
var/ignore_sound = FALSE //whether to ignore sounds entirely or not
//emotes (don't set them if you want the default value)
var/death_emote //what is said when beepsky dies
var/capture_one //what is said when cuffing someone
var/capture_two //what is said when cuffing someone, directly to the person being cuffed
var/infraction //the level of threat detected
var/taunt // beepsky pointing at a criminal
var/attack_one //text when attacking criminal
var/attack_two //text when attacking criminal, but directly to the criminal
var/patrol_emote //engaging patrol text
var/patrol_fail_emote //failing to engage patrol text
var/list/arrest_texts //first is for not-cuffing, second is for cuffing
var/arrest_emote //text stating that you're cuffing some criminal C with a threat of level X in location Y
//for reference, the following words are replaced when processed before speech:
//LOCATION = the location passed, if any (this is only used by arrest_emote)
//CRIMINAL = the name of the criminal (this is used by everything but patrol_emote and infraction)
//BOT = the name of the bot (this can be used on any of the emotes)
//THREAT_LEVEL = the level of the threat detected (can be used on arrest_emote and infraction)
/datum/beepsky_fashion/proc/get_overlay(var/dir)
if(icon_file && obj_icon_state)
var/image/beepsky_overlay = image(icon_file, obj_icon_state, dir = dir)
beepsky_overlay.alpha = obj_alpha
beepsky_overlay.color = obj_color
return beepsky_overlay
/datum/beepsky_fashion/proc/stun_attack(mob/living/carbon/C) //fired when beepsky does a stun attack with the fashion worn, for sounds/overlays/etc
return
//actual fashions from here on out
/datum/beepsky_fashion/wizard
obj_icon_state = "wizard"
name = "Archmage Beepsky"
desc = "A secbot stolen from the wizard federation."
death_emote = "BOT casts EI NATH on themselves!"
capture_one = "BOT is casting cable ties on CRIMINAL!"
capture_two = "BOT is casting cable ties on you!"
infraction = "Magical disturbance of magnitude THREAT_LEVEL detected!"
taunt = "BOT points his staff towards CRIMINAL!"
attack_one = "BOT casts magic missile on CRIMINAL!"
attack_two = "BOT casts magic missile on you!"
patrol_emote = "Beginning search for magical disturbances."
patrol_fail_emote = "Failure to find magical disturbances. Recallibrating."
arrest_emote = "ARREST_TYPE level THREAT_LEVEL magical practitioner CRIMINAL in LOCATION."
stun_sounds = list('sound/magic/lightningbolt.ogg',
'sound/magic/fireball.ogg',
'sound/weapons/zapbang.ogg',
'sound/magic/knock.ogg',
'sound/magic/fleshtostone.ogg',
'sound/effects/magic.ogg',
'sound/magic/disintegrate.ogg')
/datum/beepsky_fashion/cowboy
obj_icon_state = "cowboy"
name = "Sheriff Beepsky"
desc = "The sheriff of this here station."
capture_one = "BOT is tying CRIMINAL up!"
capture_two = "BOT is tying you up!"
infraction = "Outlaws with a bounty of THREAT_LEVEL000 space dollars detected!"
taunt = "BOT aims his revolver towards CRIMINAL!"
attack_one = "BOT unloads his revolver onto CRIMINAL!"
attack_two = "BOT unloads his revolver onto you!"
patrol_emote = "Engaging bounty hunting protocols."
patrol_fail_emote = "Unable to find any bounties due to error. Rebooting."
arrest_emote = "ARREST_TYPE outlaw CRIMINAL with a bounty of THREAT_LEVEL000 in LOCATION."
stun_sounds = list('sound/weapons/Gunshot.ogg',
'sound/weapons/Gunshot2.ogg',
'sound/weapons/Gunshot3.ogg',
'sound/weapons/Gunshot4.ogg')
/datum/beepsky_fashion/chef
obj_icon_state = "chef"
name = "Chef Beepsky"
desc = "Cooking up the finest foods the station has ever seen."
death_emote = "Mamma-mia!"
infraction = "Grade THREAT_LEVEL prosciutto detected!"
taunt = "BOT glares at CRIMINAL."
attack_one = "BOT CQCs CRIMINAL!"
attack_two = "BOT CQCs you!"
patrol_emote = "Beginning search for the bad prosciutto."
patrol_fail_emote = "All prosciutto is stale. Rebooting."
arrest_texts = list("Frying", "Grilling") //any good secoff knows the difference
arrest_emote = "ARREST_TYPE grade THREAT_LEVEL prosciutto CRIMINAL in LOCATION."
stun_sounds = list('sound/weapons/cqchit1.ogg',
'sound/weapons/cqchit2.ogg')
/datum/beepsky_fashion/cat
obj_icon_state = "cat"
name = "OwOfficer Bweepskwee"
desc = "A beepsky unit with cat ears. Catgirl science has gone too far."
death_emote = "Nya!"
capture_one = "BOT is tying CRIMINAL up!!"
capture_two = "BOT is tying you up!"
infraction = "Wevel THREAT_LEVEL infwactwion awert!!!"
taunt = "BOT points at CRIMINAL and nyas!"
attack_one = "BOT shoves CRIMINAL onto a table!"
attack_two = "BOT shoves you onto a table!"
patrol_emote = "Enwgagwing patwol mwodies.."
patrol_fail_emote = "Unawbwle two stwawt patwollies. Nya."
arrest_texts = list("Dwetwaining", "Awwesting")
arrest_emote = "ARREST_TYPE wevel THREAT_LEVEL scwumbwag CRIMINAL in LOCATION. Nya."
ignore_sound = TRUE //we instead make the stunned person fire the nya emote
/datum/beepsky_fashion/cat/stun_attack(var/mob/living/carbon/C) //makes a fake table under you on hit, makes cat people nya when hit
if(iscatperson(C))
C.emote("nya")
var/turf/target_turf = get_turf(C)
if(target_turf) //slams you on a fake table
playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
var/obj/effect/overlay_holder = new(target_turf)
overlay_holder.name = "Catboy Table"
overlay_holder.desc = "Where bad catboys go."
var/image/table_overlay = image('icons/obj/smooth_structures/table.dmi', "table")
overlay_holder.add_overlay(table_overlay)
QDEL_IN(overlay_holder, 10)
/datum/beepsky_fashion/cake //nothing else. it's just beepsky. with a cake on his head.
obj_icon_state = "cake"
name = "Cakesky"
desc = "It's a secbot, wearing a cake on his head!"
/datum/beepsky_fashion/captain
obj_icon_state = "captain"
name = "Captainsky"
desc = "The real captain of this station."
capture_one = "BOT is lecturing CRIMINAL on why he is the captain!"
capture_two = "BOT is lecturing you on why he is the captain!"
infraction = "Level THREAT_LEVEL greytider detected."
attack_one = "BOT beats CRIMINAL with the chain of command!"
attack_two = "BOT beats you with the chain of command!"
patrol_emote = "Uselessness protocols engaged."
patrol_fail_emote = "Unit has been found as useless. Rebooting."
arrest_texts = list("Demoting", "Firing")
arrest_emote = "ARREST_TYPE level THREAT_LEVEL lesser crewmember CRIMINAL in LOCATION."
stun_sounds = list('sound/weapons/chainhit.ogg')
/datum/beepsky_fashion/king
obj_icon_state = "king"
name = "King Beepsky"
desc = "He who has ascended to bare the right of king, sits atop the throne."
capture_one = "BOT is calling the guards onto CRIMINAL!"
capture_two = "BOT is calling the guards onto you!"
infraction = "Treason of level THREAT_LEVEL detected!"
attack_one = "BOT strikes CRIMINAL with his kingly authority!"
attack_two = "BOT strikes you with his kingly authority!"
patrol_emote = "Searching for peasants to beat up."
patrol_fail_emote = "Peasants are using dark magic. Recallibrating."
arrest_texts = list("Knighting", "Executing")
arrest_emote = "ARREST_TYPE level THREAT_LEVEL peasant CRIMINAL in LOCATION."
stun_sounds = list('sound/weapons/punch1.ogg',
'sound/weapons/punch2.ogg',
'sound/weapons/punch3.ogg',
'sound/weapons/punch4.ogg')
/datum/beepsky_fashion/pirate
obj_icon_state = "pirate"
name = "Beepsbeard the Pirate"
desc = "Sailor of the seven seas, all sea-faring bots fear the one known as Beepsbeard."
capture_one = "BOT is making CRIMINAL walk the plank!"
capture_two = "BOT is making you walk the plank!"
infraction = "Enemy vessel spotted with threat level THREAT_LEVEL!"
attack_one = "BOT strikes CRIMINAL with his cutlass!"
attack_two = "BOT strikes you with his cutlass!"
patrol_emote = "Searching for enemy vessels to board."
patrol_fail_emote = "No way to engage enemy vessels. Rebooting."
arrest_texts = list("Boarding", "Sinking")
arrest_emote = "ARREST_TYPE level THREAT_LEVEL vessel CRIMINAL in LOCATION."
stun_sounds = list('sound/weapons/bladeslice.ogg')
/datum/beepsky_fashion/engineer
obj_icon_state = "engineer"
name = "Chief Engineer Beepsky"
desc = "He fixes criminals with a wrench to the face."
capture_one = "BOT is tying CRIMINAL up!"
capture_two = "BOT is tying you up!"
infraction = "Structural integrity issue spotted with threat level THREAT_LEVEL"
attack_one = "BOT strikes CRIMINAL with his wrench!"
attack_two = "BOT strikes you with his wrench!"
arrest_texts = list("Fixing", "Repairing")
arrest_emote = "ARREST_TYPE level THREAT_LEVEL structural issue in LOCATION"
stun_sounds = list('sound/weapons/genhit.ogg')
/datum/beepsky_fashion/tophat
obj_icon_state = "tophat"
name = "Fancy Beepsky"
desc = "It's a secbot, wearing a top hat! How fancy."
/datum/beepsky_fashion/fedora
obj_icon_state = "fedora"
name = "Fedorasky"
desc = "It's a secbot, wearing a fedora!"
/datum/beepsky_fashion/sombrero
obj_icon_state = "sombrero"
name = "Sombrerosky"
desc = "A secbot wearing a sombrero. Truly, a hombre to all."
/datum/beepsky_fashion/santa
obj_icon_state = "santa"
name = "Saint Beepsky"
desc = "Have you been a level 7 infraction this holiday season?"
capture_one = "BOT is tying CRIMINAL up with fairy lights!"
capture_two = "BOT is tying you up with fairy lights!"
infraction = "Level THREAT_LEVEL threat to holiday cheer spotted!"
attack_one = "BOT crushes CRIMINAL with their holiday spirit!"
attack_two = "BOT crushes you with their holiday spirit!"
arrest_emote = "ARREST_TYPE level THREAT_LEVEL threat to holiday cheer in LOCATION"
+1 -1
View File
@@ -94,7 +94,7 @@
if(get_dist(owner, stalker) <= 1)
playsound(owner, 'sound/magic/demon_attack1.ogg', 50)
owner.visible_message("<span class='warning'>[owner] is torn apart by invisible claws!</span>", "<span class='userdanger'>Ghostly claws tear your body apart!</span>")
owner.take_bodypart_damage(rand(20, 45))
owner.take_bodypart_damage(rand(20, 45), wound_bonus=CANT_WOUND)
else if(prob(50))
stalker.forceMove(get_step_towards(stalker, owner))
if(get_dist(owner, stalker) <= 8)
+1 -2
View File
@@ -103,8 +103,7 @@
. = ..()
QDEL_IN(src, 300)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/effect/hallucination/simple/bluespace_stream/attack_hand(mob/user)
/obj/effect/hallucination/simple/bluespace_stream/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user != seer || !linked_to)
return
var/slip_in_message = pick("slides sideways in an odd way, and disappears", "jumps into an unseen dimension",\
+6 -3
View File
@@ -2,7 +2,7 @@
var/speed = 80 //time in deciseconds taken to butcher something
var/effectiveness = 100 //percentage effectiveness; numbers above 100 yield extra drops
var/bonus_modifier = 0 //percentage increase to bonus item chance
var/butcher_sound = 'sound/weapons/slice.ogg' //sound played when butchering
var/butcher_sound = 'sound/effects/butcher.ogg' //sound played when butchering
var/butchering_enabled = TRUE
var/can_be_blunt = FALSE
@@ -64,8 +64,11 @@
H.visible_message("<span class='danger'>[user] slits [H]'s throat!</span>", \
"<span class='userdanger'>[user] slits your throat...</span>")
log_combat(user, H, "finishes slicing the throat of")
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD)
H.bleed_rate = clamp(H.bleed_rate + 20, 0, 30)
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) // easy tiger, we'll get to that in a sec
var/obj/item/bodypart/slit_throat = H.get_bodypart(BODY_ZONE_HEAD)
if(slit_throat)
var/datum/wound/slash/critical/screaming_through_a_slit_throat = new
screaming_through_a_slit_throat.apply_wound(slit_throat)
H.apply_status_effect(/datum/status_effect/neck_slice)
/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
+1 -1
View File
@@ -48,7 +48,7 @@
var/damage = rand(min_damage, max_damage)
if(HAS_TRAIT(H, TRAIT_LIGHT_STEP))
damage *= 0.75
H.apply_damage(damage, BRUTE, picked_def_zone)
H.apply_damage(damage, BRUTE, picked_def_zone, wound_bonus = CANT_WOUND)
if(cooldown < world.time - 10) //cooldown to avoid message spam.
if(!H.incapacitated(ignore_restraints = TRUE))

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