From f4fe24f34ad8288a7225b582e98de44241fdcead Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Tue, 5 Mar 2024 15:42:28 -0500 Subject: [PATCH] Fixes moths not being able to eat clothes (#10699) * https://github.com/tgstation/tgstation/pull/55356 * https://github.com/tgstation/tgstation/pull/61082 * final touchups * bad vars oopsies * fix bad armor var * dumb span --- code/datums/armor.dm | 109 +++++++++--------- code/modules/clothing/clothing.dm | 60 ++++++++-- .../unit_tests/food_edibility_check.dm | 4 +- 3 files changed, 109 insertions(+), 64 deletions(-) diff --git a/code/datums/armor.dm b/code/datums/armor.dm index 6ad80052956c3..3a11186a292e9 100644 --- a/code/datums/armor.dm +++ b/code/datums/armor.dm @@ -1,73 +1,76 @@ -#define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]-[magic]-[stamina]" +#define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]-[magic]-[stamina]-[consume]" -/proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, stamina = 0) - . = locate(ARMORID) - if (!.) - . = new /datum/armor(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic, stamina) +/proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, stamina = 0, consume = 0) + . = locate(ARMORID) + if (!.) + . = new /datum/armor(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic, stamina, consume) /datum/armor - datum_flags = DF_USE_TAG - var/melee - var/bullet - var/laser - var/energy - var/bomb - var/bio - var/rad - var/fire - var/acid - var/magic - var/stamina + datum_flags = DF_USE_TAG + var/melee + var/bullet + var/laser + var/energy + var/bomb + var/bio + var/rad + var/fire + var/acid + var/magic + var/stamina + var/consume -/datum/armor/New(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, stamina = 0) - src.melee = melee - src.bullet = bullet - src.laser = laser - src.energy = energy - src.bomb = bomb - src.bio = bio - src.rad = rad - src.fire = fire - src.acid = acid - src.magic = magic - src.stamina = stamina - tag = ARMORID +/datum/armor/New(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, stamina = 0, consume = 0) + src.melee = melee + src.bullet = bullet + src.laser = laser + src.energy = energy + src.bomb = bomb + src.bio = bio + src.rad = rad + src.fire = fire + src.acid = acid + src.magic = magic + src.stamina = stamina + src.consume = consume + tag = ARMORID -/datum/armor/proc/modifyRating(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, stamina = 0) - return getArmor(src.melee+melee, src.bullet+bullet, src.laser+laser, src.energy+energy, src.bomb+bomb, src.bio+bio, src.rad+rad, src.fire+fire, src.acid+acid, src.magic+magic, src.stamina+stamina) +/datum/armor/proc/modifyRating(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0, stamina = 0, consume = 0) + return getArmor(src.melee+melee, src.bullet+bullet, src.laser+laser, src.energy+energy, src.bomb+bomb, src.bio+bio, src.rad+rad, src.fire+fire, src.acid+acid, src.magic+magic, src.stamina+stamina, src.consume+consume) /datum/armor/proc/modifyAllRatings(modifier = 0) - return getArmor(melee+modifier, bullet+modifier, laser+modifier, energy+modifier, bomb+modifier, bio+modifier, rad+modifier, fire+modifier, acid+modifier, magic+modifier, stamina+modifier) + return getArmor(melee+modifier, bullet+modifier, laser+modifier, energy+modifier, bomb+modifier, bio+modifier, rad+modifier, fire+modifier, acid+modifier, magic+modifier, stamina+modifier, consume+modifier) -/datum/armor/proc/setRating(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic) - return getArmor((isnull(melee) ? src.melee : melee),\ - (isnull(bullet) ? src.bullet : bullet),\ - (isnull(laser) ? src.laser : laser),\ - (isnull(energy) ? src.energy : energy),\ - (isnull(bomb) ? src.bomb : bomb),\ - (isnull(bio) ? src.bio : bio),\ - (isnull(rad) ? src.rad : rad),\ - (isnull(fire) ? src.fire : fire),\ - (isnull(acid) ? src.acid : acid),\ - (isnull(magic) ? src.magic : magic),\ - (isnull(stamina) ? src.stamina : stamina)) +/datum/armor/proc/setRating(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic, consume) + return getArmor((isnull(melee) ? src.melee : melee),\ + (isnull(bullet) ? src.bullet : bullet),\ + (isnull(laser) ? src.laser : laser),\ + (isnull(energy) ? src.energy : energy),\ + (isnull(bomb) ? src.bomb : bomb),\ + (isnull(bio) ? src.bio : bio),\ + (isnull(rad) ? src.rad : rad),\ + (isnull(fire) ? src.fire : fire),\ + (isnull(acid) ? src.acid : acid),\ + (isnull(magic) ? src.magic : magic),\ + (isnull(stamina) ? src.stamina : stamina),\ + (isnull(consume) ? src.consume : consume)) /datum/armor/proc/getRating(rating) - return vars[rating] + return vars[rating] /datum/armor/proc/getList() - return list(MELEE = melee, BULLET = bullet, LASER = laser, ENERGY = energy, BOMB = bomb, BIO = bio, RAD = rad, FIRE = fire, ACID = acid, MAGIC = magic, STAMINA = stamina) + return list(MELEE = melee, BULLET = bullet, LASER = laser, ENERGY = energy, BOMB = bomb, BIO = bio, RAD = rad, FIRE = fire, ACID = acid, MAGIC = magic, STAMINA = stamina, CONSUME = consume) /datum/armor/proc/attachArmor(datum/armor/AA) - return getArmor(melee+AA.melee, bullet+AA.bullet, laser+AA.laser, energy+AA.energy, bomb+AA.bomb, bio+AA.bio, rad+AA.rad, fire+AA.fire, acid+AA.acid, magic+AA.magic, stamina+AA.stamina) + return getArmor(melee+AA.melee, bullet+AA.bullet, laser+AA.laser, energy+AA.energy, bomb+AA.bomb, bio+AA.bio, rad+AA.rad, fire+AA.fire, acid+AA.acid, magic+AA.magic, stamina+AA.stamina, consume+AA.consume) /datum/armor/proc/detachArmor(datum/armor/AA) - return getArmor(melee-AA.melee, bullet-AA.bullet, laser-AA.laser, energy-AA.energy, bomb-AA.bomb, bio-AA.bio, rad-AA.rad, fire-AA.fire, acid-AA.acid, magic-AA.magic, stamina-AA.stamina) + return getArmor(melee-AA.melee, bullet-AA.bullet, laser-AA.laser, energy-AA.energy, bomb-AA.bomb, bio-AA.bio, rad-AA.rad, fire-AA.fire, acid-AA.acid, magic-AA.magic, stamina-AA.stamina, consume+AA.consume) /datum/armor/vv_edit_var(var_name, var_value) - if (var_name == NAMEOF(src, tag)) - return FALSE - . = ..() - tag = ARMORID // update tag in case armor values were edited + if (var_name == NAMEOF(src, tag)) + return FALSE + . = ..() + tag = ARMORID // update tag in case armor values were edited #undef ARMORID diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index d12e5834d727e..f789c34fa30eb 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -4,6 +4,8 @@ #define SENSORS_TRACKING 3 #define SENSOR_CHANGE_DELAY 1.5 SECONDS +#define MOTH_EATING_CLOTHING_DAMAGE 15 + /obj/item/clothing name = "clothing" resistance_flags = FLAMMABLE @@ -52,6 +54,9 @@ var/high_pressure_multiplier = 1 var/static/list/high_pressure_multiplier_types = list(MELEE, BULLET, LASER, ENERGY, BOMB) + /// A lazily initiated "food" version of the clothing for moths + var/obj/item/food/clothing/moth_snack + /obj/item/clothing/Initialize(mapload) if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE)) actions_types += /datum/action/item_action/toggle_voice_box @@ -76,17 +81,45 @@ /obj/item/food/clothing // fuck you name = "temporary moth clothing snack item" desc = "If you're reading this it means I messed up. This is related to moths eating clothes and I didn't know a better way to do it than making a new food object." // die - food_reagents = list(/datum/reagent/consumable/nutriment = 1) + bite_consumption = 1 + // sigh, ok, so it's not ACTUALLY infinite nutrition. this is so you can eat clothes more than...once. + // bite_consumption limits how much you actually get, and the take_damage in after eat makes sure you can't abuse this. + // ...maybe this was a mistake after all. + food_reagents = list(/datum/reagent/consumable/nutriment = INFINITY) tastes = list("dust" = 1, "lint" = 1) foodtypes = CLOTH -/obj/item/clothing/attack(mob/M, mob/user, def_zone) - if(user.a_intent != INTENT_HARM && (ismoth(M) || ispsyphoza(M)) && !(clothing_flags & NOTCONSUMABLE) && !(resistance_flags & INDESTRUCTIBLE) && (armor.getRating(MELEE) == 0)) - var/obj/item/food/clothing/clothing_as_food = new // I shall send you to hell in the next PR - clothing_as_food.name = name - if(clothing_as_food.attack(M, user, def_zone)) - take_damage(15, sound_effect=FALSE) - qdel(clothing_as_food) + /// A weak reference to the clothing that created us + var/datum/weakref/clothing + +/obj/item/food/clothing/make_edible() + AddComponent(/datum/component/edible,\ + initial_reagents = food_reagents,\ + food_flags = food_flags,\ + foodtypes = foodtypes,\ + volume = max_volume,\ + eat_time = eat_time,\ + tastes = tastes,\ + eatverbs = eatverbs,\ + bite_consumption = bite_consumption,\ + microwaved_type = microwaved_type,\ + junkiness = junkiness,\ + after_eat = CALLBACK(src, PROC_REF(after_eat))) + +/obj/item/food/clothing/proc/after_eat(mob/eater) + var/obj/item/clothing/resolved_clothing = clothing.resolve() + if (resolved_clothing) + resolved_clothing.take_damage(MOTH_EATING_CLOTHING_DAMAGE, sound_effect = FALSE, damage_flag = CONSUME) + else + qdel(src) + +/obj/item/clothing/attack(mob/attacker, mob/user, def_zone) + if(user.a_intent != INTENT_HARM && (ismoth(attacker) || ispsyphoza(attacker)) && !(clothing_flags & NOTCONSUMABLE) && !(resistance_flags & INDESTRUCTIBLE) && (armor.getRating(MELEE) == 0)) + if (isnull(moth_snack)) + moth_snack = new + moth_snack.name = name + moth_snack.clothing = WEAKREF(src) + moth_snack.attack(attacker, user, def_zone) else return ..() @@ -102,6 +135,7 @@ /obj/item/clothing/Destroy() user_vars_remembered = null //Oh god somebody put REFERENCES in here? not to worry, we'll clean it up + QDEL_NULL(moth_snack) return ..() /obj/item/clothing/dropped(mob/user) @@ -449,7 +483,6 @@ BLIND // can't see anything return 1 return 0 - /obj/item/clothing/obj_destruction(damage_flag) if(damage_flag == BOMB || damage_flag == MELEE) var/turf/T = get_turf(src) @@ -457,6 +490,13 @@ BLIND // can't see anything var/obj/effect/decal/cleanable/shreds/Shreds = new(T) Shreds.desc = "The sad remains of what used to be [name]." deconstruct(FALSE) + if(damage_flag == CONSUME) //This allows for moths to fully consume clothing, rather than damaging it like other sources like brute + var/turf/current_position = get_turf(src) + new /obj/effect/decal/cleanable/shreds(current_position, name) + if(isliving(loc)) + var/mob/living/possessing_mob = loc + possessing_mob.visible_message("[src] is consumed until naught but shreds remains!", "[src] falls apart into little bits!") + deconstruct(FALSE) else ..() @@ -475,3 +515,5 @@ BLIND // can't see anything #undef SENSORS_VITALS #undef SENSORS_TRACKING #undef SENSOR_CHANGE_DELAY + +#undef MOTH_EATING_CLOTHING_DAMAGE diff --git a/code/modules/unit_tests/food_edibility_check.dm b/code/modules/unit_tests/food_edibility_check.dm index a5528c90dd530..8eae05e3330f1 100644 --- a/code/modules/unit_tests/food_edibility_check.dm +++ b/code/modules/unit_tests/food_edibility_check.dm @@ -8,8 +8,8 @@ /obj/item/food/grown/mushroom, /obj/item/food/donkpocket/random, /obj/item/food/deepfryholder, - //obj/item/food/clothing, - //obj/item/food/meat/slab/human/mutant, + /obj/item/food/clothing, + /obj/item/food/meat/slab/human/mutant, /obj/item/food/grown/shell) var/list/food_paths = subtypesof(/obj/item/food) - not_food