From d741b0e987fcbee1bd3a5c27d5c581ffa99a5a25 Mon Sep 17 00:00:00 2001 From: Neerti Date: Sun, 17 Sep 2017 13:18:16 -0400 Subject: [PATCH] Slime Update Pink Slime Aura and Mend Synthetic (technomancer) should now fix FBPs again. Adds procs to get the 'real' number of damage from humans, including limb damage on prosthetic limbs. Slime following made a bit more robust, slimes (and other simple animals) stop wandering when following. Slimes following a leader that passes the can_command() check will refrain from attacking things if not attacked first. Slime kill command implemented, requires the slime to be in your faction or be the slime's friend, and not just obedient. This can be accomplished with end-game slime agents. Slimes require three 'free' tiles to split, which should prevent super overcrowed cells and by extension avoid Amber Tide from crashing the mob controller. Dark Blue Cold Aura now properly adjusts temperature based on protection gradually instead of instantly setting to the lowest value. --- code/__defines/mobs.dm | 7 ++- .../spells/modifier/mend_synthetic.dm | 15 ++++-- .../mob/living/carbon/human/human_damage.dm | 12 +++++ code/modules/mob/living/living.dm | 6 +++ .../mob/living/simple_animal/simple_animal.dm | 2 + .../mob/living/simple_animal/slime/ai.dm | 18 +++---- .../mob/living/simple_animal/slime/life.dm | 51 ++++++++++--------- .../mob/living/simple_animal/slime/slime.dm | 26 ++++++++-- .../living/simple_animal/slime/subtypes.dm | 17 +++++-- 9 files changed, 106 insertions(+), 48 deletions(-) diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index de957d8b21..425b6e7f76 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -218,4 +218,9 @@ #define SA_PLANT 1 #define SA_ANIMAL 2 #define SA_ROBOTIC 3 -#define SA_HUMANOID 4 \ No newline at end of file +#define SA_HUMANOID 4 + +// For slime commanding. Higher numbers allow for more actions. +#define SLIME_COMMAND_OBEY 1 // When disciplined. +#define SLIME_COMMAND_FACTION 2 // When in the same 'faction'. +#define SLIME_COMMAND_FRIEND 3 // When befriended with a slime friendship agent. \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm b/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm index 0c39e99d60..cca20eb3b0 100644 --- a/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm +++ b/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm @@ -29,17 +29,22 @@ stacks = MODIFIER_STACK_EXTEND /datum/modifier/technomancer/mend_synthetic/tick() - if(!holder.isSynthetic()) // Don't heal biologicals! - expire() - return - if(!holder.getBruteLoss() && !holder.getFireLoss()) // No point existing if the spell can't heal. +// if(!holder.isSynthetic()) // Don't heal biologicals! +// expire() +// return + if(!holder.getActualBruteLoss() && !holder.getActualFireLoss()) // No point existing if the spell can't heal. expire() return if(ishuman(holder)) var/mob/living/carbon/human/H = holder for(var/obj/item/organ/external/E in H.organs) var/obj/item/organ/external/O = E - O.heal_damage(4 * spell_power, 4 * spell_power, 0, 1) + if(O.robotic >= ORGAN_ROBOT) + O.heal_damage(4 * spell_power, 4 * spell_power, 0, 1) + else + holder.adjustBruteLoss(-4 * spell_power) // Should heal roughly 20 burn/brute over 10 seconds, as tick() is run every 2 seconds. + holder.adjustFireLoss(-4 * spell_power) // Ditto. + holder.adjust_instability(1) if(origin) var/mob/living/L = origin.resolve() diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 30ee7c64d6..34ab2bf4bb 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -80,6 +80,12 @@ amount += O.brute_dam return amount +/mob/living/carbon/human/getActualBruteLoss() + var/amount = 0 + for(var/obj/item/organ/external/O in organs) // Unlike the above, robolimbs DO count. + amount += O.brute_dam + return amount + /mob/living/carbon/human/getFireLoss() var/amount = 0 for(var/obj/item/organ/external/O in organs) @@ -96,6 +102,12 @@ amount += O.burn_dam return amount +/mob/living/carbon/human/getActualFireLoss() + var/amount = 0 + for(var/obj/item/organ/external/O in organs) // Unlike the above, robolimbs DO count. + amount += O.burn_dam + return amount + /mob/living/carbon/human/adjustBruteLoss(var/amount) amount = amount*species.brute_mod if(amount > 0) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index b33688e59b..d7f53441c2 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -218,6 +218,9 @@ default behaviour is: /mob/living/proc/getShockBruteLoss() //Only checks for things that'll actually hurt (not robolimbs) return bruteloss +/mob/living/proc/getActualBruteLoss() // Mostly for humans with robolimbs. + return getBruteLoss() + /mob/living/proc/adjustBruteLoss(var/amount) if(status_flags & GODMODE) return 0 //godmode @@ -286,6 +289,9 @@ default behaviour is: /mob/living/proc/getShockFireLoss() //Only checks for things that'll actually hurt (not robolimbs) return fireloss +/mob/living/proc/getActualFireLoss() // Mostly for humans with robolimbs. + return getBruteLoss() + /mob/living/proc/adjustFireLoss(var/amount) if(status_flags & GODMODE) return 0 //godmode if(amount > 0) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index c6b8bee691..df30442538 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -994,6 +994,7 @@ //Follow a target (and don't attempt to murder it horribly) /mob/living/simple_animal/proc/FollowTarget() ai_log("FollowTarget() [follow_mob]",1) + stop_automated_movement = 1 //If we were chasing someone and we can't anymore, give up. if(!follow_mob || follow_mob.stat) ai_log("FollowTarget() Losing follow at top",2) @@ -1324,6 +1325,7 @@ //Forget a follow mode /mob/living/simple_animal/proc/LoseFollow() ai_log("LoseFollow() [target_mob]",2) + stop_automated_movement = 0 follow_mob = null handle_stance(STANCE_IDLE) GiveUpMoving() diff --git a/code/modules/mob/living/simple_animal/slime/ai.dm b/code/modules/mob/living/simple_animal/slime/ai.dm index 2a61f91e31..b35ebb6e03 100644 --- a/code/modules/mob/living/simple_animal/slime/ai.dm +++ b/code/modules/mob/living/simple_animal/slime/ai.dm @@ -1,11 +1,16 @@ /mob/living/simple_animal/slime/FindTarget() if(victim) // Don't worry about finding another target if we're eatting someone. return -// if(!will_hunt()) -// return + if(follow_mob && can_command(follow_mob)) // If following someone, don't attack until the leader says so, something hits you, or the leader is no longer worthy. + return ..() /mob/living/simple_animal/slime/special_target_check(mob/living/L) + if(L.faction == faction && !attack_same) + return FALSE + if(L in friends) + return FALSE + if(istype(L, /mob/living/simple_animal/slime)) var/mob/living/simple_animal/slime/buddy = L if(buddy.slime_color == src.slime_color || discipline || unity || buddy.unity) @@ -47,12 +52,3 @@ return else ..() - -/* -/mob/living/simple_animal/slime/proc/will_hunt() // Check for being stopped from feeding and chasing - if(nutrition <= get_starve_nutrition() || rabid) - return TRUE - if(nutrition <= get_hunger_nutrition() || prob(25)) - return TRUE - return FALSE -*/ \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm index 30c2dba554..21e7c62820 100644 --- a/code/modules/mob/living/simple_animal/slime/life.dm +++ b/code/modules/mob/living/simple_animal/slime/life.dm @@ -97,16 +97,21 @@ // This is to make slime responses feel a bit more natural and not instant. /mob/living/simple_animal/slime/proc/delayed_say(var/message, var/mob/target) - sleep(rand(1 SECOND, 2 SECONDS)) - if(target) - face_atom(target) - say(message) + spawn(rand(1 SECOND, 2 SECONDS)) + if(target) + face_atom(target) + say(message) //Commands, reactions, etc /mob/living/simple_animal/slime/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) ..() if((findtext(message, num2text(number)) || findtext(message, name) || findtext(message, "slimes"))) // Talking to us + // First make sure it's not just another slime repeating things. + if(istype(speaker, /mob/living/simple_animal/slime)) + if(!speaker.client) + return + // Say hello back. if(findtext(message, "hello") || findtext(message, "hi") || findtext(message, "greetings")) delayed_say(pick("Hello...", "Hi..."), speaker) @@ -142,33 +147,31 @@ adjust_discipline(1, TRUE) if(follow_mob) // We're being asked to stop following someone. - if(follow_mob == speaker) + if(can_command(speaker) == SLIME_COMMAND_FRIEND || follow_mob == speaker) delayed_say("Yes... I'll stop...", speaker) LoseFollow() else delayed_say("No... I'll keep following \the [follow_mob]...", speaker) - // Help request - if(findtext(message, "help")) - if(!can_command(speaker)) - delayed_say("No...", speaker) - return - else - delayed_say("I will protect \the [speaker].", speaker) - // Murder request if(findtext(message, "harm") || findtext(message, "kill") || findtext(message, "murder") || findtext(message, "eat") || findtext(message, "consume")) - if(!can_command(speaker)) + if(can_command(speaker) < SLIME_COMMAND_FACTION) delayed_say("No...", speaker) return - //LoseFollow() - - /* - if(reacts && speaker && (message in reactions) && (!hostile || isliving(speaker)) && say_understands(speaker,language)) - var/mob/living/L = speaker - if(L.faction == faction) - spawn(10) - face_atom(speaker) - say(reactions[message]) - */ \ No newline at end of file + for(var/mob/living/L in view(7, src) - list(src, 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(special_target_check(L)) + delayed_say("Okay... I attack \the [L]...", speaker) + LoseFollow() + set_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) diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index e648788497..29ffe8e4a3 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -297,6 +297,24 @@ if(is_adult) if(amount_grown >= 10) + // Check if there's enough 'room' to split. + var/list/nearby_things = orange(1, src) + var/free_tiles = 0 + for(var/turf/T in nearby_things) + var/free = TRUE + if(T.density) // No walls. + continue + for(var/atom/movable/AM in T) + if(AM.density) + free = FALSE + break + + if(free) + free_tiles++ + + if(free_tiles < 3) // Three free tiles are needed, as four slimes are made and the 4th tile is from the center tile that the current slime occupies. + to_chat(src, "It is too cramped here to reproduce...") + return var/list/babies = list() for(var/i = 1 to 4) @@ -352,13 +370,13 @@ if(rabid) return FALSE if(docile) - return TRUE + return SLIME_COMMAND_OBEY if(commander in friends) - return TRUE + return SLIME_COMMAND_FRIEND if(faction == commander.faction) - return TRUE + return SLIME_COMMAND_FACTION if(discipline > resentment && obedience >= 5) - return TRUE + return SLIME_COMMAND_OBEY return FALSE /mob/living/simple_animal/slime/proc/give_hat(var/obj/item/clothing/head/new_hat, var/mob/living/user) diff --git a/code/modules/mob/living/simple_animal/slime/subtypes.dm b/code/modules/mob/living/simple_animal/slime/subtypes.dm index ec6b23644d..089edb1a82 100644 --- a/code/modules/mob/living/simple_animal/slime/subtypes.dm +++ b/code/modules/mob/living/simple_animal/slime/subtypes.dm @@ -200,12 +200,15 @@ var/cold_factor = abs(protection - 1) var/delta = -20 delta *= cold_factor - L.bodytemperature = max(50, delta) + L.bodytemperature = max(50, L.bodytemperature + delta) var/turf/T = get_turf(src) var/datum/gas_mixture/env = T.return_air() if(env) env.add_thermal_energy(-10 * 1000) +/mob/living/simple_animal/slime/dark_blue/get_cold_protection() + return 1 // This slime is immune to cold. + /mob/living/simple_animal/slime/silver desc = "This slime is shiny, and can deflect lasers or other energy weapons directed at it." @@ -513,8 +516,16 @@ /datum/modifier/slime_heal/tick() if(holder.stat == DEAD) // Required or else simple animals become immortal. expire() - holder.adjustBruteLoss(-2) - holder.adjustFireLoss(-2) + + if(ishuman(holder)) // Robolimbs need this code sadly. + var/mob/living/carbon/human/H = holder + for(var/obj/item/organ/external/E in H.organs) + var/obj/item/organ/external/O = E + O.heal_damage(2, 2, 0, 1) + else + holder.adjustBruteLoss(-2) + holder.adjustFireLoss(-2) + holder.adjustToxLoss(-2) holder.adjustOxyLoss(-2) holder.adjustCloneLoss(-1)