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"