Merge branch 'master' into cool-ipcs

This commit is contained in:
Timothy Teakettle
2020-06-19 01:57:02 +01:00
committed by GitHub
500 changed files with 50897 additions and 303103 deletions
@@ -22,8 +22,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
//FLAGS BITMASK
///This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not.
#define HEAR_1 (1<<3)
///Projectiels will check ricochet on things impacted that have this.
#define CHECK_RICOCHET_1 (1<<4)
///Projectiles will use default chance-based ricochet handling on things with this.
#define DEFAULT_RICOCHET_1 (1<<4)
///Conducts electricity (metal etc.).
#define CONDUCT_1 (1<<5)
///For machines and structures that should not break into parts, eg, holodeck stuff.
@@ -137,3 +137,12 @@ 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)
#define RICOCHET_HARD (1<<1)
@@ -1,20 +1,3 @@
// Flags for the obj_flags var on /obj
#define EMAGGED (1<<0)
#define IN_USE (1<<1) //If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
#define CAN_BE_HIT (1<<2) //can this be bludgeoned by items?
#define BEING_SHOCKED (1<<3) //Whether this thing is currently (already) being shocked by a tesla
#define DANGEROUS_POSSESSION (1<<4) //Admin possession yes/no
#define ON_BLUEPRINTS (1<<5) //Are we visible on the station blueprints at roundstart?
#define UNIQUE_RENAME (1<<6) //can you customize the description/name of the thing?
#define USES_TGUI (1<<7) //put on things that use tgui on ui_interact instead of custom/old UI.
#define FROZEN (1<<8)
#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)
// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
// Flags for the item_flags var on /obj/item
#define BEING_REMOVED (1<<0)
@@ -41,6 +24,10 @@
#define NO_UNIFORM_REQUIRED (1<<11)
///Damage when attacking people is not affected by combat mode.
#define NO_COMBAT_MODE_FORCE_MODIFIER (1<<12)
/// This item can be used to parry. Only a basic check used to determine if we should proceed with parry chain at all.
#define ITEM_CAN_PARRY (1<<13)
/// This item can be used in the directional blocking system. Only a basic check used to determine if we should proceed with directional block handling at all.
#define ITEM_CAN_BLOCK (1<<14)
// Flags for the clothing_flags var on /obj/item/clothing
+15
View File
@@ -0,0 +1,15 @@
// Flags for the obj_flags var on /obj
#define EMAGGED (1<<0)
#define IN_USE (1<<1) //If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
#define CAN_BE_HIT (1<<2) //can this be bludgeoned by items?
#define BEING_SHOCKED (1<<3) //Whether this thing is currently (already) being shocked by a tesla
#define DANGEROUS_POSSESSION (1<<4) //Admin possession yes/no
#define ON_BLUEPRINTS (1<<5) //Are we visible on the station blueprints at roundstart?
#define UNIQUE_RENAME (1<<6) //can you customize the description/name of the thing?
#define USES_TGUI (1<<7) //put on things that use tgui on ui_interact instead of custom/old UI.
#define FROZEN (1<<8)
#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)
// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
+11
View File
@@ -11,6 +11,17 @@
#define NUKE_RESULT_WRONG_STATION 7
#define NUKE_RESULT_WRONG_STATION_DEAD 8
//fugitive end results
#define FUGITIVE_RESULT_BADASS_HUNTER 0
#define FUGITIVE_RESULT_POSTMORTEM_HUNTER 1
#define FUGITIVE_RESULT_MAJOR_HUNTER 2
#define FUGITIVE_RESULT_HUNTER_VICTORY 3
#define FUGITIVE_RESULT_MINOR_HUNTER 4
#define FUGITIVE_RESULT_STALEMATE 5
#define FUGITIVE_RESULT_MINOR_FUGITIVE 6
#define FUGITIVE_RESULT_FUGITIVE_VICTORY 7
#define FUGITIVE_RESULT_MAJOR_FUGITIVE 8
#define APPRENTICE_DESTRUCTION "destruction"
#define APPRENTICE_BLUESPACE "bluespace"
#define APPRENTICE_ROBELESS "robeless"
+1
View File
@@ -59,6 +59,7 @@
#define ANTAG_HUD_CLOCKWORK 22
#define ANTAG_HUD_BROTHER 23
#define ANTAG_HUD_BLOODSUCKER 24
#define ANTAG_HUD_FUGITIVE 25
// Notification action types
#define NOTIFY_JUMP "jump"
+33 -86
View File
@@ -29,10 +29,11 @@
#define EFFECT_DROWSY "drowsy"
#define EFFECT_JITTER "jitter"
// mob/living/var/combat_flags variable.
/// Default combat flags for those affected by sprinting (combat mode has been made into its own component)
#define COMBAT_FLAGS_DEFAULT NONE
#define COMBAT_FLAGS_DEFAULT (COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE)
/// Default combat flags for everyone else (so literally everyone but humans).
#define COMBAT_FLAGS_SPRINT_EXEMPT (COMBAT_FLAG_SPRINT_ACTIVE | COMBAT_FLAG_SPRINT_TOGGLED | COMBAT_FLAG_SPRINT_FORCED)
#define COMBAT_FLAGS_SPRINT_EXEMPT (COMBAT_FLAG_SPRINT_ACTIVE | COMBAT_FLAG_SPRINT_TOGGLED | COMBAT_FLAG_SPRINT_FORCED | COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE)
/// The user wants sprint mode on
#define COMBAT_FLAG_SPRINT_TOGGLED (1<<0)
@@ -50,6 +51,16 @@
#define COMBAT_FLAG_SOFT_STAMCRIT (1<<6)
/// Force sprint mode on at all times, overrides everything including sprint disable traits.
#define COMBAT_FLAG_SPRINT_FORCED (1<<7)
/// This mob is capable of using the active parrying system.
#define COMBAT_FLAG_PARRY_CAPABLE (1<<8)
/// This mob is capable of using the active blocking system.
#define COMBAT_FLAG_BLOCK_CAPABLE (1<<9)
/// This mob is capable of unarmed parrying
#define COMBAT_FLAG_UNARMED_PARRY (1<<10)
/// This mob is currently actively blocking
#define COMBAT_FLAG_ACTIVE_BLOCKING (1<<11)
/// This mob is currently starting an active block
#define COMBAT_FLAG_ACTIVE_BLOCK_STARTING (1<<12)
// Helpers for getting someone's stamcrit state. Cast to living.
#define NOT_STAMCRIT 0
@@ -112,18 +123,6 @@
#define GRAB_NECK 2
#define GRAB_KILL 3
/// Attack types for check_block()/run_block(). Flags, combinable.
/// Attack was melee, whether or not armed.
#define ATTACK_TYPE_MELEE (1<<0)
/// Attack was with a gun or something that should count as a gun (but not if a gun shouldn't count for a gun, crazy right?)
#define ATTACK_TYPE_PROJECTILE (1<<1)
/// Attack was unarmed.. this usually means hand to hand combat.
#define ATTACK_TYPE_UNARMED (1<<2)
/// Attack was a thrown atom hitting the victim.
#define ATTACK_TYPE_THROWN (1<<3)
/// Attack was a bodyslam/leap/tackle. See: Xenomorph leap tackles.
#define ATTACK_TYPE_TACKLE (1<<4)
//attack visual effects
#define ATTACK_EFFECT_PUNCH "punch"
#define ATTACK_EFFECT_KICK "kick"
@@ -164,9 +163,8 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
/obj/item/gun)))
//Combat object defines
//Embedded objects
#define EMBEDDED_PAIN_CHANCE 15 //Chance for embedded objects to cause pain (damage user)
#define EMBEDDED_ITEM_FALLOUT 5 //Chance for embedded object to fall out (causing pain but removing the object)
#define EMBED_CHANCE 45 //Chance for an object to embed into somebody when thrown (if it's sharp)
@@ -175,7 +173,16 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define EMBEDDED_IMPACT_PAIN_MULTIPLIER 4 //Coefficient of multiplication for the damage the item does when it first embeds (this*item.w_class)
#define EMBED_THROWSPEED_THRESHOLD 4 //The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1)
#define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 8 //Coefficient of multiplication for the damage the item does when removed without a surgery (this*item.w_class)
#define EMBEDDED_UNSAFE_REMOVAL_TIME 150 //A Time in ticks, total removal time = (this/item.w_class)
#define EMBEDDED_UNSAFE_REMOVAL_TIME 30 //A Time in ticks, total removal time = (this*item.w_class)
#define EMBEDDED_JOSTLE_CHANCE 5 //Chance for embedded objects to cause pain every time they move (jostle)
#define EMBEDDED_JOSTLE_PAIN_MULTIPLIER 1 //Coefficient of multiplication for the damage the item does while
#define EMBEDDED_PAIN_STAM_PCT 0.0 //This percentage of all pain will be dealt as stam damage rather than brute (0-1)
#define EMBED_CHANCE_TURF_MOD -15 //You are this many percentage points less likely to embed into a turf (good for things glass shards and spears vs walls)
#define EMBED_HARMLESS list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE)
#define EMBED_HARMLESS_SUPERIOR list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE, "embed_chance" = 100, "fall_chance" = 0.1)
#define EMBED_POINTY list("ignore_throwspeed_threshold" = TRUE)
#define EMBED_POINTY_SUPERIOR list("embed_chance" = 100, "ignore_throwspeed_threshold" = TRUE)
//Gun weapon weight
#define WEAPON_LIGHT 1
@@ -190,6 +197,14 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define EGUN_SELFCHARGE 1
#define EGUN_SELFCHARGE_BORG 2
//Gun suppression
#define SUPPRESSED_NONE 0
#define SUPPRESSED_QUIET 1 ///standard suppressed
#define SUPPRESSED_VERY 2 /// no message
//Nice shot bonus
#define NICE_SHOT_RICOCHET_BONUS 10 //if the shooter has the NICE_SHOT trait and they fire a ricocheting projectile, add this to the ricochet chance and auto aim angle
///Time to spend without clicking on other things required for your shots to become accurate.
#define GUN_AIMING_TIME (2 SECONDS)
@@ -273,72 +288,4 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
* should the current-attack-damage be lower than the item force multiplied by this value,
* a "inefficiently" prefix will be added to the message.
*/
#define INEFFICIENT_ATTACK_MSG_THRESHOLD 0.7
//bullet_act() return values
#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
/// Check whether or not we can block, without "triggering" a block. Basically run checks without effects like depleting shields.
/// Wrapper for do_run_block(). The arguments on that means the same as for this.
#define mob_check_block(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)\
do_run_block(FALSE, object, damage, attack_text, attack_type, armour_penetration, attacker, check_zone(def_zone), return_list)
/// Runs a block "sequence", effectively checking and then doing effects if necessary.
/// Wrapper for do_run_block(). The arguments on that means the same as for this.
#define mob_run_block(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)\
do_run_block(TRUE, object, damage, attack_text, attack_type, armour_penetration, attacker, check_zone(def_zone), return_list)
/// Bitflags for check_block() and run_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
/// Attack was not blocked
#define BLOCK_NONE NONE
/// Attack was blocked, do not do damage. THIS FLAG MUST BE THERE FOR DAMAGE/EFFECT PREVENTION!
#define BLOCK_SUCCESS (1<<1)
/// The below are for "metadata" on "how" the attack was blocked.
/// Attack was and should be redirected according to list argument REDIRECT_METHOD (NOTE: the SHOULD here is important, as it says "the thing blocking isn't handling the reflecting for you so do it yourself"!)
#define BLOCK_SHOULD_REDIRECT (1<<2)
/// Attack was redirected (whether by us or by SHOULD_REDIRECT flagging for automatic handling)
#define BLOCK_REDIRECTED (1<<3)
/// Attack was blocked by something like a shield.
#define BLOCK_PHYSICAL_EXTERNAL (1<<4)
/// Attack was blocked by something worn on you.
#define BLOCK_PHYSICAL_INTERNAL (1<<5)
/// Attack outright missed because the target dodged. Should usually be combined with redirection passthrough or something (see martial arts)
#define BLOCK_TARGET_DODGED (1<<7)
/// Meta-flag for run_block/do_run_block : By default, BLOCK_SUCCESS tells do_run_block() to assume the attack is completely blocked and not continue the block chain. If this is present, it will continue to check other items in the chain rather than stopping.
#define BLOCK_CONTINUE_CHAIN (1<<8)
/// For keys in associative list/block_return as we don't want to saturate our (somewhat) limited flags.
#define BLOCK_RETURN_REDIRECT_METHOD "REDIRECT_METHOD"
/// Pass through victim
#define REDIRECT_METHOD_PASSTHROUGH "passthrough"
/// Deflect at randomish angle
#define REDIRECT_METHOD_DEFLECT "deflect"
/// reverse 180 angle, basically (as opposed to "realistic" wall reflections)
#define REDIRECT_METHOD_REFLECT "reflect"
/// "do not taser the bad man with the desword" - actually aims at the firer/attacker rather than just reversing
#define REDIRECT_METHOD_RETURN_TO_SENDER "no_you"
/// These keys are generally only applied to the list if real_attack is FALSE. Used incase we want to make "smarter" mob AI in the future or something.
/// Tells the caller how likely from 0 (none) to 100 (always) we are to reflect energy projectiles
#define BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE "reflect_projectile_chance"
/// Tells the caller how likely we are to block attacks from 0 to 100 in general
#define BLOCK_RETURN_NORMAL_BLOCK_CHANCE "normal_block_chance"
/// Tells the caller about how many hits we can soak on average before our blocking fails.
#define BLOCK_RETURN_BLOCK_CAPACITY "block_capacity"
/// Default if the above isn't set in the list.
#define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_DEFLECT
/// Block priorities
#define BLOCK_PRIORITY_HELD_ITEM 100
#define BLOCK_PRIORITY_WEAR_SUIT 75
#define BLOCK_PRIORITY_CLOTHING 50
#define BLOCK_PRIORITY_UNIFORM 25
#define BLOCK_PRIORITY_DEFAULT BLOCK_PRIORITY_HELD_ITEM
#define FEEBLE_ATTACK_MSG_THRESHOLD 0.5
+32
View File
@@ -0,0 +1,32 @@
// Attack types for check_block()/run_block(). Flags, combinable.
/// Attack was melee, whether or not armed.
#define ATTACK_TYPE_MELEE (1<<0)
/// Attack was with a gun or something that should count as a gun (but not if a gun shouldn't count for a gun, crazy right?)
#define ATTACK_TYPE_PROJECTILE (1<<1)
/// Attack was unarmed.. this usually means hand to hand combat.
#define ATTACK_TYPE_UNARMED (1<<2)
/// Attack was a thrown atom hitting the victim.
#define ATTACK_TYPE_THROWN (1<<3)
/// Attack was a bodyslam/leap/tackle. See: Xenomorph leap tackles.
#define ATTACK_TYPE_TACKLE (1<<4)
/// Attack was from a parry counterattack. Do not attempt to parry-this!
#define ATTACK_TYPE_PARRY_COUNTERATTACK (1<<5)
// Requires for datum definitions to not error with must be a constant statement when used in lists as text associative keys.
// KEEP IN SYNC WITH ABOVE!
#define TEXT_ATTACK_TYPE_MELEE "1"
#define TEXT_ATTACK_TYPE_PROJECTILE "2"
#define TEXT_ATTACK_TYPE_UNARMED "4"
#define TEXT_ATTACK_TYPE_THROWN "8"
#define TEXT_ATTACK_TYPE_TACKLE "16"
#define TEXT_ATTACK_TYPE_PARRY_COUNTERATTACK "32"
GLOBAL_LIST_INIT(attack_type_names, list(
TEXT_ATTACK_TYPE_MELEE = "Melee",
TEXT_ATTACK_TYPE_PROJECTILE = "Projectile",
TEXT_ATTACK_TYPE_UNARMED = "Unarmed",
TEXT_ATTACK_TYPE_THROWN = "Thrown",
TEXT_ATTACK_TYPE_TACKLE = "Tackle",
TEXT_ATTACK_TYPE_PARRY_COUNTERATTACK = "Parry Counterattack"
))
+80
View File
@@ -0,0 +1,80 @@
/// Check whether or not we can block, without "triggering" a block. Basically run checks without effects like depleting shields.
/// Wrapper for do_run_block(). The arguments on that means the same as for this.
#define mob_check_block(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)\
do_run_block(FALSE, object, damage, attack_text, attack_type, armour_penetration, attacker, check_zone(def_zone), return_list)
/// Runs a block "sequence", effectively checking and then doing effects if necessary.
/// Wrapper for do_run_block(). The arguments on that means the same as for this.
#define mob_run_block(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)\
do_run_block(TRUE, object, damage, attack_text, attack_type, armour_penetration, attacker, check_zone(def_zone), return_list)
// Don't ask why there's block_parry.dm and this. This is for the run_block() system, which is the "parent" system of the directional block and parry systems.
/// Bitflags for check_block() and handle_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
/// Attack was not blocked
#define BLOCK_NONE NONE
/// Attack was blocked, do not do damage. THIS FLAG MUST BE THERE FOR DAMAGE/EFFECT PREVENTION!
#define BLOCK_SUCCESS (1<<1)
/// The below are for "metadata" on "how" the attack was blocked.
/// Attack was and should be redirected according to list argument REDIRECT_METHOD (NOTE: the SHOULD here is important, as it says "the thing blocking isn't handling the reflecting for you so do it yourself"!)
#define BLOCK_SHOULD_REDIRECT (1<<2)
/// Attack was redirected (whether by us or by SHOULD_REDIRECT flagging for automatic handling)
#define BLOCK_REDIRECTED (1<<3)
/// Attack was blocked by something like a shield.
#define BLOCK_PHYSICAL_EXTERNAL (1<<4)
/// Attack was blocked by something worn on you.
#define BLOCK_PHYSICAL_INTERNAL (1<<5)
/// Attack outright missed because the target dodged. Should usually be combined with redirection passthrough or something (see martial arts)
#define BLOCK_TARGET_DODGED (1<<7)
/// Meta-flag for run_block/do_run_block : By default, BLOCK_SUCCESS tells do_run_block() to assume the attack is completely blocked and not continue the block chain. If this is present, it will continue to check other items in the chain rather than stopping.
#define BLOCK_CONTINUE_CHAIN (1<<8)
/// Attack should change the amount of damage incurred. This means something calling run_block() has to handle it!
#define BLOCK_SHOULD_CHANGE_DAMAGE (1<<9)
/// Attack should scale by this percent, 0 for no block and 100 for full blocked
#define BLOCK_SHOULD_PARTIAL_MITIGATE (1<<10)
/// For keys in associative list/block_return as we don't want to saturate our (somewhat) limited flags.
#define BLOCK_RETURN_REDIRECT_METHOD "REDIRECT_METHOD"
/// Pass through victim
#define REDIRECT_METHOD_PASSTHROUGH "passthrough"
/// Deflect at randomish angle
#define REDIRECT_METHOD_DEFLECT "deflect"
/// reverse 180 angle, basically (as opposed to "realistic" wall reflections)
#define REDIRECT_METHOD_REFLECT "reflect"
/// "do not taser the bad man with the desword" - actually aims at the firer/attacker rather than just reversing
#define REDIRECT_METHOD_RETURN_TO_SENDER "no_you"
/// These keys are generally only applied to the list if real_attack is FALSE. Used incase we want to make "smarter" mob AI in the future or something.
/// Tells the caller how likely from 0 (none) to 100 (always) we are to reflect energy projectiles
#define BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE "reflect_projectile_chance"
/// Tells the caller how likely we are to block attacks from 0 to 100 in general
#define BLOCK_RETURN_NORMAL_BLOCK_CHANCE "normal_block_chance"
/// Tells the caller about how many hits we can soak on average before our blocking fails.
#define BLOCK_RETURN_BLOCK_CAPACITY "block_capacity"
/// Tells the caller we got blocked by active directional block.
#define BLOCK_RETURN_ACTIVE_BLOCK "active_block"
/// Tells the caller our damage mitigation for their attack.
#define BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATED "damage_mitigated"
/// For [BLOCK_CHANGE_DAMAGE]. Set damage to this.
#define BLOCK_RETURN_SET_DAMAGE_TO "set_damage_to"
/// For [BLOCK_SHOULD_PARTIAL_MITIGATE]. Percentage mitigation.
#define BLOCK_RETURN_MITIGATION_PERCENT "partial_mitigation"
/// Used internally by run_parry proc, use on an on_active_parry() proc to override parrying efficiency.
#define BLOCK_RETURN_OVERRIDE_PARRY_EFFICIENCY "override_parry_efficiency"
/// Always set to 100 by run_block() if BLOCK_SUCCESS is in return value. Otherwise, defaults to mitigation percent if not set. Used by projectile/proc/on_hit().
#define BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE "projectile_block_percentage"
/// Default if the above isn't set in the list.
#define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_DEFLECT
/// Block priorities. Higher means it's checked sooner.
// THESE MUST NEVER BE 0! Block code uses ! instead of isnull for the speed boost.
#define BLOCK_PRIORITY_ACTIVE_BLOCK 200
#define BLOCK_PRIORITY_HELD_ITEM 100
#define BLOCK_PRIORITY_CLOTHING 50
#define BLOCK_PRIORITY_WEAR_SUIT 75
#define BLOCK_PRIORITY_UNIFORM 25
#define BLOCK_PRIORITY_DEFAULT BLOCK_PRIORITY_HELD_ITEM
+72
View File
@@ -0,0 +1,72 @@
// We can't determine things like NORTHEAST vs NORTH *and* EAST without making our own flags :(
#define BLOCK_DIR_NORTH (1<<0)
#define BLOCK_DIR_NORTHEAST (1<<1)
#define BLOCK_DIR_NORTHWEST (1<<2)
#define BLOCK_DIR_WEST (1<<3)
#define BLOCK_DIR_EAST (1<<4)
#define BLOCK_DIR_SOUTH (1<<5)
#define BLOCK_DIR_SOUTHEAST (1<<6)
#define BLOCK_DIR_SOUTHWEST (1<<7)
#define BLOCK_DIR_ONTOP (1<<8)
GLOBAL_LIST_INIT(dir2blockdir, list(
"[NORTH]" = BLOCK_DIR_NORTH,
"[NORTHEAST]" = BLOCK_DIR_NORTHEAST,
"[NORTHWEST]" = BLOCK_DIR_NORTHWEST,
"[WEST]" = BLOCK_DIR_WEST,
"[EAST]" = BLOCK_DIR_EAST,
"[SOUTH]" = BLOCK_DIR_SOUTH,
"[SOUTHEAST]" = BLOCK_DIR_SOUTHEAST,
"[SOUTHWEST]" = BLOCK_DIR_SOUTHWEST,
"[NONE]" = BLOCK_DIR_ONTOP
))
#define DIR2BLOCKDIR(d) (GLOB.dir2blockdir["[d]"])
GLOBAL_LIST_INIT(block_direction_names, list(
"[BLOCK_DIR_NORTH]" = "Front",
"[BLOCK_DIR_NORTHEAST]" = "Front Right",
"[BLOCK_DIR_NORTHWEST]" = "Front Left",
"[BLOCK_DIR_WEST]" = "Left",
"[BLOCK_DIR_EAST]" = "Right",
"[BLOCK_DIR_SOUTH]" = "Behind",
"[BLOCK_DIR_SOUTHEAST]" = "Behind Right",
"[BLOCK_DIR_SOUTHWEST]" = "Behind Left",
"[BLOCK_DIR_ONTOP]" = "Ontop"
))
/// If this is the value of active_block_starting it signals we want to interrupt the start
#define ACTIVE_BLOCK_STARTING_INTERRUPT "INTERRUPT"
/// ""types"" of parry "items"
#define UNARMED_PARRY "unarmed"
#define MARTIAL_PARRY "martial"
#define ITEM_PARRY "item"
/// Parry phase we're in
#define NOT_PARRYING 0
#define PARRY_WINDUP 1
#define PARRY_ACTIVE 2
#define PARRY_SPINDOWN 3
// /datum/block_parry_data/var/parry_flags
/// Default handling for audio/visual feedback
#define PARRY_DEFAULT_HANDLE_FEEDBACK (1<<0)
/// Lock sprinting while parrying
#define PARRY_LOCK_SPRINTING (1<<1)
/// Lock attacking while parrying
#define PARRY_LOCK_ATTACKING (1<<2)
/// Parry effects.
/// Automatically melee attacks back normally, LMB equivalent action of an harm intent attack. List association should be defaulting to 1, being the attack damage multiplier for said counterattack
#define PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN "melee_counterattack_chain"
/// List association should be TRUE.
#define PARRY_DISARM_ATTACKER "disarm_attacker"
/// List association should be duration or null for just plain knockdown.
#define PARRY_KNOCKDOWN_ATTACKER "knockdown_attacker"
/// List association should be duration.
#define PARRY_STAGGER_ATTACKER "stagger_attacker"
/// List association should be amount of time to daze attacker.
#define PARRY_DAZE_ATTACKER "daze_attacker"
/// Set to TRUE in list association to ignore adjacency checks
#define PARRY_COUNTERATTACK_IGNORE_ADJACENCY "ignore_adjacency"
+3 -1
View File
@@ -67,7 +67,9 @@
//tablecrafting defines
#define CAT_NONE ""
#define CAT_WEAPONRY "Weaponry"
#define CAT_WEAPON "Weapons"
#define CAT_WEAPON "Ranged Weapons"
#define CAT_MELEE "Melee Weapons"
#define CAT_OTHER "Misc"
#define CAT_AMMO "Ammunition"
#define CAT_PARTS "Weapon Parts"
#define CAT_ROBOT "Robots"
+20
View File
@@ -26,6 +26,11 @@
#define COMPONENT_ADD_TRAIT (1<<0)
#define COMPONENT_REMOVE_TRAIT (1<<1)
/// fires on the target datum when an element is attached to it (/datum/element)
#define COMSIG_ELEMENT_ATTACH "element_attach"
/// fires on the target datum when an element is attached to it (/datum/element)
#define COMSIG_ELEMENT_DETACH "element_detach"
// /atom signals
#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
@@ -231,6 +236,8 @@
#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
#define COMSIG_CARBON_EMBED_RIP "item_embed_start_rip" // defined twice, in carbon and human's topics, fired when interacting with a valid embedded_object to pull it out (mob/living/carbon/target, /obj/item, /obj/item/bodypart/L)
#define COMSIG_CARBON_EMBED_REMOVAL "item_embed_remove_safe" // called when removing a given item from a mob, from mob/living/carbon/remove_embedded_object(mob/living/carbon/target, /obj/item)
// /mob/living/silicon signals
#define COMSIG_ROBOT_UPDATE_ICONS "robot_update_icons" //from base of robot/update_icons(): ()
@@ -277,9 +284,15 @@
#define COMSIG_ITEM_MOUSE_EXIT "item_mouse_exit" //from base of obj/item/MouseExited(): (location, control, params)
#define COMSIG_ITEM_MOUSE_ENTER "item_mouse_enter" //from base of obj/item/MouseEntered(): (location, control, params)
#define COMSIG_ITEM_DECONSTRUCTOR_DEEPSCAN "deconstructor_deepscan" //Called by deconstructive analyzers deepscanning an item: (obj/machinery/rnd/destructive_analyzer/analyzer_machine, mob/user, list/information_list)
#define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed" ///from [/obj/item/proc/disableEmbedding]:
#define COMSIG_MINE_TRIGGERED "minegoboom" ///from [/obj/effect/mine/proc/triggermine]:
// Uncovered information
#define COMPONENT_DEEPSCAN_UNCOVERED_INFORMATION 1
// /obj/item/grenade signals
#define COMSIG_GRENADE_PRIME "grenade_prime" //called in /obj/item/gun/process_fire (user, target, params, zone_override)
#define COMSIG_GRENADE_ARMED "grenade_armed" //called in /obj/item/gun/process_fire (user, target, params, zone_override)
// /obj/item/clothing signals
#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
#define COMSIG_SUIT_MADE_HELMET "suit_made_helmet" //from base of obj/item/clothing/suit/MakeHelmet(): (helmet)
@@ -307,8 +320,15 @@
#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_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_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
#define COMSIG_PELLET_CLOUD_INIT "pellet_cloud_init" // sent to targets during the process_hit proc of projectiles
// /mob/living/carbon/human signals
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
+16
View File
@@ -33,3 +33,19 @@
#define ID_NO_BANK_ACCOUNT 0
#define ID_FREE_BANK_ACCOUNT 1
#define ID_LOCKED_BANK_ACCOUNT 2
//Some price defines to help standarize the intended vending value of items. Do not bother adding too many examples.
#define PRICE_FREE 0 // Sustainance/soviet vendor stuff.
#define PRICE_CHEAP_AS_FREE 10 // Cheap lighters, syringes, soft drinks etc.
#define PRICE_REALLY_CHEAP 20 // Snacks, hot drinks, tools.
#define PRICE_PRETTY_CHEAP 30 // Some snacks, beer.
#define PRICE_CHEAP 40 // Clothings. some electronics
#define PRICE_ALMOST_CHEAP 60 // Fancy clothing, cig packs, booze-o-mat, seeds, medical.
#define PRICE_BELOW_NORMAL 80 // Clothesmate and kinkmate premium stuff.
#define PRICE_NORMAL 100 // Kitchen knife, other stuff.
#define PRICE_ABOVE_NORMAL 150 // Liberation (capitalism ahoy) and donksoft vendors.
#define PRICE_ALMOST_EXPENSIVE 200 // Butcher knife, cartridges, some premium stuff.
#define PRICE_EXPENSIVE 325 // Premium stuff.
#define PRICE_ABOVE_EXPENSIVE 500 // RCD, Crew pinpointer/monitor, galoshes
#define PRICE_REALLY_EXPENSIVE 700 // More premium stuff.
#define PRICE_ALMOST_ONE_GRAND 900 // $$$ Insulated gloves, backpack water-tank spray $$$
+32
View File
@@ -0,0 +1,32 @@
/// Requires absolute stillness from the user
#define DO_AFTER_DISALLOW_MOVING_ABSOLUTE_USER (1<<0)
/// Requires absolute stillness from the target
#define DO_AFTER_DISALLOW_MOVING_ABSOLUTE_TARGET (1<<1)
/// Requires that the user is on a turf.
#define DO_AFTER_REQUIRES_USER_ON_TURF (1<<2)
/// Requires relative stillness to our target via dx and dy coordinate difference but only if both are spacedrifting. Specify DO_AFTER_ALLOW_NONSPACEDRIFT_RELATIVITY to say otherwise.
#define DO_AFTER_DISALLOW_MOVING_RELATIVE (1<<3)
/// Breaks if active hand item changes. Requires a tool be specified, otherwise defaults to active item
#define DO_AFTER_DISALLOW_ACTIVE_ITEM_CHANGE (1<<4)
/// Breaks if the user has no free hands. If a tool is specified, allows that as well.
#define DO_AFTER_REQUIRE_FREE_HAND_OR_TOOL (1<<5)
/// Do not display progressbar.
#define DO_AFTER_NO_PROGRESSBAR (1<<6)
/// Do not check do_after_coefficient()
#define DO_AFTER_NO_COEFFICIENT (1<<7)
/// For relative stillness, allow non spacedrift relative movement
#define DO_AFTER_ALLOW_NONSPACEDRIFT_RELATIVITY (1<<8)
/// Ignores checks.
#define DO_AFTER_PROCEED "PROCEED"
/// Uses all other checks
#define DO_AFTER_CONTINUE "CONTINUE"
/// Breaks
#define DO_AFTER_STOP "STOP"
/// Stage - initiating a do_after
#define DO_AFTER_STARTING 1
/// Stage - main loop of a do_after
#define DO_AFTER_PROGRESSING 2
/// Stage - Last check of a do_after
#define DO_AFTER_FINISHING 3
+9
View File
@@ -1,3 +1,6 @@
/// Checks if something is a BYOND object datatype rather than a primitive, or whatever's closest to one.
#define is_object_datatype(object) (object && !ispath(object) && !istext(object) && !isnum(object))
// simple is_type and similar inline helpers
#define in_range(source, user) (get_dist(source, user) <= 1 && (get_step(source, 0)?:z) == (get_step(user, 0)?:z))
@@ -178,6 +181,12 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isitem(A) (istype(A, /obj/item))
#define isgrenade(A) (istype(A, /obj/item/grenade))
#define islandmine(A) (istype(A, /obj/effect/mine))
#define isammocasing(A) (istype(A, /obj/item/ammo_casing))
#define isidcard(I) (istype(I, /obj/item/card/id))
#define isstructure(A) (istype(A, /obj/structure))
+25
View File
@@ -88,3 +88,28 @@
#define EMISSIVE_BLOCK_GENERIC 1
/// Uses a dedicated render_target object to copy the entire appearance in real time to the blocking layer. For things that can change in appearance a lot from the base state, like humans.
#define EMISSIVE_BLOCK_UNIQUE 2
/// Returns the red part of a #RRGGBB hex sequence as number
#define GETREDPART(hexa) hex2num(copytext(hexa, 2, 4))
/// Returns the green part of a #RRGGBB hex sequence as number
#define GETGREENPART(hexa) hex2num(copytext(hexa, 4, 6))
/// Returns the blue part of a #RRGGBB hex sequence as number
#define GETBLUEPART(hexa) hex2num(copytext(hexa, 6, 8))
/// Parse the hexadecimal color into lumcounts of each perspective.
#define PARSE_LIGHT_COLOR(source) \
do { \
if (source.light_color) { \
var/__light_color = source.light_color; \
source.lum_r = GETREDPART(__light_color) / 255; \
source.lum_g = GETGREENPART(__light_color) / 255; \
source.lum_b = GETBLUEPART(__light_color) / 255; \
} else { \
source.lum_r = 1; \
source.lum_g = 1; \
source.lum_b = 1; \
}; \
} while (FALSE)
+64 -1
View File
@@ -8,5 +8,68 @@
//ids
#define MOVESPEED_ID_SANITY "mood_sanity"
#define MOVESPEED_ID_MOB_GRAB_STATE "mob_grab_state"
#define MOVESPEED_ID_MOB_WALK_RUN_CONFIG_SPEED "MOB_WALK_RUN"
#define MOVESPEED_ID_MOB_GRAB_STATE "MOB_GRAB_STATE"
#define MOVESPEED_ID_MOB_EQUIPMENT "MOB_EQUIPMENT"
#define MOVESPEED_ID_MOB_GRAVITY "MOB_GRAVITY"
#define MOVESPEED_ID_CONFIG_SPEEDMOD "MOB_CONFIG_MODIFIER"
#define MOVESPEED_ID_SLIME_REAGENTMOD "SLIME_REAGENT_MODIFIER"
#define MOVESPEED_ID_SLIME_HEALTHMOD "SLIME_HEALTH_MODIFIER"
#define MOVESPEED_ID_SLIME_TEMPMOD "SLIME_TEMPERATURE_MODIFIER"
#define MOVESPEED_ID_SLIME_STATUS "SLIME_STATUS"
#define MOVESPEED_ID_TARANTULA_WEB "TARANTULA_WEB"
#define MOVESPEED_ID_LIVING_TURF_SPEEDMOD "LIVING_TURF_SPEEDMOD"
#define MOVESPEED_ID_LIVING_LIMBLESS "LIVING_LIMBLESS"
#define MOVESPEED_ID_CARBON_SOFTCRIT "CARBON_SOFTCRIT"
#define MOVESPEED_ID_CARBON_OLDSPEED "CARBON_DEPRECATED_SPEED"
#define MOVESPEED_ID_DNA_VAULT "DNA_VAULT"
#define MOVESPEED_ID_YELLOW_ORB "YELLOW_ORB"
#define MOVESPEED_ID_TARFOOT "TARFOOT"
#define MOVESPEED_ID_SEPIA "SEPIA"
#define MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD "MONKEY_REAGENT_SPEEDMOD"
#define MOVESPEED_ID_MONKEY_TEMPERATURE_SPEEDMOD "MONKEY_TEMPERATURE_SPEEDMOD"
#define MOVESPEED_ID_MONKEY_HEALTH_SPEEDMOD "MONKEY_HEALTH_SPEEDMOD"
#define MOVESPEED_ID_CHANGELING_MUSCLES "CHANGELING_MUSCLES"
#define MOVESPEED_ID_SIMPLEMOB_VARSPEED "SIMPLEMOB_VARSPEED_MODIFIER"
#define MOVESPEED_ID_ADMIN_VAREDIT "ADMIN_VAREDIT_MODIFIER"
#define MOVESPEED_ID_PAI_SPACEWALK_SPEEDMOD "PAI_SPACEWALK_MODIFIER"
#define MOVESPEED_ID_SPECIES "SPECIES_SPEED_MOD"
#define MOVESPEED_ID_PRONE_DRAGGING "PRONE_DRAG"
#define MOVESPEED_ID_HUMAN_CARRYING "HUMAN_CARRY"
#define MOVESPEED_ID_SHRINK_RAY "SHRUNKEN_SPEED_MODIFIER"
#define MOVESPEED_ID_SLAUGHTER "SLAUGHTER"
#define MOVESPEED_ID_CYBER_THRUSTER "CYBER_IMPLANT_THRUSTER"
#define MOVESPEED_ID_JETPACK "JETPACK"
#define MOVESPEED_ID_MKULTRA "MKULTRA"
#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"
#define MOVESPEED_ID_DAMAGE_SLOWDOWN "DAMAGE"
#define MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING "FLYING"
#define MOVESPEED_ID_ACTIVE_BLOCK "ACTIVE_BLOCK"
#define MOVESPEED_ID_MOB_WALK_RUN "mob_walk_run"
+14
View File
@@ -0,0 +1,14 @@
/// This atom should be ricocheted off of from its inherent properties using standard % chance handling.
#define PROJECTILE_RICOCHET_YES 1
/// This atom should not be ricocheted off of from its inherent properties.
#define PROJECTILE_RICOCHET_NO 2
/// This atom should prevent any kind of projectile ricochet from its inherent properties.
#define PROJECTILE_RICOCHET_PREVENT 3
/// This atom should force a projectile ricochet from its inherent properties.
#define PROJECTILE_RICOCHET_FORCE 4
//bullet_act() return values
#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
+1
View File
@@ -27,6 +27,7 @@
#define BOT_NAV 15 // computing navigation
#define BOT_WAIT_FOR_NAV 16 // waiting for nav computation
#define BOT_NO_ROUTE 17 // no destination beacon found (or no route)
#define BOT_TIPPED 18 // someone tipped a medibot over ;_;
//Bot types
#define SEC_BOT (1<<0) // Secutritrons (Beepsky) and ED-209s
+2
View File
@@ -7,6 +7,8 @@
#define SHUTTLE_STRANDED "stranded"
#define SHUTTLE_ESCAPE "escape"
#define SHUTTLE_ENDGAME "endgame: game over"
#define SHUTTLE_RECHARGING "recharging"
#define SHUTTLE_PREARRIVAL "landing"
#define EMERGENCY_IDLE_OR_RECALLED (SSshuttle.emergency && ((SSshuttle.emergency.mode == SHUTTLE_IDLE) || (SSshuttle.emergency.mode == SHUTTLE_RECALL)))
#define EMERGENCY_ESCAPED_OR_ENDGAMED (SSshuttle.emergency && ((SSshuttle.emergency.mode == SHUTTLE_ESCAPE) || (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)))
+2
View File
@@ -96,6 +96,8 @@
#define STATUS_EFFECT_SPASMS /datum/status_effect/spasms //causes random muscle spasms
#define STATUS_EFFECT_FAKE_VIRUS /datum/status_effect/fake_virus //gives you fluff messages for cough, sneeze, headache, etc but without an actual virus
#define STATUS_EFFECT_BREASTS_ENLARGEMENT /datum/status_effect/chem/breast_enlarger //Applied slowdown due to the ominous bulk.
#define STATUS_EFFECT_PENIS_ENLARGEMENT /datum/status_effect/chem/penis_enlarger //More applied slowdown, just like the above.
+1 -1
View File
@@ -24,7 +24,7 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list(
// Let's keep all of this in one place. given what we put above anyways..
// volume amount for items
#define ITEM_VOLUME_DISK DEFAULT_VOLUME_TINY
#define ITEM_VOLUME_DISK 1
// #define SAMPLE_VOLUME_AMOUNT 2
+3
View File
@@ -18,6 +18,7 @@
#define VALENTINES "Valentine's Day"
#define APRIL_FOOLS "April Fool's Day"
#define EASTER "Easter"
#define PRIDE_MONTH "Pride Month"
#define HALLOWEEN "Halloween"
#define CHRISTMAS "Christmas"
#define FESTIVE_SEASON "Festive Season"
@@ -38,6 +39,8 @@ When using time2text(), please use "DDD" to find the weekday. Refrain from using
#define SATURDAY "Sat"
#define SUNDAY "Sun"
#define WEEKDAY2NUM(D) (D == SUNDAY ? 1 : D == MONDAY ? 2 : D == TUESDAY ? 3 : D == WEDNESDAY ? 4 : D == THURSDAY ? 5 : D == FRIDAY ? 6 : 7) //this looks ugly, but switch statements can't be used as vars, so *shrug
#define SECONDS *10
#define MINUTES SECONDS*60
+9 -1
View File
@@ -67,6 +67,8 @@
#define TRAIT_BLIND "blind"
#define TRAIT_MUTE "mute"
#define TRAIT_EMOTEMUTE "emotemute"
#define TRAIT_LOOC_MUTE "looc_mute" //Just like unconsciousness, it disables LOOC salt.
#define TRAIT_AOOC_MUTE "aooc_mute" //Same as above but for AOOC.
#define TRAIT_DEAF "deaf"
#define TRAIT_NEARSIGHT "nearsighted"
#define TRAIT_FAT "fat"
@@ -195,6 +197,7 @@
#define TRAIT_MUTATION_STASIS "mutation_stasis" //Prevents processed genetics mutations from processing.
#define TRAIT_FAST_PUMP "fast_pump"
#define TRAIT_NO_PROCESS_FOOD "no-process-food" // You don't get benefits from nutriment, nor nutrition from reagent consumables
#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)
@@ -255,7 +258,7 @@
#define BOOK_TRAIT "granter (book)" // knowledge is power
// unique trait sources, still defines
#define STATUE_MUTE "statue"
#define STATUE_TRAIT "statue"
#define CLONING_POD_TRAIT "cloning-pod"
#define VIRTUAL_REALITY_TRAIT "vr_trait"
#define CHANGELING_DRAIN "drain"
@@ -296,3 +299,8 @@
#define CLOWNOP_TRAIT "clown-op"
#define MEGAFAUNA_TRAIT "megafauna"
#define DEATHSQUAD_TRAIT "deathsquad"
/// This trait is added by the active directional block system.
#define ACTIVE_BLOCK_TRAIT "active_block"
/// This trait is added by the parry system.
#define ACTIVE_PARRY_TRAIT "active_parry"
#define STICKY_NODROP "sticky-nodrop" //sticky nodrop sounds like a bad soundcloud rapper's name
+1
View File
@@ -170,6 +170,7 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
newA.setup(str)
newA.set_dynamic_lighting()
newA.has_gravity = oldA.has_gravity
newA.noteleport = oldA.noteleport
else
newA = area_choice
+1 -1
View File
@@ -104,7 +104,7 @@ GLOBAL_VAR_INIT(cmp_field, "name")
var/a_sign = num2sign(initial(A.value) * -1)
var/b_sign = num2sign(initial(B.value) * -1)
// Neutral traits go last.
// Neutral traits go last
if(a_sign == 0)
a_sign = 2
if(b_sign == 0)
+323
View File
@@ -0,0 +1,323 @@
/**
* Higher overhead "advanced" version of do_after.
* @params
* - atom/user is the atom doing the action or the "physical" user
* - delay is time in deciseconds
* - atom/target is the atom the action is being done to, defaults to user
* - do_after_flags see __DEFINES/flags/do_after.dm for details.
* - datum/callback/extra_checks - Every time this ticks, extra_checks() is invoked with (user, delay, target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool).
* Stage can be DO_AFTER_STARTING, DO_AFTER_PROGRESSING, DO_AFTER_FINISHING
* If it returns DO_AFTER_STOP, this breaks.
* If it returns nothing, all other checks are done.
* If it returns DO_AFTER_PROCEED, all other checks are ignored.
* - required_mobility_flags is checked with CHECK_ALL_MOBILITY. Will immediately fail if the user isn't a mob.
* - requried_combat_flags is checked with CHECK_MULTIPLE_BITFIELDS. Will immediately fail if the user isn't a mob.
* - mob/living/mob_redirect - advanced option: If this is specified, movement and mobility/combat flag checks will use this instead of user. Progressbars will also go to this.
* - obj/item/tool - The tool we're using. See do_after flags for details.
*/
#define INVOKE_CALLBACK cb_return = extra_checks?.Invoke(user, delay, target, world.time - starttime, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool)
#define CHECK_FLAG_FAILURE ((required_mobility_flags || required_combat_flags) && (!living_user || (required_mobility_flags && !CHECK_ALL_MOBILITY(living_user, required_mobility_flags)) || (required_combat_flags && !CHECK_MULTIPLE_BITFIELDS(living_user.combat_flags, required_combat_flags))))
#define TIMELEFT (world.time - starttime)
/proc/do_after_advanced(atom/user, delay, atom/target, do_after_flags, datum/callback/extra_checks, required_mobility_flags, required_combat_flags, mob/living/mob_redirect, obj/item/tool)
// CHECK AND SET VARIABLES
if(!user)
return FALSE
if(!target)
target = user
if((user.loc == null) || (target.loc == null))
return FALSE
var/mob/living/living_user = mob_redirect
if(!living_user && isliving(user))
living_user = user
var/stage = DO_AFTER_STARTING
var/startlocuser = user.loc
var/startloctarget = target.loc
var/turf/userturf = get_turf(user)
var/turf/targetturf = get_turf(target)
if(!userturf || !targetturf)
return FALSE
if((do_after_flags & DO_AFTER_REQUIRES_USER_ON_TURF) && !isturf(user.loc))
return FALSE
var/starttime = world.time
var/endtime = world.time + delay
var/obj/item/initially_held_item = mob_redirect?.get_active_held_item()
if(!(do_after_flags & DO_AFTER_NO_COEFFICIENT) && living_user)
delay *= living_user.do_after_coefficent()
var/atom/movable/AM_user = ismovable(user) && user
var/drifting = AM_user?.Process_Spacemove(NONE) && AM_user.inertia_dir
var/initial_dx = targetturf.x - userturf.x
var/initial_dy = targetturf.y - userturf.y
var/dx = initial_dx
var/dy = initial_dy
// DO OUR STARTING CHECKS
var/cb_return
INVOKE_CALLBACK
if(cb_return == DO_AFTER_STOP)
return FALSE
else if(cb_return != DO_AFTER_PROCEED)
if(CHECK_FLAG_FAILURE)
return FALSE
// SETUP LOOP
var/datum/progressbar/progbar
if(living_user)
if(!(do_after_flags & DO_AFTER_NO_PROGRESSBAR))
progbar = new(living_user, delay, target)
// MAIN LOOP
. = TRUE
if(!delay)
return
var/obj/item/held
var/locchanged
var/ctu
var/ctt
while(world.time < endtime)
stoplag(1)
progbar?.update(TIMELEFT)
if(QDELETED(user) || QDELETED(target) || (user.loc == null) || (target.loc == null))
. = FALSE
break
INVOKE_CALLBACK
if(cb_return == DO_AFTER_STOP)
. = FALSE
break
else if(cb_return == DO_AFTER_PROCEED)
continue
// otherwise, go through our normal checks.
if(((do_after_flags & DO_AFTER_DISALLOW_MOVING_ABSOLUTE_USER) && (user.loc != startlocuser)) || ((do_after_flags & DO_AFTER_DISALLOW_MOVING_ABSOLUTE_TARGET) && (target.loc != startloctarget)))
. = FALSE
break
else if(do_after_flags & DO_AFTER_DISALLOW_MOVING_RELATIVE)
ctu = get_turf(user)
ctt = get_turf(target)
locchanged = (userturf != ctu) || (targetturf != ctt)
userturf = ctu
targetturf = ctt
dx = targetturf.x - userturf.x
dy = targetturf.y - userturf.y
if((dx != initial_dx) || (dy != initial_dy))
. = FALSE
break
if(locchanged && !drifting && !(do_after_flags & DO_AFTER_ALLOW_NONSPACEDRIFT_RELATIVITY))
. = FALSE
break
if(!AM_user.inertia_dir)
drifting = FALSE
if((do_after_flags & DO_AFTER_REQUIRES_USER_ON_TURF) && !isturf(user.loc))
return FALSE
if(CHECK_FLAG_FAILURE)
. = FALSE
break
held = living_user?.get_active_held_item()
if((do_after_flags & DO_AFTER_DISALLOW_ACTIVE_ITEM_CHANGE) && (held != (tool || initially_held_item)))
. = FALSE
break
if((do_after_flags & DO_AFTER_REQUIRE_FREE_HAND_OR_TOOL) && (!living_user?.is_holding(tool) && !length(living_user?.get_empty_held_indexes())))
. = FALSE
break
// CLEANUP
qdel(progbar)
// If we failed, just return.
if(!.)
return FALSE
// DO FINISHING CHECKS
if(QDELETED(user) || QDELETED(target))
return FALSE
INVOKE_CALLBACK
if(cb_return == DO_AFTER_STOP)
return FALSE
else if(cb_return == DO_AFTER_PROCEED)
return TRUE
if(CHECK_FLAG_FAILURE)
return FALSE
if(((do_after_flags & DO_AFTER_DISALLOW_MOVING_ABSOLUTE_USER) && (user.loc != startlocuser)) || ((do_after_flags & DO_AFTER_DISALLOW_MOVING_ABSOLUTE_TARGET) && (target.loc != startloctarget)))
return FALSE
else if(do_after_flags & DO_AFTER_DISALLOW_MOVING_RELATIVE)
ctu = get_turf(user)
ctt = get_turf(target)
locchanged = (userturf != ctu) || (targetturf != ctt)
userturf = ctu
targetturf = ctt
dx = targetturf.x - userturf.x
dy = targetturf.y - userturf.y
if((dx != initial_dx) || (dy != initial_dy))
return FALSE
if(locchanged && !drifting && !(do_after_flags & DO_AFTER_ALLOW_NONSPACEDRIFT_RELATIVITY))
return FALSE
if((do_after_flags & DO_AFTER_REQUIRES_USER_ON_TURF) && !isturf(user.loc))
return FALSE
held = living_user?.get_active_held_item()
if((do_after_flags & DO_AFTER_DISALLOW_ACTIVE_ITEM_CHANGE) && (held != (tool || initially_held_item)))
return FALSE
if((do_after_flags & DO_AFTER_REQUIRE_FREE_HAND_OR_TOOL) && (!living_user?.is_holding(tool) && !length(living_user?.get_empty_held_indexes())))
return FALSE
#undef INVOKE_CALLBACK
#undef CHECK_FLAG_FAILURE
/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = FALSE, resume_time = 0 SECONDS)
if(!user || !target)
return 0
var/user_loc = user.loc
var/drifting = 0
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = 1
var/target_loc = target.loc
var/holding = user.get_active_held_item()
var/datum/progressbar/progbar
if (progress)
progbar = new(user, time, target)
var/endtime = world.time+time
var/starttime = world.time
. = 1
while (world.time + resume_time < endtime)
stoplag(1)
if (progress)
progbar.update(world.time - starttime + resume_time)
if(QDELETED(user) || QDELETED(target))
. = 0
break
if(uninterruptible)
continue
if(drifting && !user.inertia_dir)
drifting = 0
user_loc = user.loc
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)
qdel(progbar)
//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)
return FALSE
return TRUE
//pass a list in the format list("health" = mob's health var) to check health during this
/mob/living/break_do_after_checks(list/checked_health, check_clicks)
if(islist(checked_health))
if(health < checked_health["health"])
return FALSE
checked_health["health"] = health
return ..()
/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE), resume_time = 0 SECONDS)
if(!user)
return 0
var/atom/Tloc = null
if(target && !isturf(target))
Tloc = target.loc
var/atom/Uloc = user.loc
var/drifting = 0
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = 1
var/holding = user.get_active_held_item()
var/holdingnull = 1 //User's hand started out empty, check for an empty hand
if(holding)
holdingnull = 0 //Users hand started holding something, check to see if it's still holding that
delay *= user.do_after_coefficent()
var/datum/progressbar/progbar
if (progress)
progbar = new(user, delay, target)
var/endtime = world.time + delay
var/starttime = world.time
. = 1
var/mob/living/L = isliving(user) && user //evals to last thing eval'd
while (world.time + resume_time < endtime)
stoplag(1)
if (progress)
progbar.update(world.time - starttime + resume_time)
if(drifting && !user.inertia_dir)
drifting = 0
Uloc = user.loc
if(L && !CHECK_ALL_MOBILITY(L, required_mobility_flags))
. = 0
break
if(QDELETED(user) || user.stat || (!drifting && user.loc != Uloc) || (extra_checks && !extra_checks.Invoke()))
. = 0
break
if(!QDELETED(Tloc) && (QDELETED(target) || Tloc != target.loc))
if((Uloc != Tloc || Tloc != user) && !drifting)
. = 0
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
if(!holdingnull)
if(!holding)
. = 0
break
if(user.get_active_held_item() != holding)
. = 0
break
if (progress)
qdel(progbar)
/mob/proc/do_after_coefficent() // This gets added to the delay on a do_after, default 1
. = 1
return
/proc/do_after_mob(mob/user, var/list/targets, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks)
if(!user || !targets)
return 0
if(!islist(targets))
targets = list(targets)
var/user_loc = user.loc
var/drifting = 0
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = 1
var/list/originalloc = list()
for(var/atom/target in targets)
originalloc[target] = target.loc
var/holding = user.get_active_held_item()
var/datum/progressbar/progbar
if(progress)
progbar = new(user, time, targets[1])
var/endtime = world.time + time
var/starttime = world.time
. = 1
mainloop:
while(world.time < endtime)
stoplag(1)
if(progress)
progbar.update(world.time - starttime)
if(QDELETED(user) || !targets)
. = 0
break
if(uninterruptible)
continue
if(drifting && !user.inertia_dir)
drifting = 0
user_loc = user.loc
for(var/atom/target in targets)
if((!drifting && user_loc != user.loc) || QDELETED(target) || originalloc[target] != target.loc || user.get_active_held_item() != holding || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke()))
. = 0
break mainloop
if(progbar)
qdel(progbar)
-16
View File
@@ -544,22 +544,6 @@
var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
announcer.announce("ARRIVAL", character.real_name, rank, list()) //make the list empty to make it announce it in common
/proc/GetHexColors(const/hexa)
return list(
GetRedPart(hexa)/ 255,
GetGreenPart(hexa)/ 255,
GetBluePart(hexa)/ 255
)
/proc/GetRedPart(const/hexa)
return hex2num(copytext(hexa, 2, 4))
/proc/GetGreenPart(const/hexa)
return hex2num(copytext(hexa, 4, 6))
/proc/GetBluePart(const/hexa)
return hex2num(copytext(hexa, 6, 8))
/proc/lavaland_equipment_pressure_check(turf/T)
. = FALSE
if(!istype(T))
+1 -167
View File
@@ -216,6 +216,7 @@
"ipc_screen" = snowflake_ipc_antenna_list ? pick(snowflake_ipc_antenna_list) : "None",
"ipc_antenna" = "None",
"flavor_text" = "",
"silicon_flavor_text" = "",
"meat_type" = "Mammalian",
"body_model" = body_model,
"body_size" = RESIZE_DEFAULT_SIZE
@@ -319,173 +320,6 @@ GLOBAL_LIST_EMPTY(species_list)
else
return "unknown"
/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = FALSE, resume_time = 0 SECONDS)
if(!user || !target)
return 0
var/user_loc = user.loc
var/drifting = 0
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = 1
var/target_loc = target.loc
var/holding = user.get_active_held_item()
var/datum/progressbar/progbar
if (progress)
progbar = new(user, time, target)
var/endtime = world.time+time
var/starttime = world.time
. = 1
while (world.time + resume_time < endtime)
stoplag(1)
if (progress)
progbar.update(world.time - starttime + resume_time)
if(QDELETED(user) || QDELETED(target))
. = 0
break
if(uninterruptible)
continue
if(drifting && !user.inertia_dir)
drifting = 0
user_loc = user.loc
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)
qdel(progbar)
//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)
return FALSE
return TRUE
//pass a list in the format list("health" = mob's health var) to check health during this
/mob/living/break_do_after_checks(list/checked_health, check_clicks)
if(islist(checked_health))
if(health < checked_health["health"])
return FALSE
checked_health["health"] = health
return ..()
/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE), resume_time = 0 SECONDS)
if(!user)
return 0
var/atom/Tloc = null
if(target && !isturf(target))
Tloc = target.loc
var/atom/Uloc = user.loc
var/drifting = 0
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = 1
var/holding = user.get_active_held_item()
var/holdingnull = 1 //User's hand started out empty, check for an empty hand
if(holding)
holdingnull = 0 //Users hand started holding something, check to see if it's still holding that
delay *= user.do_after_coefficent()
var/datum/progressbar/progbar
if (progress)
progbar = new(user, delay, target)
var/endtime = world.time + delay
var/starttime = world.time
. = 1
var/mob/living/L = isliving(user) && user //evals to last thing eval'd
while (world.time + resume_time < endtime)
stoplag(1)
if (progress)
progbar.update(world.time - starttime + resume_time)
if(drifting && !user.inertia_dir)
drifting = 0
Uloc = user.loc
if(L && !CHECK_ALL_MOBILITY(L, required_mobility_flags))
. = 0
break
if(QDELETED(user) || user.stat || (!drifting && user.loc != Uloc) || (extra_checks && !extra_checks.Invoke()))
. = 0
break
if(!QDELETED(Tloc) && (QDELETED(target) || Tloc != target.loc))
if((Uloc != Tloc || Tloc != user) && !drifting)
. = 0
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
if(!holdingnull)
if(!holding)
. = 0
break
if(user.get_active_held_item() != holding)
. = 0
break
if (progress)
qdel(progbar)
/mob/proc/do_after_coefficent() // This gets added to the delay on a do_after, default 1
. = 1
return
/proc/do_after_mob(mob/user, var/list/targets, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks)
if(!user || !targets)
return 0
if(!islist(targets))
targets = list(targets)
var/user_loc = user.loc
var/drifting = 0
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = 1
var/list/originalloc = list()
for(var/atom/target in targets)
originalloc[target] = target.loc
var/holding = user.get_active_held_item()
var/datum/progressbar/progbar
if(progress)
progbar = new(user, time, targets[1])
var/endtime = world.time + time
var/starttime = world.time
. = 1
mainloop:
while(world.time < endtime)
stoplag(1)
if(progress)
progbar.update(world.time - starttime)
if(QDELETED(user) || !targets)
. = 0
break
if(uninterruptible)
continue
if(drifting && !user.inertia_dir)
drifting = 0
user_loc = user.loc
for(var/atom/target in targets)
if((!drifting && user_loc != user.loc) || QDELETED(target) || originalloc[target] != target.loc || user.get_active_held_item() != holding || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke()))
. = 0
break mainloop
if(progbar)
qdel(progbar)
/proc/is_species(A, species_datum)
. = FALSE
if(ishuman(A))
-6
View File
@@ -675,12 +675,6 @@ Turf and target are separate in case you want to teleport some distance from a t
loc = loc.loc
return null
//For objects that should embed, but make no sense being is_sharp or is_pointed()
//e.g: rods
GLOBAL_LIST_INIT(can_embed_types, typecacheof(list(
/obj/item/stack/rods,
/obj/item/pipe)))
/*
Checks if that loc and dir has an item on the wall
*/
+7 -1
View File
@@ -49,6 +49,8 @@ GLOBAL_LIST_INIT(bitfields, list(
"DROPDEL" = DROPDEL,
"NOBLUDGEON" = NOBLUDGEON,
"ABSTRACT" = ABSTRACT,
"ITEM_CAN_BLOCK" = ITEM_CAN_BLOCK,
"ITEM_CAN_PARRY" = ITEM_CAN_PARRY
),
"admin_flags" = list(
"BUILDMODE" = R_BUILDMODE,
@@ -123,7 +125,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"UNUSED_RESERVATION_TURF_1" = UNUSED_RESERVATION_TURF_1,
"CAN_BE_DIRTY_1" = CAN_BE_DIRTY_1,
"HEAR_1" = HEAR_1,
"CHECK_RICOCHET_1" = CHECK_RICOCHET_1,
"DEFAULT_RICOCHET_1" = DEFAULT_RICOCHET_1,
"CONDUCT_1" = CONDUCT_1,
"NO_LAVA_GEN_1" = NO_LAVA_GEN_1,
"NODECONSTRUCT_1" = NODECONSTRUCT_1,
@@ -138,6 +140,10 @@ GLOBAL_LIST_INIT(bitfields, list(
"BLOCK_FACE_ATOM_1" = BLOCK_FACE_ATOM_1,
"PREVENT_CONTENTS_EXPLOSION_1" = PREVENT_CONTENTS_EXPLOSION_1
),
"flags_ricochet" = list(
"RICOCHET_SHINY" = RICOCHET_SHINY,
"RICOCHET_HARD" = RICOCHET_HARD
),
"clothing_flags" = list(
"LAVAPROTECT" = LAVAPROTECT,
"STOPSPRESSUREDAMAGE" = STOPSPRESSUREDAMAGE,
+3
View File
@@ -223,3 +223,6 @@ GLOBAL_LIST_INIT(station_numerals, greek_letters + phonetic_alphabet + numbers_a
GLOBAL_LIST_INIT(admiral_messages, list("Do you know how expensive these stations are?","Stop wasting my time.","I was sleeping, thanks a lot.","Stand and fight you cowards!","You knew the risks coming in.","Stop being paranoid.","Whatever's broken just build a new one.","No.", "<i>null</i>","<i>Error: No comment given.</i>", "It's a good day to die!"))
GLOBAL_LIST_INIT(redacted_strings, list("\[REDACTED\]", "\[CLASSIFIED\]", "\[ARCHIVED\]", "\[EXPLETIVE DELETED\]", "\[EXPUNGED\]", "\[INFORMATION ABOVE YOUR SECURITY CLEARANCE\]", "\[MOVE ALONG CITIZEN\]", "\[NOTHING TO SEE HERE\]", "\[ACCESS DENIED\]"))
GLOBAL_LIST_INIT(wisdoms, world.file2list("strings/wisdoms.txt"))
+20 -1
View File
@@ -51,7 +51,7 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
/obj/item/airlock_painter = 1,
/obj/item/stack/cable_coil/random = 4,
/obj/item/stack/cable_coil/random/five = 6,
/obj/item/stack/medical/bruise_pack = 1,
/obj/item/stack/medical/suture = 1,
/obj/item/stack/rods/ten = 9,
/obj/item/stack/rods/twentyfive = 1,
/obj/item/stack/rods/fifty = 1,
@@ -116,5 +116,24 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
/obj/item/autosurgeon/testicles = 1,
/obj/item/storage/box/marshmallow = 2,
/obj/item/clothing/gloves/tackler/offbrand = 1,
/obj/item/stack/sticky_tape = 1,
"" = 3
))
GLOBAL_LIST_INIT(ratking_trash, list(//Garbage: used by the regal rat mob when spawning garbage.
/obj/item/cigbutt,
/obj/item/trash/cheesie,
/obj/item/trash/candy,
/obj/item/trash/chips,
/obj/item/trash/pistachios,
/obj/item/trash/plate,
/obj/item/trash/popcorn,
/obj/item/trash/raisins,
/obj/item/trash/sosjerky,
/obj/item/trash/syndi_cakes))
GLOBAL_LIST_INIT(ratking_coins, list(//Coins: Used by the regal rat mob when spawning coins.
/obj/item/coin/iron,
/obj/item/coin/silver,
/obj/item/coin/plastic,
/obj/item/coin/titanium))
+3 -1
View File
@@ -19,6 +19,7 @@
#define POLL_IGNORE_WIZARD "wizard"
#define POLL_IGNORE_CLONE "clone"
#define POLL_IGNORE_CONTRACTOR_SUPPORT "contractor_support"
#define POLL_IGNORE_FUGITIVE "fugitive"
GLOBAL_LIST_INIT(poll_ignore_desc, list(
POLL_IGNORE_SENTIENCE_POTION = "Sentience potion",
@@ -39,7 +40,8 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list(
POLL_IGNORE_DEMON = "Demons",
POLL_IGNORE_WIZARD = "Wizards",
POLL_IGNORE_CLONE = "Defective/SDGF clones",
POLL_IGNORE_CONTRACTOR_SUPPORT = "Contractor Support Unit"
POLL_IGNORE_CONTRACTOR_SUPPORT = "Contractor Support Unit",
POLL_IGNORE_FUGITIVE = "Fugitive Hunter"
))
GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore())
+3 -1
View File
@@ -93,6 +93,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_PASSTABLE" = TRAIT_PASSTABLE,
"TRAIT_GIANT" = TRAIT_GIANT,
"TRAIT_DWARF" = TRAIT_DWARF,
"TRAIT_NICE_SHOT" = TRAIT_NICE_SHOT,
"TRAIT_COMBAT_MODE_LOCKED" = TRAIT_COMBAT_MODE_LOCKED,
"TRAIT_SPRINT_LOCKED" = TRAIT_SPRINT_LOCKED,
"TRAIT_AUTO_CATCH_ITEM" = TRAIT_AUTO_CATCH_ITEM,
@@ -116,7 +117,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_MASO" = TRAIT_MASO,
"TRAIT_HIGH_BLOOD" = TRAIT_HIGH_BLOOD,
"TRAIT_EMPATH" = TRAIT_EMPATH,
"TRAIT_FRIENDLY" = TRAIT_FRIENDLY
"TRAIT_FRIENDLY" = TRAIT_FRIENDLY,
"TRAIT_NICE_SHOT" = TRAIT_NICE_SHOT
),
/obj/item/bodypart = list(
"TRAIT_PARALYSIS" = TRAIT_PARALYSIS
+3
View File
@@ -17,6 +17,9 @@
// 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)
+1 -1
View File
@@ -242,7 +242,7 @@ If you're feeling frisky, examine yourself and click the underlined item to pull
/obj/screen/alert/embeddedobject/Click()
if(isliving(usr))
var/mob/living/carbon/human/M = usr
var/mob/living/carbon/M = usr
return M.help_shake_act(M)
/obj/screen/alert/weightless
+17 -15
View File
@@ -7,17 +7,17 @@
*and lastly
*afterattack. The return value does not matter.
*/
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params)
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params, flags, damage_multiplier = 1)
if(isliving(user))
var/mob/living/L = user
if(!CHECK_MOBILITY(L, MOBILITY_USE))
if(!CHECK_MOBILITY(L, MOBILITY_USE) && !(flags & ATTACKCHAIN_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))
return
if(pre_attack(target, user, params))
return
if(target.attackby(src,user, params))
if(target.attackby(src, user, params, flags, damage_multiplier))
return
if(QDELETED(src) || QDELETED(target))
return
@@ -52,15 +52,15 @@
/obj/attackby(obj/item/I, mob/living/user, params)
return ..() || ((obj_flags & CAN_BE_HIT) && I.attack_obj(src, user))
/mob/living/attackby(obj/item/I, mob/living/user, params)
/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)
. = 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)
/obj/item/proc/attack(mob/living/M, mob/living/user)
/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
SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user)
@@ -79,7 +79,7 @@
M.lastattackerckey = user.ckey
user.do_attack_animation(M)
M.attacked_by(src, user)
M.attacked_by(src, user, attackchain_flags, damage_multiplier)
log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
add_fingerprint(user)
@@ -104,8 +104,8 @@
/atom/movable/proc/attacked_by()
return
/obj/attacked_by(obj/item/I, mob/living/user)
var/totitemdamage = I.force
/obj/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
var/totitemdamage = I.force * damage_multiplier
var/bad_trait
var/stamloss = user.getStaminaLoss()
@@ -134,10 +134,12 @@
take_damage(totitemdamage, I.damtype, "melee", 1)
return TRUE
/mob/living/attacked_by(obj/item/I, mob/living/user)
var/totitemdamage = pre_attacked_by(I, user)
if((user != src) && mob_run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, null, null) & BLOCK_SUCCESS)
/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)
return FALSE
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
send_item_attack_message(I, user, null, totitemdamage)
I.do_stagger_action(src, user, totitemdamage)
if(I.force)
@@ -151,7 +153,7 @@
user.add_mob_blood(src)
return TRUE //successful attack
/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user)
/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
@@ -211,8 +213,8 @@
var/message_verb = "attacked"
if(I.attack_verb && I.attack_verb.len)
message_verb = "[pick(I.attack_verb)]"
if(current_force < I.force * INEFFICIENT_ATTACK_MSG_THRESHOLD)
message_verb = "inefficiently [message_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 = ""
@@ -435,6 +435,10 @@
config_entry_value = 64
min_val = 0
/datum/config_entry/number/ratcap
config_entry_value = 64
min_val = 0
/datum/config_entry/flag/disable_stambuffer
/datum/config_entry/keyed_list/box_random_engine
@@ -517,3 +521,10 @@
* Camera mobs, AIs, ghosts and some other are of course exempt from this. This also doesn't influence simplemob AI, for the best.
*/
/datum/config_entry/flag/use_field_of_vision
//Shuttle size limiter
/datum/config_entry/number/max_shuttle_count
config_entry_value = 6
/datum/config_entry/number/max_shuttle_size
config_entry_value = 250
+2
View File
@@ -76,6 +76,8 @@ SUBSYSTEM_DEF(air)
var/list/pipenet_rebuilds = pipenets_needing_rebuilt
for(var/thing in pipenet_rebuilds)
var/obj/machinery/atmospherics/AT = thing
if(!istype(AT))
continue
AT.build_network()
cost_rebuilds = MC_AVERAGE(cost_rebuilds, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
pipenets_needing_rebuilt.Cut()
+1
View File
@@ -8,6 +8,7 @@ SUBSYSTEM_DEF(mobs)
var/static/list/clients_by_zlevel[][]
var/static/list/dead_players_by_zlevel[][] = list(list()) // Needs to support zlevel 1 here, MaxZChanged only happens when z2 is created and new_players can login before that.
var/static/list/cubemonkeys = list()
var/static/list/cheeserats = list()
/datum/controller/subsystem/mobs/stat_entry()
..("P:[GLOB.mob_living_list.len]")
+5
View File
@@ -117,6 +117,11 @@
paralysis_type = "legs"
resilience = TRAUMA_RESILIENCE_ABSOLUTE
/datum/brain_trauma/severe/paralysis/spinesnapped
random_gain = FALSE
paralysis_type = "legs"
resilience = TRAUMA_RESILIENCE_LOBOTOMY
/datum/brain_trauma/severe/narcolepsy
name = "Narcolepsy"
desc = "Patient may involuntarily fall asleep during normal activities."
+1 -1
View File
@@ -114,7 +114,7 @@
// BYOND Bug #2563917
// Construct text
var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g")
var/complete_text = "<span class='center maptext [extra_classes.Join(" ")]' style='color: [tgt_color]'>[text]</span>"
var/complete_text = "<span class='center maptext [extra_classes.Join(" ")]' style='color: [tgt_color]'>[owner.say_emphasis(text)]</span>"
var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(replacetext(complete_text, html_metachars, "m"), null, CHAT_MESSAGE_WIDTH))
approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT)
+2 -1
View File
@@ -38,8 +38,9 @@
parent = raw_args[1]
var/list/arguments = raw_args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
stack_trace("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
qdel(src, TRUE, TRUE)
CRASH("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
return
_JoinParent(parent)
+2
View File
@@ -119,6 +119,8 @@
if(hud_icon)
hud_icon.combat_on = FALSE
hud_icon.update_icon()
source.stop_active_blocking()
source.end_parry_sequence()
///Changes the user direction to (try) keep match the pointer.
/datum/component/combat_mode/proc/on_move(atom/movable/source, dir, atom/oldloc, forced)
+30 -2
View File
@@ -35,17 +35,34 @@ k// PARTS //
desc = "A twenty bore shotgun barrel."
icon_state = "barrel_shotgun"
/obj/item/weaponcrafting/improvised_parts/barrel_pistol
name = "pistol barrel"
desc = "A pipe with a small diameter and some holes finely cut into it. It fits .32 ACP bullets. Probably."
icon_state = "barrel_pistol"
w_class = WEIGHT_CLASS_SMALL
// RECEIVERS
/obj/item/weaponcrafting/improvised_parts/rifle_receiver
name = "bolt action receiver"
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle."
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle. It's generic enough to modify to create other rifles, potentially."
icon_state = "receiver_rifle"
w_class = WEIGHT_CLASS_SMALL
/obj/item/weaponcrafting/improvised_parts/pistol_receiver
name = "pistol receiver"
desc = "A receiver to connect house and connects all the parts to make an improvised pistol."
icon_state = "receiver_pistol"
w_class = WEIGHT_CLASS_SMALL
/obj/item/weaponcrafting/improvised_parts/laser_receiver
name = "energy emitter assembly"
desc = "A mixture of components haphazardly wired together to form an energy emitter."
icon_state = "laser_assembly"
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver
name = "break-action assembly"
desc = "An improvised receiver to create a break-action breechloaded shotgun."
desc = "An improvised receiver to create a break-action breechloaded shotgun. Parts of this are still useful if you want to make another type of shotgun, however."
icon_state = "receiver_shotgun"
w_class = WEIGHT_CLASS_SMALL
@@ -62,3 +79,14 @@ k// PARTS //
desc = "A crudely fashioned wooden body to help keep higher calibre improvised weapons from blowing themselves apart."
icon_state = "wooden_body"
/obj/item/weaponcrafting/improvised_parts/wooden_grip
name = "wooden pistol grip"
desc = "A nice wooden grip hollowed out for pistol magazines."
icon_state = "wooden_pistolgrip"
w_class = WEIGHT_CLASS_SMALL
/obj/item/weaponcrafting/improvised_parts/makeshift_lens
name = "makeshift focusing lens"
desc = "A properly made lens made with actual glassworking tools would perform much better, but this will have to do."
icon_state = "focusing_lens"
w_class = WEIGHT_CLASS_TINY
@@ -124,9 +124,9 @@
category = CAT_MISC
subcategory = CAT_TOOL
/datum/crafting_recipe/bruise_pack
name = "Bruise Pack"
result = /obj/item/stack/medical/bruise_pack/one
/datum/crafting_recipe/brute_pack
name = "Suture Pack"
result = /obj/item/stack/medical/suture/one
time = 1
reqs = list(/obj/item/stack/medical/gauze = 1,
/datum/reagent/medicine/styptic_powder = 10)
@@ -134,8 +134,8 @@
subcategory = CAT_TOOL
/datum/crafting_recipe/burn_pack
name = "Burn Ointment"
result = /obj/item/stack/medical/ointment/one
name = "Regenerative Mesh"
result = /obj/item/stack/medical/mesh/one
time = 1
reqs = list(/obj/item/stack/medical/gauze = 1,
/datum/reagent/medicine/silver_sulfadiazine = 10)
@@ -6,7 +6,7 @@
tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
time = 50
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_OTHER
/datum/crafting_recipe/pin_removal/check_requirements(mob/user, list/collected_requirements)
var/obj/item/gun/G = collected_requirements[/obj/item/gun][1]
@@ -22,7 +22,7 @@
/obj/item/shield/riot = 1)
time = 40
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
/datum/crafting_recipe/strobeshield/New()
..()
@@ -38,7 +38,7 @@
tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
time = 100
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
/datum/crafting_recipe/spear
name = "Spear"
@@ -49,7 +49,7 @@
parts = list(/obj/item/shard = 1)
time = 40
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
/datum/crafting_recipe/stunprod
name = "Stunprod"
@@ -59,7 +59,7 @@
/obj/item/assembly/igniter = 1)
time = 40
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
/datum/crafting_recipe/teleprod
name = "Teleprod"
@@ -70,7 +70,7 @@
/obj/item/stack/ore/bluespace_crystal = 1)
time = 40
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
/datum/crafting_recipe/bola
name = "Bola"
@@ -88,7 +88,7 @@
/obj/item/stack/sheet/metal = 1)
time = 40
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
/datum/crafting_recipe/tailwhip
name = "Liz O' Nine Tails"
@@ -97,7 +97,7 @@
/obj/item/stack/cable_coil = 1)
time = 40
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
/datum/crafting_recipe/catwhip
name = "Cat O' Nine Tails"
@@ -106,7 +106,7 @@
/obj/item/stack/cable_coil = 1)
time = 40
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
/datum/crafting_recipe/chainsaw
name = "Chainsaw"
@@ -117,7 +117,7 @@
tools = list(TOOL_WELDER)
time = 50
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
//////////////////
///BOMB CRAFTING//
@@ -134,7 +134,7 @@
parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2)
time = 30
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_OTHER
/datum/crafting_recipe/chemical_payload2
name = "Chemical Payload (Gibtonite)"
@@ -147,7 +147,7 @@
parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2)
time = 50
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_OTHER
/datum/crafting_recipe/molotov
name = "Molotov"
@@ -169,7 +169,7 @@
parts = list(/obj/item/reagent_containers/food/drinks/soda_cans = 1)
time = 15
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_OTHER
/datum/crafting_recipe/lance
name = "Explosive Lance (Grenade)"
@@ -180,7 +180,7 @@
/obj/item/grenade = 1)
time = 15
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
subcategory = CAT_MELEE
//////////////////
///GUNS CRAFTING//
@@ -276,6 +276,49 @@
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
/datum/crafting_recipe/ipistol
name = "Improvised Pistol (.32)"
result = /obj/item/gun/ballistic/automatic/pistol/improvised/nomag
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 1,
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 1,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
/obj/item/weaponcrafting/improvised_parts/wooden_grip = 1,
/obj/item/stack/sheet/plastic = 15,
/obj/item/stack/sheet/plasteel = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER, TOOL_WIRECUTTER)
time = 100
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
/datum/crafting_recipe/ilaser
name = "Improvised Energy Gun"
result = /obj/item/gun/energy/e_gun/old/improvised
reqs = list(/obj/item/weaponcrafting/improvised_parts/laser_receiver = 1,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 1,
/obj/item/stock_parts/cell = 1,
/obj/item/stack/sheet/metal = 10,
/obj/item/stack/sheet/plasteel = 5,
/obj/item/stack/cable_coil = 10)
tools = list(TOOL_SCREWDRIVER)
time = 100
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
/datum/crafting_recipe/ilaser/upgraded
name = "Improvised Energy Gun Upgrade"
result = /obj/item/gun/energy/e_gun/old/improvised/upgraded
reqs = list(/obj/item/gun/energy/e_gun/old/improvised = 1,
/obj/item/glasswork/glass_base/lens = 1,
/obj/item/stock_parts/capacitor/quadratic = 2,
/obj/item/stock_parts/micro_laser/ultra = 1,
/obj/item/stock_parts/cell/bluespace = 1,
/obj/item/stack/cable_coil = 5)
tools = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL)
time = 100
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
//////////////////
///AMMO CRAFTING//
//////////////////
@@ -399,6 +442,17 @@
category = CAT_WEAPONRY
subcategory = CAT_AMMO
/datum/crafting_recipe/m32acp
name = ".32ACP Empty Magazine"
result = /obj/item/ammo_box/magazine/m32acp/empty
reqs = list(/obj/item/stack/sheet/metal = 3,
/obj/item/stack/sheet/plasteel = 1,
/obj/item/stack/packageWrap = 1)
tools = list(TOOL_WELDER,TOOL_SCREWDRIVER)
time = 5
category = CAT_WEAPONRY
subcategory = CAT_AMMO
////////////////////
// PARTS CRAFTING //
////////////////////
@@ -423,13 +477,24 @@
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/pistol_barrel
name = "Improvised Pistol Barrel"
result = /obj/item/weaponcrafting/improvised_parts/barrel_pistol
reqs = list(/obj/item/pipe = 1,
/obj/item/stack/sheet/plasteel = 1)
tools = list(TOOL_WELDER,TOOL_SAW)
time = 150
category = CAT_WEAPONRY
subcategory = CAT_PARTS
// RECEIVERS
/datum/crafting_recipe/rifle_receiver
name = "Improvised Rifle Receiver"
result = /obj/item/weaponcrafting/improvised_parts/rifle_receiver
reqs = list(/obj/item/stack/sheet/metal = 20)
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER) // Rifle is the easiest to craft and can be made at an autolathe, this is a very light kick in the shin for dual-wielding ishotguns.
reqs = list(/obj/item/stack/sheet/metal = 10,
/obj/item/stack/sheet/plasteel = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
time = 50
category = CAT_WEAPONRY
subcategory = CAT_PARTS
@@ -439,11 +504,33 @@
result = /obj/item/weaponcrafting/improvised_parts/shotgun_receiver
reqs = list(/obj/item/stack/sheet/metal = 10,
/obj/item/stack/sheet/plasteel = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER) // Increased cost is to stop dual-wield alpha striking. ishotgun is a rvolver and can be duel-wielded
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER) // Dual wielding has been removed, plasteel is a soft timesink to obtain for most to make mass production harder.
time = 50
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/pistol_receiver
name = "Improvised Pistol Receiver"
result = /obj/item/weaponcrafting/improvised_parts/pistol_receiver
reqs = list(/obj/item/stack/sheet/metal = 5,
/obj/item/stack/sheet/plasteel = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER, TOOL_SAW)
time = 50
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/laser_receiver
name = "Energy Weapon Assembly"
result = /obj/item/weaponcrafting/improvised_parts/laser_receiver
reqs = list(/obj/item/stack/sheet/metal = 10,
/obj/item/stock_parts/capacitor = 2,
/obj/item/stock_parts/micro_laser = 1,
/obj/item/assembly/prox_sensor = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WELDER) // Prox sensor and multitool for the circuit board, welder for extremely ghetto soldering.
time = 150
category = CAT_WEAPONRY
subcategory = CAT_PARTS
// MISC
/datum/crafting_recipe/trigger_assembly
@@ -455,3 +542,13 @@
time = 150
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/makeshift_lens
name = "Makeshift Lens"
result = /obj/item/weaponcrafting/improvised_parts/makeshift_lens
reqs = list(/obj/item/stack/sheet/metal = 1,
/obj/item/stack/sheet/glass = 2)
tools = list(TOOL_WELDER) // Glassmaking lets you make non-makeshift lenses.
time = 50
category = CAT_WEAPONRY
subcategory = CAT_PARTS
+363
View File
@@ -0,0 +1,363 @@
/*
This component is responsible for handling individual instances of embedded objects. The embeddable element is what allows an item to be embeddable and stores its embedding stats,
and when it impacts and meets the requirements to stick into something, it instantiates an embedded component. Once the item falls out, the component is destroyed, while the
element survives to embed another day.
There are 2 different things that can be embedded presently: carbons, and closed turfs (see: walls)
- Carbon embedding has all the classical embedding behavior, and tracks more events and signals. The main behaviors and hooks to look for are:
-- Every process tick, there is a chance to randomly proc pain, controlled by pain_chance. There may also be a chance for the object to fall out randomly, per fall_chance
-- Every time the mob moves, there is a chance to proc jostling pain, controlled by jostle_chance (and only 50% as likely if the mob is walking or crawling)
-- Various signals hooking into carbon topic() and the embed removal surgery in order to handle removals.
- Turf embedding is much simpler. All we do here is draw an overlay of the item's inhand on the turf, hide the item, and create an HTML link in the turf's inspect
that allows you to rip the item out. There's nothing dynamic about this, so far less checks.
In addition, there are 2 cases of embedding: embedding, and sticking
- Embedding involves harmful and dangerous embeds, whether they cause brute damage, stamina damage, or a mix. This is the default behavior for embeddings, for when something is "pointy"
- Sticking occurs when an item should not cause any harm while embedding (imagine throwing a sticky ball of tape at someone, rather than a shuriken). An item is considered "sticky"
when it has 0 for both pain multiplier and jostle pain multiplier. It's a bit arbitrary, but fairly straightforward.
Stickables differ from embeds in the following ways:
-- Text descriptors use phrasing like "X is stuck to Y" rather than "X is embedded in Y"
-- There is no slicing sound on impact
-- All damage checks and bloodloss are skipped for carbons
-- Pointy objects create sparks when embedding into a turf
*/
/datum/component/embedded
dupe_mode = COMPONENT_DUPE_ALLOWED
var/obj/item/bodypart/limb
var/obj/item/weapon
// all of this stuff is explained in _DEFINES/combat.dm
var/embed_chance // not like we really need it once we're already stuck in but hey
var/fall_chance
var/pain_chance
var/pain_mult
var/impact_pain_mult
var/remove_pain_mult
var/rip_time
var/ignore_throwspeed_threshold
var/jostle_chance
var/jostle_pain_mult
var/pain_stam_pct
var/embed_chance_turf_mod
///if both our pain multiplier and jostle pain multiplier are 0, we're harmless and can omit most of the damage related stuff
var/harmful
var/mutable_appearance/overlay
/datum/component/embedded/Initialize(obj/item/I,
datum/thrownthing/throwingdatum,
obj/item/bodypart/part,
embed_chance = EMBED_CHANCE,
fall_chance = EMBEDDED_ITEM_FALLOUT,
pain_chance = EMBEDDED_PAIN_CHANCE,
pain_mult = EMBEDDED_PAIN_MULTIPLIER,
remove_pain_mult = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
impact_pain_mult = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
rip_time = EMBEDDED_UNSAFE_REMOVAL_TIME,
ignore_throwspeed_threshold = FALSE,
jostle_chance = EMBEDDED_JOSTLE_CHANCE,
jostle_pain_mult = EMBEDDED_JOSTLE_PAIN_MULTIPLIER,
pain_stam_pct = EMBEDDED_PAIN_STAM_PCT,
embed_chance_turf_mod = EMBED_CHANCE_TURF_MOD)
if((!iscarbon(parent) && !isclosedturf(parent)) || !isitem(I))
return COMPONENT_INCOMPATIBLE
if(part)
limb = part
src.embed_chance = embed_chance
src.fall_chance = fall_chance
src.pain_chance = pain_chance
src.pain_mult = pain_mult
src.remove_pain_mult = remove_pain_mult
src.rip_time = rip_time
src.impact_pain_mult = impact_pain_mult
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
src.jostle_chance = jostle_chance
src.jostle_pain_mult = jostle_pain_mult
src.pain_stam_pct = pain_stam_pct
src.embed_chance_turf_mod = embed_chance_turf_mod
src.weapon = I
if(!weapon.isEmbedHarmless())
harmful = TRUE
weapon.embedded(parent)
if(iscarbon(parent))
initCarbon()
else if(isclosedturf(parent))
initTurf(throwingdatum)
/datum/component/embedded/RegisterWithParent()
if(iscarbon(parent))
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/jostleCheck)
RegisterSignal(parent, COMSIG_CARBON_EMBED_RIP, .proc/ripOutCarbon)
RegisterSignal(parent, COMSIG_CARBON_EMBED_REMOVAL, .proc/safeRemoveCarbon)
else if(isclosedturf(parent))
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examineTurf)
RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/itemMoved)
/datum/component/embedded/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_EMBED_RIP, COMSIG_CARBON_EMBED_REMOVAL, COMSIG_PARENT_EXAMINE))
/datum/component/embedded/process()
if(iscarbon(parent))
processCarbon()
/datum/component/embedded/Destroy()
if(weapon)
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
if(overlay)
var/atom/A = parent
A.cut_overlay(overlay, TRUE)
qdel(overlay)
return ..()
////////////////////////////////////////
/////////////HUMAN PROCS////////////////
////////////////////////////////////////
/// Set up an instance of embedding for a carbon. This is basically an extension of Initialize() so not much to say
/datum/component/embedded/proc/initCarbon()
START_PROCESSING(SSdcs, src)
var/mob/living/carbon/victim = parent
if(!istype(limb))
limb = pick(victim.bodyparts)
limb.embedded_objects |= weapon // on the inside... on the inside...
weapon.forceMove(victim)
RegisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING), .proc/byeItemCarbon)
if(harmful)
victim.visible_message("<span class='danger'>[weapon] embeds itself in [victim]'s [limb.name]!</span>",ignored_mobs=victim)
to_chat(victim, "<span class='userdanger'>[weapon] embeds itself in your [limb.name]!</span>")
victim.throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
playsound(victim,'sound/weapons/bladeslice.ogg', 40)
weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody!
var/damage = weapon.w_class * impact_pain_mult
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
else
victim.visible_message("<span class='danger'>[weapon] sticks itself to [victim]'s [limb.name]!</span>",ignored_mobs=victim)
to_chat(victim, "<span class='userdanger'>[weapon] sticks itself to your [limb.name]!</span>")
/// Called every time a carbon with a harmful embed moves, rolling a chance for the item to cause pain. The chance is halved if the carbon is crawling or walking.
/datum/component/embedded/proc/jostleCheck()
var/mob/living/carbon/victim = parent
var/chance = jostle_chance
if(victim.m_intent == MOVE_INTENT_WALK || !(victim.mobility_flags & MOBILITY_STAND))
chance *= 0.5
if(harmful && prob(chance))
var/damage = weapon.w_class * jostle_pain_mult
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] jostles and stings!</span>")
/// Called when then item randomly falls out of a carbon. This handles the damage and descriptors, then calls safe_remove()
/datum/component/embedded/proc/fallOutCarbon()
var/mob/living/carbon/victim = parent
if(harmful)
var/damage = weapon.w_class * remove_pain_mult
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
victim.visible_message("<span class='danger'>[weapon] falls out of [victim.name]'s [limb.name]!</span>", ignored_mobs=victim)
to_chat(victim, "<span class='userdanger'>[weapon] falls out of your [limb.name]!</span>")
else
victim.visible_message("<span class='danger'>[weapon] falls off of [victim.name]'s [limb.name]!</span>", ignored_mobs=victim)
to_chat(victim, "<span class='userdanger'>[weapon] falls off of your [limb.name]!</span>")
safeRemoveCarbon()
/// Called when a carbon with an object embedded/stuck to them inspects themselves and clicks the appropriate link to begin ripping the item out. This handles the ripping attempt, descriptors, and dealing damage, then calls safe_remove()
/datum/component/embedded/proc/ripOutCarbon(datum/source, obj/item/I, obj/item/bodypart/limb)
if(I != weapon || src.limb != limb)
return
var/mob/living/carbon/victim = parent
var/time_taken = rip_time * weapon.w_class
victim.visible_message("<span class='warning'>[victim] attempts to remove [weapon] from [victim.p_their()] [limb.name].</span>","<span class='notice'>You attempt to remove [weapon] from your [limb.name]... (It will take [DisplayTimeText(time_taken)].)</span>")
if(do_after(victim, time_taken, target = victim))
if(!weapon || !limb || weapon.loc != victim || !(weapon in limb.embedded_objects))
qdel(src)
return
if(harmful)
var/damage = weapon.w_class * remove_pain_mult
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage) //It hurts to rip it out, get surgery you dingus.
victim.emote("scream")
victim.visible_message("<span class='notice'>[victim] successfully rips [weapon] out of [victim.p_their()] [limb.name]!</span>", "<span class='notice'>You successfully remove [weapon] from your [limb.name].</span>")
else
victim.visible_message("<span class='notice'>[victim] successfully rips [weapon] off of [victim.p_their()] [limb.name]!</span>", "<span class='notice'>You successfully remove [weapon] from your [limb.name].</span>")
safeRemoveCarbon(TRUE)
/// This proc handles the final step and actual removal of an embedded/stuck item from a carbon, whether or not it was actually removed safely.
/// Pass TRUE for to_hands if we want it to go to the victim's hands when they pull it out
/datum/component/embedded/proc/safeRemoveCarbon(to_hands)
var/mob/living/carbon/victim = parent
limb.embedded_objects -= weapon
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) // have to unhook these here so they don't also register as having disappeared
if(!weapon)
if(!victim.has_embedded_objects())
victim.clear_alert("embeddedobject")
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
qdel(src)
return
if(weapon.unembedded()) // if it deleted itself
weapon = null
if(!victim.has_embedded_objects())
victim.clear_alert("embeddedobject")
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
qdel(src)
return
if(to_hands)
victim.put_in_hands(weapon)
else
weapon.forceMove(get_turf(victim))
if(!victim.has_embedded_objects())
victim.clear_alert("embeddedobject")
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
qdel(src)
/// Something deleted or moved our weapon while it was embedded, how rude!
/datum/component/embedded/proc/byeItemCarbon()
var/mob/living/carbon/victim = parent
limb.embedded_objects -= weapon
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
if(victim)
to_chat(victim, "<span class='userdanger'>\The [weapon] that was embedded in your [limb.name] disappears!</span>")
if(!victim.has_embedded_objects())
victim.clear_alert("embeddedobject")
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
weapon = null
qdel(src)
/// Items embedded/stuck to carbons both check whether they randomly fall out (if applicable), as well as if the target mob and limb still exists.
/// Items harmfully embedded in carbons have an additional check for random pain (if applicable)
/datum/component/embedded/proc/processCarbon()
var/mob/living/carbon/victim = parent
if(!victim || !limb) // in case the victim and/or their limbs exploded (say, due to a sticky bomb)
weapon.forceMove(get_turf(weapon))
qdel(src)
if(victim.stat == DEAD)
return
var/damage = weapon.w_class * pain_mult
var/chance = pain_chance
if(pain_stam_pct && IS_STAMCRIT(victim)) //if it's a less-lethal embed, give them a break if they're already stamcritted
chance *= 0.3
damage *= 0.7
if(harmful && prob(chance))
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] hurts!</span>")
if(prob(fall_chance))
fallOutCarbon()
////////////////////////////////////////
//////////////TURF PROCS////////////////
////////////////////////////////////////
/// Turfs are much lower maintenance, since we don't care if they're in pain, but since they don't bleed or scream, we draw an overlay to show their status.
/// The only difference pointy/sticky items make here is text descriptors and pointy objects making a spark shower on impact.
/datum/component/embedded/proc/initTurf(datum/thrownthing/throwingdatum)
var/turf/closed/hit = parent
// we can't store the item IN the turf (cause turfs are just kinda... there), so we fake it by making the item invisible and bailing if it moves due to a blast
weapon.forceMove(hit)
weapon.invisibility = INVISIBILITY_ABSTRACT
RegisterSignal(weapon, COMSIG_MOVABLE_MOVED, .proc/itemMoved)
var/pixelX = rand(-2, 2)
var/pixelY = rand(-1, 3) // bias this upwards since in-hands are usually on the lower end of the sprite
switch(throwingdatum.init_dir)
if(NORTH)
pixelY -= 2
if(SOUTH)
pixelY += 2
if(WEST)
pixelX += 2
if(EAST)
pixelX -= 2
if(throwingdatum.init_dir in list(NORTH, WEST, NORTHWEST, SOUTHWEST))
overlay = mutable_appearance(icon=weapon.righthand_file,icon_state=weapon.item_state)
else
overlay = mutable_appearance(icon=weapon.lefthand_file,icon_state=weapon.item_state)
var/matrix/M = matrix()
M.Translate(pixelX, pixelY)
overlay.transform = M
hit.add_overlay(overlay, TRUE)
if(harmful)
hit.visible_message("<span class='danger'>[weapon] embeds itself in [hit]!</span>")
playsound(hit,'sound/weapons/bladeslice.ogg', 70)
var/datum/effect_system/spark_spread/sparks = new
sparks.set_up(1, 1, parent)
sparks.attach(parent)
sparks.start()
else
hit.visible_message("<span class='danger'>[weapon] sticks itself to [hit]!</span>")
/datum/component/embedded/proc/examineTurf(datum/source, mob/user, list/examine_list)
if(harmful)
examine_list += "\t <a href='?src=[REF(src)];embedded_object=[REF(weapon)]' class='warning'>There is \a [weapon] embedded in [parent]!</a>"
else
examine_list += "\t <a href='?src=[REF(src)];embedded_object=[REF(weapon)]' class='warning'>There is \a [weapon] stuck to [parent]!</a>"
/// Someone is ripping out the item from the turf by hand
/datum/component/embedded/Topic(datum/source, href_list)
var/mob/living/us = usr
if(in_range(us, parent) && locate(href_list["embedded_object"]) == weapon)
if(harmful)
us.visible_message("<span class='notice'>[us] begins unwedging [weapon] from [parent].</span>", "<span class='notice'>You begin unwedging [weapon] from [parent]...</span>")
else
us.visible_message("<span class='notice'>[us] begins unsticking [weapon] from [parent].</span>", "<span class='notice'>You begin unsticking [weapon] from [parent]...</span>")
if(do_after(us, 30, target = parent))
us.put_in_hands(weapon)
weapon.unembedded()
qdel(src)
/// This proc handles if something knocked the invisible item loose from the turf somehow (probably an explosion). Just make it visible and say it fell loose, then get outta here.
/datum/component/embedded/proc/itemMoved()
weapon.invisibility = initial(weapon.invisibility)
weapon.visible_message("<span class='notice'>[weapon] falls loose from [parent].</span>")
weapon.unembedded()
qdel(src)
+1 -1
View File
@@ -144,7 +144,7 @@
var/obj/item/projectile/picked_projectiletype = pickweight(weighted_projectile_types)
var/obj/item/master = comp.parent
comp.appliedComponents += master.AddComponent(/datum/component/shrapnel, picked_projectiletype)
comp.appliedComponents += master.AddComponent(/datum/component/mirv, picked_projectiletype)
return "[newName] of [initial(picked_projectiletype.name)] shrapnel"
/datum/fantasy_affix/strength
+1 -1
View File
@@ -73,7 +73,7 @@
if(!material_amount)
to_chat(user, "<span class='warning'>[I] does not contain sufficient materials to be accepted by [parent].</span>")
return
if((!precise_insertion || !GLOB.typecache_stack[I]) && !has_space(material_amount))
if((!precise_insertion || !GLOB.typecache_stack[I.type]) && !has_space(material_amount))
to_chat(user, "<span class='warning'>[parent] has not enough space. Please remove materials from [parent] in order to insert more.</span>")
return
user_insert(I, user)
@@ -1,36 +1,37 @@
/datum/component/shrapnel
/datum/component/mirv
var/projectile_type
var/radius // shoots a projectile for every turf on this radius from the hit target
var/override_projectile_range
/datum/component/shrapnel/Initialize(projectile_type, radius=1, override_projectile_range)
if(!isgun(parent) && !ismachinery(parent) && !isstructure(parent))
/datum/component/mirv/Initialize(projectile_type, radius=1, override_projectile_range)
if(!isgun(parent) && !ismachinery(parent) && !isstructure(parent) && !isgrenade(parent))
return COMPONENT_INCOMPATIBLE
src.projectile_type = projectile_type
src.radius = radius
src.override_projectile_range = override_projectile_range
if(isgrenade(parent))
parent.AddComponent(/datum/component/pellet_cloud, projectile_type=projectile_type)
/datum/component/shrapnel/RegisterWithParent()
/datum/component/mirv/RegisterWithParent()
. = ..()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
/datum/component/shrapnel/UnregisterFromParent()
/datum/component/mirv/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_PROJECTILE_ON_HIT))
/datum/component/shrapnel/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
/datum/component/mirv/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
do_shrapnel(firer, target)
/datum/component/shrapnel/proc/do_shrapnel(mob/firer, atom/target)
/datum/component/mirv/proc/do_shrapnel(mob/firer, atom/target)
if(radius < 1)
return
var/turf/target_turf = get_turf(target)
for(var/turf/shootat_turf in RANGE_TURFS(radius, target) - RANGE_TURFS(radius-1, target))
var/obj/item/projectile/P = new projectile_type(target_turf)
var/obj/item/projectile/P = new projectile_type(target_turf)
//Shooting Code:
P.range = radius+1
if(override_projectile_range)
+283
View File
@@ -0,0 +1,283 @@
/*
* This component is used when you want to create a bunch of shrapnel or projectiles (say, shrapnel from a fragmentation grenade, or buckshot from a shotgun) from a central point,
* without necessarily printing a separate message for every single impact. This component should be instantiated right when you need it (like the moment of firing), then activated
* by signal.
*
* Pellet cloud currently works on two classes of sources: directed (ammo casings), and circular (grenades, landmines).
* -Directed: This means you're shooting multiple pellets, like buckshot. If an ammo casing is defined as having multiple pellets, it will automatically create a pellet cloud
* and call COMSIG_PELLET_CLOUD_INIT (see [/obj/item/ammo_casing/proc/fire_casing]). Thus, the only projectiles fired will be the ones fired here.
* The magnitude var controls how many pellets are created.
* -Circular: This results in a big spray of shrapnel flying all around the detonation point when the grenade fires COMSIG_GRENADE_PRIME or landmine triggers COMSIG_MINE_TRIGGERED.
* The magnitude var controls how big the detonation radius is (the bigger the magnitude, the more shrapnel is created). Grenades can be covered with bodies to reduce shrapnel output.
*
* Once all of the fired projectiles either hit a target or disappear due to ranging out/whatever else, we resolve the list of all the things we hit and print aggregate messages so we get
* one "You're hit by 6 buckshot pellets" vs 6x "You're hit by the buckshot blah blah" messages.
*
* Note that this is how all guns handle shooting ammo casings with multiple pellets, in case such a thing comes up.
*/
/datum/component/pellet_cloud
/// What's the projectile path of the shrapnel we're shooting?
var/projectile_type
/// How many shrapnel projectiles are we responsible for tracking? May be reduced for grenades if someone dives on top of it. Defined by ammo casing for casings, derived from magnitude otherwise
var/num_pellets
/// For grenades/landmines, how big is the radius of turfs we're targeting? Note this does not effect the projectiles range, only how many we generate
var/radius = 4
/// The list of pellets we're responsible for tracking, once these are all accounted for, we finalize.
var/list/pellets = list()
/// An associated list with the atom hit as the key and how many pellets they've eaten for the value, for printing aggregate messages
var/list/targets_hit = list()
/// For grenades, any /mob/living's the grenade is moved onto, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
var/list/bodies
/// For grenades, tracking people who die covering a grenade for achievement purposes, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
var/list/purple_hearts
/// For grenades, tracking how many pellets are removed due to martyrs and how many pellets are added due to the last person to touch it being on top of it
var/pellet_delta = 0
/// how many pellets ranged out without hitting anything
var/terminated
/// how many pellets impacted something
var/hits
/// If the parent tried deleting and we're not done yet, we send it to nullspace then delete it after
var/queued_delete = FALSE
/// for if we're an ammo casing being fired
var/mob/living/shooter
/datum/component/pellet_cloud/Initialize(projectile_type=/obj/item/shrapnel, magnitude=5)
if(!isammocasing(parent) && !isgrenade(parent) && !islandmine(parent))
return COMPONENT_INCOMPATIBLE
if(magnitude < 1)
stack_trace("Invalid magnitude [magnitude] < 1 on pellet_cloud, parent: [parent]")
magnitude = 1
src.projectile_type = projectile_type
if(isammocasing(parent))
num_pellets = magnitude
else if(isgrenade(parent) || islandmine(parent))
radius = magnitude
/datum/component/pellet_cloud/Destroy(force, silent)
purple_hearts = null
pellets = null
targets_hit = null
bodies = null
return ..()
/datum/component/pellet_cloud/RegisterWithParent()
RegisterSignal(parent, COMSIG_PARENT_PREQDELETED, .proc/nullspace_parent)
if(isammocasing(parent))
RegisterSignal(parent, COMSIG_PELLET_CLOUD_INIT, .proc/create_casing_pellets)
else if(isgrenade(parent))
RegisterSignal(parent, COMSIG_GRENADE_ARMED, .proc/grenade_armed)
RegisterSignal(parent, COMSIG_GRENADE_PRIME, .proc/create_blast_pellets)
else if(islandmine(parent))
RegisterSignal(parent, COMSIG_MINE_TRIGGERED, .proc/create_blast_pellets)
/datum/component/pellet_cloud/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_PELLET_CLOUD_INIT, COMSIG_GRENADE_PRIME, COMSIG_GRENADE_ARMED, COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UNCROSSED, COMSIG_MINE_TRIGGERED, COMSIG_ITEM_DROPPED))
/**
* create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance)
*
* Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing()] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes.
* The arguments really don't matter, this proc is triggered by COMSIG_PELLET_CLOUD_INIT which is only for this really, it's just a big mess of the state vars we need for doing the stuff over here.
*/
/datum/component/pellet_cloud/proc/create_casing_pellets(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro)
shooter = user
var/targloc = get_turf(target)
if(!zone_override)
zone_override = shooter.zone_selected
for(var/i in 1 to num_pellets)
shell.ready_proj(target, user, SUPPRESSED_VERY, zone_override, fired_from)
if(distro)
if(randomspread)
spread = round((rand() - 0.5) * distro)
else //Smart spread
spread = round((i / num_pellets - 0.5) * distro)
RegisterSignal(shell.BB, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/pellet_hit)
RegisterSignal(shell.BB, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), .proc/pellet_range)
pellets += shell.BB
if(!shell.throw_proj(target, targloc, shooter, params, spread))
return
if(i != num_pellets)
shell.newshot()
/**
* create_blast_pellets() is for when we have a central point we want to shred the surroundings of with a ring of shrapnel, namely frag grenades and landmines.
*
* Note that grenades have extra handling for someone throwing themselves/being thrown on top of it, while landmines do not (obviously, it's a landmine!). See [/datum/component/pellet_cloud/proc/handle_martyrs()]
*/
/datum/component/pellet_cloud/proc/create_blast_pellets(obj/O, mob/living/lanced_by)
var/atom/A = parent
if(isgrenade(parent)) // handle_martyrs can reduce the radius and thus the number of pellets we produce if someone dives on top of a frag grenade
handle_martyrs(lanced_by) // note that we can modify radius in this proc
if(radius < 1)
return
var/list/all_the_turfs_were_gonna_lacerate = RANGE_TURFS(radius, A) - RANGE_TURFS(radius-1, A)
num_pellets = all_the_turfs_were_gonna_lacerate.len + pellet_delta
for(var/T in all_the_turfs_were_gonna_lacerate)
var/turf/shootat_turf = T
pew(shootat_turf)
/**
* handle_martyrs() is used for grenades that shoot shrapnel to check if anyone threw themselves/were thrown on top of the grenade, thus absorbing a good chunk of the shrapnel
*
* Between the time the grenade is armed and the actual detonation, we set var/list/bodies to the list of mobs currently on the new tile, as if the grenade landed on top of them, tracking if any of them move off the tile and removing them from the "under" list
* Once the grenade detonates, handle_martyrs() is called and gets all the new mobs on the tile, and add the ones not in var/list/bodies to var/list/martyrs
* We then iterate through the martyrs and reduce the shrapnel magnitude for each mob on top of it, shredding each of them with some of the shrapnel they helped absorb. This can snuff out all of the shrapnel if there's enough bodies
*
* Note we track anyone who's alive and client'd when they get shredded in var/list/purple_hearts, for achievement checking later
*/
/datum/component/pellet_cloud/proc/handle_martyrs(mob/living/lanced_by)
var/magnitude_absorbed
var/list/martyrs = list()
var/self_harm_radius_mult = 3
if(lanced_by && prob(60))
to_chat(lanced_by, "<span class='userdanger'>Your plan to whack someone with a grenade on a stick backfires on you, literally!</span>")
self_harm_radius_mult = 1 // we'll still give the guy who got hit some extra shredding, but not 3*radius
pellet_delta += radius
for(var/i in 1 to radius)
pew(lanced_by) // thought you could be tricky and lance someone with no ill effects!!
for(var/mob/living/body in get_turf(parent))
if(body == shooter)
pellet_delta += radius * self_harm_radius_mult
for(var/i in 1 to radius * self_harm_radius_mult)
pew(body) // free shrapnel if it goes off in your hand, and it doesn't even count towards the absorbed. fun!
else if(!(body in bodies))
martyrs += body // promoted from a corpse to a hero
for(var/M in martyrs)
var/mob/living/martyr = M
if(radius > 4)
martyr.visible_message("<b><span class='danger'>[martyr] heroically covers \the [parent] with [martyr.p_their()] body, absorbing a load of the shrapnel!</span></b>", "<span class='userdanger'>You heroically cover \the [parent] with your body, absorbing a load of the shrapnel!</span>")
magnitude_absorbed += round(radius * 0.5)
else if(radius >= 2)
martyr.visible_message("<b><span class='danger'>[martyr] heroically covers \the [parent] with [martyr.p_their()] body, absorbing some of the shrapnel!</span></b>", "<span class='userdanger'>You heroically cover \the [parent] with your body, absorbing some of the shrapnel!</span>")
magnitude_absorbed += 2
else
martyr.visible_message("<b><span class='danger'>[martyr] heroically covers \the [parent] with [martyr.p_their()] body, snuffing out the shrapnel!</span></b>", "<span class='userdanger'>You heroically cover \the [parent] with your body, snuffing out the shrapnel!</span>")
magnitude_absorbed = radius
var/pellets_absorbed = (radius ** 2) - ((radius - magnitude_absorbed - 1) ** 2)
radius -= magnitude_absorbed
pellet_delta -= round(pellets_absorbed * 0.5)
if(martyr.stat != DEAD && martyr.client)
LAZYADD(purple_hearts, martyr)
RegisterSignal(martyr, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
for(var/i in 1 to round(pellets_absorbed * 0.5))
pew(martyr)
if(radius < 1)
break
///One of our pellets hit something, record what it was and check if we're done (terminated == num_pellets)
/datum/component/pellet_cloud/proc/pellet_hit(obj/item/projectile/P, atom/movable/firer, atom/target, Angle)
pellets -= P
terminated++
hits++
targets_hit[target]++
if(targets_hit[target] == 1)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
UnregisterSignal(P, list(COMSIG_PARENT_QDELETING, COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT))
if(terminated == num_pellets)
finalize()
///One of our pellets disappeared due to hitting their max range (or just somehow got qdel'd), remove it from our list and check if we're done (terminated == num_pellets)
/datum/component/pellet_cloud/proc/pellet_range(obj/item/projectile/P)
pellets -= P
terminated++
UnregisterSignal(P, list(COMSIG_PARENT_QDELETING, COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT))
if(terminated == num_pellets)
finalize()
/// Minor convenience function for creating each shrapnel piece with circle explosions, mostly stolen from the MIRV component
/datum/component/pellet_cloud/proc/pew(atom/target, spread=0)
var/obj/item/projectile/P = new projectile_type(get_turf(parent))
//Shooting Code:
P.spread = spread
P.original = target
P.fired_from = parent
P.firer = parent // don't hit ourself that would be really annoying
P.permutated += parent // don't hit the target we hit already with the flak
P.suppressed = SUPPRESSED_VERY // set the projectiles to make no message so we can do our own aggregate message
P.preparePixelProjectile(target, parent)
RegisterSignal(P, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/pellet_hit)
RegisterSignal(P, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), .proc/pellet_range)
pellets += P
P.fire()
///All of our pellets are accounted for, time to go target by target and tell them how many things they got hit by.
/datum/component/pellet_cloud/proc/finalize()
var/obj/item/projectile/P = projectile_type
var/proj_name = initial(P.name)
for(var/atom/target in targets_hit)
var/num_hits = targets_hit[target]
UnregisterSignal(target, COMSIG_PARENT_QDELETING)
if(num_hits > 1)
target.visible_message("<span class='danger'>[target] is hit by [num_hits] [proj_name]s!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
to_chat(target, "<span class='userdanger'>You're hit by [num_hits] [proj_name]s!</span>")
else
target.visible_message("<span class='danger'>[target] is hit by a [proj_name]!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
to_chat(target, "<span class='userdanger'>You're hit by a [proj_name]!</span>")
UnregisterSignal(parent, COMSIG_PARENT_PREQDELETED)
if(queued_delete)
qdel(parent)
qdel(src)
/// Look alive, we're armed! Now we start watching to see if anyone's covering us
/datum/component/pellet_cloud/proc/grenade_armed(obj/item/nade)
if(ismob(nade.loc))
shooter = nade.loc
LAZYINITLIST(bodies)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/grenade_dropped)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/grenade_moved)
RegisterSignal(parent, COMSIG_MOVABLE_UNCROSSED, .proc/grenade_uncrossed)
/// Someone dropped the grenade, so set them to the shooter in case they're on top of it when it goes off
/datum/component/pellet_cloud/proc/grenade_dropped(obj/item/nade, mob/living/slick_willy)
shooter = slick_willy
grenade_moved()
/// Our grenade has moved, reset var/list/bodies so we're "on top" of any mobs currently on the tile
/datum/component/pellet_cloud/proc/grenade_moved()
LAZYCLEARLIST(bodies)
for(var/mob/living/L in get_turf(parent))
RegisterSignal(L, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
bodies += L
/// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it
/datum/component/pellet_cloud/proc/grenade_uncrossed(datum/source, atom/movable/AM)
bodies -= AM
/// Our grenade or landmine or caseless shell or whatever tried deleting itself, so we intervene and nullspace it until we're done here
/datum/component/pellet_cloud/proc/nullspace_parent()
var/atom/movable/AM = parent
AM.moveToNullspace()
queued_delete = TRUE
return TRUE
/// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it
/datum/component/pellet_cloud/proc/on_target_qdel(atom/target)
UnregisterSignal(target, COMSIG_PARENT_QDELETING)
targets_hit -= target
bodies -= target
purple_hearts -= target
+11
View File
@@ -11,6 +11,17 @@
RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, .proc/join_swarm)
RegisterSignal(parent, COMSIG_MOVABLE_UNCROSSED, .proc/leave_swarm)
/datum/component/swarming/Destroy()
if(is_swarming)
for(var/A in swarm_members)
var/datum/component/swarming/other_swarm = A
other_swarm.swarm_members -= src
swarm_members -= other_swarm
if(!length(other_swarm.swarm_members))
other_swarm.unswarm()
unswarm()
return ..()
/datum/component/swarming/proc/join_swarm(datum/source, atom/movable/AM)
var/datum/component/swarming/other_swarm = AM.GetComponent(/datum/component/swarming)
if(!other_swarm)
+5 -5
View File
@@ -206,7 +206,7 @@
user.set_resting(FALSE, TRUE, FALSE)
user.forceMove(get_turf(target))
target.adjustStaminaLoss(65)
target.Paralyze(10)
target.Paralyze(10)
target.DefaultCombatKnockdown(20)
if(ishuman(target) && iscarbon(user))
target.grabbedby(user)
@@ -354,7 +354,7 @@
playsound(user, 'sound/effects/blobattack.ogg', 60, TRUE)
playsound(user, 'sound/effects/splat.ogg', 70, TRUE)
user.emote("scream")
user.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic) // oopsie indeed!
user.gain_trauma(/datum/brain_trauma/severe/paralysis/spinesnapped) // oopsie indeed!
shake_camera(user, 7, 7)
user.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
user.clear_fullscreen("flash", 4.5)
@@ -415,10 +415,10 @@
for(var/i = 0, i < speed, i++)
var/obj/item/shard/shard = new /obj/item/shard(get_turf(user))
//shard.embedding = list(embed_chance = 100, ignore_throwspeed_threshold = TRUE, impact_pain_mult=3, pain_chance=5)
//shard.AddElement(/datum/element/embed, shard.embedding)
shard.updateEmbedding()
user.hitby(shard, skipcatch = TRUE, hitpush = FALSE)
//shard.embedding = list()
//shard.AddElement(/datum/element/embed, shard.embedding)
shard.embedding = list()
shard.updateEmbedding()
W.obj_destruction()
user.adjustStaminaLoss(10 * speed)
user.DefaultCombatKnockdown(40)
+2
View File
@@ -19,11 +19,13 @@
SHOULD_CALL_PARENT(1)
if(type == /datum/element)
return ELEMENT_INCOMPATIBLE
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
if(element_flags & ELEMENT_DETACH)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
/// Deactivates the functionality defines by the element on the given datum
/datum/element/proc/Detach(datum/source, force)
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
SHOULD_CALL_PARENT(1)
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
+227
View File
@@ -0,0 +1,227 @@
/*
The presence of this element allows an item (or a projectile carrying an item) to embed itself in a human or turf when it is thrown into a target (whether by hand, gun, or explosive wave) with either
at least 4 throwspeed (EMBED_THROWSPEED_THRESHOLD) or ignore_throwspeed_threshold set to TRUE. Items meant to be used as shrapnel for projectiles should have ignore_throwspeed_threshold set to true.
Whether we're dealing with a direct /obj/item (throwing a knife at someone) or an /obj/projectile with a shrapnel_type, how we handle things plays out the same, with one extra step separating them.
Items simply make their COMSIG_MOVABLE_IMPACT or COMSIG_MOVABLE_IMPACT_ZONE check (against a closed turf or a carbon, respectively), while projectiles check on COMSIG_PROJECTILE_SELF_ON_HIT.
Upon a projectile hitting a valid target, it spawns whatever type of payload it has defined, then has that try to embed itself in the target on its own.
Otherwise non-embeddable or stickable items can be made embeddable/stickable through wizard events/sticky tape/admin memes.
*/
#define STANDARD_WALL_HARDNESS 40
/datum/element/embed
element_flags = ELEMENT_BESPOKE
id_arg_index = 2
var/initialized = FALSE /// whether we can skip assigning all the vars (since these are bespoke elements, we don't have to reset the vars every time we attach to something, we already know what we are!)
// all of this stuff is explained in _DEFINES/combat.dm
var/embed_chance
var/fall_chance
var/pain_chance
var/pain_mult
var/remove_pain_mult
var/impact_pain_mult
var/rip_time
var/ignore_throwspeed_threshold
var/jostle_chance
var/jostle_pain_mult
var/pain_stam_pct
var/payload_type
var/embed_chance_turf_mod
/datum/element/embed/Attach(datum/target, embed_chance, fall_chance, pain_chance, pain_mult, remove_pain_mult, impact_pain_mult, rip_time, ignore_throwspeed_threshold, jostle_chance, jostle_pain_mult, pain_stam_pct, embed_chance_turf_mod, projectile_payload=/obj/item/shard)
. = ..()
if(!isitem(target) && !isprojectile(target))
return ELEMENT_INCOMPATIBLE
if(isitem(target))
RegisterSignal(target, COMSIG_MOVABLE_IMPACT_ZONE, .proc/checkEmbedMob)
RegisterSignal(target, COMSIG_MOVABLE_IMPACT, .proc/checkEmbedOther)
RegisterSignal(target, COMSIG_ELEMENT_ATTACH, .proc/severancePackage)
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/examined)
RegisterSignal(target, COMSIG_EMBED_TRY_FORCE, .proc/tryForceEmbed)
RegisterSignal(target, COMSIG_ITEM_DISABLE_EMBED, .proc/detachFromWeapon)
if(!initialized)
src.embed_chance = embed_chance
src.fall_chance = fall_chance
src.pain_chance = pain_chance
src.pain_mult = pain_mult
src.remove_pain_mult = remove_pain_mult
src.rip_time = rip_time
src.impact_pain_mult = impact_pain_mult
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
src.jostle_chance = jostle_chance
src.jostle_pain_mult = jostle_pain_mult
src.pain_stam_pct = pain_stam_pct
src.embed_chance_turf_mod = embed_chance_turf_mod
initialized = TRUE
else
payload_type = projectile_payload
RegisterSignal(target, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/checkEmbedProjectile)
/datum/element/embed/Detach(obj/target)
. = ..()
if(isitem(target))
UnregisterSignal(target, list(COMSIG_MOVABLE_IMPACT_ZONE, COMSIG_ELEMENT_ATTACH, COMSIG_MOVABLE_IMPACT, COMSIG_PARENT_EXAMINE, COMSIG_EMBED_TRY_FORCE, COMSIG_ITEM_DISABLE_EMBED))
else
UnregisterSignal(target, list(COMSIG_PROJECTILE_SELF_ON_HIT))
/// Checking to see if we're gonna embed into a human
/datum/element/embed/proc/checkEmbedMob(obj/item/weapon, mob/living/carbon/victim, hit_zone, datum/thrownthing/throwingdatum, forced=FALSE)
if(!istype(victim) || HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE))
return
var/actual_chance = embed_chance
if(!weapon.isEmbedHarmless()) // all the armor in the world won't save you from a kick me sign
var/armor = max(victim.run_armor_check(hit_zone, "bullet", silent=TRUE), victim.run_armor_check(hit_zone, "bomb", silent=TRUE)) // we'll be nice and take the better of bullet and bomb armor
if(armor) // we only care about armor penetration if there's actually armor to penetrate
var/pen_mod = -armor + weapon.armour_penetration // even a little bit of armor can make a big difference for shrapnel with large negative armor pen
actual_chance += pen_mod // doing the armor pen as a separate calc just in case this ever gets expanded on
if(actual_chance <= 0)
victim.visible_message("<span class='danger'>[weapon] bounces off [victim]'s armor!</span>", "<span class='notice'>[weapon] bounces off your armor!</span>", vision_distance = COMBAT_MESSAGE_RANGE)
return
var/roll_embed = prob(actual_chance)
var/pass = forced || ((((throwingdatum ? throwingdatum.speed : weapon.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || ignore_throwspeed_threshold) && roll_embed)
if(!pass)
return
var/obj/item/bodypart/limb = victim.get_bodypart(hit_zone) || pick(victim.bodyparts)
victim.AddComponent(/datum/component/embedded,\
weapon,\
throwingdatum,\
part = limb,\
embed_chance = embed_chance,\
fall_chance = fall_chance,\
pain_chance = pain_chance,\
pain_mult = pain_mult,\
remove_pain_mult = remove_pain_mult,\
rip_time = rip_time,\
ignore_throwspeed_threshold = ignore_throwspeed_threshold,\
jostle_chance = jostle_chance,\
jostle_pain_mult = jostle_pain_mult,\
pain_stam_pct = pain_stam_pct,\
embed_chance_turf_mod = embed_chance_turf_mod)
return TRUE
/// We need the hit_zone if we're embedding into a human, so this proc only handles if we're embedding into a turf
/datum/element/embed/proc/checkEmbedOther(obj/item/weapon, turf/closed/hit, datum/thrownthing/throwingdatum, forced=FALSE)
if(!istype(hit))
return
var/chance = embed_chance + embed_chance_turf_mod
if(iswallturf(hit))
var/turf/closed/wall/W = hit
chance += 2 * (W.hardness - STANDARD_WALL_HARDNESS)
if(!forced && chance <= 0 || embed_chance_turf_mod <= -100)
return
var/pass = ((((throwingdatum ? throwingdatum.speed : weapon.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || ignore_throwspeed_threshold) && prob(chance))
if(!pass)
return
hit.AddComponent(/datum/component/embedded,\
weapon,\
throwingdatum,\
embed_chance = embed_chance,\
fall_chance = fall_chance,\
pain_chance = pain_chance,\
pain_mult = pain_mult,\
remove_pain_mult = remove_pain_mult,\
rip_time = rip_time,\
ignore_throwspeed_threshold = ignore_throwspeed_threshold,\
jostle_chance = jostle_chance,\
jostle_pain_mult = jostle_pain_mult,\
pain_stam_pct = pain_stam_pct,\
embed_chance_turf_mod = embed_chance_turf_mod)
return TRUE
///A different embed element has been attached, so we'll detach and let them handle things
/datum/element/embed/proc/severancePackage(obj/item/weapon, datum/element/E)
if(istype(E, /datum/element/embed))
Detach(weapon)
///If we don't want to be embeddable anymore (deactivating an e-dagger for instance)
/datum/element/embed/proc/detachFromWeapon(obj/weapon)
Detach(weapon)
///Someone inspected our embeddable item
/datum/element/embed/proc/examined(obj/item/I, mob/user, list/examine_list)
if(I.isEmbedHarmless())
examine_list += "[I] feels sticky, and could probably get stuck to someone if thrown properly!"
else
examine_list += "[I] has a fine point, and could probably embed in someone if thrown properly!"
/**
* checkEmbedProjectile() is what we get when a projectile with a defined shrapnel_type impacts a target.
*
* If we hit a valid target (carbon or closed turf), we create the shrapnel_type object and immediately call tryEmbed() on it, targeting what we impacted. That will lead
* it to call tryForceEmbed() on its own embed element (it's out of our hands here, our projectile is done), where it will run through all the checks it needs to.
*/
/datum/element/embed/proc/checkEmbedProjectile(obj/item/projectile/P, atom/movable/firer, atom/hit, angle, hit_zone)
if(!iscarbon(hit) && !isclosedturf(hit))
Detach(P)
return // we don't care
var/obj/item/payload = new payload_type(get_turf(hit))
var/did_embed
if(iscarbon(hit))
var/mob/living/carbon/C = hit
var/obj/item/bodypart/limb
limb = C.get_bodypart(hit_zone)
if(!limb)
limb = C.get_bodypart()
did_embed = payload.tryEmbed(limb)
else
did_embed = payload.tryEmbed(hit)
if(!did_embed)
payload.failedEmbed()
Detach(P)
/**
* tryForceEmbed() is called here when we fire COMSIG_EMBED_TRY_FORCE from [/obj/item/proc/tryEmbed]. Mostly, this means we're a piece of shrapnel from a projectile that just impacted something, and we're trying to embed in it.
*
* The reason for this extra mucking about is avoiding having to do an extra hitby(), and annoying the target by impacting them once with the projectile, then again with the shrapnel (which likely represents said bullet), and possibly
* AGAIN if we actually embed. This way, we save on at least one message. Runs the standard embed checks on the mob/turf.
*
* Arguments:
* * I- what we're trying to embed, obviously
* * target- what we're trying to shish-kabob, either a bodypart, a carbon, or a closed turf
* * hit_zone- if our target is a carbon, try to hit them in this zone, if we don't have one, pick a random one. If our target is a bodypart, we already know where we're hitting.
* * forced- if we want this to succeed 100%
*/
/datum/element/embed/proc/tryForceEmbed(obj/item/I, atom/target, hit_zone, forced=FALSE)
var/obj/item/bodypart/limb
var/mob/living/carbon/C
var/turf/closed/T
if(!forced && !prob(embed_chance))
return
if(iscarbon(target))
C = target
if(!hit_zone)
limb = pick(C.bodyparts)
hit_zone = limb.body_zone
else if(isbodypart(target))
limb = target
hit_zone = limb.body_zone
C = limb.owner
else if(isclosedturf(target))
T = target
if(C)
return checkEmbedMob(I, C, hit_zone, forced=TRUE)
else if(T)
return checkEmbedOther(I, T, forced=TRUE)
+2 -2
View File
@@ -117,9 +117,9 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
return FALSE
var/lower_name = lowertext(flavor_name)
var/new_text = stripped_multiline_input(user, "Set the [lower_name] displayed on 'examine'. [addendum]", flavor_name, texts_by_atom[usr], max_len, TRUE)
var/new_text = stripped_multiline_input(user, "Set the [lower_name] displayed on 'examine'. [addendum]", flavor_name, html_decode(texts_by_atom[usr]), max_len, TRUE)
if(!isnull(new_text) && (user in texts_by_atom))
texts_by_atom[user] = html_decode(new_text)
texts_by_atom[user] = new_text
to_chat(src, "Your [lower_name] has been updated.")
return TRUE
return FALSE
+1 -1
View File
@@ -20,7 +20,7 @@
///List of atoms this element is attached to. Doubles as a multiplier if the same element is attached multiple times to a target multiple times.
var/list/attached_atoms
/datum/element/photosynthesis/Attach(datum/target, brute = -1, burn = -1, tox = -1, oxy = -1, nutri = 4, minus = 0.5, bonus = 0.2, malus = 0)
/datum/element/photosynthesis/Attach(datum/target, brute = -1, burn = -1, tox = -1, oxy = -1, nutri = 4, minus = 0.2, bonus = 0.3, malus = -0.1)
. = ..()
if(. == ELEMENT_INCOMPATIBLE || !(isliving(target) || (isobj(target) && light_bruteheal)))
return ELEMENT_INCOMPATIBLE
-53
View File
@@ -1,53 +0,0 @@
#define EMBEDID "embed-[embed_chance]-[embedded_fall_chance]-[embedded_pain_chance]-[embedded_pain_multiplier]-[embedded_fall_pain_multiplier]-[embedded_impact_pain_multiplier]-[embedded_unsafe_removal_pain_multiplier]-[embedded_unsafe_removal_time]"
/proc/getEmbeddingBehavior(embed_chance = EMBED_CHANCE,
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
. = locate(EMBEDID)
if (!.)
. = new /datum/embedding_behavior(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
/datum/embedding_behavior
var/embed_chance
var/embedded_fall_chance
var/embedded_pain_chance
var/embedded_pain_multiplier //The coefficient of multiplication for the damage this item does while embedded (this*w_class)
var/embedded_fall_pain_multiplier //The coefficient of multiplication for the damage this item does when falling out of a limb (this*w_class)
var/embedded_impact_pain_multiplier //The coefficient of multiplication for the damage this item does when first embedded (this*w_class)
var/embedded_unsafe_removal_pain_multiplier //The coefficient of multiplication for the damage removing this without surgery causes (this*w_class)
var/embedded_unsafe_removal_time //A time in ticks, multiplied by the w_class.
/datum/embedding_behavior/New(embed_chance = EMBED_CHANCE,
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
src.embed_chance = embed_chance
src.embedded_fall_chance = embedded_fall_chance
src.embedded_pain_chance = embedded_pain_chance
src.embedded_pain_multiplier = embedded_pain_multiplier
src.embedded_fall_pain_multiplier = embedded_fall_pain_multiplier
src.embedded_impact_pain_multiplier = embedded_impact_pain_multiplier
src.embedded_unsafe_removal_pain_multiplier = embedded_unsafe_removal_pain_multiplier
src.embedded_unsafe_removal_time = embedded_unsafe_removal_time
tag = EMBEDID
/datum/embedding_behavior/proc/setRating(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
return getEmbeddingBehavior((isnull(embed_chance) ? src.embed_chance : embed_chance),\
(isnull(embedded_fall_chance) ? src.embedded_fall_chance : embedded_fall_chance),\
(isnull(embedded_pain_chance) ? src.embedded_pain_chance : embedded_pain_chance),\
(isnull(embedded_pain_multiplier) ? src.embedded_pain_multiplier : embedded_pain_multiplier),\
(isnull(embedded_fall_pain_multiplier) ? src.embedded_fall_pain_multiplier : embedded_fall_pain_multiplier),\
(isnull(embedded_impact_pain_multiplier) ? src.embedded_impact_pain_multiplier : embedded_impact_pain_multiplier),\
(isnull(embedded_unsafe_removal_pain_multiplier) ? src.embedded_unsafe_removal_pain_multiplier : embedded_unsafe_removal_pain_multiplier),\
(isnull(embedded_unsafe_removal_time) ? src.embedded_unsafe_removal_time : embedded_unsafe_removal_time))
#undef EMBEDID
+2 -1
View File
@@ -27,7 +27,8 @@ GLOBAL_LIST_INIT(huds, list(
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker()
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker(),
ANTAG_HUD_FUGITIVE = new/datum/atom_hud/antag()
))
/datum/atom_hud
+5 -1
View File
@@ -10,6 +10,10 @@
var/help_verb
var/pacifism_check = TRUE //are the martial arts combos/attacks unable to be used by pacifist.
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
/// Can we be used to unarmed parry?
var/can_martial_parry = FALSE
/// Set this variable to something not null, this'll be the preferred unarmed parry in most cases if [can_martial_parry] is TRUE. YOU MUST RUN [get_block_parry_data(this)] INSTEAD OF DIRECTLY ACCESSING!
var/datum/block_parry_data/block_parry_data
var/pugilist = FALSE
/datum/martial_art/proc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
@@ -91,4 +95,4 @@
///Gets called when a projectile hits the owner. Returning anything other than BULLET_ACT_HIT will stop the projectile from hitting the mob.
/datum/martial_art/proc/on_projectile_hit(mob/living/carbon/human/A, obj/item/projectile/P, def_zone)
return BULLET_ACT_HIT
return BULLET_ACT_HIT
+1 -1
View File
@@ -66,9 +66,9 @@
return
/obj/item/clothing/gloves/boxing/dropped(mob/user)
. = ..()
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(H.get_item_by_slot(SLOT_GLOVES) == src)
style.remove(H)
return
+1
View File
@@ -203,6 +203,7 @@
style.teach(H,1)
/obj/item/clothing/gloves/krav_maga/dropped(mob/user)
. = ..()
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
+1 -1
View File
@@ -480,12 +480,12 @@
return
/obj/item/storage/belt/champion/wrestling/dropped(mob/user)
. = ..()
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(H.get_item_by_slot(SLOT_BELT) == src)
style.remove(H)
return
//Subtype of wrestling, reserved for the wrestling belts found in the holodeck
/datum/martial_art/wrestling/holodeck
+8 -2
View File
@@ -331,14 +331,20 @@
/datum/mind/proc/enslave_mind_to_creator(mob/living/creator)
if(iscultist(creator))
SSticker.mode.add_cultist(src)
if(iscultist(creator, TRUE))
SSticker.mode.add_cultist(src)
else
src.add_antag_datum(/datum/antagonist/cult/neutered/traitor)
else if(is_revolutionary(creator))
var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE)
converter.add_revolutionary(src,FALSE)
else if(is_servant_of_ratvar(creator))
add_servant_of_ratvar(current)
if(is_servant_of_ratvar(creator, TRUE))
add_servant_of_ratvar(current)
else
add_servant_of_ratvar(current, FALSE, FALSE, /datum/antagonist/clockcult/neutered/traitor)
else if(is_nuclear_operative(creator))
var/datum/antagonist/nukeop/converter = creator.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
+9 -12
View File
@@ -406,6 +406,8 @@
w_class = WEIGHT_CLASS_SMALL
sharpness = IS_SHARP
var/mob/living/carbon/human/fired_by
/// if we missed our target
var/missed = TRUE
/obj/item/hardened_spike/Initialize(mapload, firedby)
. = ..()
@@ -413,13 +415,12 @@
addtimer(CALLBACK(src, .proc/checkembedded), 5 SECONDS)
/obj/item/hardened_spike/proc/checkembedded()
if(ishuman(loc))
var/mob/living/carbon/human/embedtest = loc
for(var/l in embedtest.bodyparts)
var/obj/item/bodypart/limb = l
if(src in limb.embedded_objects)
return limb
unembedded()
if(missed)
unembedded()
/obj/item/hardened_spike/embedded(atom/target)
if(isbodypart(target))
missed = FALSE
/obj/item/hardened_spike/unembedded()
var/turf/T = get_turf(src)
@@ -490,11 +491,7 @@
var/obj/item/bodypart/L = spikey.checkembedded()
L.embedded_objects -= spikey
//this is where it would deal damage, if it transfers chems it removes itself so no damage
spikey.forceMove(get_turf(L))
transfered.visible_message("<span class='notice'>[spikey] falls out of [transfered]!</span>")
if(!transfered.has_embedded_objects())
transfered.clear_alert("embeddedobject")
SEND_SIGNAL(transfered, COMSIG_CLEAR_MOOD_EVENT, "embedded")
spikey.unembedded()
+16
View File
@@ -162,6 +162,10 @@
port_id = "pirate"
can_be_bought = FALSE
/datum/map_template/shuttle/hunter
port_id = "hunter"
can_be_bought = FALSE
/datum/map_template/shuttle/ruin //For random shuttles in ruins
port_id = "ruin"
can_be_bought = FALSE
@@ -613,3 +617,15 @@
/datum/map_template/shuttle/snowdin/excavation
suffix = "excavation"
name = "Snowdin Excavation Elevator"
/datum/map_template/shuttle/hunter/space_cop
suffix = "space_cop"
name = "Police Spacevan"
/datum/map_template/shuttle/hunter/russian
suffix = "russian"
name = "Russian Cargo Ship"
/datum/map_template/shuttle/hunter/bounty
suffix = "bounty"
name = "Bounty Hunter Ship"
+41
View File
@@ -798,3 +798,44 @@ datum/status_effect/pacify
name = "Genetic Breakdown"
desc = "I don't feel so good. Your body can't handle the mutations! You have one minute to remove your mutations, or you will be met with a horrible fate."
icon_state = "dna_melt"
/datum/status_effect/fake_virus
id = "fake_virus"
duration = 1800//3 minutes
status_type = STATUS_EFFECT_REPLACE
tick_interval = 1
alert_type = null
var/msg_stage = 0//so you dont get the most intense messages immediately
/datum/status_effect/fake_virus/tick()
var/fake_msg = ""
var/fake_emote = ""
switch(msg_stage)
if(0 to 300)
if(prob(1))
fake_msg = pick("<span class='warning'>[pick("Your head hurts.", "Your head pounds.")]</span>",
"<span class='warning'>[pick("You're having difficulty breathing.", "Your breathing becomes heavy.")]</span>",
"<span class='warning'>[pick("You feel dizzy.", "Your head spins.")]</span>",
"<span notice='warning'>[pick("You swallow excess mucus.", "You lightly cough.")]</span>",
"<span class='warning'>[pick("Your head hurts.", "Your mind blanks for a moment.")]</span>",
"<span class='warning'>[pick("Your throat hurts.", "You clear your throat.")]</span>")
if(301 to 600)
if(prob(2))
fake_msg = pick("<span class='warning'>[pick("Your head hurts a lot.", "Your head pounds incessantly.")]</span>",
"<span class='warning'>[pick("Your windpipe feels like a straw.", "Your breathing becomes tremendously difficult.")]</span>",
"<span class='warning'>You feel very [pick("dizzy","woozy","faint")].</span>",
"<span class='warning'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>",
"<span class='warning'>You nod off for a moment.</span>")
else
if(prob(3))
if(prob(50))// coin flip to throw a message or an emote
fake_msg = pick("<span class='userdanger'>[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]</span>",
"<span class='userdanger'>[pick("Your lungs hurt!", "It hurts to breathe!")]</span>",
"<span class='warning'>[pick("You feel nauseated.", "You feel like you're going to throw up!")]</span>")
else
fake_emote = pick("cough", "sniff", "sneeze")
if(fake_emote)
owner.emote(fake_emote)
else if(fake_msg)
to_chat(owner, fake_msg)
msg_stage++
+11
View File
@@ -93,6 +93,13 @@
/area/shuttle/abandoned/pod
name = "Abandoned Ship Pod"
////////////////////////////Bounty Hunter Shuttles////////////////////////////
/area/shuttle/hunter
name = "Hunter Shuttle"
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
blob_allowed = FALSE
canSmoothWithAreas = /area/shuttle/hunter
////////////////////////////Single-area shuttles////////////////////////////
/area/shuttle/transit
@@ -103,6 +110,10 @@
/area/shuttle/custom
name = "Custom player shuttle"
/area/shuttle/custom/powered
name = "Custom Powered player shuttle"
requires_power = FALSE
/area/shuttle/arrival
name = "Arrival Shuttle"
unique = TRUE // SSjob refers to this area for latejoiners
+38 -1
View File
@@ -8,6 +8,13 @@
var/interaction_flags_atom = NONE
var/datum/reagents/reagents = null
var/flags_ricochet = NONE
///When a projectile tries to ricochet off this atom, the projectile ricochet chance is multiplied by this
var/ricochet_chance_mod = 1
///When a projectile ricochets off this atom, it deals the normal damage * this modifier to this atom
var/ricochet_damage_mod = 0.33
//This atom's HUD (med/sec, etc) images. Associative list.
var/list/image/hud_list = null
//HUD images that this atom can provide.
@@ -141,8 +148,27 @@
return ..()
/**
* Checks if a projectile should ricochet off of us. Projectiles get final say.
* [__DEFINES/projectiles.dm] for return values.
*/
/atom/proc/check_projectile_ricochet(obj/item/projectile/P)
return (flags_1 & DEFAULT_RICOCHET_1)? PROJECTILE_RICOCHET_YES : PROJECTILE_RICOCHET_NO
/atom/proc/handle_ricochet(obj/item/projectile/P)
return
var/turf/p_turf = get_turf(P)
var/face_direction = get_dir(src, p_turf)
var/face_angle = dir2angle(face_direction)
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (P.Angle + 180))
var/a_incidence_s = abs(incidence_s)
if(a_incidence_s > 90 && a_incidence_s < 270)
return FALSE
if((P.flag in list("bullet", "bomb")) && P.ricochet_incidence_leeway)
if((a_incidence_s < 90 && a_incidence_s < 90 - P.ricochet_incidence_leeway) || (a_incidence_s > 270 && a_incidence_s -270 > P.ricochet_incidence_leeway))
return
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
P.setAngle(new_angle_s)
return TRUE
/atom/proc/CanPass(atom/movable/mover, turf/target)
return !density
@@ -846,6 +872,17 @@
/atom/proc/GenerateTag()
return
/**
* Called after a shuttle is loaded **from map template initially**.
*
* @params
* * port - Mobile port/shuttle
* * dock - Stationary dock the shuttle's at
* * idnum - ID number of the shuttle
*/
/atom/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
return
// Generic logging helper
/atom/proc/log_message(message, message_type, color=null, log_globally=TRUE)
if(!log_globally)
@@ -202,7 +202,7 @@
icon_state = "moustacheg"
clumsy_check = GRENADE_NONCLUMSY_FUMBLE
/obj/item/grenade/chem_grenade/teargas/moustache/prime()
/obj/item/grenade/chem_grenade/teargas/moustache/prime(mob/living/lanced_by)
var/list/check_later = list()
for(var/mob/living/carbon/C in get_turf(src))
check_later += C
+2 -2
View File
@@ -145,7 +145,7 @@
new /obj/item/stack/sheet/plasteel(src.loc)
qdel(src)
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user)
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
add_fingerprint(user)
return ..()
@@ -240,4 +240,4 @@
#undef DOM_BLOCKED_SPAM_CAP
#undef DOM_REQUIRED_TURFS
#undef DOM_HULK_HITS_REQUIRED
#undef DOM_HULK_HITS_REQUIRED
+1 -1
View File
@@ -288,7 +288,7 @@ datum/gang_item/clothing/shades //Addition: Why not have cool shades on a gang m
name = "Fragmentation Grenade"
id = "frag nade"
cost = 5
item_path = /obj/item/grenade/syndieminibomb/concussion/frag
item_path = /obj/item/grenade/frag
/datum/gang_item/equipment/implant_breaker
name = "Implant Breaker"
+2
View File
@@ -92,6 +92,8 @@ Class Procs:
pressure_resistance = 15
max_integrity = 200
layer = BELOW_OBJ_LAYER //keeps shit coming out of the machine from ending up underneath it.
flags_ricochet = RICOCHET_HARD
ricochet_chance_mod = 0.3
anchored = TRUE
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
+9
View File
@@ -257,3 +257,12 @@
name = "AI upload monitor"
desc = "A telescreen that connects to the AI upload's camera network."
network = list("aiupload")
// Subtype that connects to shuttles.
/obj/machinery/computer/security/shuttle
circuit = /obj/item/circuitboard/computer/security/shuttle
/obj/machinery/computer/security/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
for(var/i in network)
network -= i
network += "[idnum][i]"
+2 -1
View File
@@ -169,7 +169,8 @@
to_chat(user, "[src] is now in [mode] mode.")
/obj/item/grenade/barrier/prime()
/obj/item/grenade/barrier/prime(mob/living/lanced_by)
. = ..()
new /obj/structure/barricade/security(get_turf(src.loc))
switch(mode)
if(VERTICAL)
@@ -1,7 +1,7 @@
/obj/item/electronics/airlock
name = "airlock electronics"
req_access = list(ACCESS_MAINT_TUNNELS)
custom_price = 50
custom_price = PRICE_CHEAP
var/list/accesses = list()
var/one_access = 0
+1
View File
@@ -12,6 +12,7 @@
armor = list("melee" = 30, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 70)
CanAtmosPass = ATMOS_PASS_DENSITY
flags_1 = PREVENT_CLICK_UNDER_1
ricochet_chance_mod = 0.8
interaction_flags_atom = INTERACT_ATOM_UI_INTERACT
+1 -1
View File
@@ -260,7 +260,7 @@
/obj/item/electronics/firelock
name = "firelock circuitry"
custom_price = 50
custom_price = PRICE_CHEAP
desc = "A circuit board used in construction of firelocks."
icon_state = "mainboard"
+1 -1
View File
@@ -2,7 +2,7 @@
/obj/item/electronics/firealarm
name = "fire alarm electronics"
custom_price = 50
custom_price = PRICE_CHEAP
desc = "A fire alarm circuit. Can handle heat levels up to 40 degrees celsius."
/obj/item/wallframe/firealarm
@@ -70,7 +70,7 @@
else
return ..()
/obj/machinery/porta_turret_cover/attacked_by(obj/item/I, mob/user)
/obj/machinery/porta_turret_cover/attacked_by(obj/item/I, mob/user, attackchain_flags = NONE, damage_multiplier = 1)
return parent_turret.attacked_by(I, user)
/obj/machinery/porta_turret_cover/attack_alien(mob/living/carbon/alien/humanoid/user)
@@ -0,0 +1,33 @@
/obj/machinery/shuttle
name = "shuttle component"
desc = "Something for shuttles."
density = TRUE
obj_integrity = 250
max_integrity = 250
icon = 'icons/turf/shuttle.dmi'
icon_state = "burst_plasma"
idle_power_usage = 150
circuit = /obj/item/circuitboard/machine/shuttle/engine
var/icon_state_closed = "burst_plasma"
var/icon_state_open = "burst_plasma_open"
var/icon_state_off = "burst_plasma_off"
/obj/machinery/shuttle/Initialize()
. = ..()
GLOB.custom_shuttle_machines += src
/obj/machinery/shuttle/Destroy()
. = ..()
GLOB.custom_shuttle_machines -= src
/obj/machinery/shuttle/attackby(obj/item/I, mob/living/user, params)
if(default_deconstruction_screwdriver(user, icon_state_open, icon_state_closed, I))
return
if(default_pry_open(I))
return
if(panel_open)
if(default_change_direction_wrench(user, I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
@@ -0,0 +1,138 @@
//-----------------------------------------------
//-------------Engine Thrusters------------------
//-----------------------------------------------
#define ENGINE_HEAT_TARGET 600
#define ENGINE_HEATING_POWER 5000000
/obj/machinery/shuttle/engine
name = "shuttle thruster"
desc = "A thruster for shuttles."
density = TRUE
obj_integrity = 250
max_integrity = 250
icon = 'icons/turf/shuttle.dmi'
icon_state = "burst_plasma"
idle_power_usage = 150
circuit = /obj/item/circuitboard/machine/shuttle/engine
var/thrust = 0
var/fuel_use = 0
var/bluespace_capable = TRUE
var/cooldown = 0
var/thruster_active = FALSE
var/datum/weakref/attached_heater
/obj/machinery/shuttle/engine/plasma
name = "plasma thruster"
desc = "A thruster that burns plasma stored in an adjacent plasma thruster heater."
icon_state = "burst_plasma"
icon_state_off = "burst_plasma_off"
idle_power_usage = 0
circuit = /obj/item/circuitboard/machine/shuttle/engine/plasma
thrust = 25
fuel_use = 0.24
bluespace_capable = FALSE
cooldown = 45
/obj/machinery/shuttle/engine/void
name = "void thruster"
desc = "A thruster using technology to breach voidspace for propulsion."
icon_state = "burst_void"
icon_state_off = "burst_void"
icon_state_closed = "burst_void"
icon_state_open = "burst_void_open"
idle_power_usage = 0
circuit = /obj/item/circuitboard/machine/shuttle/engine/void
thrust = 400
fuel_use = 0
bluespace_capable = TRUE
cooldown = 90
/obj/machinery/shuttle/engine/Initialize()
. = ..()
check_setup()
/obj/machinery/shuttle/engine/on_construction()
. = ..()
check_setup()
/obj/machinery/shuttle/engine/Destroy()
attached_heater = FALSE
thruster_active = FALSE
return ..()
/obj/machinery/shuttle/engine/proc/check_setup()
if(!anchored)
attached_heater = null
update_engine()
return
var/heater_turf
switch(dir)
if(NORTH)
heater_turf = get_offset_target_turf(src, 0, 1)
if(SOUTH)
heater_turf = get_offset_target_turf(src, 0, -1)
if(EAST)
heater_turf = get_offset_target_turf(src, 1, 0)
if(WEST)
heater_turf = get_offset_target_turf(src, -1, 0)
if(!heater_turf)
attached_heater = null
update_engine()
return
attached_heater = null
for(var/obj/machinery/atmospherics/components/unary/shuttle/heater/as_heater in heater_turf)
if(as_heater.dir != dir)
continue
if(as_heater.panel_open)
continue
if(!as_heater.anchored)
continue
attached_heater = WEAKREF(as_heater)
break
update_engine()
return
/obj/machinery/shuttle/engine/proc/update_engine()
if(!attached_heater)
icon_state = icon_state_off
thruster_active = FALSE
return
var/obj/machinery/atmospherics/components/unary/shuttle/heater/resolved_heater = attached_heater.resolve()
if(panel_open)
thruster_active = FALSE
else if(resolved_heater?.hasFuel(1))
icon_state = icon_state_closed
thruster_active = TRUE
else
thruster_active = FALSE
icon_state = icon_state_off
return
/obj/machinery/shuttle/engine/void/update_engine()
if(panel_open)
thruster_active = FALSE
return
thruster_active = TRUE
icon_state = icon_state_closed
return
//Thanks to spaceheater.dm for inspiration :)
/obj/machinery/shuttle/engine/proc/fireEngine()
var/turf/heatTurf = loc
if(!heatTurf)
return
var/datum/gas_mixture/env = heatTurf.return_air()
var/heat_cap = env.heat_capacity()
var/req_power = abs(env.return_temperature() - ENGINE_HEAT_TARGET) * heat_cap
req_power = min(req_power, ENGINE_HEATING_POWER)
var/deltaTemperature = req_power / heat_cap
if(deltaTemperature < 0)
return
env.temperature += deltaTemperature
air_update_turf()
/obj/machinery/shuttle/engine/default_change_direction_wrench(mob/user, obj/item/I)
. = ..()
update_engine()
@@ -0,0 +1,132 @@
//-----------------------------------------------
//--------------Engine Heaters-------------------
//This uses atmospherics, much like a thermomachine,
//but instead of changing temp, it stores plasma and uses
//it for the engine.
//-----------------------------------------------
/obj/machinery/atmospherics/components/unary/shuttle
name = "shuttle atmospherics device"
desc = "This does something to do with shuttle atmospherics"
icon_state = "heater"
icon = 'icons/turf/shuttle.dmi'
/obj/machinery/atmospherics/components/unary/shuttle/heater
name = "engine heater"
desc = "Directs energy into compressed particles in order to power an attached thruster."
icon_state = "heater_pipe"
var/icon_state_closed = "heater_pipe"
var/icon_state_open = "heater_pipe_open"
var/icon_state_off = "heater_pipe"
idle_power_usage = 50
circuit = /obj/item/circuitboard/machine/shuttle/heater
density = TRUE
max_integrity = 400
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 30)
layer = OBJ_LAYER
showpipe = TRUE
pipe_flags = PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY
var/gas_type = /datum/gas/plasma
var/efficiency_multiplier = 1
var/gas_capacity = 0
/obj/machinery/atmospherics/components/unary/shuttle/heater/New()
. = ..()
GLOB.custom_shuttle_machines += src
SetInitDirections()
update_adjacent_engines()
updateGasStats()
/obj/machinery/atmospherics/components/unary/shuttle/heater/Destroy()
. = ..()
update_adjacent_engines()
GLOB.custom_shuttle_machines -= src
/obj/machinery/atmospherics/components/unary/shuttle/heater/on_construction()
..(dir, dir)
SetInitDirections()
update_adjacent_engines()
/obj/machinery/atmospherics/components/unary/shuttle/heater/default_change_direction_wrench(mob/user, obj/item/I)
if(!..())
return FALSE
SetInitDirections()
var/obj/machinery/atmospherics/node = nodes[1]
if(node)
node.disconnect(src)
nodes[1] = null
if(!parents[1])
return
nullifyPipenet(parents[1])
atmosinit()
node = nodes[1]
if(node)
node.atmosinit()
node.addMember(src)
build_network()
return TRUE
/obj/machinery/atmospherics/components/unary/shuttle/heater/RefreshParts()
var/cap = 0
var/eff = 0
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
cap += M.rating
for(var/obj/item/stock_parts/micro_laser/L in component_parts)
eff += L.rating
gas_capacity = 5000 * ((cap - 1) ** 2) + 1000
efficiency_multiplier = round(((eff / 2) / 2.8) ** 2, 0.1)
updateGasStats()
/obj/machinery/atmospherics/components/unary/shuttle/heater/examine(mob/user)
. = ..()
var/datum/gas_mixture/air_contents = airs[1]
. += "The engine heater's gas dial reads [air_contents.return_volume()] liters in internal tank.<br>"
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/updateGasStats()
var/datum/gas_mixture/air_contents = airs[1]
if(!air_contents)
return
air_contents.volume = gas_capacity
air_contents.temperature = T20C
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/hasFuel(var/required)
var/datum/gas_mixture/air_contents = airs[1]
var/moles = air_contents.total_moles()
return moles >= required
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/consumeFuel(var/amount)
var/datum/gas_mixture/air_contents = airs[1]
air_contents.remove(amount)
return
/obj/machinery/atmospherics/components/unary/shuttle/heater/attackby(obj/item/I, mob/living/user, params)
update_adjacent_engines()
if(default_deconstruction_screwdriver(user, icon_state_open, icon_state_closed, I))
return
if(default_pry_open(I))
return
if(panel_open)
if(default_change_direction_wrench(user, I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/update_adjacent_engines()
var/engine_turf
switch(dir)
if(NORTH)
engine_turf = get_offset_target_turf(src, 0, -1)
if(SOUTH)
engine_turf = get_offset_target_turf(src, 0, 1)
if(EAST)
engine_turf = get_offset_target_turf(src, -1, 0)
if(WEST)
engine_turf = get_offset_target_turf(src, 1, 0)
if(!engine_turf)
return
for(var/obj/machinery/shuttle/engine/E in engine_turf)
E.check_setup()
+1 -1
View File
@@ -290,7 +290,7 @@
if("shuttle_id")
update()
/obj/machinery/status_display/shuttle/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
/obj/machinery/status_display/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
if (port && (shuttle_id == initial(shuttle_id) || override))
shuttle_id = port.id
update()
+1 -1
View File
@@ -282,7 +282,7 @@
else
return ..()
/obj/mecha/attacked_by(obj/item/I, mob/living/user)
/obj/mecha/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
mecha_log_message("Attacked by [I]. Attacker - [user]")
return ..()
+5
View File
@@ -428,6 +428,11 @@
desc = "A poster decipting a snake shaped into an ominous 'S'!"
icon_state = "poster47"
/obj/structure/sign/poster/contraband/bountyhunters
name = "Bounty Hunters"
desc = "A poster advertising bounty hunting services. \"I hear you got a problem.\""
icon_state = "poster48"
/obj/structure/sign/poster/official
poster_item_name = "motivational poster"
poster_item_desc = "An official Nanotrasen-issued poster to foster a compliant and obedient workforce. It comes with state-of-the-art adhesive backing, for easy pinning to any vertical surface."
+28 -10
View File
@@ -5,19 +5,21 @@
anchored = TRUE
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "uglymine"
var/triggered = 0
/// We manually check to see if we've been triggered in case multiple atoms cross us in the time between the mine being triggered and it actually deleting, to avoid a race condition with multiple detonations
var/triggered = FALSE
/obj/effect/mine/proc/mineEffect(mob/victim)
to_chat(victim, "<span class='danger'>*click*</span>")
/obj/effect/mine/Crossed(AM as mob|obj)
if(isturf(loc))
if(ismob(AM))
var/mob/MM = AM
if(!(MM.movement_type & FLYING))
triggermine(AM)
else
triggermine(AM)
/obj/effect/mine/Crossed(atom/movable/AM)
if(triggered || !isturf(loc))
return
. = ..()
if(AM.movement_type & FLYING)
return
triggermine(AM)
/obj/effect/mine/proc/triggermine(mob/victim)
if(triggered)
@@ -27,9 +29,13 @@
s.set_up(3, 1, src)
s.start()
mineEffect(victim)
SEND_SIGNAL(src, COMSIG_MINE_TRIGGERED)
triggered = 1
qdel(src)
/obj/effect/mine/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir)
. = ..()
triggermine()
/obj/effect/mine/explosive
name = "explosive mine"
@@ -50,6 +56,18 @@
if(isliving(victim))
victim.DefaultCombatKnockdown(stun_time)
/obj/effect/mine/shrapnel
name = "shrapnel mine"
var/shrapnel_type = /obj/item/projectile/bullet/shrapnel
var/shrapnel_magnitude = 3
/obj/effect/mine/shrapnel/mineEffect(mob/victim)
AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_magnitude)
/obj/effect/mine/shrapnel/sting
name = "stinger mine"
shrapnel_type = /obj/item/projectile/bullet/pellet/stingball
/obj/effect/mine/kickmine
name = "kick mine"
@@ -105,7 +123,7 @@
/obj/effect/mine/pickup/triggermine(mob/victim)
if(triggered)
return
triggered = 1
triggered = TRUE
invisibility = INVISIBILITY_ABSTRACT
mineEffect(victim)
qdel(src)
+90 -3
View File
@@ -491,7 +491,7 @@
/obj/item/kitchen/knife = 5,
/obj/item/screwdriver = 5,
/obj/item/crowbar/red = 1, //Dont you need a crowbar to open this?
/obj/item/stack/medical/bruise_pack = 3,
/obj/item/stack/medical/suture = 3,
/obj/item/reagent_containers/food/drinks/bottle/vodka = 2,
/obj/item/radio = 5,
/obj/item/flashlight = 4,
@@ -611,13 +611,13 @@
/obj/item/clothing/mask/breath = 5,
/obj/item/clothing/mask/breath/medical = 1
)
/obj/effect/spawner/lootdrop/welder_tools/no_turf
spawn_on_turf = FALSE
/obj/effect/spawner/lootdrop/low_tools/no_turf
spawn_on_turf = FALSE
/obj/effect/spawner/lootdrop/breathing_tanks/no_turf
spawn_on_turf = FALSE
@@ -644,3 +644,90 @@
/obj/effect/spawner/lootdrop/glowstick/no_turf
spawn_on_turf = FALSE
// Random Parts
/obj/effect/spawner/lootdrop/stock_parts
name = "random stock parts spawner"
lootcount = 1
loot = list(
/obj/item/stock_parts/capacitor,
/obj/item/stock_parts/scanning_module,
/obj/item/stock_parts/manipulator,
/obj/item/stock_parts/micro_laser,
/obj/item/stock_parts/matter_bin,
/obj/item/stock_parts/cell
)
// Random Weapon Parts
/obj/effect/spawner/lootdrop/weapon_parts
name = "random weapon parts spawner 50%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 50,
/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 10,
/obj/item/weaponcrafting/improvised_parts/barrel_shotgun = 5,
/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 5,
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 10,
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 3,
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 3,
/obj/item/weaponcrafting/improvised_parts/laser_receiver = 1,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 10,
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 3,
)
/obj/effect/spawner/lootdrop/weapon_parts
name = "random weapon parts spawner 25%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 75,
/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 5,
/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 5,
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 5,
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 2,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 5,
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 3,
)
/obj/effect/spawner/lootdrop/ammo
name = "random ammo 75%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 25,
/obj/item/ammo_box/c32mm = 15,
/obj/item/ammo_box/r32mm = 15,
/obj/item/ammo_box/magazine/wt550m9 = 1,
/obj/item/ammo_casing/shotgun/buckshot = 7,
/obj/item/ammo_casing/shotgun/rubbershot = 7,
/obj/item/ammo_casing/a762 = 15,
/obj/item/ammo_box/a762 = 15,
)
/obj/effect/spawner/lootdrop/ammo/fiftypercent
name = "random ammo 50%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 50,
/obj/item/ammo_box/c32mm = 7,
/obj/item/ammo_box/r32mm = 7,
/obj/item/ammo_box/magazine/wt550m9 = 2,
/obj/item/ammo_casing/shotgun/buckshot = 10,
/obj/item/ammo_casing/shotgun/rubbershot = 10,
/obj/item/ammo_casing/a762 = 7,
/obj/item/ammo_box/a762 = 7,
)
/obj/effect/spawner/lootdrop/ammo/shotgun
name = "random ammo 50%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 50,
/obj/item/ammo_box/shotgun/loaded/buckshot = 5,
/obj/item/ammo_box/shotgun/loaded/beanbag = 5,
/obj/item/ammo_box/shotgun/loaded/incendiary = 5,
/obj/item/ammo_casing/shotgun/buckshot = 8,
/obj/item/ammo_casing/shotgun/rubbershot = 9,
/obj/item/ammo_casing/shotgun = 8,
/obj/item/ammo_casing/shotgun/incendiary = 10,
)
+174 -20
View File
@@ -4,6 +4,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// if true, everyone item when created will have its name changed to be
// more... RPG-like.
GLOBAL_VAR_INIT(stickpocalypse, FALSE) // if true, all non-embeddable items will be able to harmlessly stick to people when thrown
GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to embed in people, takes precedence over stickpocalypse
/obj/item
name = "item"
icon = 'icons/obj/items_and_weapons.dmi'
@@ -104,7 +107,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
var/datum/embedding_behavior/embedding
var/list/embedding = NONE
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
var/heat = 0
@@ -141,6 +144,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
/* Our block parry data. Should be set in init, or something if you are using it.
* This won't be accessed without ITEM_CAN_BLOCK or ITEM_CAN_PARRY so do not set it unless you have to to save memory.
* If you decide it's a good idea to leave this unset while turning the flags on, you will runtime. Enjoy.
* If this is set to a path, it'll run get_block_parry_data(path). YOU MUST RUN [get_block_parry_data(this)] INSTEAD OF DIRECTLY ACCESSING!
*/
var/datum/block_parry_data/block_parry_data
///Skills vars
//list of skill PATHS exercised when using this item. An associated bitfield can be set to indicate additional ways the skill is used by this specific item.
var/list/datum/skill/used_skills
@@ -152,7 +162,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/obj/item/Initialize()
if (attack_verb)
if(attack_verb)
attack_verb = typelist("attack_verb", attack_verb)
. = ..()
@@ -160,9 +170,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
new path(src)
actions_types = null
if(GLOB.rpg_loot_items)
AddComponent(/datum/component/fantasy)
if(force_string)
item_flags |= FORCE_STRING_OVERRIDE
@@ -172,16 +179,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(damtype == "brute")
hitsound = "swing_hit"
if (!embedding)
embedding = getEmbeddingBehavior()
else if (islist(embedding))
embedding = getEmbeddingBehavior(arglist(embedding))
else if (!istype(embedding, /datum/embedding_behavior))
stack_trace("Invalid type [embedding.type] found in .embedding during /obj/item Initialize()")
if(sharpness) //give sharp objects butchering functionality, for consistency
AddComponent(/datum/component/butchering, 80 * toolspeed)
/obj/item/Destroy()
item_flags &= ~DROPDEL //prevent reqdels
if(ismob(loc))
@@ -191,6 +188,26 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
qdel(X)
return ..()
/obj/item/ComponentInitialize()
. = ..()
// this proc says it's for initializing components, but we're initializing elements too because it's you and me against the world >:)
if(!LAZYLEN(embedding))
if(GLOB.embedpocalypse)
embedding = EMBED_POINTY
name = "pointy [name]"
else if(GLOB.stickpocalypse)
embedding = EMBED_HARMLESS
name = "sticky [name]"
updateEmbedding()
if(GLOB.rpg_loot_items)
AddComponent(/datum/component/fantasy)
if(sharpness) //give sharp objects butchering functionality, for consistency
AddComponent(/datum/component/butchering, 80 * toolspeed)
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside))
return 0
@@ -240,9 +257,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
. += "[src] is made of cold-resistant materials."
if(resistance_flags & FIRE_PROOF)
. += "[src] is made of fire-retardant materials."
if(item_flags & (ITEM_CAN_BLOCK | ITEM_CAN_PARRY))
var/datum/block_parry_data/data = return_block_parry_datum(block_parry_data)
. += "[src] has the capacity to be used to block and/or parry. <a href='?src=[REF(data)];name=[name];block=[item_flags & ITEM_CAN_BLOCK];parry=[item_flags & ITEM_CAN_PARRY];render=1'>\[Show Stats\]</a>"
if(!user.research_scanner)
return
@@ -404,6 +422,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return ITALICS | REDUCE_RANGE
/obj/item/proc/dropped(mob/user)
SHOULD_CALL_PARENT(TRUE)
for(var/X in actions)
var/datum/action/A = X
A.Remove(user)
@@ -416,6 +435,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// called just as an item is picked up (loc is not yet changed)
/obj/item/proc/pickup(mob/user)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user)
item_flags |= IN_INVENTORY
@@ -908,11 +928,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// if w_volume is 0 you fucked up anyways lol
return w_volume || AUTO_SCALE_VOLUME(w_class)
/obj/item/proc/embedded(mob/living/carbon/human/embedded_mob)
/obj/item/proc/embedded(atom/embedded_target)
return
/obj/item/proc/unembedded()
return
if(item_flags & DROPDEL)
QDEL_NULL(src)
return TRUE
/**
* Sets our slowdown and updates equipment slowdown of any mob we're equipped on.
@@ -928,3 +950,135 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
. = ..()
if(var_name == NAMEOF(src, slowdown))
set_slowdown(var_value) //don't care if it's a duplicate edit as slowdown'll be set, do it anyways to force normal behavior.
/**
* Does the current embedding var meet the criteria for being harmless? Namely, does it explicitly define the pain multiplier and jostle pain mult to be 0? If so, return true.
*
*/
/obj/item/proc/isEmbedHarmless()
if(embedding)
return !isnull(embedding["pain_mult"]) && !isnull(embedding["jostle_pain_mult"]) && embedding["pain_mult"] == 0 && embedding["jostle_pain_mult"] == 0
///In case we want to do something special (like self delete) upon failing to embed in something, return true
/obj/item/proc/failedEmbed()
if(item_flags & DROPDEL)
QDEL_NULL(src)
return TRUE
/**
* tryEmbed() is for when you want to try embedding something without dealing with the damage + hit messages of calling hitby() on the item while targetting the target.
*
* Really, this is used mostly with projectiles with shrapnel payloads, from [/datum/element/embed/proc/checkEmbedProjectile], and called on said shrapnel. Mostly acts as an intermediate between different embed elements.
*
* Arguments:
* * target- Either a body part, a carbon, or a closed turf. What are we hitting?
* * forced- Do we want this to go through 100%?
*/
/obj/item/proc/tryEmbed(atom/target, forced=FALSE, silent=FALSE)
if(!isbodypart(target) && !iscarbon(target) && !isclosedturf(target))
return
if(!forced && !LAZYLEN(embedding))
return
if(SEND_SIGNAL(src, COMSIG_EMBED_TRY_FORCE, target, forced, silent))
return TRUE
failedEmbed()
///For when you want to disable an item's embedding capabilities (like transforming weapons and such), this proc will detach any active embed elements from it.
/obj/item/proc/disableEmbedding()
SEND_SIGNAL(src, COMSIG_ITEM_DISABLE_EMBED)
return
///For when you want to add/update the embedding on an item. Uses the vars in [/obj/item/embedding], and defaults to config values for values that aren't set. Will automatically detach previous embed elements on this item.
/obj/item/proc/updateEmbedding()
if(!islist(embedding) || !LAZYLEN(embedding))
return
AddElement(/datum/element/embed,\
embed_chance = (!isnull(embedding["embed_chance"]) ? embedding["embed_chance"] : EMBED_CHANCE),\
fall_chance = (!isnull(embedding["fall_chance"]) ? embedding["fall_chance"] : EMBEDDED_ITEM_FALLOUT),\
pain_chance = (!isnull(embedding["pain_chance"]) ? embedding["pain_chance"] : EMBEDDED_PAIN_CHANCE),\
pain_mult = (!isnull(embedding["pain_mult"]) ? embedding["pain_mult"] : EMBEDDED_PAIN_MULTIPLIER),\
remove_pain_mult = (!isnull(embedding["remove_pain_mult"]) ? embedding["remove_pain_mult"] : EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER),\
rip_time = (!isnull(embedding["rip_time"]) ? embedding["rip_time"] : EMBEDDED_UNSAFE_REMOVAL_TIME),\
ignore_throwspeed_threshold = (!isnull(embedding["ignore_throwspeed_threshold"]) ? embedding["ignore_throwspeed_threshold"] : FALSE),\
impact_pain_mult = (!isnull(embedding["impact_pain_mult"]) ? embedding["impact_pain_mult"] : EMBEDDED_IMPACT_PAIN_MULTIPLIER),\
jostle_chance = (!isnull(embedding["jostle_chance"]) ? embedding["jostle_chance"] : EMBEDDED_JOSTLE_CHANCE),\
jostle_pain_mult = (!isnull(embedding["jostle_pain_mult"]) ? embedding["jostle_pain_mult"] : EMBEDDED_JOSTLE_PAIN_MULTIPLIER),\
pain_stam_pct = (!isnull(embedding["pain_stam_pct"]) ? embedding["pain_stam_pct"] : EMBEDDED_PAIN_STAM_PCT),\
embed_chance_turf_mod = (!isnull(embedding["embed_chance_turf_mod"]) ? embedding["embed_chance_turf_mod"] : EMBED_CHANCE_TURF_MOD))
return TRUE
+2 -1
View File
@@ -154,7 +154,8 @@ RLD
icon_state = "rcd"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
custom_price = 900
custom_price = PRICE_ABOVE_EXPENSIVE
custom_premium_price = PRICE_ALMOST_ONE_GRAND
max_matter = 160
item_flags = NO_MAT_REDEMPTION | NOBLUDGEON
has_ammobar = TRUE
+55 -9
View File
@@ -83,7 +83,7 @@
/obj/item/card/emag/bluespace
name = "bluespace cryptographic sequencer"
desc = "It's a blue card with a magnetic strip attached to some circuitry. It appears to have some sort of transmitter attached to it."
color = rgb(40, 130, 255)
icon_state = "emag_bs"
prox_check = FALSE
/obj/item/card/emag/attack()
@@ -166,6 +166,7 @@
slot_flags = ITEM_SLOT_ID
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
resistance_flags = FIRE_PROOF | ACID_PROOF
var/id_type_name = "identification card"
var/mining_points = 0 //For redeeming at mining equipment vendors
var/list/access = list()
var/registered_name = null // The name registered_name on the card
@@ -174,6 +175,8 @@
var/bank_support = ID_FREE_BANK_ACCOUNT
var/datum/bank_account/registered_account
var/obj/machinery/paystand/my_store
var/uses_overlays = TRUE
var/icon/cached_flat_icon
/obj/item/card/id/Initialize(mapload)
. = ..()
@@ -187,6 +190,15 @@
if(ID_LOCKED_BANK_ACCOUNT)
registered_account = new /datum/bank_account/remote/non_transferable(pick(GLOB.redacted_strings))
/obj/item/card/id/Destroy()
if(bank_support == ID_LOCKED_BANK_ACCOUNT)
QDEL_NULL(registered_account)
else
registered_account = null
if(my_store)
my_store.my_card = null
my_store = null
return ..()
/obj/item/card/id/vv_edit_var(var_name, var_value)
. = ..()
@@ -353,20 +365,38 @@
/obj/item/card/id/RemoveID()
return src
/*
Usage:
update_label()
Sets the id name to whatever registered_name and assignment is
/obj/item/card/id/update_overlays()
. = ..()
if(!uses_overlays)
return
cached_flat_icon = null
var/job = assignment ? ckey(GetJobName()) : null
if(registered_name == "Captain")
job = "captain"
if(registered_name && registered_name != "Captain")
. += mutable_appearance(icon, "assigned")
if(job)
. += mutable_appearance(icon, "id[job]")
/obj/item/card/id/proc/get_cached_flat_icon()
if(!cached_flat_icon)
cached_flat_icon = getFlatIcon(src)
return cached_flat_icon
/obj/item/card/id/get_examine_string(mob/user, thats = FALSE)
if(uses_overlays)
return "[icon2html(get_cached_flat_icon(), user)] [thats? "That's ":""][get_examine_name(user)]" //displays all overlays in chat
return ..()
update_label("John Doe", "Clowny")
Properly formats the name and occupation and sets the id name to the arguments
*/
/obj/item/card/id/proc/update_label(newname, newjob)
if(newname || newjob)
name = "[(!newname) ? "identification card" : "[newname]'s ID Card"][(!newjob) ? "" : " ([newjob])"]"
update_icon()
return
name = "[(!registered_name) ? "identification card" : "[registered_name]'s ID Card"][(!assignment) ? "" : " ([assignment])"]"
update_icon()
/obj/item/card/id/silver
name = "silver identification card"
@@ -379,6 +409,7 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/silver/reaper
name = "Thirteen's ID Card (Reaper)"
access = list(ACCESS_MAINT_TUNNELS)
icon_state = "reaper"
assignment = "Reaper"
registered_name = "Thirteen"
@@ -530,7 +561,7 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/ert
name = "\improper CentCom ID"
desc = "An ERT ID card."
icon_state = "centcom"
icon_state = "ert_commander"
registered_name = "Emergency Response Team Commander"
assignment = "Emergency Response Team Commander"
@@ -539,6 +570,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/Security
icon_state = "ert_security"
registered_name = "Security Response Officer"
assignment = "Security Response Officer"
@@ -547,6 +579,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/Engineer
icon_state = "ert_engineer"
registered_name = "Engineer Response Officer"
assignment = "Engineer Response Officer"
@@ -555,6 +588,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/Medical
icon_state = "ert_medical"
registered_name = "Medical Response Officer"
assignment = "Medical Response Officer"
@@ -563,6 +597,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/chaplain
icon_state = "ert_chaplain"
registered_name = "Religious Response Officer"
assignment = "Religious Response Officer"
@@ -615,40 +650,49 @@ update_label("John Doe", "Clowny")
. += "<span class='notice'>Your sentence is up! You're free!</span>"
/obj/item/card/id/prisoner/one
icon_state = "prisoner_001"
name = "Prisoner #13-001"
registered_name = "Prisoner #13-001"
/obj/item/card/id/prisoner/two
icon_state = "prisoner_002"
name = "Prisoner #13-002"
registered_name = "Prisoner #13-002"
/obj/item/card/id/prisoner/three
icon_state = "prisoner_003"
name = "Prisoner #13-003"
registered_name = "Prisoner #13-003"
/obj/item/card/id/prisoner/four
icon_state = "prisoner_004"
name = "Prisoner #13-004"
registered_name = "Prisoner #13-004"
/obj/item/card/id/prisoner/five
icon_state = "prisoner_005"
name = "Prisoner #13-005"
registered_name = "Prisoner #13-005"
/obj/item/card/id/prisoner/six
icon_state = "prisoner_006"
name = "Prisoner #13-006"
registered_name = "Prisoner #13-006"
/obj/item/card/id/prisoner/seven
icon_state = "prisoner_007"
name = "Prisoner #13-007"
registered_name = "Prisoner #13-007"
/obj/item/card/id/mining
name = "mining ID"
icon_state = "retro"
access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/away
name = "a perfectly generic identification card"
desc = "A perfectly generic identification card. Looks like it could use some flavor."
icon_state = "retro"
access = list(ACCESS_AWAY_GENERAL)
/obj/item/card/id/away/hotel
@@ -691,6 +735,7 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/departmental_budget
name = "departmental card (FUCK)"
desc = "Provides access to the departmental budget."
icon_state = "budgetcard"
var/department_ID = ACCOUNT_CIV
var/department_name = ACCOUNT_CIV_NAME
@@ -703,6 +748,7 @@ update_label("John Doe", "Clowny")
B.bank_cards += src
name = "departmental card ([department_name])"
desc = "Provides access to the [department_name]."
icon_state = "[lowertext(department_ID)]_budget"
SSeconomy.dep_cards += src
/obj/item/card/id/departmental_budget/Destroy()
+6 -1
View File
@@ -8,6 +8,9 @@ CIGARS
SMOKING PIPES
CHEAP LIGHTERS
ZIPPO
ROLLING PAPER
VAPES
BONGS
CIGARETTE PACKETS ARE IN FANCY.DM
*/
@@ -506,7 +509,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
resistance_flags = FIRE_PROOF
light_color = LIGHT_COLOR_FIRE
grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/oil = 5)
custom_price = 55
custom_price = PRICE_ALMOST_CHEAP
/obj/item/lighter/Initialize()
. = ..()
@@ -616,6 +619,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
desc = "A cheap-as-free lighter."
icon_state = "lighter"
fancy = FALSE
custom_price = PRICE_CHEAP_AS_FREE
overlay_list = list(
"transp",
"tall",
@@ -799,6 +803,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
to_chat(user, "<span class='warning'>You need to close the cap first!</span>")
/obj/item/clothing/mask/vape/dropped(mob/user)
. = ..()
var/mob/living/carbon/C = user
if(C.get_item_by_slot(SLOT_WEAR_MASK) == src)
ENABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
@@ -14,6 +14,10 @@
name = "Security Cameras (Computer Board)"
build_path = /obj/machinery/computer/security
/obj/item/circuitboard/computer/security/shuttle
name = "Shuttlelinking Security Cameras (Computer Board)"
build_path = /obj/machinery/computer/security/shuttle
/obj/item/circuitboard/computer/xenobiology
name = "circuit board (Xenobiology Console)"
build_path = /obj/machinery/computer/camera_advanced/xenobio
@@ -379,3 +383,11 @@
/obj/item/circuitboard/computer/nanite_cloud_controller
name = "Nanite Cloud Control (Computer Board)"
build_path = /obj/machinery/computer/nanite_cloud_controller
/obj/item/circuitboard/computer/shuttle/flight_control
name = "Shuttle Flight Control (Computer Board)"
build_path = /obj/machinery/computer/custom_shuttle
/obj/item/circuitboard/computer/shuttle/docker
name = "Shuttle Navigation Computer (Computer Board)"
build_path = /obj/machinery/computer/camera_advanced/shuttle_docker/custom
@@ -1102,3 +1102,28 @@
/obj/item/stock_parts/micro_laser = 2,
/obj/item/stock_parts/scanning_module = 2
)
/obj/item/circuitboard/machine/shuttle/engine
name = "Thruster (Machine Board)"
build_path = /obj/machinery/shuttle/engine
req_components = list()
/obj/item/circuitboard/machine/shuttle/engine/plasma
name = "Plasma Thruster (Machine Board)"
build_path = /obj/machinery/shuttle/engine/plasma
req_components = list(/obj/item/stock_parts/capacitor = 2,
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/micro_laser = 1)
/obj/item/circuitboard/machine/shuttle/engine/void
name = "Void Thruster (Machine Board)"
build_path = /obj/machinery/shuttle/engine/void
req_components = list(/obj/item/stock_parts/capacitor/quadratic = 2,
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/micro_laser/quadultra = 1)
/obj/item/circuitboard/machine/shuttle/heater
name = "Electronic Engine Heater (Machine Board)"
build_path = /obj/machinery/atmospherics/components/unary/shuttle/heater
req_components = list(/obj/item/stock_parts/micro_laser = 2,
/obj/item/stock_parts/matter_bin = 1)
@@ -1,7 +1,7 @@
/obj/item/flashlight
name = "flashlight"
desc = "A hand-held emergency light."
custom_price = 100
custom_price = PRICE_REALLY_CHEAP
icon = 'icons/obj/lighting.dmi'
icon_state = "flashlight"
item_state = "flashlight"
@@ -211,6 +211,7 @@
light_color = "#CDDDFF"
flashlight_power = 0.9
hitsound = 'sound/weapons/genhit1.ogg'
custom_price = PRICE_ALMOST_CHEAP
// the desk lamps are a bit special
/obj/item/flashlight/lamp
@@ -351,12 +352,13 @@
brightness_on = 6 // luminosity when on
light_color = "#FFAA44"
flashlight_power = 0.8
custom_price = PRICE_CHEAP
/obj/item/flashlight/lantern/jade
name = "jade lantern"
desc = "An ornate, green lantern."
color = LIGHT_COLOR_GREEN
light_color = LIGHT_COLOR_GREEN
light_color = LIGHT_COLOR_GREEN
/obj/item/flashlight/slime
gender = PLURAL
@@ -429,7 +431,7 @@
/obj/item/flashlight/glowstick
name = "glowstick"
desc = "A military-grade glowstick."
custom_price = 50
custom_price = PRICE_CHEAP_AS_FREE
w_class = WEIGHT_CLASS_SMALL
brightness_on = 4
color = LIGHT_COLOR_GREEN
+6 -3
View File
@@ -6,12 +6,14 @@ T-RAY
HEALTH ANALYZER
GAS ANALYZER
SLIME SCANNER
NANITE SCANNER
GENETICS SCANNER
*/
/obj/item/t_scanner
name = "\improper T-ray scanner"
desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
custom_price = 150
custom_price = PRICE_REALLY_CHEAP
icon = 'icons/obj/device.dmi'
icon_state = "t-ray0"
var/on = FALSE
@@ -653,9 +655,10 @@ SLIME SCANNER
amount += inaccurate
return DisplayTimeText(max(1,amount))
/proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src)
/proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src, visible = TRUE)
var/icon = target
user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(user))] [target].", "<span class='notice'>You use the analyzer on [icon2html(icon, user)] [target].</span>")
if(visible)
user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(user))] [target].", "<span class='notice'>You use the analyzer on [icon2html(icon, user)] [target].</span>")
to_chat(user, "<span class='boldnotice'>Results of analysis of [icon2html(icon, user)] [target].</span>")
var/list/airs = islist(mixture) ? mixture : list(mixture)
@@ -5,7 +5,7 @@
icon_state = "scanner"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
custom_price = 900
custom_price = PRICE_ABOVE_EXPENSIVE
/obj/item/sensor_device/attack_self(mob/user)
GLOB.crewmonitor.show(user,src) //Proc already exists, just had to call it
@@ -7,7 +7,8 @@
var/forced_value = 0
var/duration = 300
/obj/item/grenade/antigravity/prime()
/obj/item/grenade/antigravity/prime(mob/living/lanced_by)
. = ..()
update_mob()
for(var/turf/T in view(range,src))
@@ -174,10 +174,11 @@
message_admins(message)
user.log_message("primed [src] ([reagent_string])",LOG_GAME)
/obj/item/grenade/chem_grenade/prime()
/obj/item/grenade/chem_grenade/prime(mob/living/lanced_by)
if(stage != READY)
return FALSE
. = ..()
var/list/datum/reagents/reactants = list()
for(var/obj/item/reagent_containers/glass/G in beakers)
reactants += G.reagents
@@ -217,7 +218,7 @@
ignition_temp = 25 // Large grenades are slightly more effective at setting off heat-sensitive mixtures than smaller grenades.
threatscale = 1.1 // 10% more effective.
/obj/item/grenade/chem_grenade/large/prime()
/obj/item/grenade/chem_grenade/large/prime(mob/living/lanced_by)
if(stage != READY)
return FALSE
@@ -286,7 +287,7 @@
return
..()
/obj/item/grenade/chem_grenade/adv_release/prime()
/obj/item/grenade/chem_grenade/adv_release/prime(mob/living/lanced_by)
if(stage != READY)
return FALSE

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