Files
S.P.L.U.R.T-Station-13/code/modules/mob/living/simple_animal/slime/slime.dm
Solaris-Shade 2fdb70b2b9 [DNM][DNM][WIP] Projectile backend code port and update
Ports#54924,  #65061, #59804 from /tg.
adds auxiliary code from /tg to make code work.
2022-03-06 15:20:23 -05:00

495 lines
16 KiB
Plaintext

/mob/living/simple_animal/slime
name = "grey baby slime (123)"
icon = 'icons/mob/slimes.dmi'
icon_state = "grey baby slime"
pass_flags = PASSTABLE
mob_size = MOB_SIZE_SMALL
gender = NEUTER
var/is_adult = 0
var/docile = 0
faction = list("slime","neutral")
harm_intent_damage = 5
icon_living = "grey baby slime"
icon_dead = "grey baby slime dead"
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "shoos"
response_disarm_simple = "shoo"
response_harm_continuous = "stomps on"
response_harm_simple = "stomp on"
emote_see = list("jiggles", "bounces in place")
speak_emote = list("blorbles")
bubble_icon = "slime"
initial_language_holder = /datum/language_holder/slime
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
maxHealth = 150
health = 150
healable = 0
gender = NEUTER
blood_volume = 0 //Until someome reworks for them to have slime jelly
nutrition = 700
see_in_dark = 8
verb_say = "blorbles"
verb_ask = "inquisitively blorbles"
verb_exclaim = "loudly blorbles"
verb_yell = "loudly blorbles"
// canstun and canknockdown don't affect slimes because they ignore stun and knockdown variables
// for the sake of cleanliness, though, here they are.
status_flags = CANUNCONSCIOUS|CANPUSH
var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside
var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35
var/powerlevel = 0 // 1-10 controls how much electricity they are generating
var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces
var/number = 0 // Used to understand when someone is talking to it
var/mob/living/Target = null // AI variable - tells the slime to hunt this down
var/mob/living/Leader = null // AI variable - tells the slime to follow this person
var/attacked = 0 // Determines if it's been attacked recently. Can be any number, is a cooloff-ish variable
var/rabid = 0 // If set to 1, the slime will attack and eat anything it comes in contact with
var/holding_still = 0 // AI variable, cooloff-ish for how long it's going to stay in one place
var/target_patience = 0 // AI variable, cooloff-ish for how long it's going to follow its target
var/list/Friends = list() // A list of friends; they are not considered targets for feeding; passed down after splitting
var/list/speech_buffer = list() // Last phrase said near it and person who said it
var/mood = "" // To show its face
var/mutator_used = FALSE //So you can't shove a dozen mutators into a single slime
var/force_stasis = FALSE
var/static/regex/slime_name_regex = new("\\w+ (baby|adult) slime \\(\\d+\\)")
///////////TIME FOR SUBSPECIES
var/colour = "grey"
var/coretype = /obj/item/slime_extract/grey
var/list/slime_mutation
var/static/list/color_mutation_cache = list()
var/static/list/slime_colours = list("rainbow", "grey", "purple", "metal", "orange",
"blue", "dark blue", "dark purple", "yellow", "silver", "pink", "red",
"gold", "green", "adamantine", "oil", "light pink", "bluespace",
"cerulean", "sepia", "black", "pyrite")
///////////CORE-CROSSING CODE
var/effectmod //What core modification is being used.
var/applied = 0 //How many extracts of the modtype have been applied.
/mob/living/simple_animal/slime/Initialize(mapload, new_colour="grey", new_is_adult=FALSE)
initialize_mutations()
var/datum/action/innate/slime/feed/F = new
F.Grant(src)
is_adult = new_is_adult
if(is_adult)
var/datum/action/innate/slime/reproduce/R = new
R.Grant(src)
health = 200
maxHealth = 200
else
var/datum/action/innate/slime/evolve/E = new
E.Grant(src)
create_reagents(100, NONE, NO_REAGENTS_VALUE)
set_colour(new_colour)
. = ..()
AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 7.5)
set_nutrition(rand(650, 800))
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/slime/Destroy()
for (var/A in actions)
var/datum/action/AC = A
AC.Remove(src)
return ..()
/mob/living/simple_animal/slime/proc/initialize_mutations()
var/list/cached = color_mutation_cache[colour]
if(!cached)
cached = color_mutation_cache[colour] = mutation_table(colour)
slime_mutation = cached
/mob/living/simple_animal/slime/proc/set_colour(new_colour)
colour = new_colour
update_name()
initialize_mutations()
var/sanitizedcolour = replacetext(colour, " ", "")
coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]")
regenerate_icons()
/mob/living/simple_animal/slime/update_name()
if(slime_name_regex.Find(name))
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
real_name = name
/mob/living/simple_animal/slime/proc/random_colour()
set_colour(pick(slime_colours))
/mob/living/simple_animal/slime/regenerate_icons()
cut_overlays()
var/icon_text = "[colour] [is_adult ? "adult" : "baby"] slime"
icon_dead = "[icon_text] dead"
if(stat != DEAD)
icon_state = icon_text
if(mood && !stat)
add_overlay("aslime-[mood]")
else
icon_state = icon_dead
..()
/mob/living/simple_animal/slime/on_reagent_change()
. = ..()
remove_movespeed_modifier(/datum/movespeed_modifier/slime_reagentmod)
var/amount = 0
if(reagents.has_reagent(/datum/reagent/medicine/morphine)) // morphine slows slimes down
amount = 2
if(reagents.has_reagent(/datum/reagent/consumable/frostoil)) // Frostoil also makes them move VEEERRYYYYY slow
amount = 5
if(amount)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_reagentmod, multiplicative_slowdown = amount)
/mob/living/simple_animal/slime/updatehealth()
. = ..()
remove_movespeed_modifier(/datum/movespeed_modifier/slime_healthmod)
var/mod = 0
if(!HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN))
var/health_deficiency = (maxHealth - health)
if(health_deficiency >= 45)
mod += (health_deficiency / 25)
if(health <= 0)
mod += 2
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_healthmod, multiplicative_slowdown = mod)
/mob/living/simple_animal/slime/adjust_bodytemperature()
. = ..()
var/mod = 0
if(bodytemperature >= 330.23) // 135 F or 57.08 C
mod = -1 // slimes become supercharged at high temperatures
else if(bodytemperature < 183.222)
mod = min(15, (283.222 - bodytemperature) / 10 * 1.75)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_tempmod, multiplicative_slowdown = mod)
/mob/living/simple_animal/slime/ObjBump(obj/O)
if(!client && powerlevel > 0)
var/probab = 10
switch(powerlevel)
if(1 to 2)
probab = 20
if(3 to 4)
probab = 30
if(5 to 6)
probab = 40
if(7 to 8)
probab = 60
if(9)
probab = 70
if(10)
probab = 95
if(prob(probab))
if(istype(O, /obj/structure/window) || istype(O, /obj/structure/grille))
if(nutrition <= get_hunger_nutrition() && !Atkcool)
if (is_adult || prob(5))
O.attack_slime(src)
Atkcool = 1
spawn(45)
Atkcool = 0
/mob/living/simple_animal/slime/Process_Spacemove(movement_dir = 0)
return 2
/mob/living/simple_animal/slime/get_status_tab_items()
. = ..()
if(!docile)
. += "Nutrition: [nutrition]/[get_max_nutrition()]"
if(amount_grown >= SLIME_EVOLUTION_THRESHOLD)
if(is_adult)
. += "You can reproduce!"
else
. += "You can evolve!"
if(stat == UNCONSCIOUS)
. += "You are knocked out by high levels of BZ!"
else
. += "Power Level: [powerlevel]"
/mob/living/simple_animal/slime/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE)
if(!forced)
amount = -abs(amount)
return ..() //Heals them
/mob/living/simple_animal/slime/bullet_act(obj/item/projectile/Proj, def_zone, piercing_hit = FALSE)
attacked += 10
if((Proj.damage_type == BURN))
adjustBruteLoss(-abs(Proj.damage)) //fire projectiles heals slimes.
Proj.on_hit(src, 0, piercing_hit)
return BULLET_ACT_BLOCK
return ..()
/mob/living/simple_animal/slime/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
powerlevel = 0 // oh no, the power!
/mob/living/simple_animal/slime/MouseDrop(atom/movable/A as mob|obj)
if(isliving(A) && A != src && usr == src)
var/mob/living/Food = A
if(CanFeedon(Food))
Feedon(Food)
return ..()
/mob/living/simple_animal/slime/doUnEquip(obj/item/W, silent = FALSE)
return
/mob/living/simple_animal/slime/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
return
/mob/living/simple_animal/slime/attack_ui(slot)
return
/mob/living/simple_animal/slime/attack_slime(mob/living/simple_animal/slime/M)
. = ..()
if(!. || M == src) //unsuccessful slime shock
return
if(buckled)
Feedstop(silent = TRUE)
visible_message("<span class='danger'>[M] pulls [src] off!</span>")
return
attacked += 5
if(nutrition >= 100) //steal some nutrition. negval handled in life()
adjust_nutrition(-50 - (40 * M.is_adult))
M.adjust_nutrition(50 + (40 * M.is_adult), get_max_nutrition(), TRUE)
if(health > 0)
M.adjustBruteLoss(-10 + (-10 * M.is_adult))
M.updatehealth()
/mob/living/simple_animal/slime/attack_animal(mob/living/simple_animal/M)
. = ..()
if(.)
attacked += 10
/mob/living/simple_animal/slime/attack_paw(mob/living/carbon/monkey/M)
. = ..()
if(.)//successful monkey bite.
attacked += 10
/mob/living/simple_animal/slime/attack_larva(mob/living/carbon/alien/larva/L)
. = ..()
if(.) //successful larva bite.
attacked += 10
/mob/living/simple_animal/slime/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
if(user.a_intent == INTENT_HARM)
discipline_slime(user)
return ..()
/mob/living/simple_animal/slime/on_attack_hand(mob/living/carbon/human/M)
if(buckled)
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
if(buckled == M)
if(prob(60))
visible_message("<span class='warning'>[M] attempts to wrestle \the [name] off!</span>")
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
else
visible_message("<span class='warning'>[M] manages to wrestle \the [name] off!</span>")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
discipline_slime(M)
else
if(prob(30))
visible_message("<span class='warning'>[M] attempts to wrestle \the [name] off of [buckled]!</span>")
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
else
visible_message("<span class='warning'>[M] manages to wrestle \the [name] off of [buckled]!</span>")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
discipline_slime(M)
else
if(stat == DEAD && surgeries.len)
if(M.a_intent == INTENT_HELP || M.a_intent == INTENT_DISARM)
for(var/datum/surgery/S in surgeries)
if(S.next_step(M,M.a_intent))
return 1
if(..()) //successful attack
attacked += 10
/mob/living/simple_animal/slime/attack_alien(mob/living/carbon/alien/humanoid/M)
. = ..()
if(!.) // the attack was blocked or was help/grab intent
return
attacked += 10
discipline_slime(M)
/mob/living/simple_animal/slime/attackby(obj/item/W, mob/living/user, params)
if(stat == DEAD && surgeries.len)
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
for(var/datum/surgery/S in surgeries)
if(S.next_step(user,user.a_intent))
return 1
if(istype(W, /obj/item/stack/sheet/mineral/plasma) && !stat) //Let's you feed slimes plasma.
if (user in Friends)
++Friends[user]
else
Friends[user] = 1
to_chat(user, "<span class='notice'>You feed the slime the plasma. It chirps happily.</span>")
var/obj/item/stack/sheet/mineral/plasma/S = W
S.use(1)
return
if(W.force > 0)
attacked += 10
if(prob(25))
user.do_attack_animation(src)
W.ApplyAttackCooldown(user, src)
to_chat(user, "<span class='danger'>[W] passes right through [src]!</span>")
return
if(Discipline && prob(50)) // wow, buddy, why am I getting attacked??
Discipline = 0
if(W.force >= 3)
var/force_effect = 2 * W.force
if(is_adult)
force_effect = round(W.force/2)
if(prob(10 + force_effect))
discipline_slime(user)
if(istype(W, /obj/item/storage/bag/bio))
var/obj/item/storage/P = W
if(!effectmod)
to_chat(user, "<span class='warning'>The slime is not currently being mutated.</span>")
return
var/hasOutput = FALSE //Have we outputted text?
var/hasFound = FALSE //Have we found an extract to be added?
for(var/obj/item/slime_extract/S in P.contents)
if(S.effectmod == effectmod)
SEND_SIGNAL(P, COMSIG_TRY_STORAGE_TAKE, S, get_turf(src), TRUE)
qdel(S)
applied++
hasFound = TRUE
if(applied >= SLIME_EXTRACT_CROSSING_REQUIRED)
to_chat(user, "<span class='notice'>You feed the slime as many of the extracts from the bag as you can, and it mutates!</span>")
playsound(src, 'sound/effects/attackblob.ogg', 50, 1)
spawn_corecross()
hasOutput = TRUE
break
if(!hasOutput)
if(!hasFound)
to_chat(user, "<span class='warning'>There are no extracts in the bag that this slime will accept!</span>")
else
to_chat(user, "<span class='notice'>You feed the slime some extracts from the bag.</span>")
playsound(src, 'sound/effects/attackblob.ogg', 50, 1)
return
..()
/mob/living/simple_animal/slime/proc/spawn_corecross()
var/static/list/crossbreeds = subtypesof(/obj/item/slimecross)
visible_message("<span class='danger'>[src] shudders, its mutated core consuming the rest of its body!</span>")
playsound(src, 'sound/magic/smoke.ogg', 50, 1)
var/crosspath
for(var/X in crossbreeds)
var/obj/item/slimecross/S = X
if(initial(S.colour) == colour && initial(S.effect) == effectmod)
crosspath = S
break
if(crosspath)
new crosspath(loc)
else
visible_message("<span class='warning'>The mutated core shudders, and collapses into a puddle, unable to maintain its form.</span>")
qdel(src)
/mob/living/simple_animal/slime/proc/apply_water()
adjustBruteLoss(rand(15,20))
if(!client)
if(Target) // Like cats
Target = null
++Discipline
return
/mob/living/simple_animal/slime/examine(mob/user)
. = list("<span class='info'>*---------*\nThis is [icon2html(src, user)] \a <EM>[src]</EM>!")
if (src.stat == DEAD)
. += "<span class='deadsay'>It is limp and unresponsive.</span>"
else
if (stat == UNCONSCIOUS) // Slime stasis
. += "<span class='deadsay'>It appears to be alive but unresponsive.</span>"
if (getBruteLoss())
if (getBruteLoss() < 40)
. += "<span class='warning'>It has some punctures in its flesh!"
else
. += "<span class='danger'>It has severe punctures and tears in its flesh!</span>"
switch(powerlevel)
if(2 to 3)
. += "It is flickering gently with a little electrical activity."
if(4 to 5)
. += "It is glowing gently with moderate levels of electrical activity."
if(6 to 9)
. += "<span class='warning'>It is glowing brightly with high levels of electrical activity.</span>"
if(10)
. += "<span class='warning'><B>It is radiating with massive levels of electrical activity!</B></span>"
. += "*---------*</span>"
/mob/living/simple_animal/slime/proc/discipline_slime(mob/user)
if(stat)
return
if(prob(80) && !client)
Discipline++
if(!is_adult)
if(Discipline == 1)
attacked = 0
if(Target)
Target = null
if(buckled)
Feedstop(silent = TRUE) //we unbuckle the slime from the mob it latched onto.
SStun = world.time + rand(20,60)
spawn(0)
mobility_flags &= ~(MOBILITY_MOVE)
if(user)
step_away(src,user,15)
sleep(3)
if(user)
step_away(src,user,15)
update_mobility()
/mob/living/simple_animal/slime/pet
docile = 1
/mob/living/simple_animal/slime/can_unbuckle()
return 0
/mob/living/simple_animal/slime/can_buckle()
return 0
/mob/living/simple_animal/slime/get_mob_buckling_height(mob/seat)
if(..())
return 3
/mob/living/simple_animal/slime/can_be_implanted()
return TRUE
/mob/living/simple_animal/slime/random/Initialize(mapload, new_colour, new_is_adult)
. = ..(mapload, pick(slime_colours), prob(50))