diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index 24f6c393b3..e29be375e6 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -116,7 +116,7 @@
#define HYPNO (1<<7)
#define NEVER_HYPNO (1<<8)
#define NO_APHRO (1<<9)
-#define NO_ASS_SLAP (1<<9)
+#define NO_ASS_SLAP (1<<10)
#define TOGGLES_CITADEL (EATING_NOISES|DIGESTION_NOISES|BREAST_ENLARGEMENT|PENIS_ENLARGEMENT)
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index b3c2b241f3..4f66482f51 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -169,6 +169,7 @@
#define TRAIT_EMPATH "empath"
#define TRAIT_FRIENDLY "friendly"
#define TRAIT_CULT_EYES "cult_eyes"
+#define TRAIT_AUTO_CATCH_ITEM "auto_catch_item"
#define TRAIT_CLOWN_MENTALITY "clown_mentality" // The future is now, clownman.
#define TRAIT_FREESPRINT "free_sprinting"
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index ce8b2e4cf0..cdf0f604b8 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -20,8 +20,6 @@
else
return "000"
-#define UNDIE_COLORABLE(U) (U?.has_color)
-
/proc/random_underwear(gender)
if(!GLOB.underwear_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear/bottom, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 29f5331fd3..74c32dd52f 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -758,16 +758,6 @@ GLOBAL_LIST_INIT(can_embed_types, typecacheof(list(
/obj/item/stack/rods,
/obj/item/pipe)))
-/proc/can_embed(obj/item/W)
- if(W.get_sharpness())
- return 1
- if(is_pointed(W))
- return 1
-
- if(is_type_in_typecache(W, GLOB.can_embed_types))
- return 1
-
-
/*
Checks if that loc and dir has an item on the wall
*/
diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm
index c25ebf5b0a..914e45add5 100644
--- a/code/_globalvars/lists/maintenance_loot.dm
+++ b/code/_globalvars/lists/maintenance_loot.dm
@@ -115,5 +115,6 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
/obj/item/clothing/shoes/kindleKicks = 1,
/obj/item/autosurgeon/penis = 1,
/obj/item/autosurgeon/testicles = 1,
+ /obj/item/storage/box/marshmallow = 2,
"" = 3
))
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index f082f2ad16..e6b2a63673 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -98,17 +98,19 @@
take_damage(I.force, I.damtype, "melee", 1)
/mob/living/attacked_by(obj/item/I, mob/living/user)
+ //CIT CHANGES START HERE - combatmode and resting checks
+ var/totitemdamage = I.force
+ if(iscarbon(user))
+ var/mob/living/carbon/tempcarb = user
+ if(!tempcarb.combatmode)
+ totitemdamage *= 0.5
+ if(user.resting)
+ totitemdamage *= 0.5
+ //CIT CHANGES END HERE
+ if(user != src && check_shields(I, totitemdamage, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
+ return FALSE
send_item_attack_message(I, user)
if(I.force)
- //CIT CHANGES START HERE - combatmode and resting checks
- var/totitemdamage = I.force
- if(iscarbon(user))
- var/mob/living/carbon/tempcarb = user
- if(!tempcarb.combatmode)
- totitemdamage *= 0.5
- if(user.resting)
- totitemdamage *= 0.5
- //CIT CHANGES END HERE
apply_damage(totitemdamage, I.damtype) //CIT CHANGE - replaces I.force with totitemdamage
if(I.damtype == BRUTE && !HAS_TRAIT(src, TRAIT_NOMARROW))
if(prob(33))
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 30e6883d24..6ee7d51091 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -91,6 +91,8 @@
var/obj/item/clothing/gloves/G = gloves
if(istype(G) && G.Touch(A,0)) // for magic gloves
return
+ if (istype(glasses) && glasses.ranged_attack(src,A,mouseparams))
+ return
for(var/datum/mutation/human/HM in dna.mutations)
HM.on_ranged_attack(src, A, mouseparams)
diff --git a/code/datums/martial/rising_bass.dm b/code/datums/martial/rising_bass.dm
index a3b71c6784..9e00c90a92 100644
--- a/code/datums/martial/rising_bass.dm
+++ b/code/datums/martial/rising_bass.dm
@@ -150,7 +150,9 @@
if(!.)
return
ADD_TRAIT(H, TRAIT_NOGUNS, RISING_BASS_TRAIT)
+ ADD_TRAIT(H, TRAIT_AUTO_CATCH_ITEM, RISING_BASS_TRAIT)
/datum/martial_art/the_rising_bass/on_remove(mob/living/carbon/human/H)
. = ..()
- REMOVE_TRAIT(H, TRAIT_NOGUNS, RISING_BASS_TRAIT)
\ No newline at end of file
+ REMOVE_TRAIT(H, TRAIT_NOGUNS, RISING_BASS_TRAIT)
+ REMOVE_TRAIT(H, TRAIT_AUTO_CATCH_ITEM, RISING_BASS_TRAIT)
\ No newline at end of file
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 66570205e3..773c12b6af 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -166,7 +166,7 @@
return FALSE
-/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
+/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user)
if(does_attack_animation)
user.changeNext_move(CLICK_CD_MELEE)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index ef20b6e35e..7c57de74a4 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -515,10 +515,10 @@
step(src, AM.dir)
..()
-/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback)
- return throw_at(target, range, speed, thrower, spin, diagonals_first, callback)
+/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback, messy_throw = TRUE)
+ return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, messy_throw)
-/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback) //If this returns FALSE then callback will not be called.
+/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback, messy_throw = TRUE) //If this returns FALSE then callback will not be called.
. = FALSE
if (!target || speed <= 0)
return
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index c5d198c05f..a410827347 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -578,21 +578,22 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
itempush = 0 //too light to push anything
return A.hitby(src, 0, itempush)
-/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
+/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, messy_throw = TRUE)
thrownby = thrower
- callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own
+ callback = CALLBACK(src, .proc/after_throw, callback, (spin && messy_throw)) //replace their callback with our own
. = ..(target, range, speed, thrower, spin, diagonals_first, callback)
-/obj/item/proc/after_throw(datum/callback/callback)
+/obj/item/proc/after_throw(datum/callback/callback, messy_throw)
if (callback) //call the original callback
. = callback.Invoke()
throw_speed = initial(throw_speed) //explosions change this.
item_flags &= ~IN_INVENTORY
- var/matrix/M = matrix(transform)
- M.Turn(rand(-170, 170))
- transform = M
- pixel_x = rand(-8, 8)
- pixel_y = rand(-8, 8)
+ if(messy_throw)
+ var/matrix/M = matrix(transform)
+ M.Turn(rand(-170, 170))
+ transform = M
+ pixel_x = rand(-8, 8)
+ pixel_y = rand(-8, 8)
/obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/storage
if(!newLoc)
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index cf8d38d9c9..884f5c4400 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -863,3 +863,205 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(reagents && reagents.total_volume)
hand_reagents()
+
+///////////////
+/////BONGS/////
+///////////////
+
+/obj/item/bong
+ name = "bong"
+ desc = "A water bong used for smoking dried plants."
+ icon = 'icons/obj/bongs.dmi'
+ icon_state = null
+ item_state = null
+ w_class = WEIGHT_CLASS_NORMAL
+ light_color = "#FFCC66"
+ var/icon_off = "bong"
+ var/icon_on = "bong_lit"
+ var/chem_volume = 100
+ var/last_used_time //for cooldown
+ var/firecharges = 0 //used for counting how many hits can be taken before the flame goes out
+ var/list/list_reagents = list() //For the base reagents bongs could get
+
+
+/obj/item/bong/Initialize()
+ . = ..()
+ create_reagents(chem_volume, NO_REACT) // so it doesn't react until you light it
+ reagents.add_reagent_list(list_reagents)
+ icon_state = icon_off
+
+/obj/item/bong/attackby(obj/item/O, mob/user, params)
+ . = ..()
+ //If we're using a dried plant..
+ if(istype(O,/obj/item/reagent_containers/food/snacks))
+ var/obj/item/reagent_containers/food/snacks/DP = O
+ if (DP.dry)
+ //Nothing if our bong is full
+ if (reagents.holder_full())
+ user.show_message("The bowl is full!", MSG_VISUAL)
+ return
+
+ //Transfer reagents and remove the plant
+ user.show_message("You stuff the [DP] into the [src]'s bowl.", MSG_VISUAL)
+ DP.reagents.trans_to(src, 100)
+ qdel(DP)
+ return
+ else
+ user.show_message("[DP] must be dried first!", MSG_VISUAL)
+ return
+
+ if (O.get_temperature() <= 500)
+ return
+ if (reagents && reagents.total_volume) //if there's stuff in the bong
+ var/lighting_text = O.ignition_effect(src, user)
+ if(lighting_text)
+ //Logic regarding igniting it on
+ if (firecharges == 0)
+ user.show_message("You light the [src] with the [O]!", MSG_VISUAL)
+ bongturnon()
+ else
+ user.show_message("You rekindle [src]'s flame with the [O]!", MSG_VISUAL)
+
+ firecharges = 1
+ return
+ else
+ user.show_message("There's nothing to light up in the bowl.", MSG_VISUAL)
+ return
+
+/obj/item/bong/CtrlShiftClick(mob/user) //empty reagents on alt click
+ ..()
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+
+ if (reagents && reagents.total_volume)
+ user.show_message("You empty the [src].", MSG_VISUAL)
+ reagents.clear_reagents()
+ if(firecharges)
+ firecharges = 0
+ bongturnoff()
+ else
+ user.show_message("The [src] is already empty.", MSG_VISUAL)
+
+/obj/item/bong/AltClick(mob/user)
+ ..()
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+
+ if(firecharges)
+ firecharges = 0
+ bongturnoff()
+ user.show_message("You quench the flame.", MSG_VISUAL)
+ return TRUE
+
+/obj/item/bong/examine(mob/user)
+ . = ..()
+ if(!reagents.total_volume)
+ . += "The bowl is empty."
+ else if (reagents.total_volume > 80)
+ . += "The bowl is filled to the brim."
+ else if (reagents.total_volume > 40)
+ . += "The bowl has plenty weed in it."
+ else
+ . += "The bowl has some weed in it."
+
+ . += "Ctrl+Shift-click to empty."
+ . += "Alt-click to extinguish."
+
+/obj/item/bong/ignition_effect(atom/A, mob/user)
+ if(firecharges)
+ . = "[user] lights [A] off of the [src]."
+ else
+ . = ""
+
+/obj/item/bong/attack(mob/living/carbon/M, mob/living/carbon/user, obj/target)
+ //if it's lit up, some stuff in the bowl and the user is a target, and we're not on cooldown
+
+ if (M != user)
+ return ..()
+
+ if(user.is_mouth_covered(head_only = 1))
+ to_chat(user, "Remove your headgear first.")
+ return ..()
+
+ if(user.is_mouth_covered(mask_only = 1))
+ to_chat(user, "Remove your mask first.")
+ return ..()
+
+ if (!reagents.total_volume)
+ to_chat(user, "There's nothing in the bowl.")
+ return ..()
+
+ if (!firecharges)
+ to_chat(user, "You have to light it up first.")
+ return ..()
+
+ if (last_used_time + 30 >= world.time)
+ return ..()
+ var/hit_strength
+ var/noise
+ var/hittext = ""
+ //if the intent is help then you take a small hit, else a big one
+ if (user.a_intent == INTENT_HARM)
+ hit_strength = 2
+ noise = 100
+ hittext = "big hit"
+ else
+ hit_strength = 1
+ noise = 70
+ hittext = "hit"
+ //bubbling sound
+ playsound(user.loc,'sound/effects/bonghit.ogg', noise, 1)
+
+ last_used_time = world.time
+
+ //message
+ user.visible_message("[user] begins to take a [hittext] from the [src]!", \
+ "You begin to take a [hittext] from [src].")
+
+ //we take a hit here, after an uninterrupted delay
+ if(!do_after(user, 25, target = user))
+ return
+ if (!(reagents && reagents.total_volume))
+ return
+
+ var/fraction = 12 * hit_strength
+
+ var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
+ s.set_up(reagents, hit_strength, 18, user.loc)
+ s.start()
+
+ reagents.reaction(user, INGEST, fraction)
+ if(!reagents.trans_to(user, fraction))
+ reagents.remove_any(fraction)
+
+ if (hit_strength == 2 && prob(15))
+ user.emote("cough")
+ user.adjustOxyLoss(15)
+
+ user.visible_message("[user] takes a [hittext] from the [src]!", \
+ "You take a [hittext] from [src].")
+
+ firecharges = firecharges - 1
+ if (!firecharges)
+ bongturnoff()
+ if (!reagents.total_volume)
+ firecharges = 0
+ bongturnoff()
+
+
+
+/obj/item/bong/proc/bongturnon()
+ icon_state = icon_on
+ set_light(3, 0.8)
+
+/obj/item/bong/proc/bongturnoff()
+ icon_state = icon_off
+ set_light(0, 0.0)
+
+
+
+/obj/item/bong/coconut
+ name = "coconut bong"
+ icon_off = "coconut_bong"
+ icon_on = "coconut_bong_lit"
+ desc = "A water bong used for smoking dried plants. This one's made out of a coconut and some bamboo."
\ No newline at end of file
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index d8abff70a6..4242fb6c4b 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -216,10 +216,11 @@
return
else
if(last_hit < world.time)
+ if(target.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
+ playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
+ return
if(ishuman(target))
var/mob/living/carbon/human/H = target
- if (H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
- return
if(check_martial_counter(H, user))
return
playsound(get_turf(src), 'sound/effects/woodhit.ogg', 75, 1, -1)
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index 77bc7ed810..c09f5b1b65 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -11,11 +11,9 @@
var/charge_cost = 30
/obj/item/borg/stun/attack(mob/living/M, mob/living/user)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.check_shields(src, 0, "[M]'s [name]", MELEE_ATTACK))
- playsound(M, 'sound/weapons/genhit.ogg', 50, 1)
- return FALSE
+ if(M.check_shields(src, 0, "[M]'s [name]", MELEE_ATTACK))
+ playsound(M, 'sound/weapons/genhit.ogg', 50, 1)
+ return FALSE
if(iscyborg(user))
var/mob/living/silicon/robot/R = user
if(!R.cell.use(charge_cost))
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 3a4579d3f8..7a16cdb018 100755
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -582,7 +582,7 @@
/obj/item/storage/belt/bandolier
name = "bandolier"
- desc = "A bandolier for holding shotgun ammunition."
+ desc = "A bandolier for holding ammunition."
icon_state = "bandolier"
item_state = "bandolier"
@@ -592,7 +592,7 @@
STR.max_items = 18
STR.display_numerical_stacking = TRUE
STR.can_hold = typecacheof(list(
- /obj/item/ammo_casing/shotgun
+ /obj/item/ammo_casing
))
/obj/item/storage/belt/bandolier/durathread
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index e214db3c71..4b2b3e2203 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -1259,3 +1259,12 @@
var/obj/item/stack/sheet/cardboard/I = new(user.drop_location())
qdel(src)
user.put_in_hands(I)
+
+/obj/item/storage/box/marshmallow
+ name = "box of marshmallows"
+ desc = "A box of marshmallows."
+ illustration = "marshmallow"
+
+/obj/item/storage/box/marshmallow/PopulateContents()
+ for (var/i in 1 to 5)
+ new /obj/item/reagent_containers/food/snacks/marshmallow(src)
\ No newline at end of file
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index 484b9862ff..b5c8f6b631 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -168,11 +168,9 @@
/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user)
- if(ishuman(L))
- var/mob/living/carbon/human/H = L
- if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that
- playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
- return FALSE
+ if(L.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that
+ playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
+ return FALSE
var/stunpwr = stunforce
var/obj/item/stock_parts/cell/our_cell = get_cell()
if(!our_cell)
diff --git a/code/game/objects/items/telescopic_iv.dm b/code/game/objects/items/telescopic_iv.dm
index e1ec33569f..9b0b714ea5 100644
--- a/code/game/objects/items/telescopic_iv.dm
+++ b/code/game/objects/items/telescopic_iv.dm
@@ -9,7 +9,7 @@
/obj/item/tele_iv/afterattack(atom/target, mob/user, proximity)
. = ..()
- if(proximity|| isopenturf(target))
+ if(proximity && isopenturf(target) && user.CanReach(target))
deploy_iv(user, target)
/obj/item/tele_iv/proc/deploy_iv(mob/user, atom/location)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index f5dfa690db..14ac2f037e 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -80,13 +80,12 @@
SEND_SIGNAL(src, COMSIG_OBJ_SETANCHORED, anchorvalue)
anchored = anchorvalue
-/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
- ..()
+/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, messy_throw)
+ . = ..()
if(obj_flags & FROZEN)
visible_message("[src] shatters into a million pieces!")
qdel(src)
-
/obj/assume_air(datum/gas_mixture/giver)
if(loc)
return loc.assume_air(giver)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
index 8da50d488f..579b1444a5 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
@@ -12,18 +12,12 @@
new /obj/item/clothing/head/hardhat/white(src)
new /obj/item/clothing/head/hardhat/weldhat/white(src)
new /obj/item/clothing/gloves/color/yellow(src)
- new /obj/item/clothing/shoes/sneakers/brown(src)
new /obj/item/tank/jetpack/suit(src)
new /obj/item/cartridge/ce(src)
new /obj/item/radio/headset/heads/ce(src)
- new /obj/item/storage/toolbox/mechanical(src)
- new /obj/item/clothing/suit/hazardvest(src)
new /obj/item/megaphone/command(src)
new /obj/item/areaeditor/blueprints(src)
- new /obj/item/airlock_painter(src)
new /obj/item/holosign_creator/engineering(src)
- new /obj/item/clothing/mask/gas(src)
- new /obj/item/multitool(src)
new /obj/item/assembly/flash/handheld(src)
new /obj/item/clothing/glasses/meson/engine(src)
new /obj/item/door_remote/chief_engineer(src)
@@ -67,7 +61,7 @@
for(var/i in 1 to 3)
new /obj/item/clothing/head/welding(src)
for(var/i in 1 to 3)
- new /obj/item/weldingtool(src)
+ new /obj/item/weldingtool/largetank(src)
/obj/structure/closet/secure_closet/engineering_personal
name = "engineer's locker"
@@ -84,7 +78,6 @@
new /obj/item/clothing/glasses/meson/engine(src)
new /obj/item/storage/box/emptysandbags(src)
-
/obj/structure/closet/secure_closet/atmospherics
name = "\proper atmospheric technician's locker"
req_access = list(ACCESS_ATMOSPHERICS)
@@ -103,3 +96,33 @@
new /obj/item/clothing/head/hardhat/atmos(src)
new /obj/item/clothing/glasses/meson/engine/tray(src)
new /obj/item/extinguisher/advanced(src)
+
+/*
+ * Empty lockers
+ * Some of the lockers are filled with junk, and sometimes its nice to just fill it with your own set-up for your own map gimmicks.
+ */
+
+/obj/structure/closet/secure_closet/engineering_chief/empty
+
+/obj/structure/closet/secure_closet/engineering_chief/empty/PopulateContents()
+ return
+
+/obj/structure/closet/secure_closet/engineering_electrical/empty
+
+/obj/structure/closet/secure_closet/engineering_electrical/empty/PopulateContents()
+ return
+
+/obj/structure/closet/secure_closet/engineering_welding/empty
+
+/obj/structure/closet/secure_closet/engineering_welding/empty/PopulateContents()
+ return
+
+/obj/structure/closet/secure_closet/engineering_personal/empty
+
+/obj/structure/closet/secure_closet/engineering_personal/empty/PopulateContents()
+ return
+
+/obj/structure/closet/secure_closet/atmospherics/empty
+
+/obj/structure/closet/secure_closet/atmospherics/empty/PopulateContents()
+ return
diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm
index 05e62c196f..7f0c3c6eb8 100644
--- a/code/game/objects/structures/dresser.dm
+++ b/code/game/objects/structures/dresser.dm
@@ -30,11 +30,11 @@
return
var/list/undergarment_choices = list("Underwear", "Underwear Color", "Undershirt", "Undershirt Color", "Socks", "Socks Color")
- if(!UNDIE_COLORABLE(GLOB.underwear_list[H.underwear]))
+ if(!(GLOB.underwear_list[H.underwear]?.has_color))
undergarment_choices -= "Underwear Color"
- if(!UNDIE_COLORABLE(GLOB.undershirt_list[H.undershirt]))
+ if(!(GLOB.undershirt_list[H.undershirt]?.has_color))
undergarment_choices -= "Undershirt Color"
- if(!UNDIE_COLORABLE(GLOB.socks_list[H.socks]))
+ if(!(GLOB.socks_list[H.socks]?.has_color))
undergarment_choices -= "Socks Color"
var/choice = input(H, "Underwear, Undershirt, or Socks?", "Changing") as null|anything in undergarment_choices
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index 433f52306b..fce45810d1 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -484,11 +484,9 @@
user.do_attack_animation(L)
- if(ishuman(L))
- var/mob/living/carbon/human/H = L
- if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
- playsound(H, 'sound/weapons/genhit.ogg', 50, TRUE)
- return FALSE
+ if(L.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
+ playsound(L, 'sound/weapons/genhit.ogg', 50, TRUE)
+ return FALSE
switch (mode)
if(BATON_STUN)
diff --git a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm
index f73912d0f5..3493622945 100644
--- a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm
+++ b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm
@@ -275,7 +275,7 @@
// All done!
if(convert_progress <= 0)
// FAIL: Can't be Vassal
- if(!SSticker.mode.can_make_vassal(target, user, display_warning=FALSE) && HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY
+ if(!SSticker.mode.can_make_vassal(target, user, display_warning=FALSE) || HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY
to_chat(user, "[target] doesn't respond to your persuasion. It doesn't appear they can be converted to follow you, they either have a mindshield or their external loyalties are too difficult for you to break.\[ALT+click to release\]")
convert_progress ++ // Pop it back up some. Avoids wasting Blood on a lost cause.
// SUCCESS: All done!
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 06511f6fa9..48489df4c7 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -722,13 +722,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "
[src]'s transfer amount is now [amount_per_transfer_from_this] units.")
+ return
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/attackby(obj/item/W, mob/user, params)
+ //DEFUSING NADE LOGIC
+ if (W.tool_behaviour == TOOL_WIRECUTTER && fused)
+ user.show_message("You cut the fuse!", MSG_VISUAL)
+ playsound(user, W.hitsound, 50, 1, -1)
+ icon_state = "coconut_carved"
+ desc = "A coconut. This one's got a hole in it."
+ name = "coconut"
+ defused = TRUE
+ fused = FALSE
+ fusedactive = FALSE
+ if(!seed.get_gene(/datum/plant_gene/trait/glow))
+ set_light(0, 0.0)
+ return
+ //IGNITING NADE LOGIC
+ if(!fusedactive && fused)
+ var/lighting_text = W.ignition_effect(src, user)
+ if(lighting_text)
+ user.visible_message("[user] ignites [src]'s fuse!", "You ignite the [src]'s fuse!")
+ fusedactive = TRUE
+ defused = FALSE
+ playsound(src, 'sound/effects/fuse.ogg', 100, 0)
+ message_admins("[ADMIN_LOOKUPFLW(user)] ignited a coconut bomb for detonation at [ADMIN_VERBOSEJMP(user)] [pretty_string_from_reagent_list(reagents.reagent_list)]")
+ log_game("[key_name(user)] primed a coconut grenade for detonation at [AREACOORD(user)].")
+ addtimer(CALLBACK(src, .proc/prime), 5 SECONDS)
+ icon_state = "coconut_grenade_active"
+ desc = "RUN!"
+ if(!seed.get_gene(/datum/plant_gene/trait/glow))
+ light_color = "#FFCC66" //for the fuse
+ set_light(3, 0.8)
+ return
+
+ //ADDING A FUSE, NADE LOGIC
+ if (istype(W,/obj/item/stack/sheet/cloth) || istype(W,/obj/item/stack/sheet/durathread))
+ if (carved && !straw && !fused)
+ user.show_message("You add a fuse to the coconut!", 1)
+ W.use(1)
+ fused = TRUE
+ icon_state = "coconut_grenade"
+ desc = "A makeshift bomb made out of a coconut. You estimate the fuse is long enough for 5 seconds."
+ name = "coconut bomb"
+ return
+ //ADDING STRAW LOGIC
+ if (istype(W,/obj/item/stack/sheet/mineral/bamboo) && opened && !straw && fused)
+ user.show_message("You add a bamboo straw to the coconut!", 1)
+ straw = TRUE
+ W.use(1)
+ icon_state += "_straw"
+ desc = "You can already feel like you're on a tropical vacation."
+ return
+ //OPENING THE NUT LOGIC
+ if (!carved && !chopped)
+ var/screwdrivered = W.tool_behaviour == TOOL_SCREWDRIVER
+ if(screwdrivered || W.sharpness)
+ user.show_message("You [screwdrivered ? "make a hole in the coconut" : "slice the coconut open"]!", 1)
+ carved = TRUE
+ opened = TRUE
+ spillable = !screwdrivered
+ reagent_flags = OPENCONTAINER
+ ENABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
+ icon_state = screwdrivered ? "coconut_carved" : "coconut_chopped"
+ desc = "A coconut. [screwdrivered ? "This one's got a hole in it" : "This one's sliced open, with all its delicious contents for your eyes to savour"]."
+ playsound(user, W.hitsound, 50, 1, -1)
+ return
+ return ..()
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/attack(mob/living/M, mob/user, obj/target)
+ if(M && user.a_intent == INTENT_HARM && !spillable)
+ var/obj/item/bodypart/affecting = user.zone_selected //Find what the player is aiming at
+ if (affecting == BODY_ZONE_HEAD && prob(15))
+ //smash the nut open
+ var/armor_block = min(90, M.run_armor_check(affecting, "melee", null, null,armour_penetration)) // For normal attack damage
+ M.apply_damage(force, BRUTE, affecting, armor_block)
+
+ //Sound
+ playsound(user, hitsound, 100, 1, -1)
+
+ //Attack logs
+ log_combat(user, M, "attacked", src)
+
+ //Display an attack message.
+ if(M != user)
+ M.visible_message("[user] has cracked open a [name] on [M]'s head!", \
+ "[user] has cracked open a [name] on [M]'s head!")
+ else
+ user.visible_message("[M] cracks open a [name] on their [M.p_them()] head!", \
+ "[M] cracks open a [name] on [M.p_their()] head!")
+
+ //The coconut breaks open so splash its reagents
+ spillable = TRUE
+ SplashReagents(M)
+
+ //Lastly we remove the nut
+ qdel(src)
+ else
+ . = ..()
+ return
+
+ if(fusedactive)
+ return
+
+ if(!opened)
+ return
+
+ if(!canconsume(M, user))
+ return
+
+ if(!reagents || !reagents.total_volume)
+ to_chat(user, "[src] is empty!")
+ return
+
+ if(user.a_intent == INTENT_HARM && spillable)
+ var/R
+ M.visible_message("[user] splashes the contents of [src] onto [M]!", \
+ "[user] splashes the contents of [src] onto [M]!")
+ if(reagents)
+ for(var/datum/reagent/A in reagents.reagent_list)
+ R += A.id + " ("
+ R += num2text(A.volume) + "),"
+ if(isturf(target) && reagents.reagent_list.len && thrownby)
+ log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]")
+ message_admins("[ADMIN_LOOKUPFLW(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] at [ADMIN_VERBOSEJMP(target)].")
+ reagents.reaction(M, TOUCH)
+ log_combat(user, M, "splashed", R)
+ reagents.clear_reagents()
+ else
+ if(M != user)
+ M.visible_message("[user] attempts to feed something to [M].", \
+ "[user] attempts to feed something to you.")
+ if(!do_mob(user, M))
+ return
+ if(!reagents || !reagents.total_volume)
+ return // The drink might be empty after the delay, such as by spam-feeding
+ M.visible_message("[user] feeds something to [M].", "[user] feeds something to you.")
+ log_combat(user, M, "fed", reagents.log_list())
+ else
+ to_chat(user, "You swallow a gulp of [src].")
+ var/fraction = min(5/reagents.total_volume, 1)
+ reagents.reaction(M, INGEST, fraction)
+ addtimer(CALLBACK(reagents, /datum/reagents.proc/trans_to, M, 5), 5)
+ playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/afterattack(obj/target, mob/user, proximity)
+ . = ..()
+ if(fusedactive)
+ return
+
+ if((!proximity) || !check_allowed_items(target,target_self=1))
+ return
+
+ if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
+ if(!reagents.total_volume)
+ to_chat(user, "[src] is empty!")
+ return
+
+ if(target.reagents.holder_full())
+ to_chat(user, "[target] is full.")
+ return
+
+ var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
+ to_chat(user, "You transfer [trans] unit\s of the solution to [target].")
+
+ else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
+ if(!target.reagents.total_volume)
+ to_chat(user, "[target] is empty and can't be refilled!")
+ return
+
+ if(reagents.holder_full())
+ to_chat(user, "[src] is full.")
+ return
+
+ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
+ to_chat(user, "You fill [src] with [trans] unit\s of the contents of [target].")
+
+ else if(reagents.total_volume)
+ if(user.a_intent == INTENT_HARM && spillable == TRUE)
+ user.visible_message("[user] splashes the contents of [src] onto [target]!", \
+ "You splash the contents of [src] onto [target].")
+ reagents.reaction(target, TOUCH)
+ reagents.clear_reagents()
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/dropped(mob/user)
+ . = ..()
+ transform *= TRANSFORM_USING_VARIABLE(40, 100) + 0.5 //temporary fix for size?
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/proc/prime()
+ if (defused)
+ return
+ var/turf/T = get_turf(src)
+ reagents.chem_temp = 1000
+ //Disable seperated contents when the grenade primes
+ if (seed.get_gene(/datum/plant_gene/trait/noreact))
+ DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
+ reagents.handle_reactions()
+ log_game("Coconut bomb detonation at [AREACOORD(T)], location [loc]")
+ qdel(src)
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/ex_act(severity)
+ qdel(src)
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/deconstruct(disassembled = TRUE)
+ if(!disassembled && fused)
+ prime()
+ if(!QDELETED(src))
+ qdel(src)
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index 4132719389..39e97e3801 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -27,6 +27,7 @@
var/rarity = 0 // How rare the plant is. Used for giving points to cargo when shipping off to CentCom.
var/list/mutatelist = list() // The type of plants that this plant can mutate into.
var/list/genes = list() // Plant genes are stored here, see plant_genes.dm for more info.
+ var/list/forbiddengenes = list()
var/list/reagents_add = list()
// A list of reagents to add to product.
// Format: "reagent_id" = potency multiplier
@@ -96,6 +97,10 @@
S.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes.
return S
+obj/item/seeds/proc/is_gene_forbidden(typepath)
+ return (typepath in forbiddengenes)
+
+
/obj/item/seeds/proc/get_gene(typepath)
return (locate(typepath) in genes)
@@ -448,7 +453,7 @@
for(var/i in 1 to amount_random_traits)
var/random_trait = pick((subtypesof(/datum/plant_gene/trait)-typesof(/datum/plant_gene/trait/plant_type)))
var/datum/plant_gene/trait/T = new random_trait
- if(T.can_add(src))
+ if(T.can_add(src) && !is_gene_forbidden(random_trait))
genes += T
else
qdel(T)
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm
index dd66f68e5d..241ec8118e 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm
@@ -74,4 +74,5 @@
/datum/sprite_accessory/underwear
icon = 'icons/mob/underwear.dmi'
- var/has_color = FALSE
\ No newline at end of file
+ var/has_color = FALSE
+ var/has_digitigrade = FALSE
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/socks.dm b/code/modules/mob/dead/new_player/sprite_accessories/socks.dm
index 0a35f0cd26..19ec677a72 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/socks.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/socks.dm
@@ -2,6 +2,9 @@
// Socks Definitions //
///////////////////////
+/datum/sprite_accessory/underwear/socks
+ has_digitigrade = TRUE
+
/datum/sprite_accessory/underwear/socks/nude
name = "Nude"
icon_state = null
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm b/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm
index 3356804cb3..9441b5120a 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm
@@ -28,41 +28,49 @@
name = "Boxers"
icon_state = "boxers"
has_color = TRUE
+ has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_bee
name = "Boxers - Bee"
icon_state = "bee_shorts"
+ has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_hearts
name = "Boxers - Heart"
icon_state = "boxers_heart"
+ has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_stripe
name = "Boxers - Striped"
icon_state = "boxers_striped"
+ has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_commie
name = "Boxers - Striped Communist"
icon_state = "boxers_commie"
+ has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_usastripe
name = "Boxers - Striped Freedom"
icon_state = "boxers_assblastusa"
+ has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_uk
name = "Boxers - Striped UK"
icon_state = "boxers_uk"
+ has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/boxer_briefs
name = "Boxer Briefs"
icon_state = "boxer_briefs"
+ has_digitigrade = TRUE
has_color = TRUE
/datum/sprite_accessory/underwear/bottom/panties
@@ -140,6 +148,7 @@
/datum/sprite_accessory/underwear/bottom/longjon
name = "Long John Bottoms"
icon_state = "ljonb"
+ has_digitigrade = TRUE
has_color = TRUE
/datum/sprite_accessory/underwear/bottom/swimsuit_red
diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm
index b9e27c0637..bdc691ce49 100644
--- a/code/modules/mob/living/carbon/alien/alien_defense.dm
+++ b/code/modules/mob/living/carbon/alien/alien_defense.dm
@@ -6,21 +6,21 @@
return 2 //no ears
/mob/living/carbon/alien/hitby(atom/movable/AM, skipcatch, hitpush)
- ..(AM, skipcatch = TRUE, hitpush = FALSE)
+ return ..(AM, skipcatch = TRUE, hitpush = FALSE)
+/mob/living/carbon/alien/can_embed(obj/item/I)
+ return FALSE
/*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other.
As such, they can either help or harm other aliens. Help works like the human help command while harm is a simple nibble.
In all, this is a lot like the monkey code. /N
*/
/mob/living/carbon/alien/attack_alien(mob/living/carbon/alien/M)
- if(isturf(loc) && istype(loc.loc, /area/start))
- to_chat(M, "No attacking people at spawn, you jackass.")
+ . = ..()
+ if(!.) // the attack was blocked or was help/grab intent
return
-
switch(M.a_intent)
-
- if ("help")
+ if (INTENT_HELP)
if(!recoveringstam)
resting = 0
AdjustStun(-60)
@@ -28,11 +28,7 @@ In all, this is a lot like the monkey code. /N
AdjustUnconscious(-60)
AdjustSleeping(-100)
visible_message("[M.name] nuzzles [src] trying to wake [p_them()] up!")
-
- if ("grab")
- grabbedby(M)
-
- else
+ if(INTENT_DISARM, INTENT_HARM)
if(health > 0)
M.do_attack_animation(src, ATTACK_EFFECT_BITE)
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
@@ -50,28 +46,31 @@ In all, this is a lot like the monkey code. /N
/mob/living/carbon/alien/attack_hand(mob/living/carbon/human/M)
- if(..()) //to allow surgery to return properly.
- return 0
-
+ . = ..()
+ if(.) //To allow surgery to return properly.
+ return
switch(M.a_intent)
- if("help")
+ if(INTENT_HELP)
help_shake_act(M)
- if("grab")
+ if(INTENT_GRAB)
grabbedby(M)
- if ("harm")
+ if (INTENT_HARM)
+ if(HAS_TRAIT(M, TRAIT_PACIFISM))
+ to_chat(M, "You don't want to hurt [src]!")
+ return TRUE
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
- return 1
- if("disarm")
+ if(INTENT_DISARM)
+ if(HAS_TRAIT(M, TRAIT_PACIFISM))
+ to_chat(M, "You don't want to hurt [src]!")
+ return TRUE
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
- return 1
- return 0
/mob/living/carbon/alien/attack_paw(mob/living/carbon/monkey/M)
- if(..())
- if (stat != DEAD)
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
- apply_damage(rand(1, 3), BRUTE, affecting)
+ . = ..()
+ if(.) //successful monkey bite.
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ apply_damage(rand(1, 3), BRUTE, affecting)
/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M)
@@ -93,13 +92,15 @@ In all, this is a lot like the monkey code. /N
adjustStaminaLoss(damage)
/mob/living/carbon/alien/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime attack
- var/damage = rand(5, 35)
- if(M.is_adult)
- damage = rand(10, 40)
- adjustBruteLoss(damage)
- log_combat(M, src, "attacked")
- updatehealth()
+ . = ..()
+ if(!.) //unsuccessful slime attack
+ return
+ var/damage = rand(5, 35)
+ if(M.is_adult)
+ damage = rand(10, 40)
+ adjustBruteLoss(damage)
+ log_combat(M, src, "attacked")
+ updatehealth()
/mob/living/carbon/alien/ex_act(severity, target, origin)
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
index fe682b5c99..d1ed09665b 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
@@ -63,12 +63,7 @@
if(A)
if(isliving(A))
var/mob/living/L = A
- var/blocked = FALSE
- if(ishuman(A))
- var/mob/living/carbon/human/H = A
- if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
- blocked = TRUE
- if(!blocked)
+ if(!L.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
L.visible_message("[src] pounces on [L]!", "[src] pounces on you!")
L.Knockdown(100)
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
index b3839a6033..1d613db07a 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
@@ -5,9 +5,11 @@
else
..()
-/mob/living/carbon/alien/humanoid/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
+/mob/living/carbon/alien/humanoid/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
- ..(user, 1)
+ . = ..(user, TRUE)
+ if(.)
+ return
adjustBruteLoss(15)
var/hitverb = "punched"
if(mob_size < MOB_SIZE_LARGE)
@@ -21,46 +23,46 @@
return 1
/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M)
- if(..())
- switch(M.a_intent)
- if ("harm")
- var/damage = rand(1, 9)
- if (prob(90))
- playsound(loc, "punch", 25, 1, -1)
- visible_message("[M] has punched [src]!", \
- "[M] has punched [src]!", null, COMBAT_MESSAGE_RANGE)
- if ((stat != DEAD) && (damage > 9 || prob(5)))//Regular humans have a very small chance of knocking an alien down.
- Unconscious(40)
- visible_message("[M] has knocked [src] down!", \
- "[M] has knocked [src] down!")
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
- apply_damage(damage, BRUTE, affecting)
- log_combat(M, src, "attacked")
+ . = ..()
+ if(.) //To allow surgery to return properly.
+ return
+ switch(M.a_intent)
+ if (INTENT_HARM)
+ var/damage = rand(1, 9)
+ if (prob(90))
+ playsound(loc, "punch", 25, 1, -1)
+ visible_message("[M] has punched [src]!", \
+ "[M] has punched [src]!", null, COMBAT_MESSAGE_RANGE)
+ if ((stat != DEAD) && (damage > 9 || prob(5)))//Regular humans have a very small chance of knocking an alien down.
+ Unconscious(40)
+ visible_message("[M] has knocked [src] down!", \
+ "[M] has knocked [src] down!")
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ apply_damage(damage, BRUTE, affecting)
+ log_combat(M, src, "attacked")
+ else
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ visible_message("[M] has attempted to punch [src]!", \
+ "[M] has attempted to punch [src]!", null, COMBAT_MESSAGE_RANGE)
+
+ if (INTENT_DISARM)
+ if (!lying)
+ if (prob(5))
+ Unconscious(40)
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ log_combat(M, src, "pushed")
+ visible_message("[M] has pushed down [src]!", \
+ "[M] has pushed down [src]!")
else
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to punch [src]!", \
- "[M] has attempted to punch [src]!", null, COMBAT_MESSAGE_RANGE)
-
- if ("disarm")
- if (!lying)
- if (prob(5))
- Unconscious(40)
+ if (prob(50))
+ dropItemToGround(get_active_held_item())
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- log_combat(M, src, "pushed")
- visible_message("[M] has pushed down [src]!", \
- "[M] has pushed down [src]!")
+ visible_message("[M] has disarmed [src]!", \
+ "[M] has disarmed [src]!", null, COMBAT_MESSAGE_RANGE)
else
- if (prob(50))
- dropItemToGround(get_active_held_item())
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- visible_message("[M] has disarmed [src]!", \
- "[M] has disarmed [src]!", null, COMBAT_MESSAGE_RANGE)
- else
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to disarm [src]!",\
- "[M] has attempted to disarm [src]!", null, COMBAT_MESSAGE_RANGE)
-
-
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ visible_message("[M] has attempted to disarm [src]!",\
+ "[M] has attempted to disarm [src]!", null, COMBAT_MESSAGE_RANGE)
/mob/living/carbon/alien/humanoid/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!no_effect && !visual_effect_icon)
diff --git a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
index 69c1be707d..7dabcf5abf 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
@@ -1,26 +1,33 @@
/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M)
- if(..())
- var/damage = rand(1, 9)
- if (prob(90))
- playsound(loc, "punch", 25, 1, -1)
- log_combat(M, src, "attacked")
- visible_message("[M] has kicked [src]!", \
- "[M] has kicked [src]!", null, COMBAT_MESSAGE_RANGE)
- if ((stat != DEAD) && (damage > 4.9))
- Unconscious(rand(100,200))
+ . = ..()
+ if(. || M.a_intent == INTENT_HELP || M.a_intent == INTENT_GRAB)
+ return
+ var/damage = rand(1, 9)
+ if (prob(90))
+ playsound(loc, "punch", 25, 1, -1)
+ log_combat(M, src, "attacked")
+ visible_message("[M] has kicked [src]!", \
+ "[M] has kicked [src]!", null, COMBAT_MESSAGE_RANGE)
+ if ((stat != DEAD) && (damage > 4.9))
+ Unconscious(rand(100,200))
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
- apply_damage(damage, BRUTE, affecting)
- else
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to kick [src]!", \
- "[M] has attempted to kick [src]!", null, COMBAT_MESSAGE_RANGE)
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ apply_damage(damage, BRUTE, affecting)
+ else
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ visible_message("[M] has attempted to kick [src]!", \
+ "[M] has attempted to kick [src]!", null, COMBAT_MESSAGE_RANGE)
-/mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
+/mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
- ..(user, 1)
+ . = ..(user, TRUE)
+ if(.)
+ return
+ playsound(loc, "punch", 25, 1, -1)
+ visible_message("[user] has pummeled [src]!", \
+ "[user] has pummeled [src]!", null, COMBAT_MESSAGE_RANGE)
adjustBruteLoss(5 + rand(1,9))
new /datum/forced_movement(src, get_step_away(user,src, 30), 1)
return 1
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 0bfd23cbff..c08fe4f582 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -103,15 +103,17 @@
new_xeno.notransform = 0
new_xeno.invisibility = 0
+ var/mob/living/carbon/old_owner = owner
if(kill_on_sucess) //ITS TOO LATE
new_xeno.visible_message("[new_xeno] bursts out of [owner]!", "You exit [owner], your previous host.", "You hear organic matter ripping and tearing!")
owner.apply_damage(rand(100,300),BRUTE,zone,FALSE) //Random high damage to torso so health sensors don't metagame.
- owner.spill_organs(TRUE,FALSE,TRUE) //Lets still make the death gruesome and impossible to just simply defib someone.
+ var/obj/item/bodypart/B = owner.get_bodypart(zone)
+ B.drop_organs(owner) //Lets still make the death gruesome and impossible to just simply defib someone.
owner.death(FALSE) //Just in case some freak occurance occurs where you somehow survive all your organs being removed from you and the 100-300 brute damage.
else //When it is removed via surgery at a late stage, rather than forced.
new_xeno.visible_message("[new_xeno] wriggles out of [owner]!", "You exit [owner], your previous host.")
owner.adjustBruteLoss(40)
- owner.cut_overlay(overlay)
+ old_owner.cut_overlay(overlay)
qdel(src)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 52cf82a06a..102bc6fc3d 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -1,990 +1,991 @@
-/mob/living/carbon
- blood_volume = BLOOD_VOLUME_NORMAL
-
-/mob/living/carbon/Initialize()
- . = ..()
- create_reagents(1000)
- update_body_parts() //to update the carbon's new bodyparts appearance
- GLOB.carbon_list += src
- blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
-
-/mob/living/carbon/Destroy()
- //This must be done first, so the mob ghosts correctly before DNA etc is nulled
- . = ..()
-
- QDEL_LIST(internal_organs)
- QDEL_LIST(stomach_contents)
- QDEL_LIST(bodyparts)
- QDEL_LIST(implants)
- remove_from_all_data_huds()
- QDEL_NULL(dna)
- GLOB.carbon_list -= src
-
-/mob/living/carbon/initialize_footstep()
- AddComponent(/datum/component/footstep, 0.6, 2)
-
-/mob/living/carbon/relaymove(mob/user, direction)
- if(user in src.stomach_contents)
- if(prob(40))
- if(prob(25))
- audible_message("You hear something rumbling inside [src]'s stomach...", \
- "You hear something rumbling.", 4,\
- "Something is rumbling inside your stomach!")
- var/obj/item/I = user.get_active_held_item()
- if(I && I.force)
- var/d = rand(round(I.force / 4), I.force)
- var/obj/item/bodypart/BP = get_bodypart(BODY_ZONE_CHEST)
- if(BP.receive_damage(d, 0))
- update_damage_overlays()
- visible_message("[user] attacks [src]'s stomach wall with the [I.name]!", \
- "[user] attacks your stomach wall with the [I.name]!")
- playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
-
- if(prob(src.getBruteLoss() - 50))
- for(var/atom/movable/A in stomach_contents)
- A.forceMove(drop_location())
- stomach_contents.Remove(A)
- src.gib()
-
-
-/mob/living/carbon/swap_hand(held_index)
- if(!held_index)
- held_index = (active_hand_index % held_items.len)+1
-
- var/obj/item/item_in_hand = src.get_active_held_item()
- if(item_in_hand) //this segment checks if the item in your hand is twohanded.
- var/obj/item/twohanded/TH = item_in_hand
- if(istype(TH))
- if(TH.wielded == 1)
- to_chat(usr, "Your other hand is too busy holding [TH]")
- return
- var/oindex = active_hand_index
- active_hand_index = held_index
- if(hud_used)
- var/obj/screen/inventory/hand/H
- H = hud_used.hand_slots["[oindex]"]
- if(H)
- H.update_icon()
- H = hud_used.hand_slots["[held_index]"]
- if(H)
- H.update_icon()
-
-
-/mob/living/carbon/activate_hand(selhand) //l/r OR 1-held_items.len
- if(!selhand)
- selhand = (active_hand_index % held_items.len)+1
-
- if(istext(selhand))
- selhand = lowertext(selhand)
- if(selhand == "right" || selhand == "r")
- selhand = 2
- if(selhand == "left" || selhand == "l")
- selhand = 1
-
- if(selhand != active_hand_index)
- swap_hand(selhand)
- else
- mode() // Activate held item
-
-/mob/living/carbon/attackby(obj/item/I, mob/user, params)
- if(lying && surgeries.len)
- if(user != src && (user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM))
- for(var/datum/surgery/S in surgeries)
- if(S.next_step(user,user.a_intent))
- return 1
- return ..()
-
-/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum)
- . = ..()
- var/hurt = TRUE
- if(istype(throwingdatum, /datum/thrownthing))
- var/datum/thrownthing/D = throwingdatum
- if(iscyborg(D.thrower))
- var/mob/living/silicon/robot/R = D.thrower
- if(!R.emagged)
- hurt = FALSE
- if(hit_atom.density && isturf(hit_atom))
- if(hurt)
- Knockdown(20)
- take_bodypart_damage(10)
- if(iscarbon(hit_atom) && hit_atom != src)
- var/mob/living/carbon/victim = hit_atom
- if(victim.movement_type & FLYING)
- return
- if(hurt)
- victim.take_bodypart_damage(10)
- take_bodypart_damage(10)
- victim.Knockdown(20)
- Knockdown(20)
- visible_message("[src] crashes into [victim], knocking them both over!",\
- "You violently crash into [victim]!")
- playsound(src,'sound/weapons/punch1.ogg',50,1)
-
-
-//Throwing stuff
-/mob/living/carbon/proc/toggle_throw_mode()
- if(stat)
- return
- if(in_throw_mode)
- throw_mode_off()
- else
- throw_mode_on()
-
-
-/mob/living/carbon/proc/throw_mode_off()
- in_throw_mode = 0
- if(client && hud_used)
- hud_used.throw_icon.icon_state = "act_throw_off"
-
-
-/mob/living/carbon/proc/throw_mode_on()
- in_throw_mode = 1
- if(client && hud_used)
- hud_used.throw_icon.icon_state = "act_throw_on"
-
-/mob/proc/throw_item(atom/target)
- SEND_SIGNAL(src, COMSIG_MOB_THROW, target)
- return
-
-/mob/living/carbon/throw_item(atom/target)
- throw_mode_off()
- if(!target || !isturf(loc))
- return
- if(istype(target, /obj/screen))
- return
-
- //CIT CHANGES - makes it impossible to throw while in stamina softcrit
- if(getStaminaLoss() >= STAMINA_SOFTCRIT)
- to_chat(src, "You're too exhausted.")
- return
- //END OF CIT CHANGES
-
- var/obj/item/I = src.get_active_held_item()
-
- var/atom/movable/thrown_thing
- var/mob/living/throwable_mob
-
- if(istype(I, /obj/item/clothing/head/mob_holder))
- var/obj/item/clothing/head/mob_holder/holder = I
- if(holder.held_mob)
- throwable_mob = holder.held_mob
- holder.release()
-
- if(!I || throwable_mob)
- if(!throwable_mob && pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE)
- throwable_mob = pulling
-
- if(throwable_mob && !throwable_mob.buckled)
- thrown_thing = throwable_mob
- if(pulling)
- stop_pulling()
- if(HAS_TRAIT(src, TRAIT_PACIFISM))
- to_chat(src, "You gently let go of [throwable_mob].")
- return
-
- adjustStaminaLossBuffered(25)//CIT CHANGE - throwing an entire person shall be very tiring
- var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
- var/turf/end_T = get_turf(target)
- if(start_T && end_T)
- log_combat(src, throwable_mob, "thrown", addition="grab from tile in [AREACOORD(start_T)] towards tile at [AREACOORD(end_T)]")
-
- else if(!CHECK_BITFIELD(I.item_flags, ABSTRACT) && !HAS_TRAIT(I, TRAIT_NODROP))
- thrown_thing = I
- dropItemToGround(I)
-
- if(HAS_TRAIT(src, TRAIT_PACIFISM) && I.throwforce)
- to_chat(src, "You set [I] down gently on the ground.")
- return
-
- adjustStaminaLossBuffered(I.getweight()*2)//CIT CHANGE - throwing items shall be more tiring than swinging em. Doubly so.
-
- if(thrown_thing)
- visible_message("[src] has thrown [thrown_thing].")
- src.log_message("has thrown [thrown_thing]", LOG_ATTACK)
- do_attack_animation(target, no_effect = 1)
- playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1)
- newtonian_move(get_dir(target, src))
- thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src)
-
-
-
-/mob/living/carbon/restrained(ignore_grab)
- . = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))
-
-/mob/living/carbon/proc/canBeHandcuffed()
- return 0
-
-
-/mob/living/carbon/show_inv(mob/user)
- user.set_machine(src)
- var/dat = {"
-
- [name]
-
-
Head: [(head && !(head.item_flags & ABSTRACT)) ? head : "Nothing"]
-
Mask: [(wear_mask && !(wear_mask.item_flags & ABSTRACT)) ? wear_mask : "Nothing"]
-
Neck: [(wear_neck && !(wear_neck.item_flags & ABSTRACT)) ? wear_neck : "Nothing"]"}
-
- for(var/i in 1 to held_items.len)
- var/obj/item/I = get_item_for_held_index(i)
- dat += "
[get_held_index_name(i)]:[(I && !(I.item_flags & ABSTRACT)) ? I : "Nothing"]"
-
- dat += " Back: [back ? back : "Nothing"]"
-
- if(istype(wear_mask, /obj/item/clothing/mask) && istype(back, /obj/item/tank))
- dat += " [internal ? "Disable Internals" : "Set Internals"]"
-
- if(handcuffed)
- dat += " Handcuffed"
- if(legcuffed)
- dat += " Legcuffed"
-
- dat += {"
-
- Close
- "}
- user << browse(dat, "window=mob[REF(src)];size=325x500")
- onclose(user, "mob[REF(src)]")
-
-/mob/living/carbon/Topic(href, href_list)
- ..()
- //strip panel
- if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
- if(href_list["internal"])
- var/slot = text2num(href_list["internal"])
- var/obj/item/ITEM = get_item_by_slot(slot)
- if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS))
- visible_message("[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].", \
- "[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].")
- if(do_mob(usr, src, POCKET_STRIP_DELAY))
- if(internal)
- internal = null
- update_internals_hud_icon(0)
- else if(ITEM && istype(ITEM, /obj/item/tank))
- if((wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS)) || getorganslot(ORGAN_SLOT_BREATHING_TUBE))
- internal = ITEM
- update_internals_hud_icon(1)
-
- visible_message("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].", \
- "[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].")
-
-
-/mob/living/carbon/fall(forced)
- loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing
-
-/mob/living/carbon/is_muzzled()
- return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle))
-
-/mob/living/carbon/hallucinating()
- if(hallucination)
- return TRUE
- else
- return FALSE
-
-/mob/living/carbon/resist_buckle()
- if(restrained())
- changeNext_move(CLICK_CD_BREAKOUT)
- last_special = world.time + CLICK_CD_BREAKOUT
- var/buckle_cd = 600
- if(handcuffed)
- var/obj/item/restraints/O = src.get_item_by_slot(SLOT_HANDCUFFED)
- buckle_cd = O.breakouttime
- visible_message("[src] attempts to unbuckle [p_them()]self!", \
- "You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)")
- if(do_after(src, buckle_cd, 0, target = src))
- if(!buckled)
- return
- buckled.user_unbuckle_mob(src,src)
- else
- if(src && buckled)
- to_chat(src, "You fail to unbuckle yourself!")
- else
- buckled.user_unbuckle_mob(src,src)
-
-/mob/living/carbon/resist_fire()
- fire_stacks -= 5
- Knockdown(60, TRUE, TRUE)
- spin(32,2)
- visible_message("[src] rolls on the floor, trying to put [p_them()]self out!", \
- "You stop, drop, and roll!")
- sleep(30)
- if(fire_stacks <= 0)
- visible_message("[src] has successfully extinguished [p_them()]self!", \
- "You extinguish yourself.")
- ExtinguishMob()
- return
-
-/mob/living/carbon/resist_restraints()
- var/obj/item/I = null
- var/type = 0
- if(handcuffed)
- I = handcuffed
- type = 1
- else if(legcuffed)
- I = legcuffed
- type = 2
- if(I)
- if(type == 1)
- changeNext_move(CLICK_CD_BREAKOUT)
- last_special = world.time + CLICK_CD_BREAKOUT
- if(type == 2)
- changeNext_move(CLICK_CD_RANGE)
- last_special = world.time + CLICK_CD_RANGE
- cuff_resist(I)
-
-
-/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 600, cuff_break = 0)
- if(I.item_flags & BEING_REMOVED)
- to_chat(src, "You're already attempting to remove [I]!")
- return
- I.item_flags |= BEING_REMOVED
- breakouttime = I.breakouttime
- if(!cuff_break)
- visible_message("[src] attempts to remove [I]!")
- to_chat(src, "You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")
- if(do_after(src, breakouttime, 0, target = src))
- clear_cuffs(I, cuff_break)
- else
- to_chat(src, "You fail to remove [I]!")
-
- else if(cuff_break == FAST_CUFFBREAK)
- breakouttime = 50
- visible_message("[src] is trying to break [I]!")
- to_chat(src, "You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)")
- if(do_after(src, breakouttime, 0, target = src))
- clear_cuffs(I, cuff_break)
- else
- to_chat(src, "You fail to break [I]!")
-
- else if(cuff_break == INSTANT_CUFFBREAK)
- clear_cuffs(I, cuff_break)
- I.item_flags &= ~BEING_REMOVED
-
-/mob/living/carbon/proc/uncuff()
- if (handcuffed)
- var/obj/item/W = handcuffed
- handcuffed = null
- if (buckled && buckled.buckle_requires_restraints)
- buckled.unbuckle_mob(src)
- update_handcuffed()
- if (client)
- client.screen -= W
- if (W)
- W.forceMove(drop_location())
- W.dropped(src)
- if (W)
- W.layer = initial(W.layer)
- W.plane = initial(W.plane)
- changeNext_move(0)
- if (legcuffed)
- var/obj/item/W = legcuffed
- legcuffed = null
- update_inv_legcuffed()
- if (client)
- client.screen -= W
- if (W)
- W.forceMove(drop_location())
- W.dropped(src)
- if (W)
- W.layer = initial(W.layer)
- W.plane = initial(W.plane)
- changeNext_move(0)
-
-/mob/living/carbon/proc/clear_cuffs(obj/item/I, cuff_break)
- if(!I.loc || buckled)
- return
- visible_message("[src] manages to [cuff_break ? "break" : "remove"] [I]!")
- to_chat(src, "You successfully [cuff_break ? "break" : "remove"] [I].")
-
- if(cuff_break)
- . = !((I == handcuffed) || (I == legcuffed))
- qdel(I)
- return
-
- else
- if(I == handcuffed)
- handcuffed.forceMove(drop_location())
- handcuffed.dropped(src)
- handcuffed = null
- if(buckled && buckled.buckle_requires_restraints)
- buckled.unbuckle_mob(src)
- update_handcuffed()
- return
- if(I == legcuffed)
- legcuffed.forceMove(drop_location())
- legcuffed.dropped()
- legcuffed = null
- update_inv_legcuffed()
- return
- else
- dropItemToGround(I)
- return
- return TRUE
-
-/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
- if(lying)
- return -6
- else
- return initial(pixel_y)
-
-/mob/living/carbon/proc/accident(obj/item/I)
- if(!I || (I.item_flags & ABSTRACT) || HAS_TRAIT(I, TRAIT_NODROP))
- return
-
- //dropItemToGround(I) CIT CHANGE - makes it so the item doesn't drop if the modifier rolls above 100
-
- var/modifier = 0
-
- if(HAS_TRAIT(src, TRAIT_CLUMSY))
- modifier -= 40 //Clumsy people are more likely to hit themselves -Honk!
-
- //CIT CHANGES START HERE
- else if(combatmode)
- modifier += 50
-
- if(modifier < 100)
- dropItemToGround(I)
- //END OF CIT CHANGES
-
- switch(rand(1,100)+modifier) //91-100=Nothing special happens
- if(-INFINITY to 0) //attack yourself
- I.attack(src,src)
- if(1 to 30) //throw it at yourself
- I.throw_impact(src)
- if(31 to 60) //Throw object in facing direction
- var/turf/target = get_turf(loc)
- var/range = rand(2,I.throw_range)
- for(var/i = 1; i < range; i++)
- var/turf/new_turf = get_step(target, dir)
- target = new_turf
- if(new_turf.density)
- break
- I.throw_at(target,I.throw_range,I.throw_speed,src)
- if(61 to 90) //throw it down to the floor
- var/turf/target = get_turf(loc)
- I.throw_at(target,I.throw_range,I.throw_speed,src)
-
-/mob/living/carbon/Stat()
- ..()
- if(statpanel("Status"))
- var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel)
- if(vessel)
- stat(null, "Plasma Stored: [vessel.storedPlasma]/[vessel.max_plasma]")
- if(locate(/obj/item/assembly/health) in src)
- stat(null, "Health: [health]")
-
- add_abilities_to_panel()
-
-/mob/living/carbon/attack_ui(slot)
- if(!has_hand_for_held_index(active_hand_index))
- return 0
- return ..()
-
-/mob/living/carbon/proc/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, toxic = FALSE)
- if(HAS_TRAIT(src, TRAIT_NOHUNGER))
- return 1
-
- if(nutrition < 100 && !blood)
- if(message)
- visible_message("[src] dry heaves!", \
- "You try to throw up, but there's nothing in your stomach!")
- if(stun)
- Knockdown(200)
- return 1
-
- if(is_mouth_covered()) //make this add a blood/vomit overlay later it'll be hilarious
- if(message)
- visible_message("[src] throws up all over [p_them()]self!", \
- "You throw up all over yourself!")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomitself)
- distance = 0
- else
- if(message)
- visible_message("[src] throws up!", "You throw up!")
- if(!isflyperson(src))
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomit)
- if(stun)
- Stun(80)
-
- playsound(get_turf(src), 'sound/effects/splat.ogg', 50, 1)
- var/turf/T = get_turf(src)
- if(!blood)
- nutrition -= lost_nutrition
- adjustToxLoss(-3)
- for(var/i=0 to distance)
- if(blood)
- if(T)
- add_splatter_floor(T)
- if(stun)
- adjustBruteLoss(3)
- else if(src.reagents.has_reagent("blazaam"))
- if(T)
- T.add_vomit_floor(src, VOMIT_PURPLE)
- else
- if(T)
- T.add_vomit_floor(src, VOMIT_TOXIC)//toxic barf looks different
- T = get_step(T, dir)
- if (is_blocked_turf(T))
- break
- return 1
-
-/mob/living/carbon/proc/spew_organ(power = 5, amt = 1)
- for(var/i in 1 to amt)
- if(!internal_organs.len)
- break //Guess we're out of organs!
- var/obj/item/organ/guts = pick(internal_organs)
- var/turf/T = get_turf(src)
- guts.Remove(src)
- guts.forceMove(T)
- var/atom/throw_target = get_edge_target_turf(guts, dir)
- guts.throw_at(throw_target, power, 4, src)
-
-
-/mob/living/carbon/fully_replace_character_name(oldname,newname)
- ..()
- if(dna)
- dna.real_name = real_name
-
-//Updates the mob's health from bodyparts and mob damage variables
-/mob/living/carbon/updatehealth()
- if(status_flags & GODMODE)
- return
- var/total_burn = 0
- var/total_brute = 0
- var/total_stamina = 0
- for(var/X in bodyparts) //hardcoded to streamline things a bit
- var/obj/item/bodypart/BP = X
- total_brute += (BP.brute_dam * BP.body_damage_coeff)
- total_burn += (BP.burn_dam * BP.body_damage_coeff)
- total_stamina += (BP.stamina_dam * BP.stam_damage_coeff)
- health = round(maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute, DAMAGE_PRECISION)
- staminaloss = round(total_stamina, DAMAGE_PRECISION)
- update_stat()
- if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
- become_husk("burn")
- med_hud_set_health()
- if(stat == SOFT_CRIT)
- add_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE, multiplicative_slowdown = SOFTCRIT_ADD_SLOWDOWN)
- else
- remove_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE)
-
-/mob/living/carbon/update_stamina()
- var/stam = getStaminaLoss()
- if(stam > DAMAGE_PRECISION)
- var/total_health = (health - stam)
- if(total_health <= crit_threshold && !stat)
- if(!IsKnockdown())
- to_chat(src, "You're too exhausted to keep going...")
- Knockdown(100)
- update_health_hud()
-
-/mob/living/carbon/update_sight()
- if(!client)
- return
- if(stat == DEAD)
- sight = (SEE_TURFS|SEE_MOBS|SEE_OBJS)
- see_in_dark = 8
- see_invisible = SEE_INVISIBLE_OBSERVER
- return
-
- sight = initial(sight)
- lighting_alpha = initial(lighting_alpha)
- var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
- if(!E)
- update_tint()
- else
- see_invisible = E.see_invisible
- see_in_dark = E.see_in_dark
- sight |= E.sight_flags
- if(!isnull(E.lighting_alpha))
- lighting_alpha = E.lighting_alpha
- if(HAS_TRAIT(src, TRAIT_NIGHT_VISION))
- lighting_alpha = min(LIGHTING_PLANE_ALPHA_NV_TRAIT, lighting_alpha)
- see_in_dark = max(NIGHT_VISION_DARKSIGHT_RANGE, see_in_dark)
-
- if(client.eye && client.eye != src)
- var/atom/A = client.eye
- if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates.
- return
-
- if(glasses)
- var/obj/item/clothing/glasses/G = glasses
- sight |= G.vision_flags
- see_in_dark = max(G.darkness_view, see_in_dark)
- if(G.invis_override)
- see_invisible = G.invis_override
- else
- see_invisible = min(G.invis_view, see_invisible)
- if(!isnull(G.lighting_alpha))
- lighting_alpha = min(lighting_alpha, G.lighting_alpha)
- if(dna)
- for(var/X in dna.mutations)
- var/datum/mutation/M = X
- if(M.name == XRAY)
- sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
- see_in_dark = max(see_in_dark, 8)
-
- if(see_override)
- see_invisible = see_override
- . = ..()
-
-
-//to recalculate and update the mob's total tint from tinted equipment it's wearing.
-/mob/living/carbon/proc/update_tint()
- if(!GLOB.tinted_weldhelh)
- return
- tinttotal = get_total_tint()
- if(tinttotal >= TINT_BLIND)
- become_blind(EYES_COVERED)
- else if(tinttotal >= TINT_DARKENED)
- cure_blind(EYES_COVERED)
- overlay_fullscreen("tint", /obj/screen/fullscreen/impaired, 2)
- else
- cure_blind(EYES_COVERED)
- clear_fullscreen("tint", 0)
-
-/mob/living/carbon/proc/get_total_tint()
- . = 0
- if(istype(head, /obj/item/clothing/head))
- var/obj/item/clothing/head/HT = head
- . += HT.tint
- if(wear_mask)
- . += wear_mask.tint
-
- var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
- if(E)
- . += E.tint
-
- else
- . += INFINITY
-
-/mob/living/carbon/get_permeability_protection(list/target_zones = list(HANDS,CHEST,GROIN,LEGS,FEET,ARMS,HEAD))
- var/list/tally = list()
- for(var/obj/item/I in get_equipped_items())
- for(var/zone in target_zones)
- if(I.body_parts_covered & zone)
- tally["[zone]"] = max(1 - I.permeability_coefficient, target_zones["[zone]"])
- var/protection = 0
- for(var/key in tally)
- protection += tally[key]
- protection *= INVERSE(target_zones.len)
- return protection
-
-//this handles hud updates
-/mob/living/carbon/update_damage_hud()
-
- if(!client)
- return
-
- if(health <= crit_threshold)
- var/severity = 0
- switch(health)
- if(-20 to -10)
- severity = 1
- if(-30 to -20)
- severity = 2
- if(-40 to -30)
- severity = 3
- if(-50 to -40)
- severity = 4
- if(-50 to -40)
- severity = 5
- if(-60 to -50)
- severity = 6
- if(-70 to -60)
- severity = 7
- if(-90 to -70)
- severity = 8
- if(-95 to -90)
- severity = 9
- if(-INFINITY to -95)
- severity = 10
- if(!InFullCritical())
- var/visionseverity = 4
- switch(health)
- if(-8 to -4)
- visionseverity = 5
- if(-12 to -8)
- visionseverity = 6
- if(-16 to -12)
- visionseverity = 7
- if(-20 to -16)
- visionseverity = 8
- if(-24 to -20)
- visionseverity = 9
- if(-INFINITY to -24)
- visionseverity = 10
- overlay_fullscreen("critvision", /obj/screen/fullscreen/crit/vision, visionseverity)
- else
- clear_fullscreen("critvision")
- overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity)
- else
- clear_fullscreen("crit")
- clear_fullscreen("critvision")
-
- //Oxygen damage overlay
- var/windedup = getOxyLoss() + getStaminaLoss() * 0.2
- if(windedup)
- var/severity = 0
- switch(windedup)
- if(10 to 20)
- severity = 1
- if(20 to 25)
- severity = 2
- if(25 to 30)
- severity = 3
- if(30 to 35)
- severity = 4
- if(35 to 40)
- severity = 5
- if(40 to 45)
- severity = 6
- if(45 to INFINITY)
- severity = 7
- overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity)
- else
- clear_fullscreen("oxy")
-
- //Fire and Brute damage overlay (BSSR)
- var/hurtdamage = getBruteLoss() + getFireLoss() + damageoverlaytemp
- if(hurtdamage)
- var/severity = 0
- switch(hurtdamage)
- if(5 to 15)
- severity = 1
- if(15 to 30)
- severity = 2
- if(30 to 45)
- severity = 3
- if(45 to 70)
- severity = 4
- if(70 to 85)
- severity = 5
- if(85 to INFINITY)
- severity = 6
- overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
- else
- clear_fullscreen("brute")
-
-/mob/living/carbon/update_health_hud(shown_health_amount)
- if(!client || !hud_used)
- return
- if(hud_used.healths)
- if(stat != DEAD)
- . = 1
- if(!shown_health_amount)
- shown_health_amount = health
- if(shown_health_amount >= maxHealth)
- hud_used.healths.icon_state = "health0"
- else if(shown_health_amount > maxHealth*0.8)
- hud_used.healths.icon_state = "health1"
- else if(shown_health_amount > maxHealth*0.6)
- hud_used.healths.icon_state = "health2"
- else if(shown_health_amount > maxHealth*0.4)
- hud_used.healths.icon_state = "health3"
- else if(shown_health_amount > maxHealth*0.2)
- hud_used.healths.icon_state = "health4"
- else if(shown_health_amount > 0)
- hud_used.healths.icon_state = "health5"
- else
- hud_used.healths.icon_state = "health6"
- else
- hud_used.healths.icon_state = "health7"
-
-/mob/living/carbon/proc/update_internals_hud_icon(internal_state = 0)
- if(hud_used && hud_used.internals)
- hud_used.internals.icon_state = "internal[internal_state]"
-
-/mob/living/carbon/update_stat()
- if(status_flags & GODMODE)
- return
- if(stat != DEAD)
- if(health <= HEALTH_THRESHOLD_DEAD && !HAS_TRAIT(src, TRAIT_NODEATH))
- death()
- return
- if(IsUnconscious() || IsSleeping() || getOxyLoss() > 50 || (HAS_TRAIT(src, TRAIT_DEATHCOMA)) || (health <= HEALTH_THRESHOLD_FULLCRIT && !HAS_TRAIT(src, TRAIT_NOHARDCRIT)))
- stat = UNCONSCIOUS
- blind_eyes(1)
- if(combatmode)
- toggle_combat_mode(TRUE, TRUE)
- else
- if(health <= crit_threshold && !HAS_TRAIT(src, TRAIT_NOSOFTCRIT))
- stat = SOFT_CRIT
- if(combatmode)
- toggle_combat_mode(TRUE, TRUE)
- else
- stat = CONSCIOUS
- adjust_blindness(-1)
- update_canmove()
- update_damage_hud()
- update_health_hud()
- med_hud_set_status()
-
-//called when we get cuffed/uncuffed
-/mob/living/carbon/proc/update_handcuffed()
- if(handcuffed)
- drop_all_held_items()
- stop_pulling()
- throw_alert("handcuffed", /obj/screen/alert/restrained/handcuffed, new_master = src.handcuffed)
- if(handcuffed.demoralize_criminals)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "handcuffed", /datum/mood_event/handcuffed)
- else
- clear_alert("handcuffed")
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "handcuffed")
- update_action_buttons_icon() //some of our action buttons might be unusable when we're handcuffed.
- update_inv_handcuffed()
- update_hud_handcuffed()
-
-/mob/living/carbon/fully_heal(admin_revive = FALSE)
- if(reagents)
- reagents.clear_reagents()
- var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain)
- if(B)
- B.brain_death = FALSE
- for(var/thing in diseases)
- var/datum/disease/D = thing
- if(D.severity != DISEASE_SEVERITY_POSITIVE)
- D.cure(FALSE)
- if(admin_revive)
- regenerate_limbs()
- regenerate_organs()
- handcuffed = initial(handcuffed)
- for(var/obj/item/restraints/R in contents) //actually remove cuffs from inventory
- qdel(R)
- update_handcuffed()
- if(reagents)
- reagents.addiction_list = list()
- cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
- ..()
- // heal ears after healing traits, since ears check TRAIT_DEAF trait
- // when healing.
- restoreEars()
-
-/mob/living/carbon/can_be_revived()
- . = ..()
- if(!getorgan(/obj/item/organ/brain) && (!mind || !mind.has_antag_datum(/datum/antagonist/changeling)))
- return 0
-
-/mob/living/carbon/harvest(mob/living/user)
- if(QDELETED(src))
- return
- var/organs_amt = 0
- for(var/X in internal_organs)
- var/obj/item/organ/O = X
- if(prob(50))
- organs_amt++
- O.Remove(src)
- O.forceMove(drop_location())
- if(organs_amt)
- to_chat(user, "You retrieve some of [src]\'s internal organs!")
-
-/mob/living/carbon/ExtinguishMob()
- for(var/X in get_equipped_items())
- var/obj/item/I = X
- I.acid_level = 0 //washes off the acid on our clothes
- I.extinguish() //extinguishes our clothes
- ..()
-
-/mob/living/carbon/fakefire(var/fire_icon = "Generic_mob_burning")
- var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/OnFire.dmi', fire_icon, -FIRE_LAYER)
- new_fire_overlay.appearance_flags = RESET_COLOR
- overlays_standing[FIRE_LAYER] = new_fire_overlay
- apply_overlay(FIRE_LAYER)
-
-/mob/living/carbon/fakefireextinguish()
- remove_overlay(FIRE_LAYER)
-
-
-/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130)
- C.visible_message("[src] is attempting to devour [C]!", \
- "[src] is attempting to devour you!")
- if(!do_mob(src, C, devour_time))
- return
- if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == INTENT_GRAB)
- C.visible_message("[src] devours [C]!", \
- "[src] devours you!")
- C.forceMove(src)
- stomach_contents.Add(C)
- log_combat(src, C, "devoured")
-
-/mob/living/carbon/proc/create_bodyparts()
- var/l_arm_index_next = -1
- var/r_arm_index_next = 0
- for(var/X in bodyparts)
- var/obj/item/bodypart/O = new X()
- O.owner = src
- bodyparts.Remove(X)
- bodyparts.Add(O)
- if(O.body_part == ARM_LEFT)
- l_arm_index_next += 2
- O.held_index = l_arm_index_next //1, 3, 5, 7...
- hand_bodyparts += O
- else if(O.body_part == ARM_RIGHT)
- r_arm_index_next += 2
- O.held_index = r_arm_index_next //2, 4, 6, 8...
- hand_bodyparts += O
-
-/mob/living/carbon/do_after_coefficent()
- . = ..()
- var/datum/component/mood/mood = src.GetComponent(/datum/component/mood) //Currently, only carbons or higher use mood, move this once that changes.
- if(mood)
- switch(mood.sanity) //Alters do_after delay based on how sane you are
- if(SANITY_INSANE to SANITY_DISTURBED)
- . *= 1.25
- if(SANITY_NEUTRAL to SANITY_GREAT)
- . *= 0.90
-
-
-/mob/living/carbon/proc/create_internal_organs()
- for(var/X in internal_organs)
- var/obj/item/organ/I = X
- I.Insert(src)
-
-/mob/living/carbon/proc/update_disabled_bodyparts()
- for(var/B in bodyparts)
- var/obj/item/bodypart/BP = B
- BP.update_disabled()
-
-/mob/living/carbon/vv_get_dropdown()
- . = ..()
- . += "---"
- .["Make AI"] = "?_src_=vars;[HrefToken()];makeai=[REF(src)]"
- .["Modify bodypart"] = "?_src_=vars;[HrefToken()];editbodypart=[REF(src)]"
- .["Modify organs"] = "?_src_=vars;[HrefToken()];editorgans=[REF(src)]"
- .["Hallucinate"] = "?_src_=vars;[HrefToken()];hallucinate=[REF(src)]"
- .["Give martial arts"] = "?_src_=vars;[HrefToken()];givemartialart=[REF(src)]"
- .["Give brain trauma"] = "?_src_=vars;[HrefToken()];givetrauma=[REF(src)]"
- .["Cure brain traumas"] = "?_src_=vars;[HrefToken()];curetraumas=[REF(src)]"
-
-/mob/living/carbon/can_resist()
- return bodyparts.len > 2 && ..()
-
-/mob/living/carbon/proc/hypnosis_vulnerable()//unused atm, but added in case
- if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
- return FALSE
- if(hallucinating())
- return TRUE
- if(IsSleeping())
- return TRUE
- if(HAS_TRAIT(src, TRAIT_DUMB))
- return TRUE
- var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
- if(mood)
- if(mood.sanity < SANITY_UNSTABLE)
- return TRUE
-
-/mob/living/carbon/transfer_ckey(mob/new_mob, send_signal = TRUE)
- if(combatmode)
- toggle_combat_mode(TRUE, TRUE)
- return ..()
-
-/mob/living/carbon/can_see_reagents()
- . = ..()
- if(.) //No need to run through all of this if it's already true.
- return
- if(isclothing(head))
- var/obj/item/clothing/H = head
- if(H.clothing_flags & SCAN_REAGENTS)
- return TRUE
- if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
- return TRUE
+/mob/living/carbon
+ blood_volume = BLOOD_VOLUME_NORMAL
+
+/mob/living/carbon/Initialize()
+ . = ..()
+ create_reagents(1000)
+ update_body_parts() //to update the carbon's new bodyparts appearance
+ GLOB.carbon_list += src
+ blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
+
+/mob/living/carbon/Destroy()
+ //This must be done first, so the mob ghosts correctly before DNA etc is nulled
+ . = ..()
+
+ QDEL_LIST(internal_organs)
+ QDEL_LIST(stomach_contents)
+ QDEL_LIST(bodyparts)
+ QDEL_LIST(implants)
+ remove_from_all_data_huds()
+ QDEL_NULL(dna)
+ GLOB.carbon_list -= src
+
+/mob/living/carbon/initialize_footstep()
+ AddComponent(/datum/component/footstep, 0.6, 2)
+
+/mob/living/carbon/relaymove(mob/user, direction)
+ if(user in src.stomach_contents)
+ if(prob(40))
+ if(prob(25))
+ audible_message("You hear something rumbling inside [src]'s stomach...", \
+ "You hear something rumbling.", 4,\
+ "Something is rumbling inside your stomach!")
+ var/obj/item/I = user.get_active_held_item()
+ if(I && I.force)
+ var/d = rand(round(I.force / 4), I.force)
+ var/obj/item/bodypart/BP = get_bodypart(BODY_ZONE_CHEST)
+ if(BP.receive_damage(d, 0))
+ update_damage_overlays()
+ visible_message("[user] attacks [src]'s stomach wall with the [I.name]!", \
+ "[user] attacks your stomach wall with the [I.name]!")
+ playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
+
+ if(prob(src.getBruteLoss() - 50))
+ for(var/atom/movable/A in stomach_contents)
+ A.forceMove(drop_location())
+ stomach_contents.Remove(A)
+ src.gib()
+
+
+/mob/living/carbon/swap_hand(held_index)
+ if(!held_index)
+ held_index = (active_hand_index % held_items.len)+1
+
+ var/obj/item/item_in_hand = src.get_active_held_item()
+ if(item_in_hand) //this segment checks if the item in your hand is twohanded.
+ var/obj/item/twohanded/TH = item_in_hand
+ if(istype(TH))
+ if(TH.wielded == 1)
+ to_chat(usr, "Your other hand is too busy holding [TH]")
+ return
+ var/oindex = active_hand_index
+ active_hand_index = held_index
+ if(hud_used)
+ var/obj/screen/inventory/hand/H
+ H = hud_used.hand_slots["[oindex]"]
+ if(H)
+ H.update_icon()
+ H = hud_used.hand_slots["[held_index]"]
+ if(H)
+ H.update_icon()
+
+
+/mob/living/carbon/activate_hand(selhand) //l/r OR 1-held_items.len
+ if(!selhand)
+ selhand = (active_hand_index % held_items.len)+1
+
+ if(istext(selhand))
+ selhand = lowertext(selhand)
+ if(selhand == "right" || selhand == "r")
+ selhand = 2
+ if(selhand == "left" || selhand == "l")
+ selhand = 1
+
+ if(selhand != active_hand_index)
+ swap_hand(selhand)
+ else
+ mode() // Activate held item
+
+/mob/living/carbon/attackby(obj/item/I, mob/user, params)
+ if(lying && surgeries.len)
+ if(user != src && (user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM))
+ for(var/datum/surgery/S in surgeries)
+ if(S.next_step(user,user.a_intent))
+ return 1
+ return ..()
+
+/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum)
+ . = ..()
+ var/hurt = TRUE
+ if(istype(throwingdatum, /datum/thrownthing))
+ var/datum/thrownthing/D = throwingdatum
+ if(iscyborg(D.thrower))
+ var/mob/living/silicon/robot/R = D.thrower
+ if(!R.emagged)
+ hurt = FALSE
+ if(hit_atom.density && isturf(hit_atom))
+ if(hurt)
+ Knockdown(20)
+ take_bodypart_damage(10)
+ if(iscarbon(hit_atom) && hit_atom != src)
+ var/mob/living/carbon/victim = hit_atom
+ if(victim.movement_type & FLYING)
+ return
+ if(hurt)
+ victim.take_bodypart_damage(10)
+ take_bodypart_damage(10)
+ victim.Knockdown(20)
+ Knockdown(20)
+ visible_message("[src] crashes into [victim], knocking them both over!",\
+ "You violently crash into [victim]!")
+ playsound(src,'sound/weapons/punch1.ogg',50,1)
+
+
+//Throwing stuff
+/mob/living/carbon/proc/toggle_throw_mode()
+ if(stat)
+ return
+ if(in_throw_mode)
+ throw_mode_off()
+ else
+ throw_mode_on()
+
+
+/mob/living/carbon/proc/throw_mode_off()
+ in_throw_mode = 0
+ if(client && hud_used)
+ hud_used.throw_icon.icon_state = "act_throw_off"
+
+
+/mob/living/carbon/proc/throw_mode_on()
+ in_throw_mode = 1
+ if(client && hud_used)
+ hud_used.throw_icon.icon_state = "act_throw_on"
+
+/mob/proc/throw_item(atom/target)
+ SEND_SIGNAL(src, COMSIG_MOB_THROW, target)
+ return
+
+/mob/living/carbon/throw_item(atom/target)
+ throw_mode_off()
+ if(!target || !isturf(loc))
+ return
+ if(istype(target, /obj/screen))
+ return
+
+ //CIT CHANGES - makes it impossible to throw while in stamina softcrit
+ if(getStaminaLoss() >= STAMINA_SOFTCRIT)
+ to_chat(src, "You're too exhausted.")
+ return
+ var/random_turn = a_intent == INTENT_HARM
+ //END OF CIT CHANGES
+
+ var/obj/item/I = src.get_active_held_item()
+
+ var/atom/movable/thrown_thing
+ var/mob/living/throwable_mob
+
+ if(istype(I, /obj/item/clothing/head/mob_holder))
+ var/obj/item/clothing/head/mob_holder/holder = I
+ if(holder.held_mob)
+ throwable_mob = holder.held_mob
+ holder.release()
+
+ if(!I || throwable_mob)
+ if(!throwable_mob && pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE)
+ throwable_mob = pulling
+
+ if(throwable_mob && !throwable_mob.buckled)
+ thrown_thing = throwable_mob
+ if(pulling)
+ stop_pulling()
+ if(HAS_TRAIT(src, TRAIT_PACIFISM))
+ to_chat(src, "You gently let go of [throwable_mob].")
+ return
+
+ adjustStaminaLossBuffered(25)//CIT CHANGE - throwing an entire person shall be very tiring
+ var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
+ var/turf/end_T = get_turf(target)
+ if(start_T && end_T)
+ log_combat(src, throwable_mob, "thrown", addition="grab from tile in [AREACOORD(start_T)] towards tile at [AREACOORD(end_T)]")
+
+ else if(!CHECK_BITFIELD(I.item_flags, ABSTRACT) && !HAS_TRAIT(I, TRAIT_NODROP))
+ thrown_thing = I
+ dropItemToGround(I)
+
+ if(HAS_TRAIT(src, TRAIT_PACIFISM) && I.throwforce)
+ to_chat(src, "You set [I] down gently on the ground.")
+ return
+
+ adjustStaminaLossBuffered(I.getweight()*2)//CIT CHANGE - throwing items shall be more tiring than swinging em. Doubly so.
+
+ if(thrown_thing)
+ visible_message("[src] has thrown [thrown_thing].")
+ src.log_message("has thrown [thrown_thing]", LOG_ATTACK)
+ do_attack_animation(target, no_effect = 1)
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1)
+ newtonian_move(get_dir(target, src))
+ thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src, null, null, null, random_turn)
+
+
+
+/mob/living/carbon/restrained(ignore_grab)
+ . = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))
+
+/mob/living/carbon/proc/canBeHandcuffed()
+ return 0
+
+
+/mob/living/carbon/show_inv(mob/user)
+ user.set_machine(src)
+ var/dat = {"
+
+ [name]
+
+ Head: [(head && !(head.item_flags & ABSTRACT)) ? head : "Nothing"]
+ Mask: [(wear_mask && !(wear_mask.item_flags & ABSTRACT)) ? wear_mask : "Nothing"]
+ Neck: [(wear_neck && !(wear_neck.item_flags & ABSTRACT)) ? wear_neck : "Nothing"]"}
+
+ for(var/i in 1 to held_items.len)
+ var/obj/item/I = get_item_for_held_index(i)
+ dat += " [get_held_index_name(i)]: | [(I && !(I.item_flags & ABSTRACT)) ? I : "Nothing"]"
+
+ dat += " Back: [back ? back : "Nothing"]"
+
+ if(istype(wear_mask, /obj/item/clothing/mask) && istype(back, /obj/item/tank))
+ dat += " [internal ? "Disable Internals" : "Set Internals"]"
+
+ if(handcuffed)
+ dat += " Handcuffed"
+ if(legcuffed)
+ dat += " Legcuffed"
+
+ dat += {"
+
+ Close
+ "}
+ user << browse(dat, "window=mob[REF(src)];size=325x500")
+ onclose(user, "mob[REF(src)]")
+
+/mob/living/carbon/Topic(href, href_list)
+ ..()
+ //strip panel
+ if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
+ if(href_list["internal"])
+ var/slot = text2num(href_list["internal"])
+ var/obj/item/ITEM = get_item_by_slot(slot)
+ if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS))
+ visible_message("[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].", \
+ "[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].")
+ if(do_mob(usr, src, POCKET_STRIP_DELAY))
+ if(internal)
+ internal = null
+ update_internals_hud_icon(0)
+ else if(ITEM && istype(ITEM, /obj/item/tank))
+ if((wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS)) || getorganslot(ORGAN_SLOT_BREATHING_TUBE))
+ internal = ITEM
+ update_internals_hud_icon(1)
+
+ visible_message("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].", \
+ "[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].")
+
+
+/mob/living/carbon/fall(forced)
+ loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing
+
+/mob/living/carbon/is_muzzled()
+ return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle))
+
+/mob/living/carbon/hallucinating()
+ if(hallucination)
+ return TRUE
+ else
+ return FALSE
+
+/mob/living/carbon/resist_buckle()
+ if(restrained())
+ changeNext_move(CLICK_CD_BREAKOUT)
+ last_special = world.time + CLICK_CD_BREAKOUT
+ var/buckle_cd = 600
+ if(handcuffed)
+ var/obj/item/restraints/O = src.get_item_by_slot(SLOT_HANDCUFFED)
+ buckle_cd = O.breakouttime
+ visible_message("[src] attempts to unbuckle [p_them()]self!", \
+ "You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)")
+ if(do_after(src, buckle_cd, 0, target = src))
+ if(!buckled)
+ return
+ buckled.user_unbuckle_mob(src,src)
+ else
+ if(src && buckled)
+ to_chat(src, "You fail to unbuckle yourself!")
+ else
+ buckled.user_unbuckle_mob(src,src)
+
+/mob/living/carbon/resist_fire()
+ fire_stacks -= 5
+ Knockdown(60, TRUE, TRUE)
+ spin(32,2)
+ visible_message("[src] rolls on the floor, trying to put [p_them()]self out!", \
+ "You stop, drop, and roll!")
+ sleep(30)
+ if(fire_stacks <= 0)
+ visible_message("[src] has successfully extinguished [p_them()]self!", \
+ "You extinguish yourself.")
+ ExtinguishMob()
+ return
+
+/mob/living/carbon/resist_restraints()
+ var/obj/item/I = null
+ var/type = 0
+ if(handcuffed)
+ I = handcuffed
+ type = 1
+ else if(legcuffed)
+ I = legcuffed
+ type = 2
+ if(I)
+ if(type == 1)
+ changeNext_move(CLICK_CD_BREAKOUT)
+ last_special = world.time + CLICK_CD_BREAKOUT
+ if(type == 2)
+ changeNext_move(CLICK_CD_RANGE)
+ last_special = world.time + CLICK_CD_RANGE
+ cuff_resist(I)
+
+
+/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 600, cuff_break = 0)
+ if(I.item_flags & BEING_REMOVED)
+ to_chat(src, "You're already attempting to remove [I]!")
+ return
+ I.item_flags |= BEING_REMOVED
+ breakouttime = I.breakouttime
+ if(!cuff_break)
+ visible_message("[src] attempts to remove [I]!")
+ to_chat(src, "You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")
+ if(do_after(src, breakouttime, 0, target = src))
+ clear_cuffs(I, cuff_break)
+ else
+ to_chat(src, "You fail to remove [I]!")
+
+ else if(cuff_break == FAST_CUFFBREAK)
+ breakouttime = 50
+ visible_message("[src] is trying to break [I]!")
+ to_chat(src, "You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)")
+ if(do_after(src, breakouttime, 0, target = src))
+ clear_cuffs(I, cuff_break)
+ else
+ to_chat(src, "You fail to break [I]!")
+
+ else if(cuff_break == INSTANT_CUFFBREAK)
+ clear_cuffs(I, cuff_break)
+ I.item_flags &= ~BEING_REMOVED
+
+/mob/living/carbon/proc/uncuff()
+ if (handcuffed)
+ var/obj/item/W = handcuffed
+ handcuffed = null
+ if (buckled && buckled.buckle_requires_restraints)
+ buckled.unbuckle_mob(src)
+ update_handcuffed()
+ if (client)
+ client.screen -= W
+ if (W)
+ W.forceMove(drop_location())
+ W.dropped(src)
+ if (W)
+ W.layer = initial(W.layer)
+ W.plane = initial(W.plane)
+ changeNext_move(0)
+ if (legcuffed)
+ var/obj/item/W = legcuffed
+ legcuffed = null
+ update_inv_legcuffed()
+ if (client)
+ client.screen -= W
+ if (W)
+ W.forceMove(drop_location())
+ W.dropped(src)
+ if (W)
+ W.layer = initial(W.layer)
+ W.plane = initial(W.plane)
+ changeNext_move(0)
+
+/mob/living/carbon/proc/clear_cuffs(obj/item/I, cuff_break)
+ if(!I.loc || buckled)
+ return
+ visible_message("[src] manages to [cuff_break ? "break" : "remove"] [I]!")
+ to_chat(src, "You successfully [cuff_break ? "break" : "remove"] [I].")
+
+ if(cuff_break)
+ . = !((I == handcuffed) || (I == legcuffed))
+ qdel(I)
+ return
+
+ else
+ if(I == handcuffed)
+ handcuffed.forceMove(drop_location())
+ handcuffed.dropped(src)
+ handcuffed = null
+ if(buckled && buckled.buckle_requires_restraints)
+ buckled.unbuckle_mob(src)
+ update_handcuffed()
+ return
+ if(I == legcuffed)
+ legcuffed.forceMove(drop_location())
+ legcuffed.dropped()
+ legcuffed = null
+ update_inv_legcuffed()
+ return
+ else
+ dropItemToGround(I)
+ return
+ return TRUE
+
+/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
+ if(lying)
+ return -6
+ else
+ return initial(pixel_y)
+
+/mob/living/carbon/proc/accident(obj/item/I)
+ if(!I || (I.item_flags & ABSTRACT) || HAS_TRAIT(I, TRAIT_NODROP))
+ return
+
+ //dropItemToGround(I) CIT CHANGE - makes it so the item doesn't drop if the modifier rolls above 100
+
+ var/modifier = 0
+
+ if(HAS_TRAIT(src, TRAIT_CLUMSY))
+ modifier -= 40 //Clumsy people are more likely to hit themselves -Honk!
+
+ //CIT CHANGES START HERE
+ else if(combatmode)
+ modifier += 50
+
+ if(modifier < 100)
+ dropItemToGround(I)
+ //END OF CIT CHANGES
+
+ switch(rand(1,100)+modifier) //91-100=Nothing special happens
+ if(-INFINITY to 0) //attack yourself
+ I.attack(src,src)
+ if(1 to 30) //throw it at yourself
+ I.throw_impact(src)
+ if(31 to 60) //Throw object in facing direction
+ var/turf/target = get_turf(loc)
+ var/range = rand(2,I.throw_range)
+ for(var/i = 1; i < range; i++)
+ var/turf/new_turf = get_step(target, dir)
+ target = new_turf
+ if(new_turf.density)
+ break
+ I.throw_at(target,I.throw_range,I.throw_speed,src)
+ if(61 to 90) //throw it down to the floor
+ var/turf/target = get_turf(loc)
+ I.throw_at(target,I.throw_range,I.throw_speed,src)
+
+/mob/living/carbon/Stat()
+ ..()
+ if(statpanel("Status"))
+ var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel)
+ if(vessel)
+ stat(null, "Plasma Stored: [vessel.storedPlasma]/[vessel.max_plasma]")
+ if(locate(/obj/item/assembly/health) in src)
+ stat(null, "Health: [health]")
+
+ add_abilities_to_panel()
+
+/mob/living/carbon/attack_ui(slot)
+ if(!has_hand_for_held_index(active_hand_index))
+ return 0
+ return ..()
+
+/mob/living/carbon/proc/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, toxic = FALSE)
+ if(HAS_TRAIT(src, TRAIT_NOHUNGER))
+ return 1
+
+ if(nutrition < 100 && !blood)
+ if(message)
+ visible_message("[src] dry heaves!", \
+ "You try to throw up, but there's nothing in your stomach!")
+ if(stun)
+ Knockdown(200)
+ return 1
+
+ if(is_mouth_covered()) //make this add a blood/vomit overlay later it'll be hilarious
+ if(message)
+ visible_message("[src] throws up all over [p_them()]self!", \
+ "You throw up all over yourself!")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomitself)
+ distance = 0
+ else
+ if(message)
+ visible_message("[src] throws up!", "You throw up!")
+ if(!isflyperson(src))
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomit)
+ if(stun)
+ Stun(80)
+
+ playsound(get_turf(src), 'sound/effects/splat.ogg', 50, 1)
+ var/turf/T = get_turf(src)
+ if(!blood)
+ nutrition -= lost_nutrition
+ adjustToxLoss(-3)
+ for(var/i=0 to distance)
+ if(blood)
+ if(T)
+ add_splatter_floor(T)
+ if(stun)
+ adjustBruteLoss(3)
+ else if(src.reagents.has_reagent("blazaam"))
+ if(T)
+ T.add_vomit_floor(src, VOMIT_PURPLE)
+ else
+ if(T)
+ T.add_vomit_floor(src, VOMIT_TOXIC)//toxic barf looks different
+ T = get_step(T, dir)
+ if (is_blocked_turf(T))
+ break
+ return 1
+
+/mob/living/carbon/proc/spew_organ(power = 5, amt = 1)
+ for(var/i in 1 to amt)
+ if(!internal_organs.len)
+ break //Guess we're out of organs!
+ var/obj/item/organ/guts = pick(internal_organs)
+ var/turf/T = get_turf(src)
+ guts.Remove(src)
+ guts.forceMove(T)
+ var/atom/throw_target = get_edge_target_turf(guts, dir)
+ guts.throw_at(throw_target, power, 4, src)
+
+
+/mob/living/carbon/fully_replace_character_name(oldname,newname)
+ ..()
+ if(dna)
+ dna.real_name = real_name
+
+//Updates the mob's health from bodyparts and mob damage variables
+/mob/living/carbon/updatehealth()
+ if(status_flags & GODMODE)
+ return
+ var/total_burn = 0
+ var/total_brute = 0
+ var/total_stamina = 0
+ for(var/X in bodyparts) //hardcoded to streamline things a bit
+ var/obj/item/bodypart/BP = X
+ total_brute += (BP.brute_dam * BP.body_damage_coeff)
+ total_burn += (BP.burn_dam * BP.body_damage_coeff)
+ total_stamina += (BP.stamina_dam * BP.stam_damage_coeff)
+ health = round(maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute, DAMAGE_PRECISION)
+ staminaloss = round(total_stamina, DAMAGE_PRECISION)
+ update_stat()
+ if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
+ become_husk("burn")
+ med_hud_set_health()
+ if(stat == SOFT_CRIT)
+ add_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE, multiplicative_slowdown = SOFTCRIT_ADD_SLOWDOWN)
+ else
+ remove_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE)
+
+/mob/living/carbon/update_stamina()
+ var/stam = getStaminaLoss()
+ if(stam > DAMAGE_PRECISION)
+ var/total_health = (health - stam)
+ if(total_health <= crit_threshold && !stat)
+ if(!IsKnockdown())
+ to_chat(src, "You're too exhausted to keep going...")
+ Knockdown(100)
+ update_health_hud()
+
+/mob/living/carbon/update_sight()
+ if(!client)
+ return
+ if(stat == DEAD)
+ sight = (SEE_TURFS|SEE_MOBS|SEE_OBJS)
+ see_in_dark = 8
+ see_invisible = SEE_INVISIBLE_OBSERVER
+ return
+
+ sight = initial(sight)
+ lighting_alpha = initial(lighting_alpha)
+ var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
+ if(!E)
+ update_tint()
+ else
+ see_invisible = E.see_invisible
+ see_in_dark = E.see_in_dark
+ sight |= E.sight_flags
+ if(!isnull(E.lighting_alpha))
+ lighting_alpha = E.lighting_alpha
+ if(HAS_TRAIT(src, TRAIT_NIGHT_VISION))
+ lighting_alpha = min(LIGHTING_PLANE_ALPHA_NV_TRAIT, lighting_alpha)
+ see_in_dark = max(NIGHT_VISION_DARKSIGHT_RANGE, see_in_dark)
+
+ if(client.eye && client.eye != src)
+ var/atom/A = client.eye
+ if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates.
+ return
+
+ if(glasses)
+ var/obj/item/clothing/glasses/G = glasses
+ sight |= G.vision_flags
+ see_in_dark = max(G.darkness_view, see_in_dark)
+ if(G.invis_override)
+ see_invisible = G.invis_override
+ else
+ see_invisible = min(G.invis_view, see_invisible)
+ if(!isnull(G.lighting_alpha))
+ lighting_alpha = min(lighting_alpha, G.lighting_alpha)
+ if(dna)
+ for(var/X in dna.mutations)
+ var/datum/mutation/M = X
+ if(M.name == XRAY)
+ sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
+ see_in_dark = max(see_in_dark, 8)
+
+ if(see_override)
+ see_invisible = see_override
+ . = ..()
+
+
+//to recalculate and update the mob's total tint from tinted equipment it's wearing.
+/mob/living/carbon/proc/update_tint()
+ if(!GLOB.tinted_weldhelh)
+ return
+ tinttotal = get_total_tint()
+ if(tinttotal >= TINT_BLIND)
+ become_blind(EYES_COVERED)
+ else if(tinttotal >= TINT_DARKENED)
+ cure_blind(EYES_COVERED)
+ overlay_fullscreen("tint", /obj/screen/fullscreen/impaired, 2)
+ else
+ cure_blind(EYES_COVERED)
+ clear_fullscreen("tint", 0)
+
+/mob/living/carbon/proc/get_total_tint()
+ . = 0
+ if(istype(head, /obj/item/clothing/head))
+ var/obj/item/clothing/head/HT = head
+ . += HT.tint
+ if(wear_mask)
+ . += wear_mask.tint
+
+ var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
+ if(E)
+ . += E.tint
+
+ else
+ . += INFINITY
+
+/mob/living/carbon/get_permeability_protection(list/target_zones = list(HANDS,CHEST,GROIN,LEGS,FEET,ARMS,HEAD))
+ var/list/tally = list()
+ for(var/obj/item/I in get_equipped_items())
+ for(var/zone in target_zones)
+ if(I.body_parts_covered & zone)
+ tally["[zone]"] = max(1 - I.permeability_coefficient, target_zones["[zone]"])
+ var/protection = 0
+ for(var/key in tally)
+ protection += tally[key]
+ protection *= INVERSE(target_zones.len)
+ return protection
+
+//this handles hud updates
+/mob/living/carbon/update_damage_hud()
+
+ if(!client)
+ return
+
+ if(health <= crit_threshold)
+ var/severity = 0
+ switch(health)
+ if(-20 to -10)
+ severity = 1
+ if(-30 to -20)
+ severity = 2
+ if(-40 to -30)
+ severity = 3
+ if(-50 to -40)
+ severity = 4
+ if(-50 to -40)
+ severity = 5
+ if(-60 to -50)
+ severity = 6
+ if(-70 to -60)
+ severity = 7
+ if(-90 to -70)
+ severity = 8
+ if(-95 to -90)
+ severity = 9
+ if(-INFINITY to -95)
+ severity = 10
+ if(!InFullCritical())
+ var/visionseverity = 4
+ switch(health)
+ if(-8 to -4)
+ visionseverity = 5
+ if(-12 to -8)
+ visionseverity = 6
+ if(-16 to -12)
+ visionseverity = 7
+ if(-20 to -16)
+ visionseverity = 8
+ if(-24 to -20)
+ visionseverity = 9
+ if(-INFINITY to -24)
+ visionseverity = 10
+ overlay_fullscreen("critvision", /obj/screen/fullscreen/crit/vision, visionseverity)
+ else
+ clear_fullscreen("critvision")
+ overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity)
+ else
+ clear_fullscreen("crit")
+ clear_fullscreen("critvision")
+
+ //Oxygen damage overlay
+ var/windedup = getOxyLoss() + getStaminaLoss() * 0.2
+ if(windedup)
+ var/severity = 0
+ switch(windedup)
+ if(10 to 20)
+ severity = 1
+ if(20 to 25)
+ severity = 2
+ if(25 to 30)
+ severity = 3
+ if(30 to 35)
+ severity = 4
+ if(35 to 40)
+ severity = 5
+ if(40 to 45)
+ severity = 6
+ if(45 to INFINITY)
+ severity = 7
+ overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity)
+ else
+ clear_fullscreen("oxy")
+
+ //Fire and Brute damage overlay (BSSR)
+ var/hurtdamage = getBruteLoss() + getFireLoss() + damageoverlaytemp
+ if(hurtdamage)
+ var/severity = 0
+ switch(hurtdamage)
+ if(5 to 15)
+ severity = 1
+ if(15 to 30)
+ severity = 2
+ if(30 to 45)
+ severity = 3
+ if(45 to 70)
+ severity = 4
+ if(70 to 85)
+ severity = 5
+ if(85 to INFINITY)
+ severity = 6
+ overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
+ else
+ clear_fullscreen("brute")
+
+/mob/living/carbon/update_health_hud(shown_health_amount)
+ if(!client || !hud_used)
+ return
+ if(hud_used.healths)
+ if(stat != DEAD)
+ . = 1
+ if(!shown_health_amount)
+ shown_health_amount = health
+ if(shown_health_amount >= maxHealth)
+ hud_used.healths.icon_state = "health0"
+ else if(shown_health_amount > maxHealth*0.8)
+ hud_used.healths.icon_state = "health1"
+ else if(shown_health_amount > maxHealth*0.6)
+ hud_used.healths.icon_state = "health2"
+ else if(shown_health_amount > maxHealth*0.4)
+ hud_used.healths.icon_state = "health3"
+ else if(shown_health_amount > maxHealth*0.2)
+ hud_used.healths.icon_state = "health4"
+ else if(shown_health_amount > 0)
+ hud_used.healths.icon_state = "health5"
+ else
+ hud_used.healths.icon_state = "health6"
+ else
+ hud_used.healths.icon_state = "health7"
+
+/mob/living/carbon/proc/update_internals_hud_icon(internal_state = 0)
+ if(hud_used && hud_used.internals)
+ hud_used.internals.icon_state = "internal[internal_state]"
+
+/mob/living/carbon/update_stat()
+ if(status_flags & GODMODE)
+ return
+ if(stat != DEAD)
+ if(health <= HEALTH_THRESHOLD_DEAD && !HAS_TRAIT(src, TRAIT_NODEATH))
+ death()
+ return
+ if(IsUnconscious() || IsSleeping() || getOxyLoss() > 50 || (HAS_TRAIT(src, TRAIT_DEATHCOMA)) || (health <= HEALTH_THRESHOLD_FULLCRIT && !HAS_TRAIT(src, TRAIT_NOHARDCRIT)))
+ stat = UNCONSCIOUS
+ blind_eyes(1)
+ if(combatmode)
+ toggle_combat_mode(TRUE, TRUE)
+ else
+ if(health <= crit_threshold && !HAS_TRAIT(src, TRAIT_NOSOFTCRIT))
+ stat = SOFT_CRIT
+ if(combatmode)
+ toggle_combat_mode(TRUE, TRUE)
+ else
+ stat = CONSCIOUS
+ adjust_blindness(-1)
+ update_canmove()
+ update_damage_hud()
+ update_health_hud()
+ med_hud_set_status()
+
+//called when we get cuffed/uncuffed
+/mob/living/carbon/proc/update_handcuffed()
+ if(handcuffed)
+ drop_all_held_items()
+ stop_pulling()
+ throw_alert("handcuffed", /obj/screen/alert/restrained/handcuffed, new_master = src.handcuffed)
+ if(handcuffed.demoralize_criminals)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "handcuffed", /datum/mood_event/handcuffed)
+ else
+ clear_alert("handcuffed")
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "handcuffed")
+ update_action_buttons_icon() //some of our action buttons might be unusable when we're handcuffed.
+ update_inv_handcuffed()
+ update_hud_handcuffed()
+
+/mob/living/carbon/fully_heal(admin_revive = FALSE)
+ if(reagents)
+ reagents.clear_reagents()
+ var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain)
+ if(B)
+ B.brain_death = FALSE
+ for(var/thing in diseases)
+ var/datum/disease/D = thing
+ if(D.severity != DISEASE_SEVERITY_POSITIVE)
+ D.cure(FALSE)
+ if(admin_revive)
+ regenerate_limbs()
+ regenerate_organs()
+ handcuffed = initial(handcuffed)
+ for(var/obj/item/restraints/R in contents) //actually remove cuffs from inventory
+ qdel(R)
+ update_handcuffed()
+ if(reagents)
+ reagents.addiction_list = list()
+ cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
+ ..()
+ // heal ears after healing traits, since ears check TRAIT_DEAF trait
+ // when healing.
+ restoreEars()
+
+/mob/living/carbon/can_be_revived()
+ . = ..()
+ if(!getorgan(/obj/item/organ/brain) && (!mind || !mind.has_antag_datum(/datum/antagonist/changeling)))
+ return 0
+
+/mob/living/carbon/harvest(mob/living/user)
+ if(QDELETED(src))
+ return
+ var/organs_amt = 0
+ for(var/X in internal_organs)
+ var/obj/item/organ/O = X
+ if(prob(50))
+ organs_amt++
+ O.Remove(src)
+ O.forceMove(drop_location())
+ if(organs_amt)
+ to_chat(user, "You retrieve some of [src]\'s internal organs!")
+
+/mob/living/carbon/ExtinguishMob()
+ for(var/X in get_equipped_items())
+ var/obj/item/I = X
+ I.acid_level = 0 //washes off the acid on our clothes
+ I.extinguish() //extinguishes our clothes
+ ..()
+
+/mob/living/carbon/fakefire(var/fire_icon = "Generic_mob_burning")
+ var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/OnFire.dmi', fire_icon, -FIRE_LAYER)
+ new_fire_overlay.appearance_flags = RESET_COLOR
+ overlays_standing[FIRE_LAYER] = new_fire_overlay
+ apply_overlay(FIRE_LAYER)
+
+/mob/living/carbon/fakefireextinguish()
+ remove_overlay(FIRE_LAYER)
+
+
+/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130)
+ C.visible_message("[src] is attempting to devour [C]!", \
+ "[src] is attempting to devour you!")
+ if(!do_mob(src, C, devour_time))
+ return
+ if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == INTENT_GRAB)
+ C.visible_message("[src] devours [C]!", \
+ "[src] devours you!")
+ C.forceMove(src)
+ stomach_contents.Add(C)
+ log_combat(src, C, "devoured")
+
+/mob/living/carbon/proc/create_bodyparts()
+ var/l_arm_index_next = -1
+ var/r_arm_index_next = 0
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/O = new X()
+ O.owner = src
+ bodyparts.Remove(X)
+ bodyparts.Add(O)
+ if(O.body_part == ARM_LEFT)
+ l_arm_index_next += 2
+ O.held_index = l_arm_index_next //1, 3, 5, 7...
+ hand_bodyparts += O
+ else if(O.body_part == ARM_RIGHT)
+ r_arm_index_next += 2
+ O.held_index = r_arm_index_next //2, 4, 6, 8...
+ hand_bodyparts += O
+
+/mob/living/carbon/do_after_coefficent()
+ . = ..()
+ var/datum/component/mood/mood = src.GetComponent(/datum/component/mood) //Currently, only carbons or higher use mood, move this once that changes.
+ if(mood)
+ switch(mood.sanity) //Alters do_after delay based on how sane you are
+ if(SANITY_INSANE to SANITY_DISTURBED)
+ . *= 1.25
+ if(SANITY_NEUTRAL to SANITY_GREAT)
+ . *= 0.90
+
+
+/mob/living/carbon/proc/create_internal_organs()
+ for(var/X in internal_organs)
+ var/obj/item/organ/I = X
+ I.Insert(src)
+
+/mob/living/carbon/proc/update_disabled_bodyparts()
+ for(var/B in bodyparts)
+ var/obj/item/bodypart/BP = B
+ BP.update_disabled()
+
+/mob/living/carbon/vv_get_dropdown()
+ . = ..()
+ . += "---"
+ .["Make AI"] = "?_src_=vars;[HrefToken()];makeai=[REF(src)]"
+ .["Modify bodypart"] = "?_src_=vars;[HrefToken()];editbodypart=[REF(src)]"
+ .["Modify organs"] = "?_src_=vars;[HrefToken()];editorgans=[REF(src)]"
+ .["Hallucinate"] = "?_src_=vars;[HrefToken()];hallucinate=[REF(src)]"
+ .["Give martial arts"] = "?_src_=vars;[HrefToken()];givemartialart=[REF(src)]"
+ .["Give brain trauma"] = "?_src_=vars;[HrefToken()];givetrauma=[REF(src)]"
+ .["Cure brain traumas"] = "?_src_=vars;[HrefToken()];curetraumas=[REF(src)]"
+
+/mob/living/carbon/can_resist()
+ return bodyparts.len > 2 && ..()
+
+/mob/living/carbon/proc/hypnosis_vulnerable()//unused atm, but added in case
+ if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
+ return FALSE
+ if(hallucinating())
+ return TRUE
+ if(IsSleeping())
+ return TRUE
+ if(HAS_TRAIT(src, TRAIT_DUMB))
+ return TRUE
+ var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
+ if(mood)
+ if(mood.sanity < SANITY_UNSTABLE)
+ return TRUE
+
+/mob/living/carbon/transfer_ckey(mob/new_mob, send_signal = TRUE)
+ if(combatmode)
+ toggle_combat_mode(TRUE, TRUE)
+ return ..()
+
+/mob/living/carbon/can_see_reagents()
+ . = ..()
+ if(.) //No need to run through all of this if it's already true.
+ return
+ if(isclothing(head))
+ var/obj/item/clothing/H = head
+ if(H.clothing_flags & SCAN_REAGENTS)
+ return TRUE
+ if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
+ return TRUE
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 06575aa802..ba40ae8e5f 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -48,41 +48,42 @@
if(affecting && affecting.dismemberable && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
affecting.dismember(P.damtype)
-/mob/living/carbon/proc/can_catch_item(skip_throw_mode_check)
- . = FALSE
- if(mind)
- if(mind.martial_art && mind.martial_art.dodge_chance == 100)
- return TRUE
- if(!skip_throw_mode_check && !in_throw_mode)
+/mob/living/carbon/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
+ . = ..()
+ if(!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) && !skip_throw_mode_check && !in_throw_mode)
return
- if(get_active_held_item())
+ if(get_active_held_item() || restrained())
return
- if(restrained())
- return
- return TRUE
-
-/mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE)
- if(!skipcatch) //ugly, but easy
- if(can_catch_item())
- if(istype(AM, /obj/item))
- var/obj/item/I = AM
- if (mind)
- if (mind.martial_art && mind.martial_art.dodge_chance == 100) //autocatch for rising bass
- if (get_active_held_item())
- visible_message("[I] falls to the ground as [src] chops it out of the air!")
- return 1
- if(!in_throw_mode)
- throw_mode_on()
- if(isturf(I.loc))
- I.attack_hand(src)
- if(get_active_held_item() == I) //if our attack_hand() picks up the item...
- visible_message("[src] catches [I]!") //catch that sucker!
- throw_mode_off()
- return 1
- ..()
+ I.attack_hand(src)
+ if(get_active_held_item() == I) //if our attack_hand() picks up the item...
+ visible_message("[src] catches [I]!") //catch that sucker!
+ throw_mode_off()
+ return TRUE
+/mob/living/carbon/embed_item(obj/item/I)
+ throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
+ var/obj/item/bodypart/L = pick(bodyparts)
+ L.embedded_objects |= I
+ I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
+ I.forceMove(src)
+ L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
+ visible_message("[I] embeds itself in [src]'s [L.name]!","[I] embeds itself in your [L.name]!")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
+ //CIT CHANGES START HERE - combatmode and resting checks
+ var/totitemdamage = I.force
+ if(iscarbon(user))
+ var/mob/living/carbon/tempcarb = user
+ if(!tempcarb.combatmode)
+ totitemdamage *= 0.5
+ if(user.resting)
+ totitemdamage *= 0.5
+ if(!combatmode)
+ totitemdamage *= 1.5
+ //CIT CHANGES END HERE
+ if(user != src && check_shields(I, totitemdamage, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
+ return FALSE
var/obj/item/bodypart/affecting
if(user == src)
affecting = get_bodypart(check_zone(user.zone_selected)) //we're self-mutilating! yay!
@@ -93,17 +94,6 @@
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
send_item_attack_message(I, user, affecting.name)
if(I.force)
- //CIT CHANGES START HERE - combatmode and resting checks
- var/totitemdamage = I.force
- if(iscarbon(user))
- var/mob/living/carbon/tempcarb = user
- if(!tempcarb.combatmode)
- totitemdamage *= 0.5
- if(user.resting)
- totitemdamage *= 0.5
- if(!combatmode)
- totitemdamage *= 1.5
- //CIT CHANGES END HERE
apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage
if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
var/basebloodychance = affecting.brute_dam + totitemdamage
@@ -137,7 +127,9 @@
//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
-
+ . = ..()
+ if(.) //was the attack blocked?
+ return
for(var/thing in diseases)
var/datum/disease/D = thing
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
@@ -152,8 +144,7 @@
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
for(var/datum/surgery/S in surgeries)
if(S.next_step(user, user.a_intent))
- return 1
- return 0
+ return TRUE
/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
@@ -173,7 +164,8 @@
help_shake_act(M)
return 0
- if(..()) //successful monkey bite.
+ . = ..()
+ if(.) //successful monkey bite.
for(var/thing in M.diseases)
var/datum/disease/D = thing
ForceContractDisease(D)
@@ -181,26 +173,27 @@
/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime attack
- if(M.powerlevel > 0)
- var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
- if(prob(stunprob))
- M.powerlevel -= 3
- if(M.powerlevel < 0)
- M.powerlevel = 0
+ . = ..()
+ if(!.)
+ return
+ if(M.powerlevel > 0)
+ var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
+ if(prob(stunprob))
+ M.powerlevel -= 3
+ if(M.powerlevel < 0)
+ M.powerlevel = 0
- visible_message("The [M.name] has shocked [src]!", \
- "The [M.name] has shocked [src]!")
+ visible_message("The [M.name] has shocked [src]!", \
+ "The [M.name] has shocked [src]!")
- do_sparks(5, TRUE, src)
- var/power = M.powerlevel + rand(0,3)
- Knockdown(power*20)
- if(stuttering < power)
- stuttering = power
- if (prob(stunprob) && M.powerlevel >= 8)
- adjustFireLoss(M.powerlevel * rand(6,10))
- updatehealth()
- return 1
+ do_sparks(5, TRUE, src)
+ var/power = M.powerlevel + rand(0,3)
+ Knockdown(power*20)
+ if(stuttering < power)
+ stuttering = power
+ if (prob(stunprob) && M.powerlevel >= 8)
+ adjustFireLoss(M.powerlevel * rand(6,10))
+ updatehealth()
/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone)
if(!attacker.limb_destroyer)
@@ -332,12 +325,12 @@
else
return
-
+
else if(check_zone(M.zone_selected) == "r_arm" || check_zone(M.zone_selected) == "l_arm")
M.visible_message( \
"[M] shakes [src]'s hand.", \
"You shake [src]'s hand.", )
-
+
else
M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \
"You hug [src] to make [p_them()] feel better!")
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 165e1fdd31..2b1d6afc4f 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -67,66 +67,36 @@
P.setAngle(rand(0, 360))//SHING
return FALSE
- if(!(P.original == src && P.firer == src)) //can't block or reflect when shooting yourself
- if(P.is_reflectable)
- if(check_reflect(def_zone)) // Checks if you've passed a reflection% check
- visible_message("The [P.name] gets reflected by [src]!", \
- "The [P.name] gets reflected by [src]!")
- // Find a turf near or on the original location to bounce to
- if(P.starting)
- var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/turf/curloc = get_turf(src)
+ return ..()
- // redirect the projectile
- P.original = locate(new_x, new_y, P.z)
- P.starting = curloc
- P.firer = src
- P.yo = new_y - curloc.y
- P.xo = new_x - curloc.x
- var/new_angle_s = P.Angle + rand(120,240)
- while(new_angle_s > 180) // Translate to regular projectile degrees
- new_angle_s -= 360
- P.setAngle(new_angle_s)
+/mob/living/carbon/human/check_reflect(def_zone)
+ if(wear_suit?.IsReflect(def_zone))
+ return TRUE
+ return ..()
- return -1 // complete projectile permutation
-
- if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
- P.on_hit(src, 100, def_zone)
- return 2
-
- return (..(P , def_zone))
-
-/mob/living/carbon/human/proc/check_reflect(def_zone) //Reflection checks for anything in your l_hand, r_hand, or wear_suit based on the reflection chance of the object
- if(wear_suit)
- if(wear_suit.IsReflect(def_zone) == 1)
- return 1
- for(var/obj/item/I in held_items)
- if(I.IsReflect(def_zone) == 1)
- return 1
- return 0
-
-/mob/living/carbon/human/proc/check_shields(atom/AM, var/damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
+/mob/living/carbon/human/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
+ . = ..()
+ if(.)
+ return
var/block_chance_modifier = round(damage / -3)
-
- for(var/obj/item/I in held_items)
- if(!istype(I, /obj/item/clothing))
- var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
- if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
- return 1
if(wear_suit)
var/final_block_chance = wear_suit.block_chance - (CLAMP((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
- return 1
+ return TRUE
if(w_uniform)
var/final_block_chance = w_uniform.block_chance - (CLAMP((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
- return 1
+ return TRUE
if(wear_neck)
var/final_block_chance = wear_neck.block_chance - (CLAMP((armour_penetration-wear_neck.armour_penetration)/2,0,100)) + block_chance_modifier
if(wear_neck.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
- return 1
- return 0
+ return TRUE
+ return FALSE
+
+/mob/living/carbon/human/can_embed(obj/item/I)
+ if(I.get_sharpness() || is_pointed(I) || is_type_in_typecache(I, GLOB.can_embed_types))
+ return TRUE
+ return FALSE
/mob/living/carbon/human/proc/check_block()
if(mind)
@@ -135,39 +105,7 @@
return FALSE
/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE)
- if(dna && dna.species)
- var/spec_return = dna.species.spec_hitby(AM, src)
- if(spec_return)
- return spec_return
- var/obj/item/I
- var/throwpower = 30
- if(istype(AM, /obj/item))
- I = AM
- throwpower = I.throwforce
- if(I.thrownby == src) //No throwing stuff at yourself to trigger hit reactions
- return ..()
- if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
- hitpush = FALSE
- skipcatch = TRUE
- blocked = TRUE
- else if(I)
- if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD && !(mind.martial_art && mind.martial_art.dodge_chance == 100))
- if(can_embed(I))
- if(prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE))
- throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
- var/obj/item/bodypart/L = pick(bodyparts)
- L.embedded_objects |= I
- I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
- I.forceMove(src)
- L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
- visible_message("[I] embeds itself in [src]'s [L.name]!","[I] embeds itself in your [L.name]!")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
- hitpush = FALSE
- skipcatch = TRUE //can't catch the now embedded item
- if (mind)
- if (mind.martial_art && mind.martial_art.dodge_chance == 100)
- skipcatch = FALSE
- return ..()
+ return dna?.species?.spec_hitby(AM, src) || ..()
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (HAS_TRAIT(src, TRAIT_FAT)) && ismonkey(pulling))
@@ -201,12 +139,12 @@
return dna.species.spec_attacked_by(I, user, affecting, a_intent, src)
-/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
+/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
- var/hulk_verb = pick("smash","pummel")
- if(check_shields(user, 15, "the [hulk_verb]ing"))
+ . = ..(user, TRUE)
+ if(.)
return
- ..(user, 1)
+ var/hulk_verb = pick("smash","pummel")
playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
var/message = "[user] has [hulk_verb]ed [src]!"
visible_message("[message]", \
@@ -215,7 +153,8 @@
return 1
/mob/living/carbon/human/attack_hand(mob/user)
- if(..()) //to allow surgery to return properly.
+ . = ..()
+ if(.) //To allow surgery to return properly.
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
@@ -227,8 +166,7 @@
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
if(M.a_intent == INTENT_HELP)
- ..() //shaking
- return 0
+ return ..() //shaking
if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stunned instead.
var/obj/item/I = get_active_held_item()
@@ -249,78 +187,69 @@
if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites.
if(..()) //successful monkey bite, this handles disease contraction.
var/damage = rand(1, 3)
- if(check_shields(M, damage, "the [M.name]"))
- return 0
- if(stat != DEAD)
- apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee"))
+ apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee"))
return 1
/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(check_shields(M, 0, "the M.name"))
- visible_message("[M] attempted to touch [src]!")
- return 0
+ . = ..()
+ if(!.)
+ return
+ if(M.a_intent == INTENT_HARM)
+ if (w_uniform)
+ w_uniform.add_fingerprint(M)
+ var/damage = prob(90) ? 20 : 0
+ if(!damage)
+ playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
+ visible_message("[M] has lunged at [src]!", \
+ "[M] has lunged at [src]!")
+ return 0
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ if(!affecting)
+ affecting = get_bodypart(BODY_ZONE_CHEST)
+ var/armor_block = run_armor_check(affecting, "melee", null, null,10)
- if(..())
- if(M.a_intent == INTENT_HARM)
- if (w_uniform)
- w_uniform.add_fingerprint(M)
- var/damage = prob(90) ? 20 : 0
- if(!damage)
- playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
- visible_message("[M] has lunged at [src]!", \
- "[M] has lunged at [src]!")
- return 0
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
- if(!affecting)
- affecting = get_bodypart(BODY_ZONE_CHEST)
- var/armor_block = run_armor_check(affecting, "melee", null, null,10)
+ playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
+ visible_message("[M] has slashed at [src]!", \
+ "[M] has slashed at [src]!")
+ log_combat(M, src, "attacked")
+ if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
+ return 1
+ apply_damage(damage, BRUTE, affecting, armor_block)
- playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!")
- log_combat(M, src, "attacked")
- if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
- return 1
- apply_damage(damage, BRUTE, affecting, armor_block)
-
- if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stun instead.
- var/obj/item/I = get_active_held_item()
- if(I && dropItemToGround(I))
- playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
- visible_message("[M] disarmed [src]!", \
- "[M] disarmed [src]!")
+ if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stun instead.
+ var/obj/item/I = get_active_held_item()
+ if(I && dropItemToGround(I))
+ playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
+ visible_message("[M] disarmed [src]!", \
+ "[M] disarmed [src]!")
+ else
+ playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
+ if(!lying) //CITADEL EDIT
+ Knockdown(100, TRUE, FALSE, 30, 25)
else
- playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
- if(!lying) //CITADEL EDIT
- Knockdown(100, TRUE, FALSE, 30, 25)
- else
- Knockdown(100)
- log_combat(M, src, "tackled")
- visible_message("[M] has tackled down [src]!", \
- "[M] has tackled down [src]!")
-
+ Knockdown(100)
+ log_combat(M, src, "tackled")
+ visible_message("[M] has tackled down [src]!", \
+ "[M] has tackled down [src]!")
/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L)
-
- if(..()) //successful larva bite.
- var/damage = rand(1, 3)
- if(check_shields(L, damage, "the [L.name]"))
- return 0
- if(stat != DEAD)
- L.amount_grown = min(L.amount_grown + damage, L.max_grown)
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
- if(!affecting)
- affecting = get_bodypart(BODY_ZONE_CHEST)
- var/armor_block = run_armor_check(affecting, "melee")
- apply_damage(damage, BRUTE, affecting, armor_block)
+ . = ..()
+ if(!.) //unsuccessful larva bite.
+ return
+ var/damage = rand(1, 3)
+ if(stat != DEAD)
+ L.amount_grown = min(L.amount_grown + damage, L.max_grown)
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
+ if(!affecting)
+ affecting = get_bodypart(BODY_ZONE_CHEST)
+ var/armor_block = run_armor_check(affecting, "melee")
+ apply_damage(damage, BRUTE, affecting, armor_block)
/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
. = ..()
if(.)
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- if(check_shields(M, damage, "the [M.name]", MELEE_ATTACK, M.armour_penetration))
- return FALSE
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
if(!dam_zone) //Dismemberment successful
return TRUE
@@ -332,23 +261,22 @@
/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime attack
- var/damage = rand(5, 25)
- if(M.is_adult)
- damage = rand(10, 35)
+ . = ..()
+ if(!.) //unsuccessful slime attack
+ return
+ var/damage = rand(5, 25)
+ if(M.is_adult)
+ damage = rand(10, 35)
- if(check_shields(M, damage, "the [M.name]"))
- return 0
+ var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
+ if(!dam_zone) //Dismemberment successful
+ return 1
- var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
- if(!dam_zone) //Dismemberment successful
- return 1
-
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
- if(!affecting)
- affecting = get_bodypart(BODY_ZONE_CHEST)
- var/armor_block = run_armor_check(affecting, "melee")
- apply_damage(damage, BRUTE, affecting, armor_block)
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+ if(!affecting)
+ affecting = get_bodypart(BODY_ZONE_CHEST)
+ var/armor_block = run_armor_check(affecting, "melee")
+ apply_damage(damage, BRUTE, affecting, armor_block)
/mob/living/carbon/human/mech_melee_attack(obj/mecha/M)
if(M.occupant.a_intent == INTENT_HARM)
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 6f574bdc12..2e069297b3 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -545,6 +545,20 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//Underwear, Undershirts & Socks
if(!(NO_UNDERWEAR in species_traits))
+
+ if(H.socks && H.get_num_legs(FALSE) >= 2)
+ if(H.hidden_socks)
+ H.socks = "Nude"
+ else
+ H.socks = H.saved_socks
+ var/datum/sprite_accessory/underwear/socks/S = GLOB.socks_list[H.socks]
+ if(S)
+ var/digilegs = ((DIGITIGRADE in species_traits) && S.has_digitigrade) ? "_d" : ""
+ var/mutable_appearance/MA = mutable_appearance(S.icon, "[S.icon_state][digilegs]", -BODY_LAYER)
+ if(S.has_color)
+ MA.color = "#[H.socks_color]"
+ standing += MA
+
if(H.underwear)
if(H.hidden_underwear)
H.underwear = "Nude"
@@ -552,8 +566,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.underwear = H.saved_underwear
var/datum/sprite_accessory/underwear/bottom/B = GLOB.underwear_list[H.underwear]
if(B)
- var/mutable_appearance/MA = mutable_appearance(B.icon, B.icon_state, -BODY_LAYER)
- if(UNDIE_COLORABLE(B))
+ var/digilegs = ((DIGITIGRADE in species_traits) && B.has_digitigrade) ? "_d" : ""
+ var/mutable_appearance/MA = mutable_appearance(B.icon, "[B.icon_state][digilegs]", -BODY_LAYER)
+ if(B.has_color)
MA.color = "#[H.undie_color]"
standing += MA
@@ -564,28 +579,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.undershirt = H.saved_undershirt
var/datum/sprite_accessory/underwear/top/T = GLOB.undershirt_list[H.undershirt]
if(T)
+ var/state = "[T.icon_state][((DIGITIGRADE in species_traits) && T.has_digitigrade) ? "_d" : ""]"
var/mutable_appearance/MA
if(H.dna.species.sexes && H.gender == FEMALE)
- MA = wear_female_version(T.icon_state, T.icon, BODY_LAYER)
+ MA = wear_female_version(state, T.icon, BODY_LAYER)
else
- MA = mutable_appearance(T.icon, T.icon_state, -BODY_LAYER)
- if(UNDIE_COLORABLE(T))
+ MA = mutable_appearance(T.icon, state, -BODY_LAYER)
+ if(T.has_color)
MA.color = "#[H.shirt_color]"
standing += MA
- if(H.socks && H.get_num_legs(FALSE) >= 2)
- if(H.hidden_socks)
- H.socks = "Nude"
- else
- H.socks = H.saved_socks
- var/datum/sprite_accessory/underwear/socks/S = GLOB.socks_list[H.socks]
- if(S)
- var/digilegs = (DIGITIGRADE in species_traits) ? "_d" : ""
- var/mutable_appearance/MA = mutable_appearance(S.icon, "[S.icon_state][digilegs]", -BODY_LAYER)
- if(UNDIE_COLORABLE(S))
- MA.color = "#[H.socks_color]"
- standing += MA
-
if(standing.len)
H.overlays_standing[BODY_LAYER] = standing
@@ -1682,11 +1685,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
attacker_style = M.mind.martial_art
if(attacker_style?.pacifism_check && HAS_TRAIT(M, TRAIT_PACIFISM)) // most martial arts are quite harmful, alas.
attacker_style = null
- if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
- log_combat(M, H, "attempted to touch")
- H.visible_message("[M] attempted to touch [H]!")
- return 0
- SEND_SIGNAL(M, COMSIG_MOB_ATTACK_HAND, M, H, attacker_style)
switch(M.a_intent)
if("help")
help(M, H, attacker_style)
diff --git a/code/modules/mob/living/carbon/monkey/combat.dm b/code/modules/mob/living/carbon/monkey/combat.dm
index 92ad87f6b5..56ef4fe24a 100644
--- a/code/modules/mob/living/carbon/monkey/combat.dm
+++ b/code/modules/mob/living/carbon/monkey/combat.dm
@@ -369,6 +369,23 @@
retaliate(L)
return ..()
+/mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if(M.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
+ retaliate(M)
+ else if(M.a_intent == INTENT_DISARM && prob(MONKEY_RETALIATE_DISARM_PROB))
+ retaliate(M)
+ return ..()
+
+/mob/living/carbon/monkey/attack_larva(mob/living/carbon/alien/larva/L)
+ if(L.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
+ retaliate(L)
+ return ..()
+
+/mob/living/carbon/monkey/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
+ if(user.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
+ retaliate(user)
+ return ..()
+
/mob/living/carbon/monkey/attack_paw(mob/living/L)
if(L.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
retaliate(L)
diff --git a/code/modules/mob/living/carbon/monkey/monkey_defense.dm b/code/modules/mob/living/carbon/monkey/monkey_defense.dm
index df90dd56fd..32e3d21ee2 100644
--- a/code/modules/mob/living/carbon/monkey/monkey_defense.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey_defense.dm
@@ -6,37 +6,55 @@
..()
/mob/living/carbon/monkey/attack_paw(mob/living/M)
- if(..()) //successful monkey bite.
- var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
- if(!affecting)
- affecting = get_bodypart(BODY_ZONE_CHEST)
- if(M.limb_destroyer)
- dismembering_strike(M, affecting.body_zone)
- if(stat != DEAD)
- var/dmg = rand(1, 5)
- apply_damage(dmg, BRUTE, affecting)
+ . = ..()
+ if(!.) //unsuccessful monkey bite.
+ return
+ var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+ if(!affecting)
+ affecting = get_bodypart(BODY_ZONE_CHEST)
+ if(M.limb_destroyer)
+ dismembering_strike(M, affecting.body_zone)
+ var/dmg = rand(1, 5)
+ apply_damage(dmg, BRUTE, affecting)
/mob/living/carbon/monkey/attack_larva(mob/living/carbon/alien/larva/L)
- if(..()) //successful larva bite.
- var/damage = rand(1, 3)
- if(stat != DEAD)
- L.amount_grown = min(L.amount_grown + damage, L.max_grown)
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
- if(!affecting)
- affecting = get_bodypart(BODY_ZONE_CHEST)
- apply_damage(damage, BRUTE, affecting)
+ . = ..()
+ if(!.) //unsuccessful larva bite
+ return
+ var/damage = rand(1, 3)
+ if(stat != DEAD)
+ L.amount_grown = min(L.amount_grown + damage, L.max_grown)
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
+ if(!affecting)
+ affecting = get_bodypart(BODY_ZONE_CHEST)
+ apply_damage(damage, BRUTE, affecting)
+
+/mob/living/carbon/monkey/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
+ . = ..(user, TRUE)
+ if(.)
+ return
+ var/hulk_verb = pick("smash","pummel")
+ playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
+ var/message = "[user] has [hulk_verb]ed [src]!"
+ visible_message("[message]", \
+ "[message]")
+ adjustBruteLoss(15)
+ return TRUE
/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M)
- if(..()) //To allow surgery to return properly.
+ . = ..()
+ if(.) //To allow surgery to return properly.
return
-
switch(M.a_intent)
- if("help")
+ if(INTENT_HELP)
help_shake_act(M)
- if("grab")
+ if(INTENT_GRAB)
grabbedby(M)
- if("harm")
+ if(INTENT_HARM)
+ if(HAS_TRAIT(M, TRAIT_PACIFISM))
+ to_chat(M, "You don't want to hurt [src]!")
+ return
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
if (prob(75))
visible_message("[M] has punched [name]!", \
@@ -60,7 +78,7 @@
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("[M] has attempted to punch [name]!", \
"[M] has attempted to punch [name]!", null, COMBAT_MESSAGE_RANGE)
- if("disarm")
+ if(INTENT_DISARM)
if(!IsUnconscious())
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
if (prob(25))
@@ -74,50 +92,51 @@
visible_message("[M] has disarmed [src]!", "[M] has disarmed [src]!", null, COMBAT_MESSAGE_RANGE)
/mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(..()) //if harm or disarm intent.
- if (M.a_intent == INTENT_HARM)
- if ((prob(95) && health > 0))
- playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- var/damage = rand(15, 30)
- if (damage >= 25)
- damage = rand(20, 40)
- if(AmountUnconscious() < 300)
- Unconscious(rand(200, 300))
- visible_message("[M] has wounded [name]!", \
- "[M] has wounded [name]!", null, COMBAT_MESSAGE_RANGE)
- else
- visible_message("[M] has slashed [name]!", \
- "[M] has slashed [name]!", null, COMBAT_MESSAGE_RANGE)
-
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
- log_combat(M, src, "attacked")
- if(!affecting)
- affecting = get_bodypart(BODY_ZONE_CHEST)
- if(!dismembering_strike(M, affecting.body_zone)) //Dismemberment successful
- return 1
- apply_damage(damage, BRUTE, affecting)
-
+ . = ..()
+ if(!.) // the attack was blocked or was help/grab intent
+ return
+ if (M.a_intent == INTENT_HARM)
+ if ((prob(95) && health > 0))
+ playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
+ var/damage = rand(15, 30)
+ if (damage >= 25)
+ damage = rand(20, 40)
+ if(AmountUnconscious() < 300)
+ Unconscious(rand(200, 300))
+ visible_message("[M] has wounded [name]!", \
+ "[M] has wounded [name]!", null, COMBAT_MESSAGE_RANGE)
else
- playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to lunge at [name]!", \
- "[M] has attempted to lunge at [name]!", null, COMBAT_MESSAGE_RANGE)
+ visible_message("[M] has slashed [name]!", \
+ "[M] has slashed [name]!", null, COMBAT_MESSAGE_RANGE)
- if (M.a_intent == INTENT_DISARM)
- var/obj/item/I = null
- playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
- if(prob(95))
- Knockdown(20)
- visible_message("[M] has tackled down [name]!", \
- "[M] has tackled down [name]!", null, COMBAT_MESSAGE_RANGE)
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ log_combat(M, src, "attacked")
+ if(!affecting)
+ affecting = get_bodypart(BODY_ZONE_CHEST)
+ if(!dismembering_strike(M, affecting.body_zone)) //Dismemberment successful
+ return 1
+ apply_damage(damage, BRUTE, affecting)
+
+ else
+ playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
+ visible_message("[M] has attempted to lunge at [name]!", \
+ "[M] has attempted to lunge at [name]!", null, COMBAT_MESSAGE_RANGE)
+
+ else
+ var/obj/item/I = null
+ playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
+ if(prob(95))
+ Knockdown(20)
+ visible_message("[M] has tackled down [name]!", \
+ "[M] has tackled down [name]!", null, COMBAT_MESSAGE_RANGE)
+ else
+ I = get_active_held_item()
+ if(dropItemToGround(I))
+ visible_message("[M] has disarmed [name]!", "[M] has disarmed [name]!", null, COMBAT_MESSAGE_RANGE)
else
- I = get_active_held_item()
- if(dropItemToGround(I))
- visible_message("[M] has disarmed [name]!", "[M] has disarmed [name]!", null, COMBAT_MESSAGE_RANGE)
- else
- I = null
- log_combat(M, src, "disarmed", "[I ? " removing \the [I]" : ""]")
- updatehealth()
-
+ I = null
+ log_combat(M, src, "disarmed", "[I ? " removing \the [I]" : ""]")
+ updatehealth()
/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M)
. = ..()
@@ -132,17 +151,19 @@
apply_damage(damage, M.melee_damage_type, affecting)
/mob/living/carbon/monkey/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime attack
- var/damage = rand(5, 35)
- if(M.is_adult)
- damage = rand(20, 40)
- var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
- if(!dam_zone) //Dismemberment successful
- return 1
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
- if(!affecting)
- affecting = get_bodypart(BODY_ZONE_CHEST)
- apply_damage(damage, BRUTE, affecting)
+ . = ..()
+ if(!.) //unsuccessful slime attack
+ return
+ var/damage = rand(5, 35)
+ if(M.is_adult)
+ damage = rand(20, 40)
+ var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
+ if(!dam_zone) //Dismemberment successful
+ return 1
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+ if(!affecting)
+ affecting = get_bodypart(BODY_ZONE_CHEST)
+ apply_damage(damage, BRUTE, affecting)
/mob/living/carbon/monkey/acid_act(acidpwr, acid_volume, bodyzone_hit)
. = 1
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 722c984309..3c5c5e3518 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -36,7 +36,50 @@
/mob/living/proc/on_hit(obj/item/projectile/P)
return
+/mob/living/proc/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
+ var/block_chance_modifier = round(damage / -3)
+ for(var/obj/item/I in held_items)
+ if(!istype(I, /obj/item/clothing))
+ var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
+ if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
+ return TRUE
+ return FALSE
+
+/mob/living/proc/check_reflect(def_zone) //Reflection checks for anything in your hands, based on the reflection chance of the object(s)
+ for(var/obj/item/I in held_items)
+ if(I.IsReflect(def_zone))
+ return TRUE
+ return FALSE
+
+/mob/living/proc/reflect_bullet_check(obj/item/projectile/P, def_zone)
+ if(P.is_reflectable && check_reflect(def_zone)) // Checks if you've passed a reflection% check
+ visible_message("The [P.name] gets reflected by [src]!", \
+ "The [P.name] gets reflected by [src]!")
+ // Find a turf near or on the original location to bounce to
+ if(P.starting)
+ var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
+ var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
+ var/turf/curloc = get_turf(src)
+ // redirect the projectile
+ P.original = locate(new_x, new_y, P.z)
+ P.starting = curloc
+ P.firer = src
+ P.yo = new_y - curloc.y
+ P.xo = new_x - curloc.x
+ var/new_angle_s = P.Angle + rand(120,240)
+ while(new_angle_s > 180) // Translate to regular projectile degrees
+ new_angle_s -= 360
+ P.setAngle(new_angle_s)
+ return TRUE
+ return FALSE
+
/mob/living/bullet_act(obj/item/projectile/P, def_zone)
+ if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself
+ if(reflect_bullet_check(P, def_zone))
+ return -1 // complete projectile permutation
+ if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
+ P.on_hit(src, 100, def_zone)
+ return 2
var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null)
if(!P.nodamage)
apply_damage(P.damage, P.damage_type, def_zone, armor)
@@ -55,9 +98,32 @@
else
return 0
+/mob/living/proc/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
+ return FALSE
+
+/mob/living/proc/embed_item(obj/item/I)
+ return
+
+/mob/living/proc/can_embed(obj/item/I)
+ return FALSE
+
/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE)
- if(istype(AM, /obj/item))
- var/obj/item/I = AM
+ var/obj/item/I
+ var/throwpower = 30
+ if(isitem(AM))
+ I = AM
+ throwpower = I.throwforce
+ if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
+ hitpush = FALSE
+ skipcatch = TRUE
+ blocked = TRUE
+ else if(I && I.throw_speed >= EMBED_THROWSPEED_THRESHOLD && can_embed(I, src) && prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE) && (!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) || incapacitated() || get_active_held_item()))
+ embed_item(I)
+ hitpush = FALSE
+ skipcatch = TRUE //can't catch the now embedded item
+ if(I)
+ if(!skipcatch && isturf(I.loc) && catch_item(I))
+ return TRUE
var/zone = ran_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest
var/dtype = BRUTE
var/volume = I.get_volume_by_throwforce_and_or_w_class()
@@ -214,6 +280,24 @@
Move(user.loc)
return 1
+/mob/living/attack_hand(mob/user)
+ ..() //Ignoring parent return value here.
+ SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
+ if((user != src) && user.a_intent != INTENT_HELP && check_shields(user, 0, user.name, attack_type = UNARMED_ATTACK))
+ log_combat(user, src, "attempted to touch")
+ visible_message("[user] attempted to touch [src]!")
+ return TRUE
+
+/mob/living/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
+ if(user.a_intent == INTENT_HARM)
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ to_chat(user, "You don't want to hurt [src]!")
+ return TRUE
+ var/hulk_verb = pick("smash","pummel")
+ if(user != src && check_shields(user, 15, "the [hulk_verb]ing"))
+ return TRUE
+ ..()
+ return FALSE
/mob/living/attack_slime(mob/living/simple_animal/slime/M)
if(!SSticker.HasRoundStarted())
@@ -229,6 +313,12 @@
to_chat(M, "You don't want to hurt anyone!")
return FALSE
+ var/damage = rand(5, 35)
+ if(M.is_adult)
+ damage = rand(20, 40)
+ if(check_shields(M, damage, "the [M.name]"))
+ return FALSE
+
if (stat != DEAD)
log_combat(M, src, "attacked")
M.do_attack_animation(src)
@@ -245,7 +335,8 @@
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "You don't want to hurt anyone!")
return FALSE
-
+ if(check_shields(M, rand(M.melee_damage_lower, M.melee_damage_upper), "the [M.name]", MELEE_ATTACK, M.armour_penetration))
+ return FALSE
if(M.attack_sound)
playsound(loc, M.attack_sound, 50, 1, 1)
M.do_attack_animation(src)
@@ -256,10 +347,6 @@
/mob/living/attack_paw(mob/living/carbon/monkey/M)
- if(isturf(loc) && istype(loc.loc, /area/start))
- to_chat(M, "No attacking people at spawn, you jackass.")
- return FALSE
-
if (M.a_intent == INTENT_HARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "You don't want to hurt anyone!")
@@ -268,6 +355,8 @@
if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
to_chat(M, "You can't bite with your mouth covered!")
return FALSE
+ if(check_shields(M, 0, "the [M.name]"))
+ return FALSE
M.do_attack_animation(src, ATTACK_EFFECT_BITE)
if (prob(75))
log_combat(M, src, "attacked")
@@ -282,15 +371,16 @@
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
switch(L.a_intent)
- if("help")
+ if(INTENT_HELP)
visible_message("[L.name] rubs its head against [src].")
return FALSE
else
if(HAS_TRAIT(L, TRAIT_PACIFISM))
to_chat(L, "You don't want to hurt anyone!")
- return
-
+ return FALSE
+ if(L != src && check_shields(L, rand(1, 3), "the [L.name]"))
+ return FALSE
L.do_attack_animation(src)
if(prob(90))
log_combat(L, src, "attacked")
@@ -301,24 +391,29 @@
else
visible_message("[L.name] has attempted to bite [src]!", \
"[L.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
- return FALSE
/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if((M != src) && M.a_intent != INTENT_HELP && check_shields(M, 0, "the [M.name]"))
+ visible_message("[M] attempted to touch [src]!")
+ return FALSE
switch(M.a_intent)
- if ("help")
- visible_message("[M] caresses [src] with its scythe like arm.")
+ if (INTENT_HELP)
+ if(!isalien(src)) //I know it's ugly, but the alien vs alien attack_alien behaviour is a bit different.
+ visible_message("[M] caresses [src] with its scythe like arm.")
return FALSE
- if ("grab")
+ if (INTENT_GRAB)
grabbedby(M)
return FALSE
- if("harm")
+ if(INTENT_HARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "You don't want to hurt anyone!")
return FALSE
- M.do_attack_animation(src)
+ if(!isalien(src))
+ M.do_attack_animation(src)
return TRUE
- if("disarm")
- M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
+ if(INTENT_DISARM)
+ if(!isalien(src))
+ M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
return TRUE
/mob/living/ex_act(severity, target, origin)
diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm
index 7c59c2b791..97d26f672a 100644
--- a/code/modules/mob/living/silicon/ai/ai_defense.dm
+++ b/code/modules/mob/living/silicon/ai/ai_defense.dm
@@ -1,15 +1,9 @@
-
/mob/living/silicon/ai/attacked_by(obj/item/I, mob/living/user, def_zone)
+ . = ..()
+ if(!.)
+ return FALSE
if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt.
spark_system.start()
- return ..()
-
-
-/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(!SSticker.HasRoundStarted())
- to_chat(M, "You cannot attack people before the game has started.")
- return
- ..()
/mob/living/silicon/ai/attack_slime(mob/living/simple_animal/slime/user)
return //immune to slimes
diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm
index dfc718f1ab..5ac841326b 100644
--- a/code/modules/mob/living/silicon/pai/pai_defense.dm
+++ b/code/modules/mob/living/silicon/pai/pai_defense.dm
@@ -26,13 +26,14 @@
fold_in(force = 1)
Knockdown(200)
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/silicon/pai/attack_hand(mob/living/carbon/human/user)
switch(user.a_intent)
- if("help")
+ if(INTENT_HELP)
visible_message("[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.")
- if("disarm")
+ if(INTENT_DISARM)
visible_message("[user] boops [src] on the head!")
- if("harm")
+ if(INTENT_HARM)
user.do_attack_animation(src)
if (user.name == master)
visible_message("Responding to its master's touch, [src] disengages its holochassis emitter, rapidly losing coherence.")
@@ -41,14 +42,19 @@
if(user.put_in_hands(card))
user.visible_message("[user] promptly scoops up [user.p_their()] pAI's card.")
else
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ to_chat(user, "You don't want to hurt [src]!")
+ return
visible_message("[user] stomps on [src]!.")
take_holo_damage(2)
+ else
+ grabbedby(user)
-/mob/living/silicon/pai/bullet_act(obj/item/projectile/Proj)
- if(Proj.stun)
+/mob/living/silicon/pai/bullet_act(obj/item/projectile/P, def_zone)
+ if(P.stun)
fold_in(force = TRUE)
- src.visible_message("The electrically-charged projectile disrupts [src]'s holomatrix, forcing [src] to fold in!")
- . = ..(Proj)
+ visible_message("The electrically-charged projectile disrupts [src]'s holomatrix, forcing [src] to fold in!")
+ . = ..()
/mob/living/silicon/pai/stripPanelUnequip(obj/item/what, mob/who, where) //prevents stripping
to_chat(src, "Your holochassis stutters and warps intensely as you attempt to interact with the object, forcing you to cease lest the field fail.")
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 0f09b6f62a..7e06c66eff 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -13,7 +13,19 @@
spark_system.start()
return ..()
+/mob/living/silicon/robot/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
+ . = ..()
+ if(.)
+ spark_system.start()
+ spawn(0)
+ step_away(src,user,15)
+ sleep(3)
+ step_away(src,user,15)
+
/mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/humanoid/M)
+ . = ..()
+ if(!.) // the attack was blocked or was help/grab intent
+ return
if (M.a_intent == INTENT_DISARM)
if(!(lying))
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
@@ -30,24 +42,19 @@
visible_message("[M] has forced back [src]!", \
"[M] has forced back [src]!", null, COMBAT_MESSAGE_RANGE)
playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1)
- else
- ..()
- return
/mob/living/silicon/robot/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime shock
- flash_act()
- var/stunprob = M.powerlevel * 7 + 10
- if(prob(stunprob) && M.powerlevel >= 8)
- adjustBruteLoss(M.powerlevel * rand(6,10))
-
- var/damage = rand(1, 3)
-
+ . = ..()
+ if(!.) //unsuccessful slime shock
+ return
+ var/stunprob = M.powerlevel * 7 + 10
+ var/damage = M.powerlevel * rand(6,10)
+ if(prob(stunprob) && M.powerlevel >= 8)
+ flash_act(affect_silicon = TRUE) //my borg eyes!
if(M.is_adult)
- damage = rand(20, 40)
+ damage += rand(10, 20)
else
- damage = rand(5, 35)
- damage = round(damage / 2) // borgs receive half damage
+ damage += rand(2, 17)
adjustBruteLoss(damage)
updatehealth()
@@ -56,23 +63,17 @@
//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user)
add_fingerprint(user)
- if(opened && !wiresexposed && !issilicon(user))
- if(cell)
- cell.update_icon()
- cell.add_fingerprint(user)
- user.put_in_active_hand(cell)
- to_chat(user, "You remove \the [cell].")
- cell = null
- update_icons()
- diag_hud_set_borgcell()
+ if(opened && !wiresexposed && cell && !issilicon(user))
+ cell.update_icon()
+ cell.add_fingerprint(user)
+ user.put_in_active_hand(cell)
+ to_chat(user, "You remove \the [cell].")
+ cell = null
+ update_icons()
+ diag_hud_set_borgcell()
if(!opened)
- if(..()) // hulk attack
- spark_system.start()
- spawn(0)
- step_away(src,user,15)
- sleep(3)
- step_away(src,user,15)
+ return ..()
/mob/living/silicon/robot/fire_act()
if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
@@ -182,9 +183,9 @@
if (stat != DEAD)
adjustBruteLoss(30)
-/mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj)
- ..(Proj)
+/mob/living/silicon/robot/bullet_act(obj/item/projectile/P, def_zone)
+ ..()
updatehealth()
- if(prob(75) && Proj.damage > 0)
+ if(prob(75) && P.damage > 0)
spark_system.start()
return 2
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index 073a2eec2b..ca8ad25713 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -6,7 +6,10 @@
return 2
/mob/living/silicon/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(..()) //if harm or disarm intent
+ . = ..()
+ if(!.) // the attack was blocked or was help/grab intent
+ return
+ if(M.a_intent == INTENT_HARM)
var/damage = 20
if (prob(90))
log_combat(M, src, "attacked")
@@ -49,34 +52,33 @@
/mob/living/silicon/attack_paw(mob/living/user)
return attack_hand(user)
-/mob/living/silicon/attack_larva(mob/living/carbon/alien/larva/L)
- if(L.a_intent == INTENT_HELP)
- visible_message("[L.name] rubs its head against [src].")
-
-/mob/living/silicon/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
+/mob/living/silicon/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
- ..(user, 1)
+ . = ..(user, TRUE)
+ if(.)
+ return
adjustBruteLoss(rand(10, 15))
playsound(loc, "punch", 25, 1, -1)
visible_message("[user] has punched [src]!", \
"[user] has punched [src]!")
- return 1
- return 0
+ return TRUE
+ return FALSE
-//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/silicon/attack_hand(mob/living/carbon/human/M)
+ . = ..()
+ if(.) //the attack was blocked
+ return
switch(M.a_intent)
- if ("help")
+ if (INTENT_HELP)
M.visible_message("[M] pets [src].", \
"You pet [src].")
- if("grab")
+ if(INTENT_GRAB)
grabbedby(M)
else
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
playsound(src.loc, 'sound/effects/bang.ogg', 10, 1)
visible_message("[M] punches [src], but doesn't leave a dent.", \
"[M] punches [src], but doesn't leave a dent.", null, COMBAT_MESSAGE_RANGE)
- return 0
/mob/living/silicon/attack_drone(mob/living/simple_animal/drone/M)
if(M.a_intent == INTENT_HARM)
@@ -108,19 +110,25 @@
M.visible_message("[M] is thrown off of [src]!")
flash_act(affect_silicon = 1)
-/mob/living/silicon/bullet_act(obj/item/projectile/Proj)
- if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
- adjustBruteLoss(Proj.damage)
- if(prob(Proj.damage*1.5))
+/mob/living/silicon/bullet_act(obj/item/projectile/P, def_zone)
+ if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself
+ if(reflect_bullet_check(P, def_zone))
+ return -1 // complete projectile permutation
+ if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
+ P.on_hit(src, 100, def_zone)
+ return 2
+ if((P.damage_type == BRUTE || P.damage_type == BURN))
+ adjustBruteLoss(P.damage)
+ if(prob(P.damage*1.5))
for(var/mob/living/M in buckled_mobs)
M.visible_message("[M] is knocked off of [src]!")
unbuckle_mob(M)
M.Knockdown(40)
- if(Proj.stun || Proj.knockdown)
+ if(P.stun || P.knockdown)
for(var/mob/living/M in buckled_mobs)
unbuckle_mob(M)
- M.visible_message("[M] is knocked off of [src] by the [Proj]!")
- Proj.on_hit(src)
+ M.visible_message("[M] is knocked off of [src] by the [P]!")
+ P.on_hit(src)
return 2
/mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/static)
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index 793df63c87..0dfa126e79 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -1,20 +1,22 @@
/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M)
- ..()
+ . = ..()
+ if(.) //the attack was blocked
+ return
switch(M.a_intent)
- if("help")
+ if(INTENT_HELP)
if (health > 0)
visible_message("[M] [response_help] [src].")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- if("grab")
+ if(INTENT_GRAB)
if(grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
vore_attack(M, pulling)
else
grabbedby(M)
- if("harm", "disarm")
+ if(INTENT_HARM, INTENT_DISARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "You don't want to hurt [src]!")
return
@@ -27,12 +29,11 @@
updatehealth()
return TRUE
-/mob/living/simple_animal/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
+/mob/living/simple_animal/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
- if(HAS_TRAIT(user, TRAIT_PACIFISM))
- to_chat(user, "You don't want to hurt [src]!")
- return FALSE
- ..(user, 1)
+ . = ..(user, TRUE)
+ if(.)
+ return
playsound(loc, "punch", 25, 1, -1)
visible_message("[user] has punched [src]!", \
"[user] has punched [src]!", null, COMBAT_MESSAGE_RANGE)
@@ -40,32 +41,32 @@
return TRUE
/mob/living/simple_animal/attack_paw(mob/living/carbon/monkey/M)
- if(..()) //successful monkey bite.
- if(stat != DEAD)
- var/damage = rand(1, 3)
- attack_threshold_check(damage)
- return 1
+ . = ..()
+ if(.) //successful larva bite
+ var/damage = rand(1, 3)
+ attack_threshold_check(damage)
+ return 1
if (M.a_intent == INTENT_HELP)
if (health > 0)
visible_message("[M.name] [response_help] [src].")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(..()) //if harm or disarm intent.
- if(M.a_intent == INTENT_DISARM)
- playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
- visible_message("[M] [response_disarm] [name]!", \
- "[M] [response_disarm] [name]!", null, COMBAT_MESSAGE_RANGE)
- log_combat(M, src, "disarmed")
- else
- var/damage = rand(15, 30)
- visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!", null, COMBAT_MESSAGE_RANGE)
- playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- attack_threshold_check(damage)
- log_combat(M, src, "attacked")
- return 1
+ . = ..()
+ if(!.) // the attack was blocked or was help/grab intent
+ return
+ if(M.a_intent == INTENT_DISARM)
+ playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
+ visible_message("[M] [response_disarm] [name]!", \
+ "[M] [response_disarm] [name]!", null, COMBAT_MESSAGE_RANGE)
+ log_combat(M, src, "disarmed")
+ else
+ var/damage = rand(15, 30)
+ visible_message("[M] has slashed at [src]!", \
+ "[M] has slashed at [src]!", null, COMBAT_MESSAGE_RANGE)
+ playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
+ attack_threshold_check(damage)
+ log_combat(M, src, "attacked")
/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
. = ..()
@@ -82,7 +83,8 @@
return attack_threshold_check(damage, M.melee_damage_type)
/mob/living/simple_animal/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime attack
+ . = ..()
+ if(.) //successful slime shock
var/damage = rand(15, 25)
if(M.is_adult)
damage = rand(20, 35)
diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm
index 2de4ca39fd..109c7b4636 100644
--- a/code/modules/mob/living/simple_animal/bot/honkbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm
@@ -113,7 +113,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
mode = BOT_HUNT
/mob/living/simple_animal/bot/honkbot/attack_hand(mob/living/carbon/human/H)
- if(H.a_intent == "harm")
+ if(H.a_intent == INTENT_HARM)
retaliate(H)
addtimer(CALLBACK(src, .proc/react_buzz), 5)
return ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 02e171e4c4..bda309f7c7 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -232,9 +232,9 @@
/mob/living/simple_animal/pet/cat/attack_hand(mob/living/carbon/human/M)
. = ..()
switch(M.a_intent)
- if("help")
+ if(INTENT_HELP)
wuv(1, M)
- if("harm")
+ if(INTENT_HARM)
wuv(-1, M)
/mob/living/simple_animal/pet/cat/proc/wuv(change, mob/M)
@@ -290,7 +290,9 @@
D.decorate_donut()
/mob/living/simple_animal/pet/cat/cak/attack_hand(mob/living/L)
- ..()
+ . = ..()
+ if(.) //the attack was blocked
+ return
if(L.a_intent == INTENT_HARM && L.reagents && !stat)
L.reagents.add_reagent("nutriment", 0.4)
L.reagents.add_reagent("vitamin", 0.4)
diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index 0d933d171b..986e5c9b4d 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -643,9 +643,9 @@
/mob/living/simple_animal/pet/dog/attack_hand(mob/living/carbon/human/M)
. = ..()
switch(M.a_intent)
- if("help")
+ if(INTENT_HELP)
wuv(1,M)
- if("harm")
+ if(INTENT_HARM)
wuv(-1,M)
/mob/living/simple_animal/pet/dog/proc/wuv(change, mob/M)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index e40eb585e8..c9207fcf89 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -31,9 +31,9 @@
//picky up the drone c:
/mob/living/simple_animal/drone/attack_hand(mob/user)
- ..()
- if(user.a_intent == INTENT_HELP)
- mob_try_pickup(user)
+ if(user.a_intent != INTENT_HELP)
+ return ..() // TODO: convert picking up mobs into an element or component.
+ mob_try_pickup(user)
/mob/living/simple_animal/drone/proc/try_reactivate(mob/living/user)
var/mob/dead/observer/G = get_ghost()
diff --git a/code/modules/mob/living/simple_animal/guardian/types/charger.dm b/code/modules/mob/living/simple_animal/guardian/types/charger.dm
index 49514d0d12..914d38022f 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/charger.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/charger.dm
@@ -54,10 +54,8 @@
var/blocked = FALSE
if(hasmatchingsummoner(A)) //if the summoner matches don't hurt them
blocked = TRUE
- if(ishuman(A))
- var/mob/living/carbon/human/H = A
- if(H.check_shields(src, 90, "[name]", attack_type = THROWN_PROJECTILE_ATTACK))
- blocked = TRUE
+ if(L.check_shields(src, 90, "[name]", attack_type = THROWN_PROJECTILE_ATTACK))
+ blocked = TRUE
if(!blocked)
L.drop_all_held_items()
L.visible_message("[src] slams into [L]!", "[src] slams into you!")
diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
index 514edf896b..a5e3cd8120 100644
--- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
@@ -166,7 +166,9 @@
..()
/mob/living/simple_animal/hostile/mushroom/attack_hand(mob/living/carbon/human/M)
- ..()
+ . = ..()
+ if(.) // the attack was blocked
+ return
if(M.a_intent == INTENT_HARM)
Bruise()
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index d1e10ea693..439ea5b2bf 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -253,33 +253,34 @@
return
/mob/living/simple_animal/slime/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime attack
- if(M == src)
- return
- if(buckled)
- Feedstop(silent = TRUE)
- visible_message("[M] pulls [src] off!")
- return
- attacked += 5
- if(nutrition >= 100) //steal some nutrition. negval handled in life()
- nutrition -= (50 + (40 * M.is_adult))
- M.add_nutrition(50 + (40 * M.is_adult))
- if(health > 0)
- M.adjustBruteLoss(-10 + (-10 * M.is_adult))
- M.updatehealth()
+ . = ..()
+ if(!. || M == src) //unsuccessful slime shock
+ return
+ if(buckled)
+ Feedstop(silent = TRUE)
+ visible_message("[M] pulls [src] off!")
+ return
+ attacked += 5
+ if(nutrition >= 100) //steal some nutrition. negval handled in life()
+ nutrition -= (50 + (40 * M.is_adult))
+ M.add_nutrition(50 + (40 * M.is_adult))
+ if(health > 0)
+ M.adjustBruteLoss(-10 + (-10 * M.is_adult))
+ M.updatehealth()
/mob/living/simple_animal/slime/attack_animal(mob/living/simple_animal/M)
. = ..()
if(.)
attacked += 10
-
/mob/living/simple_animal/slime/attack_paw(mob/living/carbon/monkey/M)
- if(..()) //successful monkey bite.
+ . = ..()
+ if(.)//successful monkey bite.
attacked += 10
/mob/living/simple_animal/slime/attack_larva(mob/living/carbon/alien/larva/L)
- if(..()) //successful larva bite.
+ . = ..()
+ if(.) //successful larva bite.
attacked += 10
/mob/living/simple_animal/slime/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
@@ -321,9 +322,11 @@
attacked += 10
/mob/living/simple_animal/slime/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(..()) //if harm or disarm intent.
- attacked += 10
- discipline_slime(M)
+ . = ..()
+ if(!.) // the attack was blocked or was help/grab intent
+ return
+ attacked += 10
+ discipline_slime(M)
/mob/living/simple_animal/slime/attackby(obj/item/W, mob/living/user, params)
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm
index 8c304d8a2b..56c50078c1 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm
@@ -26,10 +26,9 @@ Contents:
/obj/item/clothing/suit/space/space_ninja/proc/enable_signals()
if(!affecting)
return
- RegisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE), .proc/reduce_stealth)
+ RegisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE), .proc/reduce_stealth)
RegisterSignal(affecting, COMSIG_MOVABLE_BUMP, .proc/bumping_stealth)
-
/obj/item/clothing/suit/space/space_ninja/proc/reduce_stealth(datum/source)
affecting.alpha = min(affecting.alpha + 40, 100)
@@ -42,7 +41,7 @@ Contents:
return FALSE
stealth = !stealth
stealth_cooldown = world.time + 5 SECONDS
- UnregisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE))
+ UnregisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE))
animate(affecting, alpha = 255, time = 3 SECONDS)
affecting.visible_message("[affecting.name] appears from thin air!", \
"You are now visible.")
diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm
index 2ca6ce2611..f3f7e45378 100644
--- a/code/modules/paperwork/paperplane.dm
+++ b/code/modules/paperwork/paperplane.dm
@@ -102,7 +102,7 @@
/obj/item/paperplane/throw_impact(atom/hit_atom)
if(iscarbon(hit_atom))
var/mob/living/carbon/C = hit_atom
- if(C.can_catch_item(TRUE))
+ if(!C.get_active_held_item() && !C.restrained())
var/datum/action/innate/origami/origami_action = locate() in C.actions
if(origami_action?.active) //if they're a master of origami and have the ability turned on, force throwmode on so they'll automatically catch the plane.
C.throw_mode_on()
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index 1ac62ba651..513626465a 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -260,7 +260,7 @@
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 50)
- var/name = stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN)
+ var/name = html_decode(stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/pill/P
@@ -287,7 +287,7 @@
adjust_item_drop_location(P)
reagents.trans_to(P,vol_each)
else
- var/name = stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN)
+ var/name = html_decode(stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
@@ -313,7 +313,7 @@
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 40)
- var/name = stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN)
+ var/name = html_decode(stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/pill/P
@@ -331,7 +331,7 @@
return
if(condi)
- var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN)
+ var/name = html_decode(stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/food/condiment/P = new(drop_location())
@@ -344,7 +344,7 @@
if(text2num(many))
amount_full = round(reagents.total_volume / 30)
vol_part = ((reagents.total_volume*1000) % 30000) / 1000 //% operator doesn't support decimals.
- var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN)
+ var/name = html_decode(stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
@@ -372,7 +372,7 @@
if(text2num(many))
amount_full = round(reagents.total_volume / 60)
vol_part = reagents.total_volume % 60
- var/name = stripped_input(usr, "Name:","Name your hypovial!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN)
+ var/name = html_decode(stripped_input(usr, "Name:","Name your hypovial!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
@@ -407,7 +407,7 @@
return
vol_each = min(reagents.total_volume / amount, 20)
- var/name = stripped_input(usr,"Name:","Name your SmartDart!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN)
+ var/name = html_decode(stripped_input(usr,"Name:","Name your SmartDart!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index 5d31bfae9b..e8551074e7 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -247,6 +247,23 @@
. = 1
..()
+/datum/reagent/consumable/coconutmilk
+ name = "Coconut Milk"
+ id = "coconutmilk"
+ description = "A transparent white liquid extracted from coconuts. Rich in taste."
+ color = "#DFDFDF" // rgb: 223, 223, 223
+ taste_description = "sweet milk"
+ quality = DRINK_GOOD
+ glass_icon_state = "glass_white"
+ glass_name = "glass of coconut milk"
+ glass_desc = "White and nutritious goodness!"
+
+/datum/reagent/consumable/coconutmilk/on_mob_life(mob/living/carbon/M)
+ if(M.getBruteLoss() && prob(20))
+ M.heal_bodypart_damage(2,0, 0)
+ . = 1
+ ..()
+
/datum/reagent/consumable/cream
name = "Cream"
id = "cream"
diff --git a/code/modules/vending/megaseed.dm b/code/modules/vending/megaseed.dm
index 5c092c3659..03241c4a86 100644
--- a/code/modules/vending/megaseed.dm
+++ b/code/modules/vending/megaseed.dm
@@ -14,6 +14,7 @@
/obj/item/seeds/chanter = 3,
/obj/item/seeds/chili = 3,
/obj/item/seeds/cocoapod = 3,
+ /obj/item/seeds/coconut = 3,
/obj/item/seeds/coffee = 3,
/obj/item/seeds/cotton = 3,
/obj/item/seeds/corn = 3,
diff --git a/html/changelogs/AutoChangeLog-pr-10123.yml b/html/changelogs/AutoChangeLog-pr-10123.yml
new file mode 100644
index 0000000000..208b17b930
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10123.yml
@@ -0,0 +1,4 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - rscadd: "throwing things no longer makes them randomly turned as long as you aren't on harm intent"
diff --git a/html/changelogs/AutoChangeLog-pr-10165.yml b/html/changelogs/AutoChangeLog-pr-10165.yml
new file mode 100644
index 0000000000..be6f9dedf7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10165.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixed missing digi versions fishnet sprites and wrong digitigrade left dir purple stockings sprite."
+ - imageadd: "Add digitigrade versions for boxers and the long johns."
diff --git a/html/changelogs/AutoChangeLog-pr-10309.yml b/html/changelogs/AutoChangeLog-pr-10309.yml
new file mode 100644
index 0000000000..a59ebff156
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10309.yml
@@ -0,0 +1,4 @@
+author: "Seris02"
+delete-after: True
+changes:
+ - rscadd: "disabler sechuds"
diff --git a/html/changelogs/AutoChangeLog-pr-10319.yml b/html/changelogs/AutoChangeLog-pr-10319.yml
new file mode 100644
index 0000000000..88235aab8e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10319.yml
@@ -0,0 +1,5 @@
+author: "Seris02"
+delete-after: True
+changes:
+ - rscadd: "adds coconut"
+ - rscadd: "adds a coconut bong"
diff --git a/html/changelogs/AutoChangeLog-pr-10338.yml b/html/changelogs/AutoChangeLog-pr-10338.yml
new file mode 100644
index 0000000000..c4816a3fbe
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10338.yml
@@ -0,0 +1,4 @@
+author: "Seris02"
+delete-after: True
+changes:
+ - rscadd: "marshmallow"
diff --git a/html/changelogs/AutoChangeLog-pr-10344.yml b/html/changelogs/AutoChangeLog-pr-10344.yml
new file mode 100644
index 0000000000..e0381c6a43
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10344.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Chestbursters won't delete the host's brain somewhat anymore."
diff --git a/html/changelogs/AutoChangeLog-pr-10345.yml b/html/changelogs/AutoChangeLog-pr-10345.yml
new file mode 100644
index 0000000000..a95653cdda
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10345.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - tweak: "allows bandoliers to hold any ammo type as long as it has a casing"
diff --git a/html/changelogs/AutoChangeLog-pr-10349.yml b/html/changelogs/AutoChangeLog-pr-10349.yml
new file mode 100644
index 0000000000..fad3179c6e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10349.yml
@@ -0,0 +1,6 @@
+author: "KathrinBailey"
+delete-after: True
+changes:
+ - rscadd: "Empty engineering lockers for mappers."
+ - rscadd: "Industrial welding tools to the engineer welding locker."
+ - rscdel: "Removed the multitool, airlock painter, mechanical toolbox, brown sneakers, hazard vest and airlock painter from the CE's locker."
diff --git a/html/changelogs/AutoChangeLog-pr-10362.yml b/html/changelogs/AutoChangeLog-pr-10362.yml
new file mode 100644
index 0000000000..f92e16302a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10362.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "rouge cases of #$39; in bottle/pill/patch/condiments"
diff --git a/html/changelogs/AutoChangeLog-pr-10364.yml b/html/changelogs/AutoChangeLog-pr-10364.yml
new file mode 100644
index 0000000000..8834c494ad
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10364.yml
@@ -0,0 +1,4 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - bugfix: "telescopic iv drips now have the proper sanity checks for deployment."
diff --git a/html/changelogs/AutoChangeLog-pr-10365.yml b/html/changelogs/AutoChangeLog-pr-10365.yml
new file mode 100644
index 0000000000..f7ba047fc7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10365.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - bugfix: "no ass slap is no longer the same thing as no aphro"
diff --git a/html/changelogs/AutoChangeLog-pr-9856.yml b/html/changelogs/AutoChangeLog-pr-9856.yml
new file mode 100644
index 0000000000..697c1c78f5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9856.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "Refactored code to allow all living mobs to use shields and not only humans."
+ - tweak: "Monkys will now retaliate against aliens attacking them (as if they even posed a threat to start with)."
diff --git a/icons/mob/underwear.dmi b/icons/mob/underwear.dmi
index bf0df371eb..e0789a1eeb 100644
Binary files a/icons/mob/underwear.dmi and b/icons/mob/underwear.dmi differ
diff --git a/icons/mob/underwear_old.dmi b/icons/mob/underwear_old.dmi
deleted file mode 100644
index 5e16a473ba..0000000000
Binary files a/icons/mob/underwear_old.dmi and /dev/null differ
diff --git a/icons/obj/bongs.dmi b/icons/obj/bongs.dmi
new file mode 100644
index 0000000000..406cce3817
Binary files /dev/null and b/icons/obj/bongs.dmi differ
diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi
index 6b29d599cc..a719150f11 100644
Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ
diff --git a/icons/obj/hydroponics/growing.dmi b/icons/obj/hydroponics/growing.dmi
index 469b1e1aff..712ea11a3b 100644
Binary files a/icons/obj/hydroponics/growing.dmi and b/icons/obj/hydroponics/growing.dmi differ
diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi
index a57719fb3a..e746d8f43d 100644
Binary files a/icons/obj/hydroponics/harvest.dmi and b/icons/obj/hydroponics/harvest.dmi differ
diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi
index 8695d03b3c..43e231cbab 100644
Binary files a/icons/obj/hydroponics/seeds.dmi and b/icons/obj/hydroponics/seeds.dmi differ
diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi
index 8ede8c66ab..8fee8fcf9f 100644
Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ
diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm b/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm
index a1466f58d4..98de5eed14 100644
--- a/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm
+++ b/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm
@@ -424,12 +424,7 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
if(A)
if(isliving(A))
var/mob/living/L = A
- var/blocked = 0
- if(ishuman(A))
- var/mob/living/carbon/human/H = A
- if(H.check_shields(0, "the [name]", src, attack_type = LEAP_ATTACK))
- blocked = 1
- if(!blocked)
+ if(!L.check_shields(0, "the [name]", src, attack_type = LEAP_ATTACK))
L.visible_message("[src] pounces on [L]!", "[src] pounces on you!")
L.Knockdown(iscarbon(L) ? 60 : 45, override_stamdmg = CLAMP(pounce_stamloss, 0, pounce_stamloss_cap-L.getStaminaLoss())) // Temporary. If someone could rework how dogborg pounces work to accomodate for combat changes, that'd be nice.
playsound(src, 'sound/weapons/Egloves.ogg', 50, 1)
diff --git a/sound/effects/bonghit.ogg b/sound/effects/bonghit.ogg
new file mode 100644
index 0000000000..45a0dec1b6
Binary files /dev/null and b/sound/effects/bonghit.ogg differ
diff --git a/sound/weapons/klonk.ogg b/sound/weapons/klonk.ogg
new file mode 100644
index 0000000000..471f3ad8b7
Binary files /dev/null and b/sound/weapons/klonk.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 252cd8ab3e..d92fbff5d9 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1599,6 +1599,7 @@
#include "code\modules\clothing\clothing.dm"
#include "code\modules\clothing\ears\_ears.dm"
#include "code\modules\clothing\glasses\_glasses.dm"
+#include "code\modules\clothing\glasses\disablerglasses.dm"
#include "code\modules\clothing\glasses\engine_goggles.dm"
#include "code\modules\clothing\glasses\hud.dm"
#include "code\modules\clothing\glasses\phantomthief.dm"
|