Merge branch 'master' into upstream-merge-36442
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
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
*/
|
||||
|
||||
#define LAZYINITLIST(L) if (!L) L = list()
|
||||
#define UNSETEMPTY(L) if (L && !L.len) L = null
|
||||
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
|
||||
#define UNSETEMPTY(L) if (L && !length(L)) L = null
|
||||
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } }
|
||||
#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 <= 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)
|
||||
|
||||
@@ -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)
|
||||
@@ -1,98 +0,0 @@
|
||||
/client
|
||||
var/list/atom/selected_target[2]
|
||||
var/obj/item/active_mousedown_item = null
|
||||
var/mouseParams = ""
|
||||
var/mouseLocation = null
|
||||
var/mouseObject = null
|
||||
var/mouseControlObject = null
|
||||
|
||||
/client/MouseDown(object, location, control, params)
|
||||
var/delay = mob.CanMobAutoclick(object, location, params)
|
||||
if(delay)
|
||||
selected_target[1] = object
|
||||
selected_target[2] = params
|
||||
while(selected_target[1])
|
||||
Click(selected_target[1], location, control, selected_target[2])
|
||||
sleep(delay)
|
||||
active_mousedown_item = mob.canMobMousedown(object, location, params)
|
||||
if(active_mousedown_item)
|
||||
active_mousedown_item.onMouseDown(object, location, params, mob)
|
||||
|
||||
/client/MouseUp(object, location, control, params)
|
||||
selected_target[1] = null
|
||||
if(active_mousedown_item)
|
||||
active_mousedown_item.onMouseUp(object, location, params, mob)
|
||||
active_mousedown_item = null
|
||||
|
||||
/mob/proc/CanMobAutoclick(object, location, params)
|
||||
|
||||
/mob/living/carbon/CanMobAutoclick(atom/object, location, params)
|
||||
if(!object.IsAutoclickable())
|
||||
return
|
||||
var/obj/item/h = get_active_held_item()
|
||||
if(h)
|
||||
. = h.CanItemAutoclick(object, location, params)
|
||||
|
||||
/mob/proc/canMobMousedown(object, location, params)
|
||||
|
||||
/mob/living/carbon/canMobMousedown(atom/object, location, params)
|
||||
var/obj/item/H = get_active_held_item()
|
||||
if(H)
|
||||
. = H.canItemMouseDown(object, location, params)
|
||||
|
||||
/obj/item/proc/CanItemAutoclick(object, location, params)
|
||||
|
||||
/obj/item/proc/canItemMouseDown(object, location, params)
|
||||
if(canMouseDown)
|
||||
return src
|
||||
|
||||
/obj/item/proc/onMouseDown(object, location, params, mob)
|
||||
return
|
||||
|
||||
/obj/item/proc/onMouseUp(object, location, params, mob)
|
||||
return
|
||||
|
||||
/obj/item
|
||||
var/canMouseDown = FALSE
|
||||
|
||||
/obj/item/gun
|
||||
var/automatic = 0 //can gun use it, 0 is no, anything above 0 is the delay between clicks in ds
|
||||
|
||||
/obj/item/gun/CanItemAutoclick(object, location, params)
|
||||
. = automatic
|
||||
|
||||
/atom/proc/IsAutoclickable()
|
||||
. = 1
|
||||
|
||||
/obj/screen/IsAutoclickable()
|
||||
. = 0
|
||||
|
||||
/obj/screen/click_catcher/IsAutoclickable()
|
||||
. = 1
|
||||
|
||||
//Please don't roast me too hard
|
||||
/client/MouseMove(object,location,control,params)
|
||||
mouseParams = params
|
||||
mouseLocation = location
|
||||
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)
|
||||
|
||||
/obj/item/proc/onMouseMove(object, location, control, params)
|
||||
return
|
||||
|
||||
/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
|
||||
mouseParams = params
|
||||
mouseLocation = over_location
|
||||
mouseObject = over_object
|
||||
mouseControlObject = over_control
|
||||
if(selected_target[1] && over_object && over_object.IsAutoclickable())
|
||||
selected_target[1] = over_object
|
||||
selected_target[2] = params
|
||||
if(active_mousedown_item)
|
||||
active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
|
||||
|
||||
/obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
|
||||
return
|
||||
@@ -19,3 +19,120 @@
|
||||
// recieve a mousedrop
|
||||
/atom/proc/MouseDrop_T(atom/dropping, mob/user)
|
||||
return
|
||||
|
||||
|
||||
/client
|
||||
var/list/atom/selected_target[2]
|
||||
var/obj/item/active_mousedown_item = null
|
||||
var/mouseParams = ""
|
||||
var/mouseLocation = null
|
||||
var/mouseObject = null
|
||||
var/mouseControlObject = null
|
||||
var/middragtime = 0
|
||||
var/atom/middragatom
|
||||
|
||||
/client/MouseDown(object, location, control, params)
|
||||
var/delay = mob.CanMobAutoclick(object, location, params)
|
||||
if(delay)
|
||||
selected_target[1] = object
|
||||
selected_target[2] = params
|
||||
while(selected_target[1])
|
||||
Click(selected_target[1], location, control, selected_target[2])
|
||||
sleep(delay)
|
||||
active_mousedown_item = mob.canMobMousedown(object, location, params)
|
||||
if(active_mousedown_item)
|
||||
active_mousedown_item.onMouseDown(object, location, params, mob)
|
||||
|
||||
/client/MouseUp(object, location, control, params)
|
||||
selected_target[1] = null
|
||||
if(active_mousedown_item)
|
||||
active_mousedown_item.onMouseUp(object, location, params, mob)
|
||||
active_mousedown_item = null
|
||||
|
||||
/mob/proc/CanMobAutoclick(object, location, params)
|
||||
|
||||
/mob/living/carbon/CanMobAutoclick(atom/object, location, params)
|
||||
if(!object.IsAutoclickable())
|
||||
return
|
||||
var/obj/item/h = get_active_held_item()
|
||||
if(h)
|
||||
. = h.CanItemAutoclick(object, location, params)
|
||||
|
||||
/mob/proc/canMobMousedown(object, location, params)
|
||||
|
||||
/mob/living/carbon/canMobMousedown(atom/object, location, params)
|
||||
var/obj/item/H = get_active_held_item()
|
||||
if(H)
|
||||
. = H.canItemMouseDown(object, location, params)
|
||||
|
||||
/obj/item/proc/CanItemAutoclick(object, location, params)
|
||||
|
||||
/obj/item/proc/canItemMouseDown(object, location, params)
|
||||
if(canMouseDown)
|
||||
return src
|
||||
|
||||
/obj/item/proc/onMouseDown(object, location, params, mob)
|
||||
return
|
||||
|
||||
/obj/item/proc/onMouseUp(object, location, params, mob)
|
||||
return
|
||||
|
||||
/obj/item
|
||||
var/canMouseDown = FALSE
|
||||
|
||||
/obj/item/gun
|
||||
var/automatic = 0 //can gun use it, 0 is no, anything above 0 is the delay between clicks in ds
|
||||
|
||||
/obj/item/gun/CanItemAutoclick(object, location, params)
|
||||
. = automatic
|
||||
|
||||
/atom/proc/IsAutoclickable()
|
||||
. = 1
|
||||
|
||||
/obj/screen/IsAutoclickable()
|
||||
. = 0
|
||||
|
||||
/obj/screen/click_catcher/IsAutoclickable()
|
||||
. = 1
|
||||
|
||||
//Please don't roast me too hard
|
||||
/client/MouseMove(object,location,control,params)
|
||||
mouseParams = params
|
||||
mouseLocation = location
|
||||
mouseObject = object
|
||||
mouseControlObject = control
|
||||
if(mob && LAZYLEN(mob.mousemove_intercept_objects))
|
||||
for(var/datum/D in mob.mousemove_intercept_objects)
|
||||
D.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)
|
||||
var/list/L = params2list(params)
|
||||
if (L["middle"])
|
||||
if (src_object && src_location != over_location)
|
||||
middragtime = world.time
|
||||
middragatom = src_object
|
||||
else
|
||||
middragtime = 0
|
||||
middragatom = null
|
||||
mouseParams = params
|
||||
mouseLocation = over_location
|
||||
mouseObject = over_object
|
||||
mouseControlObject = over_control
|
||||
if(selected_target[1] && over_object && over_object.IsAutoclickable())
|
||||
selected_target[1] = over_object
|
||||
selected_target[2] = params
|
||||
if(active_mousedown_item)
|
||||
active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
|
||||
|
||||
|
||||
/obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
|
||||
return
|
||||
|
||||
/client/MouseDrop(src_object, over_object, src_location, over_location, src_control, over_control, params)
|
||||
if (middragatom == src_object)
|
||||
middragtime = 0
|
||||
middragatom = null
|
||||
..()
|
||||
@@ -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
|
||||
@@ -341,6 +344,14 @@
|
||||
config_entry_value = null
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/minute_click_limit
|
||||
config_entry_value = 400
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/second_click_limit
|
||||
config_entry_value = 15
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/error_cooldown // The "cooldown" time for each occurrence of a unique error
|
||||
config_entry_value = 600
|
||||
min_val = 0
|
||||
|
||||
@@ -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(..())
|
||||
|
||||
@@ -64,6 +64,22 @@
|
||||
material = WOOD
|
||||
var/drop_amount = 3
|
||||
|
||||
/obj/structure/barricade/wooden/attackby(obj/item/I, mob/user)
|
||||
if(istype(I,/obj/item/stack/sheet/mineral/wood))
|
||||
var/obj/item/stack/sheet/mineral/wood/W = I
|
||||
if(W.amount < 5)
|
||||
to_chat(user, "<span class='warning'>You need at least five wooden planks to make a wall!</span>")
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You start adding [I] to [src]...</span>")
|
||||
if(do_after(user, 50, target=src))
|
||||
W.use(5)
|
||||
new /turf/closed/wall/mineral/wood/nonmetal(get_turf(src))
|
||||
qdel(src)
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/barricade/wooden/crude
|
||||
name = "crude plank barricade"
|
||||
desc = "This space is blocked off by a crude assortment of planks."
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
icon = 'icons/obj/telescience.dmi'
|
||||
icon_state = "polycrystal"
|
||||
item_state = "sheet-polycrystal"
|
||||
singular_name = "bluespace polycrystal"
|
||||
desc = "A stable polycrystal, made of fused-together bluespace crystals. You could probably break one off."
|
||||
materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT)
|
||||
attack_verb = list("bluespace polybashed", "bluespace polybattered", "bluespace polybludgeoned", "bluespace polythrashed", "bluespace polysmashed")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -130,7 +130,23 @@
|
||||
sheet_type = /obj/item/stack/sheet/mineral/wood
|
||||
hardness = 70
|
||||
explosion_block = 0
|
||||
canSmoothWith = list(/turf/closed/wall/mineral/wood, /obj/structure/falsewall/wood)
|
||||
canSmoothWith = list(/turf/closed/wall/mineral/wood, /obj/structure/falsewall/wood, /turf/closed/wall/mineral/wood/nonmetal)
|
||||
|
||||
/turf/closed/wall/mineral/wood/attackby(obj/item/W, mob/user)
|
||||
var/duration = (48/W.force) * 2 //In seconds, for now.
|
||||
if(W.sharpness)
|
||||
if(istype(W, /obj/item/hatchet) || istype(W, /obj/item/twohanded/fireaxe))
|
||||
duration /= 4 //Much better with hatchets and axes.
|
||||
if(do_after(user, duration*10, target=src)) //Into deciseconds.
|
||||
dismantle_wall(FALSE,FALSE)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/turf/closed/wall/mineral/wood/nonmetal
|
||||
desc = "A solidly wooden wall. It's a bit weaker than a wall made with metal."
|
||||
girder_type = /obj/structure/barricade/wooden
|
||||
hardness = 50
|
||||
canSmoothWith = list(/turf/closed/wall/mineral/wood, /obj/structure/falsewall/wood, /turf/closed/wall/mineral/wood/nonmetal)
|
||||
|
||||
/turf/closed/wall/mineral/iron
|
||||
name = "rough metal wall"
|
||||
@@ -250,7 +266,7 @@
|
||||
/turf/closed/wall/mineral/plastitanium/overspace
|
||||
icon_state = "map-overspace"
|
||||
fixed_underlay = list("space"=1)
|
||||
|
||||
|
||||
/turf/closed/wall/mineral/plastitanium/explosive/ex_act(severity)
|
||||
var/datum/explosion/acted_explosion = null
|
||||
for(var/datum/explosion/E in GLOB.explosions)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "water"
|
||||
desc = "Shallow water."
|
||||
icon = 'icons/turf/floors.dmi'
|
||||
icon_state = "riverwater"
|
||||
icon_state = "riverwater_motion"
|
||||
baseturfs = /turf/open/chasm/lavaland
|
||||
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
|
||||
planetary_atmos = TRUE
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -692,7 +692,6 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
icon_state = "alien_frame"
|
||||
framestack = /obj/item/stack/sheet/mineral/abductor
|
||||
framestackamount = 1
|
||||
density = TRUE
|
||||
|
||||
/obj/structure/table_frame/abductor/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/wrench))
|
||||
|
||||
@@ -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
|
||||
..()
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
to_chat(src, "<span class='revenminor'>Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!</span>")
|
||||
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
|
||||
"<span class='revenwarning'>Violets lights, dancing in your vision, receding--</span>")
|
||||
draining = FALSE
|
||||
return
|
||||
var/datum/beam/B = Beam(target,icon_state="drain_life",time=INFINITY)
|
||||
if(do_after(src, 46, 0, target)) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -106,6 +106,10 @@
|
||||
name = "Fireball"
|
||||
spell_type = /obj/effect/proc_holder/spell/aimed/fireball
|
||||
|
||||
/datum/spellbook_entry/spell_cards
|
||||
name = "Spell Cards"
|
||||
spell_type = /obj/effect/proc_holder/spell/aimed/spell_cards
|
||||
|
||||
/datum/spellbook_entry/rod_form
|
||||
name = "Rod Form"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/rod_form
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
var/inprefs = FALSE
|
||||
var/list/topiclimiter
|
||||
var/list/clicklimiter
|
||||
|
||||
var/datum/chatOutput/chatOutput
|
||||
|
||||
|
||||
@@ -650,6 +650,49 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
message_admins("<span class='adminnotice'>Proxy Detection: [key_name_admin(src)] IP intel rated [res.intel*100]% likely to be a Proxy/VPN.</span>")
|
||||
ip_intel = res.intel
|
||||
|
||||
/client/Click(atom/object, atom/location, control, params)
|
||||
var/ab = FALSE
|
||||
var/list/L = params2list(params)
|
||||
if (object && object == middragatom && L["left"])
|
||||
ab = max(0, 5 SECONDS-(world.time-middragtime)*0.1)
|
||||
var/mcl = CONFIG_GET(number/minute_click_limit)
|
||||
if (!holder && mcl)
|
||||
var/minute = round(world.time, 600)
|
||||
if (!clicklimiter)
|
||||
clicklimiter = new(LIMITER_SIZE)
|
||||
if (minute != clicklimiter[CURRENT_MINUTE])
|
||||
clicklimiter[CURRENT_MINUTE] = minute
|
||||
clicklimiter[MINUTE_COUNT] = 0
|
||||
clicklimiter[MINUTE_COUNT] += 1+(ab)
|
||||
if (clicklimiter[MINUTE_COUNT] > mcl)
|
||||
var/msg = "Your previous click was ignored because you've done too many in a minute."
|
||||
if (minute != clicklimiter[ADMINSWARNED_AT]) //only one admin message per-minute. (if they spam the admins can just boot/ban them)
|
||||
clicklimiter[ADMINSWARNED_AT] = minute
|
||||
|
||||
msg += " Administrators have been informed."
|
||||
if (ab)
|
||||
log_game("[key_name(src)] is using the middle click aimbot exploit")
|
||||
message_admins("[key_name_admin(src)] [ADMIN_FLW(usr)] [ADMIN_KICK(usr)] is using the middle click aimbot exploit</span>")
|
||||
add_system_note("aimbot", "Is using the middle click aimbot exploit")
|
||||
|
||||
log_game("[key_name(src)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
|
||||
message_admins("[key_name_admin(src)] [ADMIN_FLW(usr)] [ADMIN_KICK(usr)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
|
||||
to_chat(src, "<span class='danger'>[msg]</span>")
|
||||
return
|
||||
|
||||
var/scl = CONFIG_GET(number/second_click_limit)
|
||||
if (!holder && scl)
|
||||
var/second = round(world.time, 10)
|
||||
if (!clicklimiter)
|
||||
clicklimiter = new(LIMITER_SIZE)
|
||||
if (second != clicklimiter[CURRENT_SECOND])
|
||||
clicklimiter[CURRENT_SECOND] = second
|
||||
clicklimiter[SECOND_COUNT] = 0
|
||||
clicklimiter[SECOND_COUNT] += 1+(!!ab)
|
||||
if (clicklimiter[SECOND_COUNT] > scl)
|
||||
to_chat(src, "<span class='danger'>Your previous click was ignored because you've done too many in a second</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/client/proc/add_verbs_from_config()
|
||||
if(CONFIG_GET(flag/see_own_notes))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -345,15 +345,15 @@
|
||||
activate_pin(3)
|
||||
|
||||
/obj/item/integrated_circuit/input/turfpoint
|
||||
name = "Tile pointer"
|
||||
desc = "This circuit will get tile ref with given relative coorinates."
|
||||
extended_desc = "If the machine cannot see the target, it will not be able to calculate the correct direction.\
|
||||
This circuit is working only in assembly."
|
||||
name = "tile pointer"
|
||||
desc = "This circuit will get tile ref with given absolute coorinates."
|
||||
extended_desc = "If the machine cannot see the target, it will not be able to scan it.\
|
||||
This circuit will only work in an assembly."
|
||||
icon_state = "numberpad"
|
||||
complexity = 5
|
||||
inputs = list("X" = IC_PINTYPE_NUMBER,"Y" = IC_PINTYPE_NUMBER)
|
||||
outputs = list("tile" = IC_PINTYPE_REF)
|
||||
activators = list("calculate dir" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT,"not calculated" = IC_PINTYPE_PULSE_OUT)
|
||||
activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT,"not scanned" = IC_PINTYPE_PULSE_OUT)
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 40
|
||||
|
||||
@@ -362,11 +362,11 @@
|
||||
activate_pin(3)
|
||||
return
|
||||
var/turf/T = get_turf(assembly)
|
||||
var/target_x = CLAMP(get_pin_data(IC_INPUT, 1) - assembly.x, 0, world.maxx)
|
||||
var/target_y = CLAMP(get_pin_data(IC_INPUT, 2) - assembly.y, 0, world.maxy)
|
||||
var/target_x = CLAMP(get_pin_data(IC_INPUT, 1), 0, world.maxx)
|
||||
var/target_y = CLAMP(get_pin_data(IC_INPUT, 2), 0, world.maxy)
|
||||
var/turf/A = locate(target_x, target_y, T.z)
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
if(!A||!(A in view(T)))
|
||||
if(!A || !(A in view(T)))
|
||||
activate_pin(3)
|
||||
return
|
||||
else
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ Roboticist
|
||||
faction = "Station"
|
||||
total_positions = 2
|
||||
spawn_positions = 2
|
||||
supervisors = "research director"
|
||||
supervisors = "the research director"
|
||||
selection_color = "#ffeeff"
|
||||
exp_requirements = 60
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -63,7 +63,7 @@ Doesn't work on other aliens/AI.*/
|
||||
var/obj/machinery/atmospherics/components/unary/atmos_thing = locate() in user.loc
|
||||
if(atmos_thing)
|
||||
var/rusure = alert(user, "Laying eggs and shaping resin here would block access to [atmos_thing]. Do you want to continue?", "Blocking Atmospheric Component", "Yes", "No")
|
||||
if(rusure != "No")
|
||||
if(rusure != "Yes")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -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 = "ai-techdemon"
|
||||
/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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user