diff --git a/code/datums/cargoprofile.dm b/code/datums/cargoprofile.dm index dba67d0fbdb..21b21306e77 100644 --- a/code/datums/cargoprofile.dm +++ b/code/datums/cargoprofile.dm @@ -674,7 +674,7 @@ whitelist = null blacklist = list(/mob/camera,/mob/new_player,/mob/living/simple_animal/hostile/blobspore,/mob/living/simple_animal/hostile/creature, - /mob/living/simple_animal/space_worm,/mob/living/simple_animal/shade,/mob/living/simple_animal/hostile/faithless,/mob/dead) + /mob/living/simple_animal/hostile/spaceWorm,/mob/living/simple_animal/shade,/mob/living/simple_animal/hostile/faithless,/mob/dead) universal = 1 mobcheck = 1 diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 893992f5b7e..52aebdbfd17 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -26,7 +26,7 @@ var/list/wanted_objects = list() //A list of objects that will be checked against to attack, should we have search_objects enabled var/stat_attack = 0 //Mobs with stat_attack to 1 will attempt to attack things that are unconscious, Mobs with stat_attack set to 2 will attempt to attack the dead. var/stat_exclusive = 0 //Mobs with this set to 1 will exclusively attack things defined by stat_attack, stat_attack 2 means they will only attack corpses - + var/AIenabled = 1 //Badminnery and general AI toggle. /mob/living/simple_animal/hostile/Life() @@ -34,7 +34,7 @@ if(!.) walk(src, 0) return 0 - if(client) + if(client || !AIenabled) return 0 if(!stat) switch(stance) diff --git a/code/modules/mob/living/simple_animal/hostile/spaceworms.dm b/code/modules/mob/living/simple_animal/hostile/spaceworms.dm new file mode 100644 index 00000000000..3662485ddcc --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/spaceworms.dm @@ -0,0 +1,337 @@ + +//Worm Segments, Dummy, has no AI, relies on the head. +/mob/living/simple_animal/hostile/spaceWorm + name = "space worm segment" + desc = "A part of a space worm." + icon = 'icons/mob/animal.dmi' + icon_state = "spaceworm" + icon_living = "spaceworm" + icon_dead = "spacewormdead" + status_flags = 0 + + speak_emote = list("screeches") + emote_hear = list("screeches") + + response_help = "touches" + response_disarm = "flails at" + response_harm = "punches" + + harm_intent_damage = 2 + + maxHealth = 50 + health = 50 + + stop_automated_movement = 1 + animate_movement = SYNC_STEPS + + minbodytemp = 0 + maxbodytemp = 350 + min_oxy = 0 + max_co2 = 0 + max_tox = 0 + + a_intent = "harm" //so they don't get pushed around + + environment_smash = 1 + + speed = -1 + + AIenabled = 0 //The body isn't conscious + + anchored = 1 //otherwise people can literally fucking pull spaceworms apart + + faction = list("spaceworms") + + var/mob/living/simple_animal/hostile/spaceWorm/previousWorm //next/previous segments, correspondingly + var/mob/living/simple_animal/hostile/spaceWorm/nextWorm //head is the nextest segment + + var/mob/living/simple_animal/hostile/spaceWorm/wormHead/myHead //Can be the same as next, just a general reference to the main worm. + + var/stomachProcessProbability = 50 + var/digestionProbability = 20 + + var/atom/currentlyEating //what the worm is currently eating + var/plasmaPoopPotential = 5 //this mainly exists for the name + +/mob/living/simple_animal/hostile/spaceWorm/Process_Spacemove(var/check_drift = 0) + return 1 //space worms can flyyyyyy + +//Worm Head, Controls the AI for the entire worm "entity" +/mob/living/simple_animal/hostile/spaceWorm/wormHead + name = "space worm head" + icon_state = "spacewormhead" + icon_living = "spacewormhead" + icon_dead = "spacewormdead" + + //Stronger than normal segments + maxHealth = 125 + health = 125 + + melee_damage_lower = 10//was 20, dear god + melee_damage_upper = 15//was 25, dear god + attacktext = "bites" + attack_sound = 'sound/weapons/bite.ogg' + + animate_movement = SLIDE_STEPS + + AIenabled = 1//The head is conscious + stop_automated_movement = 0 //Ditto ^ + + faction = list("spaceworms") //head and body both have this faction JIC + + //head specific variables + var/spawnWithSegments = 6 + var/list/totalWormSegments = list() //doesn't contain src + var/catastrophicDeathProb = 15 //15% chance for the death of the head to kill the whole thing + + +/mob/living/simple_animal/hostile/spaceWorm/wormHead/New(var/location, var/segments = spawnWithSegments) + ..() + + if(!src)//This is to prevent a runtime. + return + + myHead = src //It's it's own head. + + //Used in the for to attach each worm segment to the next in the sequence, instead of all of them to src + var/mob/living/simple_animal/hostile/spaceWorm/currentWormSeg = src + + for(var/i = 1 to segments) + var/mob/living/simple_animal/hostile/spaceWorm/newSegment = new /mob/living/simple_animal/hostile/spaceWorm(loc) + currentWormSeg.Attach(newSegment) + currentWormSeg = newSegment + + for(var/mob/living/simple_animal/hostile/spaceWorm/SW in totalWormSegments) + SW.update_icon() + +/mob/living/simple_animal/hostile/spaceWorm/wormHead/update_icon() + if(stat == CONSCIOUS || stat == UNCONSCIOUS) + icon_state = "spacewormhead[previousWorm ? 1 : 0]" + if(previousWorm) + dir = get_dir(previousWorm,src) + else + icon_state = "spacewormheaddead" + + for(var/mob/living/simple_animal/hostile/spaceWorm/SW in totalWormSegments) + if(SW == src)//incase src ends up in here we don't want an infinite loop + continue + SW.update_icon() + + +//Try to move onto target's turf and eat them +/mob/living/simple_animal/hostile/spaceWorm/wormHead/AttackingTarget() + ..() + attemptToEat(target) + +//Attempt to eat things we bump into, Mobs, Walls, Clowns +/mob/living/simple_animal/hostile/spaceWorm/wormHead/Bump(atom/obstacle) + + attemptToEat(obstacle) + +//Attempt to eat things, only the head can eat +/mob/living/simple_animal/hostile/spaceWorm/wormHead/proc/attemptToEat(var/atom/noms) + + + if(currentlyEating == noms) //currentlyEating is always undefined at the end, so don't eat the same thing twice + return + + if(istype(noms, /obj/structure/window)) + return + if(istype(noms, /obj/structure/grille)) //these three bug-out and won't work, so just ignore them + return + if(istype(noms, /obj/machinery/door/window)) + return + + if(!noms) + return + currentlyEating = noms + + var/nomDelay = 25 + var/turf/simulated/wall/W + + if(noms in totalWormSegments) + return //Trying to eat part of self. + + if(istype(noms, /turf)) + if(istype(noms, /turf/simulated/wall)) + W = noms + nomDelay *= 2 + if(W.walltype == "rwall") + nomDelay *= 2 + else + return + + var/ufnomDelay = nomDelay * 0.1 + + src.visible_message("\the [src] starts to eat \the [noms]!","You start to eat \the [noms]. (This will take about [ufnomDelay] seconds.)","You hear gnashing.") //inform everyone what the fucking worm is doing. + + if(do_after(src, nomDelay,5,0)) + if(noms && Adjacent(noms) && (currentlyEating == noms))//It exists, were next to it, and it's still the thing were eating + if(W) + W.ChangeTurf(/turf/simulated/floor/plating) + new /obj/item/stack/sheet/metal(src, plasmaPoopPotential) + currentlyEating = null //ffs, unstore this + src.visible_message("\the [src] eats \the [noms]!","You eat \the [noms]!","You hear gnashing.") //inform everyone what the fucking worm is doing. + else + currentlyEating = null + contents += noms + src.visible_message("\the [src] eats \the [noms]!","You eat \the [noms]!","You hear gnashing.") //inform everyone what the fucking worm is doing. + if(ismob(noms)) + var/mob/M = noms //typecast because noms isn't movable + M.loc = src //because just setting a mob loc to null breaks the camera and such + else + currentlyEating = null + else + currentlyEating = null //JIC + + +//Harder to kill the head, but it can kill off the whole worm +/mob/living/simple_animal/hostile/spaceWorm/wormHead/Die() + ..() + if(prob(catastrophicDeathProb)) + for(var/mob/living/simple_animal/hostile/spaceWorm/SW in totalWormSegments) + SW.Die() + + +/mob/living/simple_animal/hostile/spaceWorm/Life() + if(nextWorm && !(Adjacent(nextWorm))) + Detach(0) + + if(stat == DEAD) + if(previousWorm) + previousWorm.Detach(0) + if(nextWorm) + Detach(1) + + if(prob(stomachProcessProbability)) + ProcessStomach() + + update_icon()//While most mobs don't call this on Life(), the worm would probably look stupid without it + //Plus the worm's update_icon() isn't as beefy. + + ..() //Really high fuckin priority that this is at the bottom. + + +//if a chunk a destroyed, make a new worm out of the split halves +/mob/living/simple_animal/hostile/spaceWorm/Destroy() + if(previousWorm) + previousWorm.Detach(0) + ..() + + +//Move all segments if one piece moves. +/mob/living/simple_animal/hostile/spaceWorm/Move() + var/segmentNextPos = loc + if(..()) + if(previousWorm) + previousWorm.Move(segmentNextPos) + update_icon() + + +//Update the appearence of this big weird chain-worm-thingy +/mob/living/simple_animal/hostile/spaceWorm/proc/update_icon() + if(stat != DEAD) + if(previousWorm) + icon_state = "spaceworm[get_dir(src,previousWorm) | get_dir(src,nextWorm)]" + else + icon_state = "spacewormtail"//end of rine + dir = get_dir(src,nextWorm) + + else + icon_state = "spacewormdead" + + + +//Add a new worm segment +/mob/living/simple_animal/hostile/spaceWorm/proc/Attach(var/mob/living/simple_animal/hostile/spaceWorm/toAttach) + if(!toAttach) + return + + previousWorm = toAttach + toAttach.nextWorm = src + + if(myHead) + if(toAttach.myHead) + toAttach.myHead.totalWormSegments -= src + + toAttach.myHead = myHead + myHead.totalWormSegments |= toAttach + + //if toAttach is part of another worm, disconnect all those parts and connect them to the new worm. + var/mob/living/simple_animal/hostile/spaceWorm/isPrevWorm + if(toAttach.previousWorm) + isPrevWorm = toAttach.previousWorm + + while(isPrevWorm) + if(isPrevWorm.previousWorm) + if(isPrevWorm.myHead) + isPrevWorm.myHead.totalWormSegments -=isPrevWorm.previousWorm + toAttach.myHead.totalWormSegments |= isPrevWorm.previousWorm + isPrevWorm = isPrevWorm.previousWorm + else + isPrevWorm = null + + update_icons() + + +//Remove a worm segment +/mob/living/simple_animal/hostile/spaceWorm/proc/Detach(var/die = 0) + var/mob/living/simple_animal/hostile/spaceWorm/wormHead/newHead = new /mob/living/simple_animal/hostile/spaceWorm/wormHead(loc,0) + var/mob/living/simple_animal/hostile/spaceWorm/newHeadPrev + + if(previousWorm) + newHeadPrev = previousWorm + + previousWorm = null + + if(newHeadPrev) + newHead.Attach(newHeadPrev) + + if(myHead) + myHead.totalWormSegments -= src + + if(die) + newHead.Die() + + qdel(src) + + +/mob/living/simple_animal/hostile/spaceWorm/Die() + ..() + if(myHead) + myHead.totalWormSegments -= src + + +//Process nom noms, things we've eaten have a chance to become plasma +/mob/living/simple_animal/hostile/spaceWorm/proc/ProcessStomach() + for(var/atom/movable/stomachContent in contents) + if(prob(digestionProbability)) + new /obj/item/stack/sheet/mineral/plasma(src, plasmaPoopPotential) + if(ismob(stomachContent)) + var/mob/M = stomachContent + M.ghostize() //because qdelling an entire mob without ghosting it is BAD + qdel(stomachContent) + + if(previousWorm) + for(var/atom/movable/stomachContent in contents) //move it along the digestive tract + contents -= stomachContent + previousWorm.contents += stomachContent + if(ismob(stomachContent)) + stomachContent.loc = previousWorm //weird shit happens otherwise + else + var/turf/T = get_turf(src) + for(var/atom/movable/stomachContent in contents) + contents -= stomachContent + stomachContent.loc = T + + +//Looks weird otherwise. +/mob/living/simple_animal/hostile/spaceWorm/float(on) + return + + +//Jiggle the whole worm forwards towards the next segment +/mob/living/simple_animal/hostile/spaceWorm/do_attack_animation(atom/A) + ..() + if(previousWorm) + previousWorm.do_attack_animation(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/worm.dm b/code/modules/mob/living/simple_animal/worm.dm deleted file mode 100644 index 80868dc19e6..00000000000 --- a/code/modules/mob/living/simple_animal/worm.dm +++ /dev/null @@ -1,197 +0,0 @@ -/mob/living/simple_animal/space_worm - name = "space worm segment" - desc = "A part of a space worm." - icon = 'icons/mob/animal.dmi' - icon_state = "spaceworm" - icon_living = "spaceworm" - icon_dead = "spacewormdead" - status_flags = 0 - - speak_emote = list("transmits") //not supposed to be used under AI control - emote_hear = list("transmits") //I'm just adding it so it doesn't runtime if controlled by player who speaks - - response_help = "touches" - response_disarm = "flails at" - response_harm = "punches the" - - harm_intent_damage = 2 - - maxHealth = 30 - health = 30 - - stop_automated_movement = 1 - animate_movement = SYNC_STEPS - - minbodytemp = 0 - maxbodytemp = 350 - min_oxy = 0 - max_co2 = 0 - max_tox = 0 - - a_intent = "harm" //so they don't get pushed around - - speed = -1 - - var/mob/living/simple_animal/space_worm/previous //next/previous segments, correspondingly - var/mob/living/simple_animal/space_worm/next //head is the nextest segment - - var/stomachProcessProbability = 50 - var/digestionProbability = 20 - var/flatPlasmaValue = 5 //flat plasma amount given for non-items - - var/atom/currentlyEating //what the worm is currently eating - var/eatingDuration = 0 //how long he's been eating it for - - head - name = "space worm head" - icon_state = "spacewormhead" - icon_living = "spacewormhead" - icon_dead = "spacewormdead" - - maxHealth = 20 - health = 20 - - melee_damage_lower = 10 - melee_damage_upper = 15 - attacktext = "bites" - - animate_movement = SLIDE_STEPS - - New(var/location, var/segments = 6) - ..() - - var/mob/living/simple_animal/space_worm/current = src - - for(var/i = 1 to segments) - var/mob/living/simple_animal/space_worm/newSegment = new /mob/living/simple_animal/space_worm(loc) - current.Attach(newSegment) - current = newSegment - - update_icon() - if(stat == CONSCIOUS || stat == UNCONSCIOUS) - icon_state = "spacewormhead[previous?1:0]" - if(previous) - dir = get_dir(previous,src) - else - icon_state = "spacewormheaddead" - - Life() - ..() - - if(next && !(next in view(src,1))) - Detach() - - if(stat == DEAD) //dead chunks fall off and die immediately - if(previous) - previous.Detach() - if(next) - Detach(1) - - if(prob(stomachProcessProbability)) - ProcessStomach() - - update_icon() - - return - - Destroy() //if a chunk a destroyed, make a new worm out of the split halves - if(previous) - previous.Detach() - ..() - - Move() - var/attachementNextPosition = loc - if(..()) - if(previous) - previous.Move(attachementNextPosition) - update_icon() - - Bump(atom/obstacle) - if(currentlyEating != obstacle) - currentlyEating = obstacle - eatingDuration = 0 - - if(!AttemptToEat(obstacle)) - eatingDuration++ - else - currentlyEating = null - eatingDuration = 0 - - return - - proc/update_icon() //only for the sake of consistency with the other update icon procs - if(stat == CONSCIOUS || stat == UNCONSCIOUS) - if(previous) //midsection - icon_state = "spaceworm[get_dir(src,previous) | get_dir(src,next)]" //see 3 lines below - else //tail - icon_state = "spacewormtail" - dir = get_dir(src,next) //next will always be present since it's not a head and if it's dead, it goes in the other if branch - else - icon_state = "spacewormdead" - - return - - proc/AttemptToEat(var/atom/target) - if(istype(target,/turf/simulated/wall)) - if((!istype(target,/turf/simulated/wall/r_wall) && eatingDuration >= 100) || eatingDuration >= 200) //need 20 ticks to eat an rwall, 10 for a regular one - var/turf/simulated/wall/wall = target - wall.ChangeTurf(/turf/simulated/floor) - new /obj/item/stack/sheet/metal(src, flatPlasmaValue) - return 1 - else if(istype(target,/atom/movable)) - if(istype(target,/mob) || eatingDuration >= 50) //5 ticks to eat stuff like airlocks - var/atom/movable/objectOrMob = target - contents += objectOrMob - return 1 - - return 0 - - proc/Attach(var/mob/living/simple_animal/space_worm/attachement) - if(!attachement) - return - - previous = attachement - attachement.next = src - - return - - proc/Detach(die = 0) - var/mob/living/simple_animal/space_worm/newHead = new /mob/living/simple_animal/space_worm/head(loc,0) - var/mob/living/simple_animal/space_worm/newHeadPrevious = previous - - previous = null //so that no extra heads are spawned - - newHead.Attach(newHeadPrevious) - - if(die) - newHead.Die() - - del(src) - - proc/ProcessStomach() - for(var/atom/movable/stomachContent in contents) - if(prob(digestionProbability)) - if(istype(stomachContent,/obj/item/stack)) //converts to plasma, keeping the stack value - if(!istype(stomachContent,/obj/item/stack/sheet/mineral/plasma)) - var/obj/item/stack/oldStack = stomachContent - new /obj/item/stack/sheet/mineral/plasma(src, oldStack.amount) - del(oldStack) - continue - else if(istype(stomachContent,/obj/item)) //converts to plasma, keeping the w_class - var/obj/item/oldItem = stomachContent - new /obj/item/stack/sheet/mineral/plasma(src, oldItem.w_class) - del(oldItem) - continue - else - new /obj/item/stack/sheet/mineral/plasma(src, flatPlasmaValue) //just flat amount - del(stomachContent) - continue - - if(previous) - for(var/atom/movable/stomachContent in contents) //transfer it along the digestive tract - previous.contents += stomachContent - else - for(var/atom/movable/stomachContent in contents) //or poop it out - loc.contents += stomachContent - - return \ No newline at end of file diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index c90ebae7328..ef3536cc55f 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -123,7 +123,7 @@ O.rename_self("ai",1) . = O qdel(src) - + /mob/living/carbon/human/make_into_mask(var/should_gib = 0) for(var/t in organs) qdel(t) @@ -383,7 +383,7 @@ if(!MP) return 0 //Sanity, this should never happen. - if(ispath(MP, /mob/living/simple_animal/space_worm)) + if(ispath(MP, /mob/living/simple_animal/hostile/spaceWorm)) return 0 //Unfinished. Very buggy, they seem to just spawn additional space worms everywhere and eating your own tail results in new worms spawning. if(ispath(MP, /mob/living/simple_animal/construct/behemoth)) diff --git a/paradise.dme b/paradise.dme index 8e9e07a4be8..072748afa0a 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1299,7 +1299,6 @@ #include "code\modules\mob\living\simple_animal\simple_animal.dm" #include "code\modules\mob\living\simple_animal\tribbles.dm" #include "code\modules\mob\living\simple_animal\vox.dm" -#include "code\modules\mob\living\simple_animal\worm.dm" #include "code\modules\mob\living\simple_animal\friendly\butterfly.dm" #include "code\modules\mob\living\simple_animal\friendly\cat.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi.dm" @@ -1327,6 +1326,7 @@ #include "code\modules\mob\living\simple_animal\hostile\mushroom.dm" #include "code\modules\mob\living\simple_animal\hostile\pirate.dm" #include "code\modules\mob\living\simple_animal\hostile\russian.dm" +#include "code\modules\mob\living\simple_animal\hostile\spaceworms.dm" #include "code\modules\mob\living\simple_animal\hostile\statue.dm" #include "code\modules\mob\living\simple_animal\hostile\syndicate.dm" #include "code\modules\mob\living\simple_animal\hostile\tree.dm"