Merge branch 'master' into upstream-merge-36722
This commit is contained in:
@@ -40,4 +40,11 @@
|
||||
#define CHAPLAIN (1<<10)
|
||||
#define CLOWN (1<<11)
|
||||
#define MIME (1<<12)
|
||||
#define ASSISTANT (1<<13)
|
||||
#define ASSISTANT (1<<13)
|
||||
|
||||
#define JOB_AVAILABLE 0
|
||||
#define JOB_UNAVAILABLE_GENERIC 1
|
||||
#define JOB_UNAVAILABLE_BANNED 2
|
||||
#define JOB_UNAVAILABLE_PLAYTIME 3
|
||||
#define JOB_UNAVAILABLE_ACCOUNTAGE 4
|
||||
#define JOB_UNAVAILABLE_SLOTFULL 5
|
||||
|
||||
+14
-16
@@ -116,6 +116,20 @@
|
||||
|
||||
#define GET_ANGLE_OF_INCIDENCE(face, input) (MODULUS((face) - (input), 360))
|
||||
|
||||
//Finds the shortest angle that angle A has to change to get to angle B. Aka, whether to move clock or counterclockwise.
|
||||
/proc/closer_angle_difference(a, b)
|
||||
if(!isnum(a) || !isnum(b))
|
||||
return
|
||||
a = SIMPLIFY_DEGREES(a)
|
||||
b = SIMPLIFY_DEGREES(b)
|
||||
var/inc = b - a
|
||||
if(inc < 0)
|
||||
inc += 360
|
||||
var/dec = a - b
|
||||
if(dec < 0)
|
||||
dec += 360
|
||||
. = inc > dec? -dec : inc
|
||||
|
||||
//A logarithm that converts an integer to a number scaled between 0 and 1.
|
||||
//Currently, this is used for hydroponics-produce sprite transforming, but could be useful for other transform functions.
|
||||
#define TRANSFORM_USING_VARIABLE(input, max) ( sin((90*(input))/(max))**2 )
|
||||
@@ -146,22 +160,6 @@
|
||||
return (mean + stddev * R1)
|
||||
#undef ACCURACY
|
||||
|
||||
/proc/mouse_angle_from_client(client/client)
|
||||
var/list/mouse_control = params2list(client.mouseParams)
|
||||
if(mouse_control["screen-loc"] && client)
|
||||
var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
|
||||
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
|
||||
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
|
||||
var/x = (text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32)
|
||||
var/y = (text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32)
|
||||
var/list/screenview = getviewsize(client.view)
|
||||
var/screenviewX = screenview[1] * world.icon_size
|
||||
var/screenviewY = screenview[2] * world.icon_size
|
||||
var/ox = round(screenviewX/2) - client.pixel_x //"origin" x
|
||||
var/oy = round(screenviewY/2) - client.pixel_y //"origin" y
|
||||
var/angle = SIMPLIFY_DEGREES(ATAN2(y - oy, x - ox))
|
||||
return angle
|
||||
|
||||
/proc/get_turf_in_angle(angle, turf/starting, increments)
|
||||
var/pixel_x = 0
|
||||
var/pixel_y = 0
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
|
||||
#define LAZYOR(L, I) if(!L) { L = list(); } L |= I;
|
||||
#define LAZYFIND(L, V) L ? L.Find(V) : 0
|
||||
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= length(L) ? L[I] : null) : L[I]) : null)
|
||||
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
|
||||
#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V;
|
||||
#define LAZYLEN(L) length(L)
|
||||
#define LAZYCLEARLIST(L) if(L) L.Cut()
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
return null
|
||||
return format_text ? format_text(A.name) : A.name
|
||||
|
||||
/proc/get_area_by_name(N) //get area by its name
|
||||
for(var/area/A in world)
|
||||
if(A.name == N)
|
||||
return A
|
||||
return 0
|
||||
|
||||
/proc/get_areas_in_range(dist=0, atom/center=usr)
|
||||
if(!dist)
|
||||
var/turf/T = get_turf(center)
|
||||
@@ -387,44 +381,6 @@
|
||||
active_players++
|
||||
return active_players
|
||||
|
||||
/datum/projectile_data
|
||||
var/src_x
|
||||
var/src_y
|
||||
var/time
|
||||
var/distance
|
||||
var/power_x
|
||||
var/power_y
|
||||
var/dest_x
|
||||
var/dest_y
|
||||
|
||||
/datum/projectile_data/New(var/src_x, var/src_y, var/time, var/distance, \
|
||||
var/power_x, var/power_y, var/dest_x, var/dest_y)
|
||||
src.src_x = src_x
|
||||
src.src_y = src_y
|
||||
src.time = time
|
||||
src.distance = distance
|
||||
src.power_x = power_x
|
||||
src.power_y = power_y
|
||||
src.dest_x = dest_x
|
||||
src.dest_y = dest_y
|
||||
|
||||
/proc/projectile_trajectory(src_x, src_y, rotation, angle, power)
|
||||
|
||||
// returns the destination (Vx,y) that a projectile shot at [src_x], [src_y], with an angle of [angle],
|
||||
// rotated at [rotation] and with the power of [power]
|
||||
// Thanks to VistaPOWA for this function
|
||||
|
||||
var/power_x = power * cos(angle)
|
||||
var/power_y = power * sin(angle)
|
||||
var/time = 2* power_y / 10 //10 = g
|
||||
|
||||
var/distance = time * power_x
|
||||
|
||||
var/dest_x = src_x + distance*sin(rotation);
|
||||
var/dest_y = src_y + distance*cos(rotation);
|
||||
|
||||
return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y)
|
||||
|
||||
/proc/showCandidatePollWindow(mob/M, poll_time, Question, list/candidates, ignore_category, time_passed, flashwindow = TRUE)
|
||||
set waitfor = 0
|
||||
|
||||
|
||||
+6
-21
@@ -1041,7 +1041,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
||||
return 0
|
||||
|
||||
//For creating consistent icons for human looking simple animals
|
||||
/proc/get_flat_human_icon(icon_id, datum/job/J, datum/preferences/prefs, dummy_key)
|
||||
/proc/get_flat_human_icon(icon_id, datum/job/J, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals)
|
||||
var/static/list/humanoid_icon_cache = list()
|
||||
if(!icon_id || !humanoid_icon_cache[icon_id])
|
||||
var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key)
|
||||
@@ -1053,26 +1053,11 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
||||
|
||||
|
||||
var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing")
|
||||
|
||||
body.setDir(NORTH)
|
||||
COMPILE_OVERLAYS(body)
|
||||
var/icon/partial = getFlatIcon(body)
|
||||
out_icon.Insert(partial,dir=NORTH)
|
||||
|
||||
body.setDir(SOUTH)
|
||||
COMPILE_OVERLAYS(body)
|
||||
partial = getFlatIcon(body)
|
||||
out_icon.Insert(partial,dir=SOUTH)
|
||||
|
||||
body.setDir(WEST)
|
||||
COMPILE_OVERLAYS(body)
|
||||
partial = getFlatIcon(body)
|
||||
out_icon.Insert(partial,dir=WEST)
|
||||
|
||||
body.setDir(EAST)
|
||||
COMPILE_OVERLAYS(body)
|
||||
partial = getFlatIcon(body)
|
||||
out_icon.Insert(partial,dir=EAST)
|
||||
for(var/D in showDirs)
|
||||
body.setDir(D)
|
||||
COMPILE_OVERLAYS(body)
|
||||
var/icon/partial = getFlatIcon(body)
|
||||
out_icon.Insert(partial,dir=D)
|
||||
|
||||
humanoid_icon_cache[icon_id] = out_icon
|
||||
dummy_key? unset_busy_human_dummy(dummy_key) : qdel(body)
|
||||
|
||||
@@ -288,7 +288,7 @@ Proc for attack log creation, because really why not
|
||||
|
||||
var/hp =" "
|
||||
if(living_target)
|
||||
hp = "(NEWHP: [living_target.health])"
|
||||
hp = " (NEWHP: [living_target.health]) "
|
||||
|
||||
var/starget = "NON-EXISTENT SUBJECT"
|
||||
if(target)
|
||||
@@ -307,20 +307,22 @@ Proc for attack log creation, because really why not
|
||||
var/sobject = ""
|
||||
if(object)
|
||||
sobject = "[object]"
|
||||
if(addition)
|
||||
addition = " [addition]"
|
||||
|
||||
var/sattackloc = ""
|
||||
if(attack_location)
|
||||
sattackloc = "([attack_location.x],[attack_location.y],[attack_location.z])"
|
||||
|
||||
if(is_mob_user)
|
||||
var/message = "<font color='red'>has [what_done] [starget] with [sobject][addition] [hp] [sattackloc]</font>"
|
||||
var/message = "<font color='red'>has [what_done] [starget][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]</font>"
|
||||
user.log_message(message, INDIVIDUAL_ATTACK_LOG)
|
||||
|
||||
if(is_mob_target)
|
||||
var/message = "<font color='orange'>has been [what_done] by [ssource] with [sobject][addition] [hp] [sattackloc]</font>"
|
||||
var/message = "<font color='orange'>has been [what_done] by [ssource][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]</font>"
|
||||
target.log_message(message, INDIVIDUAL_ATTACK_LOG)
|
||||
|
||||
log_attack("[ssource] [what_done] [starget] with [sobject][addition] [hp] [sattackloc]")
|
||||
log_attack("[ssource] [what_done] [starget][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]")
|
||||
|
||||
|
||||
/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/proc/mouse_angle_from_client(client/client)
|
||||
var/list/mouse_control = params2list(client.mouseParams)
|
||||
if(mouse_control["screen-loc"] && client)
|
||||
var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
|
||||
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
|
||||
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
|
||||
var/x = (text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32)
|
||||
var/y = (text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32)
|
||||
var/list/screenview = getviewsize(client.view)
|
||||
var/screenviewX = screenview[1] * world.icon_size
|
||||
var/screenviewY = screenview[2] * world.icon_size
|
||||
var/ox = round(screenviewX/2) - client.pixel_x //"origin" x
|
||||
var/oy = round(screenviewY/2) - client.pixel_y //"origin" y
|
||||
var/angle = SIMPLIFY_DEGREES(ATAN2(y - oy, x - ox))
|
||||
return angle
|
||||
|
||||
//Wow, specific name!
|
||||
/proc/mouse_absolute_datum_map_position_from_client(client/client)
|
||||
if(!isloc(client.mob.loc))
|
||||
return
|
||||
var/list/mouse_control = params2list(client.mouseParams)
|
||||
var/cx = client.mob.x
|
||||
var/cy = client.mob.y
|
||||
var/cz = client.mob.z
|
||||
if(mouse_control["screen-loc"])
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/z = 0
|
||||
var/p_x = 0
|
||||
var/p_y = 0
|
||||
//Split screen-loc up into X+Pixel_X and Y+Pixel_Y
|
||||
var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
|
||||
//Split X+Pixel_X up into list(X, Pixel_X)
|
||||
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
|
||||
//Split Y+Pixel_Y up into list(Y, Pixel_Y)
|
||||
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
|
||||
var/sx = text2num(screen_loc_X[1])
|
||||
var/sy = text2num(screen_loc_Y[1])
|
||||
//Get the resolution of the client's current screen size.
|
||||
var/list/screenview = getviewsize(client.view)
|
||||
var/svx = screenview[1]
|
||||
var/svy = screenview[2]
|
||||
var/cox = round((svx - 1) / 2)
|
||||
var/coy = round((svy - 1) / 2)
|
||||
x = cx + (sx - 1 - cox)
|
||||
y = cy + (sy - 1 - coy)
|
||||
z = cz
|
||||
p_x = text2num(screen_loc_X[2])
|
||||
p_y = text2num(screen_loc_Y[2])
|
||||
return new /datum/position(x, y, z, p_x, p_y)
|
||||
@@ -20,7 +20,7 @@
|
||||
if(isnewplayer(m))
|
||||
continue
|
||||
if(m.mind)
|
||||
if(m.stat != DEAD && !isbrain(m))
|
||||
if(m.stat != DEAD && !isbrain(m) && !iscameramob(m))
|
||||
num_survivors++
|
||||
mob_data += list("name" = m.name, "ckey" = ckey(m.mind.key))
|
||||
if(isobserver(m))
|
||||
@@ -41,9 +41,9 @@
|
||||
if(iscyborg(L))
|
||||
var/mob/living/silicon/robot/R = L
|
||||
mob_data += list("module" = R.module)
|
||||
else
|
||||
category = "others"
|
||||
mob_data += list("typepath" = L.type)
|
||||
else
|
||||
category = "others"
|
||||
mob_data += list("typepath" = m.type)
|
||||
if(!escaped)
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED && (m.onCentCom() || m.onSyndieBase()))
|
||||
escaped = "escapees"
|
||||
@@ -60,8 +60,12 @@
|
||||
file_data["[escaped]"]["npcs"]["[initial(m.name)]"] = 1
|
||||
else
|
||||
if(isobserver(m))
|
||||
file_data["[escaped]"] = mob_data
|
||||
var/pos = length(file_data["[escaped]"]) + 1
|
||||
file_data["[escaped]"]["[pos]"] = mob_data
|
||||
else
|
||||
if(!category)
|
||||
category = "others"
|
||||
mob_data += list("name" = m.name, "typepath" = m.type)
|
||||
var/pos = length(file_data["[escaped]"]["[category]"]) + 1
|
||||
file_data["[escaped]"]["[category]"]["[pos]"] = mob_data
|
||||
var/datum/station_state/end_state = new /datum/station_state()
|
||||
@@ -504,7 +508,7 @@
|
||||
/datum/controller/subsystem/ticker/proc/save_admin_data()
|
||||
if(CONFIG_GET(flag/admin_legacy_system)) //we're already using legacy system so there's nothing to save
|
||||
return
|
||||
else if(load_admins()) //returns true if there was a database failure and the backup was loaded from
|
||||
else if(load_admins(TRUE)) //returns true if there was a database failure and the backup was loaded from
|
||||
return
|
||||
var/datum/DBQuery/query_admin_rank_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] p INNER JOIN [format_table_name("admin")] a ON p.ckey = a.ckey SET p.lastadminrank = a.rank")
|
||||
query_admin_rank_update.Execute()
|
||||
|
||||
@@ -734,3 +734,36 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
||||
. = base
|
||||
if(rest)
|
||||
. += .(rest)
|
||||
|
||||
//Replacement for the \th macro when you want the whole word output as text (first instead of 1st)
|
||||
/proc/thtotext(number)
|
||||
if(!isnum(number))
|
||||
return
|
||||
switch(number)
|
||||
if(1)
|
||||
return "first"
|
||||
if(2)
|
||||
return "second"
|
||||
if(3)
|
||||
return "third"
|
||||
if(4)
|
||||
return "fourth"
|
||||
if(5)
|
||||
return "fifth"
|
||||
if(6)
|
||||
return "sixth"
|
||||
if(7)
|
||||
return "seventh"
|
||||
if(8)
|
||||
return "eighth"
|
||||
if(9)
|
||||
return "ninth"
|
||||
if(10)
|
||||
return "tenth"
|
||||
if(11)
|
||||
return "eleventh"
|
||||
if(12)
|
||||
return "twelfth"
|
||||
else
|
||||
return "[number]\th"
|
||||
|
||||
@@ -1301,8 +1301,12 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
|
||||
if(!istype(C))
|
||||
return
|
||||
|
||||
var/animate_color = initial(C.color)
|
||||
var/datum/client_colour/CC = C.mob.client_colours[1]
|
||||
if(CC)
|
||||
animate_color = CC.colour
|
||||
C.color = flash_color
|
||||
animate(C, color = initial(C.color), time = flash_time)
|
||||
animate(C, color = animate_color, time = flash_time)
|
||||
|
||||
#define RANDOM_COLOUR (rgb(rand(0,255),rand(0,255),rand(0,255)))
|
||||
|
||||
@@ -1572,3 +1576,54 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
|
||||
/proc/get_random_drink()
|
||||
return pick(subtypesof(/obj/item/reagent_containers/food/drinks))
|
||||
|
||||
//For these two procs refs MUST be ref = TRUE format like typecaches!
|
||||
/proc/weakref_filter_list(list/things, list/refs)
|
||||
if(!islist(things) || !islist(refs))
|
||||
return
|
||||
if(!refs.len)
|
||||
return things
|
||||
if(things.len > refs.len)
|
||||
var/list/f = list()
|
||||
for(var/i in refs)
|
||||
var/datum/weakref/r = i
|
||||
var/datum/d = r.resolve()
|
||||
if(d)
|
||||
f |= d
|
||||
return things & f
|
||||
|
||||
else
|
||||
. = list()
|
||||
for(var/i in things)
|
||||
if(!refs[WEAKREF(i)])
|
||||
continue
|
||||
. |= i
|
||||
|
||||
/proc/weakref_filter_list_reverse(list/things, list/refs)
|
||||
if(!islist(things) || !islist(refs))
|
||||
return
|
||||
if(!refs.len)
|
||||
return things
|
||||
if(things.len > refs.len)
|
||||
var/list/f = list()
|
||||
for(var/i in refs)
|
||||
var/datum/weakref/r = i
|
||||
var/datum/d = r.resolve()
|
||||
if(d)
|
||||
f |= d
|
||||
|
||||
return things - f
|
||||
else
|
||||
. = list()
|
||||
for(var/i in things)
|
||||
if(refs[WEAKREF(i)])
|
||||
continue
|
||||
. |= i
|
||||
|
||||
/proc/special_list_filter(list/L, datum/callback/condition)
|
||||
if(!islist(L) || !length(L) || !istype(condition))
|
||||
return list()
|
||||
. = list()
|
||||
for(var/i in L)
|
||||
if(condition.Invoke(i))
|
||||
. |= i
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
|
||||
/datum/projectile_data
|
||||
var/src_x
|
||||
var/src_y
|
||||
var/time
|
||||
var/distance
|
||||
var/power_x
|
||||
var/power_y
|
||||
var/dest_x
|
||||
var/dest_y
|
||||
|
||||
/datum/projectile_data/New(var/src_x, var/src_y, var/time, var/distance, \
|
||||
var/power_x, var/power_y, var/dest_x, var/dest_y)
|
||||
src.src_x = src_x
|
||||
src.src_y = src_y
|
||||
src.time = time
|
||||
src.distance = distance
|
||||
src.power_x = power_x
|
||||
src.power_y = power_y
|
||||
src.dest_x = dest_x
|
||||
src.dest_y = dest_y
|
||||
|
||||
/proc/projectile_trajectory(src_x, src_y, rotation, angle, power)
|
||||
|
||||
// returns the destination (Vx,y) that a projectile shot at [src_x], [src_y], with an angle of [angle],
|
||||
// rotated at [rotation] and with the power of [power]
|
||||
// Thanks to VistaPOWA for this function
|
||||
|
||||
var/power_x = power * cos(angle)
|
||||
var/power_y = power * sin(angle)
|
||||
var/time = 2* power_y / 10 //10 = g
|
||||
|
||||
var/distance = time * power_x
|
||||
|
||||
var/dest_x = src_x + distance*sin(rotation);
|
||||
var/dest_y = src_y + distance*cos(rotation);
|
||||
|
||||
return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y)
|
||||
@@ -77,10 +77,10 @@
|
||||
mouseObject = object
|
||||
mouseControlObject = control
|
||||
if(mob && LAZYLEN(mob.mousemove_intercept_objects))
|
||||
for(var/obj/item/I in mob.mousemove_intercept_objects)
|
||||
I.onMouseMove(object, location, control, params)
|
||||
for(var/datum/D in mob.mousemove_intercept_objects)
|
||||
D.onMouseMove(object, location, control, params)
|
||||
|
||||
/obj/item/proc/onMouseMove(object, location, control, params)
|
||||
/datum/proc/onMouseMove(object, location, control, params)
|
||||
return
|
||||
|
||||
/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
|
||||
|
||||
@@ -129,6 +129,9 @@
|
||||
/datum/config_entry/flag/enable_localhost_rank //Gives the !localhost! rank to any client connecting from 127.0.0.1 or ::1
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/flag/load_legacy_ranks_only //Loads admin ranks only from legacy admin_ranks.txt, while enabled ranks are mirrored to the database
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/string/hostedby
|
||||
|
||||
/datum/config_entry/flag/norespawn
|
||||
|
||||
@@ -62,7 +62,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/static/current_ticklimit = TICK_LIMIT_RUNNING
|
||||
|
||||
/datum/controller/master/New()
|
||||
config = new
|
||||
if(!config)
|
||||
config = new
|
||||
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
|
||||
|
||||
if(!random_seed)
|
||||
|
||||
@@ -7,7 +7,7 @@ SUBSYSTEM_DEF(mobs)
|
||||
var/list/currentrun = list()
|
||||
var/static/list/clients_by_zlevel[][]
|
||||
var/static/list/cubemonkeys = list()
|
||||
var/cubemonkeycap = 20
|
||||
var/cubemonkeycap = 64
|
||||
|
||||
/datum/controller/subsystem/mobs/stat_entry()
|
||||
..("P:[GLOB.mob_living_list.len]")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SUBSYSTEM_DEF(pathfinder)
|
||||
name = "pathfinder"
|
||||
name = "Pathfinder"
|
||||
init_order = INIT_ORDER_PATH
|
||||
flags = SS_NO_FIRE
|
||||
var/datum/flowcache/mobs
|
||||
@@ -19,7 +19,7 @@ SUBSYSTEM_DEF(pathfinder)
|
||||
var/list/flow
|
||||
|
||||
/datum/flowcache/New(var/n)
|
||||
.=..()
|
||||
. = ..()
|
||||
lcount = n
|
||||
run = 0
|
||||
free = 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#define MAX_THROWING_DIST 512 // 2 z-levels on default width
|
||||
#define MAX_THROWING_DIST 1280 // 5 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.
|
||||
|
||||
SUBSYSTEM_DEF(throwing)
|
||||
@@ -107,7 +107,7 @@ SUBSYSTEM_DEF(throwing)
|
||||
return
|
||||
|
||||
dist_travelled++
|
||||
|
||||
|
||||
if (dist_travelled > MAX_THROWING_DIST)
|
||||
finalize()
|
||||
return
|
||||
|
||||
@@ -71,14 +71,16 @@
|
||||
if(!owner.can_hear() || world.time < next_scare) //words can't trigger you if you can't hear them *taps head*
|
||||
return message
|
||||
for(var/word in trigger_words)
|
||||
if(findtext(raw_message, word))
|
||||
var/reg = regex(@"[^\l][REGEX_QUOTE(word)]*s[^\l]")
|
||||
if(findtext(raw_message, reg))
|
||||
addtimer(CALLBACK(src, .proc/freak_out, null, word), 10) //to react AFTER the chat message
|
||||
break
|
||||
return message
|
||||
|
||||
/datum/brain_trauma/mild/phobia/on_say(message)
|
||||
for(var/word in trigger_words)
|
||||
if(findtext(message, word))
|
||||
var/reg = regex(@"[^\l][REGEX_QUOTE(word)]*s[^\l]")
|
||||
if(findtext(message, reg))
|
||||
to_chat(owner, "<span class='warning'>You can't bring yourself to say the word \"[word]\"!</span>")
|
||||
return ""
|
||||
return message
|
||||
@@ -114,4 +116,4 @@
|
||||
owner.dizziness += 10
|
||||
owner.confused += 10
|
||||
owner.Jitter(10)
|
||||
owner.stuttering += 10
|
||||
owner.stuttering += 10
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
var/datum/callback_select/CS = new(count, savereturns)
|
||||
for (var/i in 1 to count)
|
||||
CS.invoke_callback(i, callbacks[i], callback_args[i], savereturns)
|
||||
|
||||
|
||||
while(CS.pendingcount)
|
||||
sleep(resolution*world.tick_lag)
|
||||
return CS.finished
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
#define LOCKON_AIMING_MAX_CURSOR_RADIUS 7
|
||||
#define LOCKON_IGNORE_RESULT "ignore_my_result"
|
||||
#define LOCKON_RANGING_BREAK_CHECK if(current_ranging_id != this_id){return LOCKON_IGNORE_RESULT}
|
||||
|
||||
/datum/component/lockon_aiming
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
var/lock_icon = 'icons/mob/blob.dmi'
|
||||
var/lock_icon_state = "marker"
|
||||
var/mutable_appearance/lock_appearance
|
||||
var/list/image/lock_images
|
||||
var/list/target_typecache
|
||||
var/list/immune_weakrefs //list(weakref = TRUE)
|
||||
var/mob_stat_check = TRUE //if a potential target is a mob make sure it's conscious!
|
||||
var/lock_amount = 1
|
||||
var/lock_cursor_range = 5
|
||||
var/list/locked_weakrefs
|
||||
var/update_disabled = FALSE
|
||||
var/current_ranging_id = 0
|
||||
var/list/last_location
|
||||
var/datum/callback/on_lock
|
||||
var/datum/callback/can_target_callback
|
||||
|
||||
/datum/component/lockon_aiming/Initialize(range, list/typecache, amount, list/immune, datum/callback/when_locked, icon, icon_state, datum/callback/target_callback)
|
||||
if(!ismob(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Lockon aiming component attempted to be added to a non mob!")
|
||||
if(target_callback)
|
||||
can_target_callback = target_callback
|
||||
else
|
||||
can_target_callback = CALLBACK(src, .proc/can_target)
|
||||
if(range)
|
||||
lock_cursor_range = range
|
||||
if(typecache)
|
||||
target_typecache = typecache
|
||||
if(amount)
|
||||
lock_amount = amount
|
||||
immune_weakrefs = list(WEAKREF(parent) = TRUE) //Manually take this out if you want..
|
||||
if(immune)
|
||||
for(var/i in immune)
|
||||
if(isweakref(i))
|
||||
immune_weakrefs[i] = TRUE
|
||||
else if(isatom(i))
|
||||
immune_weakrefs[WEAKREF(i)] = TRUE
|
||||
if(when_locked)
|
||||
on_lock = when_locked
|
||||
if(icon)
|
||||
lock_icon = icon
|
||||
if(icon_state)
|
||||
lock_icon_state = icon_state
|
||||
generate_lock_visuals()
|
||||
var/mob/M = parent
|
||||
LAZYOR(M.mousemove_intercept_objects, src)
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/datum/component/lockon_aiming/Destroy()
|
||||
var/mob/M = parent
|
||||
clear_visuals()
|
||||
LAZYREMOVE(M.mousemove_intercept_objects, src)
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/datum/component/lockon_aiming/proc/show_visuals()
|
||||
LAZYINITLIST(lock_images)
|
||||
var/mob/M = parent
|
||||
if(!M.client)
|
||||
return
|
||||
for(var/i in locked_weakrefs)
|
||||
var/datum/weakref/R = i
|
||||
var/atom/A = R.resolve()
|
||||
if(!A)
|
||||
continue //It'll be cleared by processing.
|
||||
var/image/I = new
|
||||
I.appearance = lock_appearance
|
||||
I.loc = A
|
||||
M.client.images |= I
|
||||
lock_images |= I
|
||||
|
||||
/datum/component/lockon_aiming/proc/clear_visuals()
|
||||
var/mob/M = parent
|
||||
if(!M.client)
|
||||
return
|
||||
if(!lock_images)
|
||||
return
|
||||
for(var/i in lock_images)
|
||||
M.client.images -= i
|
||||
qdel(i)
|
||||
lock_images.Cut()
|
||||
|
||||
/datum/component/lockon_aiming/proc/refresh_visuals()
|
||||
clear_visuals()
|
||||
show_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/generate_lock_visuals()
|
||||
lock_appearance = mutable_appearance(icon = lock_icon, icon_state = lock_icon_state, layer = FLOAT_LAYER)
|
||||
|
||||
/datum/component/lockon_aiming/proc/unlock_all(refresh_vis = TRUE)
|
||||
LAZYCLEARLIST(locked_weakrefs)
|
||||
if(refresh_vis)
|
||||
refresh_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/unlock(atom/A, refresh_vis = TRUE)
|
||||
if(!A.weak_reference)
|
||||
return
|
||||
LAZYREMOVE(locked_weakrefs, A.weak_reference)
|
||||
if(refresh_vis)
|
||||
refresh_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/lock(atom/A, refresh_vis = TRUE)
|
||||
LAZYOR(locked_weakrefs, WEAKREF(A))
|
||||
if(refresh_vis)
|
||||
refresh_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/add_immune_atom(atom/A)
|
||||
var/datum/weakref/R = WEAKREF(A)
|
||||
if(immune_weakrefs && (immune_weakrefs[R]))
|
||||
return
|
||||
LAZYSET(immune_weakrefs, R, TRUE)
|
||||
|
||||
/datum/component/lockon_aiming/proc/remove_immune_atom(atom/A)
|
||||
if(!A.weak_reference || !immune_weakrefs) //if A doesn't have a weakref how did it get on the immunity list?
|
||||
return
|
||||
LAZYREMOVE(immune_weakrefs, A.weak_reference)
|
||||
|
||||
/datum/component/lockon_aiming/onMouseMove(object,location,control,params)
|
||||
var/mob/M = parent
|
||||
if(!istype(M) || !M.client)
|
||||
return
|
||||
var/datum/position/P = mouse_absolute_datum_map_position_from_client(M.client)
|
||||
if(!P)
|
||||
return
|
||||
var/turf/T = P.return_turf()
|
||||
LAZYINITLIST(last_location)
|
||||
if(length(last_location) == 3 && last_location[1] == T.x && last_location[2] == T.y && last_location[3] == T.z)
|
||||
return //Same turf, don't bother.
|
||||
if(last_location)
|
||||
last_location.Cut()
|
||||
else
|
||||
last_location = list()
|
||||
last_location.len = 3
|
||||
last_location[1] = T.x
|
||||
last_location[2] = T.y
|
||||
last_location[3] = T.z
|
||||
autolock()
|
||||
|
||||
/datum/component/lockon_aiming/process()
|
||||
if(update_disabled)
|
||||
return
|
||||
if(!last_location)
|
||||
return
|
||||
var/changed = FALSE
|
||||
for(var/i in locked_weakrefs)
|
||||
var/datum/weakref/R = i
|
||||
if(istype(R))
|
||||
var/atom/thing = R.resolve()
|
||||
if(!istype(thing) || (get_dist(thing, locate(last_location[1], last_location[2], last_location[3])) > lock_cursor_range))
|
||||
unlock(R)
|
||||
changed = TRUE
|
||||
else
|
||||
unlock(R)
|
||||
changed = TRUE
|
||||
if(changed)
|
||||
autolock()
|
||||
|
||||
/datum/component/lockon_aiming/proc/autolock()
|
||||
var/mob/M = parent
|
||||
if(!M.client)
|
||||
return FALSE
|
||||
var/datum/position/current = mouse_absolute_datum_map_position_from_client(M.client)
|
||||
var/turf/target = current.return_turf()
|
||||
var/list/atom/targets = get_nearest(target, target_typecache, lock_amount, lock_cursor_range)
|
||||
if(targets == LOCKON_IGNORE_RESULT)
|
||||
return
|
||||
unlock_all(FALSE)
|
||||
for(var/i in targets)
|
||||
if(immune_weakrefs[WEAKREF(i)])
|
||||
continue
|
||||
lock(i, FALSE)
|
||||
refresh_visuals()
|
||||
on_lock.Invoke(locked_weakrefs)
|
||||
|
||||
/datum/component/lockon_aiming/proc/can_target(atom/A)
|
||||
var/mob/M = A
|
||||
return is_type_in_typecache(A, target_typecache) && !(ismob(A) && mob_stat_check && M.stat != CONSCIOUS) && !immune_weakrefs[WEAKREF(A)]
|
||||
|
||||
/datum/component/lockon_aiming/proc/get_nearest(turf/T, list/typecache, amount, range)
|
||||
current_ranging_id++
|
||||
var/this_id = current_ranging_id
|
||||
var/list/L = list()
|
||||
var/turf/center = get_turf(T)
|
||||
if(amount < 1 || range < 0 || !istype(center) || !islist(typecache))
|
||||
return
|
||||
if(range == 0)
|
||||
return typecache_filter_list(T.contents + T, typecache)
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/cd = 0
|
||||
while(cd <= range)
|
||||
x = center.x - cd + 1
|
||||
y = center.y + cd
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
for(x in x to center.x + cd)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
y = center.y + cd - 1
|
||||
x = center.x + cd
|
||||
for(y in center.y - cd to y)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
y = center.y - cd
|
||||
x = center.x + cd - 1
|
||||
for(x in center.x - cd to x)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
y = center.y - cd + 1
|
||||
x = center.x - cd
|
||||
for(y in y to center.y + cd)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
cd++
|
||||
CHECK_TICK
|
||||
|
||||
/datum/component/lockon_aiming/OnTransfer(datum/new_parent)
|
||||
CRASH("Warning: Lockon aiming component transfer attempted, but transfer behavior is not implemented!")
|
||||
@@ -68,7 +68,7 @@
|
||||
var/datum/mood_event/event = mood_events[i]
|
||||
msg += event.description
|
||||
else
|
||||
msg += "<span class='nicegreen'>Nothing special has happend to me lately!<span>\n"
|
||||
msg += "<span class='nicegreen'>Nothing special has happened to me lately!<span>\n"
|
||||
to_chat(owner, msg)
|
||||
|
||||
/datum/component/mood/proc/update_mood() //Called whenever a mood event is added or removed
|
||||
|
||||
@@ -199,6 +199,7 @@
|
||||
|
||||
/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C)
|
||||
set waitfor = FALSE
|
||||
var/static/list/show_directions = list(SOUTH, WEST)
|
||||
if(H.mind && (H.mind.assigned_role != H.mind.special_role))
|
||||
var/assignment
|
||||
if(H.mind.assigned_role)
|
||||
@@ -212,11 +213,14 @@
|
||||
var/id = num2hex(record_id_num++,6)
|
||||
if(!C)
|
||||
C = H.client
|
||||
var/image = get_id_photo(H, C)
|
||||
var/image = get_id_photo(H, C, show_directions)
|
||||
var/obj/item/photo/photo_front = new()
|
||||
var/obj/item/photo/photo_side = new()
|
||||
photo_front.photocreate(null, icon(image, dir = SOUTH))
|
||||
photo_side.photocreate(null, icon(image, dir = WEST))
|
||||
for(var/D in show_directions)
|
||||
if(D == SOUTH)
|
||||
photo_front.photocreate(null, icon(image, dir = D))
|
||||
if(D == WEST || D == EAST)
|
||||
photo_side.photocreate(null, icon(image, dir = D))
|
||||
|
||||
//These records should ~really~ be merged or something
|
||||
//General Record
|
||||
@@ -279,11 +283,11 @@
|
||||
locked += L
|
||||
return
|
||||
|
||||
/datum/datacore/proc/get_id_photo(mob/living/carbon/human/H, client/C)
|
||||
/datum/datacore/proc/get_id_photo(mob/living/carbon/human/H, client/C, show_directions = list(SOUTH))
|
||||
var/datum/job/J = SSjob.GetJob(H.mind.assigned_role)
|
||||
var/datum/preferences/P
|
||||
if(!C)
|
||||
C = H.client
|
||||
if(C)
|
||||
P = C.prefs
|
||||
return get_flat_human_icon(null, J, P, DUMMY_HUMAN_SLOT_MANIFEST)
|
||||
return get_flat_human_icon(null, J, P, DUMMY_HUMAN_SLOT_MANIFEST, show_directions)
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
//////////////////////////////////////
|
||||
Facial Hypertrichosis
|
||||
|
||||
Very very Noticable.
|
||||
Decreases resistance slightly.
|
||||
Decreases stage speed.
|
||||
Reduced transmittability
|
||||
No change to stealth.
|
||||
Increases resistance.
|
||||
Increases speed.
|
||||
Slighlty increases transmittability
|
||||
Intense Level.
|
||||
|
||||
BONUS
|
||||
@@ -18,10 +18,10 @@ BONUS
|
||||
|
||||
name = "Facial Hypertrichosis"
|
||||
desc = "The virus increases hair production significantly, causing rapid beard growth."
|
||||
stealth = -3
|
||||
resistance = -1
|
||||
stage_speed = -3
|
||||
transmittable = -1
|
||||
stealth = 0
|
||||
resistance = 3
|
||||
stage_speed = 2
|
||||
transmittable = 1
|
||||
level = 4
|
||||
severity = 1
|
||||
symptom_delay_min = 18
|
||||
@@ -48,4 +48,4 @@ BONUS
|
||||
to_chat(H, "<span class='warning'>You feel manly!</span>")
|
||||
if(!(H.facial_hair_style == "Dwarf Beard") && !(H.facial_hair_style == "Very Long Beard"))
|
||||
H.facial_hair_style = pick("Dwarf Beard", "Very Long Beard")
|
||||
H.update_hair()
|
||||
H.update_hair()
|
||||
|
||||
@@ -4,7 +4,7 @@ Alopecia
|
||||
|
||||
Not Noticeable.
|
||||
Increases resistance slightly.
|
||||
Reduces stage speed slightly.
|
||||
Increases stage speed.
|
||||
Transmittable.
|
||||
Intense Level.
|
||||
|
||||
@@ -19,8 +19,8 @@ BONUS
|
||||
desc = "The virus causes rapid shedding of head and body hair."
|
||||
stealth = 0
|
||||
resistance = 1
|
||||
stage_speed = -1
|
||||
transmittable = 3
|
||||
stage_speed = 2
|
||||
transmittable = 2
|
||||
level = 4
|
||||
severity = 1
|
||||
base_message_chance = 50
|
||||
@@ -52,4 +52,4 @@ BONUS
|
||||
H.hair_style = "Bald"
|
||||
else
|
||||
H.hair_style = "Balding Hair"
|
||||
H.update_hair()
|
||||
H.update_hair()
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
//////////////////////////////////////
|
||||
Vitiligo
|
||||
|
||||
Extremely Noticable.
|
||||
Decreases resistance slightly.
|
||||
Reduces stage speed slightly.
|
||||
Reduces transmission.
|
||||
Hidden.
|
||||
No change to resistance.
|
||||
Increases stage speed.
|
||||
Slightly increases transmittability.
|
||||
Critical Level.
|
||||
|
||||
BONUS
|
||||
@@ -18,10 +18,10 @@ BONUS
|
||||
|
||||
name = "Vitiligo"
|
||||
desc = "The virus destroys skin pigment cells, causing rapid loss of pigmentation in the host."
|
||||
stealth = -3
|
||||
resistance = -1
|
||||
stage_speed = -1
|
||||
transmittable = -2
|
||||
stealth = 2
|
||||
resistance = 0
|
||||
stage_speed = 3
|
||||
transmittable = 1
|
||||
level = 5
|
||||
severity = 1
|
||||
symptom_delay_min = 25
|
||||
@@ -47,10 +47,10 @@ BONUS
|
||||
//////////////////////////////////////
|
||||
Revitiligo
|
||||
|
||||
Extremely Noticable.
|
||||
Decreases resistance slightly.
|
||||
Reduces stage speed slightly.
|
||||
Reduces transmission.
|
||||
Slightly noticable.
|
||||
Increases resistance.
|
||||
Increases stage speed slightly.
|
||||
Increases transmission.
|
||||
Critical Level.
|
||||
|
||||
BONUS
|
||||
@@ -63,10 +63,10 @@ BONUS
|
||||
|
||||
name = "Revitiligo"
|
||||
desc = "The virus causes increased production of skin pigment cells, making the host's skin grow darker over time."
|
||||
stealth = -3
|
||||
resistance = -1
|
||||
stage_speed = -1
|
||||
transmittable = -2
|
||||
stealth = -1
|
||||
resistance = 3
|
||||
stage_speed = 1
|
||||
transmittable = 2
|
||||
level = 5
|
||||
severity = 1
|
||||
symptom_delay_min = 7
|
||||
|
||||
@@ -105,6 +105,14 @@
|
||||
mood_change = -3
|
||||
timeout = 3000
|
||||
|
||||
/datum/mood_event/nyctophobia
|
||||
description = "<span class='warning'>It sure is dark around here...</span>\n"
|
||||
mood_change = -3
|
||||
|
||||
/datum/mood_event/family_heirloom_missing
|
||||
description = "<span class='warning'>I'm missing my family heirloom...</span>\n"
|
||||
mood_change = -4
|
||||
|
||||
//These are unused so far but I want to remember them to use them later
|
||||
/datum/mood_event/cloned_corpse
|
||||
description = "<span class='boldwarning'>I recently saw my own corpse...</span>\n"
|
||||
|
||||
@@ -56,3 +56,7 @@
|
||||
description = "<span class='nicegreen'>I have seen the truth, praise the almighty one!</span>\n"
|
||||
mood_change = 40 //maybe being a cultist isnt that bad after all
|
||||
hidden = TRUE
|
||||
|
||||
/datum/mood_event/family_heirloom
|
||||
description = "<span class='nicegreen'>My family heirloom is safe with me.</span>\n"
|
||||
mood_change = 1
|
||||
|
||||
@@ -9,6 +9,19 @@
|
||||
#define RETURN_POINT_VECTOR(ATOM, ANGLE, SPEED) {new /datum/point/vector(ATOM, null, null, null, null, ANGLE, SPEED)}
|
||||
#define RETURN_POINT_VECTOR_INCREMENT(ATOM, ANGLE, SPEED, AMT) {new /datum/point/vector(ATOM, null, null, null, null, ANGLE, SPEED, AMT)}
|
||||
|
||||
/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
|
||||
var/datum/point/P = new
|
||||
P.x = a.x + (b.x - a.x) / 2
|
||||
P.y = a.y + (b.y - a.y) / 2
|
||||
P.z = a.z
|
||||
return P
|
||||
|
||||
/proc/pixel_length_between_points(datum/point/a, datum/point/b)
|
||||
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
|
||||
|
||||
/proc/angle_between_points(datum/point/a, datum/point/b)
|
||||
return ATAN2((b.y - a.y), (b.x - a.x))
|
||||
|
||||
/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
@@ -53,19 +66,6 @@
|
||||
/datum/position/proc/return_point()
|
||||
return new /datum/point(src)
|
||||
|
||||
/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
|
||||
var/datum/point/P = new
|
||||
P.x = a.x + (b.x - a.x) / 2
|
||||
P.y = a.y + (b.y - a.y) / 2
|
||||
P.z = a.z
|
||||
return P
|
||||
|
||||
/proc/pixel_length_between_points(datum/point/a, datum/point/b)
|
||||
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
|
||||
|
||||
/proc/angle_between_points(datum/point/a, datum/point/b)
|
||||
return ATAN2((b.y - a.y), (b.x - a.x))
|
||||
|
||||
/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
|
||||
+25
-23
@@ -11,6 +11,23 @@
|
||||
|
||||
|
||||
|
||||
/datum/trait/apathetic
|
||||
name = "Apathetic"
|
||||
desc = "You just don't care as much as other people. That's nice to have in a place like this, I guess."
|
||||
value = 1
|
||||
|
||||
/datum/trait/apathetic/add()
|
||||
GET_COMPONENT_FROM(mood, /datum/component/mood, trait_holder)
|
||||
if(mood)
|
||||
mood.mood_modifier = 0.8
|
||||
|
||||
/datum/trait/apathetic/remove()
|
||||
GET_COMPONENT_FROM(mood, /datum/component/mood, trait_holder)
|
||||
if(mood)
|
||||
mood.mood_modifier = 1 //Change this once/if species get their own mood modifiers.
|
||||
|
||||
|
||||
|
||||
/datum/trait/freerunning
|
||||
name = "Freerunning"
|
||||
desc = "You're great at quick moves! You can climb tables more quickly."
|
||||
@@ -21,6 +38,14 @@
|
||||
|
||||
|
||||
|
||||
/datum/trait/jolly
|
||||
name = "Jolly"
|
||||
desc = "You sometimes just feel happy, for no reason at all."
|
||||
value = 1
|
||||
mob_trait = TRAIT_JOLLY
|
||||
|
||||
|
||||
|
||||
/datum/trait/light_step
|
||||
name = "Light Step"
|
||||
desc = "You walk with a gentle step, making stepping on sharp objects quieter and less painful."
|
||||
@@ -81,26 +106,3 @@
|
||||
mob_trait = TRAIT_VORACIOUS
|
||||
gain_text = "<span class='notice'>You feel HONGRY.</span>"
|
||||
lose_text = "<span class='danger'>You no longer feel HONGRY.</span>"
|
||||
|
||||
|
||||
/datum/trait/jolly
|
||||
name = "Jolly"
|
||||
desc = "You sometimes just feel happy, for no reason at all."
|
||||
value = 1
|
||||
mob_trait = TRAIT_JOLLY
|
||||
|
||||
|
||||
/datum/trait/apathetic
|
||||
name = "Apathetic"
|
||||
desc = "You just don't care as much as other people, that's nice to have in a place like this, I guess."
|
||||
value = 1
|
||||
|
||||
/datum/trait/apathetic/add()
|
||||
GET_COMPONENT_FROM(mood, /datum/component/mood, trait_holder)
|
||||
if(mood)
|
||||
mood.mood_modifier = 0.8
|
||||
|
||||
/datum/trait/apathetic/remove()
|
||||
GET_COMPONENT_FROM(mood, /datum/component/mood, trait_holder)
|
||||
if(mood)
|
||||
mood.mood_modifier = 1 //Change this once/if species get their own mood modifiers.
|
||||
|
||||
+107
-12
@@ -1,5 +1,82 @@
|
||||
//predominantly negative traits
|
||||
|
||||
/datum/trait/depression
|
||||
name = "Depression"
|
||||
desc = "You sometimes just hate life."
|
||||
mob_trait = TRAIT_DEPRESSION
|
||||
value = -1
|
||||
gain_text = "<span class='danger'>You start feeling depressed.</span>"
|
||||
lose_text = "<span class='notice'>You no longer feel depressed.</span>" //if only it were that easy!
|
||||
medical_record_text = "Patient has a severe mood disorder causing them to experience sudden moments of sadness."
|
||||
|
||||
|
||||
|
||||
/datum/trait/family_heirloom
|
||||
name = "Family Heirloom"
|
||||
desc = "You are the current owner of an heirloom. passed down for generations. You have to keep it safe!"
|
||||
value = -1
|
||||
var/obj/item/heirloom
|
||||
var/where_text
|
||||
|
||||
/datum/trait/family_heirloom/on_spawn()
|
||||
var/mob/living/carbon/human/H = trait_holder
|
||||
var/obj/item/heirloom_type
|
||||
if(SSevents.holidays && SSevents.holidays[APRIL_FOOLS]) //on april fools, pick from any item in the game
|
||||
var/list/heirlooms = subtypesof(/obj/item)
|
||||
for(var/V in heirlooms)
|
||||
var/obj/item/I = V
|
||||
if((!initial(I.icon_state)) || (!initial(I.item_state)) || (initial(I.flags_1) & ABSTRACT_1))
|
||||
heirlooms -= V
|
||||
heirloom_type = pick(heirlooms)
|
||||
else
|
||||
switch(trait_holder.mind.assigned_role)
|
||||
if("Clown")
|
||||
heirloom_type = /obj/item/bikehorn/golden
|
||||
if("Mime")
|
||||
heirloom_type = /obj/item/reagent_containers/food/snacks/baguette
|
||||
if("Lawyer")
|
||||
heirloom_type = /obj/item/gavelhammer
|
||||
if("Janitor")
|
||||
heirloom_type = /obj/item/mop
|
||||
if("Security Officer")
|
||||
heirloom_type = /obj/item/book/manual/wiki/security_space_law
|
||||
if("Scientist")
|
||||
heirloom_type = /obj/item/toy/plush/slimeplushie
|
||||
if("Assistant")
|
||||
heirloom_type = /obj/item/storage/toolbox/mechanical/old/heirloom
|
||||
if(!heirloom_type)
|
||||
heirloom_type = pick(
|
||||
/obj/item/toy/cards/deck,
|
||||
/obj/item/lighter,
|
||||
/obj/item/dice/d20)
|
||||
heirloom = new heirloom_type(get_turf(trait_holder))
|
||||
var/list/slots = list(
|
||||
"in your backpack" = slot_in_backpack,
|
||||
"in your left pocket" = slot_l_store,
|
||||
"in your right pocket" = slot_r_store
|
||||
)
|
||||
var/where = H.equip_in_one_of_slots(heirloom, slots)
|
||||
if(!where)
|
||||
where = "at your feet"
|
||||
if(where == "in your backpack")
|
||||
var/obj/item/storage/B = H.back
|
||||
B.orient2hud(trait_holder)
|
||||
B.show_to(trait_holder)
|
||||
where_text = "<span class='boldnotice'>There is a precious family [heirloom.name] [where], passed down from generation to generation. Keep it safe!</span>"
|
||||
|
||||
/datum/trait/family_heirloom/post_add()
|
||||
to_chat(trait_holder, where_text)
|
||||
var/list/family_name = splittext(trait_holder.real_name, " ")
|
||||
heirloom.name = "\improper [family_name[family_name.len]] family [heirloom.name]"
|
||||
|
||||
/datum/trait/family_heirloom/process()
|
||||
if(heirloom in trait_holder.GetAllContents())
|
||||
trait_holder.SendSignal(COMSIG_CLEAR_MOOD_EVENT, "family_heirloom_missing")
|
||||
trait_holder.SendSignal(COMSIG_ADD_MOOD_EVENT, "family_heirloom", /datum/mood_event/family_heirloom)
|
||||
else
|
||||
trait_holder.SendSignal(COMSIG_CLEAR_MOOD_EVENT, "family_heirloom")
|
||||
trait_holder.SendSignal(COMSIG_ADD_MOOD_EVENT, "family_heirloom_missing", /datum/mood_event/family_heirloom_missing)
|
||||
|
||||
|
||||
|
||||
/datum/trait/heavy_sleeper
|
||||
@@ -44,6 +121,27 @@
|
||||
|
||||
|
||||
|
||||
/datum/trait/nyctophobia
|
||||
name = "Nyctophobia"
|
||||
desc = "As far as you can remember, you've always been afraid of the dark. While in the dark without a light source, you instinctually act careful, and constantly feel a sense of dread."
|
||||
value = -1
|
||||
|
||||
/datum/trait/nyctophobia/on_process()
|
||||
var/mob/living/carbon/human/H = trait_holder
|
||||
if(H.dna.species.id in list("shadow", "nightmare"))
|
||||
return //we're tied with the dark, so we don't get scared of it; don't cleanse outright to avoid cheese
|
||||
var/turf/T = get_turf(trait_holder)
|
||||
var/lums = T.get_lumcount()
|
||||
if(lums <= 0.2)
|
||||
if(trait_holder.m_intent == MOVE_INTENT_RUN)
|
||||
to_chat(trait_holder, "<span class='warning'>Easy, easy, take it slow... you're in the dark...</span>")
|
||||
trait_holder.toggle_move_intent()
|
||||
trait_holder.SendSignal(COMSIG_ADD_MOOD_EVENT, "nyctophobia", /datum/mood_event/nyctophobia)
|
||||
else
|
||||
trait_holder.SendSignal(COMSIG_CLEAR_MOOD_EVENT, "nyctophobia")
|
||||
|
||||
|
||||
|
||||
/datum/trait/nonviolent
|
||||
name = "Pacifist"
|
||||
desc = "The thought of violence makes you sick. So much so, in fact, that you can't hurt anyone."
|
||||
@@ -156,21 +254,18 @@
|
||||
var/dumb_thing = TRUE
|
||||
|
||||
/datum/trait/social_anxiety/on_process()
|
||||
var/nearby_people = 0
|
||||
for(var/mob/living/carbon/human/H in view(5, trait_holder))
|
||||
if(H.client)
|
||||
nearby_people++
|
||||
var/mob/living/carbon/human/H = trait_holder
|
||||
if(prob(5))
|
||||
if(prob(2 + nearby_people))
|
||||
H.stuttering = max(3, H.stuttering)
|
||||
else if(prob(1) && !H.silent)
|
||||
else if(prob(min(3, nearby_people)) && !H.silent)
|
||||
to_chat(H, "<span class='danger'>You retreat into yourself. You <i>really</i> don't feel up to talking.</span>")
|
||||
H.silent = max(10, H.silent)
|
||||
else if(prob(0.5) && dumb_thing)
|
||||
to_chat(H, "<span class='danger'>You think of a dumb thing you said a long time ago and scream internally.</span>")
|
||||
to_chat(H, "<span class='userdanger'>You think of a dumb thing you said a long time ago and scream internally.</span>")
|
||||
dumb_thing = FALSE //only once per life
|
||||
|
||||
/datum/trait/depression
|
||||
name = "Depression"
|
||||
desc = "You sometimes just hate life."
|
||||
mob_trait = TRAIT_DEPRESSION
|
||||
value = -1
|
||||
gain_text = "<span class='danger'>You start feeling depressed.</span>"
|
||||
lose_text = "<span class='notice'>You no longer feel depressed.</span>" //if only it were that easy!
|
||||
medical_record_text = "Patient has a severe mood disorder causing them to experience sudden moments of sadness."
|
||||
if(prob(1))
|
||||
new/obj/item/reagent_containers/food/snacks/pastatomato(get_turf(H)) //now that's what I call spaghetti code
|
||||
|
||||
@@ -31,3 +31,22 @@
|
||||
var/datum/species/species = H.dna.species
|
||||
species.liked_food = initial(species.liked_food)
|
||||
species.disliked_food = initial(species.disliked_food)
|
||||
|
||||
|
||||
|
||||
/datum/trait/monochromatic
|
||||
name = "Monochromacy"
|
||||
desc = "You suffer from full colorblindness, and perceive nearly the entire world in blacks and whites."
|
||||
value = 0
|
||||
medical_record_text = "Patient is afflicted with almost complete color blindness."
|
||||
|
||||
/datum/trait/monochromatic/add()
|
||||
trait_holder.add_client_colour(/datum/client_colour/monochrome)
|
||||
|
||||
/datum/trait/monochromatic/post_add()
|
||||
if(trait_holder.mind.assigned_role == "Detective")
|
||||
to_chat(trait_holder, "<span class='boldannounce'>Mmm. Nothing's ever clear on this station. It's all shades of gray...</span>")
|
||||
trait_holder.playsound_local(trait_holder, 'sound/ambience/ambidet1.ogg', 50, FALSE)
|
||||
|
||||
/datum/trait/monochromatic/remove()
|
||||
trait_holder.remove_client_colour(/datum/client_colour/monochrome)
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
input.weak_reference = new /datum/weakref(input)
|
||||
return input.weak_reference
|
||||
|
||||
/datum/proc/create_weakref() //Forced creation for admin proccalls
|
||||
return WEAKREF(src)
|
||||
|
||||
/datum/weakref
|
||||
var/reference
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ Credit where due:
|
||||
///////////
|
||||
|
||||
/proc/is_servant_of_ratvar(mob/M)
|
||||
return istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/clockcult)
|
||||
return isliving(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/clockcult)
|
||||
|
||||
/proc/is_eligible_servant(mob/M)
|
||||
if(!istype(M))
|
||||
|
||||
@@ -675,7 +675,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
//Picks as many people as it can from a department (Security,Engineer,Medical,Science)
|
||||
//and tasks the lings with killing and replacing them
|
||||
/datum/objective/changeling_team_objective/impersonate_department
|
||||
explanation_text = "Ensure X derpartment are killed, impersonated, and replaced by Changelings"
|
||||
explanation_text = "Ensure X department are killed, impersonated, and replaced by Changelings"
|
||||
var/command_staff_only = FALSE //if this is true, it picks command staff instead
|
||||
var/list/department_minds = list()
|
||||
var/list/department_real_names = list()
|
||||
@@ -823,7 +823,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
|
||||
|
||||
|
||||
//A subtype of impersonate_derpartment
|
||||
//A subtype of impersonate_department
|
||||
//This subtype always picks as many command staff as it can (HoS,HoP,Cap,CE,CMO,RD)
|
||||
//and tasks the lings with killing and replacing them
|
||||
/datum/objective/changeling_team_objective/impersonate_department/impersonate_heads
|
||||
|
||||
@@ -58,8 +58,13 @@
|
||||
"<span class='notice'>You climb out of [src]!</span>")
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/sleeper/Exited(atom/movable/user)
|
||||
if (!state_open && user == occupant)
|
||||
container_resist(user)
|
||||
|
||||
/obj/machinery/sleeper/relaymove(mob/user)
|
||||
container_resist(user)
|
||||
if (!state_open)
|
||||
container_resist(user)
|
||||
|
||||
/obj/machinery/sleeper/open_machine()
|
||||
if(!state_open && !panel_open)
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
occupier.adjustToxLoss(-1, 0)
|
||||
occupier.adjustBruteLoss(-1, 0)
|
||||
occupier.updatehealth()
|
||||
occupier.updatehealth()
|
||||
if(occupier.health >= 0 && occupier.stat == DEAD)
|
||||
occupier.revive()
|
||||
return occupier.health < 100
|
||||
@@ -92,9 +91,11 @@
|
||||
/obj/machinery/computer/aifixer/process()
|
||||
if(..())
|
||||
if(active)
|
||||
var/oldstat = occupier.stat
|
||||
active = Fix()
|
||||
if(oldstat != occupier.stat)
|
||||
update_icon()
|
||||
updateDialog()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/computer/aifixer/Topic(href, href_list)
|
||||
if(..())
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
icon_state = "blueprints"
|
||||
attack_verb = list("attacked", "bapped", "hit")
|
||||
var/fluffnotice = "Nobody's gonna read this stuff!"
|
||||
var/in_use = FALSE
|
||||
|
||||
/obj/item/areaeditor/attack_self(mob/user)
|
||||
add_fingerprint(user)
|
||||
@@ -25,12 +26,16 @@
|
||||
|
||||
/obj/item/areaeditor/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
return TRUE
|
||||
if(!usr.canUseTopic(src))
|
||||
usr << browse(null, "window=blueprints")
|
||||
return
|
||||
return TRUE
|
||||
if(href_list["create_area"])
|
||||
if(in_use)
|
||||
return
|
||||
in_use = TRUE
|
||||
create_area(usr)
|
||||
in_use = FALSE
|
||||
updateUsrDialog()
|
||||
|
||||
//Station blueprints!!!
|
||||
@@ -79,11 +84,16 @@
|
||||
|
||||
|
||||
/obj/item/areaeditor/blueprints/Topic(href, href_list)
|
||||
..()
|
||||
if(..())
|
||||
return
|
||||
if(href_list["edit_area"])
|
||||
if(get_area_type()!=AREA_STATION)
|
||||
return
|
||||
if(in_use)
|
||||
return
|
||||
in_use = TRUE
|
||||
edit_area()
|
||||
in_use = FALSE
|
||||
if(href_list["exit_legend"])
|
||||
legend = FALSE;
|
||||
if(href_list["view_legend"])
|
||||
|
||||
@@ -28,7 +28,10 @@
|
||||
disrupt()
|
||||
|
||||
/obj/item/device/chameleon/attack_self(mob/user)
|
||||
toggle(user)
|
||||
if (isturf(user.loc) || istype(user.loc, /obj/structure) || active_dummy)
|
||||
toggle(user)
|
||||
else
|
||||
to_chat(user, "<span class='userwarning'>You can't use [src] while inside something.</span>")
|
||||
|
||||
/obj/item/device/chameleon/afterattack(atom/target, mob/user , proximity)
|
||||
if(!proximity)
|
||||
|
||||
@@ -27,6 +27,18 @@
|
||||
/obj/item/grenade/chem_grenade/examine(mob/user)
|
||||
display_timer = (stage == READY && !nadeassembly) //show/hide the timer based on assembly state
|
||||
..()
|
||||
if(user.can_see_reagents())
|
||||
var/count = 0
|
||||
if(beakers.len)
|
||||
to_chat(user, "<span class='notice'>You scan the grenade and detect the following reagents:</span>")
|
||||
for(var/obj/item/reagent_containers/glass/G in beakers)
|
||||
var/textcount = thtotext(++count)
|
||||
for(var/datum/reagent/R in G.reagents.reagent_list)
|
||||
to_chat(user, "<span class='notice'>[R.volume] units of [R.name] in the [textcount] beaker.</span>")
|
||||
if(beakers.len == 1)
|
||||
to_chat(user, "<span class='notice'>You detect no second beaker in the grenade.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You scan the grenade, but detect nothing.</span>")
|
||||
|
||||
|
||||
/obj/item/grenade/chem_grenade/attack_self(mob/user)
|
||||
|
||||
@@ -23,8 +23,31 @@
|
||||
var/detonate_flash_range = 5
|
||||
var/detonate_fire_range = 5
|
||||
|
||||
var/active = FALSE
|
||||
|
||||
var/color_val = FALSE
|
||||
|
||||
var/datum/weakref/current
|
||||
|
||||
/obj/item/hot_potato/Destroy()
|
||||
if(active)
|
||||
deactivate()
|
||||
return ..()
|
||||
|
||||
/obj/item/hot_potato/proc/colorize(mob/target)
|
||||
//Clear color from old target
|
||||
if(current)
|
||||
var/mob/M = current.resolve()
|
||||
if(istype(M))
|
||||
M.remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
//Give to new target
|
||||
current = null
|
||||
//Swap colors
|
||||
color_val = !color_val
|
||||
if(istype(target))
|
||||
current = WEAKREF(target)
|
||||
target.add_atom_colour(color_val? "#ffff00" : "#00ffff", FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/obj/item/hot_potato/proc/detonate()
|
||||
var/atom/location = loc
|
||||
location.visible_message("<span class='userdanger'>[src] [detonate_explosion? "explodes" : "activates"]!</span>", "<span class='userdanger'>[src] activates! You've ran out of time!</span>")
|
||||
@@ -37,9 +60,6 @@
|
||||
M.dropItemToGround(src, TRUE)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/hot_potato/proc/is_active()
|
||||
return isnull(detonation_timerid)? FALSE : TRUE
|
||||
|
||||
/obj/item/hot_potato/attack_self(mob/user)
|
||||
if(activate(timer, user))
|
||||
user.visible_message("<span class='boldwarning'>[user] squeezes [src], which promptly starts to flash red-hot colors!</span>", "<span class='boldwarning'>You squeeze [src], activating its countdown and attachment mechanism!</span>",
|
||||
@@ -56,19 +76,18 @@
|
||||
L.SetSleeping(0)
|
||||
L.SetUnconscious(0)
|
||||
L.reagents.add_reagent("muscle_stimulant", CLAMP(5 - L.reagents.get_reagent_amount("muscle_stimulant"), 0, 5)) //If you don't have legs or get bola'd, tough luck!
|
||||
color_val = !color_val
|
||||
L.add_atom_colour(color_val? "#ffff00" : "#00ffff", FIXED_COLOUR_PRIORITY)
|
||||
colorize(L)
|
||||
|
||||
/obj/item/hot_potato/examine(mob/user)
|
||||
. = ..()
|
||||
if(is_active())
|
||||
if(active)
|
||||
to_chat(user, "<span class='warning'>[src] is flashing red-hot! You should probably get rid of it!</span>")
|
||||
if(show_timer)
|
||||
to_chat(user, "<span class='warning'>[src]'s timer looks to be at [DisplayTimeText(activation_time - world.time)]!</span>")
|
||||
|
||||
/obj/item/hot_potato/equipped(mob/user)
|
||||
. = ..()
|
||||
if(is_active())
|
||||
if(active)
|
||||
to_chat(user, "<span class='userdanger'>You have a really bad feeling about [src]!</span>")
|
||||
|
||||
/obj/item/hot_potato/afterattack(atom/target, mob/user, adjacent, params)
|
||||
@@ -99,7 +118,7 @@
|
||||
if(.)
|
||||
add_logs(user, victim, "forced a hot potato with explosive variables ([detonate_explosion]-[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_flash_range]/[detonate_fire_range]) onto")
|
||||
user.visible_message("<span class='userdanger'>[user] forces [src] onto [victim]!</span>", "<span class='userdanger'>You force [src] onto [victim]!</span>", "<span class='boldwarning'>You hear a mechanical click and a beep.</span>")
|
||||
user.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
colorize(null)
|
||||
else
|
||||
add_logs(user, victim, "tried to force a hot potato with explosive variables ([detonate_explosion]-[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_flash_range]/[detonate_fire_range]) onto")
|
||||
user.visible_message("<span class='boldwarning'>[user] tried to force [src] onto [victim], but it could not attach!</span>", "<span class='boldwarning'>You try to force [src] onto [victim], but it is unable to attach!</span>", "<span class='boldwarning'>You hear a mechanical click and two buzzes.</span>")
|
||||
@@ -107,10 +126,10 @@
|
||||
|
||||
/obj/item/hot_potato/dropped(mob/user)
|
||||
. = ..()
|
||||
user.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
colorize(null)
|
||||
|
||||
/obj/item/hot_potato/proc/activate(delay, mob/user)
|
||||
if(is_active())
|
||||
if(active)
|
||||
return
|
||||
update_icon()
|
||||
if(sticky)
|
||||
@@ -122,6 +141,7 @@
|
||||
var/turf/T = get_turf(src)
|
||||
message_admins("[user? "[ADMIN_LOOKUPFLW(user)] has primed [src]" : "A [src] has been primed"] (Timer:[delay],Explosive:[detonate_explosion],Range:[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_fire_range]) for detonation at [COORD(T)]([T.loc])")
|
||||
log_game("[user? "[user] has primed [src]" : "A [src] has been primed"] ([detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_fire_range]) for detonation at [COORD(T)]([T.loc])")
|
||||
active = TRUE
|
||||
|
||||
/obj/item/hot_potato/proc/deactivate()
|
||||
update_icon()
|
||||
@@ -130,12 +150,11 @@
|
||||
deltimer(detonation_timerid)
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
detonation_timerid = null
|
||||
if(ismob(loc))
|
||||
var/mob/user = loc
|
||||
user.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
colorize(null)
|
||||
active = FALSE
|
||||
|
||||
/obj/item/hot_potato/update_icon()
|
||||
icon_state = is_active()? icon_on : icon_off
|
||||
icon_state = active? icon_on : icon_off
|
||||
|
||||
/obj/item/hot_potato/syndicate
|
||||
detonate_light_range = 4
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
H.sec_hud_set_implants()
|
||||
|
||||
if(user)
|
||||
add_logs(user, target, "implanted", object="[name]")
|
||||
add_logs(user, target, "implanted", "\a [name]")
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
@@ -78,6 +78,15 @@
|
||||
icon_state = "toolbox_blue_old"
|
||||
has_latches = FALSE
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/heirloom
|
||||
name = "toolbox" //this will be named "X family toolbox"
|
||||
desc = "It's seen better days."
|
||||
force = 5
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/heirloom/PopulateContents()
|
||||
return
|
||||
|
||||
/obj/item/storage/toolbox/electrical
|
||||
name = "electrical toolbox"
|
||||
icon_state = "yellow"
|
||||
|
||||
@@ -415,7 +415,7 @@
|
||||
icon_state = "plasmawindow"
|
||||
reinf = FALSE
|
||||
heat_resistance = 25000
|
||||
armor = list("melee" = 75, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 45, "bio" = 100, "rad" = 100, "fire" = 00, "acid" = 100)
|
||||
armor = list("melee" = 75, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 45, "bio" = 100, "rad" = 100, "fire" = 99, "acid" = 100)
|
||||
max_integrity = 150
|
||||
explosion_block = 1
|
||||
glass_type = /obj/item/stack/sheet/plasmaglass
|
||||
|
||||
@@ -199,8 +199,6 @@
|
||||
return 0
|
||||
if(!(lube&SLIDE_ICE))
|
||||
to_chat(C, "<span class='notice'>You slipped[ O ? " on the [O.name]" : ""]!</span>")
|
||||
C.log_message("<font color='orange'>Slipped[O ? " on the [O.name]" : ""][(lube&SLIDE)? " (LUBE)" : ""]!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(!(lube&SLIDE_ICE))
|
||||
playsound(C.loc, 'sound/misc/slip.ogg', 50, 1, -3)
|
||||
|
||||
C.SendSignal(COMSIG_ADD_MOOD_EVENT, "slipped", /datum/mood_event/slipped)
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
if(!check_rights())
|
||||
return
|
||||
|
||||
if(!isobserver(usr))
|
||||
log_game("[key_name(usr)] checked the player panel while in game.")
|
||||
log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].")
|
||||
|
||||
if(!M)
|
||||
to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.")
|
||||
|
||||
@@ -113,7 +113,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
return ((rank.rights & flag) == flag) //true only if right has everything in flag
|
||||
|
||||
//load our rank - > rights associations
|
||||
/proc/load_admin_ranks(dbfail)
|
||||
/proc/load_admin_ranks(dbfail, no_update)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Reload blocked: Advanced ProcCall detected.</span>")
|
||||
return
|
||||
@@ -137,27 +137,38 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
prev = next
|
||||
previous_rights = R.rights
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
message_admins("Error loading admin ranks from database. Loading from backup.")
|
||||
log_sql("Error loading admin ranks from database. Loading from backup.")
|
||||
dbfail = 1
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/skip
|
||||
var/rank_name = query_load_admin_ranks.item[1]
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
||||
if(!no_update)
|
||||
var/list/sql_ranks = list()
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == rank_name) //this rank was already loaded from txt override
|
||||
skip = 1
|
||||
break
|
||||
if(!skip)
|
||||
var/rank_flags = text2num(query_load_admin_ranks.item[2])
|
||||
var/rank_exclude_flags = text2num(query_load_admin_ranks.item[3])
|
||||
var/rank_can_edit_flags = text2num(query_load_admin_ranks.item[4])
|
||||
var/datum/admin_rank/R = new(rank_name, rank_flags, rank_exclude_flags, rank_can_edit_flags)
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
var/sql_rank = sanitizeSQL(R.name)
|
||||
var/sql_flags = sanitizeSQL(R.include_rights)
|
||||
var/sql_exclude_flags = sanitizeSQL(R.exclude_rights)
|
||||
var/sql_can_edit_flags = sanitizeSQL(R.can_edit_rights)
|
||||
sql_ranks += list(list("rank" = "'[sql_rank]'", "flags" = "[sql_flags]", "exclude_flags" = "[sql_exclude_flags]", "can_edit_flags" = "[sql_can_edit_flags]"))
|
||||
SSdbcore.MassInsert(format_table_name("admin_ranks"), sql_ranks, duplicate_key = TRUE)
|
||||
else
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
message_admins("Error loading admin ranks from database. Loading from backup.")
|
||||
log_sql("Error loading admin ranks from database. Loading from backup.")
|
||||
dbfail = 1
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/skip
|
||||
var/rank_name = query_load_admin_ranks.item[1]
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == rank_name) //this rank was already loaded from txt override
|
||||
skip = 1
|
||||
break
|
||||
if(!skip)
|
||||
var/rank_flags = text2num(query_load_admin_ranks.item[2])
|
||||
var/rank_exclude_flags = text2num(query_load_admin_ranks.item[3])
|
||||
var/rank_can_edit_flags = text2num(query_load_admin_ranks.item[4])
|
||||
var/datum/admin_rank/R = new(rank_name, rank_flags, rank_exclude_flags, rank_can_edit_flags)
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
//load ranks from backup file
|
||||
if(dbfail)
|
||||
var/backup_file = file("data/admins_backup.json")
|
||||
@@ -184,7 +195,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
testing(msg)
|
||||
#endif
|
||||
|
||||
/proc/load_admins()
|
||||
/proc/load_admins(no_update)
|
||||
var/dbfail
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && !SSdbcore.Connect())
|
||||
message_admins("Failed to connect to database while loading admins. Loading from backup.")
|
||||
@@ -198,7 +209,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
GLOB.admins.Cut()
|
||||
GLOB.protected_admins.Cut()
|
||||
GLOB.deadmins.Cut()
|
||||
dbfail = load_admin_ranks(dbfail)
|
||||
dbfail = load_admin_ranks(dbfail, no_update)
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
|
||||
@@ -82,6 +82,10 @@
|
||||
if(D.rank in GLOB.protected_ranks)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the flags of this rank is blocked by server configuration.</span>")
|
||||
return
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only) && (task == "rank" || task == "permissions"))
|
||||
to_chat(usr, "<span class='admin prefix'>Database rank loading is disabled, only temporary changes can be made to an admin's rank or permissions.</span>")
|
||||
use_db = FALSE
|
||||
skip = TRUE
|
||||
if(check_rights(R_DBRANKS, FALSE))
|
||||
if(!skip)
|
||||
if(!SSdbcore.Connect())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/admins/proc/player_panel_new()//The new one
|
||||
if(!check_rights())
|
||||
return
|
||||
log_admin("[key_name(usr)] checked the player panel.")
|
||||
var/dat = "<html><head><title>Player Panel</title></head>"
|
||||
|
||||
//javascript, the part that does most of the work~
|
||||
@@ -307,4 +308,4 @@
|
||||
</body></html>
|
||||
"}
|
||||
|
||||
usr << browse(dat, "window=players;size=600x480")
|
||||
usr << browse(dat, "window=players;size=600x480")
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
..()
|
||||
src.bd = bd
|
||||
|
||||
/obj/screen/buildmode/Destroy()
|
||||
bd.buttons -= src
|
||||
bd = null
|
||||
return ..()
|
||||
|
||||
/obj/screen/buildmode/mode
|
||||
icon_state = "buildmode1"
|
||||
name = "Toggle Mode"
|
||||
@@ -102,8 +107,12 @@
|
||||
|
||||
/datum/buildmode/Destroy()
|
||||
stored = null
|
||||
for(var/button in buttons)
|
||||
qdel(button)
|
||||
QDEL_LIST(buttons)
|
||||
throw_atom = null
|
||||
holder = null
|
||||
preview.Cut()
|
||||
cornerA = null
|
||||
cornerB = null
|
||||
return ..()
|
||||
|
||||
/datum/buildmode/proc/create_buttons()
|
||||
|
||||
@@ -553,7 +553,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
set category = "Admin"
|
||||
set name = "Delete"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
if(!check_rights(R_SPAWN|R_DEBUG))
|
||||
return
|
||||
|
||||
admin_delete(A)
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
else if(L.stat)
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"There is use in shackling the dead, but for examples.\"</span>")
|
||||
return TRUE
|
||||
else if(L.handcuffed)
|
||||
else if (istype(L.handcuffed,/obj/item/restraints/handcuffs/clockwork))
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"They are already helpless, no?\"</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"<span class='neovgre_small'>You begin shaping replicant alloy into manacles around [L]'s wrists...</span>")
|
||||
to_chat(L, "<span class='userdanger'>[ranged_ability_user] begins forming manacles around your wrists!</span>")
|
||||
if(do_mob(ranged_ability_user, L, 30))
|
||||
if(!L.handcuffed)
|
||||
if(!(istype(L.handcuffed,/obj/item/restraints/handcuffs/clockwork)))
|
||||
L.handcuffed = new/obj/item/restraints/handcuffs/clockwork(L)
|
||||
L.update_handcuffed()
|
||||
to_chat(ranged_ability_user, "<span class='neovgre_small'>You shackle [L].</span>")
|
||||
|
||||
@@ -184,6 +184,7 @@
|
||||
important = TRUE
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Returns you to Reebe."
|
||||
var/client_color
|
||||
|
||||
/datum/clockwork_scripture/abscond/check_special_requirements()
|
||||
if(is_reebe(invoker.z))
|
||||
@@ -192,6 +193,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/abscond/recital()
|
||||
client_color = invoker.client.color
|
||||
animate(invoker.client, color = "#AF0AAF", time = 50)
|
||||
. = ..()
|
||||
|
||||
@@ -214,11 +216,11 @@
|
||||
invoker.pulling.forceMove(T)
|
||||
invoker.forceMove(T)
|
||||
if(invoker.client)
|
||||
animate(invoker.client, color = initial(invoker.client.color), time = 25)
|
||||
animate(invoker.client, color = client_color, time = 25)
|
||||
|
||||
/datum/clockwork_scripture/abscond/scripture_fail()
|
||||
if(invoker && invoker.client)
|
||||
animate(invoker.client, color = initial(invoker.client.color), time = 10)
|
||||
animate(invoker.client, color = client_color, time = 10)
|
||||
|
||||
|
||||
//Replicant: Creates a new clockwork slab.
|
||||
|
||||
@@ -112,8 +112,12 @@
|
||||
continue
|
||||
if(is_servant_of_ratvar(L) || (L.has_trait(TRAIT_BLIND)) || L.anti_magic_check(TRUE, TRUE))
|
||||
continue
|
||||
if(L.stat || L.restrained() || L.buckled || L.lying)
|
||||
if(L.stat || L.lying)
|
||||
continue
|
||||
if (iscarbon(L))
|
||||
var/mob/living/carbon/c = L
|
||||
if (istype(c.handcuffed,/obj/item/restraints/handcuffs/clockwork))
|
||||
continue
|
||||
if(ishostile(L))
|
||||
var/mob/living/simple_animal/hostile/H = L
|
||||
if(("ratvar" in H.faction) || (!H.mind && "neutral" in H.faction))
|
||||
|
||||
@@ -589,6 +589,7 @@
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The spell will not work on [target]!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
//Armor: Gives the target a basic cultist combat loadout
|
||||
|
||||
@@ -241,7 +241,7 @@
|
||||
|
||||
var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
|
||||
var/datum/preferences/sacface = sac_objective.target.current.client.prefs
|
||||
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
|
||||
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface, list(SOUTH))
|
||||
reshape.Shift(SOUTH, 4)
|
||||
reshape.Shift(EAST, 1)
|
||||
reshape.Crop(7,4,26,31)
|
||||
|
||||
@@ -776,7 +776,6 @@
|
||||
impact_effect_type = /obj/effect/temp_visual/dir_setting/bloodsplatter
|
||||
|
||||
/obj/item/projectile/magic/arcane_barrage/blood/Collide(atom/target)
|
||||
colliding = TRUE
|
||||
var/turf/T = get_turf(target)
|
||||
playsound(T, 'sound/effects/splat.ogg', 50, TRUE)
|
||||
if(iscultist(target))
|
||||
@@ -790,7 +789,6 @@
|
||||
M.adjustHealth(-5)
|
||||
new /obj/effect/temp_visual/cult/sparks(T)
|
||||
qdel(src)
|
||||
colliding = FALSE
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
var/mob/living/simple_animal/revenant/revvie = new(pick(spawn_locs))
|
||||
revvie.key = selected.key
|
||||
message_admins("[key_name_admin(revvie)] has been made into a revenant by an event.")
|
||||
message_admins("[key_name_admin(revvie)] [ADMIN_FLW(revvie)] has been made into a revenant by an event.")
|
||||
log_game("[key_name(revvie)] was spawned as a revenant by an event.")
|
||||
spawned_mobs += revvie
|
||||
return SUCCESSFUL_SPAWN
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -266,22 +266,22 @@
|
||||
return
|
||||
crit_fail = FALSE
|
||||
times_used = 0
|
||||
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
update_icon()
|
||||
flash.crit_fail = TRUE
|
||||
flash.update_icon()
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/device/assembly/flash/shield/update_icon(flash = 0)
|
||||
item_state = "flashshield"
|
||||
/obj/item/device/assembly/flash/shield/update_icon(flash = FALSE)
|
||||
icon_state = "flashshield"
|
||||
item_state = "flashshield"
|
||||
|
||||
if(crit_fail)
|
||||
icon_state = "riot"
|
||||
item_state = "riot"
|
||||
else if(flash)
|
||||
item_state = "flashshield_flash"
|
||||
icon_state = "flashshield_flash"
|
||||
item_state = "flashshield_flash"
|
||||
addtimer(CALLBACK(src, .proc/update_icon), 5)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ What are the archived variables for?
|
||||
once gases got hot enough, most procedures wouldnt occur due to the fact that the mole counts would get rounded away. Thus, we lowered it a few orders of magnititude */
|
||||
GLOBAL_LIST_INIT(meta_gas_info, meta_gas_list()) //see ATMOSPHERICS/gas_types.dm
|
||||
GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
|
||||
GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide))) // These gasses cannot react amongst themselves
|
||||
|
||||
/proc/init_gaslist_cache()
|
||||
. = list()
|
||||
@@ -411,10 +412,18 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
|
||||
|
||||
/datum/gas_mixture/react(turf/open/dump_location)
|
||||
. = NO_REACTION
|
||||
|
||||
reaction_results = new
|
||||
|
||||
var/list/cached_gases = gases
|
||||
if(!cached_gases.len)
|
||||
return
|
||||
var/possible
|
||||
for(var/I in cached_gases)
|
||||
if(GLOB.nonreactive_gases[I])
|
||||
continue
|
||||
possible = TRUE
|
||||
break
|
||||
if(!possible)
|
||||
return
|
||||
reaction_results = new
|
||||
var/temp = temperature
|
||||
var/ener = THERMAL_ENERGY(src)
|
||||
|
||||
|
||||
@@ -31,9 +31,6 @@
|
||||
if(frequency)
|
||||
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/filter/New()
|
||||
..()
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/filter/Destroy()
|
||||
SSradio.remove_object(src,frequency)
|
||||
return ..()
|
||||
|
||||
@@ -105,6 +105,8 @@
|
||||
addMachineryMember(A)
|
||||
|
||||
/datum/pipeline/proc/merge(datum/pipeline/E)
|
||||
if(E == src)
|
||||
return
|
||||
air.volume += E.air.volume
|
||||
members.Add(E.members)
|
||||
for(var/obj/machinery/atmospherics/pipe/S in E.members)
|
||||
|
||||
@@ -79,9 +79,10 @@
|
||||
parent = P
|
||||
|
||||
/obj/machinery/atmospherics/pipe/Destroy()
|
||||
QDEL_NULL(parent)
|
||||
|
||||
releaseAirToTurf()
|
||||
qdel(air_temporary)
|
||||
air_temporary = null
|
||||
QDEL_NULL(air_temporary)
|
||||
|
||||
var/turf/T = loc
|
||||
for(var/obj/machinery/meter/meter in T)
|
||||
@@ -91,8 +92,6 @@
|
||||
qdel(meter)
|
||||
. = ..()
|
||||
|
||||
QDEL_NULL(parent)
|
||||
|
||||
/obj/machinery/atmospherics/pipe/proc/update_node_icon()
|
||||
for(var/i in 1 to device_type)
|
||||
if(nodes[i])
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/obj/machinery/computer/cargo/express
|
||||
name = "express supply console"
|
||||
desc = "This console allows the user to purchase a package for double the price,\
|
||||
desc = "This console allows the user to purchase a package \
|
||||
with 1/40th of the delivery time: made possible by NanoTrasen's new \"Drop Pod Railgun\".\
|
||||
All sales are near instantaneous - please choose carefully"
|
||||
icon_screen = "supply_express"
|
||||
@@ -75,8 +75,7 @@
|
||||
data["siliconUser"] = user.has_unlimited_silicon_privilege
|
||||
data["points"] = SSshuttle.points
|
||||
data["supplies"] = list()
|
||||
message = "For normally priced items, please use the standard Supply or Request Console. \
|
||||
Sales are near-instantaneous - please choose carefully."
|
||||
message = "Sales are near-instantaneous - please choose carefully."
|
||||
if(SSshuttle.supplyBlocked)
|
||||
message = blockade_warning
|
||||
if(obj_flags & EMAGGED)
|
||||
|
||||
@@ -105,4 +105,9 @@
|
||||
colour = "#ff99ff"
|
||||
|
||||
/datum/client_colour/glass_colour/gray
|
||||
colour = "#cccccc"
|
||||
colour = "#cccccc"
|
||||
|
||||
|
||||
/datum/client_colour/monochrome
|
||||
colour = list(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
|
||||
priority = INFINITY //we can't see colors anyway!
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
if(prefs.muted & MUTE_OOC)
|
||||
to_chat(src, "<span class='danger'>You cannot use OOC (muted).</span>")
|
||||
return
|
||||
if(jobban_isbanned(src.mob, "OOC"))
|
||||
to_chat(src, "<span class='danger'>You have been banned from OOC.</span>")
|
||||
return
|
||||
if(jobban_isbanned(src.mob, "OOC"))
|
||||
to_chat(src, "<span class='danger'>You have been banned from OOC.</span>")
|
||||
return
|
||||
|
||||
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
var/raw_msg = msg
|
||||
@@ -277,7 +277,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, OOC_COLOR)
|
||||
set category = "OOC"
|
||||
set desc ="Ignore a player's messages on the OOC channel"
|
||||
|
||||
|
||||
|
||||
var/see_ghost_names = isobserver(mob)
|
||||
var/list/choices = list()
|
||||
for(var/client/C in GLOB.clients)
|
||||
|
||||
@@ -109,7 +109,6 @@
|
||||
icon_state = "night"
|
||||
item_state = "glasses"
|
||||
darkness_view = 8
|
||||
vision_flags = SEE_BLACKNESS
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
glass_colour_type = /datum/client_colour/glass_colour/green
|
||||
|
||||
|
||||
@@ -468,8 +468,8 @@
|
||||
|
||||
/obj/item/device/flightpack/proc/losecontrol(knockdown = FALSE, move = TRUE)
|
||||
usermessage("Warning: Control system not responding. Deactivating!", "boldwarning")
|
||||
wearer.visible_message("<span class='warning'>[wearer]'s flight suit abruptly shuts off and they lose control!</span>")
|
||||
if(wearer)
|
||||
wearer.visible_message("<span class='warning'>[wearer]'s flight suit abruptly shuts off and they lose control!</span>")
|
||||
if(move)
|
||||
while(momentum_x != 0 || momentum_y != 0)
|
||||
sleep(2)
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
|
||||
|
||||
/datum/personal_crafting/proc/check_contents(datum/crafting_recipe/R, list/contents)
|
||||
contents = contents["other"]
|
||||
main_loop:
|
||||
for(var/A in R.reqs)
|
||||
var/needed_amount = R.reqs[A]
|
||||
@@ -89,25 +90,30 @@
|
||||
|
||||
/datum/personal_crafting/proc/get_surroundings(mob/user)
|
||||
. = list()
|
||||
.["tool_behaviour"] = list()
|
||||
.["other"] = list()
|
||||
for(var/obj/item/I in get_environment(user))
|
||||
if(I.flags_2 & HOLOGRAM_2)
|
||||
continue
|
||||
if(istype(I, /obj/item/stack))
|
||||
var/obj/item/stack/S = I
|
||||
.[I.type] += S.amount
|
||||
.["other"][I.type] += S.amount
|
||||
else if(I.tool_behaviour)
|
||||
.["tool_behaviour"] += I.tool_behaviour
|
||||
else
|
||||
if(istype(I, /obj/item/reagent_containers))
|
||||
var/obj/item/reagent_containers/RC = I
|
||||
if(RC.is_drainable())
|
||||
for(var/datum/reagent/A in RC.reagents.reagent_list)
|
||||
.[A.type] += A.volume
|
||||
.[I.type] += 1
|
||||
.["other"][A.type] += A.volume
|
||||
.["other"][I.type] += 1
|
||||
|
||||
/datum/personal_crafting/proc/check_tools(mob/user, datum/crafting_recipe/R, list/contents)
|
||||
if(!R.tools.len)
|
||||
return TRUE
|
||||
var/list/possible_tools = list()
|
||||
var/list/present_qualities = list()
|
||||
present_qualities |= contents["tool_behaviour"]
|
||||
for(var/obj/item/I in user.contents)
|
||||
if(istype(I, /obj/item/storage))
|
||||
for(var/obj/item/SI in I.contents)
|
||||
@@ -120,7 +126,7 @@
|
||||
if(I.tool_behaviour)
|
||||
present_qualities.Add(I.tool_behaviour)
|
||||
|
||||
possible_tools += contents
|
||||
possible_tools |= contents["other"]
|
||||
|
||||
main_loop:
|
||||
for(var/A in R.tools)
|
||||
|
||||
@@ -110,6 +110,8 @@
|
||||
/obj/item/reagent_containers/food/drinks/proc/smash(atom/target, mob/thrower, ranged = FALSE)
|
||||
if(!isGlass)
|
||||
return
|
||||
if(QDELING(src) || !target) //Invalid loc
|
||||
return
|
||||
if(bartender_check(target) && ranged)
|
||||
return
|
||||
var/obj/item/broken_bottle/B = new (loc)
|
||||
|
||||
@@ -500,6 +500,8 @@
|
||||
for(var/I in assembly_components)
|
||||
var/obj/item/integrated_circuit/IC = I
|
||||
IC.ext_moved(oldLoc, dir)
|
||||
if(light) //Update lighting objects (From light circuits).
|
||||
update_light()
|
||||
|
||||
/obj/item/device/electronic_assembly/stop_pulling()
|
||||
for(var/I in assembly_components)
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
if(do_tick && !is_running)
|
||||
is_running = TRUE
|
||||
tick()
|
||||
else if(is_running)
|
||||
else if(!do_tick && is_running)
|
||||
is_running = FALSE
|
||||
|
||||
|
||||
|
||||
@@ -278,31 +278,47 @@
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/mob/dead/new_player/proc/IsJobAvailable(rank)
|
||||
/proc/get_job_unavailable_error_message(retval, jobtitle)
|
||||
switch(retval)
|
||||
if(JOB_AVAILABLE)
|
||||
return "[jobtitle] is available."
|
||||
if(JOB_UNAVAILABLE_GENERIC)
|
||||
return "[jobtitle] is unavailable."
|
||||
if(JOB_UNAVAILABLE_BANNED)
|
||||
return "You are currently banned from [jobtitle]."
|
||||
if(JOB_UNAVAILABLE_PLAYTIME)
|
||||
return "You do not have enough relevant playtime for [jobtitle]."
|
||||
if(JOB_UNAVAILABLE_ACCOUNTAGE)
|
||||
return "Your account is not old enough for [jobtitle]."
|
||||
if(JOB_UNAVAILABLE_SLOTFULL)
|
||||
return "[jobtitle] is already filled to capacity."
|
||||
return "Error: Unknown job availability."
|
||||
|
||||
/mob/dead/new_player/proc/IsJobUnavailable(rank)
|
||||
var/datum/job/job = SSjob.GetJob(rank)
|
||||
if(!job)
|
||||
return 0
|
||||
return JOB_UNAVAILABLE_GENERIC
|
||||
if((job.current_positions >= job.total_positions) && job.total_positions != -1)
|
||||
if(job.title == "Assistant")
|
||||
if(isnum(client.player_age) && client.player_age <= 14) //Newbies can always be assistants
|
||||
return 1
|
||||
return JOB_AVAILABLE
|
||||
for(var/datum/job/J in SSjob.occupations)
|
||||
if(J && J.current_positions < J.total_positions && J.title != job.title)
|
||||
return 0
|
||||
return JOB_UNAVAILABLE_SLOTFULL
|
||||
else
|
||||
return 0
|
||||
return JOB_UNAVAILABLE_SLOTFULL
|
||||
if(jobban_isbanned(src,rank))
|
||||
return 0
|
||||
if(!job.player_old_enough(src.client))
|
||||
return 0
|
||||
return JOB_UNAVAILABLE_BANNED
|
||||
if(!job.player_old_enough(client))
|
||||
return JOB_UNAVAILABLE_ACCOUNTAGE
|
||||
if(job.required_playtime_remaining(client))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
return JOB_UNAVAILABLE_PLAYTIME
|
||||
return JOB_AVAILABLE
|
||||
|
||||
/mob/dead/new_player/proc/AttemptLateSpawn(rank)
|
||||
if(!IsJobAvailable(rank))
|
||||
alert(src, "[rank] is not available. Please try another.")
|
||||
var/error = IsJobUnavailable(rank)
|
||||
if(error != JOB_AVAILABLE)
|
||||
alert(src, get_job_unavailable_error_message(error, rank))
|
||||
return FALSE
|
||||
|
||||
if(SSticker.late_join_disabled)
|
||||
@@ -405,7 +421,7 @@
|
||||
|
||||
var/available_job_count = 0
|
||||
for(var/datum/job/job in SSjob.occupations)
|
||||
if(job && IsJobAvailable(job.title))
|
||||
if(job && IsJobUnavailable(job.title) == JOB_AVAILABLE)
|
||||
available_job_count++;
|
||||
|
||||
|
||||
@@ -428,7 +444,7 @@
|
||||
dat += "<div class='jobs'><div class='jobsColumn'>"
|
||||
var/job_count = 0
|
||||
for(var/datum/job/job in SSjob.occupations)
|
||||
if(job && IsJobAvailable(job.title))
|
||||
if(job && IsJobUnavailable(job.title) == JOB_AVAILABLE)
|
||||
job_count++;
|
||||
if (job_count > round(available_job_count / 2))
|
||||
dat += "</div><div class='jobsColumn'>"
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
//Blood regeneration if there is some space
|
||||
if(blood_volume < BLOOD_VOLUME_NORMAL)
|
||||
blood_volume += 0.1 // regenerate blood VERY slowly
|
||||
if(blood_volume < BLOOD_VOLUME_OKAY)
|
||||
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
|
||||
|
||||
// Takes care blood loss and regeneration
|
||||
/mob/living/carbon/human/handle_blood()
|
||||
|
||||
@@ -169,9 +169,9 @@
|
||||
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
|
||||
var/turf/end_T = get_turf(target)
|
||||
if(start_T && end_T)
|
||||
var/start_T_descriptor = "<font color='#6b5d00'>tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]</font>"
|
||||
var/end_T_descriptor = "<font color='#6b4400'>tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]</font>"
|
||||
add_logs(src, throwable_mob, "thrown", addition="from [start_T_descriptor] with the target [end_T_descriptor]")
|
||||
var/start_T_descriptor = "tile in [get_area_name(start_T, TRUE)] ([start_T.x],[start_T.y],[start_T.z])"
|
||||
var/end_T_descriptor = "tile at [get_area_name(end_T, TRUE)] ([end_T.x],[end_T.y],[end_T.z])"
|
||||
add_logs(src, throwable_mob, "thrown", addition="grab from [start_T_descriptor] towards [end_T_descriptor]")
|
||||
|
||||
else if(!(I.flags_1 & (NODROP_1|ABSTRACT_1)))
|
||||
thrown_thing = I
|
||||
@@ -185,7 +185,7 @@
|
||||
|
||||
if(thrown_thing)
|
||||
visible_message("<span class='danger'>[src] has thrown [thrown_thing].</span>")
|
||||
add_logs(src, thrown_thing, "has thrown")
|
||||
add_logs(src, thrown_thing, "thrown")
|
||||
newtonian_move(get_dir(target, src))
|
||||
thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src)
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
if(movement_type & FLYING)
|
||||
return 0
|
||||
if(!(lube&SLIDE_ICE))
|
||||
add_logs(src,, "slipped",, "on [O ? O.name : "floor"]")
|
||||
add_logs(src, (O ? O : get_turf(src)), "slipped on the", null, ((lube & SLIDE) ? "(LUBE)" : null))
|
||||
return loc.handle_slip(src, knockdown_amount, O, lube)
|
||||
|
||||
/mob/living/carbon/Process_Spacemove(movement_dir = 0)
|
||||
|
||||
@@ -647,6 +647,9 @@
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/LB = X
|
||||
missing -= LB.body_zone
|
||||
if(LB.is_pseudopart) //don't show injury text for fake bodyparts; ie chainsaw arms or synthetic armblades
|
||||
continue
|
||||
var/limb_max_damage = LB.max_damage
|
||||
var/status = ""
|
||||
var/brutedamage = LB.brute_dam
|
||||
var/burndamage = LB.burn_dam
|
||||
@@ -663,20 +666,21 @@
|
||||
|
||||
else
|
||||
if(brutedamage > 0)
|
||||
status = "bruised"
|
||||
if(brutedamage > 20)
|
||||
status = "battered"
|
||||
if(brutedamage > 40)
|
||||
status = "mangled"
|
||||
status = LB.light_brute_msg
|
||||
if(brutedamage > (limb_max_damage*0.4))
|
||||
status = LB.medium_brute_msg
|
||||
if(brutedamage > (limb_max_damage*0.8))
|
||||
status = LB.heavy_brute_msg
|
||||
if(brutedamage > 0 && burndamage > 0)
|
||||
status += " and "
|
||||
if(burndamage > 40)
|
||||
status += "peeling away"
|
||||
|
||||
else if(burndamage > 10)
|
||||
status += "blistered"
|
||||
if(burndamage > (limb_max_damage*0.8))
|
||||
status += LB.heavy_burn_msg
|
||||
else if(burndamage > (limb_max_damage*0.2))
|
||||
status += LB.medium_burn_msg
|
||||
else if(burndamage > 0)
|
||||
status += "numb"
|
||||
status += LB.light_burn_msg
|
||||
|
||||
if(status == "")
|
||||
status = "OK"
|
||||
var/no_damage
|
||||
|
||||
@@ -618,23 +618,25 @@
|
||||
return pick("trails_1", "trails_2")
|
||||
|
||||
/mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0)
|
||||
if (client && client.move_delay >= world.time + world.tick_lag*2)
|
||||
if(buckled)
|
||||
return
|
||||
if(client && client.move_delay >= world.time + world.tick_lag*2)
|
||||
pressure_resistance_prob_delta -= 30
|
||||
|
||||
var/list/turfs_to_check = list()
|
||||
|
||||
if (has_limbs)
|
||||
if(has_limbs)
|
||||
var/turf/T = get_step(src, angle2dir(dir2angle(direction)+90))
|
||||
if (T)
|
||||
turfs_to_check += T
|
||||
|
||||
T = get_step(src, angle2dir(dir2angle(direction)-90))
|
||||
if (T)
|
||||
if(T)
|
||||
turfs_to_check += T
|
||||
|
||||
for (var/t in turfs_to_check)
|
||||
for(var/t in turfs_to_check)
|
||||
T = t
|
||||
if (T.density)
|
||||
if(T.density)
|
||||
pressure_resistance_prob_delta -= 20
|
||||
continue
|
||||
for (var/atom/movable/AM in T)
|
||||
@@ -760,10 +762,10 @@
|
||||
var/list/L = where
|
||||
if(what == who.get_item_for_held_index(L[2]))
|
||||
if(who.dropItemToGround(what))
|
||||
add_logs(src, who, "stripped", addition="of [what]")
|
||||
add_logs(src, who, "stripped [what] off")
|
||||
if(what == who.get_item_by_slot(where))
|
||||
if(who.dropItemToGround(what))
|
||||
add_logs(src, who, "stripped", addition="of [what]")
|
||||
add_logs(src, who, "stripped [what] off")
|
||||
|
||||
// The src mob is trying to place an item on someone
|
||||
// Override if a certain mob should be behave differently when placing items (can't, for example)
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
var/icontype = input("Please, select a display!", "AI", null/*, null*/) in list("Clown", "Monochrome", "Blue", "Inverted", "Firewall", "Green", "Red", "Static", "Red October", "House", "Heartline", "Hades", "Helios", "President", "Syndicat Meow", "Alien", "Too Deep", "Triumvirate", "Triumvirate-M", "Text", "Matrix", "Dorf", "Bliss", "Not Malf", "Fuzzy", "Goon", "Database", "Glitchman", "Murica", "Nanotrasen", "Gentoo", "Angel")
|
||||
var/icontype = input("Please, select a display!", "AI", null/*, null*/) in list("Clown", "Monochrome", "Blue", "Inverted", "Firewall", "Green", "Red", "Static", "Red October", "House", "Heartline", "Hades", "Helios", "President", "Syndicat Meow", "Alien", "Too Deep", "Triumvirate", "Triumvirate-M", "Text", "Matrix", "Dorf", "Bliss", "Not Malf", "Fuzzy", "Goon", "Database", "Glitchman", "Murica", "Nanotrasen", "Gentoo", "Angel", "TechDemon") //CIT CHANGE - adds 'TechDemon
|
||||
if(icontype == "Clown")
|
||||
icon_state = "ai-clown2"
|
||||
else if(icontype == "Monochrome")
|
||||
@@ -236,7 +236,8 @@
|
||||
icon_state = "ai-gentoo"
|
||||
else if(icontype == "Angel")
|
||||
icon_state = "ai-angel"
|
||||
|
||||
else if(icontype == "TechDemon") //CIT CHANGE - adds 'TechDemon
|
||||
icon_state = "tech_demon"
|
||||
/mob/living/silicon/ai/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
|
||||
@@ -159,6 +159,8 @@
|
||||
toner = tonermax
|
||||
diag_hud_set_borgcell()
|
||||
|
||||
verbs += /mob/living/proc/lay_down //CITADEL EDIT gimmie rest verb kthx
|
||||
|
||||
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
|
||||
/mob/living/silicon/robot/Destroy()
|
||||
if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside.
|
||||
|
||||
@@ -143,6 +143,7 @@ Difficulty: Very Hard
|
||||
INVOKE_ASYNC(src, .proc/spiral_shoot, TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/spiral_shoot(negative = FALSE, counter_start = 8)
|
||||
var/turf/start_turf = get_step(src, pick(GLOB.alldirs))
|
||||
var/counter = counter_start
|
||||
for(var/i in 1 to 80)
|
||||
if(negative)
|
||||
@@ -153,7 +154,7 @@ Difficulty: Very Hard
|
||||
counter = 1
|
||||
if(counter < 1)
|
||||
counter = 16
|
||||
shoot_projectile(null, counter * 22.5)
|
||||
shoot_projectile(start_turf, counter * 22.5)
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, 1)
|
||||
sleep(1)
|
||||
|
||||
@@ -184,7 +185,7 @@ Difficulty: Very Hard
|
||||
angle_to_target = set_angle
|
||||
var/static/list/colossus_shotgun_shot_angles = list(12.5, 7.5, 2.5, -2.5, -7.5, -12.5)
|
||||
for(var/i in colossus_shotgun_shot_angles)
|
||||
shoot_projectile(null, angle_to_target + i)
|
||||
shoot_projectile(target_turf, angle_to_target + i)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/dir_shots(list/dirs)
|
||||
if(!islist(dirs))
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/obj/item/device/modular_computer/attack_self(mob/user)
|
||||
. = ..()
|
||||
ui_interact(user)
|
||||
|
||||
// Operates TGUI
|
||||
/obj/item/device/modular_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
if(!enabled)
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
/obj/singularity/process()
|
||||
if(current_size >= STAGE_TWO)
|
||||
move()
|
||||
radiation_pulse(src, min(5000, (energy*3)+1000), RAD_DISTANCE_COEFFICIENT*0.5)
|
||||
radiation_pulse(src, min(5000, (energy*4.5)+1000), RAD_DISTANCE_COEFFICIENT*0.5)
|
||||
if(prob(event_chance))//Chance for it to run a special event TODO:Come up with one or two more that fit
|
||||
event()
|
||||
eat()
|
||||
|
||||
@@ -254,9 +254,7 @@
|
||||
current_user.setDir(SOUTH)
|
||||
if(226 to 315)
|
||||
current_user.setDir(WEST)
|
||||
var/difference = abs(lastangle - angle)
|
||||
if(difference > 350) //Too lazy to properly math, detects 360 --> 0 changes.
|
||||
difference = (lastangle > 350? ((360 - lastangle) + angle) : ((360 - angle) + lastangle))
|
||||
var/difference = abs(closer_angle_difference(lastangle, angle))
|
||||
delay_penalty(difference * aiming_time_increase_angle_multiplier)
|
||||
lastangle = angle
|
||||
|
||||
@@ -292,7 +290,7 @@
|
||||
current_user = null
|
||||
if(istype(user))
|
||||
current_user = user
|
||||
LAZYADD(current_user.mousemove_intercept_objects, src)
|
||||
LAZYOR(current_user.mousemove_intercept_objects, src)
|
||||
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED), CALLBACK(src, .proc/on_mob_move))
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
|
||||
|
||||
@@ -46,8 +46,6 @@
|
||||
var/ricochets_max = 2
|
||||
var/ricochet_chance = 30
|
||||
|
||||
var/colliding = FALSE //pause processing..
|
||||
|
||||
//Hitscan
|
||||
var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored.
|
||||
var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation.
|
||||
@@ -57,6 +55,15 @@
|
||||
var/muzzle_type
|
||||
var/impact_type
|
||||
|
||||
//Homing
|
||||
var/homing = FALSE
|
||||
var/atom/homing_target
|
||||
var/homing_turn_speed = 10 //Angle per tick.
|
||||
var/homing_inaccuracy_min = 0 //in pixels for these. offsets are set once when setting target.
|
||||
var/homing_inaccuracy_max = 0
|
||||
var/homing_offset_x = 0
|
||||
var/homing_offset_y = 0
|
||||
|
||||
var/ignore_source_check = FALSE
|
||||
|
||||
var/damage = 10
|
||||
@@ -192,7 +199,6 @@
|
||||
beam_segments[beam_index] = null
|
||||
|
||||
/obj/item/projectile/Collide(atom/A)
|
||||
colliding = TRUE
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
|
||||
ricochets++
|
||||
@@ -208,7 +214,6 @@
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(get_turf(A))
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
|
||||
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
|
||||
@@ -227,7 +232,6 @@
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(target_turf)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
|
||||
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
|
||||
@@ -237,17 +241,14 @@
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
if(A)
|
||||
permutated.Add(A)
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
else
|
||||
var/atom/alt = select_target(A)
|
||||
if(alt)
|
||||
if(!prehit(alt))
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
alt.bullet_act(src, def_zone)
|
||||
qdel(src)
|
||||
colliding = FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
|
||||
@@ -324,7 +325,7 @@
|
||||
/obj/item/projectile/proc/fire(angle, atom/direct_target)
|
||||
//If no angle needs to resolve it from xo/yo!
|
||||
if(!log_override && firer && original)
|
||||
add_logs(firer, original, "fired at", src, " [get_area(src)]")
|
||||
add_logs(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]")
|
||||
if(direct_target)
|
||||
if(prehit(direct_target))
|
||||
direct_target.bullet_act(src, def_zone)
|
||||
@@ -350,7 +351,7 @@
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(starting)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed)
|
||||
trajectory = new(starting.x, starting.y, starting.z, pixel_x, pixel_y, Angle, pixel_speed)
|
||||
last_projectile_move = world.time
|
||||
fired = TRUE
|
||||
if(hitscan)
|
||||
@@ -417,6 +418,8 @@
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
if(homing)
|
||||
process_homing()
|
||||
trajectory.increment(trajectory_multiplier)
|
||||
var/turf/T = trajectory.return_turf()
|
||||
if(!istype(T))
|
||||
@@ -445,10 +448,32 @@
|
||||
Collide(original)
|
||||
Range()
|
||||
|
||||
/obj/item/projectile/proc/process_homing() //may need speeding up in the future performance wise.
|
||||
if(!homing_target)
|
||||
return FALSE
|
||||
var/datum/point/PT = RETURN_PRECISE_POINT(homing_target)
|
||||
PT.x += CLAMP(homing_offset_x, 1, world.maxx)
|
||||
PT.y += CLAMP(homing_offset_y, 1, world.maxy)
|
||||
var/angle = closer_angle_difference(Angle, angle_between_points(RETURN_PRECISE_POINT(src), PT))
|
||||
setAngle(Angle + CLAMP(angle, -homing_turn_speed, homing_turn_speed))
|
||||
|
||||
/obj/item/projectile/proc/set_homing_target(atom/A)
|
||||
if(!A || (!isturf(A) && !isturf(A.loc)))
|
||||
return FALSE
|
||||
homing = TRUE
|
||||
homing_target = A
|
||||
homing_offset_x = rand(homing_inaccuracy_min, homing_inaccuracy_max)
|
||||
homing_offset_y = rand(homing_inaccuracy_min, homing_inaccuracy_max)
|
||||
if(prob(50))
|
||||
homing_offset_x = -homing_offset_x
|
||||
if(prob(50))
|
||||
homing_offset_y = -homing_offset_y
|
||||
|
||||
//Returns true if the target atom is on our current turf and above the right layer
|
||||
/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
|
||||
return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
|
||||
|
||||
//Spread is FORCED!
|
||||
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
|
||||
var/turf/curloc = get_turf(source)
|
||||
var/turf/targloc = get_turf(target)
|
||||
@@ -460,7 +485,7 @@
|
||||
if(targloc || !params)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
setAngle(Get_Angle(src, targloc))
|
||||
setAngle(Get_Angle(src, targloc) + spread)
|
||||
|
||||
//CIT CHANGES START HERE - makes it so laying down makes you unable to shoot through most objects
|
||||
if(iscarbon(source))
|
||||
@@ -474,14 +499,11 @@
|
||||
p_x = calculated[2]
|
||||
p_y = calculated[3]
|
||||
|
||||
if(spread)
|
||||
setAngle(calculated[1] + spread)
|
||||
else
|
||||
setAngle(calculated[1])
|
||||
setAngle(calculated[1] + spread)
|
||||
else if(targloc)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
setAngle(Get_Angle(src, targloc))
|
||||
setAngle(Get_Angle(src, targloc) + spread)
|
||||
else
|
||||
stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
|
||||
qdel(src)
|
||||
|
||||
@@ -159,11 +159,12 @@
|
||||
new_mob.invisibility = 0
|
||||
new_mob.job = "Cyborg"
|
||||
var/mob/living/silicon/robot/Robot = new_mob
|
||||
Robot.lawupdate = FALSE
|
||||
Robot.connected_ai = null
|
||||
Robot.mmi.transfer_identity(M) //Does not transfer key/client.
|
||||
Robot.clear_inherent_laws(0)
|
||||
Robot.clear_zeroth_law(0, 0)
|
||||
Robot.connected_ai = null
|
||||
|
||||
Robot.clear_zeroth_law(0)
|
||||
|
||||
if("slime")
|
||||
new_mob = new /mob/living/simple_animal/slime/random(M.loc)
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/obj/item/projectile/spellcard
|
||||
name = "enchanted card"
|
||||
desc = "A piece of paper enchanted to give it extreme durability and stiffness, along with a very hot burn to anyone unfortunate enough to get hit by a charged one."
|
||||
icon_state = "spellcard"
|
||||
damage_type = BURN
|
||||
damage = 2
|
||||
@@ -14,11 +14,12 @@
|
||||
var/obj/item/stock_parts/cell/cell
|
||||
var/powerefficiency = 0.1
|
||||
var/amount = 30
|
||||
var/recharged = 0
|
||||
var/recharge_delay = 5
|
||||
var/recharge_amount = 10
|
||||
var/recharge_counter = 0
|
||||
var/mutable_appearance/beaker_overlay
|
||||
var/working_state = "dispenser_working"
|
||||
var/nopower_state = "dispenser_nopower"
|
||||
var/has_panel_overlay = TRUE
|
||||
var/macrotier = 1
|
||||
var/obj/item/reagent_containers/beaker = null
|
||||
var/list/dispensable_reagents = list(
|
||||
@@ -62,7 +63,6 @@
|
||||
/obj/machinery/chem_dispenser/Initialize()
|
||||
. = ..()
|
||||
cell = new cell_type
|
||||
recharge()
|
||||
dispensable_reagents = sortList(dispensable_reagents)
|
||||
update_icon()
|
||||
|
||||
@@ -71,12 +71,21 @@
|
||||
QDEL_NULL(cell)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_dispenser/examine(mob/user)
|
||||
..()
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>[src]'s maintenance hatch is open!</span>")
|
||||
|
||||
/obj/machinery/chem_dispenser/process()
|
||||
if(recharged < 0)
|
||||
recharge()
|
||||
recharged = recharge_delay
|
||||
else
|
||||
recharged -= 1
|
||||
if (recharge_counter >= 4)
|
||||
if(!is_operational())
|
||||
return
|
||||
var/usedpower = cell.give(recharge_amount)
|
||||
if(usedpower)
|
||||
use_power(250*recharge_amount)
|
||||
recharge_counter = 0
|
||||
return
|
||||
recharge_counter++
|
||||
|
||||
/obj/machinery/chem_dispenser/proc/display_beaker()
|
||||
..()
|
||||
@@ -91,23 +100,18 @@ obj/machinery/chem_dispenser/proc/work_animation()
|
||||
|
||||
/obj/machinery/chem_dispenser/power_change()
|
||||
..()
|
||||
if(!powered() && nopower_state)
|
||||
icon_state = nopower_state
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
icon_state = "[(nopower_state && !powered()) ? nopower_state : initial(icon_state)]"
|
||||
|
||||
obj/machinery/chem_dispenser/update_icon()
|
||||
/obj/machinery/chem_dispenser/update_icon()
|
||||
cut_overlays()
|
||||
if(has_panel_overlay && panel_open)
|
||||
add_overlay(mutable_appearance(icon, "[initial(icon_state)]_panel-o"))
|
||||
|
||||
if(beaker)
|
||||
beaker_overlay = display_beaker()
|
||||
add_overlay(beaker_overlay)
|
||||
|
||||
/obj/machinery/chem_dispenser/proc/recharge()
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
var/usedpower = cell.give( 1 / powerefficiency) //Should always be a gain of one on the UI.
|
||||
if(usedpower)
|
||||
use_power(2500)
|
||||
|
||||
|
||||
/obj/machinery/chem_dispenser/emag_act(mob/user)
|
||||
if(obj_flags & EMAGGED)
|
||||
@@ -188,23 +192,32 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
return
|
||||
switch(action)
|
||||
if("amount")
|
||||
if(!is_operational())
|
||||
return
|
||||
var/target = text2num(params["target"])
|
||||
if(target in beaker.possible_transfer_amounts)
|
||||
amount = target
|
||||
work_animation()
|
||||
. = TRUE
|
||||
if("dispense")
|
||||
if(!is_operational() || QDELETED(cell))
|
||||
return
|
||||
var/reagent = params["reagent"]
|
||||
if(beaker && dispensable_reagents.Find(reagent))
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/free = R.maximum_volume - R.total_volume
|
||||
var/actual = min(amount, (cell.charge * powerefficiency)*10, free)
|
||||
|
||||
if(!cell.use(actual / powerefficiency))
|
||||
say("Not enough energy to complete operation!")
|
||||
return
|
||||
R.add_reagent(reagent, actual)
|
||||
cell.use(actual / powerefficiency)
|
||||
|
||||
work_animation()
|
||||
. = TRUE
|
||||
if("remove")
|
||||
if(!is_operational())
|
||||
return
|
||||
var/amount = text2num(params["amount"])
|
||||
if(beaker && amount in beaker.possible_transfer_amounts)
|
||||
beaker.reagents.remove_all(amount)
|
||||
@@ -219,6 +232,8 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
update_icon()
|
||||
. = TRUE
|
||||
if("dispense_recipe")
|
||||
if(!is_operational() || QDELETED(cell))
|
||||
return
|
||||
var/recipe_to_use = params["recipe"]
|
||||
var/list/chemicals_to_dispense = process_recipe_list(recipe_to_use)
|
||||
var/res = get_macro_resolution()
|
||||
@@ -230,16 +245,24 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
var/free = R.maximum_volume - R.total_volume
|
||||
var/actual = min(round(chemicals_to_dispense[key], res), (cell.charge * powerefficiency)*10, free)
|
||||
if(actual)
|
||||
if(!cell.use(actual / powerefficiency))
|
||||
say("Not enough energy to complete operation!")
|
||||
return
|
||||
R.add_reagent(r_id, actual)
|
||||
cell.use(actual / powerefficiency)
|
||||
work_animation()
|
||||
if("clear_recipes")
|
||||
if(!is_operational())
|
||||
return
|
||||
var/yesno = alert("Clear all recipes?",, "Yes","No")
|
||||
if(yesno == "Yes")
|
||||
saved_recipes = list()
|
||||
if("add_recipe")
|
||||
if(!is_operational())
|
||||
return
|
||||
var/name = stripped_input(usr,"Name","What do you want to name this recipe?", "Recipe", MAX_NAME_LEN)
|
||||
var/recipe = stripped_input(usr,"Recipe","Insert recipe with chem IDs")
|
||||
if(!usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
if(name && recipe)
|
||||
var/list/first_process = splittext(recipe, ";")
|
||||
if(!LAZYLEN(first_process))
|
||||
@@ -265,7 +288,8 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
|
||||
if(default_unfasten_wrench(user, I))
|
||||
return
|
||||
if(default_deconstruction_screwdriver(user, "dispenser-o", "dispenser", I))
|
||||
if(default_deconstruction_screwdriver(user, icon_state, icon_state, I))
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(exchange_parts(user, I))
|
||||
@@ -313,15 +337,14 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
|
||||
|
||||
/obj/machinery/chem_dispenser/RefreshParts()
|
||||
var/time = 0
|
||||
recharge_amount = initial(recharge_amount)
|
||||
var/newpowereff = 0.0666666
|
||||
for(var/obj/item/stock_parts/cell/P in component_parts)
|
||||
cell = P
|
||||
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
|
||||
newpowereff += 0.0166666666*M.rating
|
||||
for(var/obj/item/stock_parts/capacitor/C in component_parts)
|
||||
time += C.rating
|
||||
recharge_delay = 30/(time/2) //delay between recharges, double the usual time on lowest 50% less than usual on highest
|
||||
recharge_amount *= C.rating
|
||||
for(var/obj/item/stock_parts/manipulator/M in component_parts)
|
||||
if (M.rating > macrotier)
|
||||
macrotier = M.rating
|
||||
@@ -386,6 +409,7 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
anchored = TRUE
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "soda_dispenser"
|
||||
has_panel_overlay = FALSE
|
||||
amount = 10
|
||||
pixel_y = 6
|
||||
layer = WALL_OBJ_LAYER
|
||||
|
||||
@@ -73,12 +73,6 @@
|
||||
if (prob(50))
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/chem_master/power_change()
|
||||
if(powered())
|
||||
stat &= ~NOPOWER
|
||||
else
|
||||
stat |= NOPOWER
|
||||
|
||||
/obj/machinery/chem_master/attackby(obj/item/I, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, "mixer0_nopower", "mixer0", I))
|
||||
return
|
||||
@@ -223,7 +217,7 @@
|
||||
return
|
||||
vol_each = min(reagents.total_volume / amount, 50)
|
||||
var/name = stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
var/obj/item/reagent_containers/pill/P
|
||||
|
||||
@@ -237,7 +231,7 @@
|
||||
reagents.trans_to(P,vol_each)
|
||||
else
|
||||
var/name = stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
|
||||
|
||||
@@ -259,7 +253,7 @@
|
||||
return
|
||||
vol_each = min(reagents.total_volume / amount, 40)
|
||||
var/name = stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
var/obj/item/reagent_containers/pill/P
|
||||
|
||||
@@ -277,7 +271,7 @@
|
||||
|
||||
if(condi)
|
||||
var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
var/obj/item/reagent_containers/food/condiment/P = new(drop_location())
|
||||
P.originalname = name
|
||||
@@ -290,7 +284,7 @@
|
||||
amount_full = round(reagents.total_volume / 30)
|
||||
vol_part = reagents.total_volume % 30
|
||||
var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
|
||||
var/obj/item/reagent_containers/glass/bottle/P
|
||||
|
||||
@@ -615,7 +615,19 @@
|
||||
to_chat(M, "<span class = 'warning'>Your eyes sting!</span>")
|
||||
M.blind_eyes(2)
|
||||
|
||||
/datum/reagent/consumable/nutriment/stabilized
|
||||
name = "Stabilized Nutriment"
|
||||
id = "stabilizednutriment"
|
||||
description = "A bioengineered protien-nutrient structure designed to decompose in high saturation. In layman's terms, it won't get you fat."
|
||||
reagent_state = SOLID
|
||||
nutriment_factor = 15 * REAGENTS_METABOLISM
|
||||
color = "#664330" // rgb: 102, 67, 48
|
||||
|
||||
/datum/reagent/consumable/nutriment/stabilized/on_mob_life(mob/living/M)
|
||||
if(M.nutrition > NUTRITION_LEVEL_FULL - 25)
|
||||
M.nutrition -= 3*nutriment_factor
|
||||
..()
|
||||
|
||||
////Lavaland Flora Reagents////
|
||||
|
||||
|
||||
@@ -673,4 +685,4 @@
|
||||
description = "The sorrow and melancholy of a thousand bereaved clowns, forever denied their Honkmechs."
|
||||
nutriment_factor = 5 * REAGENTS_METABOLISM
|
||||
color = "#eef442" // rgb: 238, 244, 66
|
||||
taste_description = "mournful honking"
|
||||
taste_description = "mournful honking"
|
||||
|
||||
@@ -17,13 +17,17 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi
|
||||
display_contents_with_number = 1
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = 100
|
||||
|
||||
can_hold = list(
|
||||
/obj/item/reagent_containers/glass/beaker,
|
||||
/obj/item/device/assembly/igniter,
|
||||
/obj/item/stock_parts,
|
||||
/obj/item/stack/ore/bluespace_crystal)
|
||||
|
||||
var/works_from_distance = 0
|
||||
var/pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/rped.ogg'
|
||||
var/alt_sound = null
|
||||
|
||||
/obj/item/storage/part_replacer/can_be_inserted(obj/item/W, stop_messages = 0, mob/user)
|
||||
return ..() && W.get_part_rating()
|
||||
|
||||
/obj/item/storage/part_replacer/afterattack(obj/machinery/T, mob/living/carbon/human/user, flag, params)
|
||||
if(flag)
|
||||
return
|
||||
|
||||
@@ -82,15 +82,13 @@
|
||||
var/mob/living/carbon/human/H = mover
|
||||
if(H.nutrition >= NUTRITION_LEVEL_FAT)
|
||||
H.visible_message("<span class='warning'>[H] pushes through [src]!</span>", "<span class='notice'>You've seen and eaten worse than this.</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
else
|
||||
to_chat(H, "<span class='warning'>You're repulsed by even looking at [src]. Only a pig could force themselves to go through it.</span>")
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/morph))
|
||||
return 1
|
||||
return TRUE
|
||||
else
|
||||
return 0
|
||||
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/structure/mirror/magic/pride //Pride's mirror: Used in the Pride ruin.
|
||||
name = "pride's mirror"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
var/list/projectile_var_overrides = list()
|
||||
var/projectile_amount = 1 //Projectiles per cast.
|
||||
var/current_amount = 0 //How many projectiles left.
|
||||
var/projectiles_per_fire = 1 //Projectiles per fire. Probably not a good thing to use unless you override ready_projectile().
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/Click()
|
||||
var/mob/living/user = usr
|
||||
@@ -26,10 +27,18 @@
|
||||
charge_counter = charge_max * refund_percent
|
||||
start_recharge()
|
||||
remove_ranged_ability(msg)
|
||||
on_deactivation(user)
|
||||
else
|
||||
msg = "<span class='notice'>[active_msg]<B>Left-click to shoot it at a target!</B></span>"
|
||||
current_amount = projectile_amount
|
||||
add_ranged_ability(user, msg, TRUE)
|
||||
on_activation(user)
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/proc/on_activation(mob/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/proc/on_deactivation(mob/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/update_icon()
|
||||
if(!action)
|
||||
@@ -60,19 +69,25 @@
|
||||
remove_ranged_ability() //Auto-disable the ability once you run out of bullets.
|
||||
charge_counter = 0
|
||||
start_recharge()
|
||||
on_deactivation(user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/proc/fire_projectile(mob/living/user, atom/target)
|
||||
current_amount--
|
||||
var/obj/item/projectile/P = new projectile_type(user.loc)
|
||||
P.firer = user
|
||||
P.preparePixelProjectile(target, user)
|
||||
for(var/V in projectile_var_overrides)
|
||||
if(P.vars[V])
|
||||
P.vv_edit_var(V, projectile_var_overrides[V])
|
||||
P.fire()
|
||||
for(var/i in 1 to projectiles_per_fire)
|
||||
var/obj/item/projectile/P = new projectile_type(user.loc)
|
||||
P.firer = user
|
||||
P.preparePixelProjectile(target, user)
|
||||
for(var/V in projectile_var_overrides)
|
||||
if(P.vars[V])
|
||||
P.vv_edit_var(V, projectile_var_overrides[V])
|
||||
ready_projectile(P, target, user, i)
|
||||
P.fire()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/proc/ready_projectile(obj/item/projectile/P, atom/target, mob/user, iteration)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/lightningbolt
|
||||
name = "Lightning Bolt"
|
||||
desc = "Fire a high powered lightning bolt at your foes!"
|
||||
@@ -108,3 +123,58 @@
|
||||
active_msg = "You prepare to cast your fireball spell!"
|
||||
deactive_msg = "You extinguish your fireball... for now."
|
||||
active = FALSE
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards
|
||||
name = "Spell Cards"
|
||||
desc = "Blazing hot rapid-fire homing cards. Banish your foes with its mystical power!"
|
||||
school = "evocation"
|
||||
charge_max = 50
|
||||
clothes_req = 0
|
||||
invocation = "Sigi'lu M'Fan 'Tasia"
|
||||
invocation_type = "shout"
|
||||
range = 40
|
||||
cooldown_min = 10
|
||||
projectile_amount = 5
|
||||
projectiles_per_fire = 7
|
||||
projectile_type = /obj/item/projectile/spellcard
|
||||
var/datum/weakref/current_target_weakref
|
||||
var/projectile_turnrate = 10
|
||||
var/projectile_pixel_homing_spread = 32
|
||||
var/projectile_initial_spread_amount = 30
|
||||
var/projectile_location_spread_amount = 12
|
||||
var/datum/component/lockon_aiming/lockon_component
|
||||
ranged_clickcd_override = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards/on_activation(mob/M)
|
||||
QDEL_NULL(lockon_component)
|
||||
lockon_component = M.AddComponent(/datum/component/lockon_aiming, 5, typecacheof(list(/mob/living)), 1, null, CALLBACK(src, .proc/on_lockon_component))
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards/proc/on_lockon_component(list/locked_weakrefs)
|
||||
if(!length(locked_weakrefs))
|
||||
current_target_weakref = null
|
||||
return
|
||||
current_target_weakref = locked_weakrefs[1]
|
||||
var/atom/A = current_target_weakref.resolve()
|
||||
if(A)
|
||||
var/mob/M = lockon_component.parent
|
||||
M.face_atom(A)
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards/on_deactivation(mob/M)
|
||||
QDEL_NULL(lockon_component)
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards/ready_projectile(obj/item/projectile/P, atom/target, mob/user, iteration)
|
||||
if(current_target_weakref)
|
||||
var/atom/A = current_target_weakref.resolve()
|
||||
if(A && get_dist(A, user) < 7)
|
||||
P.homing_turn_speed = projectile_turnrate
|
||||
P.homing_inaccuracy_min = projectile_pixel_homing_spread
|
||||
P.homing_inaccuracy_max = projectile_pixel_homing_spread
|
||||
P.set_homing_target(current_target_weakref.resolve())
|
||||
var/rand_spr = rand()
|
||||
var/total_angle = projectile_initial_spread_amount * 2
|
||||
var/adjusted_angle = total_angle - ((projectile_initial_spread_amount / projectiles_per_fire) * 0.5)
|
||||
var/one_fire_angle = adjusted_angle / projectiles_per_fire
|
||||
var/current_angle = iteration * one_fire_angle * rand_spr - (projectile_initial_spread_amount / 2)
|
||||
P.pixel_x = rand(-projectile_location_spread_amount, projectile_location_spread_amount)
|
||||
P.pixel_y = rand(-projectile_location_spread_amount, projectile_location_spread_amount)
|
||||
P.preparePixelProjectile(target, user, null, current_angle)
|
||||
|
||||
@@ -43,6 +43,15 @@
|
||||
var/species_flags_list = list()
|
||||
var/dmg_overlay_type //the type of damage overlay (if any) to use when this bodypart is bruised/burned.
|
||||
|
||||
//Damage messages used by help_shake_act()
|
||||
var/light_brute_msg = "bruised"
|
||||
var/medium_brute_msg = "battered"
|
||||
var/heavy_brute_msg = "mangled"
|
||||
|
||||
var/light_burn_msg = "numb"
|
||||
var/medium_burn_msg = "blistered"
|
||||
var/heavy_burn_msg = "peeling away"
|
||||
|
||||
/obj/item/bodypart/examine(mob/user)
|
||||
..()
|
||||
if(brute_dam > 0)
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
#define ROBOTIC_LIGHT_BRUTE_MSG "marred"
|
||||
#define ROBOTIC_MEDIUM_BRUTE_MSG "dented"
|
||||
#define ROBOTIC_HEAVY_BRUTE_MSG "falling apart"
|
||||
|
||||
#define ROBOTIC_LIGHT_BURN_MSG "scorched"
|
||||
#define ROBOTIC_MEDIUM_BURN_MSG "charred"
|
||||
#define ROBOTIC_HEAVY_BURN_MSG "smoldering"
|
||||
|
||||
/obj/item/bodypart/l_arm/robot
|
||||
name = "cyborg left arm"
|
||||
@@ -10,6 +16,13 @@
|
||||
icon_state = "borg_l_arm"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
/obj/item/bodypart/r_arm/robot
|
||||
name = "cyborg right arm"
|
||||
@@ -21,6 +34,13 @@
|
||||
icon_state = "borg_r_arm"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
/obj/item/bodypart/l_leg/robot
|
||||
name = "cyborg left leg"
|
||||
@@ -32,6 +52,13 @@
|
||||
icon_state = "borg_l_leg"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
/obj/item/bodypart/r_leg/robot
|
||||
name = "cyborg right leg"
|
||||
@@ -43,6 +70,13 @@
|
||||
icon_state = "borg_r_leg"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
/obj/item/bodypart/chest/robot
|
||||
name = "cyborg torso"
|
||||
@@ -52,6 +86,15 @@
|
||||
flags_1 = CONDUCT_1
|
||||
icon_state = "borg_chest"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
var/wired = 0
|
||||
var/obj/item/stock_parts/cell/cell = null
|
||||
|
||||
@@ -102,6 +145,15 @@
|
||||
flags_1 = CONDUCT_1
|
||||
icon_state = "borg_head"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
var/obj/item/device/assembly/flash/handheld/flash1 = null
|
||||
var/obj/item/device/assembly/flash/handheld/flash2 = null
|
||||
|
||||
@@ -189,3 +241,12 @@
|
||||
icon = 'icons/mob/augmentation/surplus_augments.dmi'
|
||||
icon_state = "r_leg"
|
||||
max_damage = 20
|
||||
|
||||
|
||||
#undef ROBOTIC_LIGHT_BRUTE_MSG
|
||||
#undef ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
#undef ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
#undef ROBOTIC_LIGHT_BURN_MSG
|
||||
#undef ROBOTIC_MEDIUM_BURN_MSG
|
||||
#undef ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
user.visible_message("[user] drapes [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].", \
|
||||
"<span class='notice'>You drape [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].</span>")
|
||||
|
||||
add_logs(user, M, "operated", addition="Operation type: [procedure.name], location: [selected_zone]")
|
||||
add_logs(user, M, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need to expose [M]'s [parse_zone(selected_zone)] first!</span>")
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
|
||||
actions_types = list(/datum/action/item_action/organ_action/use)
|
||||
sight_flags = SEE_BLACKNESS
|
||||
var/night_vision = TRUE
|
||||
|
||||
/obj/item/organ/eyes/night_vision/ui_action_click()
|
||||
|
||||
@@ -35,6 +35,7 @@ ROUND_END_COUNTDOWN 90
|
||||
## This flag is automatically enabled if SQL_ENABLED isn't
|
||||
ADMIN_LEGACY_SYSTEM
|
||||
|
||||
<<<<<<< HEAD
|
||||
## Comment this out if you want to use the SQL based mentor system, the legacy system uses mentors.txt.
|
||||
## You need to set up your database to use the SQL based system.
|
||||
## This flag is automatically enabled if SQL_ENABLED isn't
|
||||
@@ -42,6 +43,17 @@ MENTOR_LEGACY_SYSTEM
|
||||
|
||||
#Mentors only see ckeys by default. Uncomment to have them only see mob name
|
||||
#MENTORS_MOBNAME_ONLY
|
||||
=======
|
||||
##Uncomment this to stop any admins loaded by the legacy system from having their rank edited by the permissions panel
|
||||
#PROTECT_LEGACY_ADMINS
|
||||
|
||||
##Uncomment this to stop any ranks loaded by the legacy system from having their flags edited by the permissions panel
|
||||
#PROTECT_LEGACY_RANKS
|
||||
>>>>>>> feb9290... Merge pull request #36554 from Jordie0608/tbhthisisntreallyalegacysystemanymore
|
||||
|
||||
##Uncomment this to have admin ranks only loaded from the legacy admin_ranks.txt
|
||||
##If enabled, each time admins are loaded ranks the database will be updated with the current ranks and their flags
|
||||
#LOAD_LEGACY_RANKS_ONLY
|
||||
|
||||
## Comment this out if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system.
|
||||
BAN_LEGACY_SYSTEM
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 387 KiB After Width: | Height: | Size: 388 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 22 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user