diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index a2b378ba426..ca637ad9ba7 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -300,8 +300,17 @@ obj/machinery/smartfridge/drying_rack/load() //For updating the filled overlay /obj/machinery/smartfridge/extract/accept_check(var/obj/item/O as obj) if(istype(O,/obj/item/slime_extract)) return 1 + if(istype(O,/obj/item/device/slime_scanner)) + return 1 return 0 +/obj/machinery/smartfridge/extract/New() + ..() + var/obj/item/device/slime_scanner/I = new /obj/item/device/slime_scanner(src) + load(I) + var/obj/item/device/slime_scanner/T = new /obj/item/device/slime_scanner(src) + load(T) + // ----------------------------- // Chemistry Medical Smartfridge // ----------------------------- diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index fe774ccf435..996ce6ff0b1 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -300,4 +300,48 @@ MASS SPECTROMETER name = "advanced mass-spectrometer" icon_state = "adv_spectrometer" details = 1 - origin_tech = "magnets=4;biotech=2" \ No newline at end of file + origin_tech = "magnets=4;biotech=2" + +/obj/item/device/slime_scanner + name = "slime scanner" + icon_state = "adv_spectrometer" + item_state = "analyzer" + origin_tech = "biotech=1" + w_class = 2.0 + flags = CONDUCT + throwforce = 0 + throw_speed = 3 + throw_range = 7 + m_amt = 30 + g_amt = 20 + +/obj/item/device/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob) + if (!isslime(M)) + user << "This device can only scan slimes!" + return + var/mob/living/carbon/slime/T = M + user.show_message("Slime scan results:") + user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby")) + user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition())) + if (T.nutrition < T.get_starve_nutrition()) + user.show_message("Warning: slime is starving!") + else if (T.nutrition < T.get_hunger_nutrition()) + user.show_message("Warning: slime is hungry") + user.show_message("Electric change strength: [T.powerlevel]") + user.show_message("Health: [T.health]") + if (T.slime_mutation[4] == T.colour) + user.show_message("This slime does not evolve any further") + else + if (T.slime_mutation[3] == T.slime_mutation[4]) + if (T.slime_mutation[2] == T.slime_mutation[1]) + user.show_message(text("Possible mutation: []", T.slime_mutation[3])) + user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting") + else + user.show_message(text("Possible mutations: [], [], [] (x2)", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3])) + user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") + else + user.show_message(text("Possible mutations: [], [], [], []", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3], T.slime_mutation[4])) + user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") + if (T.cores > 1) + user.show_message("Anomalious slime core amount detected") + user.show_message("Growth progress: [T.amount_grown]/10") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/metroid/death.dm b/code/modules/mob/living/carbon/metroid/death.dm index fc26fcbf5b7..5ee5bf3eda0 100644 --- a/code/modules/mob/living/carbon/metroid/death.dm +++ b/code/modules/mob/living/carbon/metroid/death.dm @@ -8,12 +8,14 @@ maxHealth = 150 revive() regenerate_icons() - name = "[colour] [is_adult ? "adult" : "baby"] slime ([rand(1, 1000)])" + number = rand(1, 1000) + name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])" return if(stat == DEAD) return stat = DEAD icon_state = "[colour] baby slime dead" + overlays = 0 for(var/mob/O in viewers(src, null)) O.show_message("The [name] seizes up and falls limp...", 1) //ded -- Urist diff --git a/code/modules/mob/living/carbon/metroid/life.dm b/code/modules/mob/living/carbon/metroid/life.dm index aec12755d58..e23f7df22ad 100644 --- a/code/modules/mob/living/carbon/metroid/life.dm +++ b/code/modules/mob/living/carbon/metroid/life.dm @@ -5,8 +5,6 @@ var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while var/SStun = 0 // stun variable - - /mob/living/carbon/slime/Life() set invisibility = 0 set background = BACKGROUND_ENABLED @@ -24,88 +22,69 @@ handle_targets() + if (!ckey) + handle_speech_and_mood() var/datum/gas_mixture/environment if(src.loc) environment = loc.return_air() - //Apparently, the person who wrote this code designed it so that //blinded get reset each cycle and then get activated later in the //code. Very ugly. I dont care. Moving this stuff here so its easy //to find it. src.blinded = null - // Basically just deletes any screen objects :< - regular_hud_updates() + regular_hud_updates() // Basically just deletes any screen objects :< - //Handle temperature/pressure differences between body and environment if(environment) - handle_environment(environment) - - //Status updates, death etc. - handle_regular_status_updates() - + handle_environment(environment) // Handle temperature/pressure differences between body and environment + handle_regular_status_updates() // Status updates, death etc. /mob/living/carbon/slime/proc/AIprocess() // the master AI process - //world << "AI proc started." if(AIproc || stat == DEAD || client) return var/hungry = 0 - var/starving = 0 - if(is_adult) - switch(nutrition) - if(400 to 1100) hungry = 1 - if(0 to 399) - starving = 1 - else - switch(nutrition) - if(150 to 900) hungry = 1 - if(0 to 149) starving = 1 + if (nutrition < get_starve_nutrition()) + hungry = 2 + else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition()) + hungry = 1 + AIproc = 1 - //world << "AIproc [AIproc] && stat != 2 [stat] && (attacked > 0 [attacked] || starving [starving] || hungry [hungry] || rabid [rabid] || Victim [Victim] || Target [Target]" - while(AIproc && stat != 2 && (attacked > 0 || starving || hungry || rabid || Victim)) + + while(AIproc && stat != 2 && (attacked || hungry || rabid || Victim)) if(Victim) // can't eat AND have this little process at the same time - //world << "break 1" break if(!Target || client) - //world << "break 2" break - if(Target.health <= -70 || Target.stat == 2) Target = null AIproc = 0 - //world << "break 3" break if(Target) - //world << "[Target] Target Found" for(var/mob/living/carbon/slime/M in view(1,Target)) if(M.Victim == Target) Target = null AIproc = 0 - //world << "break 4" break if(!AIproc) - //world << "break 5" break if(Target in view(1,src)) - if(istype(Target, /mob/living/silicon)) if(!Atkcool) spawn() Atkcool = 1 - sleep(15) + sleep(45) Atkcool = 0 if(Target.Adjacent(src)) Target.attack_slime(src) - //world << "retrun 1" return if(!Target.lying && prob(80)) @@ -113,16 +92,12 @@ if(!Atkcool) spawn() Atkcool = 1 - sleep(25) + sleep(45) Atkcool = 0 if(Target.Adjacent(src)) Target.attack_slime(src) - - if(prob(30)) - step_to(src, Target) - else if(!Atkcool && Target.Adjacent(src)) Feedon(Target) @@ -133,13 +108,12 @@ else if(Target in view(7, src)) - if(Target.Adjacent(src)) + if(!Target.Adjacent(src)) // Bug of the month candidate: slimes were attempting to move to target only if it was directly next to them, which caused them to target things, but not approach them step_to(src, Target) else Target = null AIproc = 0 - //world << "break 6" break var/sleeptime = movement_delay() @@ -148,7 +122,6 @@ sleep(sleeptime + 2) // this is about as fast as a player slime can go AIproc = 0 - //world << "AI proc ended." /mob/living/carbon/slime/proc/handle_environment(datum/gas_mixture/environment) if(!environment) @@ -158,28 +131,11 @@ //var/environment_heat_capacity = environment.heat_capacity() var/loc_temp = get_temperature(environment) - /* - if((environment.temperature > (T0C + 50)) || (environment.temperature < (T0C + 10))) - var/transfer_coefficient - - transfer_coefficient = 1 - if(wear_mask && (wear_mask.body_parts_covered & HEAD) && (environment.temperature < wear_mask.protective_temperature)) - transfer_coefficient *= wear_mask.heat_transfer_coefficient - - // handle_temperature_damage(HEAD, environment.temperature, environment_heat_capacity*transfer_coefficient) - */ - - if(loc_temp < 310.15) // a cold place bodytemperature += adjust_body_temperature(bodytemperature, loc_temp, 1) else // a hot place bodytemperature += adjust_body_temperature(bodytemperature, loc_temp, 1) - /* - if(stat==2) - bodytemperature += 0.1*(environment.temperature - bodytemperature)*environment_heat_capacity/(environment_heat_capacity + 270000) - - */ //Account for massive pressure differences if(bodytemperature < (T0C + 5)) // start calculating temperature damage etc @@ -199,7 +155,6 @@ return //TODO: DEFERRED - /mob/living/carbon/slime/proc/adjust_body_temperature(current, loc_temp, boost) var/temperature = current var/difference = abs(current-loc_temp) //get difference @@ -221,12 +176,10 @@ if(reagents) reagents.metabolize(src) - src.updatehealth() return //TODO: DEFERRED - /mob/living/carbon/slime/proc/handle_regular_status_updates() if(is_adult) @@ -234,20 +187,17 @@ else health = 150 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss()) - - - if(health < config.health_threshold_dead && stat != 2) death() return else if(src.health < config.health_threshold_crit) - // if(src.health <= 20 && prob(1)) spawn(0) emote("gasp") - //if(!src.rejuv) src.oxyloss++ - if(!src.reagents.has_reagent("inaprovaline")) src.adjustOxyLoss(10) + if(!src.reagents.has_reagent("inaprovaline")) + src.adjustOxyLoss(10) - if(src.stat != DEAD) src.stat = UNCONSCIOUS + if(src.stat != DEAD) + src.stat = UNCONSCIOUS if(prob(30)) adjustOxyLoss(-1) @@ -256,12 +206,9 @@ adjustCloneLoss(-1) adjustBruteLoss(-1) - if (src.stat == DEAD) - src.lying = 1 src.blinded = 1 - else if (src.paralysis || src.stunned || src.weakened || (status_flags && FAKEDEATH)) //Stunned etc. if (src.stunned > 0) @@ -306,35 +253,25 @@ return 1 - /mob/living/carbon/slime/proc/handle_nutrition() - if(prob(20)) - if(is_adult) nutrition-=rand(4,6) - else nutrition-=rand(2,3) + if (prob(15)) + nutrition -= 1 + is_adult if(nutrition <= 0) nutrition = 0 if(prob(75)) - adjustToxLoss(rand(0,5)) - else + else if (nutrition >= get_grow_nutrition() && amount_grown < 10) + nutrition -= 20 + amount_grown++ + + if(amount_grown >= 10 && !Victim && !Target && !ckey) if(is_adult) - if(nutrition >= 1000) - if(prob(40)) amount_grown++ - + Reproduce() else - if(nutrition >= 800) - if(prob(40)) amount_grown++ - - if(amount_grown >= 10 && !Victim && !Target) - if(!ckey) - if(is_adult) - Reproduce() - - else - Evolve() + Evolve() /mob/living/carbon/slime/proc/handle_targets() if(Tempstun) @@ -346,8 +283,7 @@ if(attacked > 50) attacked = 50 if(attacked > 0) - if(prob(85)) - attacked-- + attacked-- if(Discipline > 0) @@ -357,136 +293,273 @@ if(prob(10)) Discipline-- - if(!client) - if(!canmove) return - // DO AI STUFF HERE - - if(Target) - if(attacked <= 0) - Target = null - if(Victim) return // if it's eating someone already, continue eating! - - if(prob(1)) - emote(pick("bounce","sway","light","vibrate","jiggle")) + if(Target) + --target_patience + if (target_patience <= 0 || SStun || Discipline || attacked) // Tired of chasing or something draws out attention + target_patience = 0 + Target = null if(AIproc && SStun) return - var/hungry = 0 // determines if the slime is hungry - var/starving = 0 // determines if the slime is starving-hungry - if(is_adult) // 1200 max nutrition - switch(nutrition) - if(601 to 900) - if(prob(25)) hungry = 1//Ensures they continue eating, but aren't as aggressive at the same time - if(301 to 600) hungry = 1 - if(0 to 300) - starving = 1 - else - switch(nutrition) // 1000 max nutrition - if(501 to 700) - if(prob(25)) hungry = 1 - if(201 to 500) hungry = 1 - if(0 to 200) starving = 1 + if (nutrition < get_starve_nutrition()) + hungry = 2 + else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition()) + hungry = 1 - - if(starving && !client) // if a slime is starving, it starts losing its friends + if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends if(Friends.len > 0 && prob(1)) var/mob/nofriend = pick(Friends) - Friends -= nofriend + --Friends[nofriend] if(!Target) - var/list/targets = list() + if(will_hunt() && hungry || attacked || rabid) // Only add to the list if we need to + var/list/targets = list() - if(hungry || starving) //Only add to the list if we need to for(var/mob/living/L in view(7,src)) - //Ignore other slimes, dead mobs and simple_animals - if(isslime(L) || L.stat != CONSCIOUS || isanimal(L)) + if(isslime(L) || L.stat == DEAD || isanimal(L)) // Ignore other slimes, dead mobs, and simple_animals continue - if(issilicon(L)) - if(!is_adult) //Non-starving diciplined adult slimes wont eat things - if(!starving && Discipline > 0) + if(L in Friends) // No eating friends! + continue + + if(issilicon(L)) // They can't eat silicons, but they can glomp them in defence + if (rabid || attacked) + targets += L // Possible target found! + + if(!iscarbon(L)) + continue + + if(istype(L, /mob/living/carbon/human)) // Ignore slime(wo)men + var/mob/living/carbon/human/H = L + if(H.dna) + if(H.dna.mutantrace == "slime") continue - if(tame) //Tame slimes ignore electronic life + if(!L.canmove) // Only one slime can latch on at a time. + var/notarget = 0 + for(var/mob/living/carbon/slime/M in view(1,L)) + if(M.Victim == L) + notarget = 1 + if(notarget) continue - targets += L //Possible target found! + targets += L // Possible target found! - else if(iscarbon(L)) - - if(istype(L, /mob/living/carbon/human)) //Ignore slime(wo)men - var/mob/living/carbon/human/H = L - if(H.dna) - if(H.dna.mutantrace == "slime") - continue - - if(!is_adult) //Non-starving diciplined adult slimes wont eat things - if(!starving && Discipline > 0) - continue - - if(L in Friends) //No eating friends! - continue - - if(tame && ishuman(L)) //Tame slimes dont eat people. - continue - - if(!L.canmove) //Only one slime can latch on at a time. - - var/notarget = 0 - for(var/mob/living/carbon/slime/M in view(1,L)) - if(M.Victim == L) - notarget = 1 - if(notarget) - continue - - targets += L //Possible target found! - - - - if((hungry || starving) && targets.len > 0) - if(!is_adult) - if(!starving) + if(targets.len > 0) + if(attacked || rabid || hungry == 2) + Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care + else for(var/mob/living/carbon/C in targets) if(!Discipline && prob(5)) - if(ishuman(C)) - Target = C - break - if(isalienadult(C)) + if(ishuman(C) || isalienadult(C)) Target = C break - if(islarva(C)) + if(islarva(C) || ismonkey(C)) Target = C break - if(ismonkey(C)) - Target = C - break - else - Target = targets[1] - else - Target = targets[1] // closest target - if(targets.len > 0) - if(attacked > 0 || rabid) - Target = targets[1] //closest mob probably attacked it, so override Target and attack the nearest! + if (Target) + target_patience = rand(5,7) + if (is_adult) + target_patience += 3 + if(!Target) // If we have no target, we are wandering or following orders + if (Leader) + if (holding_still) + holding_still = max(holding_still - 1, 0) + else if(canmove && isturf(loc)) + step_to(src, Leader) - if(!Target) - if(hungry || starving) - if(canmove && isturf(loc) && prob(50)) + else if(hungry) + if (holding_still) + holding_still = max(holding_still - hungry, 0) + else if(canmove && isturf(loc) && prob(50)) step(src, pick(cardinal)) else - if(canmove && isturf(loc) && prob(33)) + if (holding_still) + holding_still = max(holding_still - 1, 0) + else if(canmove && isturf(loc) && prob(33)) step(src, pick(cardinal)) - else - if(!AIproc) - spawn() AIprocess() + else if(!AIproc) + spawn() + AIprocess() + +/mob/living/carbon/slime/proc/handle_speech_and_mood() + //Mood starts here + var/newmood = "" + if (rabid || attacked) newmood = "angry" + else if (Target) newmood = "mischevous" + + if (!newmood) + if (Discipline && prob(25)) + newmood = "pout" + else if (prob(1)) + newmood = pick("sad", ":3", "pout") + + if ((mood == "sad" || mood == ":3" || mood == "pout") && !newmood) + if (prob(75)) newmood = mood + + if (newmood != mood) // This is so we don't redraw them every time + mood = newmood + regenerate_icons() + + //Speech understanding starts here + var/to_say + if (speech_buffer.len > 0) + var/who = speech_buffer[1] // Who said it? + var/phrase = speech_buffer[2] // What did they say? + if ((findtext(phrase, num2text(number)) || findtext(phrase, "slimes"))) // Talking to us + if (findtext(phrase, "hello") || findtext(phrase, "hi")) + to_say = pick("Hello...", "Hi...") + else if (findtext(phrase, "follow")) + if (Leader) + if (Leader == who) // Already following him + to_say = pick("Yes...", "Lead...", "Following...") + else if (Friends[who] > Friends[Leader]) // VIVA + Leader = who + to_say = "Yes... I follow [who]..." + else + to_say = "No... I follow [Leader]..." + else + if (Friends[who] > 2) + Leader = who + to_say = "I follow..." + else // Not friendly enough + to_say = pick("No...", "I won't follow...") + else if (findtext(phrase, "stop")) + if (Victim) // We are asked to stop feeding + if (Friends[who] > 4) + Victim = null + if (Friends[who] < 7) + --Friends[who] + to_say = "Grrr..." // I'm angry but I do it + else + to_say = "Fine..." + else if (Leader) // We are asked to stop following + if (Leader == who) + to_say = "Yes... I'll stay..." + Leader = null + else + if (Friends[who] > Friends[Leader]) + Leader = null + to_say = "Yes... I'll stop..." + else + to_say = "No... I'll keep following..." + else if (findtext(phrase, "stay")) + if (Leader) + if (Leader == who) + holding_still = Friends[who] * 10 + to_say = "Yes... Staying..." + else if (Friends[who] > Friends[Leader]) + holding_still = (Friends[who] - Friends[Leader]) * 10 + to_say = "Yes... Staying..." + else + to_say = "No... I'll keep following..." + else + if (Friends[who] > 2) + holding_still = Friends[who] * 10 + to_say = "Yes... Staying..." + else + to_say = "No... I won't stay..." + speech_buffer = list() + + //Speech starts here + if (to_say) + say (to_say) + else if(prob(1)) + emote(pick("bounce","sway","light","vibrate","jiggle")) + else + var/t = 10 + var/slimes_near = -1 // Don't count myself + var/dead_slimes = 0 + var/friends_near = list() + for (var/mob/living/carbon/M in view(7,src)) + if (isslime(M)) + ++slimes_near + if (M.stat == DEAD) + ++dead_slimes + if (M in Friends) + t += 20 + friends_near += M + if (nutrition < get_hunger_nutrition()) t += 10 + if (nutrition < get_starve_nutrition()) t += 10 + if (prob(2) && prob(t)) + var/phrases = list() + if (Target) phrases += "[Target]... looks tasty..." + if (nutrition < get_starve_nutrition()) + phrases += "So... hungry..." + phrases += "Very... hungry..." + phrases += "Need... food..." + phrases += "Must... eat..." + else if (nutrition < get_hunger_nutrition()) + phrases += "Hungry..." + phrases += "Where is the food?" + phrases += "I want to eat..." + phrases += "Rawr..." + phrases += "Blop..." + phrases += "Blorble..." + if (rabid || attacked) + phrases += "Hrr..." + phrases += "Nhuu..." + phrases += "Unn..." + if (mood == ":3") + phrases += "Purr..." + if (attacked) + phrases += "Grrr..." + if (getToxLoss() > 30) + phrases += "Cold..." + if (getToxLoss() > 60) + phrases += "So... cold..." + phrases += "Very... cold..." + if (getToxLoss() > 90) + phrases += "..." + phrases += "C... c..." + if (Victim) + phrases += "Nom..." + phrases += "Tasty..." + if (powerlevel > 3) phrases += "Bzzz..." + if (powerlevel > 5) phrases += "Zap..." + if (powerlevel > 8) phrases += "Zap... Bzz..." + if (mood == "sad") phrases += "Bored..." + if (slimes_near) phrases += "Brother..." + if (slimes_near > 1) phrases += "Brothers..." + if (dead_slimes) phrases += "What happened?" + if (!slimes_near) + phrases += "Lonely..." + for (var/M in friends_near) + phrases += "[M]... friend..." + if (nutrition < get_hunger_nutrition()) + phrases += "[M]... feed me..." + say (pick(phrases)) + +/mob/living/carbon/slime/proc/get_max_nutrition() // Can't go above it + if (is_adult) return 1200 + else return 1000 + +/mob/living/carbon/slime/proc/get_grow_nutrition() // Above it we grow, below it we can eat + if (is_adult) return 1000 + else return 800 + +/mob/living/carbon/slime/proc/get_hunger_nutrition() // Below it we will always eat + if (is_adult) return 600 + else return 500 + +/mob/living/carbon/slime/proc/get_starve_nutrition() // Below it we will eat before everything else + if (is_adult) return 300 + else return 200 + +/mob/living/carbon/slime/proc/will_hunt(var/hunger = -1) // Check for being stopped from feeding and chasing + if (hunger == 2 || rabid || attacked) return 1 + if (Leader) return 0 + if (holding_still) return 0 + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm index 082f3bbbac1..e2cf043eced 100644 --- a/code/modules/mob/living/carbon/metroid/metroid.dm +++ b/code/modules/mob/living/carbon/metroid/metroid.dm @@ -15,7 +15,7 @@ gender = NEUTER update_icon = 0 - nutrition = 700 // 1000 = max + nutrition = 700 see_in_dark = 8 update_slimes = 0 @@ -25,23 +25,27 @@ status_flags = CANPARALYSE|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 into an adult - // if adult: if 10: reproduces + 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/Victim = null // the person the slime is currently feeding on 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/tame = 0 // if set to 1, the slime will not eat humans ever, or attack them - var/rabid = 0 // if set to 1, the slime will attack and eat anything it comes in contact with + 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 potential friends - var/list/FriendsWeight = list() // A list containing values respective to Friends. This determines how many times a slime "likes" something. If the slime likes it more than 2 times, it becomes a friend + var/list/Friends = list() // A list of friends; they are not considered targets for feeding; passed down after splitting - // slimes pass on genetic data, so all their offspring have the same "Friends", + var/list/speech_buffer = list() // Last phrase said near it and person who said it + + var/mood = "" // To show its face ///////////TIME FOR SUBSPECIES @@ -52,19 +56,27 @@ /mob/living/carbon/slime/New() create_reagents(100) spawn (0) - name = "[colour] [is_adult ? "adult" : "baby"] slime ([rand(1, 1000)])" + number = rand(1, 1000) + name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])" icon_state = "[colour] [is_adult ? "adult" : "baby"] slime" real_name = name slime_mutation = mutation_table(colour) + mutation_chance = rand(25, 35) var/sanitizedcolour = replacetext(colour, " ", "") coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]") ..() /mob/living/carbon/slime/regenerate_icons() icon_state = "[colour] [is_adult ? "adult" : "baby"] slime" + overlays = 0 + if (mood) + overlays += image('icons/mob/slimes.dmi', icon_state = "aslime-[mood]") ..() /mob/living/carbon/slime/movement_delay() + if (bodytemperature >= 330.23) // 135 F + return -1 // slimes become supercharged at high temperatures + var/tally = 0 var/health_deficiency = (100 - health) @@ -74,23 +86,19 @@ tally += (283.222 - bodytemperature) / 10 * 1.75 if(reagents) - if(reagents.has_reagent("hyperzine")) // hyperzine slows slimes down - tally *= 2 // moves twice as slow + if(reagents.has_reagent("hyperzine")) // Hyperzine slows slimes down + tally *= 2 - if(reagents.has_reagent("frostoil")) // frostoil also makes them move VEEERRYYYYY slow + if(reagents.has_reagent("frostoil")) // Frostoil also makes them move VEEERRYYYYY slow tally *= 5 if(health <= 0) // if damaged, the slime moves twice as slow tally *= 2 - if (bodytemperature >= 330.23) // 135 F - return -1 // slimes become supercharged at high temperatures - - return tally+config.slime_delay - + return tally + config.slime_delay /mob/living/carbon/slime/Bump(atom/movable/AM as mob|obj, yes) - if ((!( yes ) || now_pushing)) + if ((!(yes) || now_pushing)) return now_pushing = 1 @@ -98,31 +106,21 @@ 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(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(AM, /obj/structure/window) || istype(AM, /obj/structure/grille)) - if(is_adult) - if(nutrition <= 600 && !Atkcool) + if(nutrition <= get_hunger_nutrition() && !Atkcool) + if (is_adult || prob(5)) AM.attack_slime(src) spawn() Atkcool = 1 - sleep(15) + sleep(45) Atkcool = 0 - else - if(nutrition <= 500 && !Atkcool) - if(prob(5)) - AM.attack_slime(src) - spawn() - Atkcool = 1 - sleep(15) - Atkcool = 0 if(ismob(AM)) var/mob/tmob = AM @@ -156,7 +154,6 @@ /mob/living/carbon/slime/Process_Spacemove() return 2 - /mob/living/carbon/slime/Stat() ..() @@ -166,20 +163,16 @@ else stat(null, "Health: [round((health / 150) * 100)]%") - if (client.statpanel == "Status") - if(is_adult) - stat(null, "Nutrition: [nutrition]/1200") - if(amount_grown >= 10) + stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]") + if(amount_grown >= 10) + if(is_adult) stat(null, "You can reproduce!") - else - stat(null, "Nutrition: [nutrition]/1000") - if(amount_grown >= 10) + else stat(null, "You can evolve!") stat(null,"Power Level: [powerlevel]") - /mob/living/carbon/slime/adjustFireLoss(amount) ..(-abs(amount)) // Heals them return @@ -189,7 +182,6 @@ ..(Proj) return 0 - /mob/living/carbon/slime/emp_act(severity) powerlevel = 0 // oh no, the power! ..() @@ -244,17 +236,15 @@ /mob/living/carbon/slime/unEquip(obj/item/W as obj) return - /mob/living/carbon/slime/attack_ui(slot) - return - + return /mob/living/carbon/slime/attack_slime(mob/living/carbon/slime/M as mob) if (!ticker) M << "You cannot attack people before the game has started." return - if(Victim) return // can't attack while eating! + if (Victim) return // can't attack while eating! if (health > -100) @@ -265,19 +255,16 @@ var/damage = rand(1, 3) attacked += 5 - if(is_adult) + if(M.is_adult) damage = rand(1, 6) else damage = rand(1, 3) adjustBruteLoss(damage) - updatehealth() - return - /mob/living/carbon/slime/attack_animal(mob/living/simple_animal/M as mob) if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") @@ -292,7 +279,8 @@ updatehealth() /mob/living/carbon/slime/attack_paw(mob/living/carbon/monkey/M as mob) - if(!(istype(M, /mob/living/carbon/monkey))) return//Fix for aliens receiving double messages when attacking other aliens. + if(!(istype(M, /mob/living/carbon/monkey))) + return // Fix for aliens receiving double messages when attacking other aliens. if (!ticker) M << "You cannot attack people before the game has started." @@ -301,6 +289,7 @@ if (istype(loc, /turf) && istype(loc.loc, /area/start)) M << "No attacking people at spawn, you jackass." return + ..() switch(M.a_intent) @@ -401,7 +390,7 @@ if ("grab") if (M == src || anchored) return - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src ) + var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src) M.put_in_active_hand(G) @@ -422,8 +411,9 @@ if (prob(90)) if (HULK in M.mutations) damage += 5 - if(Victim) + if(Victim || Target) Victim = null + Target = null anchored = 0 if(prob(80) && !client) Discipline++ @@ -513,8 +503,9 @@ if ((O.client && !( O.blinded ))) O.show_message(text(" [] has tackled [name]!", M), 1) - if(Victim) + if(Victim || Target) Victim = null + Target = null anchored = 0 if(prob(80) && !client) Discipline++ @@ -548,16 +539,17 @@ if(prob(25)) user << "\red [W] passes right through [src]!" return - if(Discipline && prob(50)) // wow, buddy, why am I getting attacked?? + if(Discipline && prob(50)) // wow, buddy, why am I getting attacked?? Discipline = 0 if(W.force >= 3) if(is_adult) if(prob(5 + round(W.force/2))) - if(Victim) + if(Victim || Target) if(prob(80) && !client) Discipline++ Victim = null + Target = null anchored = 0 spawn() @@ -577,7 +569,7 @@ else if(prob(10 + W.force*2)) - if(Victim) + if(Victim || Target) if(prob(80) && !client) Discipline++ if(Discipline == 1) @@ -588,6 +580,7 @@ SStun = 0 Victim = null + Target = null anchored = 0 spawn(0) @@ -604,17 +597,22 @@ /mob/living/carbon/slime/restrained() return 0 - mob/living/carbon/slime/var/co2overloadtime = null mob/living/carbon/slime/var/temperature_resistance = T0C+75 - /mob/living/carbon/slime/show_inv(mob/user) return /mob/living/carbon/slime/toggle_throw_mode() return +/mob/living/carbon/slime/proc/apply_water() + adjustToxLoss(rand(15,20)) + if (!client) + if (Target) // Like cats + Target = null + ++Discipline + return /obj/item/slime_extract name = "slime extract" diff --git a/code/modules/mob/living/carbon/metroid/powers.dm b/code/modules/mob/living/carbon/metroid/powers.dm index 771fc56eae1..3d8e2c14f1a 100644 --- a/code/modules/mob/living/carbon/metroid/powers.dm +++ b/code/modules/mob/living/carbon/metroid/powers.dm @@ -71,7 +71,7 @@ "A sharp, deep pain bathes every inch of your body!")]" if(istype(M, /mob/living/carbon)) - Victim.adjustCloneLoss(rand(1,10)) + Victim.adjustCloneLoss(rand(5,6)) Victim.adjustToxLoss(rand(1,2)) if(Victim.health <= 0) Victim.adjustToxLoss(rand(2,4)) @@ -88,7 +88,7 @@ if(slime.Victim == M && slime != src) slime.Feedstop() - nutrition += rand(10,25) + nutrition += rand(15,30) if(nutrition >= lastnut + 50) if(prob(80)) lastnut = nutrition @@ -96,12 +96,11 @@ if(powerlevel > 10) powerlevel = 10 - if(is_adult) - if(nutrition > 1200) - nutrition = 1200 - else - if(nutrition > 1000) - nutrition = 1000 + if (nutrition > get_max_nutrition()) + if (amount_grown < 10) + nutrition -= 20 + ++amount_grown + nutrition = min(nutrition, get_max_nutrition()) Victim.updatehealth() updatehealth() @@ -139,7 +138,11 @@ if(Victim.LAssailant && Victim.LAssailant != Victim) if(prob(50)) if(!(Victim.LAssailant in Friends)) - Friends.Add(Victim.LAssailant) // no idea why i was using the |= operator + Friends[Victim.LAssailant] = 1 + //Friends.Add(Victim.LAssailant) // no idea why i was using the |= operator + else + ++Friends[Victim.LAssailant] + if(M.client && istype(src, /mob/living/carbon/human)) if(prob(85)) @@ -179,7 +182,7 @@ maxHealth = 200 amount_grown = 0 regenerate_icons() - name = text("[colour] [is_adult ? "adult" : "baby"] slime ([rand(1, 1000)])") + name = text("[colour] [is_adult ? "adult" : "baby"] slime ([number])") else src << "I am not ready to evolve yet..." else @@ -204,13 +207,14 @@ var/new_powerlevel = round(powerlevel / 4) for(var/i=1,i<=4,i++) var/mob/living/carbon/slime/M = new /mob/living/carbon/slime/(loc) - if(prob(70)) - M.colour = colour - else + if(prob(mutation_chance)) M.colour = slime_mutation[rand(1,4)] + else + M.colour = colour if(ckey) M.nutrition = new_nutrition //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature! M.powerlevel = new_powerlevel if(i != 1) step_away(M,src) + M.Friends = Friends.Copy() babies += M feedback_add_details("slime_babies_born","slimebirth_[replacetext(M.colour," ","_")]") @@ -225,4 +229,4 @@ else src << "I am not ready to reproduce yet..." else - src << "I am not old enough to reproduce yet..." + src << "I am not old enough to reproduce yet..." \ No newline at end of file diff --git a/code/modules/mob/living/carbon/metroid/subtypes.dm b/code/modules/mob/living/carbon/metroid/subtypes.dm index e61054fce8d..3b7e0107abb 100644 --- a/code/modules/mob/living/carbon/metroid/subtypes.dm +++ b/code/modules/mob/living/carbon/metroid/subtypes.dm @@ -19,35 +19,35 @@ proc/mutation_table(var/colour) slime_mutation[3] = "gold" slime_mutation[4] = "gold" if("orange") - slime_mutation[1] = "red" - slime_mutation[2] = "red" - slime_mutation[3] = "dark purple" - slime_mutation[4] = "yellow" + slime_mutation[1] = "dark purple" + slime_mutation[2] = "yellow" + slime_mutation[3] = "red" + slime_mutation[4] = "red" if("blue") slime_mutation[1] = "dark blue" - slime_mutation[2] = "pink" + slime_mutation[2] = "silver" slime_mutation[3] = "pink" - slime_mutation[4] = "silver" + slime_mutation[4] = "pink" //Tier 3 if("dark blue") slime_mutation[1] = "purple" - slime_mutation[2] = "cerulean" - slime_mutation[3] = "blue" + slime_mutation[2] = "blue" + slime_mutation[3] = "cerulean" slime_mutation[4] = "cerulean" if("dark purple") slime_mutation[1] = "purple" - slime_mutation[2] = "sepia" - slime_mutation[3] = "orange" + slime_mutation[2] = "orange" + slime_mutation[3] = "sepia" slime_mutation[4] = "sepia" if("yellow") slime_mutation[1] = "metal" - slime_mutation[2] = "bluespace" - slime_mutation[3] = "orange" + slime_mutation[2] = "orange" + slime_mutation[3] = "bluespace" slime_mutation[4] = "bluespace" if("silver") slime_mutation[1] = "metal" - slime_mutation[2] = "pyrite" - slime_mutation[3] = "blue" + slime_mutation[2] = "blue" + slime_mutation[3] = "pyrite" slime_mutation[4] = "pyrite" //Tier 4 if("pink") diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index d1292c3452a..4f722d5d8a5 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -288,6 +288,16 @@ var/list/department_radio_keys = list( P.speech_buffer.Remove(pick(P.speech_buffer)) P.speech_buffer.Add(html_decode(message)) + if(isslime(A)) //Slimes answering to people + if (A == src) + continue + + var/mob/living/carbon/slime/S = A + if (src in S.Friends) + S.speech_buffer = list() + S.speech_buffer.Add(src) + S.speech_buffer.Add(lowertext(html_decode(message))) + if(istype(A, /obj/)) //radio in pocket could work, radio in backpack wouldn't --rastaf0 var/obj/O = A spawn (0) diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index 61cb43dd931..e7a8c57b042 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -218,7 +218,7 @@ datum T.MakeSlippery() for(var/mob/living/carbon/slime/M in T) - M.adjustToxLoss(rand(15,20)) + M.apply_water() var/hotspot = (locate(/obj/effect/hotspot) in T) if(hotspot && !istype(T, /turf/space)) diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 860334f6cd4..aecd81c02b8 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -935,7 +935,7 @@ datum/chemical_reaction/pestkiller name = "Slime Spawn" id = "m_spawn" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/grey required_other = 1 @@ -951,7 +951,7 @@ datum/chemical_reaction/pestkiller name = "Slime Monkey" id = "m_monkey" result = null - required_reagents = list("blood" = 5) + required_reagents = list("blood" = 1) result_amount = 1 required_container = /obj/item/slime_extract/grey required_other = 1 @@ -966,7 +966,7 @@ datum/chemical_reaction/pestkiller name = "Mutation Toxin" id = "mutationtoxin" result = "mutationtoxin" - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_other = 1 required_container = /obj/item/slime_extract/green @@ -978,7 +978,7 @@ datum/chemical_reaction/pestkiller name = "Slime Metal" id = "m_metal" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/metal required_other = 1 @@ -996,7 +996,7 @@ datum/chemical_reaction/pestkiller name = "Slime Crit" id = "m_tele" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/gold required_other = 1 @@ -1065,7 +1065,7 @@ datum/chemical_reaction/pestkiller name = "Slime Crit Lesser" id = "m_tele3" result = null - required_reagents = list("blood" = 5) + required_reagents = list("blood" = 1) result_amount = 1 required_container = /obj/item/slime_extract/gold required_other = 1 @@ -1117,7 +1117,7 @@ datum/chemical_reaction/pestkiller name = "Slime Bork" id = "m_tele2" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/silver required_other = 1 @@ -1148,7 +1148,7 @@ datum/chemical_reaction/pestkiller name = "Slime Bork 2" id = "m_tele4" result = null - required_reagents = list("water" = 5) + required_reagents = list("water" = 1) result_amount = 1 required_container = /obj/item/slime_extract/silver required_other = 1 @@ -1180,7 +1180,7 @@ datum/chemical_reaction/pestkiller name = "Slime Frost Oil" id = "m_frostoil" result = "frostoil" - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 10 required_container = /obj/item/slime_extract/blue required_other = 1 @@ -1192,7 +1192,7 @@ datum/chemical_reaction/pestkiller name = "Slime Freeze" id = "m_freeze" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/darkblue required_other = 1 @@ -1212,7 +1212,7 @@ datum/chemical_reaction/pestkiller name = "Slime Capsaicin Oil" id = "m_capsaicinoil" result = "capsaicin" - required_reagents = list("blood" = 5) + required_reagents = list("blood" = 1) result_amount = 10 required_container = /obj/item/slime_extract/orange required_other = 1 @@ -1223,7 +1223,7 @@ datum/chemical_reaction/pestkiller name = "Slime fire" id = "m_fire" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/orange required_other = 1 @@ -1243,7 +1243,7 @@ datum/chemical_reaction/pestkiller name = "Slime EMP" id = "m_emp" result = null - required_reagents = list("blood" = 5) + required_reagents = list("blood" = 1) result_amount = 1 required_container = /obj/item/slime_extract/yellow required_other = 1 @@ -1256,7 +1256,7 @@ datum/chemical_reaction/pestkiller name = "Slime Powercell" id = "m_cell" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/yellow required_other = 1 @@ -1269,7 +1269,7 @@ datum/chemical_reaction/pestkiller name = "Slime Glow" id = "m_glow" result = null - required_reagents = list("water" = 5) + required_reagents = list("water" = 1) result_amount = 1 required_container = /obj/item/slime_extract/yellow required_other = 1 @@ -1286,7 +1286,7 @@ datum/chemical_reaction/pestkiller name = "Slime Steroid" id = "m_steroid" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/purple required_other = 1 @@ -1299,7 +1299,7 @@ datum/chemical_reaction/pestkiller name = "Slime Jam" id = "m_jam" result = "slimejelly" - required_reagents = list("sugar" = 5) + required_reagents = list("sugar" = 1) result_amount = 10 required_container = /obj/item/slime_extract/purple required_other = 1 @@ -1312,7 +1312,7 @@ datum/chemical_reaction/pestkiller name = "Slime Plasma" id = "m_plasma" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/darkpurple required_other = 1 @@ -1327,7 +1327,7 @@ datum/chemical_reaction/pestkiller name = "Slime Glycerol" id = "m_glycerol" result = "glycerol" - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 8 required_container = /obj/item/slime_extract/red required_other = 1 @@ -1339,14 +1339,13 @@ datum/chemical_reaction/pestkiller name = "Bloodlust" id = "m_bloodlust" result = null - required_reagents = list("blood" = 5) + required_reagents = list("blood" = 1) result_amount = 1 required_container = /obj/item/slime_extract/red required_other = 1 /datum/chemical_reaction/slimebloodlust/on_reaction(var/datum/reagents/holder) feedback_add_details("slime_cores_used","[replacetext(name," ","_")]") for(var/mob/living/carbon/slime/slime in viewers(get_turf(holder.my_atom), null)) - slime.tame = 0 slime.rabid = 1 for(var/mob/O in viewers(get_turf(holder.my_atom), null)) O.show_message(text("\red The [slime] is driven into a frenzy!."), 1) @@ -1356,7 +1355,7 @@ datum/chemical_reaction/pestkiller name = "Slime Potion" id = "m_potion" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/pink required_other = 1 @@ -1371,7 +1370,7 @@ datum/chemical_reaction/pestkiller name = "Advanced Mutation Toxin" id = "mutationtoxin2" result = "amutationtoxin" - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_other = 1 required_container = /obj/item/slime_extract/black @@ -1383,7 +1382,7 @@ datum/chemical_reaction/pestkiller name = "Slime Explosion" id = "m_explosion" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/oil required_other = 1 @@ -1401,7 +1400,7 @@ datum/chemical_reaction/pestkiller result = null result_amount = 1 required_container = /obj/item/slime_extract/lightpink - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) required_other = 1 /datum/chemical_reaction/slimepotion2/on_reaction(var/datum/reagents/holder) feedback_add_details("slime_cores_used","[replacetext(name," ","_")]") @@ -1412,7 +1411,7 @@ datum/chemical_reaction/pestkiller name = "Slime Golem" id = "m_golem" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/adamantine required_other = 1 @@ -1428,7 +1427,7 @@ datum/chemical_reaction/pestkiller name = "Slime Crystal" id = "m_crystal" result = null - required_reagents = list("blood" = 5) + required_reagents = list("blood" = 1) result_amount = 1 required_container = /obj/item/slime_extract/bluespace required_other = 1 @@ -1444,7 +1443,7 @@ datum/chemical_reaction/pestkiller name = "Slime Steroid 2" id = "m_steroid2" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/cerulean required_other = 1 @@ -1458,7 +1457,7 @@ datum/chemical_reaction/pestkiller name = "Slime Camera" id = "m_camera" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/sepia required_other = 1 @@ -1471,7 +1470,7 @@ datum/chemical_reaction/pestkiller name = "Slime Film" id = "m_film" result = null - required_reagents = list("blood" = 5) + required_reagents = list("blood" = 1) result_amount = 1 required_container = /obj/item/slime_extract/sepia required_other = 1 @@ -1487,7 +1486,7 @@ datum/chemical_reaction/pestkiller name = "Slime Paint" id = "s_paint" result = null - required_reagents = list("plasma" = 5) + required_reagents = list("plasma" = 1) result_amount = 1 required_container = /obj/item/slime_extract/pyrite required_other = 1