diff --git a/code/__DEFINES/movespeed_modification.dm b/code/__DEFINES/movespeed_modification.dm
index 9faa37ac..757de996 100644
--- a/code/__DEFINES/movespeed_modification.dm
+++ b/code/__DEFINES/movespeed_modification.dm
@@ -32,7 +32,5 @@
#define MOVESPEED_ID_SANITY "MOOD_SANITY"
-#define MOVESPEED_ID_TASED_STATUS "TASED"
-
-#define MOVESPEED_ID_PRONE_DRAGGING "PRONE_DRAG"
-#define MOVESPEED_ID_HUMAN_CARRYING "HUMAN_CARRY"
\ No newline at end of file
+#define MOVESPEED_ID_SHRUNK "SHRINK_SPEED_MODIFIER"
+#define MOVESPEED_ID_GROW "GROWTH_SPEED_MODIFIER"
\ No newline at end of file
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 3051a72d..c9a94ecc 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -307,6 +307,9 @@
/obj/machinery/suit_storage_unit/attackby(obj/item/I, mob/user, params)
if(state_open && is_operational())
+ if(istype(I, /obj/item/clothing/head/mob_holder))
+ to_chat(user, "You can't quite fit that while you hold it!")
+ return
if(istype(I, /obj/item/clothing/suit))
if(suit)
to_chat(user, "The unit already contains a suit!.")
diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm
index af9e47f5..69e244a6 100644
--- a/code/game/machinery/washing_machine.dm
+++ b/code/game/machinery/washing_machine.dm
@@ -219,6 +219,10 @@
update_icon()
return
+ if(istype(W, /obj/item/clothing/head/mob_holder))
+ to_chat(user, "It's too unweildy to put in this way.")
+ return 1
+
else if(user.a_intent != INTENT_HARM)
if (!state_open)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
index dd33f696..0755fdc7 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
@@ -80,6 +80,9 @@ God bless America.
I.reagents.trans_to(src, I.reagents.total_volume)
qdel(I)
return
+ if(istype(I,/obj/item/clothing/head/mob_holder))
+ to_chat(user, "This does not fit in the fryer.") // TODO: Deepfrying instakills mobs, spawns a whole deep-fried mob.
+ return
if(!reagents.has_reagent("cooking_oil"))
to_chat(user, "[src] has no cooking oil to fry with!")
return
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 89a7ec25..d9a1716a 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -159,22 +159,35 @@
return
//END OF CIT CHANGES
- var/atom/movable/thrown_thing
var/obj/item/I = src.get_active_held_item()
- if(!I)
- if(pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE)
- var/mob/living/throwable_mob = pulling
- if(!throwable_mob.buckled)
- thrown_thing = throwable_mob
+ 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].")
- 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)]")
+ 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
@@ -194,6 +207,8 @@
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))
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 22da4634..b4ce85c0 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -16,6 +16,10 @@
msg += "[t_He] [t_is] wearing [wear_mask.get_examine_string(user)] on [t_his] face.\n"
if (wear_neck)
msg += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck.\n"
+ if(can_be_held)
+ msg += "[t_He] looks small enough to be picked up with Alt+Click!\n"
+
+
for(var/obj/item/I in held_items)
if(!(I.item_flags & ABSTRACT))
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 1bfff1a9..50f63044 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -107,6 +107,10 @@
//Status effects
msg += status_effect_examines()
+ //Can be picked up?
+ if(can_be_held)
+ msg += "[t_He] looks small enough to be picked up with Alt+Click!\n"
+
//CIT CHANGES START HERE - adds genital details to examine text
if(LAZYLEN(internal_organs))
for(var/obj/item/organ/genital/dicc in internal_organs)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index b4a8839e..5bd897f9 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -854,84 +854,52 @@
.["Copy outfit"] = "?_src_=vars;[HrefToken()];copyoutfit=[REF(src)]"
/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user)
- if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS)
- //If they dragged themselves and we're currently aggressively grabbing them try to piggyback
- if(user == target && can_piggyback(target))
- piggyback(target)
- return
- //If you dragged them to you and you're aggressively grabbing try to fireman carry them
- else if(user != target && can_be_firemanned(target))
- fireman_carry(target)
- return
+ //If they dragged themselves and we're currently aggressively grabbing them try to piggyback
+ if(user == target && can_piggyback(target) && pulling == target && (HAS_TRAIT(src, TRAIT_PACIFISM) || grab_state >= GRAB_AGGRESSIVE) && stat == CONSCIOUS)
+ buckle_mob(target,TRUE,TRUE)
. = ..()
-//src is the user that will be carrying, target is the mob to be carried
-/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target)
- return (istype(target) && target.stat == CONSCIOUS)
+/mob/living/carbon/human/proc/piggyback_instant(mob/living/M)
+ return buckle_mob(M, TRUE, TRUE, FALSE, TRUE)
-/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target)
- return (ishuman(target) && target.lying)
+//Can C try to piggyback at all.
+/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/C)
+ if(istype(C) && C.stat == CONSCIOUS)
+ return TRUE
+ return FALSE
-/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target)
- if(can_be_firemanned(target))
- visible_message("[src] starts lifting [target] onto their back...",
- "You start lifting [target] onto your back...")
- if(do_after(src, 30, TRUE, target))
- //Second check to make sure they're still valid to be carried
- if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
- target.resting = FALSE
- buckle_mob(target, TRUE, TRUE, 90, 1, 0)
- return
- visible_message("[src] fails to fireman carry [target]!")
- else
- to_chat(src, "You can't fireman carry [target] while they're standing!")
-
-/mob/living/carbon/human/proc/piggyback(mob/living/carbon/target)
- if(can_piggyback(target))
- visible_message("[target] starts to climb onto [src]...")
- if(do_after(target, 15, target = src))
- if(can_piggyback(target))
- if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
- target.visible_message("[target] can't hang onto [src]!")
- return
- buckle_mob(target, TRUE, TRUE, FALSE, 0, 2)
- else
- visible_message("[target] fails to climb onto [src]!")
- else
- to_chat(target, "You can't piggyback ride [src] right now!")
-
-/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0)
+/mob/living/carbon/human/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE, bypass_piggybacking = FALSE, no_delay = FALSE)
if(!force)//humans are only meant to be ridden through piggybacking and special cases
return
- if(!is_type_in_typecache(target, can_ride_typecache))
- target.visible_message("[target] really can't seem to mount [src]...")
+ if(bypass_piggybacking)
+ return ..()
+ if(!is_type_in_typecache(M, can_ride_typecache))
+ M.visible_message("[M] really can't seem to mount [src]...")
return
- buckle_lying = lying_buckle
var/datum/component/riding/human/riding_datum = LoadComponent(/datum/component/riding/human)
- if(target_hands_needed)
- riding_datum.ride_check_rider_restrained = TRUE
- if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled)
+ riding_datum.ride_check_rider_incapacitated = TRUE
+ riding_datum.ride_check_rider_restrained = TRUE
+ riding_datum.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4)))
+ if(buckled_mobs && ((M in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled || (M.stat != CONSCIOUS))
return
- var/equipped_hands_self
- var/equipped_hands_target
- if(hands_needed)
- equipped_hands_self = riding_datum.equip_buckle_inhands(src, hands_needed, target)
- if(target_hands_needed)
- equipped_hands_target = riding_datum.equip_buckle_inhands(target, target_hands_needed)
-
- if(hands_needed || target_hands_needed)
- if(hands_needed && !equipped_hands_self)
- src.visible_message("[src] can't get a grip on [target] because their hands are full!",
- "You can't get a grip on [target] because your hands are full!")
- return
- else if(target_hands_needed && !equipped_hands_target)
- target.visible_message("[target] can't get a grip on [src] because their hands are full!",
- "You can't get a grip on [src] because your hands are full!")
- return
-
- stop_pulling()
- riding_datum.handle_vehicle_layer()
- . = ..(target, force, check_loc)
+ if(can_piggyback(M))
+ riding_datum.ride_check_ridden_incapacitated = TRUE
+ visible_message("[M] starts to climb onto [src]...")
+ if(no_delay || do_after(M, 15, target = src))
+ if(can_piggyback(M))
+ if(M.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
+ M.visible_message("[M] can't hang onto [src]!")
+ return
+ if(!riding_datum.equip_buckle_inhands(M, 2)) //MAKE SURE THIS IS LAST!!
+ M.visible_message("[M] can't climb onto [src]!")
+ return
+ . = ..(M, force, check_loc)
+ stop_pulling()
+ else
+ visible_message("[M] fails to climb onto [src]!")
+ else
+ . = ..(M,force,check_loc)
+ stop_pulling()
/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this
for(var/obj/item/clothing/C in get_equipped_items()) //doesn't include pockets
@@ -1098,4 +1066,8 @@
race = /datum/species/zombie/infectious
/mob/living/carbon/human/species/zombie/krokodil_addict
- race = /datum/species/krokodil_addict
\ No newline at end of file
+ race = /datum/species/krokodil_addict
+
+//define holder_type on nibbas we wanna commit scoop to
+/mob/living/carbon/human
+ var/holder_type = /obj/item/clothing/head/mob_holder/micro
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/monkey/combat.dm b/code/modules/mob/living/carbon/monkey/combat.dm
index 25bc243f..92ad87f6 100644
--- a/code/modules/mob/living/carbon/monkey/combat.dm
+++ b/code/modules/mob/living/carbon/monkey/combat.dm
@@ -132,6 +132,10 @@
pickupTarget = null
pickupTimer = 0
else if(ismob(pickupTarget.loc)) // in someones hand
+ if(istype(pickupTarget, /obj/item/clothing/head/mob_holder/))
+ var/obj/item/clothing/head/mob_holder/h = pickupTarget
+ if(h && h.held_mob==src)
+ return//dont let them pickpocket themselves
var/mob/M = pickupTarget.loc
if(!pickpocketing)
pickpocketing = TRUE
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index 7b44a01a..47a177f7 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -15,6 +15,7 @@
bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey,
/obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey)
hud_type = /datum/hud/monkey
+ can_be_held = "monkey"
/mob/living/carbon/monkey/Initialize(mapload, cubespawned=FALSE, mob/spawner)
verbs += /mob/living/proc/mob_sleep
@@ -45,6 +46,10 @@
SSmobs.cubemonkeys -= src
return ..()
+/mob/living/carbon/monkey/generate_mob_holder()
+ var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, "monkey", 'icons/mob/animals_held.dmi', 'icons/mob/animals_held_lh.dmi', 'icons/mob/animals_held_rh.dmi', TRUE)
+ return holder
+
/mob/living/carbon/monkey/create_internal_organs()
internal_organs += new /obj/item/organ/appendix
internal_organs += new /obj/item/organ/lungs
@@ -169,15 +174,3 @@
var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src)
equip_to_slot_or_del(helmet,SLOT_HEAD)
helmet.attack_self(src) // todo encapsulate toggle
-
-/mob/living/carbon/monkey/tumor
- name = "living teratoma"
- verb_say = "blabbers"
- initial_language_holder = /datum/language_holder/monkey
- icon = 'icons/mob/monkey.dmi'
- icon_state = ""
- butcher_results = list(/obj/effect/spawner/lootdrop/teratoma/minor = 5, /obj/effect/spawner/lootdrop/teratoma/major = 1)
- type_of_meat = /obj/effect/spawner/lootdrop/teratoma/minor
- aggressive = TRUE
- bodyparts = list(/obj/item/bodypart/chest/monkey/teratoma, /obj/item/bodypart/head/monkey/teratoma, /obj/item/bodypart/l_arm/monkey/teratoma,
- /obj/item/bodypart/r_arm/monkey/teratoma, /obj/item/bodypart/r_leg/monkey/teratoma, /obj/item/bodypart/l_leg/monkey/teratoma)
diff --git a/code/modules/mob/living/carbon/monkey/update_icons.dm b/code/modules/mob/living/carbon/monkey/update_icons.dm
index ff83b00f..75ec032c 100644
--- a/code/modules/mob/living/carbon/monkey/update_icons.dm
+++ b/code/modules/mob/living/carbon/monkey/update_icons.dm
@@ -1,80 +1,355 @@
+//IMPORTANT: Multiple animate() calls do not stack well, so try to do them all at once if you can.
+/mob/living/carbon/update_transform()
+ var/matrix/ntransform = matrix(transform) //aka transform.Copy()
+ var/final_pixel_y = pixel_y
+ var/final_dir = dir
+ var/changed = 0
-/mob/living/carbon/monkey/regenerate_icons()
- if(!..())
- update_body_parts()
- update_hair()
- update_inv_wear_mask()
- update_inv_head()
- update_inv_back()
- update_transform()
+ if(lying != lying_prev && rotate_on_lying)
+ changed++
+ ntransform.TurnTo(lying_prev,lying)
+ if(lying == 0) //Lying to standing
+ final_pixel_y = get_standard_pixel_y_offset()
+ if(size_multiplier >= 1) //if its bigger than normal
+ ntransform.Translate(0,16 * (size_multiplier-1))
+ else
+ if(lying_prev == 90)
+ ntransform.Translate(16 * (size_multiplier-1),16 * (size_multiplier-1))
+
+ if(lying_prev == 270)
+ ntransform.Translate(-16 * (size_multiplier-1),16 * (size_multiplier-1))
+
+ else //if(lying != 0)
+ if(lying_prev == 0) //Standing to lying
+ pixel_y = get_standard_pixel_y_offset()
+ final_pixel_y = get_standard_pixel_y_offset(lying)
+ if(lying == 90) //Check the angle of the sprite to offset it accordingly.
+ ntransform.Translate(-16 * (size_multiplier-1),0)
+ if(size_multiplier < 1) //if its smaller than normal
+ ntransform.Translate(0,16 * (size_multiplier-1)) //we additionally offset the sprite downwards
+
+ if(lying == 270) //check the angle of the sprite to offset it accordingly
+ ntransform.Translate(16 * (size_multiplier-1),0)
+ if(size_multiplier < 1) //if its smaller than normal
+ ntransform.Translate(0,16 * (size_multiplier-1)) //we additionally offset the sprite downwards
+
+ if(dir & (EAST|WEST)) //Facing east or west
+ final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
+
+ if(resize != RESIZE_DEFAULT_SIZE)
+ changed++
+ ntransform.Scale(resize)
+ resize = RESIZE_DEFAULT_SIZE
+
+ //Apply size multiplier, thank NeverExisted for this
+ if(size_multiplier != previous_size)
+ changed++
+ //now we offset the sprite
+ //Scaling affects offset. There's probably a smarter and easier way to do this, but this way it works for sure (?)
+ //Just to be clear. All this bullshit is needed because someone wanted to store the old transform matrix instead of using a new one each iteration
+ //Winfre is currently doing a great job at coating my nuts in slobber while i code this
+ if(!lying) //when standing. People of all sizes are affected equally
+ ntransform.Translate(0,-16 * (previous_size-1)) //reset the sprite
+ ntransform.Scale(size_multiplier/previous_size) //scale the sprite accordingly.
+ ntransform.Translate(0,16 * (size_multiplier-1)) //apply the new offset
+ else //when lying. Macros dont get an offset, Micros do. We must also check the cases when a micro becomes a macro and viceversa
+ if(previous_size <= 1 && size_multiplier <= 1) //micro stays a micro. We modify the side-offset
+ ntransform.Translate(0,-16 * (previous_size-1)) //reset the sprite
+ ntransform.Scale(size_multiplier/previous_size) //scale the sprite accordingly
+ ntransform.Translate(0,16 * (size_multiplier-1)) //apply the new offset
+
+ if(previous_size <= 1 && size_multiplier > 1) //micro becomes a macro. We remove the side-offset
+ ntransform.Translate(0,-16 * (previous_size-1)) //reset the sprite
+ ntransform.Scale(size_multiplier/previous_size) //scale the sprite accordingly
+
+ if(previous_size > 1 && size_multiplier <= 1) //macro becomes a micro. We add an offset
+ ntransform.Scale(size_multiplier/previous_size) //scale the sprite accordingly.
+ ntransform.Translate(0,16 * (size_multiplier-1)) //apply the new offset
+
+ if(previous_size > 1 && size_multiplier > 1) //macro stays a macro. We just scale the sprite with no offset changes
+ ntransform.Scale(size_multiplier/previous_size) //scale the sprite accordingly
+
+ previous_size = size_multiplier
+
+ if(changed)
+ animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, dir = final_dir, easing = EASE_IN|EASE_OUT)
+ floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life().
-////////
+/mob/living/carbon
+ var/list/overlays_standing[TOTAL_LAYERS]
+
+/mob/living/carbon/proc/apply_overlay(cache_index)
+ if((. = overlays_standing[cache_index]))
+ add_overlay(.)
+
+/mob/living/carbon/proc/remove_overlay(cache_index)
+ var/I = overlays_standing[cache_index]
+ if(I)
+ cut_overlay(I)
+ overlays_standing[cache_index] = null
+
+/mob/living/carbon/regenerate_icons()
+ if(notransform)
+ return 1
+ update_inv_hands()
+ update_inv_handcuffed()
+ update_inv_legcuffed()
+ update_fire()
-/mob/living/carbon/monkey/update_hair()
- remove_overlay(HAIR_LAYER)
-
- var/obj/item/bodypart/head/HD = get_bodypart(BODY_ZONE_HEAD)
- if(!HD) //Decapitated
+/mob/living/carbon/update_inv_hands()
+ remove_overlay(HANDS_LAYER)
+ if (handcuffed)
+ drop_all_held_items()
return
- if(HAS_TRAIT(src, TRAIT_HUSK))
+ var/list/hands = list()
+ for(var/obj/item/I in held_items)
+ if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD)
+ I.screen_loc = ui_hand_position(get_held_index_of_item(I))
+ client.screen += I
+ if(observers && observers.len)
+ for(var/M in observers)
+ var/mob/dead/observe = M
+ if(observe.client && observe.client.eye == src)
+ observe.client.screen += I
+ else
+ observers -= observe
+ if(!observers.len)
+ observers = null
+ break
+
+ var/t_state = I.item_state
+ if(!t_state)
+ t_state = I.icon_state
+
+ var/icon_file = I.lefthand_file
+ if(get_held_index_of_item(I) % 2 == 0)
+ icon_file = I.righthand_file
+
+ hands += I.build_worn_icon(state = t_state, default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE)
+
+ overlays_standing[HANDS_LAYER] = hands
+ apply_overlay(HANDS_LAYER)
+
+
+/mob/living/carbon/update_fire(var/fire_icon = "Generic_mob_burning")
+ remove_overlay(FIRE_LAYER)
+ if(on_fire)
+ 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/update_damage_overlays()
+ remove_overlay(DAMAGE_LAYER)
+
+ var/mutable_appearance/damage_overlay = mutable_appearance('icons/mob/dam_mob.dmi', "blank", -DAMAGE_LAYER)
+ overlays_standing[DAMAGE_LAYER] = damage_overlay
+
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ if(BP.dmg_overlay_type)
+ if(BP.brutestate)
+ damage_overlay.add_overlay("[BP.dmg_overlay_type]_[BP.body_zone]_[BP.brutestate]0") //we're adding icon_states of the base image as overlays
+ if(BP.burnstate)
+ damage_overlay.add_overlay("[BP.dmg_overlay_type]_[BP.body_zone]_0[BP.burnstate]")
+
+ apply_overlay(DAMAGE_LAYER)
+
+
+/mob/living/carbon/update_inv_wear_mask()
+ remove_overlay(FACEMASK_LAYER)
+
+ if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
return
- var/hair_hidden = 0
+ if(client && hud_used && hud_used.inv_slots[SLOT_WEAR_MASK])
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_MASK]
+ inv.update_icon()
+
+ if(wear_mask)
+ if(!(head && (head.flags_inv & HIDEMASK)))
+ overlays_standing[FACEMASK_LAYER] = wear_mask.build_worn_icon(state = wear_mask.icon_state, default_layer = FACEMASK_LAYER, default_icon_file = 'icons/mob/mask.dmi')
+ update_hud_wear_mask(wear_mask)
+
+ apply_overlay(FACEMASK_LAYER)
+
+/mob/living/carbon/update_inv_neck()
+ remove_overlay(NECK_LAYER)
+
+ if(client && hud_used && hud_used.inv_slots[SLOT_NECK])
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_NECK]
+ inv.update_icon()
+
+ if(wear_neck)
+ if(!(head && (head.flags_inv & HIDENECK)))
+ overlays_standing[NECK_LAYER] = wear_neck.build_worn_icon(state = wear_neck.icon_state, default_layer = NECK_LAYER, default_icon_file = 'icons/mob/neck.dmi')
+ update_hud_neck(wear_neck)
+
+ apply_overlay(NECK_LAYER)
+
+/mob/living/carbon/update_inv_back()
+ remove_overlay(BACK_LAYER)
+
+ if(client && hud_used && hud_used.inv_slots[SLOT_BACK])
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_BACK]
+ inv.update_icon()
+
+ if(back)
+ overlays_standing[BACK_LAYER] = back.build_worn_icon(state = back.icon_state, default_layer = BACK_LAYER, default_icon_file = 'icons/mob/back.dmi')
+ update_hud_back(back)
+
+ apply_overlay(BACK_LAYER)
+
+/mob/living/carbon/update_inv_head()
+ remove_overlay(HEAD_LAYER)
+
+ if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
+ return
+
+ if(client && hud_used && hud_used.inv_slots[SLOT_BACK])
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_HEAD]
+ inv.update_icon()
if(head)
- var/obj/item/I = head
- if(I.flags_inv & HIDEHAIR)
- hair_hidden = 1
- if(wear_mask)
- var/obj/item/clothing/mask/M = wear_mask
- if(M.flags_inv & HIDEHAIR)
- hair_hidden = 1
- if(!hair_hidden)
- if(!getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain
- overlays_standing[HAIR_LAYER] = mutable_appearance('icons/mob/human_face.dmi', "debrained", -HAIR_LAYER)
- apply_overlay(HAIR_LAYER)
+ overlays_standing[HEAD_LAYER] = head.build_worn_icon(state = head.icon_state, default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/head.dmi')
+ update_hud_head(head)
+
+ apply_overlay(HEAD_LAYER)
-/mob/living/carbon/monkey/update_fire()
- ..("Monkey_burning")
+/mob/living/carbon/update_inv_handcuffed()
+ remove_overlay(HANDCUFF_LAYER)
+ if(handcuffed)
+ var/mutable_appearance/cuffs = mutable_appearance('icons/mob/restraints.dmi', handcuffed.item_state, -HANDCUFF_LAYER)
+ cuffs.color = handcuffed.color
-/mob/living/carbon/monkey/update_inv_legcuffed()
+ overlays_standing[HANDCUFF_LAYER] = cuffs
+ apply_overlay(HANDCUFF_LAYER)
+
+/mob/living/carbon/update_inv_legcuffed()
remove_overlay(LEGCUFF_LAYER)
clear_alert("legcuffed")
if(legcuffed)
var/mutable_appearance/legcuffs = mutable_appearance('icons/mob/restraints.dmi', legcuffed.item_state, -LEGCUFF_LAYER)
- legcuffs.color = handcuffed.color
- legcuffs.pixel_y = 8
+ legcuffs.color = legcuffed.color
overlays_standing[HANDCUFF_LAYER] = legcuffs
apply_overlay(LEGCUFF_LAYER)
throw_alert("legcuffed", /obj/screen/alert/restrained/legcuffed, new_master = legcuffed)
-//monkey HUD updates for items in our inventory
+//mob HUD updates for items in our inventory
+
+//update whether handcuffs appears on our hud.
+/mob/living/carbon/proc/update_hud_handcuffed()
+ if(hud_used)
+ for(var/hand in hud_used.hand_slots)
+ var/obj/screen/inventory/hand/H = hud_used.hand_slots[hand]
+ if(H)
+ H.update_icon()
//update whether our head item appears on our hud.
-/mob/living/carbon/monkey/update_hud_head(obj/item/I)
- if(client && hud_used && hud_used.hud_shown)
- I.screen_loc = ui_monkey_head
- client.screen += I
+/mob/living/carbon/proc/update_hud_head(obj/item/I)
+ return
//update whether our mask item appears on our hud.
-/mob/living/carbon/monkey/update_hud_wear_mask(obj/item/I)
- if(client && hud_used && hud_used.hud_shown)
- I.screen_loc = ui_monkey_mask
- client.screen += I
+/mob/living/carbon/proc/update_hud_wear_mask(obj/item/I)
+ return
//update whether our neck item appears on our hud.
-/mob/living/carbon/monkey/update_hud_neck(obj/item/I)
- if(client && hud_used && hud_used.hud_shown)
- I.screen_loc = ui_monkey_neck
- client.screen += I
+/mob/living/carbon/proc/update_hud_neck(obj/item/I)
+ return
//update whether our back item appears on our hud.
-/mob/living/carbon/monkey/update_hud_back(obj/item/I)
- if(client && hud_used && hud_used.hud_shown)
- I.screen_loc = ui_monkey_back
- client.screen += I
\ No newline at end of file
+/mob/living/carbon/proc/update_hud_back(obj/item/I)
+ return
+
+
+
+//Overlays for the worn overlay so you can overlay while you overlay
+//eg: ammo counters, primed grenade flashing, etc.
+//"icon_file" is used automatically for inhands etc. to make sure it gets the right inhand file
+/obj/item/proc/worn_overlays(isinhands = FALSE, icon_file)
+ . = list()
+
+
+/mob/living/carbon/update_body()
+ update_body_parts()
+
+/mob/living/carbon/proc/update_body_parts()
+ //CHECK FOR UPDATE
+ var/oldkey = icon_render_key
+ icon_render_key = generate_icon_render_key()
+ if(oldkey == icon_render_key)
+ return
+
+ remove_overlay(BODYPARTS_LAYER)
+
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ BP.update_limb()
+
+ //LOAD ICONS
+ if(limb_icon_cache[icon_render_key])
+ load_limb_from_cache()
+ return
+
+ //GENERATE NEW LIMBS
+ var/list/new_limbs = list()
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ new_limbs += BP.get_limb_icon()
+ if(new_limbs.len)
+ overlays_standing[BODYPARTS_LAYER] = new_limbs
+ limb_icon_cache[icon_render_key] = new_limbs
+
+ apply_overlay(BODYPARTS_LAYER)
+ update_damage_overlays()
+
+
+
+/////////////////////
+// Limb Icon Cache //
+/////////////////////
+/*
+ Called from update_body_parts() these procs handle the limb icon cache.
+ the limb icon cache adds an icon_render_key to a human mob, it represents:
+ - skin_tone (if applicable)
+ - gender
+ - limbs (stores as the limb name and whether it is removed/fine, organic/robotic)
+ These procs only store limbs as to increase the number of matching icon_render_keys
+ This cache exists because drawing 6/7 icons for humans constantly is quite a waste
+ See RemieRichards on irc.rizon.net #coderbus
+*/
+
+//produces a key based on the mob's limbs
+
+/mob/living/carbon/proc/generate_icon_render_key()
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ . += "-[BP.body_zone]"
+ if(BP.use_digitigrade)
+ . += "-digitigrade[BP.use_digitigrade]"
+ if(BP.animal_origin)
+ . += "-[BP.animal_origin]"
+ if(BP.status == BODYPART_ORGANIC)
+ . += "-organic"
+ else
+ . += "-robotic"
+
+ if(HAS_TRAIT(src, TRAIT_HUSK))
+ . += "-husk"
+
+
+//change the mob's icon to the one matching its key
+/mob/living/carbon/proc/load_limb_from_cache()
+ if(limb_icon_cache[icon_render_key])
+ remove_overlay(BODYPARTS_LAYER)
+ overlays_standing[BODYPARTS_LAYER] = limb_icon_cache[icon_render_key]
+ apply_overlay(BODYPARTS_LAYER)
+ update_damage_overlays()
diff --git a/code/modules/mob/living/inhand_holder.dm b/code/modules/mob/living/inhand_holder.dm
index b82e8cc4..353a4f4f 100644
--- a/code/modules/mob/living/inhand_holder.dm
+++ b/code/modules/mob/living/inhand_holder.dm
@@ -5,80 +5,128 @@
desc = "Yell at coderbrush."
icon = null
icon_state = ""
- item_flags = DROPDEL
var/mob/living/held_mob
- var/can_head = TRUE
- var/destroying = FALSE
+ var/can_head = FALSE
+ w_class = WEIGHT_CLASS_BULKY
-/obj/item/clothing/head/mob_holder/Initialize(mapload, mob/living/M, _worn_state, head_icon, lh_icon, rh_icon, _can_head = TRUE)
+/obj/item/clothing/head/mob_holder/Initialize(mapload, mob/living/M, _worn_state, alt_worn, lh_icon, rh_icon, _can_head_override = FALSE)
. = ..()
- can_head = _can_head
- if(head_icon)
- alternate_worn_icon = head_icon
+
+ if(M)
+ M.setDir(SOUTH)
+ held_mob = M
+ M.forceMove(src)
+ appearance = M.appearance
+ name = M.name
+ desc = M.desc
+
+ if(_can_head_override)
+ can_head = _can_head_override
+ if(alt_worn)
+ alternate_worn_icon = alt_worn
if(_worn_state)
item_state = _worn_state
+ icon_state = _worn_state
if(lh_icon)
lefthand_file = lh_icon
if(rh_icon)
righthand_file = rh_icon
if(!can_head)
slot_flags = NONE
- deposit(M)
/obj/item/clothing/head/mob_holder/Destroy()
- destroying = TRUE
if(held_mob)
- release(FALSE)
+ release()
return ..()
-/obj/item/clothing/head/mob_holder/proc/deposit(mob/living/L)
- if(!istype(L))
- return FALSE
- L.setDir(SOUTH)
- update_visuals(L)
- held_mob = L
- L.forceMove(src)
- name = L.name
- desc = L.desc
- return TRUE
+/obj/item/clothing/head/mob_holder/dropped()
+ ..()
+ if(isturf(loc))//don't release on soft-drops
+ release()
-/obj/item/clothing/head/mob_holder/proc/update_visuals(mob/living/L)
- appearance = L.appearance
-
-/obj/item/clothing/head/mob_holder/proc/release(del_on_release = TRUE)
- if(!held_mob)
- if(del_on_release && !destroying)
- qdel(src)
- return FALSE
+/obj/item/clothing/head/mob_holder/proc/release()
if(isliving(loc))
var/mob/living/L = loc
- to_chat(L, "[held_mob] wriggles free!")
L.dropItemToGround(src)
- held_mob.forceMove(get_turf(held_mob))
- held_mob.reset_perspective()
- held_mob.setDir(SOUTH)
- held_mob.visible_message("[held_mob] uncurls!")
- held_mob = null
- if(del_on_release && !destroying)
- qdel(src)
- return TRUE
+ if(held_mob)
+ var/mob/living/m = held_mob
+ m.forceMove(get_turf(m))
+ m.reset_perspective()
+ m.setDir(SOUTH)
+ held_mob = null
+ qdel(src)
/obj/item/clothing/head/mob_holder/relaymove(mob/user)
- release()
+ return
/obj/item/clothing/head/mob_holder/container_resist()
+ if(isliving(loc))
+ var/mob/living/L = loc
+ visible_message("[src] escapes [L]!")
release()
-/obj/item/clothing/head/mob_holder/drone/deposit(mob/living/L)
- . = ..()
- if(!isdrone(L))
- qdel(src)
- name = "drone (hiding)"
- desc = "This drone is scared and has curled up into a ball!"
+/mob/living/proc/mob_pickup(mob/living/L)
+ var/obj/item/clothing/head/mob_holder/holder = generate_mob_holder()
+ if(!holder)
+ return
+ drop_all_held_items()
+ L.put_in_hands(holder)
+ return
-/obj/item/clothing/head/mob_holder/drone/update_visuals(mob/living/L)
- var/mob/living/simple_animal/drone/D = L
- if(!D)
- return ..()
- icon = 'icons/mob/drone.dmi'
- icon_state = "[D.visualAppearence]_hat"
+/mob/living/proc/mob_try_pickup(mob/living/user)
+ if(!ishuman(user) || !src.Adjacent(user) || user.incapacitated() || !can_be_held || (abs(get_effective_size()/get_effective_size(user)) >= 2))
+ return FALSE
+ if(user.get_active_held_item())
+ to_chat(user, "Your hands are full!")
+ return FALSE
+ if(buckled)
+ to_chat(user, "[src] is buckled to something!")
+ return FALSE
+ if(src == user)
+ to_chat(user, "You can't pick yourself up.")
+ return FALSE
+ visible_message("[user] starts picking up [src].", \
+ "[user] starts picking you up!")
+ if(!do_after(user, 20, target = src))
+ return FALSE
+
+ if(user.get_active_held_item()||buckled)
+ return FALSE
+
+ visible_message("[user] picks up [src]!", \
+ "[user] picks you up!")
+ to_chat(user, "You pick [src] up.")
+ mob_pickup(user)
+ return TRUE
+
+/mob/living/AltClick(mob/user)
+ . = ..()
+ if(mob_try_pickup(user))
+ return TRUE
+
+
+// I didn't define these for mobs, because you shouldn't be able to breathe out of mobs using their loc isn't always the logical thing to do.
+/*
+/obj/item/clothing/head/mob_holder/assume_air(datum/gas_mixture/env)
+ var/atom/location = loc
+ if(!loc)
+ return //null
+ var/turf/T = get_turf(loc)
+ while(location != T)
+ location = location.loc
+ if(ismob(location))
+ return location.loc.assume_air(env)
+ return loc.assume_air(env)
+
+/obj/item/clothing/head/mob_holder/remove_air(amount)
+ var/atom/location = loc
+ if(!loc)
+ return //null
+ var/turf/T = get_turf(loc)
+ while(location != T)
+ location = location.loc
+ if(ismob(location))
+ return location.loc.remove_air()
+ return loc.remove_air(amount)
+*/
+//Turned off for sizecode to work right now
\ No newline at end of file
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index f311649d..70317492 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -40,6 +40,12 @@
QDEL_LIST(diseases)
return ..()
+
+/mob/living/proc/generate_mob_holder()
+ var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, (istext(can_be_held) ? can_be_held : ""), 'icons/mob/animals_held.dmi', 'icons/mob/animals_held_lh.dmi', 'icons/mob/animals_held_rh.dmi')
+ return holder
+
+
/mob/living/proc/OpenCraftingMenu()
return
@@ -136,6 +142,11 @@
else if((M.restrained() || M.a_intent == INTENT_HELP) && (restrained() || a_intent == INTENT_HELP))
mob_swap = 1
if(mob_swap)
+
+ //handle micro bumping on help intent
+ if(handle_micro_bump_helping(M))
+ return 1
+
//switch our position with M
if(loc && !loc.Adjacent(M.loc))
return 1
@@ -168,6 +179,11 @@
//not if he's not CANPUSH of course
if(!(M.status_flags & CANPUSH))
return 1
+
+ //handle micro bumping on other intents
+ if(handle_micro_bump_other(M))
+ return 1
+
if(isliving(M))
var/mob/living/L = M
if(HAS_TRAIT(L, TRAIT_PUSHIMMUNE))
@@ -281,7 +297,11 @@
var/datum/disease/D = thing
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
ContactContractDisease(D)
-p
+
+ if(iscarbon(L))
+ var/mob/living/carbon/C = L
+ if(HAS_TRAIT(src, TRAIT_STRONG_GRABBER))
+ C.grippedby(src)
//mob verbs are a lot faster than object verbs
//for more info on why this is not atom/pull, see examinate() in mob.dm
@@ -1124,23 +1144,6 @@ p
if(can_be_held)
mob_try_pickup(over)
-/mob/living/proc/mob_pickup(mob/living/L)
- return
-
-/mob/living/proc/mob_try_pickup(mob/living/user)
- if(!ishuman(user))
- return
- if(user.get_active_held_item())
- to_chat(user, "Your hands are full!")
- return FALSE
- if(buckled)
- to_chat(user, "[src] is buckled to something!")
- return FALSE
- user.visible_message("[user] starts trying to scoop up [src]!")
- if(!do_after(user, 20, target = src))
- return FALSE
- mob_pickup(user)
- return TRUE
/mob/living/proc/get_static_viruses() //used when creating blood and other infective objects
if(!LAZYLEN(diseases))
@@ -1236,3 +1239,10 @@ p
update_canmove()
for(var/chem in healing_chems)
reagents.add_reagent(chem, healing_chems[chem])
+
+//retard edits below
+/mob/living
+ var/size_multiplier = 1 //multiplier for the mob's icon size atm
+ var/previous_size = 1
+ var/holder_default
+// can_be_held = "micro"
\ No newline at end of file
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index b6e2c16a..3740827b 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -108,7 +108,7 @@
var/list/obj/effect/proc_holder/abilities = list()
- var/can_be_held = FALSE //whether this can be picked up and held.
+ var/can_be_held = TRUE //whether this can be picked up and held. Currently needs to be on for sizecode to work, fix later.
var/radiation = 0 //If the mob is irradiated.
var/ventcrawl_layer = PIPING_LAYER_DEFAULT
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 7df851ec..f2047435 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -31,6 +31,7 @@
var/mob/living/simple_animal/mouse/movement_target
gold_core_spawnable = FRIENDLY_SPAWN
collar_type = "cat"
+ can_be_held = "cat2"
do_footstep = TRUE
@@ -80,6 +81,7 @@
pass_flags = PASSMOB
mob_size = MOB_SIZE_SMALL
collar_type = "kitten"
+ can_be_held = "cat"
//RUNTIME IS ALIVE! SQUEEEEEEEE~
/mob/living/simple_animal/pet/cat/Runtime
@@ -262,6 +264,7 @@
attacked_sound = 'sound/items/eatfood.ogg'
deathmessage = "loses its false life and collapses!"
death_sound = "bodyfall"
+ can_be_held = "cak"
/mob/living/simple_animal/pet/cat/cak/CheckParts(list/parts)
..()
diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index c194233c..9760b066 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -15,6 +15,7 @@
turns_per_move = 10
do_footstep = TRUE
+ can_be_held = TRUE
//Corgis and pugs are now under one dog subtype
@@ -35,6 +36,7 @@
var/obj/item/inventory_back
var/shaved = FALSE
var/nofur = FALSE //Corgis that have risen past the material plane of existence.
+ can_be_held = "corgi"
/mob/living/simple_animal/pet/dog/corgi/Destroy()
QDEL_NULL(inventory_head)
@@ -63,6 +65,7 @@
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/pug = 3)
gold_core_spawnable = FRIENDLY_SPAWN
collar_type = "pug"
+ can_be_held = "pug"
/mob/living/simple_animal/pet/dog/corgi/exoticcorgi
name = "Exotic Corgi"
@@ -360,6 +363,7 @@
icon_dead = "old_corgi_dead"
desc = "At a ripe old age of [record_age] Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP
turns_per_move = 20
+ can_be_held = "old_corgi"
/mob/living/simple_animal/pet/dog/corgi/Ian/Life()
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
@@ -582,6 +586,7 @@
unsuitable_atmos_damage = 0
minbodytemp = TCMB
maxbodytemp = T0C + 40
+ can_be_held = "void_puppy"
/mob/living/simple_animal/pet/dog/corgi/puppy/void/Process_Spacemove(movement_dir = 0)
return 1 //Void puppies can navigate space.
@@ -603,6 +608,7 @@
response_harm = "kicks"
var/turns_since_scan = 0
var/puppies = 0
+ can_be_held = "lisa"
//Lisa already has a cute bow!
/mob/living/simple_animal/pet/dog/corgi/Lisa/Topic(href, href_list)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index 6d312147..f880adb7 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -274,3 +274,7 @@
/mob/living/simple_animal/drone/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
return 0 //So they don't die trying to fix wiring
+
+/mob/living/simple_animal/drone/generate_mob_holder()
+ var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, "[visualAppearence]_hat", null, null, null, TRUE)
+ return holder
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 33031fd8..e40eb585 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -29,28 +29,11 @@
if("Nothing")
return
-//ATTACK HAND IGNORING PARENT RETURN VALUE
+//picky up the drone c:
/mob/living/simple_animal/drone/attack_hand(mob/user)
- if(ishuman(user))
- if(stat == DEAD || status_flags & GODMODE || !can_be_held)
- ..()
- return
- if(user.get_active_held_item())
- to_chat(user, "Your hands are full!")
- return
- visible_message("[user] starts picking up [src].", \
- "[user] starts picking you up!")
- if(!do_after(user, 20, target = src))
- return
- visible_message("[user] picks up [src]!", \
- "[user] picks you up!")
- if(buckled)
- to_chat(user, "[src] is buckled to [buckled] and cannot be picked up!")
- return
- to_chat(user, "You pick [src] up.")
- drop_all_held_items()
- var/obj/item/clothing/head/mob_holder/drone/DH = new(get_turf(src), src)
- user.put_in_hands(DH)
+ ..()
+ if(user.a_intent == INTENT_HELP)
+ 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/friendly/fox.dm b/code/modules/mob/living/simple_animal/friendly/fox.dm
index 28b66c26..3f58ca59 100644
--- a/code/modules/mob/living/simple_animal/friendly/fox.dm
+++ b/code/modules/mob/living/simple_animal/friendly/fox.dm
@@ -18,7 +18,7 @@
response_disarm = "gently pushes aside"
response_harm = "kicks"
gold_core_spawnable = FRIENDLY_SPAWN
-
+ can_be_held = "fox"
do_footstep = TRUE
//Captain fox
diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm
index e329dd3f..a7c56cc7 100644
--- a/code/modules/mob/living/simple_animal/friendly/lizard.dm
+++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm
@@ -23,6 +23,7 @@
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
var/static/list/edibles = typecacheof(list(/mob/living/simple_animal/butterfly, /mob/living/simple_animal/cockroach)) //list of atoms, however turfs won't affect AI, but will affect consumption.
+ can_be_held = "lizard"
/mob/living/simple_animal/hostile/lizard/CanAttack(atom/the_target)//Can we actually attack a possible target?
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
@@ -39,3 +40,7 @@
return TRUE
else
return ..()
+
+/mob/living/simple_animal/hostile/lizard/generate_mob_holder()
+ var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, "lizard", 'icons/mob/animals_held.dmi', 'icons/mob/animals_held_lh.dmi', 'icons/mob/animals_held_rh.dmi', TRUE)
+ return holder
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index bf45c9cc..47e8f4d0 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -25,6 +25,7 @@
var/body_color //brown, gray and white, leave blank for random
gold_core_spawnable = FRIENDLY_SPAWN
var/chew_probability = 1
+ can_be_held = TRUE
/mob/living/simple_animal/mouse/Initialize()
. = ..()
@@ -34,7 +35,7 @@
icon_state = "mouse_[body_color]"
icon_living = "mouse_[body_color]"
icon_dead = "mouse_[body_color]_dead"
-
+ can_be_held = "mouse_[body_color]"
/mob/living/simple_animal/mouse/proc/splat()
src.health = 0
@@ -87,14 +88,17 @@
/mob/living/simple_animal/mouse/white
body_color = "white"
icon_state = "mouse_white"
+ can_be_held = "mouse_white"
/mob/living/simple_animal/mouse/gray
body_color = "gray"
icon_state = "mouse_gray"
+ can_be_held = "mouse_gray"
/mob/living/simple_animal/mouse/brown
body_color = "brown"
icon_state = "mouse_brown"
+ can_be_held = "mouse_brown"
//TOM IS ALIVE! SQUEEEEEEEE~K :)
/mob/living/simple_animal/mouse/brown/Tom
@@ -118,3 +122,8 @@
/obj/item/reagent_containers/food/snacks/deadmouse/on_grind()
reagents.clear_reagents()
+
+/mob/living/simple_animal/mouse/generate_mob_holder()
+ var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, (istext(can_be_held) ? can_be_held : ""), 'icons/mob/animals_held.dmi', 'icons/mob/animals_held_lh.dmi', 'icons/mob/animals_held_rh.dmi')
+ holder.w_class = WEIGHT_CLASS_TINY
+ return holder
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/friendly/sloth.dm b/code/modules/mob/living/simple_animal/friendly/sloth.dm
index 324fa107..175cb8e8 100644
--- a/code/modules/mob/living/simple_animal/friendly/sloth.dm
+++ b/code/modules/mob/living/simple_animal/friendly/sloth.dm
@@ -22,7 +22,7 @@
maxHealth = 50
speed = 10
glide_size = 2
-
+ can_be_held = "sloth" //finally oranges can be held
do_footstep = TRUE
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index 871fd32b..1d152f72 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -102,9 +102,17 @@
return ..()
/obj/machinery/disposal/proc/place_item_in_disposal(obj/item/I, mob/user)
- I.forceMove(src)
- user.visible_message("[user.name] places \the [I] into \the [src].", "You place \the [I] into \the [src].")
-
+ if(istype(I, /obj/item/clothing/head/mob_holder))
+ var/obj/item/clothing/head/mob_holder/H = I
+ var/mob/living/m = H.held_mob
+ H.release()
+ if(m)
+ user.start_pulling(m, 1)
+ stuff_mob_in(m,user)
+ return//you don't want this going into disposals ever
+ if(user.temporarilyRemoveItemFromInventory(I)) //double-checks never hurt
+ I.forceMove(src)
+ user.visible_message("[user.name] places \the [I] into \the [src].", "You place \the [I] into \the [src].")
//mouse drop another mob or self
/obj/machinery/disposal/MouseDrop_T(mob/living/target, mob/living/user)
if(istype(target))
diff --git a/hyperstation/code/modules/resize/holder_micro.dm b/hyperstation/code/modules/resize/holder_micro.dm
new file mode 100644
index 00000000..6f3d7806
--- /dev/null
+++ b/hyperstation/code/modules/resize/holder_micro.dm
@@ -0,0 +1,8 @@
+// Micro Holders - Extends /obj/item/holder
+
+/obj/item/clothing/head/mob_holder/micro
+ name = "micro"
+ desc = "Another person, small enough to fit in your hand."
+ icon = null // I forgot how to fix this.
+ icon_state = ""
+ slot_flags = ITEM_SLOT_FEET | ITEM_SLOT_HEAD | ITEM_SLOT_ID
\ No newline at end of file
diff --git a/hyperstation/code/modules/resize/resizing.dm b/hyperstation/code/modules/resize/resizing.dm
new file mode 100644
index 00000000..0fc6a9dc
--- /dev/null
+++ b/hyperstation/code/modules/resize/resizing.dm
@@ -0,0 +1,160 @@
+//LETS GET THIS FUCKING SIZECONTENT GAMERS
+var/const/RESIZE_MACRO = 6
+var/const/RESIZE_HUGE = 4
+var/const/RESIZE_BIG = 2
+var/const/RESIZE_NORMAL = 1
+var/const/RESIZE_SMALL = 0.75
+var/const/RESIZE_TINY = 0.50
+var/const/RESIZE_MICRO = 0.25
+
+//averages
+var/const/RESIZE_A_MACROHUGE = (RESIZE_MACRO + RESIZE_HUGE) / 2
+var/const/RESIZE_A_HUGEBIG = (RESIZE_HUGE + RESIZE_BIG) / 2
+var/const/RESIZE_A_BIGNORMAL = (RESIZE_BIG + RESIZE_NORMAL) / 2
+var/const/RESIZE_A_NORMALSMALL = (RESIZE_NORMAL + RESIZE_SMALL) / 2
+var/const/RESIZE_A_SMALLTINY = (RESIZE_SMALL + RESIZE_TINY) / 2
+var/const/RESIZE_A_TINYMICRO = (RESIZE_TINY + RESIZE_MICRO) / 2
+
+//Scale up a mob's icon by the size_multiplier
+/mob/living/update_transform()
+ ASSERT(!iscarbon(src)) //the source isnt carbon should always be true
+ var/matrix/M = matrix() //matrix (M) variable
+ M.Scale(size_multiplier)
+ M.Translate(0, 16*(size_multiplier-1)) //translate by 16 * size_multiplier - 1 on Y axis
+ src.transform = M //the source of transform is M
+
+
+/mob/proc/get_effective_size()
+ return 100000
+
+mob/living/get_effective_size()
+ return src.size_multiplier
+
+/mob/living/proc/resize(var/new_size, var/animate = TRUE)
+ if(size_multiplier == new_size)
+ return 1
+
+ size_multiplier = new_size //Change size_multiplier so that other items can interact with them
+ src.update_transform() //WORK DAMN YOU
+
+//handle the big steppy, except nice
+/mob/living/proc/handle_micro_bump_helping(var/mob/living/tmob)
+
+ //Both small.
+ if(src.get_effective_size() <= RESIZE_A_SMALLTINY && tmob.get_effective_size() <= RESIZE_A_SMALLTINY)
+ now_pushing = 0
+ src.forceMove(tmob.loc)
+ return 1
+
+ //Doing messages
+ if(abs(get_effective_size()/tmob.get_effective_size()) >= 2) //if the initiator is twice the size of the micro
+ now_pushing = 0
+ src.forceMove(tmob.loc)
+
+ //Smaller person being stepped on
+ if(get_effective_size() > tmob.get_effective_size() && iscarbon(src))
+ if(istype(tmob) && istype(tmob, /datum/sprite_accessory/taur/naga))
+ to_chat(src,"You carefully slither around [tmob].")
+ to_chat(tmob,"[src]'s huge tail slithers beside you!")
+ else
+ to_chat(src,"You carefully step over [tmob].")
+ to_chat(tmob,"[src] steps over you carefully!")
+ return 1
+
+ //Smaller person stepping under a larger person
+ if(tmob.get_effective_size() > get_effective_size())
+ micro_step_under(tmob)
+ src.forceMove(tmob.loc)
+ now_pushing = 0
+ return 1
+
+//Stepping on disarm intent
+/mob/living/proc/handle_micro_bump_other(var/mob/living/tmob)
+ ASSERT(isliving(tmob))
+
+ //Both small
+ if(src.get_effective_size() <= RESIZE_A_SMALLTINY && tmob.get_effective_size() <= RESIZE_A_SMALLTINY)
+ now_pushing = 0
+ src.forceMove(tmob.loc)
+ return 1
+
+ if(abs(get_effective_size()/tmob.get_effective_size()) >= 2)
+ if(src.a_intent == "disarm" && src.canmove && !src.buckled)
+ now_pushing = 0
+ src.forceMove(tmob.loc)
+ if(get_effective_size() > tmob.get_effective_size() && iscarbon(src))
+ if(istype(tmob) && istype(tmob, /datum/sprite_accessory/taur/naga))
+ to_chat(src,"You carefully roll over [tmob] with your tail!")
+ to_chat(tmob,"[src]'s huge tail rolls over you!")
+ sizediffStamLoss(tmob)
+ else
+ to_chat(src,"You painfully but harmlessly step on [tmob]!")
+ to_chat(tmob,"[src] steps onto you with force!")
+ sizediffStamLoss(tmob)
+ return 1
+
+ if(src.a_intent == "harm" && src.canmove && !src.buckled)
+ now_pushing = 0
+ src.forceMove(tmob.loc)
+ if(get_effective_size() > tmob.get_effective_size() && iscarbon(src))
+ if(istype(tmob) && istype(tmob, /datum/sprite_accessory/taur/naga))
+ to_chat(src,"You grind [tmob] into the floor with your tail!")
+ to_chat(tmob,"[src]'s massive tail plows you into the floor!")
+ sizediffStamLoss(tmob)
+ sizediffBruteloss(tmob)
+ else
+ to_chat(src,"You pound [tmob] into the floor underfoot!")
+ to_chat(tmob,"[src] slams you into the ground, crushing you!")
+ sizediffStamLoss(tmob)
+ sizediffBruteloss(tmob)
+ return 1
+
+// if(src.a_inent == "grab"... goes here
+
+ if(tmob.get_effective_size() > get_effective_size())
+ micro_step_under(tmob)
+ src.forceMove(tmob.loc)
+ now_pushing = 0
+ return 1
+
+//smaller person stepping under another person
+/mob/living/proc/micro_step_under(var/mob/living/tmob)
+ if(istype(tmob) && istype(tmob, /datum/sprite_accessory/taur/naga))
+ to_chat(src,"You jump over [tmob]'s thick tail.")
+ to_chat(tmob,"[src] bounds over your tail.")
+ else
+ to_chat(src,"You run between [tmob]'s legs.")
+ to_chat(tmob,"[src] runs between your legs.")
+
+//Proc for scaling stamina damage on size difference
+/mob/living/proc/sizediffStamLoss(var/mob/living/tmob)
+ var/S = (get_effective_size()/tmob.get_effective_size()*25) //macro divided by micro, times 25
+ tmob.Knockdown(S) //final result in stamina knockdown
+
+//Proc for scaling brute damage on size difference
+/mob/living/proc/sizediffBruteloss(var/mob/living/tmob)
+ var/B = (get_effective_size()/tmob.get_effective_size()*2) //macro divided by micro, times 2
+ tmob.adjustBruteLoss(B) //final result in brute loss
+
+//Proc for picking up people. WIP.
+/*
+/mob/living/proc/attempt_to_scoop(var/mob/living/M)
+ var/sizediv = get_effective_size()/M.get_effective_size()
+ if(!holder_default && holder_type)
+ holder_default = holder_type
+ if(!istype(M))
+ return 0
+ if(buckled)
+ to_chat(src,"You have to unbuckle them before you can pick them up.")
+ return 0
+ if(sizediv >= 2)
+ holder_type = /obj/item/holder/micro
+ var/obj/item/holder/m_holder = get_scooped(M)
+ holder_type = holder_default
+ if (m_holder)
+ return 1
+ else
+ return 0
+*/
+
+//Clothes coming off at different sizes, and health/speed/stam changes as well
diff --git a/hyperstation/code/modules/resize/sizechems.dm b/hyperstation/code/modules/resize/sizechems.dm
new file mode 100644
index 00000000..90deb236
--- /dev/null
+++ b/hyperstation/code/modules/resize/sizechems.dm
@@ -0,0 +1,40 @@
+//Size Chemicals, now with better and less cringy names.
+
+/datum/reagent/dahl/growthchem
+ name = "Prospacillin"
+ id = "growthchem"
+ description = "A stabilized altercation of size-altering liquids, this one appears to increase cell volume."
+ color = "#E70C0C"
+ taste_description = "a sharp, fiery and intoxicating flavour."
+ overdose_threshold = 10
+ metabolization_rate = 0.25
+ can_synth = FALSE //DO NOT MAKE THIS SNYTHESIZABLE, THESE CHEMS ARE SUPPOSED TO NOT BE USED COMMONLY
+
+/datum/reagent/dahl/growthchem/on_mob_add(mob/living/carbon/M)
+ log_game("SIZECODE: [M] ckey: [M.key] has ingested growthchem.")
+
+/datum/reagent/dahl/growthchem/on_mob_life(mob/living/carbon/M)
+ if(M.size_multiplier < RESIZE_MACRO)
+ M.resize(M.size_multiplier+0.01)
+
+ return
+
+/datum/reagent/dahl/shrinkchem
+ name = "Diminicillin"
+ id = "shrinkchem"
+ description = "A stabilized altercation of size-altering liquids, this one appears to decrease cell volume."
+ color = "#0C26E7"
+ taste_description = "a pungent, acidic and jittery flavour."
+ overdose_threshold = 10
+ metabolization_rate = 0.25
+ can_synth = FALSE //SAME STORY AS ABOVE
+
+/datum/reagent/dahl/shrinkchem/on_mob_add(mob/living/carbon/M)
+ log_game("SIZECODE: [M] ckey: [M.key] has ingested shrinkchem.")
+
+/datum/reagent/dahl/shrinkchem/on_mob_life(mob/living/carbon/M)
+ if(M.size_multiplier > RESIZE_MICRO)
+ M.resize(M.size_multiplier-0.01)
+
+ return
+
diff --git a/hyperstation/code/modules/resize/sizegun.dm b/hyperstation/code/modules/resize/sizegun.dm
new file mode 100644
index 00000000..d1154838
--- /dev/null
+++ b/hyperstation/code/modules/resize/sizegun.dm
@@ -0,0 +1,86 @@
+/obj/item/projectile/sizelaser
+ name = "sizeray laser"
+ icon_state = "omnilaser"
+ hitsound = null
+ damage = 5
+ damage_type = STAMINA
+ flag = "laser"
+ pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
+
+/obj/item/projectile/sizelaser/shrinkray
+ icon_state="bluelaser"
+
+/obj/item/projectile/sizelaser/growthray
+ icon_state="laser"
+
+/obj/item/projectile/sizelaser/shrinkray/on_hit(var/atom/target, var/blocked = 0)
+ if(istype(target, /mob/living/carbon/human))
+ var/mob/living/M = target
+ switch(M.size_multiplier)
+ if(RESIZE_MACRO to INFINITY)
+ M.resize(RESIZE_HUGE)
+ if(RESIZE_HUGE to RESIZE_MACRO)
+ M.resize(RESIZE_BIG)
+ if(RESIZE_BIG to RESIZE_HUGE)
+ M.resize(RESIZE_NORMAL)
+ if(RESIZE_NORMAL to RESIZE_BIG)
+ M.resize(RESIZE_SMALL)
+ if(RESIZE_SMALL to RESIZE_NORMAL)
+ M.resize(RESIZE_TINY)
+ if(RESIZE_TINY to RESIZE_SMALL)
+ M.resize(RESIZE_MICRO)
+ if((0 - INFINITY) to RESIZE_NORMAL)
+ M.resize(RESIZE_MICRO)
+ M.update_transform()
+ return 1
+
+/obj/item/projectile/sizelaser/growthray/on_hit(var/atom/target, var/blocked = 0 )
+ if(istype(target, /mob/living/carbon/human))
+ var/mob/living/M = target
+ switch(M.size_multiplier)
+ if(RESIZE_HUGE to RESIZE_MACRO)
+ M.resize(RESIZE_MACRO)
+ if(RESIZE_BIG to RESIZE_HUGE)
+ M.resize(RESIZE_HUGE)
+ if(RESIZE_NORMAL to RESIZE_BIG)
+ M.resize(RESIZE_BIG)
+ if(RESIZE_SMALL to RESIZE_NORMAL)
+ M.resize(RESIZE_NORMAL)
+ if(RESIZE_TINY to RESIZE_SMALL)
+ M.resize(RESIZE_SMALL)
+ if(RESIZE_MICRO to RESIZE_TINY)
+ M.resize(RESIZE_TINY)
+ if((0 - INFINITY) to RESIZE_MICRO)
+ M.resize(RESIZE_MICRO)
+ M.update_transform()
+ return 1
+
+/obj/item/ammo_casing/energy/laser/growthray
+ projectile_type = /obj/item/projectile/sizelaser/growthray
+ select_name = "Growth"
+
+/obj/item/ammo_casing/energy/laser/shrinkray
+ projectile_type = /obj/item/projectile/sizelaser/shrinkray
+ select_name = "Shrink"
+
+//Gun
+/obj/item/gun/energy/laser/sizeray
+ name = "size ray"
+ icon_state = "bluetag"
+ desc = "Debug size manipulator. You probably shouldn't have this!"
+ item_state = null
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray, /obj/item/ammo_casing/energy/laser/growthray)
+ selfcharge = EGUN_SELFCHARGE
+ charge_delay = 5
+ ammo_x_offset = 2
+ clumsy_check = 1
+
+ attackby(obj/item/W, mob/user)
+ if(W==src)
+ if(icon_state=="bluetag")
+ icon_state="redtag"
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/growthray)
+ else
+ icon_state="bluetag"
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray)
+ return ..()
diff --git a/icons/mob/animals_held.dmi b/icons/mob/animals_held.dmi
new file mode 100644
index 00000000..82a065d9
Binary files /dev/null and b/icons/mob/animals_held.dmi differ
diff --git a/icons/mob/animals_held_lh.dmi b/icons/mob/animals_held_lh.dmi
new file mode 100644
index 00000000..6c407c85
Binary files /dev/null and b/icons/mob/animals_held_lh.dmi differ
diff --git a/icons/mob/animals_held_rh.dmi b/icons/mob/animals_held_rh.dmi
new file mode 100644
index 00000000..322dad06
Binary files /dev/null and b/icons/mob/animals_held_rh.dmi differ