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