[MIRROR] Adds Ants, Decomposition, and some extras. (#6944)
* Adds Ants, Decomposition, and some extras. (#59634) Co-authored-by: Kylerace <kylerlumpkin1@ gmail.com> * Adds Ants, Decomposition, and some extras. Co-authored-by: Wallemations <66052067+Wallemations@users.noreply.github.com> Co-authored-by: Kylerace <kylerlumpkin1@ gmail.com>
@@ -43,6 +43,8 @@
|
||||
#define CALTROP_BYPASS_SHOES (1 << 0)
|
||||
#define CALTROP_IGNORE_WALKERS (1 << 1)
|
||||
#define CALTROP_SILENT (1 << 2)
|
||||
#define CALTROP_NOSTUN (1 << 3)
|
||||
#define CALTROP_NOCRAWL (1 << 4)
|
||||
|
||||
//Ingredient type in datum/component/customizable_reagent_holder
|
||||
#define CUSTOM_INGREDIENT_TYPE_EDIBLE 1
|
||||
|
||||
@@ -114,6 +114,9 @@
|
||||
/// Read the documentation for /datum/status_effect/confusion for more information.
|
||||
#define STATUS_EFFECT_CONFUSION /datum/status_effect/confusion
|
||||
|
||||
//Deals with covering the target in ants.
|
||||
#define STATUS_EFFECT_ANTS /datum/status_effect/ants
|
||||
|
||||
/////////////
|
||||
// NEUTRAL //
|
||||
/////////////
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
//"Don't leave food on the floor, that's how we get ants"
|
||||
|
||||
#define DECOMPOSITION_TIME 10 MINUTES
|
||||
#define DECOMPOSITION_TIME_RAW 5 MINUTES
|
||||
#define DECOMPOSITION_TIME_GROSS 7 MINUTES
|
||||
|
||||
#define DECOMP_EXAM_NORMAL 0
|
||||
#define DECOMP_EXAM_GROSS 1
|
||||
#define DECOMP_EXAM_RAW 2
|
||||
|
||||
/datum/component/decomposition
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
/// Makes sure food only starts decomposing if a player's EVER picked it up before
|
||||
var/handled = FALSE
|
||||
/// Used to stop food in someone's hand & in storage slots from decomposing.
|
||||
var/protected = FALSE
|
||||
/// Used to stop the timer & check for the examine proc
|
||||
var/timerid
|
||||
/// Used so the timer won't reset.
|
||||
var/time_remaining = DECOMPOSITION_TIME
|
||||
/// Used to give raw/gross food lower timers
|
||||
var/decomp_flags
|
||||
/// Used for examining
|
||||
var/examine_type = DECOMP_EXAM_NORMAL
|
||||
|
||||
/datum/component/decomposition/Initialize(decomp_flags = NONE)
|
||||
if(!isobj(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.decomp_flags = decomp_flags
|
||||
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/handle_movement)
|
||||
RegisterSignal(parent, list(
|
||||
COMSIG_ITEM_PICKUP, //person picks up an item
|
||||
COMSIG_STORAGE_ENTERED), //Object enters a storage object (boxes, etc.)
|
||||
.proc/picked_up)
|
||||
RegisterSignal(parent, list(
|
||||
COMSIG_ITEM_DROPPED, //Object is dropped anywhere
|
||||
COMSIG_STORAGE_EXITED), //Object exits a storage object (boxes, etc)
|
||||
.proc/dropped)
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
|
||||
|
||||
if(decomp_flags & RAW) // Raw food overrides gross
|
||||
time_remaining = DECOMPOSITION_TIME_RAW
|
||||
examine_type = DECOMP_EXAM_RAW
|
||||
else if(decomp_flags & GROSS)
|
||||
time_remaining = DECOMPOSITION_TIME_GROSS
|
||||
examine_type = DECOMP_EXAM_GROSS
|
||||
|
||||
/datum/component/decomposition/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_ITEM_PICKUP,
|
||||
COMSIG_STORAGE_ENTERED,
|
||||
COMSIG_MOVABLE_MOVED,
|
||||
COMSIG_ITEM_DROPPED,
|
||||
COMSIG_STORAGE_EXITED,
|
||||
COMSIG_PARENT_EXAMINE))
|
||||
|
||||
/datum/component/decomposition/proc/handle_movement()
|
||||
if(!handled) // Has someone touched this previously?
|
||||
return
|
||||
var/obj/food = parent // Doesn't HAVE to be food, that's just what it's intended for
|
||||
|
||||
if(!(istype(food.loc, /turf/open))) // Is this currently in an open turf?
|
||||
remove_timer() // If not, remove any active timers and return
|
||||
return
|
||||
if(locate(/obj/structure/table) in get_turf(food)) // Is this currently over a table?
|
||||
remove_timer()
|
||||
return
|
||||
if(locate(/obj/structure/rack) in get_turf(food)) // Is it on a rack?
|
||||
remove_timer()
|
||||
return
|
||||
if(locate(/obj/machinery/conveyor) in get_turf(food)) // Makes sure no decals spawn on disposals conveyors
|
||||
remove_timer()
|
||||
return
|
||||
// If all other checks fail, then begin decomposition.
|
||||
timerid = addtimer(CALLBACK(src, .proc/decompose), time_remaining, TIMER_STOPPABLE | TIMER_UNIQUE)
|
||||
|
||||
/datum/component/decomposition/Destroy()
|
||||
remove_timer()
|
||||
return ..()
|
||||
|
||||
/datum/component/decomposition/proc/remove_timer()
|
||||
if(active_timers) // Makes sure there's an active timer to delete.
|
||||
time_remaining = timeleft(timerid)
|
||||
deltimer(timerid)
|
||||
|
||||
/datum/component/decomposition/proc/dropped()
|
||||
SIGNAL_HANDLER
|
||||
protected = FALSE
|
||||
handle_movement()
|
||||
|
||||
/datum/component/decomposition/proc/picked_up()
|
||||
SIGNAL_HANDLER
|
||||
remove_timer()
|
||||
protected = TRUE
|
||||
if(!handled)
|
||||
handled = TRUE
|
||||
|
||||
/datum/component/decomposition/proc/decompose()
|
||||
var/obj/decomp = parent //Lets us spawn things at decomp
|
||||
new /obj/effect/decal/cleanable/ants(decomp.loc)
|
||||
new /obj/item/food/badrecipe/moldy(decomp.loc)
|
||||
decomp.visible_message("<span class='notice'>[decomp] gets overtaken by mold and ants! Gross!</span>")
|
||||
qdel(decomp)
|
||||
return
|
||||
|
||||
/datum/component/decomposition/proc/examine(datum/source, mob/user, list/examine_list)
|
||||
SIGNAL_HANDLER
|
||||
var/time_d = 0
|
||||
if(active_timers) // Is the timer currently applied to this?
|
||||
time_d = timeleft(timerid)
|
||||
else
|
||||
time_d = time_remaining
|
||||
switch(examine_type)
|
||||
if(DECOMP_EXAM_NORMAL)// All other types
|
||||
switch(time_d) // Deciseconds used so there's no gaps between examine times.
|
||||
if(3001 to 4500) // 7.5 to 5 Minutes left
|
||||
examine_list += "[parent] looks kinda stale."
|
||||
if(1501 to 3000) // 5 to 2.5 Minutes left
|
||||
examine_list += "[parent] is starting to look pretty gross."
|
||||
if(1 to 1500) // 2.5 Minutes to 1 Decisecond left
|
||||
examine_list += "[parent] looks barely edible."
|
||||
if(DECOMP_EXAM_GROSS) // Gross food
|
||||
switch(time_d)
|
||||
if(2101 to 3150) // 5.25 to 3.5 Minutes
|
||||
examine_list += "[parent] looks kinda stale."
|
||||
if(1050 to 2100) // 3.5 to 1.75 Minutes left
|
||||
examine_list += "[parent] is starting to look pretty gross."
|
||||
if(1 to 1051) // 1.75 Minutes to 1 Decisecond left
|
||||
examine_list += "[parent] looks barely edible."
|
||||
if(DECOMP_EXAM_RAW) // Raw food
|
||||
switch(time_d)
|
||||
if(1501 to 2250) // 3.75 to 2.5 Minutes left
|
||||
examine_list += "[parent] looks kinda stale."
|
||||
if(751 to 1500) // 2.5 to 1.25 Minutes left
|
||||
examine_list += "[parent] is starting to look pretty gross."
|
||||
if(1 to 750) // 1.25 Minutes to 1 Decisecond left
|
||||
examine_list += "[parent] looks barely edible."
|
||||
|
||||
#undef DECOMPOSITION_TIME
|
||||
#undef DECOMPOSITION_TIME_GROSS
|
||||
#undef DECOMPOSITION_TIME_RAW
|
||||
|
||||
#undef DECOMP_EXAM_NORMAL
|
||||
#undef DECOMP_EXAM_GROSS
|
||||
#undef DECOMP_EXAM_RAW
|
||||
@@ -19,12 +19,15 @@
|
||||
///Miscelanous caltrop flags; shoe bypassing, walking interaction, silence
|
||||
var/flags
|
||||
|
||||
///The sound that plays when a caltrop is triggered.
|
||||
var/soundfile
|
||||
|
||||
///given to connect_loc to listen for something moving over target
|
||||
var/static/list/crossed_connections = list(
|
||||
COMSIG_ATOM_ENTERED = .proc/on_entered,
|
||||
)
|
||||
|
||||
/datum/element/caltrop/Attach(datum/target, min_damage = 0, max_damage = 0, probability = 100, flags = NONE)
|
||||
/datum/element/caltrop/Attach(datum/target, min_damage = 0, max_damage = 0, probability = 100, flags = NONE, soundfile = null)
|
||||
. = ..()
|
||||
if(!isatom(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
@@ -33,6 +36,7 @@
|
||||
src.max_damage = max(min_damage, max_damage)
|
||||
src.probability = probability
|
||||
src.flags = flags
|
||||
src.soundfile = soundfile
|
||||
|
||||
if(ismovable(target))
|
||||
AddElement(/datum/element/connect_loc_behalf, target, crossed_connections)
|
||||
@@ -62,7 +66,7 @@
|
||||
if(H.buckled) //if they're buckled to something, that something should be checked instead.
|
||||
return
|
||||
|
||||
if(H.body_position == LYING_DOWN) //if we're not standing we cant step on the caltrop
|
||||
if(H.body_position == LYING_DOWN && !(flags & CALTROP_NOCRAWL)) //if we're not standing we cant step on the caltrop
|
||||
return
|
||||
|
||||
var/picked_def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
@@ -94,7 +98,13 @@
|
||||
)
|
||||
|
||||
H.apply_damage(damage, BRUTE, picked_def_zone, wound_bonus = CANT_WOUND)
|
||||
H.Paralyze(60)
|
||||
|
||||
if(!(flags & CALTROP_NOSTUN)) // Won't set off the paralysis.
|
||||
H.Paralyze(60)
|
||||
|
||||
if(!soundfile)
|
||||
return
|
||||
playsound(H, soundfile, 15, TRUE, -3)
|
||||
|
||||
/datum/element/caltrop/Detach(datum/target)
|
||||
. = ..()
|
||||
|
||||
@@ -969,6 +969,91 @@
|
||||
. = ..()
|
||||
QDEL_NULL(mob_overlay)
|
||||
|
||||
//Deals with ants covering someone.
|
||||
/datum/status_effect/ants
|
||||
id = "ants"
|
||||
status_type = STATUS_EFFECT_REFRESH
|
||||
alert_type = /atom/movable/screen/alert/status_effect/ants
|
||||
duration = 2 MINUTES //Keeping the normal timer makes sure people can't somehow dump 300+ ants on someone at once so they stay there for like 30 minutes. Max w/ 1 dump is 57.6 brute.
|
||||
examine_text = "<span class='warning'>SUBJECTPRONOUN is covered in ants!</span>"
|
||||
processing_speed = STATUS_EFFECT_NORMAL_PROCESS
|
||||
/// Will act as the main timer as well as changing how much damage the ants do.
|
||||
var/ants_remaining = 0
|
||||
|
||||
/datum/status_effect/ants/on_creation(mob/living/new_owner, amount_left)
|
||||
if(isnum(amount_left))
|
||||
to_chat(new_owner, "<span class='userdanger'>You're covered in ants!</span>")
|
||||
ants_remaining += amount_left
|
||||
. = ..()
|
||||
|
||||
/datum/status_effect/ants/refresh(effect, amount_left)
|
||||
var/mob/living/carbon/human/victim = owner
|
||||
if(isnum(amount_left) && ants_remaining >= 1)
|
||||
if(!prob(1)) // 99%
|
||||
to_chat(victim, "<span class='userdanger'>You're covered in MORE ants!</span>")
|
||||
else // 1%
|
||||
victim.say("AAHH! THIS SITUATION HAS ONLY BEEN MADE WORSE WITH THE ADDITION OF YET MORE ANTS!!", forced = /datum/status_effect/ants)
|
||||
ants_remaining += amount_left
|
||||
. = ..()
|
||||
|
||||
/datum/status_effect/ants/on_remove()
|
||||
ants_remaining = 0
|
||||
to_chat(owner, "<span class='notice'>All of the ants are off of your body!</span>")
|
||||
UnregisterSignal(owner, COMSIG_COMPONENT_CLEAN_ACT, .proc/ants_washed)
|
||||
. = ..()
|
||||
|
||||
/datum/status_effect/ants/proc/ants_washed()
|
||||
SIGNAL_HANDLER
|
||||
owner.remove_status_effect(STATUS_EFFECT_ANTS)
|
||||
return COMPONENT_CLEANED
|
||||
|
||||
/datum/status_effect/ants/tick()
|
||||
var/mob/living/carbon/human/victim = owner
|
||||
victim.adjustBruteLoss(max(0.1, round((ants_remaining * 0.004),0.1))) //Scales with # of ants (lowers with time). Roughly 10 brute over 50 seconds.
|
||||
if(victim.stat <= SOFT_CRIT) //Makes sure people don't scratch at themselves while they're unconcious
|
||||
if(prob(15))
|
||||
switch(rand(1,2))
|
||||
if(1)
|
||||
victim.say(pick("GET THEM OFF ME!!", "OH GOD THE ANTS!!", "MAKE IT END!!", "THEY'RE EVERYWHERE!!", "GET THEM OFF!!", "SOMEBODY HELP ME!!"), forced = /datum/status_effect/ants)
|
||||
if(2)
|
||||
victim.emote("scream")
|
||||
if(prob(50))
|
||||
switch(rand(1,50))
|
||||
if (1 to 8) //16% Chance
|
||||
var/obj/item/bodypart/head/hed = victim.get_bodypart(BODY_ZONE_HEAD)
|
||||
to_chat(victim, "<span class='danger'>You scratch at the ants on your scalp!.</span>")
|
||||
hed.receive_damage(0.1,0)
|
||||
if (9 to 29) //40% chance
|
||||
var/obj/item/bodypart/arm = victim.get_bodypart(pick(BODY_ZONE_L_ARM,BODY_ZONE_R_ARM))
|
||||
to_chat(victim, "<span class='danger'>You scratch at the ants on your arms!</span>")
|
||||
arm.receive_damage(0.1,0)
|
||||
if (30 to 49) //38% chance
|
||||
var/obj/item/bodypart/leg = victim.get_bodypart(pick(BODY_ZONE_L_LEG,BODY_ZONE_R_LEG))
|
||||
to_chat(victim, "<span class='danger'>You scratch at the ants on your leg!</span>")
|
||||
leg.receive_damage(0.1,0)
|
||||
if(50) // 2% chance
|
||||
to_chat(victim, "<span class='danger'>You rub some ants away from your eyes!</span>")
|
||||
victim.blur_eyes(3)
|
||||
ants_remaining -= 5 // To balance out the blindness, it'll be a little shorter.
|
||||
ants_remaining--
|
||||
if(ants_remaining <= 0 || victim.stat >= HARD_CRIT)
|
||||
victim.remove_status_effect(STATUS_EFFECT_ANTS) //If this person has no more ants on them or are dead, they are no longer affected.
|
||||
|
||||
/atom/movable/screen/alert/status_effect/ants
|
||||
name = "Ants!"
|
||||
desc = "<span class='warning'>JESUS FUCKING CHRIST! CLICK TO GET THOSE THINGS OFF!</span>"
|
||||
icon_state = "antalert"
|
||||
|
||||
/atom/movable/screen/alert/status_effect/ants/Click()
|
||||
var/mob/living/living = owner
|
||||
if(!istype(living) || !living.can_resist() || living != owner)
|
||||
return
|
||||
to_chat(living, "<span class='notice'>You start to shake the ants off!</span>")
|
||||
if(!do_after(living, 2 SECONDS, target = living))
|
||||
return
|
||||
for (var/datum/status_effect/ants/ant_covered in living.status_effects)
|
||||
to_chat(living, "<span class='notice'>You manage to get some of the ants off!</span>")
|
||||
ant_covered.ants_remaining -= 10 // 5 Times more ants removed per second than just waiting in place
|
||||
|
||||
/datum/status_effect/ghoul
|
||||
id = "ghoul"
|
||||
@@ -980,4 +1065,4 @@
|
||||
name = "Flesh Servant"
|
||||
desc = "You are a Ghoul! A eldritch monster reanimated to serve its master."
|
||||
icon_state = "mind_control"
|
||||
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
/datum/status_effect/proc/before_remove() //! Called before being removed; returning FALSE will cancel removal
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/proc/refresh()
|
||||
/datum/status_effect/proc/refresh(effect, ...)
|
||||
var/original_duration = initial(duration)
|
||||
if(original_duration == -1)
|
||||
return
|
||||
@@ -112,17 +112,17 @@
|
||||
. = FALSE
|
||||
var/datum/status_effect/S1 = effect
|
||||
LAZYINITLIST(status_effects)
|
||||
var/list/arguments = args.Copy()
|
||||
arguments[1] = src
|
||||
for(var/datum/status_effect/S in status_effects)
|
||||
if(S.id == initial(S1.id) && S.status_type)
|
||||
if(S.status_type == STATUS_EFFECT_REPLACE)
|
||||
S.be_replaced()
|
||||
else if(S.status_type == STATUS_EFFECT_REFRESH)
|
||||
S.refresh()
|
||||
S.refresh(arglist(arguments))
|
||||
return
|
||||
else
|
||||
return
|
||||
var/list/arguments = args.Copy()
|
||||
arguments[1] = src
|
||||
S1 = new effect(arguments)
|
||||
. = S1
|
||||
|
||||
|
||||
@@ -257,3 +257,20 @@
|
||||
/obj/effect/decal/cleanable/garbage/Initialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/swabable, CELL_LINE_TABLE_SLUDGE, CELL_VIRUS_TABLE_GENERIC, rand(2,4), 15)
|
||||
|
||||
/obj/effect/decal/cleanable/ants
|
||||
name = "space ants"
|
||||
desc = "A small colony of space ants. They're normally used to the vacuum of space, so they can't climb too well."
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "spaceants"
|
||||
beauty = -150
|
||||
|
||||
/obj/effect/decal/cleanable/ants/Initialize(mapload)
|
||||
. = ..()
|
||||
var/scale = (rand(6, 8) / 10) + (rand(2, 5) / 50)
|
||||
transform = matrix(transform, scale, scale, MATRIX_SCALE)
|
||||
setDir(pick(GLOB.cardinals))
|
||||
reagents.add_reagent(/datum/reagent/ants, rand(2, 5))
|
||||
pixel_x = rand(-5, 5)
|
||||
pixel_y = rand(-5, 5)
|
||||
AddElement(/datum/element/caltrop, min_damage = 0.2, max_damage = 1, flags = (CALTROP_NOCRAWL | CALTROP_NOSTUN | CALTROP_BYPASS_SHOES), soundfile = 'sound/weapons/bite.ogg')
|
||||
|
||||
@@ -11,5 +11,6 @@
|
||||
/obj/effect/decal/cleanable/wrapping = 5,
|
||||
/obj/effect/decal/cleanable/plastic = 5,
|
||||
/obj/effect/decal/cleanable/glass = 5,
|
||||
/obj/effect/decal/cleanable/dirt = 30
|
||||
/obj/effect/decal/cleanable/dirt = 30,
|
||||
/obj/effect/decal/cleanable/ants = 5,
|
||||
)
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
var/burns_on_grill = FALSE
|
||||
///Price of this food if sold in a venue
|
||||
var/venue_value
|
||||
///Food that's immune to decomposition.
|
||||
var/preserved_food = FALSE
|
||||
|
||||
/obj/item/food/Initialize()
|
||||
. = ..()
|
||||
@@ -51,6 +53,7 @@
|
||||
MakeProcessable()
|
||||
MakeLeaveTrash()
|
||||
MakeGrillable()
|
||||
MakeDecompose()
|
||||
|
||||
///This proc adds the edible component, overwrite this if you for some reason want to change some specific args like callbacks.
|
||||
/obj/item/food/proc/MakeEdible()
|
||||
@@ -82,3 +85,8 @@
|
||||
if(trash_type)
|
||||
AddElement(/datum/element/food_trash, trash_type)
|
||||
return
|
||||
|
||||
///This proc makes things decompose. Set preserved_food to TRUE to make it never decompose.
|
||||
/obj/item/food/proc/MakeDecompose()
|
||||
if(!preserved_food)
|
||||
AddComponent(/datum/component/decomposition, decomp_flags = foodtypes)
|
||||
|
||||
@@ -190,6 +190,7 @@
|
||||
food_reagents = list(/datum/reagent/toxin/bad_food = 30)
|
||||
foodtypes = GROSS
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
preserved_food = TRUE //Can't decompose any more than this
|
||||
|
||||
/obj/item/food/badrecipe/Initialize()
|
||||
. = ..()
|
||||
@@ -197,7 +198,7 @@
|
||||
|
||||
/obj/item/food/badrecipe/moldy
|
||||
name = "moldy mess"
|
||||
desc = "A rancid, living culture of mold. Somewhere, under there, at SOME POINT... there was food."
|
||||
desc = "A rancid, disgusting culture of mold and ants. Somewhere under there, at <i>some point,</i> there was food."
|
||||
food_reagents = list(/datum/reagent/consumable/mold = 30)
|
||||
|
||||
/obj/item/food/badrecipe/moldy/Initialize()
|
||||
@@ -592,12 +593,15 @@
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
max_volume = 30
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
preserved_food = TRUE
|
||||
|
||||
|
||||
/obj/item/food/canned/proc/open_can(mob/user)
|
||||
to_chat(user, span_notice("You pull back the tab of \the [src]."))
|
||||
playsound(user.loc, 'sound/items/foodcanopen.ogg', 50)
|
||||
reagents.flags |= OPENCONTAINER
|
||||
preserved_food = FALSE
|
||||
MakeDecompose()
|
||||
|
||||
/obj/item/food/canned/attack_self(mob/user)
|
||||
if(!is_drainable())
|
||||
@@ -691,3 +695,13 @@
|
||||
|
||||
/obj/item/food/rationpack/proc/check_liked(fraction, mob/M) //Nobody likes rationpacks. Nobody.
|
||||
return FOOD_DISLIKED
|
||||
|
||||
/obj/item/food/ant_candy
|
||||
name = "ant candy"
|
||||
desc = "A colony of ants suspended in hardened sugar. Those things are dead, right?"
|
||||
icon_state = "ant_pop"
|
||||
food_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1, /datum/reagent/consumable/sugar = 5, /datum/reagent/ants = 3)
|
||||
tastes = list("candy" = 1, "insects" = 1)
|
||||
foodtypes = JUNKFOOD | SUGAR | GROSS
|
||||
food_flags = FOOD_FINGER_FOOD
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
@@ -252,3 +252,21 @@
|
||||
/obj/item/food/pizzaslice/arnold/attackby(obj/item/I, mob/user)
|
||||
i_kill_you(I, user)
|
||||
. = ..()
|
||||
|
||||
// Ant Pizza, now with more ants.
|
||||
/obj/item/food/pizza/ants
|
||||
name = "\improper Ant Party pizza"
|
||||
desc = "/// Filled with bugs, remember to fix"
|
||||
icon_state = "antpizza"
|
||||
food_reagents = list(/datum/reagent/consumable/nutriment = 20, /datum/reagent/ants = 25, /datum/reagent/consumable/tomatojuice = 10, /datum/reagent/consumable/nutriment/vitamin = 4, /datum/reagent/consumable/nutriment/protein = 2)
|
||||
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "insects" = 1)
|
||||
foodtypes = GRAIN | VEGETABLES | DAIRY | GROSS
|
||||
slice_type = /obj/item/food/pizzaslice/ants
|
||||
boxtag = "Anthill Deluxe"
|
||||
|
||||
/obj/item/food/pizzaslice/ants
|
||||
name = "\improper Ant Party pizza slice"
|
||||
desc = "The key to a perfect slice of pizza is not to overdo it with the ants."
|
||||
icon_state = "antpizzaslice"
|
||||
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "insects" = 1)
|
||||
foodtypes = GRAIN | VEGETABLES | DAIRY | GROSS
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
if(prob(80)) //mid dirt - 1/15
|
||||
return
|
||||
|
||||
//Construction zones. Blood, sweat, and oil. Oh, and dirt.
|
||||
//Construction zones. Blood, sweat, and oil. Oh, and dirt. A small colony of space-ants or two will pop up
|
||||
var/static/list/engine_dirt_areas = typecacheof(list(/area/engineering,
|
||||
/area/command/heads_quarters/ce,
|
||||
/area/science/robotics,
|
||||
@@ -49,13 +49,16 @@
|
||||
if(prob(3))
|
||||
new /obj/effect/decal/cleanable/blood/old(src)
|
||||
else
|
||||
if(prob(35))
|
||||
if(prob(4))
|
||||
new /obj/effect/decal/cleanable/robot_debris/old(src)
|
||||
else
|
||||
new /obj/effect/decal/cleanable/oil(src)
|
||||
else
|
||||
new /obj/effect/decal/cleanable/dirt(src)
|
||||
switch (rand(1, 100))
|
||||
if(1 to 35)//35%
|
||||
if(prob(4))
|
||||
new /obj/effect/decal/cleanable/robot_debris/old(src)
|
||||
else
|
||||
new /obj/effect/decal/cleanable/oil(src)
|
||||
if(35 to 95)//60%
|
||||
new /obj/effect/decal/cleanable/dirt(src)
|
||||
if(95 to 100)//5%
|
||||
new /obj/effect/decal/cleanable/ants(src)
|
||||
return
|
||||
|
||||
//Bathrooms. Blood, vomit, and shavings in the sinks.
|
||||
@@ -67,6 +70,8 @@
|
||||
new /obj/effect/decal/cleanable/vomit/old(src)
|
||||
else
|
||||
new /obj/effect/decal/cleanable/blood/old(src)
|
||||
else if(prob(40)) //16% effective chance
|
||||
new /obj/effect/decal/cleanable/ants(src)
|
||||
return
|
||||
|
||||
// Cargo bays covered in oil.
|
||||
@@ -95,7 +100,7 @@
|
||||
new /obj/effect/decal/cleanable/blood/old(src)
|
||||
return
|
||||
|
||||
//Kitchen areas. Broken eggs, flour, spilled milk (no crying allowed.)
|
||||
//Kitchen areas. Broken eggs, flour, spilled milk (no crying allowed.), ants.
|
||||
var/static/list/kitchen_dirt_areas = typecacheof(list(/area/service/kitchen,
|
||||
/area/service/cafeteria))
|
||||
if(is_type_in_typecache(A, kitchen_dirt_areas))
|
||||
@@ -104,6 +109,8 @@
|
||||
new /obj/effect/decal/cleanable/food/egg_smudge(src)
|
||||
else
|
||||
new /obj/effect/decal/cleanable/food/flour(src)
|
||||
else if(prob(20)) //12% effective chance
|
||||
new /obj/effect/decal/cleanable/ants(src)
|
||||
return
|
||||
|
||||
//Medical areas. Mostly clean by space-OSHA standards, but has some blood and oil spread about.
|
||||
|
||||
@@ -193,3 +193,13 @@
|
||||
)
|
||||
result = /obj/item/food/cheese/royal
|
||||
subcategory = CAT_MISCFOOD
|
||||
|
||||
/datum/crafting_recipe/food/ant_candy
|
||||
name = "Ant Candy"
|
||||
reqs = list(/obj/item/stack/rods = 1,
|
||||
/datum/reagent/consumable/sugar = 5,
|
||||
/datum/reagent/water = 5,
|
||||
/datum/reagent/ants = 10
|
||||
)
|
||||
result = /obj/item/food/ant_candy
|
||||
subcategory = CAT_MISCFOOD
|
||||
|
||||
@@ -101,3 +101,14 @@
|
||||
)
|
||||
result = /obj/item/food/pizza/pineapple
|
||||
subcategory = CAT_PIZZA
|
||||
|
||||
/datum/crafting_recipe/food/antspizza
|
||||
name = "Ant Party pizza"
|
||||
reqs = list(
|
||||
/obj/item/food/pizzabread = 1,
|
||||
/obj/item/food/cheese = 2,
|
||||
/obj/item/food/grown/tomato = 1,
|
||||
/datum/reagent/ants = 20
|
||||
)
|
||||
result = /obj/item/food/pizza/ants
|
||||
subcategory = CAT_PIZZA
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/mob/living/simple_animal/ant
|
||||
name = "giant ant"
|
||||
desc = "A writhing mass of ants, glued together to make an adorable pet!"
|
||||
icon = 'icons/mob/pets.dmi'
|
||||
icon_state = "ant"
|
||||
icon_living = "ant"
|
||||
icon_dead = "ant_dead"
|
||||
speak = list("BZZZZT!", "CHTCHTCHT!", "Bzzz", "ChtChtCht")
|
||||
speak_emote = list("buzzes", "chitters")
|
||||
emote_hear = list("buzzes.", "clacks.")
|
||||
emote_see = list("shakes its head.", "twitches its antennae.")
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
pass_flags = PASSTABLE
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BUG
|
||||
minbodytemp = 200
|
||||
maxbodytemp = 400
|
||||
unsuitable_atmos_damage = 1
|
||||
butcher_results = list(/obj/item/food/meat/slab = 2, /obj/effect/decal/cleanable/ants = 1) //It's just a bunch of ants glued together into a larger ant
|
||||
response_help_continuous = "pets"
|
||||
response_help_simple = "pet"
|
||||
response_disarm_continuous = "gently pushes aside"
|
||||
response_disarm_simple = "gently push aside"
|
||||
response_harm_continuous = "kicks"
|
||||
response_harm_simple = "kick"
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
can_be_held = FALSE
|
||||
footstep_type = FOOTSTEP_MOB_CLAW
|
||||
health = 75
|
||||
maxHealth = 75
|
||||
// randomizes hunting intervals, minimum 5 turns
|
||||
var/time_to_hunt = 5
|
||||
|
||||
/mob/living/simple_animal/ant/Initialize()
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
|
||||
time_to_hunt = rand(5,10)
|
||||
|
||||
/mob/living/simple_animal/ant/Life(delta_time = SSMOBS_DT, times_fired) // In this larger state, the ants have become the predators.
|
||||
. = ..()
|
||||
turns_since_scan++
|
||||
if(turns_since_scan > time_to_hunt)
|
||||
turns_since_scan = 0
|
||||
var/list/target_types = list(/mob/living/simple_animal/hostile/cockroach)
|
||||
for(var/mob/living/simple_animal/hostile/potential_target in view(2, get_turf(src)))
|
||||
if(potential_target.type in target_types)
|
||||
hunt(potential_target)
|
||||
return
|
||||
@@ -29,12 +29,7 @@
|
||||
response_harm_continuous = "kicks"
|
||||
response_harm_simple = "kick"
|
||||
mobility_flags = MOBILITY_FLAGS_REST_CAPABLE_DEFAULT
|
||||
var/turns_since_scan = 0
|
||||
var/mob/living/simple_animal/mouse/movement_target
|
||||
///Limits how often cats can spam chasing mice.
|
||||
COOLDOWN_DECLARE(emote_cooldown)
|
||||
///Can this cat catch special mice?
|
||||
var/inept_hunter = FALSE
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
collar_type = "cat"
|
||||
can_be_held = TRUE
|
||||
|
||||
@@ -31,13 +31,16 @@
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
faction = list("neutral")
|
||||
var/squish_chance = 50
|
||||
// Randomizes hunting intervals, minumum 5 turns
|
||||
var/time_to_hunt = 5
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/cockroach/Initialize()
|
||||
. = ..()
|
||||
add_cell_sample()
|
||||
make_squashable()
|
||||
|
||||
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
|
||||
time_to_hunt = rand(5,10)
|
||||
|
||||
/mob/living/simple_animal/hostile/cockroach/proc/make_squashable()
|
||||
AddComponent(/datum/component/squashable, squash_chance = 50, squash_damage = 1)
|
||||
@@ -45,6 +48,18 @@
|
||||
/mob/living/simple_animal/hostile/cockroach/add_cell_sample()
|
||||
AddElement(/datum/element/swabable, CELL_LINE_TABLE_COCKROACH, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 7)
|
||||
|
||||
/mob/living/simple_animal/hostile/cockroach/Life(delta_time = SSMOBS_DT, times_fired) // Cockroaches are predators to space ants
|
||||
. = ..()
|
||||
turns_since_scan++
|
||||
if(turns_since_scan > time_to_hunt)
|
||||
turns_since_scan = 0
|
||||
var/list/target_types = list(/obj/effect/decal/cleanable/ants)
|
||||
for(var/obj/effect/decal/cleanable/ants/potential_target in view(2, get_turf(src)))
|
||||
if(potential_target.type in target_types)
|
||||
hunt(potential_target)
|
||||
return
|
||||
|
||||
|
||||
/obj/projectile/glockroachbullet
|
||||
damage = 10 //same damage as a hivebot
|
||||
damage_type = BRUTE
|
||||
|
||||
@@ -156,6 +156,13 @@
|
||||
///Generic flags
|
||||
var/simple_mob_flags = NONE
|
||||
|
||||
///Limits how often mobs can hunt other mobs
|
||||
COOLDOWN_DECLARE(emote_cooldown)
|
||||
var/turns_since_scan = 0
|
||||
|
||||
///Is this animal horrible at hunting?
|
||||
var/inept_hunter = FALSE
|
||||
|
||||
|
||||
/mob/living/simple_animal/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -684,3 +691,41 @@
|
||||
|
||||
/mob/living/simple_animal/proc/stop_deadchat_plays()
|
||||
stop_automated_movement = FALSE
|
||||
|
||||
|
||||
//Makes this mob hunt the prey, be it living or an object. Will kill living creatures, and delete objects.
|
||||
/mob/living/simple_animal/proc/hunt(hunted)
|
||||
if(src == hunted) //Make sure it doesn't eat itself. While not likely to ever happen, might as well check just in case.
|
||||
return
|
||||
stop_automated_movement = FALSE
|
||||
if(!isturf(src.loc)) // Are we on a proper turf?
|
||||
return
|
||||
if(stat || resting || buckled) // Are we concious, upright, and not buckled?
|
||||
return
|
||||
if(!COOLDOWN_FINISHED(src, emote_cooldown)) // Has the cooldown on this ended?
|
||||
return
|
||||
if(!Adjacent(hunted))
|
||||
stop_automated_movement = TRUE
|
||||
walk_to(src,hunted,0,3)
|
||||
if(Adjacent(hunted))
|
||||
hunt(hunted) // In case it gets next to the target immediately, skip the scan timer and kill it.
|
||||
return
|
||||
if(isliving(hunted)) // Are we hunting a living mob?
|
||||
var/mob/living/prey = hunted
|
||||
if(inept_hunter) // Make your hunter inept to have them unable to catch their prey.
|
||||
visible_message("<span class='warning'>[src] chases [prey] around, to no avail!</span>")
|
||||
step(prey, pick(GLOB.cardinals))
|
||||
COOLDOWN_START(src, emote_cooldown, 1 MINUTES)
|
||||
return
|
||||
if(!(prey.stat))
|
||||
manual_emote("chomps [prey]!")
|
||||
prey.death()
|
||||
prey = null
|
||||
COOLDOWN_START(src, emote_cooldown, 1 MINUTES)
|
||||
return
|
||||
else // We're hunting an object, and should delete it instead of killing it. Mostly useful for decal bugs like ants or spider webs.
|
||||
manual_emote("chomps [hunted]!")
|
||||
qdel(hunted)
|
||||
hunted = null
|
||||
COOLDOWN_START(src, emote_cooldown, 1 MINUTES)
|
||||
return
|
||||
|
||||
@@ -2715,3 +2715,46 @@
|
||||
var/color
|
||||
CONVERT_PH_TO_COLOR(exposed_atom.reagents.ph, color)
|
||||
exposed_atom.add_atom_colour(color, WASHABLE_COLOUR_PRIORITY)
|
||||
|
||||
/datum/reagent/ants
|
||||
name = "Ants"
|
||||
description = "A sample of a lost breed of Space Ants (formicidae bastardium tyrannus), they are well-known for ravaging the living shit out of pretty much anything."
|
||||
reagent_state = SOLID
|
||||
color = "#993333"
|
||||
taste_mult = 1.3
|
||||
taste_description = "tiny legs scuttling down the back of your throat."
|
||||
metabolization_rate = 5 * REAGENTS_METABOLISM //1u per second
|
||||
glass_name = "glass of ants"
|
||||
glass_desc = "Bottoms up...?"
|
||||
ph = 4.6 // Ants contain Formic Acid
|
||||
/// How much damage the ants are going to be doing (rises with each tick the ants are in someone's body)
|
||||
var/ant_damage = 0
|
||||
/// Tells the debuff how many ants we are being covered with.
|
||||
var/amount_left = 0
|
||||
|
||||
/datum/reagent/ants/on_mob_life(mob/living/carbon/victim, delta_time)
|
||||
victim.adjustBruteLoss(max(0.1, round((ant_damage * 0.005),0.1))) //Scales with time. Around 12.5 brute for 50 seconds.
|
||||
if(DT_PROB(5, delta_time))
|
||||
if(DT_PROB(5, delta_time)) //Super rare statement
|
||||
victim.say("AUGH NO NOT THE ANTS! NOT THE ANTS! AAAAUUGH THEY'RE IN MY EYES! MY EYES! AUUGH!!", forced = /datum/reagent/ants)
|
||||
else
|
||||
victim.say(pick("THEY'RE UNDER MY SKIN!!", "GET THEM OUT OF ME!!", "HOLY HELL THEY BURN!!", "MY GOD THEY'RE INSIDE ME!!", "GET THEM OUT!!"), forced = /datum/reagent/ants)
|
||||
if(DT_PROB(15, delta_time))
|
||||
victim.emote("scream")
|
||||
if(DT_PROB(2, delta_time))
|
||||
victim.vomit(rand(1, 2), stun = FALSE)
|
||||
ant_damage += 1
|
||||
return ..()
|
||||
|
||||
/datum/reagent/ants/on_mob_end_metabolize(mob/living/living_anthill)
|
||||
ant_damage = 0
|
||||
to_chat(living_anthill, "<span class='notice'>You feel like the last of the ants are out of your system.</span>")
|
||||
return ..()
|
||||
|
||||
/datum/reagent/ants/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume)
|
||||
. = ..()
|
||||
if(!iscarbon(exposed_mob) || (methods & (INGEST|INJECT)))
|
||||
return
|
||||
if(methods & (PATCH|TOUCH|VAPOR))
|
||||
amount_left = round(reac_volume,0.1)
|
||||
exposed_mob.apply_status_effect(STATUS_EFFECT_ANTS, amount_left)
|
||||
|
||||
@@ -908,3 +908,19 @@
|
||||
return
|
||||
clear_products(holder, step_volume_added)
|
||||
holder.my_atom.audible_message(span_notice("[icon2html(holder.my_atom, viewers(DEFAULT_MESSAGE_RANGE, src))] The reaction gives out a fizz, teleporting items everywhere!"))
|
||||
|
||||
/datum/chemical_reaction/ants
|
||||
results = list(/datum/reagent/ants = 3)
|
||||
required_reagents = list(/datum/reagent/ants = 2, /datum/reagent/consumable/sugar = 6)
|
||||
|
||||
/datum/chemical_reaction/ant_slurry // We're basically glueing ants together with synthflesh & maint sludge to make a bigger ant.
|
||||
required_reagents = list(/datum/reagent/ants = 40, /datum/reagent/medicine/c2/synthflesh = 20, /datum/reagent/drug/maint/sludge = 5)
|
||||
required_temp = 480
|
||||
reaction_flags = REACTION_INSTANT
|
||||
reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE
|
||||
|
||||
/datum/chemical_reaction/ant_slurry/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
|
||||
var/location = get_turf(holder.my_atom)
|
||||
for(var/i in rand(1, created_volume) to created_volume)
|
||||
new /mob/living/simple_animal/ant(location)
|
||||
..()
|
||||
|
||||
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 103 KiB |
@@ -641,6 +641,7 @@
|
||||
#include "code\datums\components\fantasy\affix.dm"
|
||||
#include "code\datums\components\fantasy\prefixes.dm"
|
||||
#include "code\datums\components\fantasy\suffixes.dm"
|
||||
#include "code\datums\components\food\decomposition.dm"
|
||||
#include "code\datums\components\food\edible.dm"
|
||||
#include "code\datums\components\food\ice_cream_holder.dm"
|
||||
#include "code\datums\components\plumbing\_plumbing.dm"
|
||||
@@ -2743,6 +2744,7 @@
|
||||
#include "code\modules\mob\living\simple_animal\bot\secbot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\bot\SuperBeepsky.dm"
|
||||
#include "code\modules\mob\living\simple_animal\bot\vibebot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\ant.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\butterfly.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\cat.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\crab.dm"
|
||||
|
||||