diff --git a/code/modules/critters/critter.dm b/code/modules/critters/critter.dm index bd46ecaf04..854765817c 100644 --- a/code/modules/critters/critter.dm +++ b/code/modules/critters/critter.dm @@ -23,6 +23,8 @@ wanderer = 1 //Will open doors it bumps ignoring access opensdoors = 0 + //Will randomly travel through vents + ventcrawl = 0 //Internal tracking ignore frustration = 0 @@ -34,6 +36,10 @@ target = null oldtarget_name = null target_lastloc = null + + thinkspeed = 15 + chasespeed = 4 + wanderspeed = 10 //The last guy who attacked it attacker = null //Will not attack this thing @@ -49,6 +55,11 @@ atksame = 0 atkmech = 0 + //Attacks syndies/traitors (distinguishes via mind) + atksynd = 1 + //Attacks things NOT in its obj/req_access list + atkreq = 0 + //Damage multipliers brutevuln = 1 firevuln = 1 @@ -61,7 +72,10 @@ //Basic attack message when they move to attack and attack angertext = "charges at" attacktext = "attacks" + deathtext = "dies!" + chasestate = null // the icon state to use when attacking or chasing a target + attackflick = null // the icon state to flick when it attacks attack_sound = null // the sound it makes when it attacks! attack_speed = 25 // delay of attack @@ -121,4 +135,4 @@ -*/ +*/ \ No newline at end of file diff --git a/code/modules/critters/critter_AI.dm b/code/modules/critters/critter_AI.dm index 169ce48974..ae11c6e6d6 100644 --- a/code/modules/critters/critter_AI.dm +++ b/code/modules/critters/critter_AI.dm @@ -13,7 +13,7 @@ if("thinking") src.attack = 0 src.target = null - sleep(15) + sleep(thinkspeed) walk_to(src,0) if (src.aggressive) seek_target() if (src.wanderer && !src.target) src.task = "wandering" @@ -29,11 +29,13 @@ var/mob/living/carbon/M = src.target ChaseAttack() src.task = "attacking" + if(chasestate) + icon_state = chasestate src.anchored = 1 src.target_lastloc = M.loc else var/turf/olddist = get_dist(src, src.target) - walk_to(src, src.target,1,speed) + walk_to(src, src.target,1,chasespeed) if ((get_dist(src, src.target)) >= (olddist)) src.frustration++ else @@ -45,6 +47,8 @@ if ((get_dist(src, src.target) > 1) || ((src.target:loc != src.target_lastloc))) src.anchored = 0 src.task = "chasing" + if(chasestate) + icon_state = chasestate else if (get_dist(src, src.target) <= 1) var/mob/living/carbon/M = src.target @@ -58,20 +62,25 @@ src.attacking = 0 else if(M!=null) - if(M.health < 0) - src.task = "thinking" - src.target = null - src.anchored = 0 - src.last_found = world.time - src.frustration = 0 - src.attacking = 0 + if(ismob(src.target)) + if(M.health < 0) + src.task = "thinking" + src.target = null + src.anchored = 0 + src.last_found = world.time + src.frustration = 0 + src.attacking = 0 else src.anchored = 0 src.attacking = 0 src.task = "chasing" + if(chasestate) + icon_state = chasestate if("wandering") + if(chasestate) + icon_state = initial(icon_state) patrol_step() - sleep(10) + sleep(wanderspeed) spawn(8) process() return @@ -114,29 +123,57 @@ if (src.target) src.task = "chasing" break + + // Ignore syndicates and traitors if specified + if(!atksynd && C.mind) + var/datum/mind/synd_mind = C.mind + if( synd_mind.special_role == "Syndicate" || synd_mind.special_role == "traitor" ) + continue if((C.name == src.oldtarget_name) && (world.time < src.last_found + 100)) continue if(istype(C, /mob/living/carbon/) && !src.atkcarbon) continue if(istype(C, /mob/living/silicon/) && !src.atksilicon) continue + if(atkreq) + if(src.allowed(C)) continue if(C.health < 0) continue if(istype(C, /mob/living/carbon/) && src.atkcarbon) src.attack = 1 if(istype(C, /mob/living/silicon/) && src.atksilicon) src.attack = 1 + if(atkreq) + if(!src.allowed(C)) src.attack = 1 if(src.attack) T = C break if(!src.attack) for(var/obj/effect/critter/C in view(src.seekrange,src)) - if(istype(C, /obj/effect/critter) && !src.atkcritter) continue - if(istype(C, /obj/mecha) && !src.atkmech) continue + if(!src.atkcritter) continue if(C.health <= 0) continue - if(istype(C, /obj/effect/critter) && src.atkcritter) + if(src.atkcritter) if((istype(C, src.type) && !src.atksame) || (C == src)) continue src.attack = 1 - if(istype(C, /obj/mecha) && src.atkmech) src.attack = 1 if(src.attack) T = C break + if(!src.attack) + for(var/obj/mecha/C in view(src.seekrange,src)) + if(!C.occupant) continue + + if(atkreq && C.occupant) + if(src.allowed(C.occupant)) continue + + if(!atksynd && C.occupant) + if(C.occupant.mind) + var/datum/mind/synd_mind = C.occupant.mind + if( synd_mind.special_role == "Syndicate" || synd_mind.special_role == "traitor" ) + continue + + if(!src.atkmech) continue + if(C.health <= 0) continue + if(src.atkmech) src.attack = 1 + if(src.attack) + T = C + break + if(src.attack) src.target = T src.oldtarget_name = T:name @@ -152,10 +189,11 @@ RunAttack() src.attacking = 1 - for(var/mob/O in viewers(src, null)) - O.show_message("\red [src] [src.attacktext] [src.target]!", 1) if(ismob(src.target)) + for(var/mob/O in viewers(src, null)) + O.show_message("\red [src] [src.attacktext] [src.target]!", 1) + var/damage = rand(melee_damage_lower, melee_damage_upper) if(istype(target, /mob/living/carbon/human)) @@ -174,7 +212,8 @@ if(isobj(src.target)) if(istype(target, /obj/mecha)) - src.target:take_damage(rand(melee_damage_lower,melee_damage_upper)) + //src.target:take_damage(rand(melee_damage_lower,melee_damage_upper)) + src.target:attack_critter(src) else src.target:TakeDamage(rand(melee_damage_lower,melee_damage_upper)) spawn(attack_speed) @@ -200,4 +239,4 @@ smoke.set_up(10, 0, src.loc) smoke.start() src.task = "thinking" -*/ +*/ \ No newline at end of file diff --git a/code/modules/critters/critter_defenses.dm b/code/modules/critters/critter_defenses.dm index fc50e9f02a..fde45ab5d3 100644 --- a/code/modules/critters/critter_defenses.dm +++ b/code/modules/critters/critter_defenses.dm @@ -13,7 +13,7 @@ Contains the procs that control attacking critters if("fire") damage = W.force * firevuln if("brute") damage = W.force * brutevuln TakeDamage(damage) - if(src.defensive) Target_Attacker(user) + if(src.defensive && alive) Target_Attacker(user) return @@ -51,9 +51,10 @@ Contains the procs that control attacking critters if(!target) return src.target = target src.oldtarget_name = target:name - if(task != "chasing" || task != "attacking") - for(var/mob/O in viewers(src, null)) - O.show_message("\red [src] [src.angertext] at [target:name]!", 1) + if(task != "chasing" && task != "attacking") + if(angertext && angertext != "") + for(var/mob/O in viewers(src, null)) + O.show_message("\red [src] [src.angertext] at [target:name]!", 1) src.task = "chasing" return @@ -75,7 +76,7 @@ Contains the procs that control attacking critters src.anchored = 0 src.density = 0 walk_to(src,0) - src.visible_message("[src] dies!") + src.visible_message("[src] [deathtext]") Harvest(var/obj/item/weapon/W, var/mob/living/user) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index e3d151d2ba..bf3df67ac3 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -252,6 +252,7 @@ proc/slur(phrase) p++//for each letter p is increased to find where the next letter will be. return copytext(sanitize(t),1,MAX_MESSAGE_LEN) + proc/Gibberish(t, p) /* Turn text into complete gibberish! */ var/returntext = "" @@ -269,6 +270,7 @@ proc/Gibberish(t, p) return returntext + /proc/ninjaspeak(n) /* The difference with stutter is that this proc can stutter more than 1 letter diff --git a/icons/mob/critter.dmi b/icons/mob/critter.dmi index 0febb340d1..2b5a718991 100644 Binary files a/icons/mob/critter.dmi and b/icons/mob/critter.dmi differ