diff --git a/code/modules/ai/aI_holder_subtypes/slime_xenobio_ai.dm b/code/modules/ai/aI_holder_subtypes/slime_xenobio_ai.dm index 059adfb849..41abd45903 100644 --- a/code/modules/ai/aI_holder_subtypes/slime_xenobio_ai.dm +++ b/code/modules/ai/aI_holder_subtypes/slime_xenobio_ai.dm @@ -1,266 +1,269 @@ -// Specialized AI for slime simplemobs. -// Unlike the parent AI code, this will probably break a lot of things if you put it on something that isn't /mob/living/simple_mob/slime/xenobio - -/datum/ai_holder/simple_mob/xenobio_slime - hostile = TRUE - cooperative = TRUE - firing_lanes = TRUE - var/rabid = FALSE // Will attack regardless of discipline. - var/discipline = 0 // Beating slimes makes them less likely to lash out. In theory. - var/resentment = 0 // 'Unjustified' beatings make this go up, and makes it more likely for abused slimes to go rabid. - var/obedience = 0 // Conversely, 'justified' beatings make this go up, and makes discipline decay slower, potentially making it not decay at all. - - var/always_stun = FALSE // If true, the slime will elect to attempt to permastun the target. - - var/last_discipline_decay = null // Last world.time discipline was reduced from decay. - var/discipline_decay_time = 5 SECONDS // Earliest that one discipline can decay. - -/datum/ai_holder/simple_mob/xenobio_slime/sapphire - always_stun = TRUE // They know that stuns are godly. - intelligence_level = AI_SMART // Also knows not to walk while confused if it risks death. - -/datum/ai_holder/simple_mob/xenobio_slime/light_pink - discipline = 10 - obedience = 10 - -/datum/ai_holder/simple_mob/xenobio_slime/passive/New() // For Kendrick. - ..() - pacify() - -/datum/ai_holder/simple_mob/xenobio_slime/New() - ..() - ASSERT(istype(holder, /mob/living/simple_mob/slime/xenobio)) - -// Checks if disciplining the slime would be 'justified' right now. -/datum/ai_holder/simple_mob/xenobio_slime/proc/is_justified_to_discipline() - if(rabid) - return TRUE - if(target) - if(ishuman(target)) - var/mob/living/carbon/human/H = target - if(istype(H.species, /datum/species/monkey)) - return FALSE // Attacking monkeys is okay. - return TRUE // Otherwise attacking other things is bad. - return FALSE // Not attacking anything. - -/datum/ai_holder/simple_mob/xenobio_slime/proc/can_command(mob/living/commander) - if(rabid) - return FALSE - if(!hostile) - return SLIME_COMMAND_OBEY -// if(commander in friends) -// return SLIME_COMMAND_FRIEND - if(holder.IIsAlly(commander)) - return SLIME_COMMAND_FACTION - if(discipline > resentment && obedience >= 5) - return SLIME_COMMAND_OBEY - return FALSE - -/datum/ai_holder/simple_mob/xenobio_slime/proc/adjust_discipline(amount, silent) - var/mob/living/simple_mob/slime/xenobio/my_slime = holder - if(amount > 0) - if(rabid) - return - var/justified = is_justified_to_discipline() - lost_target() // Stop attacking. - - if(justified) - obedience++ - if(!silent) - holder.say(pick("Fine...", "Okay...", "Sorry...", "I yield...", "Mercy...")) - else - if(prob(resentment * 20)) - enrage() - holder.say(pick("Evil...", "Kill...", "Tyrant...")) - else - if(!silent) - holder.say(pick("Why...?", "I don't understand...?", "Cruel...", "Stop...", "Nooo...")) - resentment++ // Done after check so first time will never enrage. - - discipline = between(0, discipline + amount, 10) - my_slime.update_mood() - -// This slime always enrages if disciplined. -/datum/ai_holder/simple_mob/xenobio_slime/red/adjust_discipline(amount, silent) - if(amount > 0 && !rabid) - holder.say("Grrr...") - holder.add_modifier(/datum/modifier/berserk, 30 SECONDS) - enrage() - -/datum/ai_holder/simple_mob/xenobio_slime/handle_special_strategical() - discipline_decay() - -// Handles decay of discipline. -/datum/ai_holder/simple_mob/xenobio_slime/proc/discipline_decay() - if(discipline > 0 && last_discipline_decay + discipline_decay_time < world.time) - if(!prob(75 + (obedience * 5))) - adjust_discipline(-1) - last_discipline_decay = world.time - -/datum/ai_holder/simple_mob/xenobio_slime/handle_special_tactic() - evolve_and_reproduce() - -// Hit the correct verbs to keep the slime species going. -/datum/ai_holder/simple_mob/xenobio_slime/proc/evolve_and_reproduce() - var/mob/living/simple_mob/slime/xenobio/my_slime = holder - if(my_slime.amount_grown >= 10) - // Press the correct verb when we can. - if(my_slime.is_adult) - my_slime.reproduce() // Splits into four new baby slimes. - else - my_slime.evolve() // Turns our holder into an adult slime. - - -// Called when pushed too far (or a red slime core was used). -/datum/ai_holder/simple_mob/xenobio_slime/proc/enrage() - var/mob/living/simple_mob/slime/xenobio/my_slime = holder - if(my_slime.harmless) - return - rabid = TRUE - my_slime.update_mood() - my_slime.visible_message(span("danger", "\The [src] enrages!")) - -// Called when using a pacification agent (or it's Kendrick being initalized). -/datum/ai_holder/simple_mob/xenobio_slime/proc/pacify() - lost_target() // So it stops trying to kill them. - rabid = FALSE - hostile = FALSE - retaliate = FALSE - cooperative = FALSE - -// The holder's attack changes based on intent. This lets the AI choose what effect is desired. -/datum/ai_holder/simple_mob/xenobio_slime/pre_melee_attack(atom/A) - if(istype(A, /mob/living)) - var/mob/living/L = A - var/mob/living/simple_mob/slime/xenobio/my_slime = holder - - if( (!L.lying && prob(30 + (my_slime.power_charge * 7) ) || (!L.lying && always_stun) )) - my_slime.a_intent = I_DISARM // Stun them first. - else if(my_slime.can_consume(L) && L.lying) - my_slime.a_intent = I_GRAB // Then eat them. - else - my_slime.a_intent = I_HURT // Otherwise robust them. - -/datum/ai_holder/simple_mob/xenobio_slime/closest_distance(atom/movable/AM) - if(istype(AM, /mob/living)) - var/mob/living/L = AM - if(ishuman(L)) - var/mob/living/carbon/human/H = L - if(istype(H.species, /datum/species/monkey)) - return 1 // Otherwise ranged slimes will eat a lot less often. - if(L.stat >= UNCONSCIOUS) - return 1 // Melee (eat) the target if dead/dying, don't shoot it. - return ..() - -/datum/ai_holder/simple_mob/xenobio_slime/can_attack(atom/movable/AM) - . = ..() - if(.) // Do some additional checks because we have Special Code(tm). - if(ishuman(AM)) - var/mob/living/carbon/human/H = AM - if(istype(H.species, /datum/species/monkey)) // istype() is so they'll eat the alien monkeys too. - return TRUE // Monkeys are always food (sorry Pun Pun). - else if(H.species && H.species.name == SPECIES_PROMETHEAN) - return FALSE // Prometheans are always our friends. - if(discipline && !rabid) - return FALSE // We're a good slime. - -// Commands, reactions, etc -/datum/ai_holder/simple_mob/xenobio_slime/on_hear_say(mob/living/speaker, message) - ai_log("xenobio_slime/on_hear_say([speaker], [message]) : Entered.", AI_LOG_DEBUG) - var/mob/living/simple_mob/slime/xenobio/my_slime = holder - - if((findtext(message, num2text(my_slime.number)) || findtext(message, my_slime.name) || findtext(message, "slimes"))) // Talking to us. - - // First, make sure it's actually a player saying something and not an AI, or else we risk infinite loops. - if(!speaker.client) - return - - // Are all slimes being referred to? - // var/mass_order = FALSE - // if(findtext(message, "slimes")) - // mass_order = TRUE - - // Say hello back. - if(findtext(message, "hello") || findtext(message, "hi") || findtext(message, "greetings")) - delayed_say(pick("Hello...", "Hi..."), speaker) - - // Follow request. - if(findtext(message, "follow") || findtext(message, "come with me")) - if(!can_command(speaker)) - delayed_say(pick("No...", "I won't follow..."), speaker) - return - - delayed_say("Yes... I follow \the [speaker]...", speaker) - set_follow(speaker) - - // Squish request. - if(findtext(message , "squish")) - if(!can_command(speaker)) - delayed_say("No...", speaker) - return - - spawn(rand(1 SECOND, 2 SECONDS)) - if(!src || !holder || !can_act()) // We might've died/got deleted/etc in the meantime. - return - my_slime.squish() - - - // Stop request. - if(findtext(message, "stop") || findtext(message, "halt") || findtext(message, "cease")) - if(my_slime.victim) // We're being asked to stop eatting someone. - if(!can_command(speaker) || !is_justified_to_discipline()) - delayed_say("No...", speaker) - return - else - delayed_say("Fine...", speaker) - adjust_discipline(1, TRUE) - my_slime.stop_consumption() - - if(target) // We're being asked to stop chasing someone. - if(!can_command(speaker) || !is_justified_to_discipline()) - delayed_say("No...", speaker) - return - else - delayed_say("Fine...", speaker) - adjust_discipline(1, TRUE) // This must come before losing the target or it will be unjustified. - lost_target() - - - if(leader) // We're being asked to stop following someone. - if(can_command(speaker) == SLIME_COMMAND_FRIEND || leader == speaker) - delayed_say("Yes... I'll stop...", speaker) - lose_follow() - else - delayed_say("No... I'll keep following \the [leader]...", speaker) - - /* // Commented out since its mostly useless now due to slimes refusing to attack if it would make them naughty. - // Murder request - if(findtext(message, "harm") || findtext(message, "attack") || findtext(message, "kill") || findtext(message, "murder") || findtext(message, "eat") || findtext(message, "consume") || findtext(message, "absorb")) - if(can_command(speaker) < SLIME_COMMAND_FACTION) - delayed_say("No...", speaker) - return - - for(var/mob/living/L in view(7, my_slime) - list(my_slime, speaker)) - if(L == src) - continue // Don't target ourselves. - var/list/valid_names = splittext(L.name, " ") // Should output list("John", "Doe") as an example. - for(var/line in valid_names) // Check each part of someone's name. - if(findtext(message, lowertext(line))) // If part of someone's name is in the command, the slime targets them if allowed to. - if(!(mass_order && line == "slime")) //don't think random other slimes are target - if(can_attack(L)) - delayed_say("Okay... I attack \the [L]...", speaker) - give_target(L) - return - else - delayed_say("No... I won't attack \the [L].", speaker) - return - - // If we're here, it couldn't find anyone with that name. - delayed_say("No... I don't know who to attack...", speaker) - */ - ai_log("xenobio_slime/on_hear_say() : Exited.", AI_LOG_DEBUG) - -/datum/ai_holder/simple_mob/xenobio_slime/can_violently_breakthrough() - if(discipline && !rabid) // Good slimes don't shatter the windows because their buddy in an adjacent cell decided to piss off Slimesky. - return FALSE +// Specialized AI for slime simplemobs. +// Unlike the parent AI code, this will probably break a lot of things if you put it on something that isn't /mob/living/simple_mob/slime/xenobio + +/datum/ai_holder/simple_mob/xenobio_slime + hostile = TRUE + cooperative = TRUE + firing_lanes = TRUE + mauling = TRUE // They need it to get the most out of monkeys. + var/rabid = FALSE // Will attack regardless of discipline. + var/discipline = 0 // Beating slimes makes them less likely to lash out. In theory. + var/resentment = 0 // 'Unjustified' beatings make this go up, and makes it more likely for abused slimes to go rabid. + var/obedience = 0 // Conversely, 'justified' beatings make this go up, and makes discipline decay slower, potentially making it not decay at all. + + var/always_stun = FALSE // If true, the slime will elect to attempt to permastun the target. + + var/last_discipline_decay = null // Last world.time discipline was reduced from decay. + var/discipline_decay_time = 5 SECONDS // Earliest that one discipline can decay. + +/datum/ai_holder/simple_mob/xenobio_slime/sapphire + always_stun = TRUE // They know that stuns are godly. + intelligence_level = AI_SMART // Also knows not to walk while confused if it risks death. + +/datum/ai_holder/simple_mob/xenobio_slime/light_pink + discipline = 10 + obedience = 10 + +/datum/ai_holder/simple_mob/xenobio_slime/passive/New() // For Kendrick. + ..() + pacify() + +/datum/ai_holder/simple_mob/xenobio_slime/New() + ..() + ASSERT(istype(holder, /mob/living/simple_mob/slime/xenobio)) + +// Checks if disciplining the slime would be 'justified' right now. +/datum/ai_holder/simple_mob/xenobio_slime/proc/is_justified_to_discipline() + if(!can_act()) + return FALSE // The slime considers it abuse if they get stunned while already stunned. + if(rabid) + return TRUE + if(target && can_attack(target)) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(istype(H.species, /datum/species/monkey)) + return FALSE // Attacking monkeys is okay. + return TRUE // Otherwise attacking other things is bad. + return FALSE // Not attacking anything. + +/datum/ai_holder/simple_mob/xenobio_slime/proc/can_command(mob/living/commander) + if(rabid) + return FALSE + if(!hostile) + return SLIME_COMMAND_OBEY +// if(commander in friends) +// return SLIME_COMMAND_FRIEND + if(holder.IIsAlly(commander)) + return SLIME_COMMAND_FACTION + if(discipline > resentment && obedience >= 5) + return SLIME_COMMAND_OBEY + return FALSE + +/datum/ai_holder/simple_mob/xenobio_slime/proc/adjust_discipline(amount, silent) + var/mob/living/simple_mob/slime/xenobio/my_slime = holder + if(amount > 0) + if(rabid) + return + var/justified = is_justified_to_discipline() + lost_target() // Stop attacking. + + if(justified) + obedience++ + if(!silent) + holder.say(pick("Fine...", "Okay...", "Sorry...", "I yield...", "Mercy...")) + else + if(prob(resentment * 20)) + enrage() + holder.say(pick("Evil...", "Kill...", "Tyrant...")) + else + if(!silent) + holder.say(pick("Why...?", "I don't understand...?", "Cruel...", "Stop...", "Nooo...")) + resentment++ // Done after check so first time will never enrage. + + discipline = between(0, discipline + amount, 10) + my_slime.update_mood() + +// This slime always enrages if disciplined. +/datum/ai_holder/simple_mob/xenobio_slime/red/adjust_discipline(amount, silent) + if(amount > 0 && !rabid) + holder.say("Grrr...") + holder.add_modifier(/datum/modifier/berserk, 30 SECONDS) + enrage() + +/datum/ai_holder/simple_mob/xenobio_slime/handle_special_strategical() + discipline_decay() + +// Handles decay of discipline. +/datum/ai_holder/simple_mob/xenobio_slime/proc/discipline_decay() + if(discipline > 0 && last_discipline_decay + discipline_decay_time < world.time) + if(!prob(75 + (obedience * 5))) + adjust_discipline(-1) + last_discipline_decay = world.time + +/datum/ai_holder/simple_mob/xenobio_slime/handle_special_tactic() + evolve_and_reproduce() + +// Hit the correct verbs to keep the slime species going. +/datum/ai_holder/simple_mob/xenobio_slime/proc/evolve_and_reproduce() + var/mob/living/simple_mob/slime/xenobio/my_slime = holder + if(my_slime.amount_grown >= 10) + // Press the correct verb when we can. + if(my_slime.is_adult) + my_slime.reproduce() // Splits into four new baby slimes. + else + my_slime.evolve() // Turns our holder into an adult slime. + + +// Called when pushed too far (or a red slime core was used). +/datum/ai_holder/simple_mob/xenobio_slime/proc/enrage() + var/mob/living/simple_mob/slime/xenobio/my_slime = holder + if(my_slime.harmless) + return + rabid = TRUE + my_slime.update_mood() + my_slime.visible_message(span("danger", "\The [src] enrages!")) + +// Called when using a pacification agent (or it's Kendrick being initalized). +/datum/ai_holder/simple_mob/xenobio_slime/proc/pacify() + lost_target() // So it stops trying to kill them. + rabid = FALSE + hostile = FALSE + retaliate = FALSE + cooperative = FALSE + +// The holder's attack changes based on intent. This lets the AI choose what effect is desired. +/datum/ai_holder/simple_mob/xenobio_slime/pre_melee_attack(atom/A) + if(istype(A, /mob/living)) + var/mob/living/L = A + var/mob/living/simple_mob/slime/xenobio/my_slime = holder + + if( (!L.lying && prob(30 + (my_slime.power_charge * 7) ) || (!L.lying && always_stun) )) + my_slime.a_intent = I_DISARM // Stun them first. + else if(my_slime.can_consume(L) && L.lying) + my_slime.a_intent = I_GRAB // Then eat them. + else + my_slime.a_intent = I_HURT // Otherwise robust them. + +/datum/ai_holder/simple_mob/xenobio_slime/closest_distance(atom/movable/AM) + if(istype(AM, /mob/living)) + var/mob/living/L = AM + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(istype(H.species, /datum/species/monkey)) + return 1 // Otherwise ranged slimes will eat a lot less often. + if(L.stat >= UNCONSCIOUS) + return 1 // Melee (eat) the target if dead/dying, don't shoot it. + return ..() + +/datum/ai_holder/simple_mob/xenobio_slime/can_attack(atom/movable/AM) + . = ..() + if(.) // Do some additional checks because we have Special Code(tm). + if(ishuman(AM)) + var/mob/living/carbon/human/H = AM + if(istype(H.species, /datum/species/monkey)) // istype() is so they'll eat the alien monkeys too. + return TRUE // Monkeys are always food (sorry Pun Pun). + else if(H.species && H.species.name == SPECIES_PROMETHEAN) + return FALSE // Prometheans are always our friends. + if(discipline && !rabid) + return FALSE // We're a good slime. + +// Commands, reactions, etc +/datum/ai_holder/simple_mob/xenobio_slime/on_hear_say(mob/living/speaker, message) + ai_log("xenobio_slime/on_hear_say([speaker], [message]) : Entered.", AI_LOG_DEBUG) + var/mob/living/simple_mob/slime/xenobio/my_slime = holder + + if((findtext(message, num2text(my_slime.number)) || findtext(message, my_slime.name) || findtext(message, "slimes"))) // Talking to us. + + // First, make sure it's actually a player saying something and not an AI, or else we risk infinite loops. + if(!speaker.client) + return + + // Are all slimes being referred to? + // var/mass_order = FALSE + // if(findtext(message, "slimes")) + // mass_order = TRUE + + // Say hello back. + if(findtext(message, "hello") || findtext(message, "hi") || findtext(message, "greetings")) + delayed_say(pick("Hello...", "Hi..."), speaker) + + // Follow request. + if(findtext(message, "follow") || findtext(message, "come with me")) + if(!can_command(speaker)) + delayed_say(pick("No...", "I won't follow..."), speaker) + return + + delayed_say("Yes... I follow \the [speaker]...", speaker) + set_follow(speaker) + + // Squish request. + if(findtext(message , "squish")) + if(!can_command(speaker)) + delayed_say("No...", speaker) + return + + spawn(rand(1 SECOND, 2 SECONDS)) + if(!src || !holder || !can_act()) // We might've died/got deleted/etc in the meantime. + return + my_slime.squish() + + + // Stop request. + if(findtext(message, "stop") || findtext(message, "halt") || findtext(message, "cease")) + if(my_slime.victim) // We're being asked to stop eatting someone. + if(!can_command(speaker) || !is_justified_to_discipline()) + delayed_say("No...", speaker) + return + else + delayed_say("Fine...", speaker) + adjust_discipline(1, TRUE) + my_slime.stop_consumption() + + if(target) // We're being asked to stop chasing someone. + if(!can_command(speaker) || !is_justified_to_discipline()) + delayed_say("No...", speaker) + return + else + delayed_say("Fine...", speaker) + adjust_discipline(1, TRUE) // This must come before losing the target or it will be unjustified. + lost_target() + + + if(leader) // We're being asked to stop following someone. + if(can_command(speaker) == SLIME_COMMAND_FRIEND || leader == speaker) + delayed_say("Yes... I'll stop...", speaker) + lose_follow() + else + delayed_say("No... I'll keep following \the [leader]...", speaker) + + /* // Commented out since its mostly useless now due to slimes refusing to attack if it would make them naughty. + // Murder request + if(findtext(message, "harm") || findtext(message, "attack") || findtext(message, "kill") || findtext(message, "murder") || findtext(message, "eat") || findtext(message, "consume") || findtext(message, "absorb")) + if(can_command(speaker) < SLIME_COMMAND_FACTION) + delayed_say("No...", speaker) + return + + for(var/mob/living/L in view(7, my_slime) - list(my_slime, speaker)) + if(L == src) + continue // Don't target ourselves. + var/list/valid_names = splittext(L.name, " ") // Should output list("John", "Doe") as an example. + for(var/line in valid_names) // Check each part of someone's name. + if(findtext(message, lowertext(line))) // If part of someone's name is in the command, the slime targets them if allowed to. + if(!(mass_order && line == "slime")) //don't think random other slimes are target + if(can_attack(L)) + delayed_say("Okay... I attack \the [L]...", speaker) + give_target(L) + return + else + delayed_say("No... I won't attack \the [L].", speaker) + return + + // If we're here, it couldn't find anyone with that name. + delayed_say("No... I don't know who to attack...", speaker) + */ + ai_log("xenobio_slime/on_hear_say() : Exited.", AI_LOG_DEBUG) + +/datum/ai_holder/simple_mob/xenobio_slime/can_violently_breakthrough() + if(discipline && !rabid) // Good slimes don't shatter the windows because their buddy in an adjacent cell decided to piss off Slimesky. + return FALSE return ..() \ No newline at end of file diff --git a/code/modules/ai/ai_holder_combat.dm b/code/modules/ai/ai_holder_combat.dm index 3d5e5c10aa..2bb224e801 100644 --- a/code/modules/ai/ai_holder_combat.dm +++ b/code/modules/ai/ai_holder_combat.dm @@ -70,8 +70,10 @@ on_engagement(target) if(firing_lanes && !test_projectile_safety(target)) // Nudge them a bit, maybe they can shoot next time. - step_rand(holder) - holder.face_atom(target) + var/turf/T = get_step(holder, pick(cardinal)) + if(T) + holder.IMove(T) // IMove() will respect movement cooldown. + holder.face_atom(target) ai_log("engage_target() : Could not safely fire at target. Exiting.", AI_LOG_DEBUG) return @@ -130,6 +132,9 @@ // Used to make sure projectiles will probably hit the target and not the wall or a friend. /datum/ai_holder/proc/test_projectile_safety(atom/movable/AM) + if(holder.Adjacent(AM)) // If they're right next to us then lets just say yes. check_trajectory() tends to spaz out otherwise. + return TRUE + var/mob/living/L = check_trajectory(AM, holder) // This isn't always reliable but its better than the previous method. // world << "Checked trajectory, would hit [L]." diff --git a/code/modules/ai/ai_holder_targeting.dm b/code/modules/ai/ai_holder_targeting.dm index aa83507024..623b2f0b83 100644 --- a/code/modules/ai/ai_holder_targeting.dm +++ b/code/modules/ai/ai_holder_targeting.dm @@ -105,7 +105,7 @@ if(isliving(the_target)) var/mob/living/L = the_target if(ishuman(L) || issilicon(L)) - if(!L.client) // SSD players get a pass + if(L.key && !L.client) // SSD players get a pass return FALSE if(L.stat) if(L.stat == DEAD) // Leave dead things alone diff --git a/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/defense.dm b/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/defense.dm index 084f4633b2..dc8c2be032 100644 --- a/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/defense.dm +++ b/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/defense.dm @@ -1,54 +1,54 @@ -// Contains code for slimes getting attacked, beat, touched, etc, and reacting to that. - -// Clicked on by empty hand. -// Handles trying to wrestle a slime off of someone being eatten. -/mob/living/simple_mob/slime/xenobio/attack_hand(mob/living/L) - if(victim) // Are we eating someone? - var/fail_odds = 30 - if(victim == L) // Harder to get the slime off if it's you that is being eatten. - fail_odds = 60 - - if(prob(fail_odds)) - visible_message(span("warning", "\The [L] attempts to wrestle \the [name] off!")) - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - - else - visible_message(span("warning", "\The [L] manages to wrestle \the [name] off!")) - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - - if(prob(40)) - adjust_discipline(1) // Do this here so that it will be justified discipline. - stop_consumption() - step_away(src, L) - - else - ..() - -// Handles the actual harming by a melee weapon. -/mob/living/simple_mob/slime/xenobio/hit_with_weapon(obj/item/I, mob/living/user, effective_force, hit_zone) - ..() // Apply damage and etc. - if(!stat && effective_force > 0) - if(!is_justified_to_discipline()) // Wow, buddy, why am I getting attacked?? - adjust_discipline(1) // This builds resentment due to being unjustified. - - if(user in friends) // Friend attacking us for no reason. - if(prob(25)) - friends -= user - say("[user]... not friend...") - - else // We're actually being bad. - var/prob_to_back_down = round(effective_force) - if(is_adult) - prob_to_back_down /= 2 - if(prob(prob_to_back_down)) - adjust_discipline(2) // Justified. - -// Shocked grilles don't hurt slimes, and in fact give them charge. -/mob/living/simple_mob/slime/xenobio/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0, def_zone = null) - power_charge = between(0, power_charge + round(shock_damage / 10), 10) - to_chat(src, span("notice", "\The [source] shocks you, and it charges you.")) - -// Getting slimebatoned/xenotased. -/mob/living/simple_mob/slime/xenobio/slimebatoned(mob/living/user, amount) - Weaken(amount) - adjust_discipline(round(amount/2)) +// Contains code for slimes getting attacked, beat, touched, etc, and reacting to that. + +// Clicked on by empty hand. +// Handles trying to wrestle a slime off of someone being eatten. +/mob/living/simple_mob/slime/xenobio/attack_hand(mob/living/L) + if(victim) // Are we eating someone? + var/fail_odds = 30 + if(victim == L) // Harder to get the slime off if it's you that is being eatten. + fail_odds = 60 + + if(prob(fail_odds)) + visible_message(span("warning", "\The [L] attempts to wrestle \the [name] off!")) + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + + else + visible_message(span("warning", "\The [L] manages to wrestle \the [name] off!")) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + + if(prob(40)) + adjust_discipline(1) // Do this here so that it will be justified discipline. + stop_consumption() + step_away(src, L) + + else + ..() + +// Handles the actual harming by a melee weapon. +/mob/living/simple_mob/slime/xenobio/hit_with_weapon(obj/item/I, mob/living/user, effective_force, hit_zone) + ..() // Apply damage and etc. + if(!stat && effective_force > 0) + if(!is_justified_to_discipline()) // Wow, buddy, why am I getting attacked?? + adjust_discipline(1) // This builds resentment due to being unjustified. + + if(user in friends) // Friend attacking us for no reason. + if(prob(25)) + friends -= user + say("[user]... not friend...") + + else // We're actually being bad. + var/prob_to_back_down = round(effective_force) + if(is_adult) + prob_to_back_down /= 2 + if(prob(prob_to_back_down)) + adjust_discipline(2) // Justified. + +// Shocked grilles don't hurt slimes, and in fact give them charge. +/mob/living/simple_mob/slime/xenobio/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0, def_zone = null) + power_charge = between(0, power_charge + round(shock_damage / 10), 10) + to_chat(src, span("notice", "\The [source] shocks you, and it charges you.")) + +// Getting slimebatoned/xenotased. +/mob/living/simple_mob/slime/xenobio/slimebatoned(mob/living/user, amount) + adjust_discipline(round(amount/2)) + Weaken(amount) // This needs to come afterwards or else it will always be considered abuse to the slime.