-tg- Move Refactor

This commit ports /tg/'s move refactor.

The throwing system has been replaced entirely, removing the necessity
of throw_at_fast and resolving multiple outstanding issues, such as
crossbows being unusable.

Spacedrifting has also been upgraded to function with the new throwing
system. It is now it's own process.

Tickcomp has been killed, and the config values have been adjusted to
more or less match live Paradise.

All mobs now share a common Bump() proc. There are only four mobtypes
which do not, including humans and simple animals. With the exception
of mob types that do not ever want to Bump() or be Bumped(), they should
call the parent proc.

Human movement slowdown has been moderately tweaked in how it stacks effects;
It shouldn't be significantly different from a player perspective.

Mobs will now spread fire if they bump into another mob. I don't want to set
the world on fiiiire, I just want start a flame in your heart~

For player facing changes: Input delay has been reduced by roughly ~50ms for
any direction keys, by advantage of a previously unknown flag on byond verbs
which allow them to operate independently from the tick rate of the server.
You may need to clear your interface.dmf file if you have a custom skin for
this change to function.
This commit is contained in:
Tigercat2000
2017-05-16 21:30:38 -07:00
parent 9448a4d5b8
commit bbca8405ef
69 changed files with 1126 additions and 1191 deletions
+2
View File
@@ -0,0 +1,2 @@
#define CALLBACK new /datum/callback
#define INVOKE_ASYNC ImmediateInvokeAsync
+3
View File
@@ -70,3 +70,6 @@
#define WEAPON_LIGHT 0
#define WEAPON_MEDIUM 1
#define WEAPON_HEAVY 2
// Embedded objects
#define EMBED_THROWSPEED_THRESHOLD 15
+6 -5
View File
@@ -77,11 +77,12 @@
#define SAFE 16
//flags for pass_flags
#define PASSTABLE 1
#define PASSGLASS 2
#define PASSGRILLE 4
#define PASSBLOB 8
#define PASSMOB 16
#define PASSTABLE 1
#define PASSGLASS 2
#define PASSGRILLE 4
#define PASSBLOB 8
#define PASSMOB 16
#define LETPASSTHROW 32
//turf-only flags
#define NOJAUNT 1
+4 -1
View File
@@ -329,4 +329,7 @@
#define TENDRIL_CLEAR_SCORE "Tendrils Killed"
// The number of station goals generated each round.
#define STATION_GOAL_BUDGET 1
#define STATION_GOAL_BUDGET 1
#define FIRST_DIAG_STEP 1
#define SECOND_DIAG_STEP 2
+1 -1
View File
@@ -47,7 +47,7 @@
#define HUMAN_STRIP_DELAY 40 //takes 40ds = 4s to strip someone.
#define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien.
#define SHOES_SLOWDOWN -1.0 // How much shoes slow you down by default. Negative values speed you up
#define SHOES_SLOWDOWN 0 // How much shoes slow you down by default. Negative values speed you up
//Mob attribute defaults.
+6 -14
View File
@@ -23,7 +23,7 @@
* If you are in the same turf, always true
* If you are vertically/horizontally adjacent, ensure there are no border objects
* If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square.
* Passing through in this case ignores anything with the throwpass flag, such as tables, racks, and morgue trays.
* Passing through in this case ignores anything with the LETPASSTHROW flag, such as tables, racks, and morgue trays.
*/
/turf/Adjacent(var/atom/neighbor, var/atom/target = null)
var/turf/T0 = get_turf(neighbor)
@@ -82,26 +82,18 @@
/*
This checks if you there is uninterrupted airspace between that turf and this one.
This is defined as any dense ON_BORDER object, or any dense object without throwpass.
This is defined as any dense ON_BORDER object, or any dense object without LETPASSTHROW.
The border_only flag allows you to not objects (for source and destination squares)
*/
/turf/proc/ClickCross(var/target_dir, var/border_only, var/target_atom = null)
for(var/obj/O in src)
if( !O.density || O == target_atom || O.throwpass) continue // throwpass is used for anything you can click through
if( !O.density || O == target_atom || (O.pass_flags & LETPASSTHROW))
continue // LETPASSTHROW is used for anything you can click through
if( O.flags&ON_BORDER) // windows have throwpass but are on border, check them first
if( O.flags&ON_BORDER) // windows are on border, check them first
if( O.dir & target_dir || O.dir&(O.dir-1) ) // full tile windows are just diagonals mechanically
return 0
else if( !border_only ) // dense, not on border, cannot pass over
return 0
return 1
/*
Aside: throwpass does not do what I thought it did originally, and is only used for checking whether or not
a thrown object should stop after already successfully entering a square. Currently the throw code involved
only seems to affect hitting mobs, because the checks performed against objects are already performed when
entering or leaving the square. Since throwpass isn't used on mobs, but only on objects, it is effectively
useless. Throwpass may later need to be removed and replaced with a passcheck (bitfield on movable atom passflags).
Since I don't want to complicate the click code rework by messing with unrelated systems it won't be changed here.
*/
return 1
+53
View File
@@ -0,0 +1,53 @@
var/global/datum/controller/process/spacedrift/drift_master
/datum/controller/process/spacedrift
var/list/processing_list = list()
/datum/controller/process/spacedrift/setup()
name = "spacedrift"
schedule_interval = 5
start_delay = 20
log_startup_progress("Spacedrift starting up.")
/datum/controller/process/spacedrift/statProcess()
..()
stat(null, "P:[processing_list.len]")
/datum/controller/process/spacedrift/doWork()
var/list/currentrun = processing_list.Copy()
while(currentrun.len)
var/atom/movable/AM = currentrun[currentrun.len]
currentrun.len--
if(!AM)
processing_list -= AM
SCHECK
continue
if(AM.inertia_next_move > world.time)
SCHECK
continue
if(!AM.loc || AM.loc != AM.inertia_last_loc || AM.Process_Spacemove(0))
AM.inertia_dir = 0
if(!AM.inertia_dir)
AM.inertia_last_loc = null
processing_list -= AM
SCHECK
continue
var/old_dir = AM.dir
var/old_loc = AM.loc
AM.inertia_moving = TRUE
step(AM, AM.inertia_dir)
AM.inertia_moving = FALSE
AM.inertia_next_move = world.time + AM.inertia_move_delay
if(AM.loc == old_loc)
AM.inertia_dir = 0
AM.setDir(old_dir)
AM.inertia_last_loc = AM.loc
SCHECK
DECLARE_GLOBAL_CONTROLLER(spacedrift, drift_master)
+138
View File
@@ -0,0 +1,138 @@
#define MAX_THROWING_DIST 512 // 2 z-levels on default width
#define MAX_TICKS_TO_MAKE_UP 3 //how many missed ticks will we attempt to make up for this run.
var/global/datum/controller/process/throwing/throw_master
/datum/controller/process/throwing
var/list/processing_list
/datum/controller/process/throwing/setup()
name = "throwing"
schedule_interval = 1
start_delay = 20
log_startup_progress("Throw ticker starting up.")
/datum/controller/process/throwing/statProcess()
..()
stat(null, "P:[processing_list.len]")
/datum/controller/process/throwing/started()
..()
if(!processing_list)
processing_list = list()
/datum/controller/process/throwing/doWork()
for(last_object in processing_list)
var/atom/movable/AM = last_object
if(istype(AM) && isnull(AM.gcDestroyed))
var/datum/thrownthing/TT = processing_list[AM]
if(istype(TT) && isnull(TT.gcDestroyed))
TT.tick()
SCHECK
else
catchBadType(TT)
processing_list -= AM
AM.throwing = null
else
catchBadType(AM)
processing_list -= AM
SCHECK
DECLARE_GLOBAL_CONTROLLER(throwing, throw_master)
/datum/thrownthing
var/atom/movable/thrownthing
var/atom/target
var/turf/target_turf
var/init_dir
var/maxrange
var/speed
var/mob/thrower
var/diagonals_first
var/dist_travelled = 0
var/start_time
var/dist_x
var/dist_y
var/dx
var/dy
var/pure_diagonal
var/diagonal_error
var/datum/callback/callback
/datum/thrownthing/proc/tick()
var/atom/movable/AM = thrownthing
if(!isturf(AM.loc) || !AM.throwing)
finalize()
return
if(dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept
finalize()
return
var/atom/step
// calculate how many tiles to move, making up for any missed ticks.
if((dist_travelled >= maxrange || AM.loc == target_turf) && has_gravity(AM, AM.loc))
finalize()
return
if(dist_travelled <= max(dist_x, dist_y)) //if we haven't reached the target yet we home in on it, otherwise we use the initial direction
step = get_step(AM, get_dir(AM, target_turf))
else
step = get_step(AM, init_dir)
if(!pure_diagonal && !diagonals_first) // not a purely diagonal trajectory and we don't want all diagonal moves to be done first
if(diagonal_error >= 0 && max(dist_x, dist_y) - dist_travelled != 1) // we do a step forward unless we're right before the target
step = get_step(AM, dx)
diagonal_error += (diagonal_error < 0) ? dist_x / 2 : -dist_y
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
finalize()
return
AM.Move(step, get_dir(AM, step))
if(!AM.throwing) // we hit something during our move
finalize(hit = TRUE)
return
dist_travelled++
if(dist_travelled > MAX_THROWING_DIST)
finalize()
return
/datum/thrownthing/proc/finalize(hit = FALSE)
set waitfor = 0
throw_master.processing_list -= thrownthing
// done throwning, either because it hit something or it finished moving
thrownthing.throwing = null
if(!hit)
for(var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on.
var/atom/A = thing
if(A == target)
hit = 1
thrownthing.throw_impact(A, src)
break
if(!hit)
thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground.
thrownthing.newtonian_move(init_dir)
else
thrownthing.newtonian_move(init_dir)
if(callback)
callback.Invoke()
/datum/thrownthing/proc/hit_atom(atom/A)
thrownthing.throw_impact(A, src)
thrownthing.newtonian_move(init_dir)
finalize(TRUE)
/datum/thrownthing/proc/hitcheck()
for(var/thing in get_turf(thrownthing))
var/atom/movable/AM = thing
if(AM == thrownthing)
continue
if(AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags & ON_BORDER))
thrownthing.throwing = null
thrownthing.throw_impact(AM, src)
return TRUE
-4
View File
@@ -39,7 +39,6 @@
var/allow_Metadata = 0 // Metadata is supported.
var/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1.
var/Ticklag = 0.5
var/Tickcomp = 0
var/socket_talk = 0 // use socket_talk to communicate with other processes
var/list/resource_urls = null
var/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round.
@@ -445,9 +444,6 @@
if("socket_talk")
socket_talk = text2num(value)
if("tickcomp")
Tickcomp = 1
if("allow_antag_hud")
config.antag_hud_allowed = 1
+98
View File
@@ -0,0 +1,98 @@
/*
USAGE:
var/datum/callback/C = new(object|null, /proc/type/path|"procstring", arg1, arg2, ... argn)
var/timerid = addtimer(C, time, timertype)
OR
var/timerid = addtimer(CALLBACK(object|null, /proc/type/path|procstring, arg1, arg2, ... argn), time, timertype)
Note: proc strings can only be given for datum proc calls, global procs must be proc paths
Also proc strings are strongly advised against because they don't compile error if the proc stops existing
See the note on proc typepath shortcuts
INVOKING THE CALLBACK:
var/result = C.Invoke(args, to, add) //additional args are added after the ones given when the callback was created
OR
var/result = C.InvokeAsync(args, to, add) //Sleeps will not block, returns . on the first sleep (then continues on in the "background" after the sleep/block ends), otherwise operates normally.
OR
INVOKE_ASYNC(<CALLBACK args>) to immediately create and call InvokeAsync
PROC TYPEPATH SHORTCUTS (these operate on paths, not types, so to these shortcuts, datum is NOT a parent of atom, etc...)
global proc while in another global proc:
.procname
Example:
CALLBACK(GLOBAL_PROC, .some_proc_here)
proc defined on current(src) object (when in a /proc/ and not an override) OR overridden at src or any of it's parents:
.procname
Example:
CALLBACK(src, .some_proc_here)
when the above doesn't apply:
.proc/procname
Example:
CALLBACK(src, .proc/some_proc_here)
proc defined on a parent of a some type:
/some/type/.proc/some_proc_here
Other wise you will have to do the full typepath of the proc (/type/of/thing/proc/procname)
*/
/datum/callback
var/datum/object = GLOBAL_PROC
var/delegate
var/list/arguments
/datum/callback/New(thingtocall, proctocall, ...)
if(thingtocall)
object = thingtocall
delegate = proctocall
if(length(args) > 2)
arguments = args.Copy(3)
/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...)
set waitfor = FALSE
if(!thingtocall)
return
var/list/calling_arguments = length(args) > 2 ? args.Copy(3) : null
if(thingtocall == GLOBAL_PROC)
call(proctocall)(arglist(calling_arguments))
else
call(thingtocall, proctocall)(arglist(calling_arguments))
/datum/callback/proc/Invoke(...)
if(!object)
return
var/list/calling_arguments = arguments
if(length(args))
if(length(arguments))
calling_arguments = calling_arguments + args //not += so that it creates a new list so the arguments list stays clean
else
calling_arguments = args
if(object == GLOBAL_PROC)
return call(delegate)(arglist(calling_arguments))
return call(object, delegate)(arglist(calling_arguments))
//copy and pasted because fuck proc overhead
/datum/callback/proc/InvokeAsync(...)
set waitfor = FALSE
if(!object)
return
var/list/calling_arguments = arguments
if(length(args))
if(length(arguments))
calling_arguments = calling_arguments + args //not += so that it creates a new list so the arguments list stays clean
else
calling_arguments = args
if(object == GLOBAL_PROC)
return call(delegate)(arglist(calling_arguments))
return call(object, delegate)(arglist(calling_arguments))
+7 -5
View File
@@ -9,7 +9,6 @@
var/blood_color
var/last_bumped = 0
var/pass_flags = 0
var/throwpass = 0
var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom.
var/simulated = 1 //filter for actions - used by lighting overlays
var/atom_say_verb = "says"
@@ -236,10 +235,13 @@
/atom/proc/emag_act()
return
/atom/proc/hitby(atom/movable/AM as mob|obj)
if(density)
AM.throwing = 0
return
/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...).
addtimer(src, "hitby_react", 2, TRUE, AM)
/atom/proc/hitby_react(atom/movable/AM)
if(AM && isturf(AM.loc))
step(AM, turn(AM.dir, 180))
/atom/proc/add_hiddenprint(mob/living/M as mob)
if(isnull(M)) return
+117 -145
View File
@@ -6,15 +6,21 @@
// var/elevation = 2 - not used anywhere
var/move_speed = 10
var/l_move_time = 1
var/throwing = 0
var/thrower
var/turf/throw_source = null
var/throw_speed = 2
var/datum/thrownthing/throwing = null
var/throw_speed = 2 //How many tiles to move per ds when being thrown. Float values are fully supported
var/throw_range = 7
var/no_spin_thrown = 0 //set this to 1 if you don't want an item that you throw to spin, no matter what. -Fox
var/no_spin = 0
var/no_spin_thrown = 0
var/moved_recently = 0
var/mob/pulledby = null
var/inertia_dir = 0
var/atom/inertia_last_loc
var/inertia_moving = 0
var/inertia_next_move = 0
var/inertia_move_delay = 5
var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move
var/area/areaMaster
@@ -71,61 +77,74 @@
if(!(direct & (direct - 1))) //Cardinal move
. = ..()
else //Diagonal move, split it into cardinal moves
moving_diagonally = FIRST_DIAG_STEP
if(direct & 1)
if(direct & 4)
if(step(src, NORTH))
moving_diagonally = SECOND_DIAG_STEP
. = step(src, EAST)
else if(step(src, EAST))
moving_diagonally = SECOND_DIAG_STEP
. = step(src, NORTH)
else if(direct & 8)
if(step(src, NORTH))
moving_diagonally = SECOND_DIAG_STEP
. = step(src, WEST)
else if(step(src, WEST))
moving_diagonally = SECOND_DIAG_STEP
. = step(src, NORTH)
else if(direct & 2)
if(direct & 4)
if(step(src, SOUTH))
moving_diagonally = SECOND_DIAG_STEP
. = step(src, EAST)
else if(step(src, EAST))
moving_diagonally = SECOND_DIAG_STEP
. = step(src, SOUTH)
else if(direct & 8)
if(step(src, SOUTH))
moving_diagonally = SECOND_DIAG_STEP
. = step(src, WEST)
else if(step(src, WEST))
moving_diagonally = SECOND_DIAG_STEP
. = step(src, SOUTH)
moving_diagonally = 0
return
if(!loc || (loc == oldloc && oldloc != newloc))
last_move = 0
return
if(.)
Moved(oldloc, direct)
last_move = direct
src.move_speed = world.time - src.l_move_time
src.l_move_time = world.time
spawn(5) // Causes space drifting. /tg/station has no concept of speed, we just use 5
if(loc && direct && last_move == direct)
if(loc == newloc) //Remove this check and people can accelerate. Not opening that can of worms just yet.
newtonian_move(last_move)
if(. && buckled_mob && !handle_buckled_mob_movement(loc, direct)) //movement failed due to buckled mob
. = 0
// Called after a successful Move(). By this point, we've already moved
/atom/movable/proc/Moved(atom/OldLoc, Dir)
if(!inertia_moving)
inertia_next_move = world.time + inertia_move_delay
newtonian_move(Dir)
return 1
// Previously known as Crossed()
// Previously known as HasEntered()
// This is automatically called when something enters your square
/atom/movable/Crossed(atom/movable/AM)
return
/atom/movable/Bump(var/atom/A as mob|obj|turf|area, sendBump)
if(src.throwing)
src.throw_impact(A)
if(A && sendBump)
A.last_bumped = world.time
/atom/movable/Bump(atom/A, yes) //the "yes" arg is to differentiate our Bump proc from byond's, without it every Bump() call would become a double Bump().
if(A && yes)
if(throwing)
throwing.hit_atom(A)
. = 1
if(!A || qdeleted(A))
return
A.Bumped(src)
else
..()
/atom/movable/proc/forceMove(atom/destination)
var/turf/old_loc = loc
@@ -166,29 +185,6 @@
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
//called when src is thrown into hit_atom
/atom/movable/proc/throw_impact(atom/hit_atom, var/speed)
if(istype(hit_atom,/mob/living))
var/mob/living/M = hit_atom
M.hitby(src,speed)
else if(isobj(hit_atom))
var/obj/O = hit_atom
if(!O.anchored)
step(O, src.dir)
O.hitby(src,speed)
else if(isturf(hit_atom))
src.throwing = 0
var/turf/T = hit_atom
if(T.density)
spawn(2)
step(src, turn(src.dir, 180))
if(istype(src,/mob/living))
var/mob/living/M = src
M.turf_collision(T, speed)
//Called whenever an object moves and by mobs when they attempt to move themselves through space
//And when an object or action applies a force on src, see newtonian_move() below
//Return 0 to have src start/keep drifting in a no-grav area and 1 to stop/not start drifting
@@ -201,13 +197,15 @@
if(pulledby && !pulledby.pulling)
return 1
if(throwing)
return 1
if(locate(/obj/structure/lattice) in range(1, get_turf(src))) //Not realistic but makes pushing things in space easier
return 1
return 0
/atom/movable/proc/newtonian_move(direction) //Only moves the object if it's under no gravity
if(!loc || Process_Spacemove(0))
inertia_dir = 0
return 0
@@ -216,119 +214,93 @@
if(!direction)
return 1
var/old_dir = dir
. = step(src, direction)
dir = old_dir
inertia_last_loc = loc
drift_master.processing_list[src] = src
return 1
//decided whether a movable atom being thrown can pass through the turf it is in.
/atom/movable/proc/hit_check(var/speed)
if(src.throwing)
for(var/atom/A in get_turf(src))
if(A == src) continue
if(istype(A,/mob/living))
if(A:lying) continue
src.throw_impact(A,speed)
if(isobj(A))
if(A.density && !A.throwpass) // **TODO: Better behaviour for windows which are dense, but shouldn't always stop movement
src.throw_impact(A,speed)
/atom/movable/proc/throw_at_fast(atom/target, range, speed, thrower, no_spin)
//called when src is thrown into hit_atom
/atom/movable/proc/throw_impact(atom/hit_atom, throwingdatum)
set waitfor = 0
throw_at(target, range, speed, thrower, no_spin)
return hit_atom.hitby(src)
/atom/movable/proc/throw_at(atom/target, range, speed, thrower, no_spin)
if(!target || !src || (flags & NODROP))
/atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked)
if(!anchored && hitpush)
step(src, AM.dir)
..()
/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, var/datum/callback/callback)
if(!target || (flags & NODROP) || speed <= 0)
return 0
//use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target
src.throwing = 1
src.thrower = thrower
src.throw_source = get_turf(src) //store the origin turf
if(target.allow_spin) // turns out 1000+ spinning objects being thrown at the singularity creates lag - Iamgoofball
if(!no_spin_thrown && !no_spin)
SpinAnimation(5, 1)
if(pulledby)
pulledby.stop_pulling()
// They are moving! Wouldn't it be cool if we calculated their momentum and added it to the throw?
if(thrower && thrower.last_move && thrower.client && thrower.client.move_delay >= world.time + world.tick_lag * 2)
var/user_momentum = thrower.movement_delay()
if(!user_momentum) // no movement_delay, this means they move once per byond tick, let's calculate from that instead
user_momentum = world.tick_lag
user_momentum = 1 / user_momentum // convert from ds to the tiles per ds that throw_at uses
if(get_dir(thrower, target) & last_move)
user_momentum = user_momentum // basically a noop, but needed
else if(get_dir(target, thrower) & last_move)
user_momentum = -user_momentum // we are moving away from the target, lets slowdown the throw accordingly
else
user_momentum = 0
if(user_momentum)
// first lets add that momentum to range
range *= (user_momentum / speed) + 1
//then lets add it to speed
speed += user_momentum
if(speed <= 0)
return //no throw speed, the user was moving too fast.
var/datum/thrownthing/TT = new()
TT.thrownthing = src
TT.target = target
TT.target_turf = get_turf(target)
TT.init_dir = get_dir(src, target)
TT.maxrange = range
TT.speed = speed
TT.thrower = thrower
TT.diagonals_first = diagonals_first
TT.callback = callback
var/dist_x = abs(target.x - src.x)
var/dist_y = abs(target.y - src.y)
var/dx = (target.x > src.x) ? EAST : WEST
var/dy = (target.y > src.y) ? NORTH : SOUTH
var/dx
if(target.x > src.x)
dx = EAST
else
dx = WEST
if(dist_x == dist_y)
TT.pure_diagonal = 1
var/dy
if(target.y > src.y)
dy = NORTH
else
dy = SOUTH
var/dist_travelled = 0
var/dist_since_sleep = 0
var/area/a = get_area(src.loc)
if(dist_x > dist_y)
var/error = dist_x/2 - dist_y
while(src && target &&((((src.x < target.x && dx == EAST) || (src.x > target.x && dx == WEST)) && dist_travelled < range) || (a && a.has_gravity == 0) || istype(src.loc, /turf/space)) && src.throwing && istype(src.loc, /turf))
// only stop when we've gone the whole distance (or max throw range) and are on a non-space tile, or hit something, or hit the end of the map, or someone picks it up
if(error < 0)
var/atom/step = get_step(src, dy)
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
break
src.Move(step, get_dir(loc, step))
hit_check(speed)
error += dist_x
dist_travelled++
dist_since_sleep++
if(dist_since_sleep >= speed)
dist_since_sleep = 0
sleep(1)
else
var/atom/step = get_step(src, dx)
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
break
src.Move(step)
hit_check(speed)
error -= dist_y
dist_travelled++
dist_since_sleep++
if(dist_since_sleep >= speed)
dist_since_sleep = 0
sleep(1)
a = get_area(src.loc)
else
var/error = dist_y/2 - dist_x
while(src && target &&((((src.y < target.y && dy == NORTH) || (src.y > target.y && dy == SOUTH)) && dist_travelled < range) || (a && a.has_gravity == 0) || istype(src.loc, /turf/space)) && src.throwing && istype(src.loc, /turf))
// only stop when we've gone the whole distance (or max throw range) and are on a non-space tile, or hit something, or hit the end of the map, or someone picks it up
if(error < 0)
var/atom/step = get_step(src, dx)
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
break
src.Move(step)
hit_check(speed)
error += dist_y
dist_travelled++
dist_since_sleep++
if(dist_since_sleep >= speed)
dist_since_sleep = 0
sleep(1)
else
var/atom/step = get_step(src, dy)
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
break
src.Move(step)
hit_check(speed)
error -= dist_x
dist_travelled++
dist_since_sleep++
if(dist_since_sleep >= speed)
dist_since_sleep = 0
sleep(1)
else if(dist_x <= dist_y)
var/olddist_x = dist_x
var/olddx = dx
dist_x = dist_y
dist_y = olddist_x
dx = dy
dy = olddx
TT.dist_x = dist_x
TT.dist_y = dist_y
TT.dx = dx
TT.dy = dy
TT.diagonal_error = dist_x / 2 - dist_y
TT.start_time = world.time
a = get_area(src.loc)
if(pulledby)
pulledby.stop_pulling()
//done throwing, either because it hit something or it finished moving
if(isobj(src)) src.throw_impact(get_turf(src),speed)
src.throwing = 0
src.thrower = null
src.throw_source = null
throwing = TT
if(spin && !no_spin && !no_spin_thrown)
SpinAnimation(5, 1)
throw_master.processing_list[src] = TT
TT.tick()
//Overlays
@@ -498,7 +498,7 @@
icon_state = "hoop"
anchored = 1
density = 1
throwpass = 1
pass_flags = LETPASSTHROW
/obj/structure/holohoop/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
if(istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2)
+4 -6
View File
@@ -167,18 +167,16 @@
..()
//When an object is thrown at the window
/obj/machinery/door/window/hitby(AM as mob|obj)
/obj/machinery/door/window/hitby(atom/movable/AM)
..()
var/tforce = 0
if(ismob(AM))
tforce = 40
else
tforce = AM:throwforce
else if(isobj(AM))
var/obj/O = AM
tforce = O.throwforce
playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
take_damage(tforce)
//..() //Does this really need to be here twice? The parent proc doesn't even do anything yet. - Nodrak
return
/obj/machinery/door/window/mech_melee_attack(obj/mecha/M)
if(M.damtype == "brute")
+26 -28
View File
@@ -94,51 +94,49 @@
/obj/machinery/shield/hitby(AM as mob|obj)
//Super realistic, resource-intensive, real-time damage calculations.
..()
var/tforce = 0
if(ismob(AM))
tforce = 40
else
tforce = AM:throwforce
else if(isobj(AM))
var/obj/O = AM
tforce = O.throwforce
src.health -= tforce
health -= tforce
//This seemed to be the best sound for hitting a force field.
playsound(src.loc, 'sound/effects/EMPulse.ogg', 100, 1)
playsound(loc, 'sound/effects/EMPulse.ogg', 100, 1)
//Handle the destruction of the shield
if(src.health <= 0)
if(health <= 0)
visible_message("<span class='notice'>The [src] dissipates</span>")
qdel(src)
return
//The shield becomes dense to absorb the blow.. purely asthetic.
opacity = 1
spawn(20) if(src) opacity = 0
..()
return
spawn(20)
if(src)
opacity = 0
/obj/machinery/shieldgen
name = "Emergency shield projector"
desc = "Used to seal minor hull breaches."
icon = 'icons/obj/objects.dmi'
icon_state = "shieldoff"
density = 1
opacity = 0
anchored = 0
pressure_resistance = 2*ONE_ATMOSPHERE
req_access = list(access_engine)
var/const/max_health = 100
var/health = max_health
var/active = 0
var/malfunction = 0 //Malfunction causes parts of the shield to slowly dissapate
var/list/deployed_shields = list()
var/is_open = 0 //Whether or not the wires are exposed
var/locked = 0
name = "Emergency shield projector"
desc = "Used to seal minor hull breaches."
icon = 'icons/obj/objects.dmi'
icon_state = "shieldoff"
density = 1
opacity = 0
anchored = 0
pressure_resistance = 2*ONE_ATMOSPHERE
req_access = list(access_engine)
var/const/max_health = 100
var/health = max_health
var/active = 0
var/malfunction = 0 //Malfunction causes parts of the shield to slowly dissapate
var/list/deployed_shields = list()
var/is_open = 0 //Whether or not the wires are exposed
var/locked = 0
/obj/machinery/shieldgen/Destroy()
QDEL_LIST(deployed_shields)
+6 -2
View File
@@ -368,9 +368,12 @@
breakthrough = 1
else
throwing = 0 //so mechas don't get stuck when landing after being sent by a Mass Driver
if(throwing)
throwing.finalize(FALSE)
crashing = null
..()
if(breakthrough)
if(crashing)
spawn(1)
@@ -524,7 +527,7 @@
user.create_attack_log("<font color='red'>attacked [name]</font>")
return
/obj/mecha/hitby(atom/movable/A as mob|obj) //wrapper
/obj/mecha/hitby(atom/movable/A) //wrapper
..()
log_message("Hit by [A].",1)
@@ -537,6 +540,7 @@
dam_coeff = B.damage_coeff
counter_tracking = 1
break
if(istype(A, /obj/item/mecha_parts/mecha_tracking))
if(!counter_tracking)
A.forceMove(src)
+2 -2
View File
@@ -104,9 +104,9 @@
/obj/structure/alien/resin/hitby(atom/movable/AM)
..()
var/tforce = 0
if(!isobj(AM))
if(ismob(AM))
tforce = 10
else
else if(isobj(AM))
var/obj/O = AM
tforce = O.throwforce
playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
@@ -67,7 +67,7 @@
/obj/item/clothing/gloves/color/black = 20,
/obj/item/clothing/head/hardhat = 10,
/obj/item/clothing/head/hardhat/red = 10,
/obj/item/clothing/head/that{throwforce = 1; throwing = 1} = 10,
/obj/item/clothing/head/that = 10,
/obj/item/clothing/head/ushanka = 10,
/obj/item/clothing/head/welding = 10,
/obj/item/clothing/mask/gas = 10,
+21 -34
View File
@@ -61,6 +61,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
var/block_chance = 0
var/hit_reaction_chance = 0 //If you want to have something unrelated to blocking/armour piercing etc. Maybe not needed, but trying to think ahead/allow more freedom
var/mob/thrownby = null
var/toolspeed = 1 // If this item is a tool, the speed multiplier
/* Species-specific sprites, concept stolen from Paradise//vg/.
@@ -217,7 +219,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
var/obj/item/weapon/storage/S = src.loc
S.remove_from_storage(src)
src.throwing = 0
if(throwing)
throwing.finalize(FALSE)
if(loc == user)
if(!user.unEquip(src))
return 0
@@ -231,36 +234,6 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
user.put_in_active_hand(src)
return 1
/obj/item/attack_alien(mob/user as mob)
if(isalien(user)) // -- TLE
var/mob/living/carbon/alien/A = user
if(!A.has_fine_manipulation)
if(src in A.contents) // To stop Aliens having items stuck in their pockets
A.unEquip(src)
to_chat(user, "Your claws aren't capable of such fine manipulation.")
return
if(istype(src.loc, /obj/item/weapon/storage))
for(var/mob/M in range(1, src.loc))
if(M.s_active == src.loc)
if(M.client)
M.client.screen -= src
src.throwing = 0
if(src.loc == user)
if(!user.unEquip(src))
return
else
if(istype(src.loc, /mob/living))
return
src.pickup(user)
user.put_in_active_hand(src)
return
/obj/item/attack_alien(mob/user as mob)
var/mob/living/carbon/alien/A = user
@@ -323,9 +296,6 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
/obj/item/proc/talk_into(mob/M, var/text, var/channel=null)
return
/obj/item/proc/moved(mob/user, old_loc)
return
/obj/item/proc/dropped(mob/user)
for(var/X in actions)
var/datum/action/A = X
@@ -546,6 +516,23 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
throw_at(S,14,3)
else ..()
/obj/item/throw_impact(atom/A)
if(A && !qdeleted(A))
var/itempush = 1
if(w_class < 4)
itempush = 0 // too light to push anything
return A.hitby(src, 0, itempush)
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
thrownby = thrower
callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own
. = ..(target, range, speed, thrower, spin, diagonals_first, callback)
/obj/item/proc/after_throw(datum/callback/callback)
if(callback) //call the original callback
. = callback.Invoke()
throw_speed = initial(throw_speed) //explosions change this.
/obj/item/proc/pwr_drain()
return 0 // Process Kill
+1 -1
View File
@@ -151,7 +151,7 @@ var/list/tape_roll_applications = list()
if(!density) return 1
if(height==0) return 1
if((mover.pass_flags & PASSTABLE || istype(mover, /obj/effect/meteor) || mover.throwing == 1) )
if((mover.pass_flags & PASSTABLE || istype(mover, /obj/effect/meteor) || mover.throwing))
return 1
else if(ismob(mover) && allowed(mover))
return 1
+1 -1
View File
@@ -115,7 +115,7 @@
last = C
break
/obj/item/weapon/twohanded/rcl/moved(mob/user, turf/old_loc, direct)
/obj/item/weapon/twohanded/rcl/on_mob_move(direct, mob/user)
if(active)
trigger(user)
+3 -3
View File
@@ -111,10 +111,10 @@
/obj/item/weapon/dice/attack_self(mob/user as mob)
diceroll(user)
/obj/item/weapon/dice/throw_at(atom/target, range, speed, mob/user as mob)
/obj/item/weapon/dice/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
if(!..())
return
diceroll(user)
diceroll(thrower)
/obj/item/weapon/dice/proc/diceroll(mob/user)
result = rand(1, sides)
@@ -133,7 +133,7 @@
user.visible_message("<span class='notice'>[user] has thrown [src]. It lands on [result]. [comment]</span>", \
"<span class='notice'>You throw [src]. It lands on [result]. [comment]</span>", \
"<span class='italics'>You hear [src] rolling, it sounds like a [fake_result].</span>")
else if(src.throwing == 0) //Dice was thrown and is coming to rest
else if(!throwing) //Dice was thrown and is coming to rest
visible_message("<span class='notice'>[src] rolls to a stop, landing on [result]. [comment]</span>")
/obj/item/weapon/dice/d20/e20/diceroll(mob/user as mob, thrown)
+4 -1
View File
@@ -316,4 +316,7 @@ a {
for(var/obj/item/Item in contents) //Empty out the contents
Item.forceMove(new_loc)
if(burn)
Item.fire_act() //Set them on fire, too
Item.fire_act() //Set them on fire, too
/obj/proc/on_mob_move(dir, mob/user)
return
@@ -56,7 +56,7 @@
if(throwing) // you keep some momentum when getting out of a thrown closet
step(AM, dir)
if(throwing)
throwing = 0
throwing.finalize(FALSE)
/obj/structure/closet/proc/open()
if(opened)
@@ -327,7 +327,7 @@
/obj/structure/closet/attack_hand(mob/user)
add_fingerprint(user)
toggle(user)
/obj/structure/closet/attack_ghost(mob/user)
if(user.can_advanced_admin_interact())
toggle(user)
+2 -2
View File
@@ -297,8 +297,8 @@
tforce = 5
else if(isobj(AM))
if(prob(50))
var/obj/item/I = AM
tforce = max(0, I.throwforce * 0.5)
var/obj/O = AM
tforce = max(0, O.throwforce * 0.5)
else if(anchored && !broken)
var/turf/T = get_turf(src)
var/obj/structure/cable/C = T.get_cable_node()
+2 -2
View File
@@ -190,7 +190,7 @@
layer = 2.0
var/obj/structure/morgue/connected = null
anchored = 1.0
throwpass = 1
pass_flags = LETPASSTHROW
/obj/structure/m_tray/attack_hand(mob/user as mob)
@@ -432,7 +432,7 @@
layer = 2.0
var/obj/structure/crematorium/connected = null
anchored = 1.0
throwpass = 1
pass_flags = LETPASSTHROW
/obj/structure/c_tray/attack_hand(mob/user as mob)
if(connected)
+8 -3
View File
@@ -18,7 +18,7 @@
density = 1
anchored = 1.0
layer = 2.8
throwpass = 1 //You can throw objects over this, despite it's density.")
pass_flags = LETPASSTHROW
climbable = 1
var/parts = /obj/item/weapon/table_parts
@@ -127,7 +127,8 @@
return
/obj/structure/table/CanPass(atom/movable/mover, turf/target, height=0)
if(height==0) return 1
if(height == 0)
return 1
if(istype(mover,/obj/item/projectile))
return (check_cover(mover,target))
if(ismob(mover))
@@ -136,6 +137,8 @@
return 1
if(istype(mover) && mover.checkpass(PASSTABLE))
return 1
if(mover.throwing)
return 1
if(locate(/obj/structure/table) in get_turf(mover))
return 1
if(flipped)
@@ -526,7 +529,7 @@
icon_state = "rack"
density = 1
anchored = 1.0
throwpass = 1 //You can throw objects over this, despite it's density.
pass_flags = LETPASSTHROW
var/parts = /obj/item/weapon/rack_parts
var/health = 5
@@ -563,6 +566,8 @@
return 1
if(istype(mover) && mover.checkpass(PASSTABLE))
return 1
if(mover.throwing)
return 1
else
return 0
+18 -16
View File
@@ -108,22 +108,24 @@ var/global/wcCommon = pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e", "#8f
return 1
/obj/structure/window/hitby(atom/movable/AM)
if(!CanPass(AM, get_step(src, AM.dir))) //So thrown objects that cross a tile with non-full windows will no longer hit the window even if it isn't visually obstructing the path.
..()
var/tforce = 0
if(isobj(AM))
var/obj/item/I = AM
tforce = I.throwforce
if(reinf) tforce *= 0.25
playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
health = max(0, health - tforce)
if(health <= 7 && !reinf)
anchored = 0
update_nearby_icons()
step(src, get_dir(AM, src))
if(health <= 0)
destroy()
/obj/structure/window/hitby(atom/movable/AM)
..()
var/tforce = 0
if(ismob(AM))
tforce = 10
else if(isobj(AM))
var/obj/O = AM
tforce = O.throwforce
if(reinf)
tforce *= 0.25
playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
health = max(0, health - tforce)
if(health <= 7 && !reinf)
anchored = 0
update_nearby_icons()
step(src, get_dir(AM, src))
if(health <= 0)
destroy()
/obj/structure/window/attack_hand(mob/user as mob)
-5
View File
@@ -2,8 +2,3 @@
name = "weapon"
icon = 'icons/obj/weapons.dmi'
hitsound = "swing_hit"
/obj/item/weapon/Bump(mob/M as mob)
spawn(0)
..()
return
-3
View File
@@ -15,9 +15,6 @@
world.tick_lag = newtick
feedback_add_details("admin_verb","TICKLAG") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
switch(alert("Enable Tick Compensation?","Tick Comp is currently: [config.Tickcomp]","Yes","No"))
if("Yes") config.Tickcomp = 1
else config.Tickcomp = 0
else
to_chat(src, "<span class='warning'>Error: ticklag(): Invalid world.ticklag value. No changes made.</span>")
+3 -3
View File
@@ -42,9 +42,9 @@
attempt_capture(P, -20) //attempting a melee capture reduces the mob's effective run_chance by 20% to balance the risk of triggering a trap mob
return 1
/obj/effect/nanomob/hitby(obj/item/O)
if(istype(O, /obj/item/device/pda))
var/obj/item/device/pda/P = O
/obj/effect/nanomob/hitby(atom/movable/AM)
if(istype(AM, /obj/item/device/pda))
var/obj/item/device/pda/P = AM
attempt_capture(P) //attempting a ranged capture does not affect the mob's effective run_chance but does prevent you from being shocked by a trap mob
return 1
@@ -985,11 +985,6 @@
// AIs are a bit slower than regular and ignore move intent.
wearer_move_delay = world.time + ai_controlled_move_delay
var/tickcomp = 0
if(config.Tickcomp)
tickcomp = ((1/(world.tick_lag))*1.3) - 1.3
wearer_move_delay += tickcomp
if(wearer.buckled) //if we're buckled to something, tell it we moved.
return wearer.buckled.relaymove(wearer, direction)
+4 -5
View File
@@ -11,7 +11,7 @@
icon_state = "tank1"
density = 0
anchored = 0
throwpass = 0
pass_flags = 0
var/tank_type = "" // Type of aquarium, used for icon updating
var/water_capacity = 0 // Number of units the tank holds (varies with tank type)
@@ -38,8 +38,7 @@
icon_state = "bowl1"
density = 0 // Small enough to not block stuff
anchored = 0 // Small enough to move even when filled
throwpass = 1 // Just like at the county fair, you can't seem to throw the ball in to win the goldfish
pass_flags = PASSTABLE // Small enough to pull onto a table
pass_flags = PASSTABLE | LETPASSTHROW // Just like at the county fair, you can't seem to throw the ball in to win the goldfish, and it's small enough to pull onto a table
tank_type = "bowl"
water_capacity = 50 // Not very big, therefore it can't hold much
@@ -57,7 +56,7 @@
icon_state = "tank1"
density = 1
anchored = 1
throwpass = 1 // You can throw objects over this, despite it's density, because it's short enough.
pass_flags = LETPASSTHROW
tank_type = "tank"
water_capacity = 200 // Decent sized, holds almost 2 full buckets
@@ -75,7 +74,7 @@
icon_state = "wall1"
density = 1
anchored = 1
throwpass = 0 // This thing is the size of a wall, you can't throw past it.
pass_flags = 0 // This thing is the size of a wall, you can't throw past it.
tank_type = "wall"
water_capacity = 500 // This thing fills an entire tile, it holds a lot.
+2 -45
View File
@@ -180,49 +180,6 @@ Gunshots/explosions/opening doors/less rare audio (done)
..()
name = "alien hunter ([rand(1, 1000)])"
/obj/effect/hallucination/simple/xeno/throw_at(atom/target, range, speed) // TODO : Make diagonal trhow into proc/property
if(!target || !src || (flags & NODROP))
return 0
throwing = 1
var/dist_x = abs(target.x - x)
var/dist_y = abs(target.y - y)
var/dist_travelled = 0
var/dist_since_sleep = 0
var/tdist_x = dist_x;
var/tdist_y = dist_y;
if(dist_x <= dist_y)
tdist_x = dist_y;
tdist_y = dist_x;
var/error = tdist_x/2 - tdist_y
while(target && (((((dist_x > dist_y) && ((x < target.x) || (x > target.x))) || ((dist_x <= dist_y) && ((y < target.y) || (y > target.y))) || (x > target.x)) && dist_travelled < range) || !has_gravity(src)))
if(!throwing)
break
if(!istype(loc, /turf))
break
var/atom/step = get_step(src, get_dir(src, target))
if(!step)
break
Move(step, get_dir(src, step))
hit_check()
error += (error < 0) ? tdist_x : -tdist_y;
dist_travelled++
dist_since_sleep++
if(dist_since_sleep >= speed)
dist_since_sleep = 0
sleep(1)
throwing = 0
throw_impact(get_turf(src))
return 1
/obj/effect/hallucination/simple/xeno/throw_impact(A)
update_icon("alienh_pounce")
if(A == target)
@@ -247,12 +204,12 @@ Gunshots/explosions/opening doors/less rare audio (done)
if(!xeno)
return
xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32)
xeno.throw_at(target,7,1)
xeno.throw_at(target,7,1, spin = 0, diagonals_first = 1)
sleep(10)
if(!xeno)
return
xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32)
xeno.throw_at(pump,7,1)
xeno.throw_at(pump,7,1, spin = 0, diagonals_first = 1)
sleep(10)
if(!xeno)
return
@@ -1,5 +1,5 @@
/mob/living/carbon/alien/hitby(atom/movable/AM)
..(AM, 1)
/mob/living/carbon/alien/hitby(atom/movable/AM, skipcatch, hitpush)
..(AM, hitpush = 0)
/*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other.
As such, they can either help or harm other aliens. Help works like the human help command while harm is a simple nibble.
@@ -79,17 +79,18 @@
else //Maybe uses plasma in the future, although that wouldn't make any sense...
leaping = 1
update_icons()
throw_at(A,MAX_ALIEN_LEAP_DIST,1)
leaping = 0
update_icons()
throw_at(A, MAX_ALIEN_LEAP_DIST, 1, spin = 0, diagonals_first = 1, callback = CALLBACK(src, .leap_end))
/mob/living/carbon/alien/humanoid/hunter/proc/leap_end()
leaping = 0
update_icons()
/mob/living/carbon/alien/humanoid/hunter/throw_impact(atom/A)
if(!leaping)
return ..()
if(A)
if(istype(A, /mob/living))
if(isliving(A))
var/mob/living/L = A
var/blocked = 0
if(ishuman(A))
@@ -126,46 +127,3 @@
if(leaping)
return
..()
//Modified throw_at() that will use diagonal dirs where appropriate
//instead of locking it to cardinal dirs
/mob/living/carbon/alien/humanoid/throw_at(atom/target, range, speed)
if(!target || !src) return 0
src.throwing = 1
var/dist_x = abs(target.x - src.x)
var/dist_y = abs(target.y - src.y)
var/dist_travelled = 0
var/dist_since_sleep = 0
var/tdist_x = dist_x;
var/tdist_y = dist_y;
if(dist_x <= dist_y)
tdist_x = dist_y;
tdist_y = dist_x;
var/error = tdist_x/2 - tdist_y
while(target && (((((dist_x > dist_y) && ((src.x < target.x) || (src.x > target.x))) || ((dist_x <= dist_y) && ((src.y < target.y) || (src.y > target.y))) || (src.x > target.x)) && dist_travelled < range) || !has_gravity(src)))
if(!src.throwing) break
if(!istype(src.loc, /turf)) break
var/atom/step = get_step(src, get_dir(src,target))
if(!step)
break
src.Move(step, get_dir(src, step))
hit_check()
error += (error < 0) ? tdist_x : -tdist_y;
dist_travelled++
dist_since_sleep++
if(dist_since_sleep >= speed)
dist_since_sleep = 0
sleep(1)
src.throwing = 0
return 1
@@ -24,32 +24,6 @@
add_language("Hivemind")
..()
//This is fine, works the same as a human
/mob/living/carbon/alien/humanoid/Bump(atom/movable/AM as mob|obj, yes)
spawn( 0 )
if((!( yes ) || now_pushing))
return
now_pushing = 0
..()
if(!istype(AM, /atom/movable))
return
if(ismob(AM))
var/mob/tmob = AM
tmob.LAssailant = src
if(!now_pushing)
now_pushing = 1
if(!AM.anchored)
var/t = get_dir(src, AM)
if(istype(AM, /obj/structure/window/full))
for(var/obj/structure/window/win in get_step(AM,t))
now_pushing = 0
return
step(AM, t)
now_pushing = null
return
return
/mob/living/carbon/alien/humanoid/movement_delay()
var/tally = 0
@@ -26,38 +26,6 @@
..()
//This is fine, works the same as a human
/mob/living/carbon/alien/larva/Bump(atom/movable/AM as mob|obj, yes)
spawn( 0 )
if((!( yes ) || now_pushing))
return
now_pushing = 1
if(ismob(AM))
var/mob/tmob = AM
if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations))
if(prob(70))
to_chat(src, "<span class='danger'>You fail to push [tmob]'s fat ass out of the way.</span>")
now_pushing = 0
return
if(!(tmob.status_flags & CANPUSH))
now_pushing = 0
return
tmob.LAssailant = src
now_pushing = 0
..()
if(!( istype(AM, /atom/movable) ))
return
if(!( now_pushing ))
now_pushing = 1
if(!( AM.anchored ))
var/t = get_dir(src, AM)
step(AM, t)
now_pushing = null
return
return
//This needs to be fixed
/mob/living/carbon/alien/larva/Stat()
..()
+23
View File
@@ -492,6 +492,29 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
//Throwing stuff
/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum)
. = ..()
var/hurt = TRUE
/*if(istype(throwingdatum, /datum/thrownthing))
var/datum/thrownthing/D = throwingdatum
if(isrobot(D.thrower))
var/mob/living/silicon/robot/R = D.thrower
if(!R.emagged)
hurt = FALSE*/
if(hit_atom.density && isturf(hit_atom))
if(hurt)
Weaken(1)
take_organ_damage(10)
if(iscarbon(hit_atom) && hit_atom != src)
var/mob/living/carbon/victim = hit_atom
if(hurt)
victim.take_organ_damage(10)
take_organ_damage(10)
victim.Weaken(1)
Weaken(1)
visible_message("<span class='danger'>[src] crashes into [victim], knocking them both over!</span>", "<span class='userdanger'>You violently crash into [victim]!</span>")
playsound(src, 'sound/weapons/punch1.ogg', 50, 1)
/mob/living/carbon/proc/toggle_throw_mode()
if(in_throw_mode)
throw_mode_off()
@@ -1,13 +1,14 @@
/mob/living/carbon/hitby(atom/movable/AM)
if(in_throw_mode && !get_active_hand()) //empty active hand and we're in throw mode
if(canmove && !restrained())
if(istype(AM, /obj/item))
var/obj/item/I = AM
if(isturf(I.loc))
put_in_active_hand(I)
visible_message("<span class='warning'>[src] catches [I]!</span>")
throw_mode_off()
return
/mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked = 0)
if(!skipcatch)
if(in_throw_mode && !get_active_hand()) //empty active hand and we're in throw mode
if(canmove && !restrained())
if(istype(AM, /obj/item))
var/obj/item/I = AM
if(isturf(I.loc))
put_in_active_hand(I)
visible_message("<span class='warning'>[src] catches [I]!</span>")
throw_mode_off()
return 1
..()
/mob/living/carbon/water_act(volume, temperature, source)
@@ -147,93 +147,6 @@
/mob/living/carbon/human/stok/New(var/new_loc)
..(new_loc, "Stok")
/mob/living/carbon/human/Bump(atom/movable/AM, yes)
if(!(yes) || now_pushing || buckled)
return 0
now_pushing = 1
if(ismob(AM))
var/mob/tmob = AM
//BubbleWrap - Should stop you pushing a restrained person out of the way
//i still don't get it, is this supposed to be 'bubblewrapping' or was it made by a guy named 'BubbleWrap'
if(ishuman(tmob))
for(var/mob/M in range(tmob, 1))
if(tmob.pinned.len || (M.pulling == tmob && (tmob.restrained() && !M.restrained()) && M.stat == CONSCIOUS))
if(!(world.time % 5)) //tmob is pinned to wall, or is restrained and pulled by a concious unrestrained human
to_chat(src, "<span class='danger'>[tmob] is restrained, you cannot push past.</span>")
now_pushing = 0
return 0
//I have to fucking document this somewhere- the above if(tmob.pinned.len || etc) check above had
//locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) at the end of it
//FIRST OF ALL, THAT IS NOT HOW YOU FUCKING USE LOCATE()
//SECOND OF ALL, OH GOD, WHY WOULD YOU EVER WANT GRABBED MOBS TO BE UNABLE TO BE PUSHED PAST GOD
if(tmob.pulling == M && (M.restrained() && !tmob.restrained()) && tmob.stat == CONSCIOUS)
if(!(world.time % 5))
to_chat(src, "<span class='danger'>[tmob] is restraining [M], you cannot push past.</span>")
now_pushing = 0
return 0
//Leaping mobs just land on the tile, no pushing, no anything.
if(status_flags & LEAPING)
loc = tmob.loc
status_flags &= ~LEAPING
now_pushing = 0
return
//BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
//it might be 'bubblewrapping' given that this rhymes with 'hugboxing'
if((tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || restrained()))
if((canmove && tmob.canmove) && (!tmob.buckled && !tmob.buckled_mob))
var/turf/oldloc = loc
loc = tmob.loc
tmob.loc = oldloc
now_pushing = 0
for(var/mob/living/carbon/slime/slime in view(1,tmob))
if(slime.Victim == tmob)
slime.UpdateFeed()
return
if(ishuman(tmob) && (FAT in tmob.mutations))
if(prob(40) && !(FAT in src.mutations))
to_chat(src, "<span class='danger'>You fail to push [tmob]'s fat ass out of the way.</span>")
now_pushing = 0
return
//anti-riot equipment is also anti-push
if(tmob.r_hand && (prob(tmob.r_hand.block_chance * 2)) && !istype(tmob.r_hand, /obj/item/clothing))
now_pushing = 0
return
if(tmob.l_hand && (prob(tmob.l_hand.block_chance * 2)) && !istype(tmob.l_hand, /obj/item/clothing))
now_pushing = 0
return
if(!(tmob.status_flags & CANPUSH))
now_pushing = 0
return
tmob.LAssailant = src
now_pushing = 0
spawn(0)
..()
if(!istype(AM, /atom/movable))
return
if(!now_pushing)
now_pushing = 1
if(!AM.anchored)
var/t = get_dir(src, AM)
if(istype(AM, /obj/structure/window/full))
for(var/obj/structure/window/win in get_step(AM, t))
now_pushing = 0
return
step(AM, t)
now_pushing = 0
/mob/living/carbon/human/Stat()
..()
statpanel("Status")
@@ -313,85 +313,37 @@ emp_act
return 1*/
//this proc handles being hit by a thrown atom
/mob/living/carbon/human/hitby(atom/movable/AM as mob|obj,var/speed = 5)
/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
var/obj/item/I
var/throwpower = 30
if(istype(AM, /obj/item))
var/obj/item/I = AM
if(in_throw_mode && !get_active_hand() && speed <= 5) //empty active hand and we're in throw mode
if(canmove && !restrained())
if(isturf(I.loc))
put_in_active_hand(I)
visible_message("<span class='warning'>[src] catches [I]!</span>")
throw_mode_off()
return
var/zone = ran_zone("chest", 65)
var/dtype = BRUTE
if(istype(I, /obj/item/weapon))
var/obj/item/weapon/W = I
dtype = W.damtype
var/throw_damage = I.throwforce*(speed/5)
I.throwing = 0 //it hit, so stop moving
if((I.thrower != src) && check_shields(throw_damage, "\the [I.name]", I, THROWN_PROJECTILE_ATTACK))
return
var/obj/item/organ/external/affecting = get_organ(zone)
if(!affecting)
var/missverb = (I.gender == PLURAL) ? "whizz" : "whizzes"
visible_message("<span class='notice'>\The [I] [missverb] past [src]'s missing [parse_zone(zone)]!</span>",
"<span class='notice'>\The [I] [missverb] past your missing [parse_zone(zone)]!</span>")
return
var/hit_area = affecting.name
src.visible_message("<span class='warning'>[src] has been hit in the [hit_area] by [I].</span>")
var/armor = run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].", I.armour_penetration) //I guess "melee" is the best fit here
apply_damage(throw_damage, dtype, zone, armor, is_sharp(I), has_edge(I), I)
if(ismob(I.thrower))
var/mob/M = I.thrower
if(M)
add_logs(M, src, "hit", I, " (thrown)", print_attack_log = I.throwforce)
//thrown weapon embedded object code.
if(dtype == BRUTE && istype(I))
if(!I.is_robot_module())
I = AM
throwpower = I.throwforce
if(I.thrownby == src) //No throwing stuff at yourself to trigger reactions
return ..()
if(check_shields(throwpower, "\the [AM.name]", AM, THROWN_PROJECTILE_ATTACK))
hitpush = 0
skipcatch = 1
blocked = 1
/*else if(I)
if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD)
if(!I.is_robot_module())
var/armor = run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].", I.armour_penetration) //I guess "melee" is the best fit here
var/sharp = is_sharp(I)
var/damage = throw_damage
var/damage = throwpower * (I.throw_speed / 5)
if(armor)
damage /= armor+1
damage /= armor + 1
//blunt objects should really not be embedding in things unless a huge amount of force is involved
var/embed_chance = sharp? damage/I.w_class : damage/(I.w_class*3)
var/embed_threshold = sharp? 5*I.w_class : 15*I.w_class
var/embed_chance = sharp? damage / I.w_class : damage/(I.w_class * 3)
var/embed_threshold = sharp? 5 * I.w_class : 15 * I.w_class
//Sharp objects will always embed if they do enough damage.
//Thrown sharp objects have some momentum already and have a small chance to embed even if the damage is below the threshold
if(((sharp && prob(damage/(10*I.w_class)*100)) || (damage > embed_threshold && prob(embed_chance))) && (I.no_embed == 0))
affecting.embed(I)
// Begin BS12 momentum-transfer code.
if(I.throw_source && speed >= 15)
var/obj/item/weapon/W = I
var/momentum = speed/2
var/dir = get_dir(I.throw_source, src)
visible_message("<span class='warning'>[src] staggers under the impact!</span>","<span class='warning'>You stagger under the impact!</span>")
src.throw_at(get_edge_target_turf(src,dir),1,momentum)
if(!W || !src) return
if(W.loc == src && W.sharp) //Projectile is embedded and suitable for pinning.
var/turf/T = near_wall(dir,2)
if(T)
src.loc = T
visible_message("<span class='warning'>[src] is pinned to the wall by [I]!</span>","<span class='warning'>You are pinned to the wall by [I]!</span>")
src.anchored = 1
src.pinned += I
if(((sharp && prob(damage / (10 * I.w_class) * 100)) || (damage > embed_threshold && prob(embed_chance))) && (I.no_embed == 0))
affecting.embed(I)*/
return ..()
/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2)
@@ -1,67 +1,75 @@
/mob/living/carbon/human/movement_delay()
var/tally = 0
. = 0
. += ..()
if(species.slowdown)
tally = species.slowdown
var/gravity = 1
if(!has_gravity(src))
return -1 // It's hard to be slowed down in space by... anything
gravity = 0
if(flying) return -1
if(flying)
gravity = 0
if(embedded_flag)
handle_embedded_objects() //Moving with objects stuck in you can cause bad times.
if(slowed)
tally += 10
. += 10
var/health_deficiency = (maxHealth - health + staminaloss)
if(reagents)
for(var/datum/reagent/R in reagents.reagent_list)
if(R.shock_reduction)
health_deficiency -= R.shock_reduction
if(health_deficiency >= 40)
tally += (health_deficiency / 25)
if(gravity)
if(species.slowdown)
. = species.slowdown
var/hungry = (500 - nutrition)/5 // So overeat would be 100 and default level would be 80
if(hungry >= 70)
tally += hungry/50
var/health_deficiency = (maxHealth - health + staminaloss)
if(reagents)
for(var/datum/reagent/R in reagents.reagent_list)
if(R.shock_reduction)
health_deficiency -= R.shock_reduction
if(health_deficiency >= 40)
. += (health_deficiency / 25)
if(wear_suit)
tally += wear_suit.slowdown
var/hungry = (500 - nutrition)/5 // So overeat would be 100 and default level would be 80
if(hungry >= 70)
. += hungry/50
if(!buckled)
if(shoes)
tally += shoes.slowdown
if(wear_suit)
. += wear_suit.slowdown
if(shock_stage >= 10) tally += 3
if(!buckled)
if(shoes)
. += shoes.slowdown
if(back)
tally += back.slowdown
if(shock_stage >= 10)
. += 3
if(l_hand && (l_hand.flags & HANDSLOW))
tally += l_hand.slowdown
if(r_hand && (r_hand.flags & HANDSLOW))
tally += r_hand.slowdown
if(back)
. += back.slowdown
if(FAT in src.mutations)
tally += 1.5
if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT)
tally += (BODYTEMP_COLD_DAMAGE_LIMIT - bodytemperature) / COLD_SLOWDOWN_FACTOR
if(l_hand && (l_hand.flags & HANDSLOW))
. += l_hand.slowdown
if(r_hand && (r_hand.flags & HANDSLOW))
. += r_hand.slowdown
tally += 2*stance_damage //damaged/missing feet or legs is slow
if(FAT in src.mutations)
. += 1.5
if(RUN in mutations)
tally = -1
if(status_flags & IGNORESLOWDOWN) // make sure this is always at the end so we don't have ignore slowdown getting ignored itself
tally = -1
if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT)
. += (BODYTEMP_COLD_DAMAGE_LIMIT - bodytemperature) / COLD_SLOWDOWN_FACTOR
if(status_flags & GOTTAGOFAST)
tally -= 1
if(status_flags & GOTTAGOREALLYFAST)
tally -= 2
. += 2 * stance_damage //damaged/missing feet or legs is slow
return (tally + config.human_delay)
if(RUN in mutations)
. = -1
if(status_flags & IGNORESLOWDOWN) // make sure this is always at the end so we don't have ignore slowdown getting ignored itself
. = -1
if(status_flags & GOTTAGOFAST)
. -= 1
if(status_flags & GOTTAGOREALLYFAST)
. -= 2
. += config.human_delay
/mob/living/carbon/human/Process_Spacemove(movement_dir = 0)
@@ -449,7 +449,7 @@
..()
retalTarget(user)
/mob/living/carbon/human/interactive/hitby(atom/movable/AM)
/mob/living/carbon/human/interactive/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
..()
var/mob/living/carbon/C = locate(/mob/living/carbon) in view(SNPC_MIN_RANGE_FIND, src)
if(C)
+18 -53
View File
@@ -103,59 +103,24 @@
return tally + config.slime_delay
/mob/living/carbon/slime/Bump(atom/movable/AM as mob|obj, yes)
if((!(yes) || now_pushing))
return
now_pushing = 1
if(isobj(AM))
if(!client && powerlevel > 0)
var/probab = 10
switch(powerlevel)
if(1 to 2) probab = 20
if(3 to 4) probab = 30
if(5 to 6) probab = 40
if(7 to 8) probab = 60
if(9) probab = 70
if(10) probab = 95
if(prob(probab))
if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille))
if(nutrition <= get_hunger_nutrition() && !Atkcool)
if(is_adult || prob(5))
AM.attack_slime(src)
spawn()
Atkcool = 1
sleep(45)
Atkcool = 0
if(ismob(AM))
var/mob/tmob = AM
if(is_adult)
if(istype(tmob, /mob/living/carbon/human))
if(prob(90))
now_pushing = 0
return
else
if(istype(tmob, /mob/living/carbon/human))
now_pushing = 0
return
now_pushing = 0
..()
if(!istype(AM, /atom/movable))
return
if(!( now_pushing ))
now_pushing = 1
if(!( AM.anchored ))
var/t = get_dir(src, AM)
if(istype(AM, /obj/structure/window))
if(AM:ini_dir == NORTHWEST || AM:ini_dir == NORTHEAST || AM:ini_dir == SOUTHWEST || AM:ini_dir == SOUTHEAST)
for(var/obj/structure/window/win in get_step(AM,t))
now_pushing = 0
return
step(AM, t)
now_pushing = null
/mob/living/carbon/slime/ObjBump(obj/O)
if(!client && powerlevel > 0)
var/chance = 10
switch(powerlevel)
if(1 to 2) chance = 20
if(3 to 4) chance = 30
if(5 to 6) chance = 40
if(7 to 8) chance = 60
if(9) chance = 70
if(10) chance = 95
if(prob(chance))
if(istype(O, /obj/structure/window) || istype(O, /obj/structure/grille))
if(nutrition <= get_hunger_nutrition() && !Atkcool)
if(is_adult || prob(5))
O.attack_slime(src)
Atkcool = 1
spawn(45)
Atkcool = 0
/mob/living/carbon/slime/Process_Spacemove(var/movement_dir = 0)
return 2
+162 -71
View File
@@ -14,6 +14,121 @@
/mob/living/proc/OpenCraftingMenu()
return
//Generic Bump(). Override MobBump() and ObjBump() instead of this.
/mob/living/Bump(atom/A, yes)
if(..()) //we are thrown onto something
return
if(buckled || !yes || now_pushing)
return
if(ismob(A))
if(MobBump(A))
return
if(isobj(A))
if(ObjBump(A))
return
if(istype(A, /atom/movable))
if(PushAM(A))
return
//Called when we bump into a mob
/mob/living/proc/MobBump(mob/M)
//Even if we don't push/swap places, we "touched" them, so spread fire
spreadFire(M)
if(now_pushing)
return 1
//Should stop you pushing a restrained person out of the way
if(isliving(M))
var/mob/living/L = M
if(L.pulledby && L.pulledby != src && L.restrained())
if(!(world.time % 5))
to_chat(src, "<span class='warning'>[L] is restrained, you cannot push past.</span>")
return 1
if(L.pulling)
if(ismob(L.pulling))
var/mob/P = L.pulling
if(P.restrained())
if(!(world.time % 5))
to_chat(src, "<span class='warning'>[L] is restrained, you cannot push past.</span>")
return 1
if(moving_diagonally) //no mob swap during diagonal moves.
return 1
if(!M.buckled && !M.has_buckled_mobs())
var/mob_swap
//the puller can always swap with it's victim if on grab intent
if(M.pulledby == src && a_intent == I_GRAB)
mob_swap = 1
//restrained people act if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
else if((M.restrained() || M.a_intent == I_HELP) && (restrained() || a_intent == I_HELP))
mob_swap = 1
if(mob_swap)
//switch our position with M
if(loc && !loc.Adjacent(M.loc))
return 1
now_pushing = 1
var/oldloc = loc
var/oldMloc = M.loc
var/M_passmob = (M.pass_flags & PASSMOB) // we give PASSMOB to both mobs to avoid bumping other mobs during swap.
var/src_passmob = (pass_flags & PASSMOB)
M.pass_flags |= PASSMOB
pass_flags |= PASSMOB
M.Move(oldloc)
Move(oldMloc)
if(!src_passmob)
pass_flags &= ~PASSMOB
if(!M_passmob)
M.pass_flags &= ~PASSMOB
now_pushing = 0
return 1
// okay, so we didn't switch. but should we push?
// not if he's not CANPUSH of course
if(!(M.status_flags & CANPUSH))
return 1
//anti-riot equipment is also anti-push
if(M.r_hand && (prob(M.r_hand.block_chance * 2)) && !istype(M.r_hand, /obj/item/clothing))
return 1
if(M.l_hand && (prob(M.l_hand.block_chance * 2)) && !istype(M.l_hand, /obj/item/clothing))
return 1
//Called when we bump into an obj
/mob/living/proc/ObjBump(obj/O)
return
//Called when we want to push an atom/movable
/mob/living/proc/PushAM(atom/movable/AM)
if(now_pushing)
return 1
if(moving_diagonally) // no pushing during diagonal moves
return 1
if(!client && (mob_size < MOB_SIZE_SMALL))
return
if(!AM.anchored)
now_pushing = 1
var/t = get_dir(src, AM)
if(istype(AM, /obj/structure/window/full))
for(var/obj/structure/window/win in get_step(AM, t))
now_pushing = 0
return
if(pulling == AM)
stop_pulling()
var/current_dir
if(isliving(AM))
current_dir = AM.dir
step(AM, t)
if(current_dir)
AM.setDir(current_dir)
now_pushing = 0
/mob/living/Stat()
. = ..()
if(. && get_rig_stats)
@@ -430,83 +545,47 @@
else
return 0
var/atom/movable/pullee = pulling
if(pullee && get_dist(src, pullee) > 1)
stop_pulling()
if(pullee && !isturf(pullee.loc) && pullee.loc != loc)
log_game("DEBUG: [src]'s pull on [pullee] was broken despite [pullee] being in [pullee.loc]. Pull stopped manually.")
stop_pulling()
if(restrained())
stop_pulling()
var/t7 = 1
if(restrained())
for(var/mob/living/M in range(src, 1))
if((M.pulling == src && M.stat == 0 && !( M.restrained() )))
t7 = null
if(t7 && pulling && (get_dist(src, pulling) <= 1 || pulling.loc == loc))
var/turf/T = loc
. = ..()
if(pulling && pulling.loc)
if(!( isturf(pulling.loc) ))
stop_pulling()
return
else
if(Debug)
diary <<"pulling disappeared? at [__LINE__] in mob.dm - pulling = [pulling]"
diary <<"REPORT THIS"
/////
if(pulling && pulling.anchored)
stop_pulling()
return
if(!restrained())
var/diag = get_dir(src, pulling)
if((diag - 1) & diag)
else
diag = null
if((get_dist(src, pulling) > 1 || diag))
if(isliving(pulling))
var/mob/living/M = pulling
var/ok = 1
if(locate(/obj/item/weapon/grab, M.grabbed_by))
if(prob(75))
var/obj/item/weapon/grab/G = pick(M.grabbed_by)
if(istype(G, /obj/item/weapon/grab))
for(var/mob/O in viewers(M, null))
O.show_message(text("<span class='warning'>[] has been pulled from []'s grip by []</span>", G.affecting, G.assailant, src), 1)
//G = null
qdel(G)
else
ok = 0
if(locate(/obj/item/weapon/grab, M.grabbed_by.len))
ok = 0
if(ok)
var/atom/movable/t = M.pulling
M.stop_pulling()
if(M.lying && (prob(M.getBruteLoss() / 6)))
var/turf/location = M.loc
if(istype(location, /turf/simulated))
location.add_blood(M)
pulling.Move(T, get_dir(pulling, T))
if(M)
M.start_pulling(t)
else
if(pulling)
pulling.Move(T, get_dir(pulling, T))
else
stop_pulling()
. = ..()
if(s_active && !( s_active in contents ) && get_turf(s_active) != get_turf(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much.
s_active.close(src)
if(.) // did we actually move?
var/turf/T = loc
. = ..()
if(.)
handle_footstep(loc)
step_count++
if(pulling && pulling == pullee) // we were pulling a thing and didn't lose it during our move.
if(pulling.anchored)
stop_pulling()
return
var/pull_dir = get_dir(src, pulling)
if(get_dist(src, pulling) > 1 || ((pull_dir - 1) & pull_dir)) // puller and pullee more than one tile away or in diagonal position
//if(isliving(pulling))
//var/mob/living/M = pulling
//if(M.lying && !M.buckled && (prob(M.getBruteLoss() * 200 / M.maxHealth)))
//M.makeTrail(T)
pulling.Move(T, get_dir(pulling, T)) // the pullee tries to reach our previous position
if(pulling && get_dist(src, pulling) > 1) // the pullee couldn't keep up
stop_pulling()
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //seperated from our puller and not in the middle of a diagonal move
pulledby.stop_pulling()
if(s_active && !(s_active in contents) && get_turf(s_active) != get_turf(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much.
s_active.close(src)
if(update_slimes)
for(var/mob/living/carbon/slime/M in view(1,src))
M.UpdateFeed(src)
/mob/living/proc/handle_footstep(turf/T)
if(istype(T))
return 1
@@ -838,13 +917,25 @@
visible_message("<span class='notice'>[user] butchers [src].</span>")
gib()
/mob/living/movement_delay()
var/tally = 0
/mob/living/movement_delay(ignorewalk = 0)
. = ..()
if(isturf(loc))
var/turf/T = loc
. += T.slowdown
if(slowed)
tally += 10
. += 10
if(ignorewalk)
. += config.run_speed
else
switch(m_intent)
if("run")
if(drowsyness > 0)
. += 6
. += config.run_speed
if("walk")
. += config.walk_speed
return tally
/mob/living/proc/can_use_guns(var/obj/item/weapon/gun/G)
if(G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser() && !issmall(src))
+51 -46
View File
@@ -52,7 +52,7 @@
if(P.dismemberment)
check_projectile_dismemberment(P, def_zone)
return P.on_hit(src, armor, def_zone)
/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
return 0
@@ -65,60 +65,47 @@
O.emp_act(severity)
..()
/obj/item/proc/get_volume_by_throwforce_and_or_w_class()
if(throwforce && w_class)
return Clamp((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
else if(w_class)
return Clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
else
return 0
//this proc handles being hit by a thrown atom
/mob/living/hitby(atom/movable/AM as mob|obj,var/speed = 5)//Standardization and logging -Sieve
/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked = 0)//Standardization and logging -Sieve
if(istype(AM, /obj/item))
var/obj/item/I = AM
var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest
var/dtype = BRUTE
var/dtype = BRUTE
var/volume = I.get_volume_by_throwforce_and_or_w_class()
if(istype(I, /obj/item/weapon))
var/obj/item/weapon/W = I
dtype = W.damtype
if(W.hitsound && W.throwforce > 0)
playsound(loc, W.hitsound, 30, 1, -1)
if(W.throwforce > 0) //If the weapon's throwforce is greater than zero...
if(W.hitsound) //...and hitsound is defined...
playsound(loc, W.hitsound, volume, 1, -1) //...play the weapon's hitsound.
else //Otherwise, if hitsound isn't defined...
playsound(loc, 'sound/weapons/genhit1.ogg', volume, 1, -1) //...play genhit1.ogg.
//run to-hit check here
else if(I.throwforce > 0) //Otherwise, if the item doesn't have a throwhitsound and has a throwforce greater than zero...
playsound(loc, 'sound/weapons/genhit1.ogg', volume, 1, -1)//...play genhit1.ogg
if(!I.throwforce)// Otherwise, if the item's throwforce is 0...
playsound(loc, 'sound/weapons/throwtap.ogg', 1, volume, -1)//...play throwtap.ogg.
if(!blocked)
visible_message("<span class='danger'>[src] has been hit by [I].</span>",
"<span class='userdanger'>[src] has been hit by [I].</span>")
var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].", I.armour_penetration)
apply_damage(I.throwforce, dtype, zone, armor, is_sharp(I), has_edge(I), I)
if(I.thrownby)
add_logs(I.thrownby, src, "hit", I)
else
return 1
else
playsound(loc, 'sound/weapons/genhit1.ogg', 50, 1, -1) //...play genhit1.ogg.)
..()
var/throw_damage = I.throwforce*(speed/5)
src.visible_message("<span class='warning'>[src] has been hit by [I].</span>")
var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].", I.armour_penetration)
apply_damage(throw_damage, dtype, zone, armor, is_sharp(I), has_edge(I), I)
I.throwing = 0 //it hit, so stop moving
if(ismob(I.thrower))
var/mob/M = I.thrower
if(M)
create_attack_log("<font color='orange'>Has been hit with a [I], thrown by [key_name(M)]</font>")
M.create_attack_log("<font color='red'>Hit [key_name(src)] with a thrown [I]</font>")
if(!istype(src,/mob/living/simple_animal/mouse))
msg_admin_attack("[key_name_admin(src)] was hit by a [I], thrown by [key_name_admin(M)]")
// Begin BS12 momentum-transfer code.
if(I.throw_source && speed >= 15)
var/obj/item/weapon/W = I
var/momentum = speed/2
var/dir = get_dir(I.throw_source, src)
visible_message("<span class='warning'>[src] staggers under the impact!</span>","<span class='warning'>You stagger under the impact!</span>")
src.throw_at(get_edge_target_turf(src,dir),1,momentum)
if(!W || !src) return
if(W.sharp) //Projectile is suitable for pinning.
//Handles embedding for non-humans and simple_animals.
I.loc = src
embedded += I
var/turf/T = near_wall(dir,2)
if(T)
src.loc = T
visible_message("<span class='warning'>[src] is pinned to the wall by [I]!</span>","<span class='warning'>You are pinned to the wall by [I]!</span>")
src.anchored = 1
src.pinned += I
/mob/living/mech_melee_attack(obj/mecha/M)
if(M.occupant.a_intent == I_HARM)
@@ -201,6 +188,24 @@
adjust_fire_stacks(3)
IgniteMob()
//Share fire evenly between the two mobs
//Called in MobBump() and Crossed()
/mob/living/proc/spreadFire(mob/living/L)
if(!istype(L))
return
var/L_old_on_fire = L.on_fire
if(on_fire) //Only spread fire stacks if we're on fire
fire_stacks /= 2
L.fire_stacks += fire_stacks
if(L.IgniteMob())
log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire")
if(L_old_on_fire) //Only ignite us and gain their stacks if they were onfire before we bumped them
L.fire_stacks /= 2
fire_stacks += L.fire_stacks
IgniteMob()
//Mobs on Fire end
/mob/living/water_act(volume, temperature)
+2 -2
View File
@@ -539,10 +539,10 @@
card.forceMove(card.loc)
icon_state = "[chassis]"
/mob/living/silicon/pai/Bump(atom/movable/AM as mob|obj, yes)
/mob/living/silicon/pai/Bump()
return
/mob/living/silicon/pai/Bumped(AM as mob|obj)
/mob/living/silicon/pai/Bumped()
return
/mob/living/silicon/pai/start_pulling(var/atom/movable/AM)
@@ -310,18 +310,15 @@
*/
/mob/living/silicon/robot/drone/Bump(atom/movable/AM as mob|obj, yes)
if(!yes || ( \
!istype(AM,/obj/machinery/door) && \
!istype(AM,/obj/machinery/recharge_station) && \
!istype(AM,/obj/machinery/disposal/deliveryChute) && \
!istype(AM,/obj/machinery/teleport/hub) && \
!istype(AM,/obj/effect/portal)
)) return
..()
return
/mob/living/silicon/robot/drone/Bump(atom/movable/AM, yes)
if(istype(AM, /obj/machinery/door) \
|| istype(AM, /obj/machinery/recharge_station) \
|| istype(AM, /obj/machinery/disposal/deliveryChute) \
|| istype(AM, /obj/machinery/teleport/hub) \
|| istype(AM, /obj/effect/portal))
return ..()
/mob/living/silicon/robot/drone/Bumped(AM as mob|obj)
/mob/living/silicon/robot/drone/Bumped(atom/movable/AM)
return
/mob/living/silicon/robot/drone/start_pulling(var/atom/movable/AM)
@@ -552,38 +552,6 @@ var/list/robot_verbs_default = list(
return 2
/mob/living/silicon/robot/Bump(atom/movable/AM as mob|obj, yes)
spawn( 0 )
if((!( yes ) || now_pushing))
return
now_pushing = 1
if(ismob(AM))
var/mob/tmob = AM
if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations))
if(prob(20))
to_chat(usr, "<span class='danger'>You fail to push [tmob]'s fat ass out of the way.</span>")
now_pushing = 0
return
if(!(tmob.status_flags & CANPUSH))
now_pushing = 0
return
now_pushing = 0
..()
if(!istype(AM, /atom/movable))
return
if(!now_pushing)
now_pushing = 1
if(!AM.anchored)
var/t = get_dir(src, AM)
if(istype(AM, /obj/structure/window/full))
for(var/obj/structure/window/win in get_step(AM,t))
now_pushing = 0
return
step(AM, t)
now_pushing = null
return
return
/mob/living/silicon/robot/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
if(istype(W, /obj/item/weapon/restraints/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do
return
@@ -195,31 +195,6 @@
src << browse(dat, "window=airoster")
onclose(src, "airoster")
/mob/living/silicon/Bump(atom/movable/AM as mob|obj, yes) //Allows the AI to bump into mobs if it's itself pushed
if((!( yes ) || now_pushing))
return
now_pushing = 1
if(ismob(AM))
var/mob/tmob = AM
if(!(tmob.status_flags & CANPUSH))
now_pushing = 0
return
now_pushing = 0
..()
if(!istype(AM, /atom/movable))
return
if(!now_pushing)
now_pushing = 1
if(!AM.anchored)
var/t = get_dir(src, AM)
if(istype(AM, /obj/structure/window))
if(AM:ini_dir == NORTHWEST || AM:ini_dir == NORTHEAST || AM:ini_dir == SOUTHWEST || AM:ini_dir == SOUTHEAST)
for(var/obj/structure/window/win in get_step(AM,t))
now_pushing = 0
return
step(AM, t)
now_pushing = null
/mob/living/silicon/assess_threat() //Secbots won't hunt silicon units
return -10
@@ -218,8 +218,8 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
if(istype(AM, /obj/item))
var/obj/item/I = AM
if(I.throwforce < src.health && I.thrower && (istype(I.thrower, /mob/living/carbon/human)))
var/mob/living/carbon/human/H = I.thrower
if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
var/mob/living/carbon/human/H = I.thrownby
retaliate(H)
..()
@@ -470,41 +470,6 @@
name = "Corgi meat"
desc = "Tastes like... well you know..."
/mob/living/simple_animal/pet/corgi/Ian/Bump(atom/movable/AM as mob|obj, yes)
spawn( 0 )
if((!( yes ) || now_pushing))
return
now_pushing = 1
if(ismob(AM))
var/mob/tmob = AM
if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations))
if(prob(70))
to_chat(src, "<span class='danger'>You fail to push [tmob]'s fat ass out of the way.</span>")
now_pushing = 0
return
if(!(tmob.status_flags & CANPUSH))
now_pushing = 0
return
tmob.LAssailant = src
now_pushing = 0
..()
if(!( istype(AM, /atom/movable) ))
return
if(!( now_pushing ))
now_pushing = 1
if(!( AM.anchored ))
var/t = get_dir(src, AM)
if(istype(AM, /obj/structure/window/full))
for(var/obj/structure/window/win in get_step(AM,t))
now_pushing = 0
return
step(AM, t)
now_pushing = null
return
return
/mob/living/simple_animal/pet/corgi/regenerate_icons()
overlays.Cut()
if(inventory_head)
@@ -103,7 +103,7 @@ Difficulty: Hard
triple_charge()
else
spawn(0)
warp_charge()
warp_charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/New()
..()
@@ -186,7 +186,7 @@ Difficulty: Hard
shake_camera(L, 4, 3)
shake_camera(src, 2, 3)
var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(L, src)))
L.throw_at_fast(throwtarget, 3)
L.throw_at(throwtarget, 3)
charging = 0
@@ -238,7 +238,7 @@ Difficulty: Medium
if(L.loc == loc)
throw_dir = pick(alldirs)
var/throwtarget = get_edge_target_turf(src, throw_dir)
L.throw_at_fast(throwtarget, 3)
L.throw_at(throwtarget, 3)
visible_message("<span class='warning'>[L] is thrown clear of [src]!</span>")
for(var/mob/M in range(7, src))
@@ -123,7 +123,6 @@
//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
@@ -25,13 +25,12 @@
ts_spiderling_list -= src
return ..()
/obj/structure/spider/spiderling/terror_spiderling/Bump(atom/A)
if(istype(A, /obj/structure/table))
forceMove(A.loc)
else if(istype(A, /obj/machinery/recharge_station))
/obj/structure/spider/spiderling/terror_spiderling/Bump(obj/O)
if(istype(O, /obj/structure/table))
forceMove(O.loc)
else if(istype(O, /obj/machinery/recharge_station))
qdel(src)
else
..()
. = ..()
/obj/structure/spider/spiderling/terror_spiderling/process()
if(travelling_in_vent)
@@ -329,16 +329,17 @@ var/global/list/ts_spiderling_list = list()
/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_special_action()
return
/mob/living/simple_animal/hostile/poison/terror_spider/Bump(atom/A)
if(istype(A, /obj/machinery/door/airlock))
var/obj/machinery/door/airlock/L = A
/mob/living/simple_animal/hostile/poison/terror_spider/ObjBump(obj/O)
if(istype(O, /obj/machinery/door/airlock))
var/obj/machinery/door/airlock/L = O
if(L.density)
try_open_airlock(L)
if(istype(A, /obj/machinery/door/firedoor))
var/obj/machinery/door/firedoor/F = A
return try_open_airlock(L)
if(istype(O, /obj/machinery/door/firedoor))
var/obj/machinery/door/firedoor/F = O
if(F.density && !F.welded)
F.open()
..()
return 1
. = ..()
/mob/living/simple_animal/hostile/poison/terror_spider/proc/msg_terrorspiders(msgtext)
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in ts_spiderlist)
@@ -362,6 +363,7 @@ var/global/list/ts_spiderling_list = list()
to_chat(src, "<span class='warning'>The door is bolted shut.</span>")
else if(D.allowed(src))
D.open(1)
return 1
else if(D.arePowerSystemsOn() && (spider_opens_doors != 2))
to_chat(src, "<span class='warning'>The door's motors resist your efforts to force it.</span>")
else if(!spider_opens_doors)
@@ -369,4 +371,5 @@ var/global/list/ts_spiderling_list = list()
else
visible_message("<span class='danger'>[src] pries open the door!</span>")
playsound(src.loc, "sparks", 100, 1)
D.open(1)
D.open(1)
return 1
@@ -250,20 +250,6 @@
else if(bodytemperature > maxbodytemp)
adjustBruteLoss(heat_damage_per_tick)
/mob/living/simple_animal/Bumped(AM as mob|obj)
if(!AM) return
if(resting || buckled)
return
if(isturf(src.loc))
if((status_flags & CANPUSH) && ismob(AM))
var/newamloc = src.loc
src.loc = AM:loc
AM:loc = newamloc
else
..()
/mob/living/simple_animal/gib()
if(icon_gib)
flick(icon_gib, src)
+124 -133
View File
@@ -15,21 +15,27 @@
return 1
return (!mover.density || !density || lying)
//The byond version of these verbs wait for the next tick before acting.
// instant verbs however can run mid tick or even during the time between ticks.
/client/verb/moveup()
set name = ".moveup"
set instant = 1
Move(get_step(mob, NORTH), NORTH)
/client/North()
..()
/client/verb/movedown()
set name = ".movedown"
set instant = 1
Move(get_step(mob, SOUTH), SOUTH)
/client/verb/moveright()
set name = ".moveright"
set instant = 1
Move(get_step(mob, EAST), EAST)
/client/South()
..()
/client/West()
..()
/client/East()
..()
/client/verb/moveleft()
set name = ".moveleft"
set instant = 1
Move(get_step(mob, WEST), WEST)
/client/Northeast()
@@ -105,12 +111,11 @@
/client/verb/toggle_throw_mode()
set hidden = 1
if(!istype(mob, /mob/living/carbon))
return
if(!mob.stat && isturf(mob.loc) && !mob.restrained())
mob:toggle_throw_mode()
if(iscarbon(mob))
var/mob/living/carbon/C = mob
C.toggle_throw_mode()
else
return
to_chat(usr, "<span class='danger'>This mob type cannot throw items.</span>")
/client/verb/drop_item()
@@ -134,16 +139,16 @@
/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.dir = direct
step(mob.control_object, direct)
if(!mob.control_object)
return
mob.control_object.setDir(direct)
else
mob.control_object.forceMove(get_step(mob.control_object,direct))
mob.control_object.forceMove(get_step(mob.control_object, direct))
return
/client/Move(n, direct)
if(viewingCanvas)
view = world.view //Reset the view
winset(src, "mapwindow.map", "icon-size=[src.reset_stretch]")
@@ -152,19 +157,28 @@
if(mob.hud_used)
mob.hud_used.show_hud(HUD_STYLE_STANDARD)
if(mob.control_object) Move_object(direct)
if(world.time < move_delay)
return
if(world.time < move_delay) return
move_delay = world.time + world.tick_lag //this is here because Move() can now be called multiple times per tick
if(!mob || !mob.loc)
return 0
if(!isliving(mob)) return mob.Move(n,direct)
if(mob.notransform)
return 0 //This is sota the goto stop mobs from moving var
if(moving) return 0
if(mob.control_object)
return Move_object(direct)
if(!mob) return
if(!isliving(mob))
return mob.Move(n, direct)
if(mob.stat==DEAD) return
if(mob.stat == DEAD)
mob.ghostize()
return 0
if(mob.notransform) return//This is sota the goto stop mobs from moving var
if(moving)
return 0
if(isliving(mob))
var/mob/living/L = mob
@@ -172,126 +186,105 @@
Process_Incorpmove(direct)
return
if(Process_Grab()) return
if(mob.buckled) //if we're buckled to something, tell it we moved.
return mob.buckled.relaymove(mob, direct)
if(mob.remote_control) //we're controlling something, our movement is relayed to it
if(mob.remote_control) //we're controlling something, our movement is relayed to it
return mob.remote_control.relaymove(mob, direct)
if(isAI(mob))
if(istype(mob.loc, /obj/item/device/aicard))
var/obj/O = mob.loc
return O.relaymove(mob, direct) //aicards have special relaymove stuff
return AIMove(n,direct,mob)
return O.relaymove(mob, direct) // aicards have special relaymove stuff
return AIMove(n, direct, mob)
if(Process_Grab())
return
if(mob.buckled) //if we're buckled to something, tell it we moved.
return mob.buckled.relaymove(mob, direct)
if(!mob.canmove)
return
//if(istype(mob.loc, /turf/space) || (mob.flags & NOGRAV))
// if(!mob.Process_Spacemove(0)) return 0
if(!mob.lastarea)
mob.lastarea = get_area(mob.loc)
if(isobj(mob.loc) || ismob(mob.loc))//Inside an object, tell it we moved
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(istype(mob.get_active_hand(), /obj/item))
var/obj/item/I = mob.get_active_hand()
I.moved(mob, n, direct)
if(!mob.Process_Spacemove(direct))
return 0
return 0
if(isturf(mob.loc))
if(mob.restrained())//Why being pulled while cuffed prevents you from moving
for(var/mob/M in range(mob, 1))
if(M.pulling == mob)
if(!M.restrained() && M.stat == 0 && M.canmove && mob.Adjacent(M))
to_chat(src, "<span class='notice'>You're restrained! You can't move!</span>")
return 0
else
M.stop_pulling()
if(mob.pinned.len)
to_chat(src, "<span class='notice'>You're pinned to a wall by [mob.pinned[1]]!</span>")
return 0
var/turf/T = mob.loc
move_delay = world.time//set move delay
move_delay += T.slowdown
mob.last_movement = world.time
switch(mob.m_intent)
if("run")
if(mob.drowsyness > 0)
move_delay += 6
move_delay += 1+config.run_speed
if("walk")
move_delay += 1+config.walk_speed
move_delay += mob.movement_delay()
if(config.Tickcomp)
move_delay -= 1.3
var/tickcomp = ((1/(world.tick_lag))*1.3)
move_delay = move_delay + tickcomp
//We are now going to move
moving = 1
//Something with pulling things
if(locate(/obj/item/weapon/grab, mob))
move_delay = max(move_delay, world.time + 7)
var/list/L = mob.ret_grab()
if(istype(L, /list))
if(L.len == 2)
L -= mob
var/mob/M = L[1]
if(M)
if((get_dist(mob, M) <= 1 || M.loc == mob.loc))
. = ..()
if(isturf(M.loc))
var/diag = get_dir(mob, M)
if((diag - 1) & diag)
else
diag = null
if((get_dist(mob, M) > 1 || diag))
step(M, get_dir(M.loc, T))
if(mob.restrained()) // Why being pulled while cuffed prevents you from moving
for(var/mob/M in orange(1, mob))
if(M.pulling == mob)
if(!M.incapacitated() && mob.Adjacent(M))
to_chat(src, "<span class='warning'>You're restrained! You can't move!</span>")
move_delay = world.time + 10
return 0
else
for(var/mob/M in L)
M.other_mobs = 1
if(mob != M)
M.animate_movement = 3
for(var/mob/M in L)
spawn( 0 )
step(M, direct)
return
spawn( 1 )
M.other_mobs = null
M.animate_movement = 2
return
M.stop_pulling()
else if(mob.confused)
step(mob, pick(cardinal))
else
. = ..()
for(var/obj/item/weapon/grab/G in mob)
if(G.state == GRAB_NECK)
mob.setDir(reverse_dir[direct])
G.adjust_position()
for(var/obj/item/weapon/grab/G in mob.grabbed_by)
G.adjust_position()
//We are now going to move
moving = 1
move_delay = mob.movement_delay() + world.time
mob.last_movement = world.time
if(locate(/obj/item/weapon/grab, mob))
move_delay = max(move_delay, world.time + 7)
var/list/L = mob.ret_grab()
if(istype(L, /list))
if(L.len == 2)
L -= mob
var/mob/M = L[1]
if(M)
if((get_dist(mob, M) <= 1 || M.loc == mob.loc))
var/turf/prev_loc = mob.loc
. = ..()
if(M && isturf(M.loc)) // Mob may get deleted during parent call
var/diag = get_dir(mob, M)
if((diag - 1) & diag)
else
diag = null
if((get_dist(mob, M) > 1 || diag))
step(M, get_dir(M.loc, prev_loc))
else
for(var/mob/M in L)
M.other_mobs = 1
if(mob != M)
M.animate_movement = 3
for(var/mob/M in L)
spawn(0)
step(M, direct)
return
spawn(1)
M.other_mobs = null
M.animate_movement = 2
return
else if(mob.confused)
step(mob, pick(cardinal))
else
. = ..()
for(var/obj/item/weapon/grab/G in mob)
if(G.state == GRAB_NECK)
mob.setDir(reverse_dir[direct])
G.adjust_position()
for(var/obj/item/weapon/grab/G in mob.grabbed_by)
G.adjust_position()
moving = 0
if(mob && .)
if(mob.throwing)
mob.throwing.finalize(FALSE)
for(var/obj/O in mob)
O.on_mob_move(direct, mob)
moving = 0
if(mob && .)
mob.throwing = 0
return .
return
///Process_Grab()
@@ -408,13 +401,13 @@
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>"
var/opposite_dir = turn(movement_dir, 180)
if(backup.newtonian_move(opposite_dir)) //You're pushing off something movable, so it moves
to_chat(src, "<span class='notice'>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
@@ -434,9 +427,7 @@
return AM
if(pulling == AM)
continue
dense_object_backup = AM
break
. = dense_object_backup
. = AM
/mob/proc/mob_has_gravity(turf/T)
+5 -1
View File
@@ -15,7 +15,11 @@
return
stop_pulling()
src.pulling = AM
if(AM.pulledby)
visible_message("<span class='danger'>[src] has pulled [AM] from [AM.pulledby]'s grip.</span>")
AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once.
pulling = AM
AM.pulledby = src
if(pullin)
pullin.update_icon(src)
-5
View File
@@ -502,8 +502,3 @@ var/global/list/obj/item/device/pda/PDAs = list()
/obj/item/device/pda/process()
if(current_app)
current_app.program_process()
/obj/item/device/pda/hit_check(speed)
if(current_app)
current_app.program_hit_check()
..()
-6
View File
@@ -74,12 +74,6 @@
return
scan_nearby()
/datum/data/pda/app/mob_hunter_game/program_hit_check()
if(!pda)
return
for(var/obj/effect/nanomob/hit_mob in get_turf(pda))
hit_mob.hitby(pda)
/datum/data/pda/app/mob_hunter_game/proc/register_capture(datum/mob_hunt/captured, wild = 0)
if(!captured)
return 0
+3 -3
View File
@@ -16,10 +16,10 @@
return
/obj/item/weapon/gun/throw/proc/get_throwrange()
return projectile_speed
return projectile_range
/obj/item/weapon/gun/throw/proc/get_throwspeed()
return projectile_range
return projectile_speed
/obj/item/weapon/gun/throw/proc/modify_projectile(obj/item/I, on_chamber = 0)
return
@@ -80,7 +80,7 @@
to_launch = null
modify_projectile(I)
playsound(user, fire_sound, 50, 1)
I.throw_at(target, get_throwrange(), get_throwspeed(), user, 1)
I.throw_at(target, get_throwrange(), get_throwspeed(), user, FALSE)
message_admins("[key_name_admin(user)] fired \a [I] from a [src].")
log_game("[key_name_admin(user)] used \a [src].")
process_chamber()
-3
View File
@@ -206,9 +206,6 @@ ALLOW_HOLIDAYS
##Defines the ticklag for the world. 0.9 is the normal one, 0.5 is smoother.
TICKLAG 0.5
## Defines if Tick Compensation is used. It results in a minor slowdown of movement of all mobs, but attempts to result in a level movement speed across all ticks. Recommended if tickrate is lowered.
TICKCOMP 1
## Whether the server will talk to other processes through socket_talk
SOCKET_TALK 0
+7 -7
View File
@@ -38,17 +38,17 @@ REVIVAL_BRAIN_LIFE -1
## We suggest editing these variabled in-game to find a good speed for your server. To do this you must be a high level admin. Open the 'debug' tab ingame. Select "Debug Controller" and then, in the popup, select "Configuration". These variables should have the same name.
## These values get directly added to values and totals in-game. To speed things up make the number negative, to slow things down, make the number positive.
## These modify the run/walk speed of all mobs before the mob-specific modifiers are applied.
## These modify the run/walk speed of all mobs before the mob-specific modifiers are applied.
RUN_SPEED 1
WALK_SPEED 4
## The variables below affect the movement of specific mob types.
HUMAN_DELAY 0
ROBOT_DELAY 0
MONKEY_DELAY 0
ALIEN_DELAY 0
METROID_DELAY 0
ANIMAL_DELAY 0
HUMAN_DELAY 1.5
ROBOT_DELAY 1.5
MONKEY_DELAY 1.5
ALIEN_DELAY 1.5
METROID_DELAY 1.5
ANIMAL_DELAY 1.5
## Comment for "normal" explosions, which ignore obstacles
## Uncomment for explosions that react to doors and walls
+60 -60
View File
@@ -29,7 +29,7 @@ macro "AZERTYoff"
is-disabled = false
elem "AZRFF-WEST+REP"
name = "WEST+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "AZRFF-CTRL+NORTH"
name = "CTRL+NORTH"
@@ -37,7 +37,7 @@ macro "AZERTYoff"
is-disabled = false
elem "AZRFF-NORTH+REP"
name = "NORTH+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "AZRFF-CTRL+EAST"
name = "CTRL+EAST"
@@ -45,7 +45,7 @@ macro "AZERTYoff"
is-disabled = false
elem "AZRFF-EAST+REP"
name = "EAST+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "AZRFF-CTRL+SOUTH"
name = "CTRL+SOUTH"
@@ -53,7 +53,7 @@ macro "AZERTYoff"
is-disabled = false
elem "AZRFF-SOUTH+REP"
name = "SOUTH+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "AZRFF-INSERT"
name = "INSERT"
@@ -85,7 +85,7 @@ macro "AZERTYoff"
is-disabled = false
elem "AZRFF-CTRL+D+REP"
name = "CTRL+D+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "AZRFF-CTRL+B"
name = "CTRL+B"
@@ -105,7 +105,7 @@ macro "AZERTYoff"
is-disabled = false
elem "AZRFF-CTRL+Q+REP"
name = "CTRL+Q+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "AZRFF-CTRL+R"
name = "CTRL+R"
@@ -113,7 +113,7 @@ macro "AZERTYoff"
is-disabled = false
elem "AZRFF-CTRL+S+REP"
name = "CTRL+S+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "AZRFF-CTRL+W"
name = "CTRL+W"
@@ -129,7 +129,7 @@ macro "AZERTYoff"
is-disabled = false
elem "AZRFF-CTRL+Z+REP"
name = "CTRL+Z+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "AZRFF-F1"
name = "F1"
@@ -215,7 +215,7 @@ macro "AZERTYon"
is-disabled = false
elem "AZRON-WEST+REP"
name = "WEST+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "AZRON-CTRL+NORTH"
name = "CTRL+NORTH"
@@ -223,7 +223,7 @@ macro "AZERTYon"
is-disabled = false
elem "AZRON-NORTH+REP"
name = "NORTH+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "AZRON-CTRL+EAST"
name = "CTRL+EAST"
@@ -231,7 +231,7 @@ macro "AZERTYon"
is-disabled = false
elem "AZRON-EAST+REP"
name = "EAST+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "AZRON-CTRL+SOUTH"
name = "CTRL+SOUTH"
@@ -239,7 +239,7 @@ macro "AZERTYon"
is-disabled = false
elem "AZRON-SOUTH+REP"
name = "SOUTH+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "AZRON-INSERT"
name = "INSERT"
@@ -291,11 +291,11 @@ macro "AZERTYon"
is-disabled = false
elem "AZRON-D+REP"
name = "D+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "AZRON-CTRL+D+REP"
name = "CTRL+D+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "AZRON-CTRL+B"
name = "CTRL+B"
@@ -335,11 +335,11 @@ macro "AZERTYon"
is-disabled = false
elem "AZRON-Q+REP"
name = "Q+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "AZRON-CTRL+Q+REP"
name = "CTRL+Q+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "AZRON-R"
name = "R"
@@ -351,11 +351,11 @@ macro "AZERTYon"
is-disabled = false
elem "s_key"
name = "S+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "AZRON-CTRL+S+REP"
name = "CTRL+S+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "AZRON-T"
name = "T"
@@ -395,11 +395,11 @@ macro "AZERTYon"
is-disabled = false
elem "w_key"
name = "Z+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "AZRON-CTRL+Z+REP"
name = "CTRL+Z+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "AZRON-F1"
name = "F1"
@@ -481,7 +481,7 @@ macro "borghotkeymode"
is-disabled = false
elem "BRGHK-WEST+REP"
name = "WEST+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "BRGHK-CTRL+NORTH"
name = "CTRL+NORTH"
@@ -489,7 +489,7 @@ macro "borghotkeymode"
is-disabled = false
elem "BRGHK-NORTH+REP"
name = "NORTH+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "BRGHK-CTRL+EAST"
name = "CTRL+EAST"
@@ -497,7 +497,7 @@ macro "borghotkeymode"
is-disabled = false
elem "BRGHK-EAST+REP"
name = "EAST+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "BRGHK-CTRL+SOUTH"
name = "CTRL+SOUTH"
@@ -505,7 +505,7 @@ macro "borghotkeymode"
is-disabled = false
elem "BRGHK-SOUTH+REP"
name = "SOUTH+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "BRGHK-INSERT"
name = "INSERT"
@@ -549,11 +549,11 @@ macro "borghotkeymode"
is-disabled = false
elem "BRGHK-A+REP"
name = "A+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "BRGHK-CTRL+A+REP"
name = "CTRL+A+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "BRGHK-B"
name = "B"
@@ -581,11 +581,11 @@ macro "borghotkeymode"
is-disabled = false
elem "BRGHK-D+REP"
name = "D+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "BRGHK-CTRL+D+REP"
name = "CTRL+D+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "BRGHK-F"
name = "F"
@@ -613,19 +613,19 @@ macro "borghotkeymode"
is-disabled = false
elem "s_key"
name = "S+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "BRGHK-CTRL+S+REP"
name = "CTRL+S+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "w_key"
name = "W+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "BRGHK-CTRL+W+REP"
name = "CTRL+W+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "BRGHK-X"
name = "X"
@@ -735,7 +735,7 @@ macro "macro"
is-disabled = false
elem "MACRO-WEST+REP"
name = "WEST+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "MACRO-CTRL+NORTH"
name = "CTRL+NORTH"
@@ -743,7 +743,7 @@ macro "macro"
is-disabled = false
elem "MACRO-NORTH+REP"
name = "NORTH+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "MACRO-CTRL+EAST"
name = "CTRL+EAST"
@@ -751,7 +751,7 @@ macro "macro"
is-disabled = false
elem "MACRO-EAST+REP"
name = "EAST+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "MACRO-CTRL+SOUTH"
name = "CTRL+SOUTH"
@@ -759,7 +759,7 @@ macro "macro"
is-disabled = false
elem "MACRO-SOUTH+REP"
name = "SOUTH+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "MACRO-INSERT"
name = "INSERT"
@@ -787,11 +787,11 @@ macro "macro"
is-disabled = false
elem "MACRO-CTRL+A+REP"
name = "CTRL+A+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "MACRO-CTRL+D+REP"
name = "CTRL+D+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "MACRO-CTRL+B"
name = "CTRL+B"
@@ -819,11 +819,11 @@ macro "macro"
is-disabled = false
elem "MACRO-CTRL+S+REP"
name = "CTRL+S+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "MACRO-CTRL+W+REP"
name = "CTRL+W+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "MACRO-CTRL+X"
name = "CTRL+X"
@@ -921,7 +921,7 @@ macro "hotkeymode"
is-disabled = false
elem "HKMODE-WEST+REP"
name = "WEST+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "HKMODE-CTRL+NORTH"
name = "CTRL+NORTH"
@@ -929,7 +929,7 @@ macro "hotkeymode"
is-disabled = false
elem "HKMODE-NORTH+REP"
name = "NORTH+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "HKMODE-CTRL+EAST"
name = "CTRL+EAST"
@@ -937,7 +937,7 @@ macro "hotkeymode"
is-disabled = false
elem "HKMODE-EAST+REP"
name = "EAST+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "HKMODE-CTRL+SOUTH"
name = "CTRL+SOUTH"
@@ -945,7 +945,7 @@ macro "hotkeymode"
is-disabled = false
elem "HKMODE-SOUTH+REP"
name = "SOUTH+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "HKMODE-INSERT"
name = "INSERT"
@@ -1001,19 +1001,19 @@ macro "hotkeymode"
is-disabled = false
elem "HKMODE-A+REP"
name = "A+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "HKMODE-CTRL+A+REP"
name = "CTRL+A+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "HKMODE-D+REP"
name = "D+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "HKMODE-CTRL+D+REP"
name = "CTRL+D+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "HKMODE-B"
name = "B"
@@ -1073,11 +1073,11 @@ macro "hotkeymode"
is-disabled = false
elem "s_key"
name = "S+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "HKMODE-CTRL+S+REP"
name = "CTRL+S+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "HKMODE-T"
name = "T"
@@ -1085,11 +1085,11 @@ macro "hotkeymode"
is-disabled = false
elem "w_key"
name = "W+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "HKMODE-CTRL+W+REP"
name = "CTRL+W+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "HKMODE-X"
name = "X"
@@ -1195,7 +1195,7 @@ macro "borgmacro"
is-disabled = false
elem "BRGMACRO-WEST+REP"
name = "WEST+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "BRGMACRO-CTRL+NORTH"
name = "CTRL+NORTH"
@@ -1203,7 +1203,7 @@ macro "borgmacro"
is-disabled = false
elem "BRGMACRO-NORTH+REP"
name = "NORTH+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "BRGMACRO-CTRL+EAST"
name = "CTRL+EAST"
@@ -1211,7 +1211,7 @@ macro "borgmacro"
is-disabled = false
elem "BRGMACRO-EAST+REP"
name = "EAST+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "BRGMACRO-CTRL+SOUTH"
name = "CTRL+SOUTH"
@@ -1219,7 +1219,7 @@ macro "borgmacro"
is-disabled = false
elem "BRGMACRO-SOUTH+REP"
name = "SOUTH+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "BRGMACRO-INSERT"
name = "INSERT"
@@ -1247,7 +1247,7 @@ macro "borgmacro"
is-disabled = false
elem "BRGMACRO-CTRL+A+REP"
name = "CTRL+A+REP"
command = ".west"
command = ".moveleft"
is-disabled = false
elem "BRGMACRO-CTRL+B"
name = "CTRL+B"
@@ -1259,7 +1259,7 @@ macro "borgmacro"
is-disabled = false
elem "BRGMACRO-CTRL+D+REP"
name = "CTRL+D+REP"
command = ".east"
command = ".moveright"
is-disabled = false
elem "BRGMACRO-CTRL+F"
name = "CTRL+F"
@@ -1275,11 +1275,11 @@ macro "borgmacro"
is-disabled = false
elem "BRGMACRO-CTRL+S+REP"
name = "CTRL+S+REP"
command = ".south"
command = ".movedown"
is-disabled = false
elem "BRGMACRO-CTRL+W+REP"
name = "CTRL+W+REP"
command = ".north"
command = ".moveup"
is-disabled = false
elem "BRGMACRO-CTRL+X"
name = "CTRL+X"
+4
View File
@@ -19,6 +19,7 @@
#include "code\__DEFINES\admin.dm"
#include "code\__DEFINES\atmospherics.dm"
#include "code\__DEFINES\bots.dm"
#include "code\__DEFINES\callbacks.dm"
#include "code\__DEFINES\clothing.dm"
#include "code\__DEFINES\combat.dm"
#include "code\__DEFINES\construction.dm"
@@ -188,7 +189,9 @@
#include "code\controllers\Processes\obj.dm"
#include "code\controllers\Processes\pipenet.dm"
#include "code\controllers\Processes\shuttles.dm"
#include "code\controllers\Processes\spacedrift.dm"
#include "code\controllers\Processes\sun.dm"
#include "code\controllers\Processes\throwing.dm"
#include "code\controllers\Processes\ticker.dm"
#include "code\controllers\Processes\timer.dm"
#include "code\controllers\Processes\weather.dm"
@@ -199,6 +202,7 @@
#include "code\datums\ai_laws.dm"
#include "code\datums\beam.dm"
#include "code\datums\browser.dm"
#include "code\datums\callback.dm"
#include "code\datums\cargoprofile.dm"
#include "code\datums\computerfiles.dm"
#include "code\datums\datacore.dm"
Binary file not shown.