diff --git a/_maps/cit_map_files/BoxStation/BoxStation.dmm b/_maps/cit_map_files/BoxStation/BoxStation.dmm index 553fb5919e..91d975de6f 100644 --- a/_maps/cit_map_files/BoxStation/BoxStation.dmm +++ b/_maps/cit_map_files/BoxStation/BoxStation.dmm @@ -52947,6 +52947,8 @@ /obj/item/gun/energy/e_gun/dragnet, /obj/item/gun/energy/e_gun/dragnet, /obj/effect/turf_decal/bot_white, +/obj/item/gun/energy/pumpaction/blaster, +/obj/item/gun/energy/pumpaction/blaster, /turf/open/floor/plasteel/dark, /area/security/armory) "ipA" = ( diff --git a/_maps/cit_map_files/Deltastation/DeltaStation2.dmm b/_maps/cit_map_files/Deltastation/DeltaStation2.dmm index d313f2e239..e26b6cf7f1 100644 --- a/_maps/cit_map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/cit_map_files/Deltastation/DeltaStation2.dmm @@ -47348,6 +47348,7 @@ /obj/item/gun/energy/ionrifle, /obj/item/clothing/suit/armor/laserproof, /obj/item/gun/energy/temperature/security, +/obj/item/gun/energy/pumpaction/blaster, /turf/open/floor/plasteel/vault{ dir = 8 }, diff --git a/_maps/cit_map_files/MetaStation/MetaStation.dmm b/_maps/cit_map_files/MetaStation/MetaStation.dmm index c048c43c85..0f34e7d510 100644 --- a/_maps/cit_map_files/MetaStation/MetaStation.dmm +++ b/_maps/cit_map_files/MetaStation/MetaStation.dmm @@ -3218,6 +3218,8 @@ /obj/item/storage/fancy/donut_box, /obj/item/gun/energy/e_gun/dragnet, /obj/item/gun/energy/e_gun/dragnet, +/obj/item/gun/energy/pumpaction/blaster, +/obj/item/gun/energy/pumpaction/blaster, /turf/open/floor/plasteel/vault{ dir = 1 }, diff --git a/_maps/cit_map_files/OmegaStation/OmegaStation.dmm b/_maps/cit_map_files/OmegaStation/OmegaStation.dmm index 81623cd949..02faf2da92 100644 --- a/_maps/cit_map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/cit_map_files/OmegaStation/OmegaStation.dmm @@ -6902,6 +6902,8 @@ }, /obj/item/gun/energy/e_gun/dragnet, /obj/item/gun/energy/e_gun/dragnet, +/obj/item/gun/energy/pumpaction/blaster, +/obj/item/gun/energy/pumpaction/blaster, /turf/open/floor/plasteel/red/corner{ dir = 8 }, diff --git a/_maps/cit_map_files/PubbyStation/PubbyStation.dmm b/_maps/cit_map_files/PubbyStation/PubbyStation.dmm index ee60df06de..9ec2f36dba 100644 --- a/_maps/cit_map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/cit_map_files/PubbyStation/PubbyStation.dmm @@ -2937,6 +2937,7 @@ dir = 4; pixel_x = -23 }, +/obj/item/gun/energy/pumpaction/blaster, /turf/open/floor/plasteel/dark, /area/security/armory) "ajh" = ( diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 8608c08c9e..6517697be9 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -36064,10 +36064,10 @@ /area/science/mixing) "bJT" = ( /obj/machinery/computer/security/telescreen{ - desc = "Used for watching the test chamber."; + desc = "Used for watching the bomb testing site."; dir = 2; layer = 4; - name = "Test Chamber Telescreen"; + name = "Testing Site Telescreen"; network = list("toxins"); pixel_y = -32 }, @@ -45555,7 +45555,7 @@ invuln = 1; luminosity = 3; name = "Hardened Bomb-Test Camera"; - network = list("toxins"); + network = list("ss13", "rd", "toxins"); use_power = 0 }, /turf/open/floor/plating/asteroid/airless, @@ -46582,7 +46582,7 @@ invuln = 1; luminosity = 3; name = "Hardened Bomb-Test Camera"; - network = list("toxins"); + network = list("ss13", "rd", "toxins"); use_power = 0 }, /turf/open/floor/plating/asteroid/airless, diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 82acf13dcf..51b907f846 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -40,4 +40,11 @@ #define CHAPLAIN (1<<10) #define CLOWN (1<<11) #define MIME (1<<12) -#define ASSISTANT (1<<13) \ No newline at end of file +#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 diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index 6ca1107619..b4a44f6d4b 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -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 diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 91eee45b4d..b46cef29fd 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -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) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 26b5ac65cc..baa9d42df5 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -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 diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 0e5fff082c..be886298a7 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -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) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 36cf604d3a..064f8b675f 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -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 = "has [what_done] [starget] with [sobject][addition] [hp] [sattackloc]" + var/message = "has [what_done] [starget][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]" user.log_message(message, INDIVIDUAL_ATTACK_LOG) if(is_mob_target) - var/message = "has been [what_done] by [ssource] with [sobject][addition] [hp] [sattackloc]" + var/message = "has been [what_done] by [ssource][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]" 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) diff --git a/code/__HELPERS/mouse_control.dm b/code/__HELPERS/mouse_control.dm new file mode 100644 index 0000000000..24e40cc355 --- /dev/null +++ b/code/__HELPERS/mouse_control.dm @@ -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) diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index b0e76bbcf3..c186f5f40f 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -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() diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 6c28a1262d..a840d6144a 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -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" + \ No newline at end of file diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index a63ff6bdf0..f433708191 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -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 diff --git a/code/__HELPERS/unused.dm b/code/__HELPERS/unused.dm new file mode 100644 index 0000000000..8b590eb2bd --- /dev/null +++ b/code/__HELPERS/unused.dm @@ -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) diff --git a/code/_onclick/autoclick.dm b/code/_onclick/autoclick.dm deleted file mode 100644 index 7a5ba0a189..0000000000 --- a/code/_onclick/autoclick.dm +++ /dev/null @@ -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 diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 3d62cdd0ac..03bff92596 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -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 + ..() \ No newline at end of file diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 0608baea8c..258a695a25 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -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 diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 70552e0ccb..2b1e9bcda9 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -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) diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm index b88e3c711c..066c621572 100644 --- a/code/controllers/subsystem/mobs.dm +++ b/code/controllers/subsystem/mobs.dm @@ -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]") diff --git a/code/controllers/subsystem/pathfinder.dm b/code/controllers/subsystem/pathfinder.dm index fe503b0b7a..871eba49ad 100644 --- a/code/controllers/subsystem/pathfinder.dm +++ b/code/controllers/subsystem/pathfinder.dm @@ -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 diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index a080f1a159..bfb7099ed2 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -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 diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm index a548af4e88..75c2f27631 100644 --- a/code/datums/brain_damage/phobia.dm +++ b/code/datums/brain_damage/phobia.dm @@ -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, "You can't bring yourself to say the word \"[word]\"!") return "" return message @@ -114,4 +116,4 @@ owner.dizziness += 10 owner.confused += 10 owner.Jitter(10) - owner.stuttering += 10 \ No newline at end of file + owner.stuttering += 10 diff --git a/code/datums/callback.dm b/code/datums/callback.dm index c603be85b7..1a26052cc9 100644 --- a/code/datums/callback.dm +++ b/code/datums/callback.dm @@ -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 diff --git a/code/datums/components/lockon_aiming.dm b/code/datums/components/lockon_aiming.dm new file mode 100644 index 0000000000..017e7ea8eb --- /dev/null +++ b/code/datums/components/lockon_aiming.dm @@ -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!") diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm index 375370f08f..f8d51a044f 100644 --- a/code/datums/components/mood.dm +++ b/code/datums/components/mood.dm @@ -68,7 +68,7 @@ var/datum/mood_event/event = mood_events[i] msg += event.description else - msg += "Nothing special has happend to me lately!\n" + msg += "Nothing special has happened to me lately!\n" to_chat(owner, msg) /datum/component/mood/proc/update_mood() //Called whenever a mood event is added or removed diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index c22af19396..c88a86c092 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -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) diff --git a/code/datums/diseases/advance/symptoms/beard.dm b/code/datums/diseases/advance/symptoms/beard.dm index c7a3ccec89..6b26183828 100644 --- a/code/datums/diseases/advance/symptoms/beard.dm +++ b/code/datums/diseases/advance/symptoms/beard.dm @@ -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, "You feel manly!") 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() \ No newline at end of file + H.update_hair() diff --git a/code/datums/diseases/advance/symptoms/shedding.dm b/code/datums/diseases/advance/symptoms/shedding.dm index c5bbb6bc7b..8946a83108 100644 --- a/code/datums/diseases/advance/symptoms/shedding.dm +++ b/code/datums/diseases/advance/symptoms/shedding.dm @@ -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() \ No newline at end of file + H.update_hair() diff --git a/code/datums/diseases/advance/symptoms/skin.dm b/code/datums/diseases/advance/symptoms/skin.dm index 014607eb44..300eecc80e 100644 --- a/code/datums/diseases/advance/symptoms/skin.dm +++ b/code/datums/diseases/advance/symptoms/skin.dm @@ -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 diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 95161f4f39..3ee3e9b048 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -105,6 +105,14 @@ mood_change = -3 timeout = 3000 +/datum/mood_event/nyctophobia + description = "It sure is dark around here...\n" + mood_change = -3 + +/datum/mood_event/family_heirloom_missing + description = "I'm missing my family heirloom...\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 = "I recently saw my own corpse...\n" diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index e96567cf9d..54eb74f10f 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -56,3 +56,7 @@ description = "I have seen the truth, praise the almighty one!\n" mood_change = 40 //maybe being a cultist isnt that bad after all hidden = TRUE + +/datum/mood_event/family_heirloom + description = "My family heirloom is safe with me.\n" + mood_change = 1 diff --git a/code/datums/position_point_vector.dm b/code/datums/position_point_vector.dm index 63b4774550..33facca9a1 100644 --- a/code/datums/position_point_vector.dm +++ b/code/datums/position_point_vector.dm @@ -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 diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm index 1bad7b3352..26c689e092 100644 --- a/code/datums/traits/good.dm +++ b/code/datums/traits/good.dm @@ -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 = "You feel HONGRY." lose_text = "You no longer feel HONGRY." - - -/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. diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index 59957ef2bc..2865877fce 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -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 = "You start feeling depressed." + lose_text = "You no longer feel depressed." //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 = "There is a precious family [heirloom.name] [where], passed down from generation to generation. Keep it safe!" + +/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, "Easy, easy, take it slow... you're in the dark...") + 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, "You retreat into yourself. You really don't feel up to talking.") H.silent = max(10, H.silent) else if(prob(0.5) && dumb_thing) - to_chat(H, "You think of a dumb thing you said a long time ago and scream internally.") + to_chat(H, "You think of a dumb thing you said a long time ago and scream internally.") 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 = "You start feeling depressed." - lose_text = "You no longer feel depressed." //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 diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm index 140b751fd8..5b0fbefe10 100644 --- a/code/datums/traits/neutral.dm +++ b/code/datums/traits/neutral.dm @@ -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, "Mmm. Nothing's ever clear on this station. It's all shades of gray...") + 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) diff --git a/code/datums/weakrefs.dm b/code/datums/weakrefs.dm index f9602c0217..3c64d5f60d 100644 --- a/code/datums/weakrefs.dm +++ b/code/datums/weakrefs.dm @@ -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 diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index bd6a8bf77d..603829a2d0 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -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)) diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 15ddee2669..b678f8cd0e 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -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 diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 52702868f7..cefc471d08 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -58,8 +58,13 @@ "You climb out of [src]!") 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) diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm index a158957ecb..60e71eeac8 100644 --- a/code/game/machinery/computer/aifixer.dm +++ b/code/game/machinery/computer/aifixer.dm @@ -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(..()) diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 1a3ff23c56..2e78d72b96 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -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, "You need at least five wooden planks to make a wall!") + return + else + to_chat(user, "You start adding [I] to [src]...") + 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." diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index ad616e8ad3..9edd19795c 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -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"]) diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index a07d8d8d60..c7865ac576 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -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, "You can't use [src] while inside something.") /obj/item/device/chameleon/afterattack(atom/target, mob/user , proximity) if(!proximity) diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm index a127201e41..f2daf58b1a 100644 --- a/code/game/objects/items/grenades/chem_grenade.dm +++ b/code/game/objects/items/grenades/chem_grenade.dm @@ -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, "You scan the grenade and detect the following reagents:") + 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, "[R.volume] units of [R.name] in the [textcount] beaker.") + if(beakers.len == 1) + to_chat(user, "You detect no second beaker in the grenade.") + else + to_chat(user, "You scan the grenade, but detect nothing.") /obj/item/grenade/chem_grenade/attack_self(mob/user) diff --git a/code/game/objects/items/hot_potato.dm b/code/game/objects/items/hot_potato.dm index 65bfd09f9c..9777deaf6d 100644 --- a/code/game/objects/items/hot_potato.dm +++ b/code/game/objects/items/hot_potato.dm @@ -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("[src] [detonate_explosion? "explodes" : "activates"]!", "[src] activates! You've ran out of time!") @@ -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("[user] squeezes [src], which promptly starts to flash red-hot colors!", "You squeeze [src], activating its countdown and attachment mechanism!", @@ -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, "[src] is flashing red-hot! You should probably get rid of it!") if(show_timer) to_chat(user, "[src]'s timer looks to be at [DisplayTimeText(activation_time - world.time)]!") /obj/item/hot_potato/equipped(mob/user) . = ..() - if(is_active()) + if(active) to_chat(user, "You have a really bad feeling about [src]!") /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("[user] forces [src] onto [victim]!", "You force [src] onto [victim]!", "You hear a mechanical click and a beep.") - 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("[user] tried to force [src] onto [victim], but it could not attach!", "You try to force [src] onto [victim], but it is unable to attach!", "You hear a mechanical click and two buzzes.") @@ -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 diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm index b49f325690..d1ff075ef2 100644 --- a/code/game/objects/items/implants/implant.dm +++ b/code/game/objects/items/implants/implant.dm @@ -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 diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm index 3f3880c281..dba70cb988 100644 --- a/code/game/objects/items/stacks/bscrystal.dm +++ b/code/game/objects/items/stacks/bscrystal.dm @@ -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") diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index 454eabf058..74c559117f 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -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" diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index f923453f62..23171bb821 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -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 diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index b8a05de431..143ae840f5 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -199,8 +199,6 @@ return 0 if(!(lube&SLIDE_ICE)) to_chat(C, "You slipped[ O ? " on the [O.name]" : ""]!") - C.log_message("Slipped[O ? " on the [O.name]" : ""][(lube&SLIDE)? " (LUBE)" : ""]!", 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) diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm index dc474d449d..8b32782d8a 100644 --- a/code/game/turfs/simulated/wall/mineral_walls.dm +++ b/code/game/turfs/simulated/wall/mineral_walls.dm @@ -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) diff --git a/code/game/turfs/simulated/water.dm b/code/game/turfs/simulated/water.dm index 765da26136..eb6fe8a194 100644 --- a/code/game/turfs/simulated/water.dm +++ b/code/game/turfs/simulated/water.dm @@ -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 diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 5cdc58dae3..d1f58dfe7f 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -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.") diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index be54715215..c850340c78 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -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, "Admin Reload blocked: Advanced ProcCall detected.") 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) diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm index b6d8c11e67..eb3969ce3a 100644 --- a/code/modules/admin/permissionedit.dm +++ b/code/modules/admin/permissionedit.dm @@ -82,6 +82,10 @@ if(D.rank in GLOB.protected_ranks) to_chat(usr, "Editing the flags of this rank is blocked by server configuration.") return + if(CONFIG_GET(flag/load_legacy_ranks_only) && (task == "rank" || task == "permissions")) + to_chat(usr, "Database rank loading is disabled, only temporary changes can be made to an admin's rank or permissions.") + use_db = FALSE + skip = TRUE if(check_rights(R_DBRANKS, FALSE)) if(!skip) if(!SSdbcore.Connect()) diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 670b22815d..8ddcc1b593 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -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 = "Player Panel" //javascript, the part that does most of the work~ @@ -307,4 +308,4 @@ "} - usr << browse(dat, "window=players;size=600x480") \ No newline at end of file + usr << browse(dat, "window=players;size=600x480") diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm index 2b6b893b59..d53234db23 100644 --- a/code/modules/admin/verbs/buildmode.dm +++ b/code/modules/admin/verbs/buildmode.dm @@ -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() diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 5c87293b73..3e1a12bdec 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -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) diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm index e9101742d2..1afa4146a3 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm @@ -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)) diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm index 95a46705f0..fedcfa0e97 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm @@ -40,7 +40,7 @@ else if(L.stat) to_chat(ranged_ability_user, "\"There is use in shackling the dead, but for examples.\"") return TRUE - else if(L.handcuffed) + else if (istype(L.handcuffed,/obj/item/restraints/handcuffs/clockwork)) to_chat(ranged_ability_user, "\"They are already helpless, no?\"") return TRUE @@ -49,7 +49,7 @@ "You begin shaping replicant alloy into manacles around [L]'s wrists...") to_chat(L, "[ranged_ability_user] begins forming manacles around your wrists!") 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, "You shackle [L].") diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm index 28ce2ccf60..ad4062598e 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm @@ -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. diff --git a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm index 86d9497934..f6df9efbbe 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm @@ -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)) diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index 30ab2da128..252d0e3d23 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -589,6 +589,7 @@ SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) else to_chat(user, "The spell will not work on [target]!") + return ..() //Armor: Gives the target a basic cultist combat loadout diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index ae8bec2537..80947fec16 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -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) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 1b744863d8..30d150e3ee 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -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 ..() diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm index f81371b504..e3a068eed4 100644 --- a/code/modules/antagonists/revenant/revenant_abilities.dm +++ b/code/modules/antagonists/revenant/revenant_abilities.dm @@ -58,6 +58,7 @@ to_chat(src, "Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!") target.visible_message("[target] slumps onto the ground.", \ "Violets lights, dancing in your vision, receding--") + 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. diff --git a/code/modules/antagonists/revenant/revenant_spawn_event.dm b/code/modules/antagonists/revenant/revenant_spawn_event.dm index b321ec1ae1..483be4dc34 100644 --- a/code/modules/antagonists/revenant/revenant_spawn_event.dm +++ b/code/modules/antagonists/revenant/revenant_spawn_event.dm @@ -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 diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm index b31cfebb6e..518d2a04b7 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook.dm @@ -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 diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index 9f5b21962a..0c9735ce4d 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -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) diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm index 007aad331a..60dba541f3 100644 --- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm +++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm @@ -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) diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm index 5281c3bad7..35dcb81ce2 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm @@ -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 ..() diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm index f4d8d54805..0b848968d1 100644 --- a/code/modules/atmospherics/machinery/datum_pipeline.dm +++ b/code/modules/atmospherics/machinery/datum_pipeline.dm @@ -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) diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index 73aaa16820..477cbbc76d 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -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]) diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm index d6b736ab31..4f5d7006d3 100644 --- a/code/modules/cargo/expressconsole.dm +++ b/code/modules/cargo/expressconsole.dm @@ -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) diff --git a/code/modules/client/client_colour.dm b/code/modules/client/client_colour.dm index 7e78032f46..f1477fb4d2 100644 --- a/code/modules/client/client_colour.dm +++ b/code/modules/client/client_colour.dm @@ -105,4 +105,9 @@ colour = "#ff99ff" /datum/client_colour/glass_colour/gray - colour = "#cccccc" \ No newline at end of file + 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! diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 193d23e7bf..30e61dba1c 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -62,6 +62,7 @@ var/inprefs = FALSE var/list/topiclimiter + var/list/clicklimiter var/datum/chatOutput/chatOutput diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index ff2333cdb4..b036e826c9 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -650,6 +650,49 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) message_admins("Proxy Detection: [key_name_admin(src)] IP intel rated [res.intel*100]% likely to be a Proxy/VPN.") 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") + 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, "[msg]") + 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, "Your previous click was ignored because you've done too many in a second") + return + ..() /client/proc/add_verbs_from_config() if(CONFIG_GET(flag/see_own_notes)) diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index 2da25dd5df..e9c4c29a5e 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -19,9 +19,9 @@ if(prefs.muted & MUTE_OOC) to_chat(src, "You cannot use OOC (muted).") return - if(jobban_isbanned(src.mob, "OOC")) - to_chat(src, "You have been banned from OOC.") - return + if(jobban_isbanned(src.mob, "OOC")) + to_chat(src, "You have been banned from OOC.") + 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) diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 2ecf385a1f..eaeedee36c 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -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 diff --git a/code/modules/clothing/spacesuits/flightsuit.dm b/code/modules/clothing/spacesuits/flightsuit.dm index 3008264d24..60a958735a 100644 --- a/code/modules/clothing/spacesuits/flightsuit.dm +++ b/code/modules/clothing/spacesuits/flightsuit.dm @@ -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("[wearer]'s flight suit abruptly shuts off and they lose control!") if(wearer) + wearer.visible_message("[wearer]'s flight suit abruptly shuts off and they lose control!") if(move) while(momentum_x != 0 || momentum_y != 0) sleep(2) diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm index 1a11ac9817..0df1d349ce 100644 --- a/code/modules/crafting/craft.dm +++ b/code/modules/crafting/craft.dm @@ -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) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index d6426cf20d..7a0a8f5f5a 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -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) diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm index 0a70774847..07be1eef78 100644 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -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) diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm index 6ad3fc9797..dd58aae211 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -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 diff --git a/code/modules/integrated_electronics/subtypes/time.dm b/code/modules/integrated_electronics/subtypes/time.dm index 86e5e99059..26bd1fc1d6 100644 --- a/code/modules/integrated_electronics/subtypes/time.dm +++ b/code/modules/integrated_electronics/subtypes/time.dm @@ -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 diff --git a/code/modules/jobs/job_types/science.dm b/code/modules/jobs/job_types/science.dm index 0d5da1eec1..2648bd2516 100644 --- a/code/modules/jobs/job_types/science.dm +++ b/code/modules/jobs/job_types/science.dm @@ -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 diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 2471593814..8930a02036 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -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 += "
" 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 += "
" diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 41715d650d..68c6ed5c83 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -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() diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm index 249428cc9e..ef4bce7f11 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm @@ -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 diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index dc0b094128..e0c8f04030 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -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 = "tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]" - var/end_T_descriptor = "tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]" - 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("[src] has thrown [thrown_thing].") - 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) diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index 7ee828adb7..6fbd4b6f0a 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -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) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index b744630a56..eddfa997b8 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -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 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2a0ac731cf..55019dbefc 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -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) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 31df48e5e5..f148ac7fdb 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -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")) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 2a3af029dd..6fce5a15f3 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -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. diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 1cf031b0cc..b7015972fd 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -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)) diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm index c57bf5f4e3..5759a24dc2 100644 --- a/code/modules/modular_computers/computers/item/computer_ui.dm +++ b/code/modules/modular_computers/computers/item/computer_ui.dm @@ -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) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 3c7d00b3fd..ad83fb31a2 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -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() diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm index 80cbf11318..4edff70e6c 100644 --- a/code/modules/projectiles/guns/misc/beam_rifle.dm +++ b/code/modules/projectiles/guns/misc/beam_rifle.dm @@ -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) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index ad1d0f76d0..806805e3a0 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -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) diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 82fb4fc59d..803167484c 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -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) diff --git a/code/modules/projectiles/projectile/magic/spellcard.dm b/code/modules/projectiles/projectile/magic/spellcard.dm new file mode 100644 index 0000000000..67e3ad374e --- /dev/null +++ b/code/modules/projectiles/projectile/magic/spellcard.dm @@ -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 diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index 32096125dd..f6f5f97607 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -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, "[src]'s maintenance hatch is open!") + /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 diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 96b454cc71..ed19a87dcf 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -73,12 +73,6 @@ if (prob(50)) qdel(src) -/obj/machinery/chem_master/power_change() - if(powered()) - stat &= ~NOPOWER - else - stat |= NOPOWER - /obj/machinery/chem_master/attackby(obj/item/I, mob/user, params) if(default_deconstruction_screwdriver(user, "mixer0_nopower", "mixer0", I)) return @@ -223,7 +217,7 @@ return vol_each = min(reagents.total_volume / amount, 50) var/name = stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN) - if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE)) + if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr))) return var/obj/item/reagent_containers/pill/P @@ -237,7 +231,7 @@ reagents.trans_to(P,vol_each) else var/name = stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN) - if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE)) + if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr))) return var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(drop_location()) @@ -259,7 +253,7 @@ return vol_each = min(reagents.total_volume / amount, 40) var/name = stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN) - if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE)) + if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr))) return var/obj/item/reagent_containers/pill/P @@ -277,7 +271,7 @@ if(condi) var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN) - if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE)) + if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr))) return var/obj/item/reagent_containers/food/condiment/P = new(drop_location()) P.originalname = name @@ -290,7 +284,7 @@ amount_full = round(reagents.total_volume / 30) vol_part = reagents.total_volume % 30 var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN) - if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE)) + if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr))) return var/obj/item/reagent_containers/glass/bottle/P diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 47bbc899a9..45838de5e7 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -615,7 +615,19 @@ to_chat(M, "Your eyes sting!") M.blind_eyes(2) +/datum/reagent/consumable/nutriment/stabilized + name = "Stabilized Nutriment" + id = "stabilizednutriment" + description = "A bioengineered protien-nutrient structure designed to decompose in high saturation. In layman's terms, it won't get you fat." + reagent_state = SOLID + nutriment_factor = 15 * REAGENTS_METABOLISM + color = "#664330" // rgb: 102, 67, 48 +/datum/reagent/consumable/nutriment/stabilized/on_mob_life(mob/living/M) + if(M.nutrition > NUTRITION_LEVEL_FULL - 25) + M.nutrition -= 3*nutriment_factor + ..() + ////Lavaland Flora Reagents//// @@ -673,4 +685,4 @@ description = "The sorrow and melancholy of a thousand bereaved clowns, forever denied their Honkmechs." nutriment_factor = 5 * REAGENTS_METABOLISM color = "#eef442" // rgb: 238, 244, 66 - taste_description = "mournful honking" \ No newline at end of file + taste_description = "mournful honking" diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index d00b5e3137..459c1a9955 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -17,13 +17,17 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi display_contents_with_number = 1 max_w_class = WEIGHT_CLASS_NORMAL max_combined_w_class = 100 + + can_hold = list( + /obj/item/reagent_containers/glass/beaker, + /obj/item/device/assembly/igniter, + /obj/item/stock_parts, + /obj/item/stack/ore/bluespace_crystal) + var/works_from_distance = 0 var/pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/rped.ogg' var/alt_sound = null -/obj/item/storage/part_replacer/can_be_inserted(obj/item/W, stop_messages = 0, mob/user) - return ..() && W.get_part_rating() - /obj/item/storage/part_replacer/afterattack(obj/machinery/T, mob/living/carbon/human/user, flag, params) if(flag) return diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index 384f22282b..5bcc58ff87 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -82,15 +82,13 @@ var/mob/living/carbon/human/H = mover if(H.nutrition >= NUTRITION_LEVEL_FAT) H.visible_message("[H] pushes through [src]!", "You've seen and eaten worse than this.") - return 1 + return TRUE else to_chat(H, "You're repulsed by even looking at [src]. Only a pig could force themselves to go through it.") if(istype(mover, /mob/living/simple_animal/hostile/morph)) - return 1 + return TRUE else - return 0 - - + return FALSE /obj/structure/mirror/magic/pride //Pride's mirror: Used in the Pride ruin. name = "pride's mirror" diff --git a/code/modules/spells/spell_types/aimed.dm b/code/modules/spells/spell_types/aimed.dm index 6980cba8e2..6c860fda9b 100644 --- a/code/modules/spells/spell_types/aimed.dm +++ b/code/modules/spells/spell_types/aimed.dm @@ -9,6 +9,7 @@ var/list/projectile_var_overrides = list() var/projectile_amount = 1 //Projectiles per cast. var/current_amount = 0 //How many projectiles left. + var/projectiles_per_fire = 1 //Projectiles per fire. Probably not a good thing to use unless you override ready_projectile(). /obj/effect/proc_holder/spell/aimed/Click() var/mob/living/user = usr @@ -26,10 +27,18 @@ charge_counter = charge_max * refund_percent start_recharge() remove_ranged_ability(msg) + on_deactivation(user) else msg = "[active_msg]Left-click to shoot it at a target!" current_amount = projectile_amount add_ranged_ability(user, msg, TRUE) + on_activation(user) + +/obj/effect/proc_holder/spell/aimed/proc/on_activation(mob/user) + return + +/obj/effect/proc_holder/spell/aimed/proc/on_deactivation(mob/user) + return /obj/effect/proc_holder/spell/aimed/update_icon() if(!action) @@ -60,19 +69,25 @@ remove_ranged_ability() //Auto-disable the ability once you run out of bullets. charge_counter = 0 start_recharge() + on_deactivation(user) return TRUE /obj/effect/proc_holder/spell/aimed/proc/fire_projectile(mob/living/user, atom/target) current_amount-- - var/obj/item/projectile/P = new projectile_type(user.loc) - P.firer = user - P.preparePixelProjectile(target, user) - for(var/V in projectile_var_overrides) - if(P.vars[V]) - P.vv_edit_var(V, projectile_var_overrides[V]) - P.fire() + for(var/i in 1 to projectiles_per_fire) + var/obj/item/projectile/P = new projectile_type(user.loc) + P.firer = user + P.preparePixelProjectile(target, user) + for(var/V in projectile_var_overrides) + if(P.vars[V]) + P.vv_edit_var(V, projectile_var_overrides[V]) + ready_projectile(P, target, user, i) + P.fire() return TRUE +/obj/effect/proc_holder/spell/aimed/proc/ready_projectile(obj/item/projectile/P, atom/target, mob/user, iteration) + return + /obj/effect/proc_holder/spell/aimed/lightningbolt name = "Lightning Bolt" desc = "Fire a high powered lightning bolt at your foes!" @@ -108,3 +123,58 @@ active_msg = "You prepare to cast your fireball spell!" deactive_msg = "You extinguish your fireball... for now." active = FALSE + +/obj/effect/proc_holder/spell/aimed/spell_cards + name = "Spell Cards" + desc = "Blazing hot rapid-fire homing cards. Banish your foes with its mystical power!" + school = "evocation" + charge_max = 50 + clothes_req = 0 + invocation = "Sigi'lu M'Fan 'Tasia" + invocation_type = "shout" + range = 40 + cooldown_min = 10 + projectile_amount = 5 + projectiles_per_fire = 7 + projectile_type = /obj/item/projectile/spellcard + var/datum/weakref/current_target_weakref + var/projectile_turnrate = 10 + var/projectile_pixel_homing_spread = 32 + var/projectile_initial_spread_amount = 30 + var/projectile_location_spread_amount = 12 + var/datum/component/lockon_aiming/lockon_component + ranged_clickcd_override = 1 + +/obj/effect/proc_holder/spell/aimed/spell_cards/on_activation(mob/M) + QDEL_NULL(lockon_component) + lockon_component = M.AddComponent(/datum/component/lockon_aiming, 5, typecacheof(list(/mob/living)), 1, null, CALLBACK(src, .proc/on_lockon_component)) + +/obj/effect/proc_holder/spell/aimed/spell_cards/proc/on_lockon_component(list/locked_weakrefs) + if(!length(locked_weakrefs)) + current_target_weakref = null + return + current_target_weakref = locked_weakrefs[1] + var/atom/A = current_target_weakref.resolve() + if(A) + var/mob/M = lockon_component.parent + M.face_atom(A) + +/obj/effect/proc_holder/spell/aimed/spell_cards/on_deactivation(mob/M) + QDEL_NULL(lockon_component) + +/obj/effect/proc_holder/spell/aimed/spell_cards/ready_projectile(obj/item/projectile/P, atom/target, mob/user, iteration) + if(current_target_weakref) + var/atom/A = current_target_weakref.resolve() + if(A && get_dist(A, user) < 7) + P.homing_turn_speed = projectile_turnrate + P.homing_inaccuracy_min = projectile_pixel_homing_spread + P.homing_inaccuracy_max = projectile_pixel_homing_spread + P.set_homing_target(current_target_weakref.resolve()) + var/rand_spr = rand() + var/total_angle = projectile_initial_spread_amount * 2 + var/adjusted_angle = total_angle - ((projectile_initial_spread_amount / projectiles_per_fire) * 0.5) + var/one_fire_angle = adjusted_angle / projectiles_per_fire + var/current_angle = iteration * one_fire_angle * rand_spr - (projectile_initial_spread_amount / 2) + P.pixel_x = rand(-projectile_location_spread_amount, projectile_location_spread_amount) + P.pixel_y = rand(-projectile_location_spread_amount, projectile_location_spread_amount) + P.preparePixelProjectile(target, user, null, current_angle) diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index 9878130144..1f432ae0ee 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -43,6 +43,15 @@ var/species_flags_list = list() var/dmg_overlay_type //the type of damage overlay (if any) to use when this bodypart is bruised/burned. + //Damage messages used by help_shake_act() + var/light_brute_msg = "bruised" + var/medium_brute_msg = "battered" + var/heavy_brute_msg = "mangled" + + var/light_burn_msg = "numb" + var/medium_burn_msg = "blistered" + var/heavy_burn_msg = "peeling away" + /obj/item/bodypart/examine(mob/user) ..() if(brute_dam > 0) diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index 6921d7e3a2..b255c32f11 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -1,4 +1,10 @@ +#define ROBOTIC_LIGHT_BRUTE_MSG "marred" +#define ROBOTIC_MEDIUM_BRUTE_MSG "dented" +#define ROBOTIC_HEAVY_BRUTE_MSG "falling apart" +#define ROBOTIC_LIGHT_BURN_MSG "scorched" +#define ROBOTIC_MEDIUM_BURN_MSG "charred" +#define ROBOTIC_HEAVY_BURN_MSG "smoldering" /obj/item/bodypart/l_arm/robot name = "cyborg left arm" @@ -10,6 +16,13 @@ icon_state = "borg_l_arm" status = BODYPART_ROBOTIC + light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG + medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG + heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG + + light_burn_msg = ROBOTIC_LIGHT_BURN_MSG + medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG + heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG /obj/item/bodypart/r_arm/robot name = "cyborg right arm" @@ -21,6 +34,13 @@ icon_state = "borg_r_arm" status = BODYPART_ROBOTIC + light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG + medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG + heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG + + light_burn_msg = ROBOTIC_LIGHT_BURN_MSG + medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG + heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG /obj/item/bodypart/l_leg/robot name = "cyborg left leg" @@ -32,6 +52,13 @@ icon_state = "borg_l_leg" status = BODYPART_ROBOTIC + light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG + medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG + heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG + + light_burn_msg = ROBOTIC_LIGHT_BURN_MSG + medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG + heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG /obj/item/bodypart/r_leg/robot name = "cyborg right leg" @@ -43,6 +70,13 @@ icon_state = "borg_r_leg" status = BODYPART_ROBOTIC + light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG + medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG + heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG + + light_burn_msg = ROBOTIC_LIGHT_BURN_MSG + medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG + heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG /obj/item/bodypart/chest/robot name = "cyborg torso" @@ -52,6 +86,15 @@ flags_1 = CONDUCT_1 icon_state = "borg_chest" status = BODYPART_ROBOTIC + + light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG + medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG + heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG + + light_burn_msg = ROBOTIC_LIGHT_BURN_MSG + medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG + heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG + var/wired = 0 var/obj/item/stock_parts/cell/cell = null @@ -102,6 +145,15 @@ flags_1 = CONDUCT_1 icon_state = "borg_head" status = BODYPART_ROBOTIC + + light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG + medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG + heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG + + light_burn_msg = ROBOTIC_LIGHT_BURN_MSG + medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG + heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG + var/obj/item/device/assembly/flash/handheld/flash1 = null var/obj/item/device/assembly/flash/handheld/flash2 = null @@ -189,3 +241,12 @@ icon = 'icons/mob/augmentation/surplus_augments.dmi' icon_state = "r_leg" max_damage = 20 + + +#undef ROBOTIC_LIGHT_BRUTE_MSG +#undef ROBOTIC_MEDIUM_BRUTE_MSG +#undef ROBOTIC_HEAVY_BRUTE_MSG + +#undef ROBOTIC_LIGHT_BURN_MSG +#undef ROBOTIC_MEDIUM_BURN_MSG +#undef ROBOTIC_HEAVY_BURN_MSG diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm index 2470146532..d74d7b6691 100644 --- a/code/modules/surgery/helpers.dm +++ b/code/modules/surgery/helpers.dm @@ -68,7 +68,7 @@ user.visible_message("[user] drapes [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].", \ "You drape [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].") - add_logs(user, M, "operated", addition="Operation type: [procedure.name], location: [selected_zone]") + add_logs(user, M, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])") else to_chat(user, "You need to expose [M]'s [parse_zone(selected_zone)] first!") diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index 456ff681fe..da2a6c1f37 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -46,7 +46,6 @@ see_in_dark = 8 lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE actions_types = list(/datum/action/item_action/organ_action/use) - sight_flags = SEE_BLACKNESS var/night_vision = TRUE /obj/item/organ/eyes/night_vision/ui_action_click() diff --git a/config/config.txt b/config/config.txt index a8c9cf13de..ac3cf9b3ab 100644 --- a/config/config.txt +++ b/config/config.txt @@ -35,6 +35,7 @@ ROUND_END_COUNTDOWN 90 ## This flag is automatically enabled if SQL_ENABLED isn't ADMIN_LEGACY_SYSTEM +<<<<<<< HEAD ## Comment this out if you want to use the SQL based mentor system, the legacy system uses mentors.txt. ## You need to set up your database to use the SQL based system. ## This flag is automatically enabled if SQL_ENABLED isn't @@ -42,6 +43,17 @@ MENTOR_LEGACY_SYSTEM #Mentors only see ckeys by default. Uncomment to have them only see mob name #MENTORS_MOBNAME_ONLY +======= +##Uncomment this to stop any admins loaded by the legacy system from having their rank edited by the permissions panel +#PROTECT_LEGACY_ADMINS + +##Uncomment this to stop any ranks loaded by the legacy system from having their flags edited by the permissions panel +#PROTECT_LEGACY_RANKS +>>>>>>> feb9290... Merge pull request #36554 from Jordie0608/tbhthisisntreallyalegacysystemanymore + +##Uncomment this to have admin ranks only loaded from the legacy admin_ranks.txt +##If enabled, each time admins are loaded ranks the database will be updated with the current ranks and their flags +#LOAD_LEGACY_RANKS_ONLY ## Comment this out if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system. BAN_LEGACY_SYSTEM @@ -374,6 +386,17 @@ SECOND_TOPIC_LIMIT 10 MINUTE_TOPIC_LIMIT 100 + +## CLICK RATE LIMITING +## Same as above, but applies to clicking on objects in the game window. +## This should be a higher then the interface limit to allow for the spam clickly nature of most battles. +## Admins are exempt from these limits. +## Hitting the minute limit notifies admins. +## Set to 0 to disable. +SECOND_CLICK_LIMIT 15 + +MINUTE_CLICK_LIMIT 400 + ##Error handling related options ## The "cooldown" time for each occurence of a unique error #ERROR_COOLDOWN 600 diff --git a/icons/mob/AI.dmi b/icons/mob/AI.dmi index f4cb3e983b..e12792217b 100644 Binary files a/icons/mob/AI.dmi and b/icons/mob/AI.dmi differ diff --git a/icons/mob/custom_w.dmi b/icons/mob/custom_w.dmi index 1b70b86779..6b17cc3acb 100644 Binary files a/icons/mob/custom_w.dmi and b/icons/mob/custom_w.dmi differ diff --git a/icons/obj/custom.dmi b/icons/obj/custom.dmi index 2a63ddd1e1..de5fce96a5 100644 Binary files a/icons/obj/custom.dmi and b/icons/obj/custom.dmi differ diff --git a/icons/obj/flora/ausflora.dmi b/icons/obj/flora/ausflora.dmi index 720e4bd742..c2440e27e1 100644 Binary files a/icons/obj/flora/ausflora.dmi and b/icons/obj/flora/ausflora.dmi differ diff --git a/icons/obj/hydroponics/equipment.dmi b/icons/obj/hydroponics/equipment.dmi index 3d125d68c7..177a0dbf56 100644 Binary files a/icons/obj/hydroponics/equipment.dmi and b/icons/obj/hydroponics/equipment.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index 03cf226b84..b0b01a2446 100644 Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 34e6a8134b..2d0d35f8a5 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index bc281c9fcb..9ebae192fc 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/interface/interface.dm b/interface/interface.dm index 27a47beeec..8a4ba5b96b 100644 --- a/interface/interface.dm +++ b/interface/interface.dm @@ -84,8 +84,9 @@ Admin: \tF3 = asay \tF5 = Aghost (admin-ghost) \tF6 = player-panel -\tF7 = admin-pm +\tF7 = Buildmode \tF8 = Invisimin +\tCtrl+F8 = Stealthmin "} mob.hotkey_help() @@ -219,4 +220,4 @@ Any-Mode: (hotkey doesn't need to be on) "} to_chat(src, hotkey_mode) - to_chat(src, other) \ No newline at end of file + to_chat(src, other) diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm index 0db74b8ed2..d8744a660b 100644 --- a/modular_citadel/code/modules/client/loadout/__donator.dm +++ b/modular_citadel/code/modules/client/loadout/__donator.dm @@ -259,3 +259,9 @@ datum/gear/darksabresheath path = /obj/item/reagent_containers/food/drinks/flask/steel cost = 2 ckeywhitelist = list("johnnyvitrano") + +/datum/gear/paperhat + name = "Paper Hat" + category = slot_head + path = /obj/item/clothing/head/paperhat + ckeywhitelist = list("kered2") diff --git a/modular_citadel/code/modules/custom_loadout/custom_items.dm b/modular_citadel/code/modules/custom_loadout/custom_items.dm index 9fde1349b4..c3421976fb 100644 --- a/modular_citadel/code/modules/custom_loadout/custom_items.dm +++ b/modular_citadel/code/modules/custom_loadout/custom_items.dm @@ -333,3 +333,9 @@ item_state = "wintergreencloak" w_class = WEIGHT_CLASS_SMALL body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/head/paperhat + name = "paperhat" + desc = "A piece of paper folded into neat little hat." + icon_state = "paperhat" + item_state = "paperhat" diff --git a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm b/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm index 5e733cfb6a..4271862c7a 100644 --- a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm +++ b/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm @@ -850,6 +850,10 @@ name = "Naga" icon_state = "naga" +/datum/sprite_accessory/taur/octopus + name = "Octopus" + icon_state = "octopus" + /datum/sprite_accessory/taur/otie name = "Otie" icon_state = "otie" diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/robot.dm b/modular_citadel/code/modules/mob/living/silicon/robot/robot.dm index 34970bc283..da77421a2f 100644 --- a/modular_citadel/code/modules/mob/living/silicon/robot/robot.dm +++ b/modular_citadel/code/modules/mob/living/silicon/robot/robot.dm @@ -1,10 +1,19 @@ +mob/living/silicon + no_vore = TRUE + /mob/living/silicon/robot var/dogborg = FALSE /mob/living/silicon/robot/lay_down() - if(resting) - cut_overlays() - icon_state = "[module.cyborg_base_icon]-rest" - else - icon_state = "[module.cyborg_base_icon]" + ..() + update_canmove() + +/mob/living/silicon/robot/update_canmove() + ..() + if(client && stat != DEAD && dogborg == TRUE) + if(resting) + cut_overlays() + icon_state = "[module.cyborg_base_icon]-rest" + else + icon_state = "[module.cyborg_base_icon]" update_icons() \ No newline at end of file diff --git a/modular_citadel/icons/mob/mam_taur.dmi b/modular_citadel/icons/mob/mam_taur.dmi index 8cd02f862e..dee50d4566 100644 Binary files a/modular_citadel/icons/mob/mam_taur.dmi and b/modular_citadel/icons/mob/mam_taur.dmi differ diff --git a/strings/phobia.json b/strings/phobia.json index d21e89aeb9..10fdbd9a0c 100644 --- a/strings/phobia.json +++ b/strings/phobia.json @@ -15,7 +15,7 @@ ], "security": [ - " sec ", + "sec", "security", "shitcurity", "baton", @@ -32,22 +32,22 @@ "chain of command", "heads of staff", "head of security", - " hos ", + "hos", "head of personnel", - " hop ", + "hop", "head of research", - " rd ", + "rd", "chief medical officer", - " cmo ", + "cmo", "chief engineer", - " ce ", + "ce", "captain", "deathsquad", "death squad", "alien", "xeno", "abductor", - " ayy", + "ayy", "gray", "grey", "ufo", @@ -66,7 +66,9 @@ "clown", "honk", "banana", - "slip" + "slip", + "slipped", + "slipping" ], "greytide": [ @@ -84,7 +86,11 @@ "lizard", "ligger", "hiss", - "wag" + "hissed", + "hissing", + "wag", + "wagged", + "wagging" ], "skeletons": [ diff --git a/tgstation.dme b/tgstation.dme index ba2d8eaea1..988dbfeffd 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -109,6 +109,7 @@ #include "code\__HELPERS\level_traits.dm" #include "code\__HELPERS\matrices.dm" #include "code\__HELPERS\mobs.dm" +#include "code\__HELPERS\mouse_control.dm" #include "code\__HELPERS\names.dm" #include "code\__HELPERS\priority_announce.dm" #include "code\__HELPERS\pronouns.dm" @@ -148,7 +149,6 @@ #include "code\_js\menus.dm" #include "code\_onclick\adjacent.dm" #include "code\_onclick\ai.dm" -#include "code\_onclick\autoclick.dm" #include "code\_onclick\click.dm" #include "code\_onclick\cyborg.dm" #include "code\_onclick\drag_drop.dm" @@ -325,6 +325,7 @@ #include "code\datums\components\infective.dm" #include "code\datums\components\jousting.dm" #include "code\datums\components\knockoff.dm" +#include "code\datums\components\lockon_aiming.dm" #include "code\datums\components\material_container.dm" #include "code\datums\components\mood.dm" #include "code\datums\components\ntnet_interface.dm" @@ -2291,6 +2292,7 @@ #include "code\modules\projectiles\projectile\energy\net_snare.dm" #include "code\modules\projectiles\projectile\energy\stun.dm" #include "code\modules\projectiles\projectile\energy\tesla.dm" +#include "code\modules\projectiles\projectile\magic\spellcard.dm" #include "code\modules\projectiles\projectile\reusable\_reusable.dm" #include "code\modules\projectiles\projectile\reusable\foam_dart.dm" #include "code\modules\projectiles\projectile\reusable\magspear.dm" @@ -2690,7 +2692,6 @@ #include "modular_citadel\code\modules\admin\topic.dm" #include "modular_citadel\code\modules\antagonists\cit_crewobjectives.dm" #include "modular_citadel\code\modules\antagonists\cit_miscreants.dm" -#include "modular_citadel\code\modules\antagonists\cult\blood_magic.dm" #include "modular_citadel\code\modules\antagonists\crew_objectives\cit_crewobjectives_cargo.dm" #include "modular_citadel\code\modules\antagonists\crew_objectives\cit_crewobjectives_civilian.dm" #include "modular_citadel\code\modules\antagonists\crew_objectives\cit_crewobjectives_command.dm" @@ -2698,6 +2699,7 @@ #include "modular_citadel\code\modules\antagonists\crew_objectives\cit_crewobjectives_medical.dm" #include "modular_citadel\code\modules\antagonists\crew_objectives\cit_crewobjectives_science.dm" #include "modular_citadel\code\modules\antagonists\crew_objectives\cit_crewobjectives_security.dm" +#include "modular_citadel\code\modules\antagonists\cult\blood_magic.dm" #include "modular_citadel\code\modules\arousal\arousal.dm" #include "modular_citadel\code\modules\arousal\organs\breasts.dm" #include "modular_citadel\code\modules\arousal\organs\eggsack.dm"