diff --git a/code/__DEFINES/~~~splurt_defines/dcs/signals.dm b/code/__DEFINES/~~~splurt_defines/dcs/signals.dm
new file mode 100644
index 0000000000000..83d0cbf595380
--- /dev/null
+++ b/code/__DEFINES/~~~splurt_defines/dcs/signals.dm
@@ -0,0 +1,13 @@
+/*
+ * # COMSIG_MICRO_PICKUP_FEET
+ * From /datum/element/mob_holder/micro
+ * Used by signals for determining whether you can pick up someone with your feet, kinky.
+*/
+#define COMSIG_MICRO_PICKUP_FEET "micro_force_grabbed"
+
+/*
+ * # COMSIG_MOB_RESIZED
+ * From /mob/living
+ * Used by signals for whenever a mob has changed sizes.
+*/
+#define COMSIG_MOB_RESIZED "mob_resized"
diff --git a/code/__DEFINES/~~~splurt_defines/sizecode.dm b/code/__DEFINES/~~~splurt_defines/sizecode.dm
new file mode 100644
index 0000000000000..20a7bd30d1a00
--- /dev/null
+++ b/code/__DEFINES/~~~splurt_defines/sizecode.dm
@@ -0,0 +1,46 @@
+//I am not a coder. Please fucking tear apart my code, and insult me for how awful I am at coding. Please and thank you. -Dahlular
+//alright bet -BoxBoy
+#define RESIZE_MACRO 6
+#define RESIZE_HUGE 4
+#define RESIZE_BIG 2
+#define RESIZE_NORMAL 1
+#define RESIZE_SMALL 0.75
+#define RESIZE_TINY 0.50
+#define RESIZE_MICRO 0.25
+
+//averages
+#define RESIZE_A_MACROHUGE (RESIZE_MACRO + RESIZE_HUGE) / 2
+#define RESIZE_A_HUGEBIG (RESIZE_HUGE + RESIZE_BIG) / 2
+#define RESIZE_A_BIGNORMAL (RESIZE_BIG + RESIZE_NORMAL) / 2
+#define RESIZE_A_NORMALSMALL (RESIZE_NORMAL + RESIZE_SMALL) / 2
+#define RESIZE_A_SMALLTINY (RESIZE_SMALL + RESIZE_TINY) / 2
+#define RESIZE_A_TINYMICRO (RESIZE_TINY + RESIZE_MICRO) / 2
+
+/*
+ * # get_size(mob/living/target)
+ * Grabs the size of your critter, works for any living creature even carbons with dna
+ * Now, please don't tell me your creature has a dna but it's very snowflakey, then i say you should rewrite your mob
+ * instead of touching this file.
+*/
+/proc/get_size(mob/living/target)
+ if(!target)
+ CRASH("get_size(NULL) was called")
+ if(!istype(target))
+ CRASH("get_size() called with an invalid target, only use this for /mob/living!")
+ var/datum/dna/has_dna = target.has_dna()
+ if(ishuman(target) && has_dna)
+ return has_dna.features["body_size"]
+ else
+ return target.size_multiplier
+
+/*
+ * # COMPARE_SIZES(mob/living/user, mob/living/target)
+ * Returns how bigger or smaller the target is in comparison to user
+ * Example:
+ * - user = 2, target = 1, result = 0.5
+ * - user = 1, target = 2, result = 2
+ * Args:
+ * - user = /mob/living
+ * - target = /mob/living
+*/
+#define COMPARE_SIZES(user, target) abs((get_size(user) / get_size(target)))
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index 6d972b674adf6..08e862aaf519f 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -135,6 +135,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = FALSE, transfer_species = TRUE)
if(!istype(destination))
return
+ var/old_size = destination.dna.features["body_size"]
destination.dna.unique_enzymes = unique_enzymes
destination.dna.unique_identity = unique_identity
destination.dna.blood_type = blood_type
@@ -145,7 +146,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
//SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION
destination.dna.mutant_bodyparts = mutant_bodyparts.Copy()
destination.dna.body_markings = body_markings.Copy()
- destination.dna.update_body_size()
+ destination.update_size(get_size(destination), old_size)
//SKYRAT EDIT ADDITION END
if(transfer_SE)
destination.dna.mutation_index = mutation_index
@@ -647,6 +648,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
dna.features = newfeatures
dna.generate_unique_features()
+ var/old_size = dna.features["body_size"]
+ dna.features = newfeatures
+ update_size(get_size(src), old_size)
+
if(mrace)
var/datum/species/newrace = new mrace.type
newrace.copy_properties_from(mrace)
diff --git a/code/datums/elements/mob_holder.dm b/code/datums/elements/mob_holder.dm
new file mode 100644
index 0000000000000..7013e79fa62a3
--- /dev/null
+++ b/code/datums/elements/mob_holder.dm
@@ -0,0 +1,79 @@
+/datum/element/mob_holder
+ element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH_ON_HOST_DESTROY
+ argument_hash_start_idx = 2
+ var/worn_state
+ var/alt_worn
+ var/right_hand
+ var/left_hand
+ var/inv_slots
+ var/proctype //if present, will be invoked on headwear generation.
+
+/datum/element/mob_holder/Attach(datum/target, worn_state, alt_worn, right_hand, left_hand, inv_slots = NONE, proctype)
+ . = ..()
+
+ if(!isliving(target))
+ return ELEMENT_INCOMPATIBLE
+
+ src.worn_state = worn_state
+ src.alt_worn = alt_worn
+ src.right_hand = right_hand
+ src.left_hand = left_hand
+ src.inv_slots = inv_slots
+ src.proctype = proctype
+
+ RegisterSignal(target, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item))
+ RegisterSignal(target, COMSIG_CLICK_ALT, PROC_REF(mob_try_pickup))
+ RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
+
+/datum/element/mob_holder/Detach(datum/source, force)
+ . = ..()
+ UnregisterSignal(source, list(COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, COMSIG_CLICK_ALT, COMSIG_ATOM_EXAMINE))
+
+/datum/element/mob_holder/proc/on_examine(mob/living/source, mob/user, list/examine_list)
+ if(ishuman(user) && !istype(source.loc, /obj/item/clothing/head/mob_holder))
+ examine_list += span_notice("Looks like [source.p_they(FALSE)] can be picked up with Alt+Click!")
+
+/datum/element/mob_holder/proc/on_requesting_context_from_item(
+ obj/source,
+ list/context,
+ obj/item/held_item,
+ mob/living/user,
+)
+ SIGNAL_HANDLER
+
+ if(ishuman(user))
+ LAZYSET(context, SCREENTIP_CONTEXT_ALT_LMB, "Pick up")
+ return CONTEXTUAL_SCREENTIP_SET
+
+/datum/element/mob_holder/proc/mob_try_pickup(mob/living/source, mob/user)
+ if(!ishuman(user) || !user.Adjacent(source) || user.incapacitated())
+ return FALSE
+ if(user.get_active_held_item())
+ to_chat(user, span_warning("Your hands are full!"))
+ return FALSE
+ if(source.buckled)
+ to_chat(user, span_warning("[source] is buckled to something!"))
+ return FALSE
+ if(source == user)
+ to_chat(user, span_warning("You can't pick yourself up."))
+ return FALSE
+ source.visible_message(span_warning("[user] starts picking up [source]."), \
+ span_userdanger("[user] starts picking you up!"))
+ if(!do_after(user, 2 SECONDS, target = source) || source.buckled)
+ return FALSE
+
+ source.visible_message(span_warning("[user] picks up [source]!"), \
+ span_userdanger("[user] picks you up!"))
+ to_chat(user, span_notice("You pick [source] up."))
+ source.drop_all_held_items()
+ var/obj/item/clothing/head/mob_holder/holder = new(get_turf(source), source, worn_state, alt_worn, right_hand, left_hand, inv_slots)
+
+ if(proctype)
+ INVOKE_ASYNC(src, proctype, source, holder, user)
+ user.put_in_hands(holder)
+ return TRUE
+
+/datum/element/mob_holder/proc/drone_worn_icon(mob/living/basic/drone/D, obj/item/clothing/head/mob_holder/holder, mob/user)
+ var/new_state = "[D.visualAppearance]_hat"
+ holder.inhand_icon_state = new_state
+ holder.icon_state = new_state
diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm
index d9cb4aabd2580..50e3ea2b70958 100644
--- a/code/datums/mutations/body.dm
+++ b/code/datums/mutations/body.dm
@@ -200,7 +200,7 @@
return
// SKYRAT EDIT END
ADD_TRAIT(owner, TRAIT_GIANT, GENETIC_MUTATION)
- owner.update_transform(1.25)
+ owner.update_size(1.25)
owner.visible_message(span_danger("[owner] suddenly grows!"), span_notice("Everything around you seems to shrink.."))
/datum/mutation/human/gigantism/on_losing(mob/living/carbon/human/owner)
@@ -212,6 +212,7 @@
REMOVE_TRAIT(owner, TRAIT_GIANT, GENETIC_MUTATION)
return
// SKYRAT EDIT END
+ owner.update_size(0.75)
//Clumsiness has a very large amount of small drawbacks depending on item.
/datum/mutation/human/clumsy
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index f6d477afbb923..fdb2d0b920c9c 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -52,6 +52,8 @@
// such that you never actually cared about checking if something is *edible*.
var/obj/item/food/clothing/moth_snack
+ var/ignore_abstract = FALSE
+
/obj/item/clothing/Initialize(mapload)
if(clothing_flags & VOICEBOX_TOGGLABLE)
actions_types += list(/datum/action/item_action/toggle_voice_box)
@@ -60,7 +62,7 @@
if(can_be_bloody && ((body_parts_covered & FEET) || (flags_inv & HIDESHOES)))
LoadComponent(/datum/component/bloodysoles)
AddElement(/datum/element/attack_equip)
- if(!icon_state)
+ if(!icon_state && !ignore_abstract)
item_flags |= ABSTRACT
/obj/item/clothing/mouse_drop_dragged(atom/over_object, mob/user, src_location, over_location, params)
diff --git a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/fugu_gland.dm b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/fugu_gland.dm
index f936caa1d51ef..f2cf66be23a62 100644
--- a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/fugu_gland.dm
+++ b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/fugu_gland.dm
@@ -36,7 +36,7 @@
animal.health = min(animal.maxHealth, animal.health * 1.5)
animal.melee_damage_lower = max((animal.melee_damage_lower * 2), 10)
animal.melee_damage_upper = max((animal.melee_damage_upper * 2), 10)
- animal.update_transform(2)
+ animal.update_size(2)
animal.AddElement(/datum/element/wall_tearer)
to_chat(user, span_info("You increase the size of [animal], giving [animal.p_them()] a surge of strength!"))
qdel(src)
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 68d4c211f6b31..e06bd3ffc2548 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -176,6 +176,16 @@
if (length(status_examines))
. += status_examines
+ //Approximate character height based on current sprite scale
+ var/dispSize = round(12*get_size(src)) // gets the character's sprite size percent and converts it to the nearest half foot
+ if(dispSize % 2) // returns 1 or 0. 1 meaning the height is not exact and the code below will execute, 0 meaning the height is exact and the else will trigger.
+ dispSize = dispSize - 1 //makes it even
+ dispSize = dispSize / 2 //rounds it out
+ . += "[t_He] appear\s to be around [dispSize] and a half feet tall."
+ else
+ dispSize = dispSize / 2
+ . += "[t_He] appear\s to be around [dispSize] feet tall."
+
var/appears_dead = FALSE
var/just_sleeping = FALSE
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 717762a408d12..95d64fa59fbae 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -344,6 +344,12 @@
//called when something steps onto a human
/mob/living/carbon/human/proc/on_entered(datum/source, atom/movable/AM)
SIGNAL_HANDLER
+
+ //Hyper Change - Step on people
+ var/mob/living/carbon/human/H = AM
+ if(istype(H) && resting && resolve_intent_name(H.combat_mode) != "help")
+ H.handle_micro_bump_other(src)
+
spreadFire(AM)
/mob/living/carbon/human/proc/canUseHUD()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index b0cf90334bec5..fcda93b77dee4 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -220,6 +220,11 @@
if(moving_diagonally)//no mob swap during diagonal moves.
return TRUE
+ //handle micro bumping on help intent
+ if(resolve_intent_name(combat_mode) == "help")
+ if(handle_micro_bump_helping(M))
+ return TRUE
+
if(!M.buckled && !M.has_buckled_mobs())
if(can_mobswap_with(M))
//switch our position with M
@@ -254,6 +259,8 @@
//not if he's not CANPUSH of course
if(!(M.status_flags & CANPUSH))
return TRUE
+ if(handle_micro_bump_other(M))
+ return TRUE
if(isliving(M))
var/mob/living/L = M
if(HAS_TRAIT(L, TRAIT_PUSHIMMUNE))
@@ -2045,10 +2052,11 @@ GLOBAL_LIST_EMPTY(fire_appearances)
set_body_position(var_value)
. = TRUE
if(NAMEOF(src, current_size))
- if(var_value == 0) //prevents divisions of and by zero.
- return FALSE
- update_transform(var_value/current_size)
- . = TRUE
+ update_size(var_value)
+ return TRUE
+ if(NAMEOF(src, size_multiplier))
+ update_size(var_value)
+ return TRUE
if(!isnull(.))
datum_flags |= DF_VAR_EDITED
diff --git a/modular_zubbers/code/datums/components/vore/_defines.dm b/modular_zubbers/code/datums/components/vore/_defines.dm
index 48c7d797be585..1450524d91982 100644
--- a/modular_zubbers/code/datums/components/vore/_defines.dm
+++ b/modular_zubbers/code/datums/components/vore/_defines.dm
@@ -23,7 +23,7 @@
/// If true, prevents mobs in crit or death from engaging in vore
#define NO_DEAD TRUE
/// If true, mobs with no player cannot be pred or prey
-#define REQUIRES_PLAYER TRUE
+#define REQUIRES_PLAYER FALSE
/// Makes every mob spawn with a vore component, just for testing
// #define VORE_TESTING_ALL_MOBS_ARE_VORE_MOBS
/// Number of rolling backups bellies will keep
diff --git a/modular_zubbers/code/datums/components/vore/vore.dm b/modular_zubbers/code/datums/components/vore/vore.dm
index a2f94d0f05af1..9b7c6dc6728da 100644
--- a/modular_zubbers/code/datums/components/vore/vore.dm
+++ b/modular_zubbers/code/datums/components/vore/vore.dm
@@ -237,13 +237,13 @@
vore_mode_action.unset_ranged_ability(user)
vore_mode_action.build_all_button_icons(UPDATE_BUTTON_BACKGROUND | UPDATE_BUTTON_STATUS)
- if(!check_vore_grab(user))
+ if(!check_vore_grab(user, clicked_on))
to_chat(user, span_danger("You must have an aggressive grab to do vore."))
return TRUE
var/mob/living/pulled = user.pulling
if(clicked_on == user) // Parent wants to eat pulled
- vore_other()
+ vore_other(clicked_on)
else if(clicked_on == pulled) // Parent wants to feed themselves to pulled
feed_self_to_other()
else // Parent wants to feed pulled to clicked_on
@@ -362,75 +362,84 @@
return TRUE
-/proc/check_vore_grab(mob/living/grabber)
- var/mob/living/grabee = grabber.pulling
- if(!istype(grabee))
+/proc/check_vore_grab(mob/living/grabber, mob/living/grabbed)
+ . = FALSE
+ if(QDELETED(grabber))
return FALSE
- if(ishuman(grabber) && grabber.grab_state < GRAB_AGGRESSIVE)
+ if(QDELETED(grabbed))
return FALSE
+ if(ishuman(grabber) && grabber.grab_state >= GRAB_AGGRESSIVE)
+ . = TRUE
+ if(istype(grabbed.loc, /obj/item/clothing/head/mob_holder))
+ . = TRUE
return TRUE
-/datum/component/vore/proc/vore_other()
+/datum/component/vore/proc/vore_other(mob/living/prey)
var/mob/living/pred = parent
- if(!check_vore_grab(pred))
+ if(!prey)
+ prey = pred.pulling
+ if(!check_vore_grab(pred, prey))
to_chat(parent, span_danger("You must have a[ishuman(pred) ? "n aggressive" : ""] grab to eat someone."))
- return
- var/mob/living/prey = pred.pulling
+ return FALSE
if(!check_vore_preferences(parent, pred, prey))
- return
+ return FALSE
#ifdef VORE_DELAY
pred.visible_message(span_danger("[pred] is attempting to [lowertext(selected_belly.insert_verb)] [prey] into their [lowertext(selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
if(!do_after(pred, VORE_DELAY, prey))
- return
- if(!check_vore_grab(pred) || !check_vore_preferences(parent, pred, prey, assume_active_consent = TRUE))
- return
+ return FALSE
+ if(!check_vore_grab(pred, prey) || !check_vore_preferences(parent, pred, prey, assume_active_consent = TRUE))
+ return FALSE
#endif
pred.visible_message(span_danger("[pred] manages to [lowertext(selected_belly.insert_verb)] [prey] into their [lowertext(selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
complete_vore(prey)
+ return TRUE
/datum/component/vore/proc/feed_self_to_other()
var/mob/living/prey = parent
- if(!check_vore_grab(prey))
- to_chat(parent, span_danger("You must have a[ishuman(prey) ? "n aggressive" : ""] grab to feed yourself to someone."))
- return
var/mob/living/pred = prey.pulling
+ if(!check_vore_grab(prey, pred))
+ to_chat(parent, span_danger("You must have a[ishuman(prey) ? "n aggressive" : ""] grab to feed yourself to someone."))
+ return FALSE
if(!check_vore_preferences(parent, pred, prey))
- return
+ return FALSE
// check_vore_preferences asserts this exists
var/datum/component/vore/pred_component = pred.GetComponent(/datum/component/vore)
#ifdef VORE_DELAY
prey.visible_message(span_danger("[prey] is attempting to make [pred] [lowertext(pred_component.selected_belly.insert_verb)] [prey] into their [lowertext(pred_component.selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
if(!do_after(prey, VORE_DELAY, pred))
- return
- if(!check_vore_grab(prey) || !check_vore_preferences(parent, pred, prey, assume_active_consent = TRUE))
- return
+ return FALSE
+ if(!check_vore_grab(prey, pred) || !check_vore_preferences(parent, pred, prey, assume_active_consent = TRUE))
+ return FALSE
#endif
prey.visible_message(span_danger("[prey] manages to make [pred] [lowertext(pred_component.selected_belly.insert_verb)] [prey] into their [lowertext(pred_component.selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
pred_component.complete_vore(prey)
+ return TRUE
-/datum/component/vore/proc/feed_other_to_other(mob/living/pred)
+/datum/component/vore/proc/feed_other_to_other(mob/living/pred, mob/living/prey)
var/mob/living/feeder = parent
- if(!check_vore_grab(feeder))
+ if(!prey)
+ prey = feeder.pulling
+ if(!check_vore_grab(feeder, prey))
to_chat(feeder, span_danger("You must have a[ishuman(feeder) ? "n aggressive" : ""] grab to feed someone to someone else."))
- return
+ return FALSE
if(!feeder.can_perform_action(pred, pred.interaction_flags_click | FORBID_TELEKINESIS_REACH))
- return
- var/mob/living/prey = feeder.pulling
+ return FALSE
if(!check_vore_preferences(feeder, pred, prey))
- return
+ return FALSE
// check_vore_preferences asserts this exists
var/datum/component/vore/pred_component = pred.GetComponent(/datum/component/vore)
#ifdef VORE_DELAY
feeder.visible_message(span_danger("[feeder] is attempting to make [pred] [lowertext(pred_component.selected_belly.insert_verb)] [prey] into their [lowertext(pred_component.selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
if(!do_after(feeder, VORE_DELAY, pred))
- return
- if(!check_vore_grab(feeder) || !check_vore_preferences(feeder, pred, prey, assume_active_consent = TRUE))
- return
+ return FALSE
+ if(!check_vore_grab(feeder, prey) || !check_vore_preferences(feeder, pred, prey, assume_active_consent = TRUE))
+ return FALSE
if(!feeder.can_perform_action(pred, pred.interaction_flags_click | FORBID_TELEKINESIS_REACH))
- return
+ return FALSE
#endif
feeder.visible_message(span_danger("[feeder] manages to make [pred] [lowertext(pred_component.selected_belly.insert_verb)] [prey] into their [lowertext(pred_component.selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
pred_component.complete_vore(prey)
+ return TRUE
/datum/component/vore/proc/complete_vore(mob/living/prey)
prey.forceMove(selected_belly)
diff --git a/modular_zzplurt/code/datums/elements/holder_micro.dm b/modular_zzplurt/code/datums/elements/holder_micro.dm
new file mode 100644
index 0000000000000..f8792d13077a7
--- /dev/null
+++ b/modular_zzplurt/code/datums/elements/holder_micro.dm
@@ -0,0 +1,221 @@
+/datum/element/mob_holder/micro
+
+/datum/element/mob_holder/micro/Attach(datum/target, worn_state, alt_worn, right_hand, left_hand, inv_slots = NONE, proctype, escape_on_find)
+ . = ..()
+
+ RegisterSignal(target, COMSIG_CLICK_ALT, PROC_REF(mob_try_pickup_micro), TRUE)
+ RegisterSignal(target, COMSIG_MICRO_PICKUP_FEET, PROC_REF(mob_pickup_micro_feet))
+ RegisterSignal(target, COMSIG_MOB_RESIZED, PROC_REF(on_resize))
+
+/datum/element/mob_holder/micro/Detach(datum/source, force)
+ . = ..()
+ UnregisterSignal(source, COMSIG_MICRO_PICKUP_FEET)
+
+/datum/element/mob_holder/micro/proc/on_resize(mob/living/micro, new_size, old_size)
+ var/obj/item/clothing/head/mob_holder/holder = micro.loc
+ if(istype(holder))
+ var/mob/living/living = get_atom_on_turf(micro.loc, /mob/living)
+ if(living && (COMPARE_SIZES(living, micro)) < 2.0)
+ living.visible_message(span_warning("\The [living] drops [micro] as [micro.p_they()] grow\s too big to carry."),
+ span_warning("You drop \The [living] as [living.p_they()] grow\s too big to carry."))
+ holder.release()
+ else if(!istype(living)) // Somehow a inside a mob_holder and the mob_holder isn't inside any livings? release.
+ holder.release()
+
+/datum/element/mob_holder/micro/on_examine(mob/living/source, mob/user, list/examine_list)
+ if(ishuman(user) && !istype(source.loc, /obj/item/clothing/head/mob_holder) && (COMPARE_SIZES(user, source)) >= 2.0)
+ examine_list += span_notice("Looks like [source.p_they(FALSE)] can be picked up using Alt+Click and grab intent!")
+
+/// Do not inherit from /mob_holder, interactions are different.
+/datum/element/mob_holder/micro/on_requesting_context_from_item(
+ obj/source,
+ list/context,
+ obj/item/held_item,
+ mob/living/user,
+)
+
+ LAZYSET(context, SCREENTIP_CONTEXT_ALT_LMB, "Pick up")
+ return CONTEXTUAL_SCREENTIP_SET
+
+/datum/element/mob_holder/micro/proc/mob_pickup_micro(mob/living/source, mob/user)
+ var/obj/item/clothing/head/mob_holder/micro/holder = new(get_turf(source), source, worn_state, alt_worn, right_hand, left_hand, inv_slots)
+ if(!holder)
+ return
+
+ user.put_in_hands(holder)
+ return
+
+//shoehorned (get it?) and lazy way to do instant foot pickups cause haha funny.
+/datum/element/mob_holder/micro/proc/mob_pickup_micro_feet(mob/living/source, mob/user)
+ var/obj/item/clothing/head/mob_holder/micro/holder = new(get_turf(source), source, worn_state, alt_worn, right_hand, left_hand, inv_slots)
+ if(!holder)
+ return
+ user.equip_to_slot(holder, ITEM_SLOT_FEET)
+ return
+
+/datum/element/mob_holder/micro/proc/mob_try_pickup_micro(mob/living/carbon/source, mob/living/carbon/user)
+ if(!(resolve_intent_name(user.combat_mode) == "grab"))
+ return FALSE
+ if(!ishuman(user) || !user.Adjacent(source) || user.incapacitated())
+ return FALSE
+ if(source == user)
+ to_chat(user, span_warning("You can't pick yourself up."))
+ source.balloon_alert(user, "cannot pick yourself!")
+ return FALSE
+ if(COMPARE_SIZES(user, source) < 2.0)
+ to_chat(user, span_warning("They're too big to pick up!"))
+ source.balloon_alert(user, "too big to pick up!")
+ return FALSE
+ if(user.get_active_held_item())
+ to_chat(user, span_warning("Your hands are full!"))
+ source.balloon_alert(user, "hands are full!")
+ return FALSE
+ if(source.buckled)
+ to_chat(user, span_warning("[source] is buckled to something!"))
+ source.balloon_alert(user, "buckled to something!")
+ return FALSE
+ source.visible_message(span_warning("[user] starts picking up [source]."), \
+ span_userdanger("[user] starts picking you up!"))
+ source.balloon_alert(user, "picking up")
+ var/time_required = COMPARE_SIZES(source, user) * 4 SECONDS //Scale how fast the pickup will be depending on size difference
+ if(!do_after(user, time_required, source))
+ return FALSE
+
+ if(user.get_active_held_item())
+ to_chat(user, span_warning("Your hands are full!"))
+ source.balloon_alert(user, "hands full!")
+ return FALSE
+ if(source.buckled)
+ to_chat(user, span_warning("[source] is buckled to something!"))
+ source.balloon_alert(user, "buckled!")
+ return FALSE
+
+ source.visible_message(span_warning("[user] picks up [source]!"),
+ span_userdanger("[user] picks you up!"))
+ source.drop_all_held_items()
+ mob_pickup_micro(source, user)
+ return TRUE
+
+/obj/item/clothing/head/mob_holder/micro
+ name = "micro"
+ desc = "Another person, small enough to fit in your hand."
+ icon = 'icons/obj/fluff/general.dmi'
+ icon_state = "error" // Some idiots determined that not having a state makes the item abstract, happy now?
+ worn_icon = null
+ inhand_icon_state = null
+ slot_flags = ITEM_SLOT_FEET | ITEM_SLOT_HEAD | ITEM_SLOT_ID | ITEM_SLOT_BACK | ITEM_SLOT_NECK
+ w_class = null //handled by their size
+ ignore_abstract = TRUE // it didn't help still
+
+/obj/item/clothing/head/mob_holder/micro/container_resist_act(mob/living/resisting)
+ if(resisting.incapacitated())
+ to_chat(resisting, span_warning("You can't escape while you're restrained like this!"))
+ return
+ var/mob/living/carrier = get_atom_on_turf(src, /mob/living)
+ visible_message(span_warning("[resisting] begins to squirm in [carrier]'s grasp!"))
+ var/time_required = COMPARE_SIZES(carrier, resisting) / 4 SECONDS //Scale how fast the resisting will be depending on size difference
+ if(!do_after(resisting, time_required, carrier, IGNORE_TARGET_LOC_CHANGE | IGNORE_HELD_ITEM))
+ if(!resisting || resisting.stat != CONSCIOUS || resisting.loc != src)
+ return
+ visible_message(span_warning("[src] stops resisting."))
+ return
+ visible_message(span_warning("[src] escapes [carrier]!"))
+ release()
+
+/obj/item/clothing/head/mob_holder/micro/assume_air(datum/gas_mixture/giver)
+ var/turf/location = get_turf(src)
+ return location.assume_air(giver)
+
+/obj/item/clothing/head/mob_holder/micro/remove_air(amount)
+ var/turf/location = get_turf(src)
+ return location.remove_air(amount)
+
+/obj/item/clothing/head/mob_holder/micro/return_air()
+ var/turf/location = get_turf(src)
+ return location.return_air()
+
+/obj/item/clothing/head/mob_holder/micro/mouse_drop_dragged(atom/M, mob/user, src_location, over_location, params)
+ . = ..()
+ if(M != usr)
+ return
+ if(usr == src)
+ return
+ if(!Adjacent(usr))
+ return
+ if(istype(M,/mob/living/silicon/ai))
+ return
+ var/mob/living/carbon/human/O = held_mob
+ if(istype(O))
+ O.MouseDrop(usr)
+
+/obj/item/clothing/head/mob_holder/micro/attack_self(mob/living/user)
+ if(world.time <= user.next_click)
+ return
+ user.changeNext_move(CLICK_CD_MELEE)
+ var/mob/living/carbon/human/M = held_mob
+ if(istype(M))
+ switch(resolve_intent_name(user.combat_mode))
+ if("harm") //TO:DO, rework all of these interactions to be a lot more in depth
+ visible_message(span_danger("[user] slams their fist down on [M]!"))
+ playsound(loc, 'sound/weapons/punch1.ogg', 50, 1)
+ M.adjustBruteLoss(5)
+ if("disarm")
+ visible_message(span_danger("[user] pins [M] down with a finger!"))
+ playsound(loc, 'sound/effects/bodyfall1.ogg', 50, 1)
+ M.adjustStaminaLoss(10)
+ if("grab")
+ visible_message(span_danger("[user] squeezes their fist around [M]!"))
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1)
+ M.adjustOxyLoss(5)
+ else
+ M.help_shake_act(user)
+
+/obj/item/clothing/head/mob_holder/micro/attacked_by(obj/item/I, mob/living/user)
+ return held_mob?.attacked_by(I, user) || ..()
+
+/mob/living/Adjacent(atom/neighbor)
+ . = ..()
+ var/obj/item/clothing/head/mob_holder/micro/micro_holder = loc
+ if(istype(micro_holder))
+ return micro_holder.Adjacent(neighbor)
+
+/obj/item/clothing/head/mob_holder/micro/attack(mob/living/eater, mob/living/holder)
+ var/datum/component/vore/vore = holder.GetComponent(/datum/component/vore)
+ if(!vore)
+ return FALSE
+
+ if(holder == eater) // Parent wants to eat pulled
+ . = vore.vore_other(held_mob)
+ else // Parent wants to feed pulled to clicked_on
+ . = vore.feed_other_to_other(eater, held_mob)
+
+/obj/item/clothing/head/mob_holder/micro/Exited(mob/living/totally_not_vored, direction)
+ // Transferred to a belly? Get rid of this before it puts us on the floor
+ if(istype(totally_not_vored.loc, /obj/vore_belly))
+ held_mob = null
+ qdel(src)
+ return ..()
+
+/obj/item/clothing/head/mob_holder/micro/GetAccess()
+ . = ..()
+ var/obj/item/held = held_mob.get_active_held_item()
+ if(held)
+ . += held.GetAccess()
+ var/mob/living/carbon/human/human_micro = held_mob
+ if(istype(human_micro))
+ . += human_micro.wear_id?.GetAccess()
+
+/obj/item/clothing/head/mob_holder/micro/GetID()
+ . = ..()
+ if(.)
+ return
+ var/obj/item/held = held_mob.get_active_held_item()
+ if(isidcard(held))
+ return held
+ var/mob/living/carbon/human/human_micro = held_mob
+ if(istype(human_micro) && isidcard(human_micro.wear_id))
+ return human_micro.wear_id
+
+/obj/item/clothing/head/mob_holder/micro/update_visuals(mob/living/carbon/human/tiny_person)
+ . = ..()
+ transform = null
diff --git a/modular_zzplurt/code/modules/mob/living/carbon/human/human.dm b/modular_zzplurt/code/modules/mob/living/carbon/human/human.dm
index 7992e19f25052..ae0e91ba1ab53 100644
--- a/modular_zzplurt/code/modules/mob/living/carbon/human/human.dm
+++ b/modular_zzplurt/code/modules/mob/living/carbon/human/human.dm
@@ -1,3 +1,7 @@
/mob/living/carbon/human
/// Are we currently in combat focus?
var/combat_focus = FALSE
+
+/mob/living/carbon/human/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/mob_holder/micro)
diff --git a/modular_zzplurt/code/modules/mob/living/living.dm b/modular_zzplurt/code/modules/mob/living/living.dm
index 44e8544302ad1..c877d5c2347d1 100644
--- a/modular_zzplurt/code/modules/mob/living/living.dm
+++ b/modular_zzplurt/code/modules/mob/living/living.dm
@@ -25,3 +25,39 @@
to_chat(src, span_userdanger("An admin has [!admin_sleeping ? "un": ""]slept you."))
log_admin("[key_name(admin)] toggled admin-sleep on [key_name(src)].")
message_admins("[key_name_admin(admin)] toggled admin-sleep on [key_name_admin(src)].")
+
+/mob/living
+ var/size_multiplier = RESIZE_NORMAL
+
+/// Returns false on failure
+/mob/living/proc/update_size(new_size, cur_size)
+ if(!new_size)
+ return FALSE
+ if(!cur_size)
+ cur_size = get_size(src)
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ if(new_size == cur_size)
+ return FALSE
+ H.dna.features["body_size"] = new_size
+ H.dna.update_body_size(cur_size)
+ else
+ if(new_size == cur_size)
+ return FALSE
+ size_multiplier = new_size
+ current_size = new_size / cur_size
+ update_transform()
+ adjust_mobsize(new_size)
+ SEND_SIGNAL(src, COMSIG_MOB_RESIZED, new_size, cur_size)
+ return TRUE
+
+/mob/living/proc/adjust_mobsize(size)
+ switch(size)
+ if(0 to 0.4)
+ mob_size = MOB_SIZE_TINY
+ if(0.41 to 0.8)
+ mob_size = MOB_SIZE_SMALL
+ if(0.81 to 1.2)
+ mob_size = MOB_SIZE_HUMAN
+ if(1.21 to INFINITY)
+ mob_size = MOB_SIZE_LARGE
diff --git a/modular_zzplurt/code/modules/movespeed/modifiers/components.dm b/modular_zzplurt/code/modules/movespeed/modifiers/components.dm
new file mode 100644
index 0000000000000..3ba8d7519a62b
--- /dev/null
+++ b/modular_zzplurt/code/modules/movespeed/modifiers/components.dm
@@ -0,0 +1,6 @@
+#define MOVESPEED_ID_STOMP "STEPPY"
+
+/datum/movespeed_modifier/stomp
+ id = MOVESPEED_ID_STOMP
+ movetypes = GROUND
+ multiplicative_slowdown = 10
diff --git a/modular_zzplurt/code/modules/resize/resizing.dm b/modular_zzplurt/code/modules/resize/resizing.dm
new file mode 100644
index 0000000000000..92c5d84771751
--- /dev/null
+++ b/modular_zzplurt/code/modules/resize/resizing.dm
@@ -0,0 +1,167 @@
+//handle the big steppy, except nice
+/mob/living/proc/handle_micro_bump_helping(mob/living/target)
+ if(ishuman(src))
+ var/mob/living/carbon/human/user = src
+
+ if(target.pulledby == user)
+ return FALSE
+
+ //Micro is on a table.
+ var/turf/steppyspot = target.loc
+ for(var/thing in steppyspot.contents)
+ if(istype(thing, /obj/structure/table))
+ return TRUE
+
+ //Both small.
+ if(get_size(user) <= RESIZE_A_TINYMICRO && get_size(target) <= RESIZE_A_TINYMICRO)
+ now_pushing = 0
+ user.forceMove(target.loc)
+ return TRUE
+
+ //Doing messages
+ if(COMPARE_SIZES(user, target) >= 2) //if the initiator is twice the size of the micro
+ now_pushing = 0
+ user.forceMove(target.loc)
+
+ //Smaller person being stepped on
+ if(iscarbon(src))
+ if(istype(user) && user.dna.features["taur"] == "Naga" || user.dna.features["taur"] == "Tentacle")
+ target.visible_message(span_notice("[src] carefully slithers around [target]."), span_notice("[src]'s huge tail slithers besides you."))
+ else
+ target.visible_message(span_notice("[src] carefully steps over [target]."), span_notice("[src] steps over you carefully."))
+ return TRUE
+
+ //Smaller person stepping under a larger person
+ if(COMPARE_SIZES(target, user) >= 2)
+ user.forceMove(target.loc)
+ now_pushing = 0
+ micro_step_under(target)
+ return TRUE
+
+//Stepping on disarm intent -- TO DO, OPTIMIZE ALL OF THIS SHIT
+/mob/living/proc/handle_micro_bump_other(mob/living/target)
+ ASSERT(isliving(target))
+ if(ishuman(src))
+ var/mob/living/carbon/human/user = src
+
+ if(target.pulledby == user)
+ return FALSE
+
+ //If on a table, don't
+ var/turf/steppyspot = target.loc
+ for(var/thing in steppyspot.contents)
+ if(istype(thing, /obj/structure/table))
+ return TRUE
+
+ //Both small
+ if(get_size(user) <= RESIZE_A_TINYMICRO && get_size(target) <= RESIZE_A_TINYMICRO)
+ now_pushing = 0
+ user.forceMove(target.loc)
+ return TRUE
+
+ if(COMPARE_SIZES(user, target) >= 2)
+ log_combat(user, target, "stepped on", addition="[resolve_intent_name(user.combat_mode)] trample")
+ if((user.mobility_flags & MOBILITY_MOVE) && !user.buckled)
+ switch(resolve_intent_name(user.combat_mode))
+ if("disarm")
+ now_pushing = 0
+ user.forceMove(target.loc)
+ user.sizediffStamLoss(target)
+ user.add_movespeed_modifier(/datum/movespeed_modifier/stomp, TRUE) //Full stop
+ addtimer(CALLBACK(user, /mob/.proc/remove_movespeed_modifier, MOVESPEED_ID_STOMP, TRUE), 3) //0.3 seconds
+ if(iscarbon(user))
+ if(istype(user) && user.dna.features["taur"] == "Naga" || user.dna.features["taur"] == "Tentacle")
+ target.visible_message(span_danger("[src] carefully rolls their tail over [target]!"), span_danger("[src]'s huge tail rolls over you!"))
+ else
+ target.visible_message(span_danger("[src] carefully steps on [target]!"), span_danger("[src] steps onto you with force!"))
+ return TRUE
+
+ if("harm")
+ now_pushing = 0
+ user.forceMove(target.loc)
+ user.sizediffStamLoss(target)
+ user.sizediffBruteloss(target)
+ playsound(loc, 'sound/misc/splort.ogg', 50, 1)
+ user.add_movespeed_modifier(/datum/movespeed_modifier/stomp, TRUE)
+ addtimer(CALLBACK(user, /mob/.proc/remove_movespeed_modifier, MOVESPEED_ID_STOMP, TRUE), 1 SECONDS) //1 second
+ //user.Stun(20)
+ if(iscarbon(user))
+ if(istype(user) && (user.dna.features["taur"] == "Naga" || user.dna.features["taur"] == "Tentacle"))
+ target.visible_message(span_danger("[src] mows down [target] under their tail!"), span_userdanger("[src] plows their tail over you mercilessly!"))
+ else
+ target.visible_message(span_danger("[src] slams their foot down on [target], crushing them!"), span_userdanger("[src] crushes you under their foot!"))
+ return TRUE
+
+ if("grab")
+ now_pushing = 0
+ user.forceMove(target.loc)
+ user.sizediffStamLoss(target)
+ user.sizediffStun(target)
+ user.add_movespeed_modifier(/datum/movespeed_modifier/stomp, TRUE)
+ addtimer(CALLBACK(user, /mob/.proc/remove_movespeed_modifier, MOVESPEED_ID_STOMP, TRUE), 7)//About 3/4th a second
+ if(iscarbon(user))
+ var/feetCover = (user.wear_suit && (user.wear_suit.body_parts_covered & FEET)) || (user.w_uniform && (user.w_uniform.body_parts_covered & FEET) || (user.shoes && (user.shoes.body_parts_covered & FEET)))
+ if(feetCover)
+ if(user?.dna?.features["taur"] == "Naga" || user?.dna?.features["taur"] == "Tentacle")
+ target.visible_message(span_danger("[src] pins [target] under their tail!"), span_danger("[src] pins you beneath their tail!"))
+ else
+ target.visible_message(span_danger("[src] pins [target] helplessly underfoot!"), span_danger("[src] pins you underfoot!"))
+ return TRUE
+ else
+ if(user?.dna?.features["taur"] == "Naga" || user?.dna?.features["taur"] == "Tentacle")
+ target.visible_message(span_danger("[user] snatches up [target] underneath their tail!"), span_userdanger("[src]'s tail winds around you and snatches you in its coils!"))
+ //target.mob_pickup_micro_feet(user)
+ SEND_SIGNAL(target, COMSIG_MICRO_PICKUP_FEET, user)
+ else
+ target.visible_message(span_danger("[user] stomps down on [target], curling their toes and picking them up!"), span_userdanger("[src]'s toes pin you down and curl around you, picking you up!"))
+ //target.mob_pickup_micro_feet(user)
+ SEND_SIGNAL(target, COMSIG_MICRO_PICKUP_FEET, user)
+ return TRUE
+
+ if(COMPARE_SIZES(target, user) >= 2)
+ user.forceMove(target.loc)
+ now_pushing = 0
+ micro_step_under(target)
+ return TRUE
+
+/mob/living/proc/macro_step_around(mob/living/target)
+ if(ishuman(src))
+ var/mob/living/carbon/human/validmob = src
+ if(validmob?.dna?.features["taur"] == "Naga" || validmob?.dna?.features["taur"] == "Tentacle")
+ visible_message(span_notice("[validmob] carefully slithers around [target]."), span_notice("You carefully slither around [target]."))
+ else
+ visible_message(span_notice("[validmob] carefully steps around [target]."), span_notice("You carefully steps around [target]."))
+
+//smaller person stepping under another person... TO DO, fix and allow special interactions with naga legs to be seen
+/mob/living/proc/micro_step_under(mob/living/target)
+ if(ishuman(src))
+ var/mob/living/carbon/human/validmob = src
+ if(validmob?.dna?.features["taur"] == "Naga" || validmob?.dna?.features["taur"] == "Tentacle")
+ visible_message(span_notice("[validmob] bounds over [validmob]'s tail."), span_notice("You jump over [target]'s thick tail."))
+ else
+ visible_message(span_notice("[validmob] runs between [validmob]'s legs."), span_notice("You run between [target]'s legs."))
+
+//Proc for scaling stamina damage on size difference
+/mob/living/carbon/proc/sizediffStamLoss(mob/living/carbon/target)
+ var/S = COMPARE_SIZES(src, target) * 25 //macro divided by micro, times 25
+ target.Knockdown(S) //final result in stamina knockdown
+
+//Proc for scaling stuns on size difference (for grab intent)
+/mob/living/carbon/proc/sizediffStun(mob/living/carbon/target)
+ var/T = COMPARE_SIZES(src, target) * 2 //Macro divided by micro, times 2
+ target.Stun(T)
+
+//Proc for scaling brute damage on size difference
+/mob/living/carbon/proc/sizediffBruteloss(mob/living/carbon/target)
+ var/B = COMPARE_SIZES(src, target) * 3 //macro divided by micro, times 3
+ target.adjustBruteLoss(B) //final result in brute loss
+
+//Proc for instantly grabbing valid size difference. Code optimizations soon(TM)
+/*
+/mob/living/proc/sizeinteractioncheck(mob/living/target)
+ if(abs(get_effective_size()/target.get_effective_size())>=2.0 && get_effective_size()>target.get_effective_size())
+ return FALSE
+ else
+ return TRUE
+*/
+//Clothes coming off at different sizes, and health/speed/stam changes as well
diff --git a/modular_zzplurt/code/modules/resize/sizechems.dm b/modular_zzplurt/code/modules/resize/sizechems.dm
new file mode 100644
index 0000000000000..39238ba8d6134
--- /dev/null
+++ b/modular_zzplurt/code/modules/resize/sizechems.dm
@@ -0,0 +1,130 @@
+//Size Chemicals, now with better and less cringy names.
+//TO DO: USE BETTER FERMICHEM TO MAKE ALL OF THESE CHEMICALS MORE INTERACTIVE
+
+//Sizechem reagent
+/datum/reagent/sizechem
+ name = "Cell-Volume Altering Base"
+ description = "A stabilized compound liquid, used as a basis for increasing or decreasing the size of living matter with more recipes."
+ color = "#C900CC"
+ taste_description = "regret"
+ can_synth = FALSE
+ metabolization_rate = 0.25
+
+//Sizechem reaction
+/datum/chemical_reaction/sizechem
+ name = "Cell-Volume Altering Base"
+ id = /datum/reagent/sizechem
+ mix_message = "the reaction rapidly alters in size!"
+ required_reagents = list(/datum/reagent/growthserum = 0.15, /datum/reagent/medicine/clonexadone = 0.15, /datum/reagent/gold = 0.15, /datum/reagent/acetone = 0.15)
+ results = list(/datum/reagent/sizechem = 0.3)
+ required_temp = 1
+ //Fermichem vars
+ OptimalTempMin = 600 // Lower area of bell curve for determining heat based rate reactions
+ OptimalTempMax = 630 // Upper end for above
+ ExplodeTemp = 635 // Temperature at which reaction explodes
+ OptimalpHMin = 5 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
+ OptimalpHMax = 5.5 // Higest value for above
+ ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase)
+ CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)
+ CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value)
+ CurveSharppH = 4 // How sharp the pH exponential curve is (to the power of value)
+ ThermicConstant = -10 // Temperature change per 1u produced
+ HIonRelease = 0.02 // pH change per 1u reaction (inverse for some reason)
+ RateUpLim = 1 // Optimal/max rate possible if all conditions are perfect
+ FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics
+ FermiExplode = FALSE // If the chemical explodes in a special way
+ PurityMin = 0.2
+
+//Growthchem reagent
+/datum/reagent/growthchem
+ name = "Prospacillin"
+ 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
+
+//Growthchem reaction
+/datum/chemical_reaction/growthchem
+ name = "Prospacillin"
+ id = /datum/reagent/growthchem
+ mix_message = "the reaction appears to grow!"
+ required_reagents = list(/datum/reagent/sizechem = 0.15, /datum/reagent/consumable/condensedcapsaicin = 0.15, /datum/reagent/drug/aphrodisiac = 0.30)
+ results = list(/datum/reagent/growthchem = 0.25)
+ required_temp = 1
+ OptimalTempMin = 700 // Lower area of bell curve for determining heat based rate reactions
+ OptimalTempMax = 730 // Upper end for above
+ ExplodeTemp = 735 // Temperature at which reaction explodes
+ OptimalpHMin = 3 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
+ OptimalpHMax = 3.5 // Higest value for above
+ ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase)
+ CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)
+ CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value)
+ CurveSharppH = 4 // How sharp the pH exponential curve is (to the power of value)
+ ThermicConstant = -10 // Temperature change per 1u produced
+ HIonRelease = 0.02 // pH change per 1u reaction (inverse for some reason)
+ RateUpLim = 1 // Optimal/max rate possible if all conditions are perfect
+ FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics
+ FermiExplode = FALSE // If the chemical explodes in a special way
+ PurityMin = 0.2
+
+//Growthchem effects
+/datum/reagent/growthchem/on_mob_add(mob/living/M)
+ . = ..()
+ log_game("SIZECODE: [M] ckey: [M.key] has ingested growthchem.")
+
+/datum/reagent/growthchem/on_mob_life(mob/living/M)
+ var/size = get_size(M)
+ if(size < RESIZE_MACRO)
+ M.update_size(0.025)
+ M.visible_message(span_danger("[pick("[M] grows!", "[M] expands in size!", "[M] pushes outwards in stature!")]"), span_danger("[pick("You feel your body fighting for space and growing!", "The world contracts inwards in every direction!", "You feel your muscles expand, and your surroundings shrink!")]"))
+ ..()
+ . = 1
+
+//Shrinkchem reagent
+/datum/reagent/shrinkchem
+ name = "Diminicillin"
+ 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.50
+ can_synth = FALSE //SAME STORY AS ABOVE
+
+//Shrinchem reaction
+/datum/chemical_reaction/shrinkchem
+ name = "Diminicillin"
+ id = /datum/reagent/shrinkchem
+ mix_message = "the reaction appears to shrink!"
+ required_reagents = list(/datum/reagent/sizechem = 0.15, /datum/reagent/consumable/frostoil = 0.15, /datum/reagent/drug = 0.30)
+ results = list(/datum/reagent/shrinkchem = 0.25)
+ required_temp = 1
+ OptimalTempMin = 100 // Lower area of bell curve for determining heat based rate reactions
+ OptimalTempMax = 150 // Upper end for above
+ ExplodeTemp = 350 // Temperature at which reaction explodes
+ OptimalpHMin = 3 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
+ OptimalpHMax = 4.5 // Higest value for above
+ ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase)
+ CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)
+ CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value)
+ CurveSharppH = 4 // How sharp the pH exponential curve is (to the power of value)
+ ThermicConstant = -10 // Temperature change per 1u produced
+ HIonRelease = 0.02 // pH change per 1u reaction (inverse for some reason)
+ RateUpLim = 1 // Optimal/max rate possible if all conditions are perfect
+ FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics
+ FermiExplode = FALSE // If the chemical explodes in a special way
+ PurityMin = 0.2
+
+//Shrinkchem effects
+/datum/reagent/shrinkchem/on_mob_add(mob/living/M)
+ . = ..()
+ log_game("SIZECODE: [M] ckey: [M.key] has ingested shrinkchem.")
+
+/datum/reagent/shrinkchem/on_mob_life(mob/living/M)
+ var/size = get_size(M)
+ if(size > RESIZE_MICRO)
+ M.update_size(0.025)
+ M.visible_message(span_danger("[pick("[M] shrinks down!", "[M] dwindles in size!", "[M] compresses down!")]"), span_danger("[pick("You feel your body compressing in size!", "The world pushes outwards in every direction!", "You feel your muscles contract, and your surroundings grow!")]"))
+ ..()
+ . = 1
diff --git a/modular_zzplurt/code/modules/resize/sizegun.dm b/modular_zzplurt/code/modules/resize/sizegun.dm
new file mode 100644
index 0000000000000..cee98c0e86244
--- /dev/null
+++ b/modular_zzplurt/code/modules/resize/sizegun.dm
@@ -0,0 +1,85 @@
+/obj/projectile/sizelaser
+ name = "sizeray laser"
+ icon_state = "omnilaser"
+ hitsound = null
+ damage = 5
+ damage_type = STAMINA
+ pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
+
+/obj/projectile/sizelaser/shrinkray
+ icon_state = "bluelaser"
+
+/obj/projectile/sizelaser/growthray
+ icon_state = "laser"
+
+/obj/projectile/sizelaser/shrinkray/on_hit(atom/target, blocked = 0, pierce_hit)
+ . = ..()
+ if(isliving(target))
+ var/mob/living/living = target
+ var/new_size = RESIZE_NORMAL
+ switch(get_size(target))
+ if(RESIZE_MACRO to INFINITY)
+ new_size = RESIZE_HUGE
+ if(RESIZE_HUGE to RESIZE_MACRO)
+ new_size = RESIZE_BIG
+ if(RESIZE_BIG to RESIZE_HUGE)
+ new_size = RESIZE_NORMAL
+ if(RESIZE_NORMAL to RESIZE_BIG)
+ new_size = RESIZE_SMALL
+ if(RESIZE_SMALL to RESIZE_NORMAL)
+ new_size = RESIZE_TINY
+ if(RESIZE_TINY to RESIZE_SMALL)
+ new_size = RESIZE_MICRO
+ if((0 - INFINITY) to RESIZE_NORMAL)
+ new_size = RESIZE_MICRO
+ living.update_size(new_size)
+
+/obj/projectile/sizelaser/growthray/on_hit(atom/target, blocked = 0, pierce_hit)
+ . = ..()
+ if(isliving(target))
+ var/mob/living/living = target
+ var/new_size = RESIZE_NORMAL
+ switch(get_size(target))
+ if(RESIZE_HUGE to RESIZE_MACRO)
+ new_size = RESIZE_MACRO
+ if(RESIZE_BIG to RESIZE_HUGE)
+ new_size = RESIZE_HUGE
+ if(RESIZE_NORMAL to RESIZE_BIG)
+ new_size = RESIZE_BIG
+ if(RESIZE_SMALL to RESIZE_NORMAL)
+ new_size = RESIZE_NORMAL
+ if(RESIZE_TINY to RESIZE_SMALL)
+ new_size = RESIZE_SMALL
+ if(RESIZE_MICRO to RESIZE_TINY)
+ new_size = RESIZE_TINY
+ if((0 - INFINITY) to RESIZE_MICRO)
+ new_size = RESIZE_MICRO
+ living.update_size(new_size)
+
+/obj/item/ammo_casing/energy/laser/growthray
+ projectile_type = /obj/projectile/sizelaser/growthray
+ select_name = "Growth"
+
+/obj/item/ammo_casing/energy/laser/shrinkray
+ projectile_type = /obj/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!"
+ inhand_icon_state = null
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray, /obj/item/ammo_casing/energy/laser/growthray)
+ selfcharge = TRUE
+ charge_delay = 5
+ ammo_x_offset = 2
+ clumsy_check = 1
+
+/obj/item/gun/energy/laser/sizeray/update_overlays()
+ . = ..()
+ var/current_index = select
+ if(current_index == 1)
+ icon_state = "redtag"
+ else
+ icon_state = "bluetag"
diff --git a/tgstation.dme b/tgstation.dme
index dec04d704ffc9..b9f19702b0dfe 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -515,9 +515,11 @@
#include "code\__DEFINES\~~~splurt_defines\inventory.dm"
#include "code\__DEFINES\~~~splurt_defines\keybinding.dm"
#include "code\__DEFINES\~~~splurt_defines\mobs.dm"
+#include "code\__DEFINES\~~~splurt_defines\sizecode.dm"
#include "code\__DEFINES\~~~splurt_defines\species_clothing_paths.dm"
#include "code\__DEFINES\~~~splurt_defines\strippable.dm"
#include "code\__DEFINES\~~~splurt_defines\underwear.dm"
+#include "code\__DEFINES\~~~splurt_defines\dcs\signals.dm"
#include "code\__DEFINES\~~~splurt_defines\traits\declarations.dm"
#include "code\__HELPERS\_auxtools_api.dm"
#include "code\__HELPERS\_dreamluau.dm"
@@ -1626,6 +1628,7 @@
#include "code\datums\elements\mirage_border.dm"
#include "code\datums\elements\mob_access.dm"
#include "code\datums\elements\mob_grabber.dm"
+#include "code\datums\elements\mob_holder.dm"
#include "code\datums\elements\mob_killed_tally.dm"
#include "code\datums\elements\move_force_on_death.dm"
#include "code\datums\elements\movement_turf_changer.dm"
@@ -9292,6 +9295,7 @@
#include "modular_zzplurt\code\datums\outfit.dm"
#include "modular_zzplurt\code\datums\sprite_accessories.dm"
#include "modular_zzplurt\code\datums\components\crafting\crafting.dm"
+#include "modular_zzplurt\code\datums\elements\holder_micro.dm"
#include "modular_zzplurt\code\datums\keybinding\human.dm"
#include "modular_zzplurt\code\datums\keybinding\living.dm"
#include "modular_zzplurt\code\game\objects\items.dm"
@@ -9342,7 +9346,10 @@
#include "modular_zzplurt\code\modules\mob\living\carbon\human\inventory.dm"
#include "modular_zzplurt\code\modules\mob\living\carbon\human\life.dm"
#include "modular_zzplurt\code\modules\mob\living\carbon\human\species.dm"
+#include "modular_zzplurt\code\modules\movespeed\modifiers\components.dm"
#include "modular_zzplurt\code\modules\reagents\chemistry\machinery\chem_dispenser.dm"
+#include "modular_zzplurt\code\modules\resize\resizing.dm"
+#include "modular_zzplurt\code\modules\resize\sizegun.dm"
#include "modular_zzplurt\code\modules\species\_species.dm"
#include "modular_zzplurt\code\modules\species\arachnid.dm"
#include "modular_zzplurt\code\modules\species\teshari.dm"