mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-22 11:37:40 +01:00
Merge pull request #7066 from tigercat2000/BumpRefactor
/tg/ Move refactor
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
#define CALLBACK new /datum/callback
|
||||
#define INVOKE_ASYNC ImmediateInvokeAsync
|
||||
@@ -70,3 +70,6 @@
|
||||
#define WEAPON_LIGHT 0
|
||||
#define WEAPON_MEDIUM 1
|
||||
#define WEAPON_HEAVY 2
|
||||
|
||||
// Embedded objects
|
||||
#define EMBED_THROWSPEED_THRESHOLD 15
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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>")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
..()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
..()
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user