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 ebe642809b..3f4e37f1a0 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -221,6 +221,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 @@ -289,6 +292,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 b1179bb3ea..c1e912b74c 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -298,6 +298,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) @@ -353,13 +371,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)