Files
Bubberstation/code/modules/mob/mob_movement.dm
Xhuis 527dddd95d Complete Revenant Rewrite (#18522)
I'm unhappy with the way revenants are right now, and my code for them is pretty unsatisfactory in comparison to what I know now. Although revenants will still fill the same role of just being spookier ghosts, they'll be a bit more passive - incapable, for instance, of giving diseases to people. The new revenants will be called umbras and will use vitae instead of essence.

Total change list:

    Revenants have been renamed to umbras. Essence has been renamed to vitae. This may be temporary.
    Umbra spawn events are now weighted higher and spawn an unoccupied umbra. Ghosts are alerted to the umbra's position and may interact with it to take control of it.
    Umbras' health is not based on vitae but has a hard cap at 100.
    Umbras have a passive vitae drain each tick, defaulting at 0.01. If the umbra runs out of vitae, they will die irrevocably. They also slowly regenerate health by doing this.
    When an umbra dies, they leave behind umbral ashes that reform after one minute. They're difficult to see and can be scattered by activating them, although they also have high research levels if you're fast enough.
    Harvesting vitae from critical targets no longer kills them. Harvesting a target in general prohibits them from being harvested until five minutes later, but they can be drained again after that.
    EMPs revitalize umbras and give them hefty amounts of vitae due to their physical nature.
    Umbras have four abilities: Toggle Nightvision, Discordant Whisper, Possess, and Thoughtsteal.
        Toggle Nightvision is self-explanatory.
        Discordant Whisper is identical to the original revenant's transmit.
        Possess allows the umbra to slip into a human's body unnoticed. While in their body, umbras will slowly drain vitae from the human at a tiny rate - not enough to cause harm, but enough to induce adverse effects in the clueless human. These effects intensify over time and eventually lead to the umbra being forced out of their host.
        Thoughtsteal paralyzes a living human for several seconds while the umbra steals their memories. After several seconds, the umbra copies the notes of the target's memories and turns invisible - the hapless victim is stunned for several seconds afterwards and can't be Thoughtstolen by the same umbra again. Umbras have an objective to steal the memories of 25% of the station's population.
    Salt piles have been added, created by salt shaker or just by splashing salt. These piles will prevent an umbra from passing and reveal them briefly if they try.
2016-06-17 10:58:07 +12:00

312 lines
6.9 KiB
Plaintext

/mob/CanPass(atom/movable/mover, turf/target, height=0)
if(height==0)
return 1
if(istype(mover, /obj/item/projectile) || mover.throwing)
return (!density || lying)
if(mover.checkpass(PASSMOB))
return 1
if(buckled == mover)
return 1
if(ismob(mover))
if (mover in buckled_mobs)
return 1
return (!mover.density || !density || lying)
/client/Northeast()
swap_hand()
return
/client/Southeast()
attack_self()
return
/client/Southwest()
if(iscarbon(usr))
var/mob/living/carbon/C = usr
C.toggle_throw_mode()
else
usr << "<span class='danger'>This mob type cannot throw items.</span>"
return
/client/Northwest()
if(!usr.get_active_hand())
usr << "<span class='warning'>You have nothing to drop in your hand!</span>"
return
usr.drop_item()
//This gets called when you press the delete button.
/client/verb/delete_key_pressed()
set hidden = 1
if(!usr.pulling)
usr << "<span class='notice'>You are not pulling anything.</span>"
return
usr.stop_pulling()
/client/verb/swap_hand()
set category = "IC"
set name = "Swap hands"
if(mob)
mob.swap_hand()
/client/verb/attack_self()
set hidden = 1
if(mob)
mob.mode()
return
/client/verb/drop_item()
set hidden = 1
if(!isrobot(mob))
mob.drop_item_v()
return
/client/Center()
if(isobj(mob.loc))
var/obj/O = mob.loc
if(mob.canmove)
return O.relaymove(mob, 0)
return
/client/proc/Move_object(direct)
if(mob && mob.control_object)
if(mob.control_object.density)
step(mob.control_object,direct)
if(!mob.control_object)
return
mob.control_object.setDir(direct)
else
mob.control_object.loc = get_step(mob.control_object,direct)
return
/client/Move(n, direct)
if(!mob || !mob.loc)
return 0
if(mob.notransform)
return 0 //This is sota the goto stop mobs from moving var
if(mob.control_object)
return Move_object(direct)
if(world.time < move_delay)
return 0
if(!isliving(mob))
return mob.Move(n,direct)
if(mob.stat == DEAD)
mob.ghostize()
return 0
if(moving)
return 0
if(isliving(mob))
var/mob/living/L = mob
if(L.incorporeal_move) //Move though walls
Process_Incorpmove(direct)
return 0
if(mob.remote_control) //we're controlling something, our movement is relayed to it
return mob.remote_control.relaymove(mob, direct)
if(isAI(mob))
return AIMove(n,direct,mob)
if(Process_Grab()) //are we restrained by someone's grip?
return
if(mob.buckled) //if we're buckled to something, tell it we moved.
return mob.buckled.relaymove(mob, direct)
if(!mob.canmove)
return 0
if(isobj(mob.loc) || ismob(mob.loc)) //Inside an object, tell it we moved
var/atom/O = mob.loc
return O.relaymove(mob, direct)
if(!mob.Process_Spacemove(direct))
return 0
//We are now going to move
moving = 1
move_delay = mob.movement_delay() + world.time
if(mob.confused)
if(mob.confused > 40)
step(mob, pick(cardinal))
else if(prob(mob.confused * 1.5))
step(mob, angle2dir(dir2angle(direct) + pick(90, -90)))
else if(prob(mob.confused * 3))
step(mob, angle2dir(dir2angle(direct) + pick(45, -45)))
else
step(mob, direct)
else
. = ..()
moving = 0
if(mob && .)
mob.throwing = 0
return .
///Process_Grab()
///Called by client/Move()
///Checks to see if you are being grabbed and if so attemps to break it
/client/proc/Process_Grab()
if(mob.pulledby)
if(mob.incapacitated(ignore_restraints = 1))
move_delay = world.time + 10
return 1
else if(mob.restrained(ignore_grab = 1))
move_delay = world.time + 10
src << "<span class='warning'>You're restrained! You can't move!</span>"
return 1
else
return mob.resist_grab(1)
///Process_Incorpmove
///Called by client/Move()
///Allows mobs to run though walls
/client/proc/Process_Incorpmove(direct)
var/turf/mobloc = get_turf(mob)
if(!isliving(mob))
return
var/mob/living/L = mob
switch(L.incorporeal_move)
if(1)
L.loc = get_step(L, direct)
L.setDir(direct)
if(2)
if(prob(50))
var/locx
var/locy
switch(direct)
if(NORTH)
locx = mobloc.x
locy = (mobloc.y+2)
if(locy>world.maxy)
return
if(SOUTH)
locx = mobloc.x
locy = (mobloc.y-2)
if(locy<1)
return
if(EAST)
locy = mobloc.y
locx = (mobloc.x+2)
if(locx>world.maxx)
return
if(WEST)
locy = mobloc.y
locx = (mobloc.x-2)
if(locx<1)
return
else
return
L.loc = locate(locx,locy,mobloc.z)
var/limit = 2//For only two trailing shadows.
for(var/turf/T in getline(mobloc, L.loc))
spawn(0)
anim(T,L,'icons/mob/mob.dmi',,"shadow",,L.dir)
limit--
if(limit<=0)
break
else
spawn(0)
anim(mobloc,mob,'icons/mob/mob.dmi',,"shadow",,L.dir)
L.loc = get_step(L, direct)
L.setDir(direct)
if(3) //Incorporeal move, but blocked by holy-watered tiles and salt piles. Used by umbras.
if(!isumbra(L))
L.incorporeal_move = 1
return
var/mob/living/simple_animal/umbra/U = L
var/turf/open/floor/stepTurf = get_step(L, direct)
for(var/obj/effect/decal/cleanable/salt/S in stepTurf)
U << "<span class='warning'>[S] bars your passage!</span>"
U.reveal(2, TRUE)
U.immobilize(2, TRUE)
return
if(stepTurf.flags & NOJAUNT)
U << "<span class='warning'>Holy energies block your path!</span>"
U.immobilize(2, TRUE)
else
U.loc = get_step(L, direct)
U.setDir(direct)
return 1
///Process_Spacemove
///Called by /client/Move()
///For moving in space
///Return 1 for movement 0 for none
/mob/Process_Spacemove(movement_dir = 0)
if(..())
return 1
var/atom/movable/backup = get_spacemove_backup()
if(backup)
if(istype(backup) && movement_dir && !backup.anchored)
if(backup.newtonian_move(turn(movement_dir, 180))) //You're pushing off something movable, so it moves
src << "<span class='info'>You push off of [backup] to propel yourself.</span>"
return 1
return 0
/mob/get_spacemove_backup()
var/atom/movable/dense_object_backup
for(var/A in orange(1, get_turf(src)))
if(isarea(A))
continue
else if(isturf(A))
var/turf/turf = A
if(istype(turf,/turf/open/space))
continue
if(!turf.density && !mob_negates_gravity())
continue
return A
else
var/atom/movable/AM = A
if(AM == buckled) //Kind of unnecessary but let's just be sure
continue
if(!AM.CanPass(src) || AM.density)
if(AM.anchored)
return AM
if(pulling == AM)
continue
dense_object_backup = AM
break
. = dense_object_backup
/mob/proc/mob_has_gravity(turf/T)
return has_gravity(src, T)
/mob/proc/mob_negates_gravity()
return 0
//moves the mob/object we're pulling
/mob/proc/Move_Pulled(atom/A)
if (!pulling)
return
if (pulling.anchored || !pulling.Adjacent(src))
stop_pulling()
return
if (A == loc && pulling.density)
return
if (!Process_Spacemove(get_dir(pulling.loc, A)))
return
step(pulling, get_dir(pulling.loc, A))
/mob/proc/slip(s_amount, w_amount, obj/O, lube)
return
/mob/proc/update_gravity()
return