diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm index d5c344e9cd31a..3553672b1080c 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm @@ -993,9 +993,6 @@ /area/ruin/comms_agent) "UI" = ( /obj/structure/table/reinforced, -/obj/machinery/computer/records/security/laptop/syndie{ - dir = 1 - }, /obj/item/paper/monitorkey{ pixel_x = -15; pixel_y = 7 diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index de9e1338f2939..125324bb07ea4 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -9394,10 +9394,9 @@ /obj/machinery/airalarm/directional/north, /obj/structure/table/wood, /obj/machinery/chem_dispenser/drinks, -/obj/effect/turf_decal/siding/wood{ - dir = 5 +/obj/effect/turf_decal/siding/wood/end{ + dir = 4 }, -/obj/effect/turf_decal/siding/wood, /turf/open/floor/iron/dark/diagonal, /area/station/service/bar) "dxZ" = ( @@ -10072,6 +10071,7 @@ }, /obj/structure/disposalpipe/segment, /obj/structure/cable, +/obj/structure/extinguisher_cabinet/directional/west, /turf/open/floor/stone, /area/station/service/bar) "dMm" = ( @@ -33247,11 +33247,10 @@ pixel_x = -7; pixel_y = 15 }, -/obj/effect/turf_decal/siding/wood{ - dir = 9 - }, -/obj/effect/turf_decal/siding/wood, /obj/structure/sign/warning/no_smoking/circle/directional/north, +/obj/effect/turf_decal/siding/wood/end{ + dir = 8 + }, /turf/open/floor/iron/dark/diagonal, /area/station/service/bar) "lnI" = ( @@ -50833,12 +50832,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, /area/station/service/lawoffice) -"rrX" = ( -/obj/effect/turf_decal/siding/wood/corner{ - dir = 4 - }, -/turf/open/floor/stone, -/area/station/service/bar) "rrZ" = ( /obj/structure/closet/crate/trashcart, /obj/effect/spawner/random/trash/garbage, @@ -56445,11 +56438,14 @@ /turf/open/floor/eighties/red, /area/station/hallway/primary/central/fore) "tjT" = ( -/obj/structure/extinguisher_cabinet/directional/north, +/obj/machinery/chem_master/condimaster, +/obj/effect/turf_decal/siding/wood/end{ + dir = 8 + }, /obj/effect/turf_decal/siding/wood{ - dir = 5 + dir = 4 }, -/turf/open/floor/stone, +/turf/open/floor/iron/dark/diagonal, /area/station/service/bar) "tjY" = ( /obj/machinery/atmospherics/components/binary/pump/on{ @@ -100086,7 +100082,7 @@ iXW dRb sON tjT -rrX +xkV lAV fYJ eGU diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index aa3df4dfd8a93..6ee4db7790ea9 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -46005,6 +46005,13 @@ dir = 4 }, /area/station/hallway/secondary/entry) +"nqI" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/neutral/half/contrasted, +/obj/effect/landmark/start/hangover, +/turf/open/floor/iron, +/area/station/commons/fitness) "nqP" = ( /obj/machinery/camera/directional/north{ c_tag = "Research Division West"; @@ -53846,8 +53853,8 @@ /obj/effect/turf_decal/tile/neutral{ dir = 1 }, -/obj/item/kirbyplants/random, /obj/structure/sign/flag/terragov/directional/north, +/obj/structure/weightmachine/weightlifter, /turf/open/floor/iron, /area/station/commons/fitness) "pyn" = ( @@ -81087,6 +81094,10 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/security/detectives_office) +"xyg" = ( +/obj/structure/weightmachine, +/turf/open/floor/iron, +/area/station/commons/fitness) "xyl" = ( /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 1 @@ -249315,7 +249326,7 @@ cGB cGB gsI tLL -spy +nqI kKL kKL kKL @@ -250338,8 +250349,8 @@ dyA skl gaC vfW -eOl vfW +xyg vfW lvk crv diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 6b4adfe0d4896..e6aabf579de2a 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -67095,10 +67095,6 @@ }, /turf/open/floor/iron, /area/station/ai_monitored/command/storage/eva) -"xBX" = ( -/obj/machinery/firealarm/directional/east, -/turf/closed/wall, -/area/station/security/checkpoint/customs) "xCf" = ( /obj/item/clothing/suit/jacket/straight_jacket, /obj/item/electropack, @@ -83046,7 +83042,7 @@ wdr fcq xfI fcq -xBX +xjh qhW xjh yme diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 74c9120d804d4..ea5c52bf36f0f 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -45,40 +45,40 @@ #define R_EVERYTHING (1<<15)-1 //the sum of all other rank permissions, used for +EVERYTHING -#define ADMIN_QUE(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminmoreinfo=[REF(user)]'>?</a>)" -#define ADMIN_FLW(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminplayerobservefollow=[REF(user)]'>FLW</a>)" -#define ADMIN_PP(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminplayeropts=[REF(user)]'>PP</a>)" -#define ADMIN_VV(atom) "(<a href='?_src_=vars;[HrefToken(forceGlobal = TRUE)];Vars=[REF(atom)]'>VV</a>)" -#define ADMIN_SM(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];subtlemessage=[REF(user)]'>SM</a>)" -#define ADMIN_TP(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];traitor=[REF(user)]'>TP</a>)" -#define ADMIN_SP(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];skill=[REF(user)]'>SP</a>)" -#define ADMIN_KICK(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];boot2=[REF(user)]'>KICK</a>)" -#define ADMIN_CENTCOM_REPLY(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];CentComReply=[REF(user)]'>RPLY</a>)" -#define ADMIN_SYNDICATE_REPLY(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];SyndicateReply=[REF(user)]'>RPLY</a>)" -#define ADMIN_SC(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminspawncookie=[REF(user)]'>SC</a>)" -#define ADMIN_SMITE(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminsmite=[REF(user)]'>SMITE</a>)" +#define ADMIN_QUE(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminmoreinfo=[REF(user)]'>?</a>)" +#define ADMIN_FLW(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminplayerobservefollow=[REF(user)]'>FLW</a>)" +#define ADMIN_PP(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminplayeropts=[REF(user)]'>PP</a>)" +#define ADMIN_VV(atom) "(<a href='byond://?_src_=vars;[HrefToken(forceGlobal = TRUE)];Vars=[REF(atom)]'>VV</a>)" +#define ADMIN_SM(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];subtlemessage=[REF(user)]'>SM</a>)" +#define ADMIN_TP(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];traitor=[REF(user)]'>TP</a>)" +#define ADMIN_SP(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];skill=[REF(user)]'>SP</a>)" +#define ADMIN_KICK(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];boot2=[REF(user)]'>KICK</a>)" +#define ADMIN_CENTCOM_REPLY(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];CentComReply=[REF(user)]'>RPLY</a>)" +#define ADMIN_SYNDICATE_REPLY(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];SyndicateReply=[REF(user)]'>RPLY</a>)" +#define ADMIN_SC(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminspawncookie=[REF(user)]'>SC</a>)" +#define ADMIN_SMITE(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminsmite=[REF(user)]'>SMITE</a>)" #define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]" #define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]" -#define ADMIN_SET_SD_CODE "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];set_selfdestruct_code=1'>SETCODE</a>)" +#define ADMIN_SET_SD_CODE "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];set_selfdestruct_code=1'>SETCODE</a>)" #define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]" #define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]" -#define ADMIN_JMP(src) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>)" +#define ADMIN_JMP(src) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>)" #define COORD(src) "[src ? src.Admin_Coordinates_Readable() : "nonexistent location"]" #define AREACOORD(src) "[src ? src.Admin_Coordinates_Readable(TRUE) : "nonexistent location"]" #define ADMIN_COORDJMP(src) "[src ? src.Admin_Coordinates_Readable(FALSE, TRUE) : "nonexistent location"]" #define ADMIN_VERBOSEJMP(src) "[src ? src.Admin_Coordinates_Readable(TRUE, TRUE) : "nonexistent location"]" -#define ADMIN_INDIVIDUALLOG(user) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];individuallog=[REF(user)]'>LOGS</a>)" -#define ADMIN_TAG(datum) "(<A href='?src=[REF(src)];[HrefToken(forceGlobal = TRUE)];tag_datum=[REF(datum)]'>TAG</a>)" -#define ADMIN_LUAVIEW(state) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];lua_state=[REF(state)]'>VIEW STATE</a>)" -#define ADMIN_LUAVIEW_CHUNK(state, log_index) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];lua_state=[REF(state)];log_index=[log_index]'>VIEW CODE</a>)" +#define ADMIN_INDIVIDUALLOG(user) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];individuallog=[REF(user)]'>LOGS</a>)" +#define ADMIN_TAG(datum) "(<A href='byond://?src=[REF(src)];[HrefToken(forceGlobal = TRUE)];tag_datum=[REF(datum)]'>TAG</a>)" +#define ADMIN_LUAVIEW(state) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];lua_state=[REF(state)]'>VIEW STATE</a>)" +#define ADMIN_LUAVIEW_CHUNK(state, log_index) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];lua_state=[REF(state)];log_index=[log_index]'>VIEW CODE</a>)" /// Displays "(SHOW)" in the chat, when clicked it tries to show atom(paper). First you need to set the request_state variable to TRUE for the paper. -#define ADMIN_SHOW_PAPER(atom) "(<A href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];show_paper=[REF(atom)]'>SHOW</a>)" +#define ADMIN_SHOW_PAPER(atom) "(<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];show_paper=[REF(atom)]'>SHOW</a>)" /// Displays "(PRINT)" in the chat, when clicked it will try to print the atom(paper) on the CentCom/Syndicate fax machine. -#define ADMIN_PRINT_FAX(atom, sender, destination) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];print_fax=[REF(atom)];sender_name=[sender];destination=[destination]'>PRINT</a>)" +#define ADMIN_PRINT_FAX(atom, sender, destination) "(<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];print_fax=[REF(atom)];sender_name=[sender];destination=[destination]'>PRINT</a>)" /// Displays "(PLAY)" in the chat, when clicked it tries to play internet sounds from the request. -#define ADMIN_PLAY_INTERNET(text, credit) "(<A href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];play_internet=[url_encode(text)];credit=[credit]'>PLAY</a>)" +#define ADMIN_PLAY_INTERNET(text, credit) "(<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];play_internet=[url_encode(text)];credit=[credit]'>PLAY</a>)" /// Displays "(SEE Z-LEVEL LAYOUT)" in the chat, when clicked it shows the z-level layouts for the current world state. -#define ADMIN_SEE_ZLEVEL_LAYOUT "(<A href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];debug_z_levels=1'>SEE Z-LEVEL LAYOUT</a>)" +#define ADMIN_SEE_ZLEVEL_LAYOUT "(<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];debug_z_levels=1'>SEE Z-LEVEL LAYOUT</a>)" /atom/proc/Admin_Coordinates_Readable(area_name, admin_jump_ref) var/turf/turf_at_coords = Safe_COORD_Location() diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index b5a7ad1ddfaac..f7f77a7169ea2 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -195,6 +195,14 @@ #define BB_DRILLABLE_ICE "BB_drillable_ice" +//emotions we displays depending on our happiness +///emotions we display when happy +#define BB_HAPPY_EMOTIONS "happy_emotions" +///emotions we display when neutral +#define BB_MODERATE_EMOTIONS "moderate_emotions" +///emotions we display when depressed +#define BB_SAD_EMOTIONS "sad_emotions" + // Keys used by one and only one behavior // Used to hold state without making bigass lists /// For /datum/ai_behavior/find_potential_targets, what if any field are we using currently diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm index 330e2d48eb226..d77817a203980 100644 --- a/code/__DEFINES/ai/monsters.dm +++ b/code/__DEFINES/ai/monsters.dm @@ -304,3 +304,11 @@ #define BB_DEER_RESTING "deer_resting" ///time till our next rest duration #define BB_DEER_NEXT_REST_TIMER "deer_next_rest_timer" + +//turtle +///our tree's ability +#define BB_TURTLE_TREE_ABILITY "turtle_tree_ability" +///people we headbutt! +#define BB_TURTLE_HEADBUTT_VICTIM "turtle_headbutt_victim" +///flore we must smell +#define BB_TURTLE_FLORA_TARGET "turtle_flora_target" diff --git a/code/__DEFINES/chat.dm b/code/__DEFINES/chat.dm index 516fe8c4e193a..80fb1a07eccf3 100644 --- a/code/__DEFINES/chat.dm +++ b/code/__DEFINES/chat.dm @@ -44,9 +44,11 @@ /// Used for debug messages to the server #define debug_world_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]") /// Adds a generic box around whatever message you're sending in chat. Really makes things stand out. -#define examine_block(str) ("<div class='examine_block'>" + str + "</div>") -/// Makes a fieldset with a name in the middle top part. Can apply additional classes -#define fieldset_block(title, content, classes) ("<fieldset class='" + classes + "'><legend align='center' style='max-width: 95%; text-align: center;'><div style='margin: 0em 0.2em -0.4em 0.2em;' >" + title + "</div></legend>" + content + "</fieldset>") +#define boxed_message(str) ("<div class='boxed_message'>" + str + "</div>") +/// Adds a box around whatever message you're sending in chat. Can apply color and/or additional classes. Available colors: red, green, blue, purple. Use it like red_box +#define custom_boxed_message(classes, str) ("<div class='boxed_message " + classes + "'>" + str + "</div>") +/// Makes a fieldset with a neaty styled name. Can apply additional classes. +#define fieldset_block(title, content, classes) ("<fieldset class='fieldset " + classes + "'><legend class='fieldset_legend'>" + title + "</legend>" + content + "</fieldset>") /// Makes a horizontal line with text in the middle #define separator_hr(str) ("<div class='separator'>" + str + "</div>") /// Emboldens runechat messages diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 5cb838603c98e..867d8a51d4163 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -98,6 +98,7 @@ DEFINE_BITFIELD(status_flags, list( #define CLICK_CD_RAPID 2 #define CLICK_CD_HYPER_RAPID 1 #define CLICK_CD_SLOW 10 +#define CLICK_CD_ACTIVATE_ABILITY 1 #define CLICK_CD_THROW 8 #define CLICK_CD_RANGE 4 diff --git a/code/__DEFINES/construction/rcd.dm b/code/__DEFINES/construction/rcd.dm index a8d98215af1dc..4f898d5ae86ec 100644 --- a/code/__DEFINES/construction/rcd.dm +++ b/code/__DEFINES/construction/rcd.dm @@ -51,3 +51,6 @@ #define RCD_MEMORY_COST_BUFF 8 /// If set to TRUE in rcd_vals, will bypass the cooldown on slowing down frequent use #define RCD_RESULT_BYPASS_FREQUENT_USE_COOLDOWN "bypass_frequent_use_cooldown" + +/// How much longer does it take to deconstruct rwalls? +#define RCD_RWALL_DELAY_MULT 2 diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm index bedfaf2fa0374..bb5b344a89a48 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm @@ -92,3 +92,6 @@ /// from /obj/projectile/energy/fisher/on_hit() or /obj/item/gun/energy/recharge/fisher when striking a target #define COMSIG_ATOM_SABOTEUR_ACT "hit_by_saboteur" #define COMSIG_SABOTEUR_SUCCESS 1 + +/// signal sent when a mouse is hovering over us, sent by atom/proc/on_mouse_entered +#define COMSIG_ATOM_MOUSE_ENTERED "mouse_entered" diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 63ebfdf98b21f..a83badb9ee067 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -547,6 +547,9 @@ ///Sent from /obj/item/skillchip/on_remove() #define COMSIG_SKILLCHIP_REMOVED "skillchip_removed" +/// from /obj/machinery/computer/camera_advanced/shuttle_docker/gatherNavComputerOverlays() : (list/images_out) +#define COMSIG_SHUTTLE_NAV_COMPUTER_IMAGE_REQUESTED "shuttle_nav_computer_image_requested" + /// Sent from /obj/item/organ/wings/functional/proc/open_wings(): (mob/living/carbon/owner) #define COMSIG_WINGS_OPENED "wings_opened" /// Sent from /obj/item/organ/wings/functional/proc/close_wings(): (mob/living/carbon/owner) diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 5f025ad99cffb..8ae95933e646b 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -4,6 +4,9 @@ #define COMSIG_KB_ACTIVATED (1<<0) #define COMSIG_KB_EMOTE "keybinding_emote_down" +///Signal sent when a keybind is deactivated +#define DEACTIVATE_KEYBIND(A) "[A]_DEACTIVATED" + //Admin #define COMSIG_KB_ADMIN_ASAY_DOWN "keybinding_admin_asay_down" #define COMSIG_KB_ADMIN_DSAY_DOWN "keybinding_admin_dsay_down" @@ -54,6 +57,7 @@ #define COMSIG_KB_LIVING_DISABLE_COMBAT_DOWN "keybinding_living_disable_combat_down" #define COMSIG_KB_LIVING_TOGGLEMOVEINTENT_DOWN "keybinding_mob_togglemoveintent_down" #define COMSIG_KB_LIVING_TOGGLEMOVEINTENTALT_DOWN "keybinding_mob_togglemoveintentalt_down" +#define COMSIG_KB_LIVING_VIEW_PET_COMMANDS "keybinding_living_view_pet_commands" //Mob #define COMSIG_KB_MOB_FACENORTH_DOWN "keybinding_mob_facenorth_down" diff --git a/code/__DEFINES/radial_defines.dm b/code/__DEFINES/radial_defines.dm new file mode 100644 index 0000000000000..35ae6eebb5984 --- /dev/null +++ b/code/__DEFINES/radial_defines.dm @@ -0,0 +1,6 @@ +#define NEXT_PAGE_ID "__next__" +#define DEFAULT_CHECK_DELAY 2 SECONDS + +#define BUTTON_SLIDE_IN (1<<0) +#define BUTTON_FADE_IN (1<<1) +#define BUTTON_FADE_OUT (1<<2) diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index 28172587e795a..bf3fd32918943 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -46,7 +46,8 @@ ///Health threshold for synthflesh and rezadone to unhusk someone #define UNHUSK_DAMAGE_THRESHOLD 50 ///Amount of synthflesh required to unhusk someone -#define SYNTHFLESH_UNHUSK_AMOUNT 100 +#define SYNTHFLESH_UNHUSK_AMOUNT 60 +#define SYNTHFLESH_UNHUSK_MAX 100 //used by chem masters and pill presses // The categories of reagent packaging diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index d905129b19b74..c3bd425af0a65 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -99,9 +99,9 @@ #define MODE_RANGE_INTERCOM 1 // A link given to ghost alice to follow bob -#define FOLLOW_LINK(alice, bob) "<a href=?src=[REF(alice)];follow=[REF(bob)]>(F)</a>" -#define TURF_LINK(alice, turfy) "<a href=?src=[REF(alice)];x=[turfy.x];y=[turfy.y];z=[turfy.z]>(T)</a>" -#define FOLLOW_OR_TURF_LINK(alice, bob, turfy) "<a href=?src=[REF(alice)];follow=[REF(bob)];x=[turfy.x];y=[turfy.y];z=[turfy.z]>(F)</a>" +#define FOLLOW_LINK(alice, bob) "<a href=byond://?src=[REF(alice)];follow=[REF(bob)]>(F)</a>" +#define TURF_LINK(alice, turfy) "<a href=byond://?src=[REF(alice)];x=[turfy.x];y=[turfy.y];z=[turfy.z]>(T)</a>" +#define FOLLOW_OR_TURF_LINK(alice, bob, turfy) "<a href=byond://?src=[REF(alice)];follow=[REF(bob)];x=[turfy.x];y=[turfy.y];z=[turfy.z]>(F)</a>" //Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam #define MAX_MESSAGE_LEN 1024 diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 88f46a53fd92c..1ce2d5d46cb9c 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -50,7 +50,7 @@ #define GET_VV_VAR_TARGET href_list[VV_HK_VARNAME] //Helper for getting something to vv_do_topic in general -#define VV_TOPIC_LINK(datum, href_key, text) "<a href='?_src_=vars;[HrefToken()];[href_key]=TRUE;target=[REF(datum)]'>text</a>" +#define VV_TOPIC_LINK(datum, href_key, text) "<a href='byond://?_src_=vars;[HrefToken()];[href_key]=TRUE;target=[REF(datum)]'>text</a>" //Helpers for vv_get_dropdown() #define VV_DROPDOWN_OPTION(href_key, name) . += "<option value='?_src_=vars;[HrefToken()];[href_key]=TRUE;target=[REF(src)]'>[name]</option>" diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index ad654c02a5dc7..24344880a3e09 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -349,4 +349,4 @@ message = html_encode(message) else message = copytext(message, 2) - to_chat(target, span_purple(examine_block("<span class='oocplain'><b>[source]: </b>[message]</span>"))) + to_chat(target, custom_boxed_message("purple_box", span_purple("<span class='oocplain'><b>[source]: </b>[message]</span>"))) diff --git a/code/__HELPERS/logging/_logging.dm b/code/__HELPERS/logging/_logging.dm index bfcaded67f021..8f8f733e6ba8b 100644 --- a/code/__HELPERS/logging/_logging.dm +++ b/code/__HELPERS/logging/_logging.dm @@ -215,11 +215,11 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) if(key) if(C?.holder && C.holder.fakekey && !include_name) if(include_link) - . += "<a href='?priv_msg=[C.getStealthKey()]'>" + . += "<a href='byond://?priv_msg=[C.getStealthKey()]'>" . += "Administrator" else if(include_link) - . += "<a href='?priv_msg=[ckey]'>" + . += "<a href='byond://?priv_msg=[ckey]'>" . += key if(!C) . += "\[DC\]" diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 08b63176f5775..9d92766ab8bde 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -335,7 +335,7 @@ GLOBAL_LIST_INIT(achievements_unlocked, list()) if(GLOB.round_id) var/statspage = CONFIG_GET(string/roundstatsurl) - var/info = statspage ? "<a href='?action=openLink&link=[url_encode(statspage)][GLOB.round_id]'>[GLOB.round_id]</a>" : GLOB.round_id + var/info = statspage ? "<a href='byond://?action=openLink&link=[url_encode(statspage)][GLOB.round_id]'>[GLOB.round_id]</a>" : GLOB.round_id parts += "[FOURSPACES]Round ID: <b>[info]</b>" parts += "[FOURSPACES]Shift Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B>" parts += "[FOURSPACES]Station Integrity: <B>[GLOB.station_was_nuked ? span_redtext("Destroyed") : "[popcount["station_integrity"]]%"]</B>" @@ -660,7 +660,7 @@ GLOBAL_LIST_INIT(achievements_unlocked, list()) var/datum/action/report/R = new C.player_details.player_actions += R R.Grant(C.mob) - to_chat(C,span_infoplain("<a href='?src=[REF(R)];report=1'>Show roundend report again</a>")) + to_chat(C,span_infoplain("<a href='byond://?src=[REF(R)];report=1'>Show roundend report again</a>")) /datum/action/report name = "Show roundend report" diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index a265ca01717ce..dd35df5f229b1 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -1136,7 +1136,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." return FALSE var/list/modifiers = params2list(params) if(LAZYACCESS(modifiers, SHIFT_CLICK)) // screen objects don't do the normal Click() stuff so we'll cheat - to_chat(usr, examine_block(jointext(examine(usr), "\n"))) + to_chat(usr, boxed_message(jointext(examine(usr), "\n"))) return FALSE var/datum/our_master = master_ref?.resolve() if(our_master && click_master) diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 918f5f62a329b..e17757501cf9e 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -322,8 +322,6 @@ var/obj/item/organ/eyes/eyes = human_mob.get_organ_slot(ORGAN_SLOT_EYES) if(eyes?.no_glasses) blocked_slots |= ITEM_SLOT_EYES - if(human_mob.bodyshape & BODYSHAPE_DIGITIGRADE) - blocked_slots |= ITEM_SLOT_FEET for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) if(!inv.slot_id) diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index c071919442eff..3d2378345cc75 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -1,6 +1,3 @@ -#define NEXT_PAGE_ID "__next__" -#define DEFAULT_CHECK_DELAY 20 - GLOBAL_LIST_EMPTY(radial_menus) /atom/movable/screen/radial @@ -113,7 +110,7 @@ GLOBAL_LIST_EMPTY(radial_menus) var/hudfix_method = TRUE //TRUE to change anchor to user, FALSE to shift by py_shift var/py_shift = 0 - var/entry_animation = TRUE + var/button_animation_flags = BUTTON_SLIDE_IN ///A replacement icon state for the generic radial slice bg icon. Doesn't affect the next page nor the center buttons var/radial_slice_icon @@ -163,6 +160,8 @@ GLOBAL_LIST_EMPTY(radial_menus) var/atom/movable/screen/radial/slice/new_element = new /atom/movable/screen/radial/slice new_element.tooltips = use_tooltips new_element.set_parent(src) + if(button_animation_flags & BUTTON_FADE_IN) + new_element.alpha = 0 elements += new_element var/page = 1 @@ -186,9 +185,9 @@ GLOBAL_LIST_EMPTY(radial_menus) page_data[page] = current pages = page current_page = clamp(set_page, 1, pages) - update_screen_objects(entry_animation, click_on_hover) + update_screen_objects(button_animation_flags, click_on_hover) -/datum/radial_menu/proc/update_screen_objects(anim = FALSE, click_on_hover = FALSE) +/datum/radial_menu/proc/update_screen_objects(anim_flag = NONE, click_on_hover = FALSE) var/list/page_choices = page_data[current_page] var/angle_per_element = round(zone / page_choices.len) for(var/i in 1 to elements.len) @@ -198,11 +197,11 @@ GLOBAL_LIST_EMPTY(radial_menus) HideElement(element) element.click_on_hover = FALSE else - SetElement(element,page_choices[i],angle,anim = anim,anim_order = i) + SetElement(element,page_choices[i],angle,anim_flag = anim_flag,anim_order = i) // Only activate click on hover after the animation plays if (!click_on_hover) continue - if (anim) + if (anim_flag) addtimer(VARSET_CALLBACK(element, click_on_hover, TRUE), i * 0.5) else element.click_on_hover = TRUE @@ -217,11 +216,11 @@ GLOBAL_LIST_EMPTY(radial_menus) E.choice = null E.next_page = FALSE -/datum/radial_menu/proc/SetElement(atom/movable/screen/radial/slice/E,choice_id,angle,anim,anim_order) +/datum/radial_menu/proc/SetElement(atom/movable/screen/radial/slice/E, choice_id, angle, anim_flag, anim_order) //Position var/py = round(cos(angle) * radius) + py_shift var/px = round(sin(angle) * radius) - if(anim) + if(anim_flag & BUTTON_SLIDE_IN) var/timing = anim_order * 0.5 var/matrix/starting = matrix() starting.Scale(0.1,0.1) @@ -232,8 +231,11 @@ GLOBAL_LIST_EMPTY(radial_menus) E.pixel_y = py E.pixel_x = px - //Visuals - E.alpha = 255 + if(anim_flag & BUTTON_FADE_IN) + animate(E, alpha = 255, time = 0.15 SECONDS, easing = EASE_OUT) + else + E.alpha = 255 + E.mouse_opacity = MOUSE_OPACITY_ICON E.cut_overlays() E.vis_contents.Cut() @@ -266,7 +268,9 @@ GLOBAL_LIST_EMPTY(radial_menus) info_button.layer = RADIAL_CONTENT_LAYER E.vis_contents += info_button -/datum/radial_menu/New() +/datum/radial_menu/New(display_close_button) + if(!display_close_button) + return close_button = new close_button.set_parent(src) @@ -327,7 +331,9 @@ GLOBAL_LIST_EMPTY(radial_menus) menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing", layer = RADIAL_BACKGROUND_LAYER, pixel_x = offset_x, pixel_y = offset_y) SET_PLANE_EXPLICIT(menu_holder, ABOVE_HUD_PLANE, M) menu_holder.appearance_flags |= KEEP_APART|RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM - menu_holder.vis_contents += elements + close_button + menu_holder.vis_contents += elements + if(!isnull(close_button)) + menu_holder.vis_contents += close_button current_user.images += menu_holder /datum/radial_menu/proc/hide() @@ -345,6 +351,14 @@ GLOBAL_LIST_EMPTY(radial_menus) next_check = world.time + check_delay stoplag(1) +/datum/radial_menu/proc/remove_menu() + if(!(button_animation_flags & BUTTON_FADE_OUT)) + qdel(src) + return + for(var/atom/movable/element as anything in elements) + animate(element, alpha = 0, time = 0.15 SECONDS) + QDEL_IN(src, 0.5 SECONDS) + /datum/radial_menu/Destroy() Reset() hide() @@ -356,11 +370,11 @@ GLOBAL_LIST_EMPTY(radial_menus) Choices should be a list where list keys are movables or text used for element names and return value and list values are movables/icons/images used for element icons */ -/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, radial_slice_icon = "radial_slice", autopick_single_option = TRUE, entry_animation = TRUE, click_on_hover = FALSE, user_space = FALSE) +/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, radial_slice_icon = "radial_slice", autopick_single_option = TRUE, button_animation_flags = BUTTON_SLIDE_IN, click_on_hover = FALSE, user_space = FALSE, check_delay = DEFAULT_CHECK_DELAY, display_close_button = TRUE, radial_menu_offset = list(0, 0)) if(!user || !anchor || !length(choices)) return - if(length(choices)==1 && autopick_single_option) + if(length(choices) == 1 && autopick_single_option) return choices[1] if(!uniqueid) @@ -372,8 +386,9 @@ GLOBAL_LIST_EMPTY(radial_menus) menu.finished = TRUE return - var/datum/radial_menu/menu = new - menu.entry_animation = entry_animation + var/datum/radial_menu/menu = new(display_close_button) + menu.button_animation_flags = button_animation_flags + menu.check_delay = check_delay GLOB.radial_menus[uniqueid] = menu if(radius) menu.radius = radius @@ -390,10 +405,12 @@ GLOBAL_LIST_EMPTY(radial_menus) var/turf/anchor_turf = get_turf(anchor) offset_x = (anchor_turf.x - user_turf.x) * ICON_SIZE_X + anchor.pixel_x - user.pixel_x offset_y = (anchor_turf.y - user_turf.y) * ICON_SIZE_Y + anchor.pixel_y - user.pixel_y + offset_x += radial_menu_offset[1] + offset_y += radial_menu_offset[2] menu.show_to(user, offset_x, offset_y) menu.wait(user, anchor, require_near) var/answer = menu.selected_choice - qdel(menu) + menu.remove_menu() GLOB.radial_menus -= uniqueid if(require_near && !in_range(anchor, user)) return diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/radial_persistent.dm index 5fe81d005bd43..d48c8d9eb456c 100644 --- a/code/_onclick/hud/radial_persistent.dm +++ b/code/_onclick/hud/radial_persistent.dm @@ -43,7 +43,7 @@ /datum/radial_menu/persistent/proc/change_choices(list/newchoices, tooltips = FALSE, animate = FALSE, keep_same_page = FALSE) if(!newchoices.len) return - entry_animation = FALSE + button_animation_flags = NONE var/target_page = keep_same_page ? current_page : 1 //Stores the current_page value before it's set back to 1 on Reset() Reset() set_choices(newchoices,tooltips, set_page = target_page) diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm index 115250104f008..805fe419c94b7 100644 --- a/code/controllers/subsystem/dbcore.dm +++ b/code/controllers/subsystem/dbcore.dm @@ -674,7 +674,7 @@ Ignore_errors instructes mysql to continue inserting rows if some of them have e /datum/db_query/proc/slow_query_check() - message_admins("HEY! A database query timed out. Did the server just hang? <a href='?_src_=holder;[HrefToken()];slowquery=yes'>\[YES\]</a>|<a href='?_src_=holder;[HrefToken()];slowquery=no'>\[NO\]</a>") + message_admins("HEY! A database query timed out. Did the server just hang? <a href='byond://?_src_=holder;[HrefToken()];slowquery=yes'>\[YES\]</a>|<a href='byond://?_src_=holder;[HrefToken()];slowquery=no'>\[NO\]</a>") /datum/db_query/proc/NextRow(async = TRUE) Activity("NextRow") diff --git a/code/controllers/subsystem/dynamic/dynamic.dm b/code/controllers/subsystem/dynamic/dynamic.dm index 5d53f3c2f65b4..152bfecce1dfc 100644 --- a/code/controllers/subsystem/dynamic/dynamic.dm +++ b/code/controllers/subsystem/dynamic/dynamic.dm @@ -203,23 +203,23 @@ SUBSYSTEM_DEF(dynamic) /datum/controller/subsystem/dynamic/proc/admin_panel() var/list/dat = list("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Game Mode Panel</title></head><body><h1><B>Game Mode Panel</B></h1>") - dat += "Dynamic Mode <a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</a> <a href='?src=[text_ref(src)];[HrefToken()]'>\[Refresh\]</a><BR>" + dat += "Dynamic Mode <a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</a> <a href='byond://?src=[text_ref(src)];[HrefToken()]'>\[Refresh\]</a><BR>" dat += "Threat Level: <b>[threat_level]</b><br/>" dat += "Budgets (Roundstart/Midrounds): <b>[initial_round_start_budget]/[threat_level - initial_round_start_budget]</b><br/>" - dat += "Midround budget to spend: <b>[mid_round_budget]</b> <a href='?src=[text_ref(src)];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='?src=[text_ref(src)];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>" + dat += "Midround budget to spend: <b>[mid_round_budget]</b> <a href='byond://?src=[text_ref(src)];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='byond://?src=[text_ref(src)];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>" dat += "<br/>" dat += "Parameters: centre = [threat_curve_centre] ; width = [threat_curve_width].<br/>" dat += "Split parameters: centre = [roundstart_split_curve_centre] ; width = [roundstart_split_curve_width].<br/>" dat += "<i>On average, <b>[clamp(peaceful_percentage, 1, 99)]</b>% of the rounds are more peaceful.</i><br/>" - dat += "Forced extended: <a href='?src=[text_ref(src)];[HrefToken()];forced_extended=1'><b>[GLOB.dynamic_forced_extended ? "On" : "Off"]</b></a><br/>" - dat += "No stacking (only one round-ender): <a href='?src=[text_ref(src)];[HrefToken()];no_stacking=1'><b>[GLOB.dynamic_no_stacking ? "On" : "Off"]</b></a><br/>" - dat += "Stacking limit: [GLOB.dynamic_stacking_limit] <a href='?src=[text_ref(src)];[HrefToken()];stacking_limit=1'>\[Adjust\]</A>" + dat += "Forced extended: <a href='byond://?src=[text_ref(src)];[HrefToken()];forced_extended=1'><b>[GLOB.dynamic_forced_extended ? "On" : "Off"]</b></a><br/>" + dat += "No stacking (only one round-ender): <a href='byond://?src=[text_ref(src)];[HrefToken()];no_stacking=1'><b>[GLOB.dynamic_no_stacking ? "On" : "Off"]</b></a><br/>" + dat += "Stacking limit: [GLOB.dynamic_stacking_limit] <a href='byond://?src=[text_ref(src)];[HrefToken()];stacking_limit=1'>\[Adjust\]</A>" dat += "<br/>" - dat += "<A href='?src=[text_ref(src)];[HrefToken()];force_latejoin_rule=1'>\[Force Next Latejoin Ruleset\]</A><br>" + dat += "<A href='byond://?src=[text_ref(src)];[HrefToken()];force_latejoin_rule=1'>\[Force Next Latejoin Ruleset\]</A><br>" if (forced_latejoin_rule) - dat += {"<A href='?src=[text_ref(src)];[HrefToken()];clear_forced_latejoin=1'>-> [forced_latejoin_rule.name] <-</A><br>"} - dat += "<A href='?src=[text_ref(src)];[HrefToken()];force_midround_rule=1'>\[Execute Midround Ruleset\]</A><br>" + dat += {"<A href='byond://?src=[text_ref(src)];[HrefToken()];clear_forced_latejoin=1'>-> [forced_latejoin_rule.name] <-</A><br>"} + dat += "<A href='byond://?src=[text_ref(src)];[HrefToken()];force_midround_rule=1'>\[Execute Midround Ruleset\]</A><br>" dat += "<br />" dat += "Executed rulesets: " if (executed_rules.len > 0) @@ -229,13 +229,13 @@ SUBSYSTEM_DEF(dynamic) else dat += "none.<br>" dat += "<br>Injection Timers: (<b>[get_heavy_midround_injection_chance(dry_run = TRUE)]%</b> heavy midround chance)<BR>" - dat += "Latejoin: [DisplayTimeText(latejoin_injection_cooldown-world.time)] <a href='?src=[text_ref(src)];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>" + dat += "Latejoin: [DisplayTimeText(latejoin_injection_cooldown-world.time)] <a href='byond://?src=[text_ref(src)];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>" var/next_injection = next_midround_injection() if (next_injection == INFINITY) dat += "All midrounds have been exhausted." else - dat += "Midround: [DisplayTimeText(next_injection - world.time)] <a href='?src=[text_ref(src)];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>" + dat += "Midround: [DisplayTimeText(next_injection - world.time)] <a href='byond://?src=[text_ref(src)];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>" usr << browse(dat.Join(), "window=gamemode_panel;size=500x500") diff --git a/code/controllers/subsystem/dynamic/ruleset_picking.dm b/code/controllers/subsystem/dynamic/ruleset_picking.dm index e3de3289899f7..f22ce3315740e 100644 --- a/code/controllers/subsystem/dynamic/ruleset_picking.dm +++ b/code/controllers/subsystem/dynamic/ruleset_picking.dm @@ -69,8 +69,8 @@ log_dynamic("[rule] ruleset executing...") message_admins("DYNAMIC: Executing midround ruleset [rule] in [DisplayTimeText(ADMIN_CANCEL_MIDROUND_TIME)]. \ - <a href='?src=[REF(src)];cancelmidround=[midround_injection_timer_id]'>CANCEL</a> | \ - <a href='?src=[REF(src)];differentmidround=[midround_injection_timer_id]'>SOMETHING ELSE</a>") + <a href='byond://?src=[REF(src)];cancelmidround=[midround_injection_timer_id]'>CANCEL</a> | \ + <a href='byond://?src=[REF(src)];differentmidround=[midround_injection_timer_id]'>SOMETHING ELSE</a>") return rule diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm index 20194e66626ca..2b61cabb86074 100644 --- a/code/controllers/subsystem/explosions.dm +++ b/code/controllers/subsystem/explosions.dm @@ -524,6 +524,7 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec /datum/controller/subsystem/explosions/proc/shake_the_room(turf/epicenter, near_distance, far_distance, quake_factor, echo_factor, creaking, sound/near_sound = sound(get_sfx(SFX_EXPLOSION)), sound/far_sound = sound('sound/effects/explosion/explosionfar.ogg'), sound/echo_sound = sound('sound/effects/explosion/explosion_distant.ogg'), sound/creaking_sound = sound(get_sfx(SFX_EXPLOSION_CREAKING)), hull_creaking_sound = sound(get_sfx(SFX_HULL_CREAKING))) var/frequency = get_rand_frequency() var/blast_z = epicenter.z + var/area/epicenter_area = get_area(epicenter) if(isnull(creaking)) // Autoset creaking. var/on_station = SSmapping.level_trait(epicenter.z, ZTRAIT_STATION) if(on_station && prob((quake_factor * QUAKE_CREAK_PROB) + (echo_factor * ECHO_CREAK_PROB))) // Huge explosions are near guaranteed to make the station creak and whine, smaller ones might. @@ -559,7 +560,7 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec base_shake_amount = max(base_shake_amount, quake_factor * 3, 0) // Devastating explosions rock the station and ground shake_camera(listener, FAR_SHAKE_DURATION, min(base_shake_amount, FAR_SHAKE_CAP)) - else if(!isspaceturf(listener_turf) && echo_factor) // Big enough explosions echo through the hull. + else if(!isspaceturf(listener_turf) && !(!(epicenter_area.type in GLOB.the_station_areas) && SSmapping.is_planetary()) && echo_factor) // Big enough explosions echo through the hull. Except on planetary maps if the epicenter is not on the station's area. var/echo_volume if(quake_factor) echo_volume = 60 diff --git a/code/controllers/subsystem/lag_switch.dm b/code/controllers/subsystem/lag_switch.dm index c79db05186017..291e80fe18f1f 100644 --- a/code/controllers/subsystem/lag_switch.dm +++ b/code/controllers/subsystem/lag_switch.dm @@ -34,7 +34,7 @@ SUBSYSTEM_DEF(lag_switch) auto_switch = FALSE UnregisterSignal(SSdcs, COMSIG_GLOB_CLIENT_CONNECT) veto_timer_id = addtimer(CALLBACK(src, PROC_REF(set_all_measures), TRUE, TRUE), 20 SECONDS, TIMER_STOPPABLE) - message_admins("Lag Switch population threshold reached. Automatic activation of lag mitigation measures occuring in 20 seconds. (<a href='?_src_=holder;[HrefToken()];change_lag_switch_option=CANCEL'>CANCEL</a>)") + message_admins("Lag Switch population threshold reached. Automatic activation of lag mitigation measures occuring in 20 seconds. (<a href='byond://?_src_=holder;[HrefToken()];change_lag_switch_option=CANCEL'>CANCEL</a>)") log_admin("Lag Switch population threshold reached. Automatic activation of lag mitigation measures occuring in 20 seconds.") /// (En/Dis)able automatic triggering of switches based on client count diff --git a/code/controllers/subsystem/map_vote.dm b/code/controllers/subsystem/map_vote.dm index ced1e65e3a215..f57d73d773e63 100644 --- a/code/controllers/subsystem/map_vote.dm +++ b/code/controllers/subsystem/map_vote.dm @@ -53,7 +53,7 @@ SUBSYSTEM_DEF(map_vote) last_message_at = world.time var/list/messages = args.Copy() - to_chat(world, span_purple(examine_block("Map Vote\n<hr>[messages.Join("\n")]"))) + to_chat(world, span_purple(boxed_message("Map Vote\n<hr>[messages.Join("\n")]"))) /datum/controller/subsystem/map_vote/proc/finalize_map_vote(datum/vote/map_vote/map_vote) if(already_voted) @@ -170,4 +170,4 @@ SUBSYSTEM_DEF(map_vote) for(var/map_id in map_vote_cache) var/datum/map_config/map = config.maplist[map_id] data += "[map.map_name] - [map_vote_cache[map_id]]" - tally_printout = examine_block("Current Tallies\n<hr>[data.Join("\n")]") + tally_printout = boxed_message("Current Tallies\n<hr>[data.Join("\n")]") diff --git a/code/controllers/subsystem/polling.dm b/code/controllers/subsystem/polling.dm index c9c7d3ea31167..6624c984cbb6a 100644 --- a/code/controllers/subsystem/polling.dm +++ b/code/controllers/subsystem/polling.dm @@ -148,11 +148,11 @@ SUBSYSTEM_DEF(polling) var/custom_link_style_start = "<style>a:visited{color:Crimson !important}</style>" var/custom_link_style_end = "style='color:DodgerBlue;font-weight:bold;-dm-text-outline: 1px black'" if(isatom(alert_pic) && isobserver(candidate_mob)) - act_jump = "[custom_link_style_start]<a href='?src=[REF(poll_alert_button)];jump=1'[custom_link_style_end]>\[Teleport\]</a>" - var/act_signup = "[custom_link_style_start]<a href='?src=[REF(poll_alert_button)];signup=1'[custom_link_style_end]>\[[start_signed_up ? "Opt out" : "Sign Up"]\]</a>" + act_jump = "[custom_link_style_start]<a href='byond://?src=[REF(poll_alert_button)];jump=1'[custom_link_style_end]>\[Teleport\]</a>" + var/act_signup = "[custom_link_style_start]<a href='byond://?src=[REF(poll_alert_button)];signup=1'[custom_link_style_end]>\[[start_signed_up ? "Opt out" : "Sign Up"]\]</a>" var/act_never = "" if(ignore_category) - act_never = "[custom_link_style_start]<a href='?src=[REF(poll_alert_button)];never=1'[custom_link_style_end]>\[Never For This Round\]</a>" + act_never = "[custom_link_style_start]<a href='byond://?src=[REF(poll_alert_button)];never=1'[custom_link_style_end]>\[Never For This Round\]</a>" if(!duplicate_message_check(alert_poll)) //Only notify people once. They'll notice if there are multiple and we don't want to spam people. SEND_SOUND(candidate_mob, 'sound/announcer/notice/notice2.ogg') @@ -165,7 +165,7 @@ SUBSYSTEM_DEF(polling) else surrounding_image = image(chat_text_border_icon) surrounding_icon = icon2html(surrounding_image, candidate_mob, extra_classes = "bigicon") - var/final_message = examine_block("<span style='text-align:center;display:block'>[surrounding_icon] <span style='font-size:1.2em'>[span_ooc(question)]</span> [surrounding_icon]\n[act_jump] [act_signup] [act_never]</span>") + var/final_message = boxed_message("<span style='text-align:center;display:block'>[surrounding_icon] <span style='font-size:1.2em'>[span_ooc(question)]</span> [surrounding_icon]\n[act_jump] [act_signup] [act_never]</span>") to_chat(candidate_mob, final_message) // Start processing it so it updates visually the timer diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 2e616a91e2121..e0b6ce3d2c003 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -385,7 +385,7 @@ SUBSYSTEM_DEF(shuttle) SSblackbox.record_feedback("text", "shuttle_reason", 1, "[call_reason]") log_shuttle("Shuttle call reason: [call_reason]") SSticker.emergency_reason = call_reason - message_admins("[ADMIN_LOOKUPFLW(user)] has called the shuttle. (<A HREF='?_src_=holder;[HrefToken()];trigger_centcom_recall=1'>TRIGGER CENTCOM RECALL</A>)") + message_admins("[ADMIN_LOOKUPFLW(user)] has called the shuttle. (<A href='byond://?_src_=holder;[HrefToken()];trigger_centcom_recall=1'>TRIGGER CENTCOM RECALL</A>)") /// Call the emergency shuttle. /// If you are doing this on behalf of a player, use requestEvac instead. diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 5be680744f676..066436d0ec698 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -39,6 +39,15 @@ SUBSYSTEM_DEF(statpanels) var/ETA = SSshuttle.emergency.getModeStr() if(ETA) global_data += "[ETA] [SSshuttle.emergency.getTimerStr()]" + + if(SSticker.reboot_timer) + var/reboot_time = timeleft(SSticker.reboot_timer) + if(reboot_time) + global_data += "Reboot: [DisplayTimeText(reboot_time, 1)]" + // admin must have delayed round end + else if(SSticker.ready_for_reboot) + global_data += "Reboot: DELAYED" + src.currentrun = GLOB.clients.Copy() mc_data = null @@ -94,11 +103,14 @@ SUBSYSTEM_DEF(statpanels) return /datum/controller/subsystem/statpanels/proc/set_status_tab(client/target) +#if MIN_COMPILER_VERSION > 515 + #warn 516 is most certainly out of beta, remove this beta notice if you haven't already +#endif + var/static/list/beta_notice = list("", "You are on the BYOND 516 beta, various UIs and such may be broken!", "Please report issues, and switch back to BYOND 515 if things are causing too many issues for you.") if(!global_data)//statbrowser hasnt fired yet and we were called from immediate_send_stat_data() return - target.stat_panel.send_message("update_stat", list( - "global_data" = global_data, + "global_data" = (target.byond_version < 516) ? global_data : (global_data + beta_notice), "ping_str" = "Ping: [round(target.lastping, 1)]ms (Average: [round(target.avgping, 1)]ms)", "other_str" = target.mob?.get_status_tab_items(), )) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index bb18a45b72d9a..96cde0ef0dded 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -67,6 +67,9 @@ SUBSYSTEM_DEF(ticker) /// Why an emergency shuttle was called var/emergency_reason + /// ID of round reboot timer, if it exists + var/reboot_timer = null + /datum/controller/subsystem/ticker/Initialize() var/list/byond_sound_formats = list( "mid" = TRUE, @@ -487,7 +490,7 @@ SUBSYSTEM_DEF(ticker) if(!hard_popcap) list_clear_nulls(queued_players) for (var/mob/dead/new_player/new_player in queued_players) - to_chat(new_player, span_userdanger("The alive players limit has been released!<br><a href='?src=[REF(new_player)];late_join=override'>[html_encode(">>Join Game<<")]</a>")) + to_chat(new_player, span_userdanger("The alive players limit has been released!<br><a href='byond://?src=[REF(new_player)];late_join=override'>[html_encode(">>Join Game<<")]</a>")) SEND_SOUND(new_player, sound('sound/announcer/notice/notice1.ogg')) GLOB.latejoin_menu.ui_interact(new_player) queued_players.len = 0 @@ -502,7 +505,7 @@ SUBSYSTEM_DEF(ticker) list_clear_nulls(queued_players) if(living_player_count() < hard_popcap) if(next_in_line?.client) - to_chat(next_in_line, span_userdanger("A slot has opened! You have approximately 20 seconds to join. <a href='?src=[REF(next_in_line)];late_join=override'>\>\>Join Game\<\<</a>")) + to_chat(next_in_line, span_userdanger("A slot has opened! You have approximately 20 seconds to join. <a href='byond://?src=[REF(next_in_line)];late_join=override'>\>\>Join Game\<\<</a>")) SEND_SOUND(next_in_line, sound('sound/announcer/notice/notice1.ogg')) next_in_line.ui_interact(next_in_line) return @@ -698,11 +701,10 @@ SUBSYSTEM_DEF(ticker) var/start_wait = world.time UNTIL(round_end_sound_sent || (world.time - start_wait) > (delay * 2)) //don't wait forever - sleep(delay - (world.time - start_wait)) + reboot_timer = addtimer(CALLBACK(src, PROC_REF(reboot_callback), reason, end_string), delay - (world.time - start_wait), TIMER_STOPPABLE) - if(delay_end && !skip_delay) - to_chat(world, span_boldannounce("Reboot was cancelled by an admin.")) - return + +/datum/controller/subsystem/ticker/proc/reboot_callback(reason, end_string) if(end_string) end_state = end_string @@ -710,6 +712,21 @@ SUBSYSTEM_DEF(ticker) world.Reboot() +/** + * Deletes the current reboot timer and nulls the var + * + * Arguments: + * * user - the user that cancelled the reboot, may be null + */ +/datum/controller/subsystem/ticker/proc/cancel_reboot(mob/user) + if(!reboot_timer) + to_chat(user, span_warning("There is no pending reboot!")) + return FALSE + to_chat(world, span_boldannounce("An admin has delayed the round end.")) + deltimer(reboot_timer) + reboot_timer = null + return TRUE + /datum/controller/subsystem/ticker/Shutdown() gather_newscaster() //called here so we ensure the log is created even upon admin reboot if(!round_end_sound) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index d0e642bd3aa2d..d9d796782c2b2 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -119,7 +119,7 @@ SUBSYSTEM_DEF(vote) ) log_vote("vote finalized", vote_log_data) if(to_display) - to_chat(world, span_infoplain(vote_font("\n[to_display]"))) + to_chat(world, span_infoplain(vote_font("[to_display]"))) // Finally, doing any effects on vote completion current_vote.finalize_vote(final_winner) @@ -230,9 +230,9 @@ SUBSYSTEM_DEF(vote) var/to_display = current_vote.initiate_vote(vote_initiator_name, duration) log_vote(to_display) - to_chat(world, span_infoplain(vote_font("\n[span_bold(to_display)]\n\ + to_chat(world, custom_boxed_message("purple_box center", span_infoplain(vote_font("[span_bold(to_display)]<br>\ Type <b>vote</b> or click <a href='byond://winset?command=vote'>here</a> to place your votes.\n\ - You have [DisplayTimeText(duration)] to vote."))) + You have [DisplayTimeText(duration)] to vote.")))) // And now that it's going, give everyone a voter action for(var/client/new_voter as anything in GLOB.clients) diff --git a/code/datums/actions/action.dm b/code/datums/actions/action.dm index 2f297f480ae66..18525a8c04e94 100644 --- a/code/datums/actions/action.dm +++ b/code/datums/actions/action.dm @@ -435,5 +435,5 @@ if(source.next_click > world.time) return else - source.next_click = world.time + CLICK_CD_RANGE + source.next_click = world.time + CLICK_CD_ACTIVATE_ABILITY INVOKE_ASYNC(src, PROC_REF(Trigger)) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm b/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm index 6cae6132d3688..4d7a3e7ad3064 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm @@ -31,11 +31,11 @@ var/list/final_list switch(happiness_value) if(HIGH_HAPPINESS_THRESHOLD to INFINITY) - final_list = happy_emotions + final_list = controller.blackboard[BB_HAPPY_EMOTIONS] || happy_emotions if(MODERATE_HAPPINESS_THRESHOLD to HIGH_HAPPINESS_THRESHOLD) - final_list = moderate_emotions + final_list = controller.blackboard[BB_MODERATE_EMOTIONS] || moderate_emotions else - final_list = depressed_emotions + final_list = controller.blackboard[BB_SAD_EMOTIONS] || depressed_emotions if(!length(final_list)) return controller.queue_behavior(/datum/ai_behavior/perform_emote, pick(final_list)) diff --git a/code/datums/ai_laws/ai_laws.dm b/code/datums/ai_laws/ai_laws.dm index 252bda405ec97..88c5650008870 100644 --- a/code/datums/ai_laws/ai_laws.dm +++ b/code/datums/ai_laws/ai_laws.dm @@ -442,7 +442,7 @@ GLOBAL_VAR(round_default_lawset) /datum/ai_laws/proc/show_laws(mob/to_who) var/list/printable_laws = get_law_list(include_zeroth = TRUE) - to_chat(to_who, examine_block(jointext(printable_laws, "\n"))) + to_chat(to_who, boxed_message(jointext(printable_laws, "\n"))) /datum/ai_laws/proc/associate(mob/living/silicon/M) if(owner) diff --git a/code/datums/browser.dm b/code/datums/browser.dm index b9d859552389d..cf0df8dac5017 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -138,13 +138,13 @@ var/output = {"<center><b>[Message]</b></center><br /> <div style="text-align:center"> - <a style="font-size:large;float:[( Button2 ? "left" : "right" )]" href="?src=[REF(src)];button=1">[Button1]</a>"} + <a style="font-size:large;float:[( Button2 ? "left" : "right" )]" href='byond://?src=[REF(src)];button=1'>[Button1]</a>"} if (Button2) - output += {"<a style="font-size:large;[( Button3 ? "" : "float:right" )]" href="?src=[REF(src)];button=2">[Button2]</a>"} + output += {"<a style="font-size:large;[( Button3 ? "" : "float:right" )]" href='byond://?src=[REF(src)];button=2'>[Button2]</a>"} if (Button3) - output += {"<a style="font-size:large;float:right" href="?src=[REF(src)];button=3">[Button3]</a>"} + output += {"<a style="font-size:large;float:right" href='byond://?src=[REF(src)];button=3'>[Button3]</a>"} output += {"</div>"} @@ -356,11 +356,11 @@ var/setting = settings["mainsettings"][name] if (setting["type"] == "datum") if (setting["subtypesonly"]) - dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;subtypesonly=1;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>" + dat += "<b>[setting["desc"]]:</b> <a href='byond://?src=[REF(src)];setting=[name];task=input;subtypesonly=1;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>" else - dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>" + dat += "<b>[setting["desc"]]:</b> <a href='byond://?src=[REF(src)];setting=[name];task=input;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>" else - dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;type=[setting["type"]]'>[setting["value"]]</a><BR>" + dat += "<b>[setting["desc"]]:</b> <a href='byond://?src=[REF(src)];setting=[name];task=input;type=[setting["type"]]'>[setting["value"]]</a><BR>" if (preview_icon) dat += "<td valign='center'>" @@ -371,7 +371,7 @@ dat += "</tr></table>" - dat += "<hr><center><a href='?src=[REF(src)];button=1'>Ok</a> " + dat += "<hr><center><a href='byond://?src=[REF(src)];button=1'>Ok</a> " dat += "</center>" diff --git a/code/datums/components/aquarium.dm b/code/datums/components/aquarium.dm index f207ecd9f5510..69939cb67b92e 100644 --- a/code/datums/components/aquarium.dm +++ b/code/datums/components/aquarium.dm @@ -100,11 +100,12 @@ ADD_KEEP_TOGETHER(movable, AQUARIUM_TRAIT) //render the fish on the same layer of the aquarium. if(reagents_size > 0) - RegisterSignal(movable.reagents, COMSIG_REAGENTS_NEW_REAGENT, PROC_REF(start_autofeed)) if(!movable.reagents) movable.create_reagents(reagents_size, SEALED_CONTAINER) - else if(movable.reagents.total_volume) + if(movable.reagents.total_volume) start_autofeed(movable.reagents) + else + RegisterSignal(movable.reagents, COMSIG_REAGENTS_NEW_REAGENT, PROC_REF(start_autofeed)) RegisterSignal(movable, COMSIG_PLUNGER_ACT, PROC_REF(on_plunger_act)) RegisterSignal(movable, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(on_item_interaction)) @@ -240,10 +241,10 @@ return ITEM_INTERACT_SUCCESS ///Called when the feed storage is no longer empty. -/datum/component/aquarium/proc/start_autofeed(atom/movable/source, new_reagent, amount, reagtemp, data, no_react) +/datum/component/aquarium/proc/start_autofeed(datum/reagents/source, new_reagent, amount, reagtemp, data, no_react) SIGNAL_HANDLER START_PROCESSING(SSobj, src) - UnregisterSignal(source.reagents, COMSIG_REAGENTS_NEW_REAGENT) + UnregisterSignal(source, COMSIG_REAGENTS_NEW_REAGENT) ///Feed the fish at defined intervals until the feed storage is empty. /datum/component/aquarium/process(seconds_per_tick) diff --git a/code/datums/components/callouts.dm b/code/datums/components/callouts.dm index 52a3e007905c3..854f769f8a10a 100644 --- a/code/datums/components/callouts.dm +++ b/code/datums/components/callouts.dm @@ -111,7 +111,7 @@ for(var/datum/callout_option/callout_option as anything in callout_options) callout_items[callout_option] = image(icon = 'icons/hud/radial.dmi', icon_state = callout_option::icon_state) - var/datum/callout_option/selection = show_radial_menu(user, get_turf(clicked_atom), callout_items, entry_animation = FALSE, click_on_hover = TRUE, user_space = TRUE) + var/datum/callout_option/selection = show_radial_menu(user, get_turf(clicked_atom), callout_items, button_animation_flags = NONE, click_on_hover = TRUE, user_space = TRUE) if (!selection) return diff --git a/code/datums/components/jetpack.dm b/code/datums/components/jetpack.dm index c7ff096029b97..5498a8a81ef85 100644 --- a/code/datums/components/jetpack.dm +++ b/code/datums/components/jetpack.dm @@ -119,7 +119,7 @@ /datum/component/jetpack/proc/deactivate(datum/source, mob/old_user) SIGNAL_HANDLER - UnregisterSignal(old_user, list(COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_MOVED, COMSIG_MOB_CLIENT_MOVE_NOGRAV, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE)) + UnregisterSignal(old_user, list(COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_MOVED, COMSIG_MOB_CLIENT_MOVE_NOGRAV, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT)) STOP_PROCESSING(SSnewtonian_movement, src) user = null @@ -159,7 +159,7 @@ last_stabilization_tick = world.time - if (!should_trigger(user) || !stabilize || isnull(user.drift_handler)) + if (!should_trigger(user) || !stabilize || !check_on_move.Invoke(FALSE) || isnull(user.drift_handler)) return var/max_drift_force = MOVE_DELAY_TO_DRIFT(user.cached_multiplicative_slowdown) diff --git a/code/datums/components/pet_commands/fetch.dm b/code/datums/components/pet_commands/fetch.dm index 9a42c485d5c06..143ac9ca1014c 100644 --- a/code/datums/components/pet_commands/fetch.dm +++ b/code/datums/components/pet_commands/fetch.dm @@ -3,11 +3,11 @@ * Watch for someone throwing or pointing at something and then go get it and bring it back. * If it's food we might eat it instead. */ -/datum/pet_command/point_targeting/fetch +/datum/pet_command/fetch command_name = "Fetch" command_desc = "Command your pet to retrieve something you throw or point at." - radial_icon = 'icons/mob/actions/actions_spells.dmi' - radial_icon_state = "summons" + radial_icon_state = "fetch" + requires_pointing = TRUE speech_commands = list("fetch") command_feedback = "bounces" pointed_reaction = "with great interest" @@ -16,22 +16,25 @@ /// If true, this is a poorly trained pet who will eat food you throw instead of bringing it back var/will_eat_targets = TRUE -/datum/pet_command/point_targeting/fetch/New(mob/living/parent) +/datum/pet_command/fetch/New(mob/living/parent) . = ..() if(isnull(parent)) return parent.AddElement(/datum/element/ai_held_item) // We don't remove this on destroy because they might still be holding something -/datum/pet_command/point_targeting/fetch/add_new_friend(mob/living/tamer) +/datum/pet_command/fetch/add_new_friend(mob/living/tamer) . = ..() RegisterSignal(tamer, COMSIG_MOB_THROW, PROC_REF(listened_throw)) -/datum/pet_command/point_targeting/fetch/remove_friend(mob/living/unfriended) +/datum/pet_command/fetch/remove_friend(mob/living/unfriended) . = ..() UnregisterSignal(unfriended, COMSIG_MOB_THROW) +/datum/pet_command/fetch/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to fetch [target]!" + /// A friend has thrown something, if we're listening or at least not busy then go get it -/datum/pet_command/point_targeting/fetch/proc/listened_throw(mob/living/carbon/thrower) +/datum/pet_command/fetch/proc/listened_throw(mob/living/carbon/thrower) SIGNAL_HANDLER var/mob/living/parent = weak_parent.resolve() @@ -57,7 +60,7 @@ RegisterSignal(thrown_thing, COMSIG_MOVABLE_THROW_LANDED, PROC_REF(listen_throw_land)) /// A throw we were listening to has finished, see if it's in range for us to try grabbing it -/datum/pet_command/point_targeting/fetch/proc/listen_throw_land(obj/item/thrown_thing, datum/thrownthing/throwingdatum) +/datum/pet_command/fetch/proc/listen_throw_land(obj/item/thrown_thing, datum/thrownthing/throwingdatum) SIGNAL_HANDLER UnregisterSignal(thrown_thing, COMSIG_MOVABLE_THROW_LANDED) @@ -76,7 +79,7 @@ parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, thrower) // Don't try and fetch turfs or anchored objects if someone points at them -/datum/pet_command/point_targeting/fetch/look_for_target(mob/living/pointing_friend, obj/item/pointed_atom) +/datum/pet_command/fetch/look_for_target(mob/living/pointing_friend, obj/item/pointed_atom) if (!istype(pointed_atom)) return FALSE if (pointed_atom.anchored) @@ -89,7 +92,7 @@ parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, pointing_friend) // Finally, plan our actions -/datum/pet_command/point_targeting/fetch/execute_action(datum/ai_controller/controller) +/datum/pet_command/fetch/execute_action(datum/ai_controller/controller) controller.queue_behavior(/datum/ai_behavior/forget_failed_fetches) var/atom/target = controller.blackboard[BB_CURRENT_PET_TARGET] diff --git a/code/datums/components/pet_commands/obeys_commands.dm b/code/datums/components/pet_commands/obeys_commands.dm index 8aaa7e7179294..4a68574d6e08c 100644 --- a/code/datums/components/pet_commands/obeys_commands.dm +++ b/code/datums/components/pet_commands/obeys_commands.dm @@ -3,12 +3,23 @@ * Manages a list of pet command datums, allowing you to boss it around * Creates a radial menu of pet commands when this creature is alt-clicked, if it has any */ +#define DEFAULT_RADIAL_VIEWING_DISTANCE 9 /datum/component/obeys_commands /// List of commands you can give to the owner of this component var/list/available_commands = list() + ///Users currently viewing our radial options + var/list/radial_viewers = list() + ///radius of our radial menu + var/radial_menu_radius = 48 + ///after how long we shutdown radial menus + var/radial_menu_lifetime = 7 SECONDS + ///offset to display the radial menu + var/list/radial_menu_offset + ///should the commands move with the pet owner's screen? + var/radial_relative_to_user /// The available_commands parameter should be passed as a list of typepaths -/datum/component/obeys_commands/Initialize(list/command_typepaths = list()) +/datum/component/obeys_commands/Initialize(list/command_typepaths = list(), list/radial_menu_offset = list(0, 0), radial_relative_to_user = FALSE) . = ..() if (!isliving(parent)) return COMPONENT_INCOMPATIBLE @@ -17,7 +28,8 @@ return COMPONENT_INCOMPATIBLE if (!length(command_typepaths)) CRASH("Initialised obedience component with no commands.") - + src.radial_menu_offset = radial_menu_offset + src.radial_relative_to_user = radial_relative_to_user for (var/command_path in command_typepaths) var/datum/pet_command/new_command = new command_path(parent) available_commands[new_command.command_name] = new_command @@ -30,7 +42,6 @@ RegisterSignal(parent, COMSIG_LIVING_BEFRIENDED, PROC_REF(add_friend)) RegisterSignal(parent, COMSIG_LIVING_UNFRIENDED, PROC_REF(remove_friend)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) - RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(display_menu)) /datum/component/obeys_commands/UnregisterFromParent() UnregisterSignal(parent, list(COMSIG_LIVING_BEFRIENDED, COMSIG_LIVING_UNFRIENDED, COMSIG_ATOM_EXAMINE, COMSIG_CLICK_ALT)) @@ -38,15 +49,26 @@ /// Add someone to our friends list /datum/component/obeys_commands/proc/add_friend(datum/source, mob/living/new_friend) SIGNAL_HANDLER - + RegisterSignal(new_friend, COMSIG_KB_LIVING_VIEW_PET_COMMANDS, PROC_REF(on_key_pressed)) + RegisterSignal(new_friend, DEACTIVATE_KEYBIND(COMSIG_KB_LIVING_VIEW_PET_COMMANDS), PROC_REF(on_key_unpressed)) for (var/command_name as anything in available_commands) var/datum/pet_command/command = available_commands[command_name] INVOKE_ASYNC(command, TYPE_PROC_REF(/datum/pet_command, add_new_friend), new_friend) +/datum/component/obeys_commands/proc/on_key_unpressed(mob/living/source) + SIGNAL_HANDLER + UnregisterSignal(source, COMSIG_ATOM_MOUSE_ENTERED) + +/datum/component/obeys_commands/proc/remove_from_viewers(mob/living/source) + radial_viewers -= REF(source) + /// Remove someone from our friends list /datum/component/obeys_commands/proc/remove_friend(datum/source, mob/living/old_friend) SIGNAL_HANDLER - + UnregisterSignal(old_friend, list( + COMSIG_KB_LIVING_VIEW_PET_COMMANDS, + DEACTIVATE_KEYBIND(COMSIG_KB_LIVING_VIEW_PET_COMMANDS), + )) for (var/command_name as anything in available_commands) var/datum/pet_command/command = available_commands[command_name] INVOKE_ASYNC(command, TYPE_PROC_REF(/datum/pet_command, remove_friend), old_friend) @@ -61,21 +83,34 @@ return examine_list += span_notice("[source.p_They()] seem[source.p_s()] happy to see you!") -/// Displays a radial menu of commands -/datum/component/obeys_commands/proc/display_menu(datum/source, mob/living/clicker) +/datum/component/obeys_commands/proc/on_key_pressed(mob/living/friend) + SIGNAL_HANDLER + RegisterSignal(friend, COMSIG_ATOM_MOUSE_ENTERED, PROC_REF(on_mouse_hover)) + +/datum/component/obeys_commands/proc/on_mouse_hover(mob/living/friend, atom/mouse_hovered) SIGNAL_HANDLER + if(mouse_hovered == parent) + display_menu(friend) + return + if(isliving(mouse_hovered)) + remove_from_viewers(friend) + +/// Displays a radial menu of commands +/datum/component/obeys_commands/proc/display_menu(mob/living/friend) var/mob/living/living_parent = parent - if (IS_DEAD_OR_INCAP(living_parent) || !clicker.can_perform_action(living_parent)) + if (IS_DEAD_OR_INCAP(living_parent) || friend.stat != CONSCIOUS) return - if (!(clicker in living_parent.ai_controller?.blackboard[BB_FRIENDS_LIST])) + if (!(friend in living_parent.ai_controller?.blackboard[BB_FRIENDS_LIST])) return // Not our friend, can't boss us around - - INVOKE_ASYNC(src, PROC_REF(display_radial_menu), clicker) - return CLICK_ACTION_SUCCESS + if(radial_viewers[REF(friend)]) + return + if(!can_see(friend, parent, DEFAULT_RADIAL_VIEWING_DISTANCE)) + return + INVOKE_ASYNC(src, PROC_REF(display_radial_menu), friend) /// Actually display the radial menu and then do something with the result -/datum/component/obeys_commands/proc/display_radial_menu(mob/living/clicker) +/datum/component/obeys_commands/proc/display_radial_menu(mob/living/friend) var/list/radial_options = list() for (var/command_name as anything in available_commands) var/datum/pet_command/command = available_commands[command_name] @@ -83,9 +118,22 @@ if (!choice) continue radial_options += choice - - var/pick = show_radial_menu(clicker, clicker, radial_options, tooltips = TRUE) - if (!pick) + radial_viewers[REF(friend)] = world.time + radial_menu_lifetime + var/pick = show_radial_menu(friend, parent, radial_options, radius = radial_menu_radius, button_animation_flags = BUTTON_FADE_IN | BUTTON_FADE_OUT, custom_check = CALLBACK(src, PROC_REF(check_menu_viewer), friend), check_delay = 0.15 SECONDS, display_close_button = FALSE, radial_menu_offset = radial_menu_offset, user_space = radial_relative_to_user) + remove_from_viewers(friend) + if(!pick) return var/datum/pet_command/picked_command = available_commands[pick] - picked_command.try_activate_command(clicker) + picked_command.try_activate_command(friend, radial_command = TRUE) + +/datum/component/obeys_commands/proc/check_menu_viewer(mob/living/user) + if(QDELETED(user) || !radial_viewers[REF(user)]) + return FALSE + if(world.time > radial_viewers[REF(user)]) + return FALSE + var/viewing_distance = DEFAULT_RADIAL_VIEWING_DISTANCE + if(!can_see(user, parent, viewing_distance)) + return FALSE + return TRUE + +#undef DEFAULT_RADIAL_VIEWING_DISTANCE diff --git a/code/datums/components/pet_commands/pet_command.dm b/code/datums/components/pet_commands/pet_command.dm index d99d128e38ea9..b291a8750f4e8 100644 --- a/code/datums/components/pet_commands/pet_command.dm +++ b/code/datums/components/pet_commands/pet_command.dm @@ -13,7 +13,7 @@ /// If true, command will not appear in radial menu and can only be accessed through speech var/hidden = FALSE /// Icon to display in radial menu - var/icon/radial_icon + var/icon/radial_icon = 'icons/hud/radial_pets.dmi' /// Icon state to display in radial menu var/radial_icon_state /// Speech strings to listen out for @@ -24,6 +24,12 @@ var/command_feedback /// How close a mob needs to be to a target to respond to a command var/sense_radius = 7 + /// does this pet command need a point to activate? + var/requires_pointing = FALSE + /// Blackboard key for targeting strategy, this is likely going to need it + var/targeting_strategy_key = BB_PET_TARGETING_STRATEGY + ///our pointed reaction we play + var/pointed_reaction /datum/pet_command/New(mob/living/parent) . = ..() @@ -34,10 +40,17 @@ RegisterSignal(tamer, COMSIG_MOB_SAY, PROC_REF(respond_to_command)) RegisterSignal(tamer, COMSIG_MOB_AUTOMUTE_CHECK, PROC_REF(waive_automute)) RegisterSignal(tamer, COMSIG_MOB_CREATED_CALLOUT, PROC_REF(respond_to_callout)) + if(requires_pointing) + RegisterSignal(tamer, COMSIG_MOVABLE_POINTED, PROC_REF(point_on_target)) /// Stop listening to a guy /datum/pet_command/proc/remove_friend(mob/living/unfriended) - UnregisterSignal(unfriended, list(COMSIG_MOB_SAY, COMSIG_MOB_AUTOMUTE_CHECK, COMSIG_MOB_CREATED_CALLOUT)) + UnregisterSignal(unfriended, list( + COMSIG_MOB_SAY, + COMSIG_MOB_AUTOMUTE_CHECK, + COMSIG_MOB_CREATED_CALLOUT, + COMSIG_MOVABLE_POINTED, + )) /// Stop the automute from triggering for commands (unless the spoken text is suspiciously longer than the command) /datum/pet_command/proc/waive_automute(mob/living/speaker, client/client, last_message, mute_type) @@ -49,7 +62,6 @@ /// Respond to something that one of our friends has asked us to do /datum/pet_command/proc/respond_to_command(mob/living/speaker, speech_args) SIGNAL_HANDLER - var/mob/living/parent = weak_parent.resolve() if (!parent) return @@ -60,7 +72,7 @@ if (!find_command_in_text(spoken_text)) return - try_activate_command(speaker) + try_activate_command(commander = speaker, radial_command = FALSE) /// Respond to a callout /datum/pet_command/proc/respond_to_callout(mob/living/caller, datum/callout_option/callout, atom/target) @@ -83,7 +95,7 @@ if (!found_new_target) return - if (try_activate_command(caller)) + if (try_activate_command(commander = caller, radial_command = FALSE)) look_for_target(parent, target) /// Does this callout with this target trigger this command? @@ -103,48 +115,77 @@ return TRUE return FALSE -/// Apply a command state if conditions are right, return command if successful -/datum/pet_command/proc/try_activate_command(mob/living/commander) +/datum/pet_command/proc/pet_able_to_respond() var/mob/living/parent = weak_parent.resolve() - if (!parent) + if(isnull(parent) || isnull(parent.ai_controller)) return FALSE - if (!parent.ai_controller) // We stopped having a brain at some point + if(IS_DEAD_OR_INCAP(parent)) // Probably can't hear them if we're dead return FALSE - if (IS_DEAD_OR_INCAP(parent)) // Probably can't hear them if we're dead - return FALSE - if (parent.ai_controller.blackboard[BB_ACTIVE_PET_COMMAND] == src) // We're already doing it + return TRUE + +/// Apply a command state if conditions are right, return command if successful +/datum/pet_command/proc/try_activate_command(mob/living/commander, radial_command) + if(!pet_able_to_respond()) return FALSE - set_command_active(parent, commander) + var/mob/living/parent = weak_parent.resolve() + set_command_active(parent, commander, radial_command) return TRUE +/datum/pet_command/proc/generate_emote_command(atom/target) + var/mob/living/living_pet = weak_parent?.resolve() + return isnull(living_pet) ? null : retrieve_command_text(living_pet, target) + +/datum/pet_command/proc/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to spring into action!" + /// Target the pointed atom for actions -/datum/pet_command/proc/look_for_target(mob/living/friend, atom/pointed_atom) +/datum/pet_command/proc/look_for_target(mob/living/friend, atom/potential_target) var/mob/living/parent = weak_parent.resolve() - if (!parent) - return FALSE - if (!parent.ai_controller) - return FALSE - if (IS_DEAD_OR_INCAP(parent)) + if(!pet_able_to_respond()) return FALSE - if (parent.ai_controller.blackboard[BB_ACTIVE_PET_COMMAND] != src) // We're not listening right now + if (parent.ai_controller.blackboard[BB_CURRENT_PET_TARGET] == potential_target) // That's already our target return FALSE - if (parent.ai_controller.blackboard[BB_CURRENT_PET_TARGET] == pointed_atom) // That's already our target - return FALSE - if (!can_see(parent, pointed_atom, sense_radius)) + if (!can_see(parent, potential_target, sense_radius)) return FALSE parent.ai_controller.CancelActions() - set_command_target(parent, pointed_atom) + set_command_target(parent, potential_target) return TRUE /// Activate the command, extend to add visible messages and the like -/datum/pet_command/proc/set_command_active(mob/living/parent, mob/living/commander) - set_command_target(parent, null) +/datum/pet_command/proc/set_command_active(mob/living/parent, mob/living/commander, radial_command = FALSE) + parent.ai_controller.clear_blackboard_key(BB_CURRENT_PET_TARGET) parent.ai_controller.CancelActions() // Stop whatever you're doing and do this instead parent.ai_controller.set_blackboard_key(BB_ACTIVE_PET_COMMAND, src) if (command_feedback) parent.balloon_alert_to_viewers("[command_feedback]") // If we get a nicer runechat way to do this, refactor this + if(!radial_command) + return + if(!requires_pointing) + var/manual_emote_text = generate_emote_command() + commander.manual_emote(manual_emote_text) + return + RegisterSignal(commander, COMSIG_MOB_CLICKON, PROC_REF(click_on_target)) + commander.client?.mouse_override_icon = 'icons/effects/mouse_pointers/pet_paw.dmi' + commander.update_mouse_pointer() + +/datum/pet_command/proc/click_on_target(mob/living/source, atom/target, list/modifiers) + SIGNAL_HANDLER + if(!can_see(source, target, 9)) + return COMSIG_MOB_CANCEL_CLICKON + on_target_set(source, target) + UnregisterSignal(source, COMSIG_MOB_CLICKON) + source.client?.mouse_override_icon = source.client::mouse_override_icon + source.update_mouse_pointer() + var/manual_emote_text = generate_emote_command(target) + if(!isnull(manual_emote_text)) + INVOKE_ASYNC(source, TYPE_PROC_REF(/atom, manual_emote), manual_emote_text) + return COMSIG_MOB_CANCEL_CLICKON + +/datum/pet_command/proc/point_on_target(mob/living/friend, atom/potential_target) + SIGNAL_HANDLER + on_target_set(friend, potential_target) /// Store the target for the AI blackboard /datum/pet_command/proc/set_command_target(mob/living/parent, atom/target) @@ -158,11 +199,6 @@ var/datum/radial_menu_choice/choice = new() choice.name = command_name choice.image = icon(icon = radial_icon, icon_state = radial_icon_state) - var/tooltip = command_desc - if (length(speech_commands)) - tooltip += "<br>Speak this command with the words [speech_commands.Join(", ")]." - choice.info = tooltip - return list("[command_name]" = choice) /** @@ -174,34 +210,15 @@ SHOULD_CALL_PARENT(FALSE) CRASH("Pet command execute action not implemented.") -/** - * # Point Targeting Pet Command - * As above but also listens for you pointing at something and marks it as a target - */ -/datum/pet_command/point_targeting - /// Text describing an action we perform upon receiving a new target - var/pointed_reaction - /// Blackboard key for targeting strategy, this is likely going to need it - var/targeting_strategy_key = BB_PET_TARGETING_STRATEGY - -/datum/pet_command/point_targeting/add_new_friend(mob/living/tamer) - . = ..() - RegisterSignal(tamer, COMSIG_MOVABLE_POINTED, PROC_REF(on_point)) - -/datum/pet_command/point_targeting/remove_friend(mob/living/unfriended) - . = ..() - UnregisterSignal(unfriended, COMSIG_MOVABLE_POINTED) - /// Target the pointed atom for actions -/datum/pet_command/point_targeting/proc/on_point(mob/living/friend, atom/pointed_atom, obj/effect/temp_visual/point/point) - SIGNAL_HANDLER - +/datum/pet_command/proc/on_target_set(mob/living/friend, atom/potential_target) var/mob/living/parent = weak_parent.resolve() if (!parent) - return FALSE + return parent.ai_controller.CancelActions() - if (look_for_target(friend, pointed_atom) && set_command_target(parent, pointed_atom)) - parent.visible_message(span_warning("[parent] follows [friend]'s gesture towards [pointed_atom] [pointed_reaction]!")) - return TRUE - return FALSE + if(!look_for_target(friend, potential_target) || !set_command_target(parent, potential_target)) + return + parent.visible_message(span_warning("[parent] follows [friend]'s gesture towards [potential_target] [pointed_reaction]!")) + + diff --git a/code/datums/components/pet_commands/pet_commands_basic.dm b/code/datums/components/pet_commands/pet_commands_basic.dm index e37e8b79d41e7..21d771bd3e318 100644 --- a/code/datums/components/pet_commands/pet_commands_basic.dm +++ b/code/datums/components/pet_commands/pet_commands_basic.dm @@ -7,14 +7,16 @@ /datum/pet_command/idle command_name = "Stay" command_desc = "Command your pet to stay idle in this location." - radial_icon = 'icons/obj/bed.dmi' - radial_icon_state = "dogbed" + radial_icon_state = "halt" speech_commands = list("sit", "stay", "stop", "сидеть", "лежать", "место", "фу", "стоп", "стой", "стоять") command_feedback = "sits" /datum/pet_command/idle/execute_action(datum/ai_controller/controller) return SUBTREE_RETURN_FINISH_PLANNING // This cancels further AI planning +/datum/pet_command/idle/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to stay idle!" + /** * # Pet Command: Stop * Tells a pet to exit command mode and resume its normal behaviour, which includes regular target-seeking and what have you @@ -22,8 +24,7 @@ /datum/pet_command/free command_name = "Loose" command_desc = "Allow your pet to resume its natural behaviours." - radial_icon = 'icons/mob/actions/actions_spells.dmi' - radial_icon_state = "repulse" + radial_icon_state = "free" speech_commands = list("free", "loose", "гулять", "вон", "свобод", "брысь") command_feedback = "relaxes" @@ -31,6 +32,9 @@ controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return // Just move on to the next planning subtree. +/datum/pet_command/free/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to go free!" + /** * # Pet Command: Follow * Tells a pet to follow you until you tell it to do something else @@ -38,8 +42,7 @@ /datum/pet_command/follow command_name = "Follow" command_desc = "Command your pet to accompany you." - radial_icon = 'icons/testing/turf_analysis.dmi' - radial_icon_state = "red_arrow" + radial_icon_state = "follow" speech_commands = list("heel", "follow", "за мной", "след", "охран", "к ноге", "ко мне") callout_type = /datum/callout_option/move ///the behavior we use to follow @@ -49,6 +52,9 @@ . = ..() set_command_target(parent, commander) +/datum/pet_command/follow/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to follow!" + /datum/pet_command/follow/execute_action(datum/ai_controller/controller) controller.queue_behavior(follow_behavior, BB_CURRENT_PET_TARGET) return SUBTREE_RETURN_FINISH_PLANNING @@ -60,14 +66,16 @@ /datum/pet_command/play_dead command_name = "Play Dead" command_desc = "Play a macabre trick." - radial_icon = 'icons/mob/simple/pets.dmi' - radial_icon_state = "puppy_dead" + radial_icon_state = "play_dead" speech_commands = list("play dead", "притворись мертвым", "умри") // Don't get too creative here, people talk about dying pretty often /datum/pet_command/play_dead/execute_action(datum/ai_controller/controller) controller.queue_behavior(/datum/ai_behavior/play_dead) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/play_dead/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to play dead!" + /** * # Pet Command: Good Boy * React if complimented @@ -115,16 +123,18 @@ controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/untargeted_ability/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to use an ability!" + /** * # Pet Command: Attack * Tells a pet to chase and bite the next thing you point at */ -/datum/pet_command/point_targeting/attack +/datum/pet_command/attack command_name = "Attack" command_desc = "Command your pet to attack things that you point out to it." - radial_icon = 'icons/effects/effects.dmi' - radial_icon_state = "bite" - + radial_icon_state = "attack" + requires_pointing = TRUE callout_type = /datum/callout_option/attack speech_commands = list("attack", "sic", "kill", "апорт", "фас", "бить", "атак") command_feedback = "growl" @@ -135,7 +145,7 @@ var/attack_behaviour = /datum/ai_behavior/basic_melee_attack // Refuse to target things we can't target, chiefly other friends -/datum/pet_command/point_targeting/attack/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/attack/set_command_target(mob/living/parent, atom/target) if (!target) return var/mob/living/living_parent = parent @@ -149,28 +159,32 @@ return return ..() +/datum/pet_command/attack/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to attack [target]!" + /// Display feedback about not targeting something -/datum/pet_command/point_targeting/attack/proc/refuse_target(mob/living/parent, atom/target) +/datum/pet_command/attack/proc/refuse_target(mob/living/parent, atom/target) var/mob/living/living_parent = parent living_parent.balloon_alert_to_viewers("[refuse_reaction]") living_parent.visible_message(span_notice("[living_parent] refuses to attack [target].")) -/datum/pet_command/point_targeting/attack/execute_action(datum/ai_controller/controller) +/datum/pet_command/attack/execute_action(datum/ai_controller/controller) controller.queue_behavior(attack_behaviour, BB_CURRENT_PET_TARGET, targeting_strategy_key) return SUBTREE_RETURN_FINISH_PLANNING /** * # Breed command. breed with a partner! */ -/datum/pet_command/point_targeting/breed +/datum/pet_command/breed command_name = "Breed" command_desc = "Command your pet to attempt to breed with a partner." - radial_icon = 'icons/mob/simple/animal.dmi' - radial_icon_state = "heart" + requires_pointing = TRUE + radial_icon_state = "breed" speech_commands = list("breed", "consummate", "размножайся") + ///the behavior we use to make babies var/datum/ai_behavior/reproduce_behavior = /datum/ai_behavior/make_babies -/datum/pet_command/point_targeting/breed/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/breed/set_command_target(mob/living/parent, atom/target) if(isnull(target) || !isliving(target)) return if(!HAS_TRAIT(parent, TRAIT_MOB_BREEDER) || !HAS_TRAIT(target, TRAIT_MOB_BREEDER)) @@ -184,21 +198,25 @@ return return ..() -/datum/pet_command/point_targeting/breed/execute_action(datum/ai_controller/controller) +/datum/pet_command/breed/execute_action(datum/ai_controller/controller) if(is_type_in_list(controller.blackboard[BB_CURRENT_PET_TARGET], controller.blackboard[BB_BABIES_PARTNER_TYPES])) controller.queue_behavior(reproduce_behavior, BB_CURRENT_PET_TARGET) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/breed/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to breed with [target]!" + /** * # Pet Command: Targetted Ability * Tells a pet to use some kind of ability on the next thing you point at */ -/datum/pet_command/point_targeting/use_ability +/datum/pet_command/use_ability command_name = "Use ability" command_desc = "Command your pet to use one of its special skills on something that you point out to it." radial_icon = 'icons/mob/actions/actions_spells.dmi' radial_icon_state = "projectile" + requires_pointing = TRUE speech_commands = list("shoot", "blast", "cast", "стреля", "выстрел", "пиу", "паф", "каст") command_feedback = "growl" pointed_reaction = "and growls" @@ -207,7 +225,7 @@ /// The AI behavior to use for the ability var/ability_behavior = /datum/ai_behavior/pet_use_ability -/datum/pet_command/point_targeting/use_ability/execute_action(datum/ai_controller/controller) +/datum/pet_command/use_ability/execute_action(datum/ai_controller/controller) if (!pet_ability_key) return var/datum/action/cooldown/using_action = controller.blackboard[pet_ability_key] @@ -218,6 +236,9 @@ controller.queue_behavior(ability_behavior, pet_ability_key, BB_CURRENT_PET_TARGET) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/use_ability/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to use an ability on [target]!" + /datum/pet_command/protect_owner command_name = "Protect owner" command_desc = "Your pet will run to your aid." @@ -278,25 +299,39 @@ /** * # Fish command: command the mob to fish at the next fishing spot you point at. Requires the profound fisher component */ -/datum/pet_command/point_targeting/fish +/datum/pet_command/fish command_name = "Fish" command_desc = "Command your pet to try fishing at a nearby fishing spot." - radial_icon = 'icons/obj/aquarium/fish.dmi' - radial_icon_state = "goldfish" + requires_pointing = TRUE + radial_icon_state = "fish" speech_commands = list("fish") -// Refuse to target things we can't target, chiefly other friends -/datum/pet_command/point_targeting/fish/set_command_target(mob/living/parent, atom/target) - if (!target) - return - if(!parent.ai_controller || !HAS_TRAIT(parent, TRAIT_PROFOUND_FISHER)) - return - var/datum/targeting_strategy/targeter = GET_TARGETING_STRATEGY(/datum/targeting_strategy/fishing) - if (!targeter?.can_attack(parent, target)) - parent.balloon_alert_to_viewers("shakes head!") - return +/datum/pet_command/fish/execute_action(datum/ai_controller/controller) + if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET)) + controller.queue_behavior(/datum/ai_behavior/interact_with_target/fishing, BB_CURRENT_PET_TARGET) + return SUBTREE_RETURN_FINISH_PLANNING + +/datum/pet_command/fish/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to go fish!" + +/datum/pet_command/move + command_name = "Move" + command_desc = "Command your pet to move to a location!" + requires_pointing = TRUE + radial_icon_state = "move" + speech_commands = list("move", "walk") + ///the behavior we use to walk towards targets + var/datum/ai_behavior/walk_behavior = /datum/ai_behavior/travel_towards + +/datum/pet_command/move/set_command_target(mob/living/parent, atom/target) + if(isnull(target) || !can_see(parent, target, 9)) + return FALSE return ..() -/datum/pet_command/point_targeting/fish/execute_action(datum/ai_controller/controller) - controller.queue_behavior(/datum/ai_behavior/hunt_target/interact_with_target/reset_target_combat_mode_off, BB_CURRENT_PET_TARGET) +/datum/pet_command/move/execute_action(datum/ai_controller/controller) + if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET)) + controller.queue_behavior(walk_behavior, BB_CURRENT_PET_TARGET) return SUBTREE_RETURN_FINISH_PLANNING + +/datum/pet_command/move/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to move!" diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm index a1be66654a2c0..ed916c29edf94 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -121,6 +121,8 @@ ///returns TRUE when they can give the specified amount and reagent. called by process request /datum/component/plumbing/proc/can_give(amount, reagent, datum/ductnet/net) + SHOULD_BE_PURE(TRUE) + if(amount <= 0) return diff --git a/code/datums/components/plumbing/reaction_chamber.dm b/code/datums/components/plumbing/reaction_chamber.dm index d0aff2f50708c..4f2acf4710a7e 100644 --- a/code/datums/components/plumbing/reaction_chamber.dm +++ b/code/datums/components/plumbing/reaction_chamber.dm @@ -8,20 +8,25 @@ return COMPONENT_INCOMPATIBLE /datum/component/plumbing/reaction_chamber/can_give(amount, reagent, datum/ductnet/net) - . = ..() var/obj/machinery/plumbing/reaction_chamber/reaction_chamber = parent - if(!. || !reaction_chamber.emptying || reagents.is_reacting) + + //cannot give when we outselves are requesting or reacting the reagents + if(!reaction_chamber.emptying || reagents.is_reacting) return FALSE + return ..() + /datum/component/plumbing/reaction_chamber/send_request(dir) var/obj/machinery/plumbing/reaction_chamber/chamber = parent + if(chamber.emptying) return //take in reagents var/present_amount var/diff - for(var/required_reagent in chamber.required_reagents) + var/list/datum/reagent/required_reagents = chamber.catalysts | chamber.required_reagents + for(var/datum/reagent/required_reagent as anything in required_reagents) //find how much amount is already present if at all and get the reagent reference present_amount = 0 for(var/datum/reagent/present_reagent as anything in reagents.reagent_list) @@ -30,10 +35,11 @@ break //compute how much more is needed - diff = min(chamber.required_reagents[required_reagent] - present_amount, MACHINE_REAGENT_TRANSFER) + diff = min(required_reagents[required_reagent] - present_amount, MACHINE_REAGENT_TRANSFER) if(diff >= CHEMICAL_QUANTISATION_LEVEL) // the closest we can ask for so values like 0.9999 become 1 process_request(diff, required_reagent, dir) - return + if(!chamber.catalysts[required_reagent]) //only block if not a catalyst as they can come in whenever they are available + return reagents.flags &= ~NO_REACT reagents.handle_reactions() diff --git a/code/datums/components/trader/trader.dm b/code/datums/components/trader/trader.dm index d623a9943b893..3b2675785aec3 100644 --- a/code/datums/components/trader/trader.dm +++ b/code/datums/components/trader/trader.dm @@ -394,7 +394,7 @@ Can accept both a type path, and an instance of a datum. Type path has priority. else buy_info += span_notice("• [initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [trader_data.currency_name][product_info[TRADER_PRODUCT_INFO_PRICE_MOD_DESCRIPTION]]; willing to buy [span_green("[tern_op_result]")]") - to_chat(customer, examine_block(buy_info.Join("\n"))) + to_chat(customer, boxed_message(buy_info.Join("\n"))) ///Displays to the customer what the trader is selling and how much is in stock /datum/component/trader/proc/trader_sells_what(mob/customer) @@ -413,7 +413,7 @@ Can accept both a type path, and an instance of a datum. Type path has priority. sell_info += span_notice("• [span_red("(OUT OF STOCK)")] [initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [trader_data.currency_name]; [span_red("[tern_op_result]")] left in stock") else sell_info += span_notice("• [initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [trader_data.currency_name]; [span_green("[tern_op_result]")] left in stock") - to_chat(customer, examine_block(sell_info.Join("\n"))) + to_chat(customer, boxed_message(sell_info.Join("\n"))) ///Sets quantity of all products to initial(quanity); this proc is currently called during initialize /datum/component/trader/proc/restock_products() diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm index 75caa272ef9bd..4be983b32113c 100644 --- a/code/datums/elements/basic_eating.dm +++ b/code/datums/elements/basic_eating.dm @@ -46,8 +46,10 @@ SIGNAL_HANDLER if(user.combat_mode || !is_type_in_list(possible_food, food_types)) return NONE - - try_eating(source, possible_food, user) + var/mob/living/living_source = source + if(living_source.stat != CONSCIOUS) + return NONE + return try_eating(source, possible_food, user) ? ITEM_INTERACT_SUCCESS : NONE /datum/element/basic_eating/proc/on_unarm_attack(mob/living/eater, atom/target, proximity, modifiers) SIGNAL_HANDLER diff --git a/code/datums/elements/leeching_walk.dm b/code/datums/elements/leeching_walk.dm index c9f547189e699..f5148b43a5a52 100644 --- a/code/datums/elements/leeching_walk.dm +++ b/code/datums/elements/leeching_walk.dm @@ -24,9 +24,8 @@ var/turf/mover_turf = get_turf(source) if(HAS_TRAIT(mover_turf, TRAIT_RUSTY)) ADD_TRAIT(source, TRAIT_BATON_RESISTANCE, type) - return - - REMOVE_TRAIT(source, TRAIT_BATON_RESISTANCE, type) + else + REMOVE_TRAIT(source, TRAIT_BATON_RESISTANCE, type) /** * Signal proc for [COMSIG_LIVING_LIFE]. @@ -43,17 +42,18 @@ // Heals all damage + Stamina var/need_mob_update = FALSE - need_mob_update += source.adjustBruteLoss(-3, updating_health = FALSE) - need_mob_update += source.adjustFireLoss(-3, updating_health = FALSE) - need_mob_update += source.adjustToxLoss(-3, updating_health = FALSE, forced = TRUE) // Slimes are people to - need_mob_update += source.adjustOxyLoss(-1.5, updating_health = FALSE) - need_mob_update += source.adjustStaminaLoss(-10, updating_stamina = FALSE) + var/delta_time = DELTA_WORLD_TIME(SSmobs) * 0.5 // SSmobs.wait is 2 secs, so this should be halved. + need_mob_update += source.adjustBruteLoss(-3 * delta_time, updating_health = FALSE) + need_mob_update += source.adjustFireLoss(-3 * delta_time, updating_health = FALSE) + need_mob_update += source.adjustToxLoss(-3 * delta_time, updating_health = FALSE, forced = TRUE) // Slimes are people too + need_mob_update += source.adjustOxyLoss(-1.5 * delta_time, updating_health = FALSE) + need_mob_update += source.adjustStaminaLoss(-10 * delta_time, updating_stamina = FALSE) if(need_mob_update) source.updatehealth() // Reduces duration of stuns/etc - source.AdjustAllImmobility(-0.5 SECONDS) + source.AdjustAllImmobility((-0.5 SECONDS) * delta_time) // Heals blood loss if(source.blood_volume < BLOOD_VOLUME_NORMAL) - source.blood_volume += 2.5 * seconds_per_tick + source.blood_volume += 2.5 * delta_time // Slowly regulates your body temp - source.adjust_bodytemperature((source.get_body_temp_normal() - source.bodytemperature)/5) + source.adjust_bodytemperature((source.get_body_temp_normal() - source.bodytemperature) / 5) diff --git a/code/datums/elements/nav_computer_icon.dm b/code/datums/elements/nav_computer_icon.dm new file mode 100644 index 0000000000000..4e9b6a3a18893 --- /dev/null +++ b/code/datums/elements/nav_computer_icon.dm @@ -0,0 +1,44 @@ +/** + * element for atoms that have helper icons overlayed on their position in the shuttle navigation computer, such as airlocks + */ +/datum/element/nav_computer_icon + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + var/use_icon + var/use_icon_state + var/only_show_on_shuttle_edge + +/datum/element/nav_computer_icon/Attach(datum/target, use_icon, use_icon_state, only_show_on_shuttle_edge) + . = ..() + if(!isatom(target)) + return ELEMENT_INCOMPATIBLE + + src.use_icon = use_icon + src.use_icon_state = use_icon_state + src.only_show_on_shuttle_edge = only_show_on_shuttle_edge + + RegisterSignal(target, COMSIG_SHUTTLE_NAV_COMPUTER_IMAGE_REQUESTED, PROC_REF(provide_image)) + +/datum/element/nav_computer_icon/proc/provide_image(datum/source, list/images_out) + SIGNAL_HANDLER + var/obj/source_obj = source + var/turf/source_turf = get_turf(source_obj) + if(!source_turf) + return + if(only_show_on_shuttle_edge) + var/isOnEdge = FALSE + for(var/direction in GLOB.cardinals) + var/turf/turf = get_step(source_obj, direction) + if(!istype(turf?.loc, /area/shuttle)) + isOnEdge = TRUE + break + if(!isOnEdge) + return + + var/image/the_image = image(use_icon, source_turf, use_icon_state) + the_image.dir = source_obj.dir + images_out += the_image + +/datum/element/nav_computer_icon/Detach(datum/source) + . = ..() + UnregisterSignal(source, COMSIG_SHUTTLE_NAV_COMPUTER_IMAGE_REQUESTED) diff --git a/code/datums/elements/pet_cult.dm b/code/datums/elements/pet_cult.dm index 36941e7b74299..f26e6e343e666 100644 --- a/code/datums/elements/pet_cult.dm +++ b/code/datums/elements/pet_cult.dm @@ -90,7 +90,8 @@ source.ai_controller.set_blackboard_key(BB_CULT_TEAM, team) var/static/list/new_pet_commands = list( - /datum/pet_command/point_targeting/attack, + /datum/pet_command/move, + /datum/pet_command/attack, /datum/pet_command/follow, /datum/pet_command/free, /datum/pet_command/idle, diff --git a/code/datums/elements/slapcrafting.dm b/code/datums/elements/slapcrafting.dm index 11c96fa2611e0..df95087b165c8 100644 --- a/code/datums/elements/slapcrafting.dm +++ b/code/datums/elements/slapcrafting.dm @@ -134,7 +134,7 @@ for(var/datum/crafting_recipe/recipe as anything in slapcraft_recipes) var/atom/result = initial(recipe.result) - examine_list += "<a href='?src=[REF(source)];check_recipe=[REF(recipe)]'>Узнать рецепт для [declent_ru_initial(result::name, GENITIVE, result::name)]</a>" + examine_list += "<a href='byond://?src=[REF(source)];check_recipe=[REF(recipe)]'>Узнать рецепт для [declent_ru_initial(result::name, GENITIVE, result::name)]</a>" /datum/element/slapcrafting/proc/topic_handler(atom/source, user, href_list) SIGNAL_HANDLER @@ -180,7 +180,7 @@ // If we did find ingredients then add them onto the list. if(length(string_ingredient_list)) to_chat(user, span_boldnotice("Дополнительные ингредиенты:")) - to_chat(user, examine_block(span_notice(string_ingredient_list))) + to_chat(user, boxed_message(span_notice(string_ingredient_list))) var/list/tool_list = "" @@ -194,7 +194,7 @@ if(length(tool_list)) to_chat(user, span_boldnotice("Необходимые инструменты:")) - to_chat(user, examine_block(span_notice(tool_list))) + to_chat(user, boxed_message(span_notice(tool_list))) qdel(cur_recipe) diff --git a/code/datums/elements/weapon_description.dm b/code/datums/elements/weapon_description.dm index d42554317d656..88d1379c9e8e8 100644 --- a/code/datums/elements/weapon_description.dm +++ b/code/datums/elements/weapon_description.dm @@ -39,7 +39,7 @@ SIGNAL_HANDLER if(item.force >= 5 || item.throwforce >= 5 || item.override_notes || item.offensive_notes || attached_proc) /// Only show this tag for items that could feasibly be weapons, shields, or those that have special notes - examine_texts += span_notice("<a href='?src=[REF(item)];examine=1'>Боевые характеристики.</a>") + examine_texts += span_notice("<a href='byond://?src=[REF(item)];examine=1'>Боевые характеристики.</a>") /** * @@ -57,7 +57,7 @@ SIGNAL_HANDLER if(href_list["examine"]) - to_chat(user, span_notice(examine_block("[build_label_text(source)]"))) + to_chat(user, span_notice(boxed_message("[build_label_text(source)]"))) /** * diff --git a/code/datums/keybinding/_keybindings.dm b/code/datums/keybinding/_keybindings.dm index dfcf492c1809f..a989d0d22a881 100644 --- a/code/datums/keybinding/_keybindings.dm +++ b/code/datums/keybinding/_keybindings.dm @@ -21,6 +21,8 @@ return SEND_SIGNAL(user.mob, keybind_signal) & COMSIG_KB_ACTIVATED /datum/keybinding/proc/up(client/user) + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(user.mob, DEACTIVATE_KEYBIND(keybind_signal)) return FALSE /datum/keybinding/proc/can_use(client/user) diff --git a/code/datums/keybinding/living.dm b/code/datums/keybinding/living.dm index 7e50e6928f9dd..61716ee6fe95a 100644 --- a/code/datums/keybinding/living.dm +++ b/code/datums/keybinding/living.dm @@ -46,6 +46,7 @@ return TRUE /datum/keybinding/living/look_up/up(client/user) + . = ..() var/mob/living/L = user.mob L.end_look_up() return TRUE @@ -66,6 +67,7 @@ return TRUE /datum/keybinding/living/look_down/up(client/user) + . = ..() var/mob/living/L = user.mob L.end_look_down() return TRUE @@ -144,6 +146,7 @@ return TRUE /datum/keybinding/living/toggle_move_intent/up(client/user) + . = ..() var/mob/living/M = user.mob M.toggle_move_intent() return TRUE diff --git a/code/datums/keybinding/mob.dm b/code/datums/keybinding/mob.dm index 881271c722229..b6f09d7fcc01b 100644 --- a/code/datums/keybinding/mob.dm +++ b/code/datums/keybinding/mob.dm @@ -191,3 +191,10 @@ if(.) return user.movement_locked = FALSE + +/datum/keybinding/living/view_pet_data + hotkey_keys = list("Shift") + name = "view_pet_commands" + full_name = "View Pet Commands" + description = "Hold down to see all the commands you can give your pets!" + keybind_signal = COMSIG_KB_LIVING_VIEW_PET_COMMANDS diff --git a/code/datums/mind/skills.dm b/code/datums/mind/skills.dm index 474291d5ae0d4..80a78c3d950f2 100644 --- a/code/datums/mind/skills.dm +++ b/code/datums/mind/skills.dm @@ -75,4 +75,4 @@ var/datum/skill/the_skill = i msg += "[initial(the_skill.name)] - [get_skill_level_name(the_skill)]\n" msg += "</span>" - to_chat(user, examine_block(msg)) + to_chat(user, boxed_message(msg)) diff --git a/code/datums/mood.dm b/code/datums/mood.dm index cb6803e85dfd6..0645675553219 100644 --- a/code/datums/mood.dm +++ b/code/datums/mood.dm @@ -389,7 +389,7 @@ msg += span_boldnicegreen(event.description + "\n") else msg += "[span_grey("Сейчас у меня нет особой реакции на что-либо.")]\n" - to_chat(user, examine_block(msg)) + to_chat(user, boxed_message(msg)) /// Updates the mob's moodies, if the area provides a mood bonus /datum/mood/proc/check_area_mood(datum/source, area/new_area) diff --git a/code/datums/status_effects/debuffs/terrified.dm b/code/datums/status_effects/debuffs/terrified.dm index 61a6ecd4eda3b..61c4abcea3bf4 100644 --- a/code/datums/status_effects/debuffs/terrified.dm +++ b/code/datums/status_effects/debuffs/terrified.dm @@ -96,6 +96,9 @@ /datum/status_effect/terrified/proc/comfort_owner(datum/source, mob/living/hugger) SIGNAL_HANDLER + if(hugger == owner) + return + if(isnightmare(hugger)) //hey wait a minute, that's not a comforting, friendly hug! if(check_surrounding_darkness()) addtimer(CALLBACK(src, PROC_REF(freak_out), HUG_TERROR_AMOUNT)) diff --git a/code/datums/votes/_vote_datum.dm b/code/datums/votes/_vote_datum.dm index 76833f73ff5b0..957160dea7d3e 100644 --- a/code/datums/votes/_vote_datum.dm +++ b/code/datums/votes/_vote_datum.dm @@ -170,13 +170,14 @@ * Return a formatted string of text to be displayed to everyone. */ /datum/vote/proc/get_result_text(list/all_winners, real_winner, list/non_voters) + var/title_text = "" var/returned_text = "" if(override_question) - returned_text += span_bold(override_question) + title_text += span_bold(override_question) else - returned_text += span_bold("[capitalize(name)] Vote") + title_text += span_bold("[capitalize(name)] Vote") - returned_text += "\nWinner Selection: " + returned_text += "Winner Selection: " switch(winner_method) if(VOTE_WINNER_METHOD_NONE) returned_text += "None" @@ -215,7 +216,7 @@ returned_text += "\n" returned_text += get_winner_text(all_winners, real_winner, non_voters) - return returned_text + return fieldset_block(title_text, returned_text, "boxed_message purple_box") /** * Gets the text that displays the winning options within the result text. diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm index 2a4af3a781aa0..c34c018d59c65 100644 --- a/code/datums/world_topic.dm +++ b/code/datums/world_topic.dm @@ -114,7 +114,7 @@ var/message = "<b color='orange'>CROSS-SECTOR MESSAGE (INCOMING):</b> [input["sender_ckey"]] (from [input["source"]]) is about to send \ the following message (will autoapprove in [soft_filter_passed ? "[extended_time_display]" : "[normal_time_display]"]): \ - <b><a href='?src=[REF(src)];reject_cross_comms_message=[timer_id]'>REJECT</a></b><br><br>\ + <b><a href='byond://?src=[REF(src)];reject_cross_comms_message=[timer_id]'>REJECT</a></b><br><br>\ [html_encode(input["message"])]" if(soft_filter_passed) diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index 77e14a0637d7b..396526ab559a8 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -865,6 +865,8 @@ if (isnull(user)) return + SEND_SIGNAL(user, COMSIG_ATOM_MOUSE_ENTERED, src) + // Screentips var/datum/hud/active_hud = user.hud_used if(!active_hud) diff --git a/code/game/atom/atom_vv.dm b/code/game/atom/atom_vv.dm index 7a7dc8d3a877d..14a8b41e6e10e 100644 --- a/code/game/atom/atom_vv.dm +++ b/code/game/atom/atom_vv.dm @@ -199,7 +199,7 @@ . = ..() var/refid = REF(src) . += "[VV_HREF_TARGETREF(refid, VV_HK_AUTO_RENAME, "<b id='name'>[src]</b>")]" - . += "<br><font size='1'><a href='?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=left'><<</a> <a href='?_src_=vars;[HrefToken()];datumedit=[refid];varnameedit=dir' id='dir'>[dir2text(dir) || dir]</a> <a href='?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=right'>>></a></font>" + . += "<br><font size='1'><a href='byond://?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=left'><<</a> <a href='byond://?_src_=vars;[HrefToken()];datumedit=[refid];varnameedit=dir' id='dir'>[dir2text(dir) || dir]</a> <a href='byond://?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=right'>>></a></font>" /** * call back when a var is edited on this atom diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 84596a16783aa..b66a534478154 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1137,7 +1137,6 @@ pulledby.stop_pulling() var/same_loc = oldloc == destination - var/movement_successful = TRUE var/area/old_area = get_area(oldloc) var/area/destarea = get_area(destination) var/movement_dir = get_dir(src, destination) @@ -1146,13 +1145,13 @@ loc = destination - if(!same_loc && loc == oldloc) - // when attempting to move an atom A into an atom B which already contains A, BYOND seems - // to silently refuse to move A to the new loc. This can really break stuff (see #77067) - stack_trace("Attempt to move [src] to [destination] was rejected by BYOND, possibly due to cyclic contents") - movement_successful = FALSE + if(!same_loc) + if(loc == oldloc) + // when attempting to move an atom A into an atom B which already contains A, BYOND seems + // to silently refuse to move A to the new loc. This can really break stuff (see #77067) + stack_trace("Attempt to move [src] to [destination] was rejected by BYOND, possibly due to cyclic contents") + return FALSE - if(movement_successful && !same_loc) if(is_multi_tile && isturf(destination)) var/list/new_locs = block( destination, @@ -1181,7 +1180,7 @@ if(destarea && old_area != destarea) destarea.Entered(src, old_area) - . = movement_successful + . = TRUE //If no destination, move the atom into nullspace (don't do this unless you know what you're doing) else diff --git a/code/game/machinery/big_manipulator.dm b/code/game/machinery/big_manipulator.dm index 21a7de89fe619..a14a6b8531174 100644 --- a/code/game/machinery/big_manipulator.dm +++ b/code/game/machinery/big_manipulator.dm @@ -288,7 +288,12 @@ target.forceMove(drop_turf) target.dir = get_dir(get_turf(target), get_turf(src)) else - target.forceMove(where_we_drop) + var/atom/drop_target = where_we_drop + if(drop_target.atom_storage) + if(!drop_target.atom_storage.attempt_insert(target, override = TRUE, messages = FALSE)) + target.forceMove(drop_target.drop_location()) + else + target.forceMove(where_we_drop) finish_manipulation() /// 3.3 take and drop proc from [take and drop procs loop]: diff --git a/code/game/machinery/camera/camera_construction.dm b/code/game/machinery/camera/camera_construction.dm index b3593aad6e7e2..19d7d2a39567b 100644 --- a/code/game/machinery/camera/camera_construction.dm +++ b/code/game/machinery/camera/camera_construction.dm @@ -189,9 +189,9 @@ ai.last_tablet_note_seen = "<HTML><HEAD><TITLE>[itemname]</TITLE></HEAD><BODY><TT>[info]</TT></BODY></HTML>" if(user.name == "Unknown") - to_chat(ai, "[span_name(user)] holds <a href='?_src_=usr;show_tablet=1;'>\a [itemname]</a> up to one of your cameras ...") + to_chat(ai, "[span_name(user)] holds <a href='byond://?_src_=usr;show_tablet=1;'>\a [itemname]</a> up to one of your cameras ...") else - to_chat(ai, "<b><a href='?src=[REF(ai)];track=[html_encode(user.name)]'>[user]</a></b> holds <a href='?_src_=usr;last_shown_paper=1;'>\a [itemname]</a> up to one of your cameras ...") + to_chat(ai, "<b><a href='byond://?src=[REF(ai)];track=[html_encode(user.name)]'>[user]</a></b> holds <a href='byond://?_src_=usr;last_shown_paper=1;'>\a [itemname]</a> up to one of your cameras ...") continue if (potential_viewer.client?.eye == src) @@ -232,16 +232,16 @@ log_paper("[key_name(user)] held [last_shown_paper] up to [src], requesting [key_name(ai)] read it.") if(user.name == "Unknown") - to_chat(ai, "[span_name(user.name)] holds <a href='?_src_=usr;show_paper_note=[REF(last_shown_paper)];'>\a [item_name]</a> up to one of your cameras ...") + to_chat(ai, "[span_name(user.name)] holds <a href='byond://?_src_=usr;show_paper_note=[REF(last_shown_paper)];'>\a [item_name]</a> up to one of your cameras ...") else - to_chat(ai, "<b><a href='?src=[REF(ai)];track=[html_encode(user.name)]'>[user]</a></b> holds <a href='?_src_=usr;show_paper_note=[REF(last_shown_paper)];'>\a [item_name]</a> up to one of your cameras ...") + to_chat(ai, "<b><a href='byond://?src=[REF(ai)];track=[html_encode(user.name)]'>[user]</a></b> holds <a href='byond://?_src_=usr;show_paper_note=[REF(last_shown_paper)];'>\a [item_name]</a> up to one of your cameras ...") continue // If it's not an AI, eye if the client's eye is set to the camera. I wonder if this even works anymore with tgui camera apps and stuff? if (potential_viewer.client?.eye == src) log_paper("[key_name(user)] held [last_shown_paper] up to [src], and [key_name(potential_viewer)] may read it.") potential_viewer.log_talk(item_name, LOG_VICTIM, tag="Pressed to camera from [key_name(user)]", log_globally=FALSE) - to_chat(potential_viewer, "[span_name(user)] holds <a href='?_src_=usr;show_paper_note=[REF(last_shown_paper)];'>\a [item_name]</a> up to your camera...") + to_chat(potential_viewer, "[span_name(user)] holds <a href='byond://?_src_=usr;show_paper_note=[REF(last_shown_paper)];'>\a [item_name]</a> up to your camera...") return return ..() diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index eb48792a523bc..d51e197a0bcdd 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -19,6 +19,8 @@ var/time_to_unscrew = 2 SECONDS /// Are we authenticated to use this? Used by things like comms console, security and medical data, and apc controller. var/authenticated = FALSE + /// Will projectiles be able to pass over this computer? + var/projectiles_pass_chance = 65 /datum/armor/machinery_computer fire = 40 @@ -28,6 +30,23 @@ . = ..() power_change() +/obj/machinery/computer/CanAllowThrough(atom/movable/mover, border_dir) // allows projectiles to fly over the computer + . = ..() + if(.) + return + if(!projectiles_pass_chance) + return FALSE + if(!isprojectile(mover)) + return FALSE + var/obj/projectile/proj = mover + if(!anchored) + return TRUE + if(proj.firer && Adjacent(proj.firer)) + return TRUE + if(prob(projectiles_pass_chance)) + return TRUE + return FALSE + /obj/machinery/computer/process() if(machine_stat & (NOPOWER|BROKEN)) return FALSE diff --git a/code/game/machinery/computer/arcade/_arcade.dm b/code/game/machinery/computer/arcade/_arcade.dm index eb91fa44f1c70..1627a3d0fe81b 100644 --- a/code/game/machinery/computer/arcade/_arcade.dm +++ b/code/game/machinery/computer/arcade/_arcade.dm @@ -7,6 +7,7 @@ icon_screen = "invaders" light_color = LIGHT_COLOR_GREEN interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_REQUIRES_LITERACY + projectiles_pass_chance = 0 // I guess gambling can save your life huh? ///If set, will dispense these as prizes instead of the default GLOB.arcade_prize_pool ///Like prize pool, it must be a list of the prize and the weight of being selected. diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 599d0930b7bb7..e2995f6cabe25 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -346,7 +346,7 @@ span_adminnotice( \ "<b color='orange'>CROSS-SECTOR MESSAGE (OUTGOING):</b> [ADMIN_LOOKUPFLW(user)] is about to send \ the following message to <b>[destination]</b> (will autoapprove in [GLOB.communications_controller.soft_filtering ? DisplayTimeText(EXTENDED_CROSS_SECTOR_CANCEL_TIME) : DisplayTimeText(CROSS_SECTOR_CANCEL_TIME)]): \ - <b><a href='?src=[REF(src)];reject_cross_comms_message=1'>REJECT</a></b><br> \ + <b><a href='byond://?src=[REF(src)];reject_cross_comms_message=1'>REJECT</a></b><br> \ [html_encode(message)]" \ ) ) diff --git a/code/game/machinery/computer/records/medical.dm b/code/game/machinery/computer/records/medical.dm index 6dd12acbdb678..c5f11ec89ca7c 100644 --- a/code/game/machinery/computer/records/medical.dm +++ b/code/game/machinery/computer/records/medical.dm @@ -18,6 +18,7 @@ icon_screen = "medlaptop" icon_keyboard = "laptop_key" pass_flags = PASSTABLE + projectiles_pass_chance = 100 /obj/machinery/computer/records/medical/attacked_by(obj/item/attacking_item, mob/living/user) . = ..() diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm index 3897d017cfaf3..fbd60018bd5f5 100644 --- a/code/game/machinery/computer/records/security.dm +++ b/code/game/machinery/computer/records/security.dm @@ -27,6 +27,7 @@ icon_screen = "seclaptop" icon_keyboard = "laptop_key" pass_flags = PASSTABLE + projectiles_pass_chance = 100 /obj/machinery/computer/records/security/laptop/syndie desc = "A cheap, jailbroken security laptop. It functions as a security records console. It's bolted to the table." diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 12aa1c3ce0362..228391e6bdeec 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -176,7 +176,7 @@ if(!isnull(console_location)) to_chat(R, span_alert("The approximate location of the console that is keeping you locked down is [console_location]")) if(R.connected_ai) - to_chat(R.connected_ai, "[!R.lockcharge ? span_notice("NOTICE - Cyborg lockdown lifted") : span_alert("ALERT - Cyborg lockdown detected")]: <a href='?src=[REF(R.connected_ai)];track=[html_encode(R.name)]'>[R.name]</a><br>") + to_chat(R.connected_ai, "[!R.lockcharge ? span_notice("NOTICE - Cyborg lockdown lifted") : span_alert("ALERT - Cyborg lockdown detected")]: <a href='byond://?src=[REF(R.connected_ai)];track=[html_encode(R.name)]'>[R.name]</a><br>") /obj/machinery/computer/robotics/proc/borg_destroyed() SIGNAL_HANDLER diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm index 8cd12610c748b..74e6d22e36355 100644 --- a/code/game/machinery/computer/teleporter.dm +++ b/code/game/machinery/computer/teleporter.dm @@ -116,7 +116,7 @@ say("Processing hub calibration to target...") calibrating = TRUE power_station.update_appearance() - addtimer(CALLBACK(src, PROC_REF(finish_calibration)), 50 * (3 - power_station.teleporter_hub.accuracy)) //Better parts mean faster calibration + addtimer(CALLBACK(src, PROC_REF(finish_calibration)), 5 SECONDS * (3 - power_station.teleporter_hub.accuracy)) //Better parts mean faster calibration return TRUE /obj/machinery/computer/teleporter/proc/set_teleport_target(new_target) diff --git a/code/game/machinery/computer/telescreen.dm b/code/game/machinery/computer/telescreen.dm index f3a6a9879b4d1..3b96ae111fba3 100644 --- a/code/game/machinery/computer/telescreen.dm +++ b/code/game/machinery/computer/telescreen.dm @@ -12,6 +12,7 @@ light_power = 0 /// The kind of wallframe that this telescreen drops var/frame_type = /obj/item/wallframe/telescreen + projectiles_pass_chance = 100 /obj/item/wallframe/telescreen name = "telescreen frame" diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index b90302111ab7b..0a41adcac98f2 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -22,6 +22,11 @@ if(circuit) . += "It has \a [circuit] installed." +/obj/structure/frame/CanAllowThrough(atom/movable/mover, border_dir) + if(isprojectile(mover)) + return TRUE + return ..() + /obj/structure/frame/atom_deconstruct(disassembled = TRUE) var/atom/movable/drop_loc = drop_location() new /obj/item/stack/sheet/iron(drop_loc, 5) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 1be4325638d37..c3657c6cac391 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -181,6 +181,8 @@ // Click on the floor to close airlocks AddComponent(/datum/component/redirect_attack_hand_from_turf) + AddElement(/datum/element/nav_computer_icon, 'icons/effects/nav_computer_indicators.dmi', "airlock", TRUE) + RegisterSignal(src, COMSIG_MACHINERY_BROKEN, PROC_REF(on_break)) RegisterSignal(SSdcs, COMSIG_GLOB_GREY_TIDE, PROC_REF(grey_tide)) diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm index 05816b0eb3d80..e623f162183a9 100644 --- a/code/game/machinery/doors/poddoor.dm +++ b/code/game/machinery/doors/poddoor.dm @@ -22,6 +22,12 @@ var/id = 1 /// The sound that plays when the door opens/closes var/animation_sound = 'sound/machines/blastdoor.ogg' + var/show_nav_computer_icon = TRUE + +/obj/machinery/door/poddoor/Initialize(mapload) + . = ..() + if(show_nav_computer_icon) + AddElement(/datum/element/nav_computer_icon, 'icons/effects/nav_computer_indicators.dmi', "airlock", TRUE) /datum/armor/door_poddoor melee = 50 diff --git a/code/game/machinery/doors/shutters.dm b/code/game/machinery/doors/shutters.dm index 56e2f5a9743b2..52c12835c2797 100644 --- a/code/game/machinery/doors/shutters.dm +++ b/code/game/machinery/doors/shutters.dm @@ -10,6 +10,7 @@ max_integrity = 100 recipe_type = /datum/crafting_recipe/shutters animation_sound = 'sound/machines/shutter.ogg' + show_nav_computer_icon = FALSE /obj/machinery/door/poddoor/shutters/animation_length(animation) switch(animation) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 186dfa9f31f9c..76653c43ddf96 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -327,7 +327,7 @@ Possible to do for anyone motivated enough: for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs) if(!AI.client) continue - to_chat(AI, span_info("Your presence is requested at <a href='?src=[REF(AI)];jump_to_holopad=[REF(src)]'>\the [area]</a>. <a href='?src=[REF(AI)];project_to_holopad=[REF(src)]'>Project Hologram?</a>")) + to_chat(AI, span_info("Your presence is requested at <a href='byond://?src=[REF(AI)];jump_to_holopad=[REF(src)]'>\the [area]</a>. <a href='byond://?src=[REF(AI)];project_to_holopad=[REF(src)]'>Project Hologram?</a>")) return TRUE else to_chat(usr, span_info("A request for AI presence was already sent recently.")) diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index d1f785f9b53d5..796ee58984565 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -762,6 +762,7 @@ DEFINE_BITFIELD(turret_flags, list( /obj/machinery/porta_turret/syndicate/Initialize(mapload) . = ..() AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES) + AddElement(/datum/element/nav_computer_icon, 'icons/effects/nav_computer_indicators.dmi', "turret", FALSE) /obj/machinery/porta_turret/syndicate/setup() return diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm index 49f00741895fe..3e3fc5af30757 100644 --- a/code/game/machinery/stasis.dm +++ b/code/game/machinery/stasis.dm @@ -14,6 +14,9 @@ fair_market_price = 10 payment_department = ACCOUNT_MED interaction_flags_click = ALLOW_SILICON_REACH + use_power = IDLE_POWER_USE + idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 3 + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 3 var/stasis_enabled = TRUE var/last_stasis_sound = FALSE var/stasis_can_toggle = 0 @@ -25,6 +28,20 @@ AddElement(/datum/element/elevation, pixel_shift = 6) update_buckle_vars(dir) +/obj/machinery/stasis/RefreshParts() + . = ..() + + var/energy_rating = 0 + for(var/datum/stock_part/part in component_parts) + energy_rating += part.energy_rating() + + for(var/obj/item/stock_parts/part in component_parts) + energy_rating += part.energy_rating + + idle_power_usage = initial(idle_power_usage) / (energy_rating/2) + active_power_usage = initial(active_power_usage) / (energy_rating/2) + update_current_power_usage() + /obj/machinery/stasis/examine(mob/user) . = ..() . += span_notice("Alt-click to [stasis_enabled ? "turn off" : "turn on"] the machine.") diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index c46f6b351543d..262e014ee0b79 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -33,7 +33,7 @@ /obj/machinery/teleport/hub/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) - . += span_notice("The status display reads: Probability of malfunction decreased by <b>[(accuracy*25)-25]%</b>.") + . += span_notice("The status display reads: Success chance is <b>[70 + (accuracy * 10)]%</b>.") /obj/machinery/teleport/hub/proc/link_power_station() if(power_station) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 8f65c540aa847..6b098e90e421f 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -2042,9 +2042,9 @@ . = ..() . += {" <br><font size='1'> - DAMTYPE: <font size='1'><a href='?_src_=vars;[HrefToken()];item_to_tweak=[REF(src)];var_tweak=damtype' id='damtype'>[uppertext(damtype)]</a> - FORCE: <font size='1'><a href='?_src_=vars;[HrefToken()];item_to_tweak=[REF(src)];var_tweak=force' id='force'>[force]</a> - WOUND: <font size='1'><a href='?_src_=vars;[HrefToken()];item_to_tweak=[REF(src)];var_tweak=wound' id='wound'>[wound_bonus]</a> - BARE WOUND: <font size='1'><a href='?_src_=vars;[HrefToken()];item_to_tweak=[REF(src)];var_tweak=bare wound' id='bare wound'>[bare_wound_bonus]</a> + DAMTYPE: <font size='1'><a href='byond://?_src_=vars;[HrefToken()];item_to_tweak=[REF(src)];var_tweak=damtype' id='damtype'>[uppertext(damtype)]</a> + FORCE: <font size='1'><a href='byond://?_src_=vars;[HrefToken()];item_to_tweak=[REF(src)];var_tweak=force' id='force'>[force]</a> + WOUND: <font size='1'><a href='byond://?_src_=vars;[HrefToken()];item_to_tweak=[REF(src)];var_tweak=wound' id='wound'>[wound_bonus]</a> + BARE WOUND: <font size='1'><a href='byond://?_src_=vars;[HrefToken()];item_to_tweak=[REF(src)];var_tweak=bare wound' id='bare wound'>[bare_wound_bonus]</a> </font> "} diff --git a/code/game/objects/items/AI_modules/_AI_modules.dm b/code/game/objects/items/AI_modules/_AI_modules.dm index a7f8dbb1798c0..905443569b2eb 100644 --- a/code/game/objects/items/AI_modules/_AI_modules.dm +++ b/code/game/objects/items/AI_modules/_AI_modules.dm @@ -36,7 +36,7 @@ /obj/item/ai_module/attack_self(mob/user as mob) ..() - to_chat(user, examine_block(display_laws())) + to_chat(user, boxed_message(display_laws())) /// Returns a text display of the laws for the module. /obj/item/ai_module/proc/display_laws() diff --git a/code/game/objects/items/charter.dm b/code/game/objects/items/charter.dm index 69b57fe4e7323..6f8ad945621e5 100644 --- a/code/game/objects/items/charter.dm +++ b/code/game/objects/items/charter.dm @@ -58,7 +58,7 @@ // Autoapproves after a certain time response_timer_id = addtimer(CALLBACK(src, PROC_REF(rename_station), new_name, user.name, user.real_name, key_name(user)), approval_time, TIMER_STOPPABLE) to_chat(GLOB.admins, - span_adminnotice("<b><font color=orange>CUSTOM STATION RENAME:</font></b>[ADMIN_LOOKUPFLW(user)] proposes to rename the [name_type] to [new_name] (will autoapprove in [DisplayTimeText(approval_time)]). [ADMIN_SMITE(user)] (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];reject_custom_name=[REF(src)]'>REJECT</A>) [ADMIN_CENTCOM_REPLY(user)]"), + span_adminnotice("<b><font color=orange>CUSTOM STATION RENAME:</font></b>[ADMIN_LOOKUPFLW(user)] proposes to rename the [name_type] to [new_name] (will autoapprove in [DisplayTimeText(approval_time)]). [ADMIN_SMITE(user)] (<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];reject_custom_name=[REF(src)]'>REJECT</A>) [ADMIN_CENTCOM_REPLY(user)]"), type = MESSAGE_TYPE_PRAYER) for(var/client/admin_client in GLOB.admins) if(admin_client.prefs.toggles & SOUND_ADMINHELP) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 37a29f87ab787..7a66a29da96d5 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -267,7 +267,7 @@ if(length(render_list)) //display our packaged information in an examine block for easy reading - to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO) + to_chat(user, boxed_message(jointext(render_list, "")), type = MESSAGE_TYPE_INFO) return ITEM_INTERACT_SUCCESS return ITEM_INTERACT_BLOCKING diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 364550f062aa7..c6aa10784eeef 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -151,7 +151,7 @@ air_update_turf(FALSE, FALSE) if(warning_given && internal_heat < max_heat * 0.75) warning_given = FALSE - message_admins("Power sink at ([x],[y],[z] - <A HREF='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>) has cooled down and will not explode.") + message_admins("Power sink at ([x],[y],[z] - <A href='byond://?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>) has cooled down and will not explode.") if(mode != OPERATING && internal_heat < MINIMUM_HEAT) internal_heat = 0 STOP_PROCESSING(SSobj, src) @@ -188,7 +188,7 @@ if(internal_heat > max_heat * ALERT / 100) if (!warning_given) warning_given = TRUE - message_admins("Power sink at ([x],[y],[z] - <A HREF='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>) has reached [ALERT]% of max heat. Explosion imminent.") + message_admins("Power sink at ([x],[y],[z] - <A href='byond://?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>) has reached [ALERT]% of max heat. Explosion imminent.") notify_ghosts( "[src] is about to reach critical heat capacity!", source = src, diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 56e058ad5c3a7..950994faaf08b 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -120,6 +120,8 @@ if(type != /obj/item/radio) return AddElement(/datum/element/slapcrafting, string_list(list(/datum/crafting_recipe/improv_explosive))) + if(prob(check_holidays(APRIL_FOOLS) ? 50 : 0.5)) // Extremely rare chance to replace a normal radio with a toy one, because it's funny + make_silly() /obj/item/radio/Destroy() remove_radio_all(src) //Just to be sure @@ -351,7 +353,8 @@ if(isliving(talking_movable)) var/mob/living/talking_living = talking_movable var/volume_modifier = (talking_living.client?.prefs.read_preference(/datum/preference/numeric/sound_radio_noise)) - if(radio_noise && talking_living.can_hear() && volume_modifier && signal.frequency != FREQ_COMMON && !LAZYACCESS(message_mods, MODE_SEQUENTIAL)) + if(radio_noise && talking_living.can_hear() && volume_modifier && signal.frequency != FREQ_COMMON && !LAZYACCESS(message_mods, MODE_SEQUENTIAL) && COOLDOWN_FINISHED(src, audio_cooldown)) + COOLDOWN_START(src, audio_cooldown, 0.5 SECONDS) var/sound/radio_noise = sound('sound/items/radio/radio_talk.ogg', volume = volume_modifier) radio_noise.frequency = get_rand_frequency_low_range() SEND_SOUND(talking_living, radio_noise) @@ -439,7 +442,7 @@ COOLDOWN_START(src, audio_cooldown, 0.5 SECONDS) var/sound/radio_receive = sound('sound/items/radio/radio_receive.ogg', volume = volume_modifier) radio_receive.frequency = get_rand_frequency_low_range() - SEND_SOUND(holder, radio_noise) + SEND_SOUND(holder, radio_receive) if((SPAN_COMMAND in spans) && COOLDOWN_FINISHED(src, important_audio_cooldown)) COOLDOWN_START(src, important_audio_cooldown, 0.5 SECONDS) var/sound/radio_important = sound('sound/items/radio/radio_important.ogg', volume = volume_modifier) @@ -577,6 +580,15 @@ set_on(TRUE) return TRUE +/obj/item/radio/proc/make_silly() + name = "\improper Little-Crew: Assistant's First Radio" + icon_state = "walkieian" + desc = "A Little-Crew branded toy radio in the shape of a lovable pet. After Little-Crew HQ was hit with a Donksoft Nuke, these have become collector's items!" + overlay_speaker_idle = null + overlay_speaker_active = null + overlay_mic_idle = null + overlay_mic_active = null + /////////////////////////////// //////////Borg Radios////////// /////////////////////////////// @@ -705,4 +717,9 @@ inhand_icon_state = "microphone" canhear_range = 3 +// In case you want to map it in/spawn it for some reason +/obj/item/radio/toy/Initialize(mapload) + . = ..() + make_silly() + #undef FREQ_LISTENING diff --git a/code/game/objects/items/devices/scanners/gas_analyzer.dm b/code/game/objects/items/devices/scanners/gas_analyzer.dm index 112833877c4d3..8fc6ff4426bba 100644 --- a/code/game/objects/items/devices/scanners/gas_analyzer.dm +++ b/code/game/objects/items/devices/scanners/gas_analyzer.dm @@ -220,7 +220,7 @@ message += span_notice("Volume: [volume] L") // don't want to change the order volume appears in, suck it // we let the join apply newlines so we do need handholding - to_chat(user, examine_block(jointext(message, "\n")), type = MESSAGE_TYPE_INFO) + to_chat(user, boxed_message(jointext(message, "\n")), type = MESSAGE_TYPE_INFO) return TRUE /obj/item/analyzer/ranged diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index 9e928f785d8c9..00705479f0949 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -81,7 +81,7 @@ floor_text += "<span class='info ml-1'>Body temperature: [scan_turf?.return_air()?.return_temperature() || "???"]</span><br>" if(user.can_read(src) && !user.is_blind()) - to_chat(user, examine_block(floor_text)) + to_chat(user, custom_boxed_message("blue_box", floor_text)) last_scan_text = floor_text return @@ -410,7 +410,7 @@ . = jointext(render_list, "") if(tochat) - to_chat(user, examine_block(.), trailing_newline = FALSE, type = MESSAGE_TYPE_INFO) + to_chat(user, custom_boxed_message("blue_box", .), trailing_newline = FALSE, type = MESSAGE_TYPE_INFO) return . /obj/item/healthanalyzer/click_ctrl_shift(mob/user) @@ -507,7 +507,7 @@ render_list += "<span class='alert ml-2'>[allergies]</span><br>" // we handled the last <br> so we don't need handholding - to_chat(user, examine_block(jointext(render_list, "")), trailing_newline = FALSE, type = MESSAGE_TYPE_INFO) + to_chat(user, custom_boxed_message("blue_box", jointext(render_list, "")), trailing_newline = FALSE, type = MESSAGE_TYPE_INFO) /obj/item/healthanalyzer/click_alt(mob/user) if(mode == SCANNER_NO_MODE) @@ -558,7 +558,7 @@ simple_scanner.show_emotion(AID_EMOTION_HAPPY) to_chat(user, "<span class='notice ml-1'>No wounds detected in subject.</span>") else - to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO) + to_chat(user, custom_boxed_message("blue_box", jointext(render_list, "")), type = MESSAGE_TYPE_INFO) if(simple_scan) var/obj/item/healthanalyzer/simple/simple_scanner = scanner simple_scanner.show_emotion(AID_EMOTION_WARN) diff --git a/code/game/objects/items/devices/scanners/slime_scanner.dm b/code/game/objects/items/devices/scanners/slime_scanner.dm index 79050f0a78c67..c355da8ba7d4a 100644 --- a/code/game/objects/items/devices/scanners/slime_scanner.dm +++ b/code/game/objects/items/devices/scanners/slime_scanner.dm @@ -57,4 +57,4 @@ to_render += "\n[span_notice("Core mutation in progress: [scanned_slime.crossbreed_modification]")]\ \n[span_notice("Progress in core mutation: [scanned_slime.applied_crossbreed_amount] / [SLIME_EXTRACT_CROSSING_REQUIRED]")]" - to_chat(user, examine_block(jointext(to_render,""))) + to_chat(user, boxed_message(jointext(to_render,""))) diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index 4f0c0a84aa317..ffa172707bc7f 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -245,7 +245,7 @@ if(attached_device) if(issignaler(attached_device)) var/obj/item/assembly/signaler/attached_signaller = attached_device - attachment = "<A HREF='?_src_=holder;[HrefToken()];secrets=list_signalers'>[attached_signaller]</A>" + attachment = "<A href='byond://?_src_=holder;[HrefToken()];secrets=list_signalers'>[attached_signaller]</A>" attachment_signal_log = attached_signaller.last_receive_signal_log ? "The following log entry is the last one associated with the attached signaller<br>[attached_signaller.last_receive_signal_log]" : "There is no signal log entry." else attachment = attached_device diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index 6124e6369c7f9..b206fcfdcdcb1 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -539,6 +539,12 @@ color = COLOR_SYNDIE_RED kiss_type = /obj/projectile/kiss/syndie +/obj/item/hand_item/kisser/ink + name = "ink kiss" + desc = "Is that a blot of ink in your pocket or are you just happy to see me?" + color = COLOR_ALMOST_BLACK + kiss_type = /obj/projectile/kiss/ink + /obj/projectile/kiss name = "kiss" icon = 'icons/mob/simple/animal.dmi' @@ -640,6 +646,22 @@ var/obj/item/organ/heart/dont_go_breakin_my_heart = heartbreakee.get_organ_slot(ORGAN_SLOT_HEART) dont_go_breakin_my_heart.apply_organ_damage(999) +/obj/projectile/kiss/ink + name = "ink kiss" + color = COLOR_ALMOST_BLACK + damage = /obj/projectile/ink_spit::damage + damage_type = /obj/projectile/ink_spit::damage_type + armor_flag = /obj/projectile/ink_spit::armor_flag + armour_penetration = /obj/projectile/ink_spit::armour_penetration + impact_effect_type = /obj/projectile/ink_spit::impact_effect_type + hitsound = /obj/projectile/ink_spit::hitsound + hitsound_wall = /obj/projectile/ink_spit::hitsound_wall + +/obj/projectile/kiss/ink/on_hit(atom/target, blocked, pierce_hit) + . = ..() + var/obj/projectile/ink_spit/ink_spit = new (target) + ink_spit.on_hit(target) + // Based on energy gun characteristics /obj/projectile/kiss/syndie name = "syndie kiss" diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index 2079ebf03dc65..ada075a1a6df1 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -565,6 +565,18 @@ return owner.ui_status(user) return UI_CLOSE +/obj/item/construction/rcd/exosuit/build_delay(mob/user, delay, atom/target) + if(delay <= 0) + return TRUE + + var/obj/item/mecha_parts/mecha_equipment/rcd/module = loc + + //deconstruction can't be cancelled by ui changes + if(mode != RCD_DECONSTRUCT) + blueprint_changed = FALSE + + return module.do_after_mecha(target, user, delay) + /obj/item/construction/rcd/exosuit/get_matter(mob/user) if(silo_link) return ..() diff --git a/code/game/objects/items/rcd/RHD.dm b/code/game/objects/items/rcd/RHD.dm index ce9f211b6942e..85cdc21947b6d 100644 --- a/code/game/objects/items/rcd/RHD.dm +++ b/code/game/objects/items/rcd/RHD.dm @@ -63,6 +63,8 @@ return do_after(user, delay, target, extra_checks = CALLBACK(src, PROC_REF(blueprint_change))) /obj/item/construction/proc/blueprint_change() + PRIVATE_PROC(TRUE) + return !blueprint_changed ///used for examining the RCD and for its UI diff --git a/code/game/objects/items/rollertable_dock.dm b/code/game/objects/items/rollertable_dock.dm index d0067e8c67596..9b2c34bc61b41 100644 --- a/code/game/objects/items/rollertable_dock.dm +++ b/code/game/objects/items/rollertable_dock.dm @@ -9,23 +9,6 @@ . = ..() loaded = new(src) -/obj/structure/table/rolling/attackby(obj/item/wtable, mob/user, params) - if(!istype(wtable, /obj/item/rolling_table_dock)) - return ..() - var/obj/item/rolling_table_dock/rable = wtable - var/turf/target_table = get_turf(src) - if(rable.loaded) - to_chat(user, span_warning("You already have a roller table docked!")) - return - if(locate(/mob/living) in target_table) - to_chat(user, span_warning("You can't collect the table with that much on top!")) - return - else - rable.loaded = src - forceMove(rable) - user.visible_message(span_notice("[user] collects [src]."), balloon_alert(user, "you collect the [src].")) - return TRUE - /obj/item/rolling_table_dock/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) var/turf/target_turf = get_turf(interacting_with) if(target_turf.is_blocked_turf(TRUE) || (locate(/mob/living) in target_turf)) diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index 7d53b4c5e880a..c3ae2d7b0d31b 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -463,6 +463,78 @@ for(var/i in 1 to 3) new extra_to_spawn (src) +/obj/item/storage/toolbox/guncase/traitor + name = "makarov gun case" + desc = "A weapon's case. Has a blood-red 'S' stamped on the cover. There seems to be a strange switch along the side inside a plastic flap." + icon_state = "pistol_case" + base_icon_state = "pistol_case" + // What ammo box do we spawn in our case? + var/ammo_box_to_spawn = /obj/item/ammo_box/c9mm + // Timer for the bomb in the case. + var/explosion_timer + // Whether or not our case is exploding. Used for determining sprite changes. + var/currently_exploding = FALSE + +/obj/item/storage/toolbox/guncase/traitor/Initialize(mapload) + . = ..() + register_context() + +/obj/item/storage/toolbox/guncase/traitor/examine(mob/user) + . = ..() + . += span_notice("Activate the Evidence Disposal Explosive using Alt-Right-Click.") + +/obj/item/storage/toolbox/guncase/traitor/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + + context[SCREENTIP_CONTEXT_ALT_RMB] = "Activate Evidence Disposal Explosive" + return CONTEXTUAL_SCREENTIP_SET + +/obj/item/storage/toolbox/guncase/traitor/PopulateContents() + new weapon_to_spawn (src) + for(var/i in 1 to 2) + new extra_to_spawn (src) + new ammo_box_to_spawn(src) + +/obj/item/storage/toolbox/guncase/traitor/update_icon_state() + . = ..() + if(currently_exploding) + icon_state = "[base_icon_state]_exploding" + else + icon_state = "[base_icon_state]" + +/obj/item/storage/toolbox/guncase/traitor/click_alt_secondary(mob/user) + . = ..() + var/i_dont_even_think_once_about_blowing_stuff_up = tgui_alert(user, "Would you like to activate the evidence disposal bomb now?", "BYE BYE", list("Yes","No")) + if(i_dont_even_think_once_about_blowing_stuff_up == "No") + return + explosion_timer = addtimer(CALLBACK(src, PROC_REF(think_fast_chucklenuts)), 5 SECONDS, (TIMER_UNIQUE|TIMER_OVERRIDE)) + to_chat(user, span_warning("You prime [src]'s evidence disposal bomb!")) + log_bomber(user, "has activated a", src, "for detonation") + playsound(src, 'sound/items/weapons/armbomb.ogg', 50, TRUE) + currently_exploding = TRUE + update_appearance() + +/// proc to handle our detonation +/obj/item/storage/toolbox/guncase/traitor/proc/think_fast_chucklenuts() + explosion(src, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 2, explosion_cause = src) + qdel(src) + +/obj/item/storage/toolbox/guncase/traitor/ammunition + name = "makarov 9mm magazine case" + weapon_to_spawn = /obj/item/ammo_box/magazine/m9mm + +/obj/item/storage/toolbox/guncase/traitor/donksoft + name = "\improper Donksoft riot pistol gun case" + weapon_to_spawn = /obj/item/gun/ballistic/automatic/pistol/toy/riot/clandestine + extra_to_spawn = /obj/item/ammo_box/magazine/toy/pistol/riot + ammo_box_to_spawn = /obj/item/ammo_box/foambox/riot + +/obj/item/storage/toolbox/guncase/traitor/ammunition/donksoft + name = "\improper Donksoft riot pistol magazine case" + weapon_to_spawn = /obj/item/ammo_box/magazine/toy/pistol/riot + extra_to_spawn = /obj/item/ammo_box/magazine/toy/pistol/riot + ammo_box_to_spawn = /obj/item/ammo_box/foambox/riot + /obj/item/storage/toolbox/guncase/bulldog name = "bulldog gun case" weapon_to_spawn = /obj/item/gun/ballistic/shotgun/bulldog diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 202fe9361c8ae..8d2cfc755c00f 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -179,7 +179,17 @@ var/area/computer_area = get_area(target) if(!computer_area || (computer_area.area_flags & NOTELEPORT)) continue - if(computer.power_station?.teleporter_hub && computer.power_station.engaged) + + if(!computer.power_station || !computer.power_station.teleporter_hub) + continue + + if((computer.power_station.machine_stat & (NOPOWER|BROKEN|MAINT)) || computer.power_station.panel_open) + continue + + if((computer.power_station.teleporter_hub.machine_stat & (NOPOWER|BROKEN|MAINT)) || computer.power_station.teleporter_hub.panel_open) + continue + + if(computer.power_station.engaged) locations["[get_area(target)] (Active)"] = computer else locations["[get_area(target)] (Inactive)"] = computer diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index b2be3569d14d4..26c649e6fac5b 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -464,12 +464,12 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' desc = "Uncanny looking hammer." - force = 20 - throwforce = 20 + force = 17 + throwforce = 14 throw_range = 4 w_class = WEIGHT_CLASS_NORMAL wound_bonus = 20 - demolition_mod = 1.25 + demolition_mod = 1.15 slot_flags = ITEM_SLOT_BELT /obj/item/carpenter_hammer/Initialize(mapload) @@ -954,13 +954,12 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/melee/baseball_bat/Initialize(mapload) . = ..() - if(prob(1)) - name = "cricket bat" - icon_state = "baseball_bat_brit" - inhand_icon_state = "baseball_bat_brit" - desc = pick("You've got red on you.", "You gotta know what a crumpet is to understand cricket.") - AddElement(/datum/element/kneecapping) + // No subtypes + if(type != /obj/item/melee/baseball_bat) + return + if(prob(check_holidays(APRIL_FOOLS) ? 50 : 1)) + make_silly() /obj/item/melee/baseball_bat/attack_self(mob/user) if(!homerun_able) @@ -1048,6 +1047,12 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 target.throw_at(target_turf, get_dist(target, target_turf), datum_throw_speed + 1, user, callback = CALLBACK(src, PROC_REF(on_hit), target)) thrown_datums[target] = target.throwing +/obj/item/melee/baseball_bat/proc/make_silly() + name = "cricket bat" + icon_state = "baseball_bat_brit" + inhand_icon_state = "baseball_bat_brit" + desc = pick("You've got red on you.", "You gotta know what a crumpet is to understand cricket.") + /obj/item/melee/baseball_bat/proc/on_hit(atom/movable/target) target.remove_filter("baseball_launch") target.throwforce *= 0.5 @@ -1076,6 +1081,11 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/melee/baseball_bat/ablative/IsReflect()//some day this will reflect thrown items instead of lasers return TRUE +// In case you ever want to spawn it via map/admin console +/obj/item/melee/baseball_bat/british/Initialize(mapload) + . = ..() + make_silly() + /obj/item/melee/flyswatter name = "flyswatter" desc = "Useful for killing pests of all sizes." diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 9a090cb2227a8..f1277544af79e 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -1222,4 +1222,14 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) /obj/structure/closet/proc/add_to_roundstart_list() GLOB.roundstart_station_closets += src +///Spears deal bonus damages to lockers +/obj/structure/closet/attacked_by(obj/item/attacking_item, mob/living/user) + if(istype(attacking_item, /obj/item/spear)) + take_damage(attacking_item.force * 2, attacking_item.damtype, MELEE, 1, get_dir(src, user)) + user.visible_message(span_danger("[user] stabs with precision [src]'s electronics with [attacking_item]!"), + span_danger("You stab with precision [src]'s electronics with [attacking_item]!"), null, COMBAT_MESSAGE_RANGE) + log_combat(user, src, "attacked", attacking_item) + return + return ..() + #undef LOCKER_FULL diff --git a/code/game/objects/structures/shower.dm b/code/game/objects/structures/shower.dm index ce6c987ba10dd..26d05f6edd178 100644 --- a/code/game/objects/structures/shower.dm +++ b/code/game/objects/structures/shower.dm @@ -273,7 +273,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/shower, (-16)) if(!radioactive_shower) // note it is possible to have a clean_shower that is radioactive (+70% water mixed with +20% radiation) wash_flags |= CLEAN_RAD - target.wash(wash_flags) + + if (isturf(target)) + target.wash(wash_flags, TRUE) + else + target.wash(wash_flags) reagents.expose(target, (TOUCH), SHOWER_EXPOSURE_MULTIPLIER * SHOWER_SPRAY_VOLUME / max(reagents.total_volume, SHOWER_SPRAY_VOLUME)) if(!isliving(target)) @@ -344,7 +348,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/shower, (-16)) return mode == SHOWER_MODE_FOREVER ? 0 : PROCESS_KILL // Wash up. - wash_atom(loc, TRUE) + wash_atom(loc) reagents.remove_all(SHOWER_SPRAY_VOLUME) /obj/machinery/shower/on_deconstruction(disassembled = TRUE) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 448c3eb5425a7..9adb4f75a2f94 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -390,6 +390,23 @@ LAZYNULL(attached_items) // safety return ..() +/obj/structure/table/rolling/item_interaction(mob/living/user, obj/item/rolling_table_dock/rable, list/modifiers) + . = NONE + if(!istype(rable)) + return + + if(rable.loaded) + to_chat(user, span_warning("You already have \a [rable.loaded] docked!")) + return ITEM_INTERACT_FAILURE + if(locate(/mob/living) in get_turf(src)) + to_chat(user, span_warning("You can't collect \the [src] with that much on top!")) + return ITEM_INTERACT_FAILURE + + rable.loaded = src + forceMove(rable) + user.visible_message(span_notice("[user] collects \the [src]."), span_notice("you collect \the [src].")) + return ITEM_INTERACT_SUCCESS + /obj/structure/table/rolling/AfterPutItemOnTable(obj/item/thing, mob/living/user) . = ..() LAZYADD(attached_items, thing) diff --git a/code/game/objects/structures/votingbox.dm b/code/game/objects/structures/votingbox.dm index 55909978fe2f7..013556febbd52 100644 --- a/code/game/objects/structures/votingbox.dm +++ b/code/game/objects/structures/votingbox.dm @@ -44,13 +44,13 @@ dat += "<h1> Unregistered. Swipe ID card to register as voting box operator </h1>" dat += "<h1>[vote_description]</h1>" if(is_operator(user)) - dat += "Voting: <a href='?src=[REF(src)];act=toggle_vote'>[voting_active ? "Active" : "Maintenance Mode"]</a><br>" - dat += "Set Description: <a href='?src=[REF(src)];act=set_desc'>Set Description</a><br>" - dat += "One vote per ID: <a href='?src=[REF(src)];act=toggle_auth'>[id_auth ? "Yes" : "No"]</a><br>" - dat += "Reset voted ID's: <a href='?src=[REF(src)];act=reset_voted'>Reset</a><br>" - dat += "Draw random vote: <a href='?src=[REF(src)];act=raffle'>Raffle</a><br>" - dat += "Shred votes: <a href='?src=[REF(src)];act=shred'>Shred</a><br>" - dat += "Tally votes: <a href='?src=[REF(src)];act=tally'>Tally</a><br>" + dat += "Voting: <a href='byond://?src=[REF(src)];act=toggle_vote'>[voting_active ? "Active" : "Maintenance Mode"]</a><br>" + dat += "Set Description: <a href='byond://?src=[REF(src)];act=set_desc'>Set Description</a><br>" + dat += "One vote per ID: <a href='byond://?src=[REF(src)];act=toggle_auth'>[id_auth ? "Yes" : "No"]</a><br>" + dat += "Reset voted ID's: <a href='byond://?src=[REF(src)];act=reset_voted'>Reset</a><br>" + dat += "Draw random vote: <a href='byond://?src=[REF(src)];act=raffle'>Raffle</a><br>" + dat += "Shred votes: <a href='byond://?src=[REF(src)];act=shred'>Shred</a><br>" + dat += "Tally votes: <a href='byond://?src=[REF(src)];act=tally'>Tally</a><br>" var/datum/browser/popup = new(user, "votebox", "Voting Box", 300, 300) popup.set_content(dat.Join()) diff --git a/code/game/turfs/closed/wall/reinf_walls.dm b/code/game/turfs/closed/wall/reinf_walls.dm index b6882a5fc2779..ca25e8bc605a5 100644 --- a/code/game/turfs/closed/wall/reinf_walls.dm +++ b/code/game/turfs/closed/wall/reinf_walls.dm @@ -215,9 +215,13 @@ dismantle_wall() /turf/closed/wall/r_wall/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - if(the_rcd.canRturf || the_rcd.construction_mode == RCD_WALLFRAME) + if (the_rcd.construction_mode == RCD_WALLFRAME) return ..() - + if(!the_rcd.canRturf) + return + . = ..() + if (.) + .["delay"] *= RCD_RWALL_DELAY_MULT /turf/closed/wall/r_wall/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, list/rcd_data) if(the_rcd.canRturf || rcd_data["[RCD_DESIGN_MODE]"] == RCD_WALLFRAME) diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index 2ec0b8e9a9c42..a71ed37f374f9 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -266,12 +266,9 @@ /turf/open/lava/proc/can_burn_stuff(atom/movable/burn_target) if(QDELETED(burn_target)) return LAVA_BE_IGNORING - if(burn_target.movement_type & MOVETYPES_NOT_TOUCHING_GROUND || !burn_target.has_gravity()) //you're flying over it. + if((burn_target.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || burn_target.throwing || !burn_target.has_gravity()) //you're flying over it. return LAVA_BE_IGNORING - if(isobj(burn_target)) - if(burn_target.throwing) // to avoid gulag prisoners easily escaping, throwing only works for objects. - return LAVA_BE_IGNORING var/obj/burn_obj = burn_target if((burn_obj.resistance_flags & immunity_resistance_flags)) return LAVA_BE_PROCESSING @@ -285,7 +282,7 @@ var/mob/living/burn_living = burn_target var/atom/movable/burn_buckled = burn_living.buckled if(burn_buckled) - if(burn_buckled.movement_type & MOVETYPES_NOT_TOUCHING_GROUND || !burn_buckled.has_gravity()) + if((burn_buckled.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || burn_buckled.throwing || !burn_buckled.has_gravity()) return LAVA_BE_PROCESSING if(isobj(burn_buckled)) var/obj/burn_buckled_obj = burn_buckled diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 3ec07c11ec28c..e82cba73603ad 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -21,27 +21,27 @@ var/dat = "<center><B>Game Panel</B></center><hr>" if(SSticker.current_state <= GAME_STATE_PREGAME) - dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_manage=1'>(Manage Dynamic Rulesets)</A><br>" - dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart=1'>(Force Roundstart Rulesets)</A><br>" + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_manage=1'>(Manage Dynamic Rulesets)</A><br>" + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_roundstart=1'>(Force Roundstart Rulesets)</A><br>" if (GLOB.dynamic_forced_roundstart_ruleset.len > 0) for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) - dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_remove=[text_ref(rule)]'>-> [rule.name] <-</A><br>"} - dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_clear=1'>(Clear Rulesets)</A><br>" - dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_options=1'>(Dynamic mode options)</A><br>" + dat += {"<A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_remove=[text_ref(rule)]'>-> [rule.name] <-</A><br>"} + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_clear=1'>(Clear Rulesets)</A><br>" + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_options=1'>(Dynamic mode options)</A><br>" dat += "<hr/>" if(SSticker.IsRoundInProgress()) - dat += "<a href='?src=[REF(src)];[HrefToken()];gamemode_panel=1'>(Game Mode Panel)</a><BR>" - dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_manage=1'>(Manage Dynamic Rulesets)</A><br>" + dat += "<a href='byond://?src=[REF(src)];[HrefToken()];gamemode_panel=1'>(Game Mode Panel)</a><BR>" + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_manage=1'>(Manage Dynamic Rulesets)</A><br>" dat += {" <BR> - <A href='?src=[REF(src)];[HrefToken()];create_object=1'>Create Object</A><br> - <A href='?src=[REF(src)];[HrefToken()];quick_create_object=1'>Quick Create Object</A><br> - <A href='?src=[REF(src)];[HrefToken()];create_turf=1'>Create Turf</A><br> - <A href='?src=[REF(src)];[HrefToken()];create_mob=1'>Create Mob</A><br> + <A href='byond://?src=[REF(src)];[HrefToken()];create_object=1'>Create Object</A><br> + <A href='byond://?src=[REF(src)];[HrefToken()];quick_create_object=1'>Quick Create Object</A><br> + <A href='byond://?src=[REF(src)];[HrefToken()];create_turf=1'>Create Turf</A><br> + <A href='byond://?src=[REF(src)];[HrefToken()];create_mob=1'>Create Mob</A><br> "} if(marked_datum && istype(marked_datum, /atom)) - dat += "<A href='?src=[REF(src)];[HrefToken()];dupe_marked_datum=1'>Duplicate Marked Datum</A><br>" + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];dupe_marked_datum=1'>Duplicate Marked Datum</A><br>" usr << browse(dat, "window=admin2;size=240x280") return @@ -110,17 +110,17 @@ ADMIN_VERB(spawn_cargo, R_SPAWN, "Spawn Cargo", "Spawn a cargo crate.", ADMIN_CA <h3>Common options</h3> <i>All these options can be changed midround.</i> <br/> <br/> - <b>Force extended:</b> - Option is <a href='?src=[REF(src)];[HrefToken()];f_dynamic_force_extended=1'> <b>[GLOB.dynamic_forced_extended ? "ON" : "OFF"]</a></b>. + <b>Force extended:</b> - Option is <a href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_force_extended=1'> <b>[GLOB.dynamic_forced_extended ? "ON" : "OFF"]</a></b>. <br/>This will force the round to be extended. No rulesets will be drafted. <br/> <br/> - <b>No stacking:</b> - Option is <a href='?src=[REF(src)];[HrefToken()];f_dynamic_no_stacking=1'> <b>[GLOB.dynamic_no_stacking ? "ON" : "OFF"]</b></a>. + <b>No stacking:</b> - Option is <a href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_no_stacking=1'> <b>[GLOB.dynamic_no_stacking ? "ON" : "OFF"]</b></a>. <br/>Unless the threat goes above [GLOB.dynamic_stacking_limit], only one "round-ender" ruleset will be drafted. <br/> <br/> - <b>Forced threat level:</b> Current value : <a href='?src=[REF(src)];[HrefToken()];f_dynamic_forced_threat=1'><b>[GLOB.dynamic_forced_threat_level]</b></a>. + <b>Forced threat level:</b> Current value : <a href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_forced_threat=1'><b>[GLOB.dynamic_forced_threat_level]</b></a>. <br/>The value threat is set to if it is higher than -1.<br/> <br/> <br/> - <b>Stacking threeshold:</b> Current value : <a href='?src=[REF(src)];[HrefToken()];f_dynamic_stacking_limit=1'><b>[GLOB.dynamic_stacking_limit]</b></a>. + <b>Stacking threeshold:</b> Current value : <a href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_stacking_limit=1'><b>[GLOB.dynamic_stacking_limit]</b></a>. <br/>The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens. <br/> "} @@ -131,9 +131,9 @@ ADMIN_VERB(spawn_cargo, R_SPAWN, "Spawn Cargo", "Spawn a cargo crate.", ADMIN_CA Change these options to forcibly enable or disable dynamic rulesets.<br/>\ Disabled rulesets will never run, even if they would otherwise be valid.<br/>\ Enabled rulesets will run even if the qualifying minimum of threat or player count is not present, this does not guarantee that they will necessarily be chosen (for example their weight may be set to 0 in config).<br/>\ - \[<A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_all_on=1'>force enable all</A> / \ - <A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_all_off=1'>force disable all</A> / \ - <A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_all_reset=1'>reset all</A>\]" + \[<A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_all_on=1'>force enable all</A> / \ + <A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_all_off=1'>force disable all</A> / \ + <A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_all_reset=1'>reset all</A>\]" if (SSticker.current_state <= GAME_STATE_PREGAME) // Don't bother displaying after the round has started var/static/list/rulesets_by_context = list() @@ -166,9 +166,9 @@ ADMIN_VERB(spawn_cargo, R_SPAWN, "Spawn Cargo", "Spawn a cargo crate.", ADMIN_CA if (RULESET_FORCE_DISABLED) color = COLOR_RED dat += "<tr><td><b>[initial(rule.name)]</b></td><td>\[<font color=[color]>[forced]</font>\]</td><td>\[\ - <A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_on=[text_ref(rule)]'>force enabled</A> /\ - <A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_off=[text_ref(rule)]'>force disabled</A> /\ - <A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_reset=[text_ref(rule)]'>reset</A>\]</td></tr>" + <A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_on=[text_ref(rule)]'>force enabled</A> /\ + <A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_off=[text_ref(rule)]'>force disabled</A> /\ + <A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_reset=[text_ref(rule)]'>reset</A>\]</td></tr>" dat += "</table>" return dat @@ -199,10 +199,10 @@ ADMIN_VERB(spawn_cargo, R_SPAWN, "Spawn Cargo", "Spawn a cargo crate.", ADMIN_CA dat += "<tr><td><b>[rule.name]</b></td>\ <td>\[Weight : [rule.weight]\]\ <td>\[<font color=[color]>[active][explanation]</font>\]</td><td>\[\ - <A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_on=[text_ref(rule.type)]'>force enabled</A> /\ - <A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_off=[text_ref(rule.type)]'>force disabled</A> /\ - <A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_reset=[text_ref(rule.type)]'>reset</A>\]</td>\ - <td>\[<A href='?src=[REF(src)];[HrefToken()];f_inspect_ruleset=[text_ref(rule)]'>VV</A>\]</td></tr>" + <A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_on=[text_ref(rule.type)]'>force enabled</A> /\ + <A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_off=[text_ref(rule.type)]'>force disabled</A> /\ + <A href='byond://?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_force_reset=[text_ref(rule.type)]'>reset</A>\]</td>\ + <td>\[<A href='byond://?src=[REF(src)];[HrefToken()];f_inspect_ruleset=[text_ref(rule)]'>VV</A>\]</td></tr>" dat += "</table>" return dat diff --git a/code/modules/admin/antag_panel.dm b/code/modules/admin/antag_panel.dm index 06ca33d89a0f2..8532f5880ecf9 100644 --- a/code/modules/admin/antag_panel.dm +++ b/code/modules/admin/antag_panel.dm @@ -30,7 +30,7 @@ GLOBAL_VAR(antag_prototypes) /datum/antagonist/proc/antag_panel() var/list/commands = list() for(var/command in get_admin_commands()) - commands += "<a href='?src=[REF(src)];command=[command]'>[command]</a>" + commands += "<a href='byond://?src=[REF(src)];command=[command]'>[command]</a>" var/command_part = commands.Join(" | ") var/data_part = antag_panel_data() var/objective_part = antag_panel_objectives() @@ -47,30 +47,30 @@ GLOBAL_VAR(antag_prototypes) var/obj_count = 1 for(var/datum/objective/objective as anything in objectives) result += "<B>[obj_count]</B>: [objective.explanation_text] \ - <a href='?src=[REF(owner)];obj_edit=[REF(objective)]'>Edit</a> \ - <a href='?src=[REF(owner)];obj_delete=[REF(objective)]'>Delete</a> \ - <a href='?src=[REF(owner)];obj_completed=[REF(objective)]'><font color=[objective.check_completion() ? "green" : "red"]>[objective.completed ? "Mark as incomplete" : "Mark as complete"]</font></a> \ + <a href='byond://?src=[REF(owner)];obj_edit=[REF(objective)]'>Edit</a> \ + <a href='byond://?src=[REF(owner)];obj_delete=[REF(objective)]'>Delete</a> \ + <a href='byond://?src=[REF(owner)];obj_completed=[REF(objective)]'><font color=[objective.check_completion() ? "green" : "red"]>[objective.completed ? "Mark as incomplete" : "Mark as complete"]</font></a> \ <br>" obj_count++ - result += "<a href='?src=[REF(owner)];obj_add=1;target_antag=[REF(src)]'>Add objective</a><br>" - result += "<a href='?src=[REF(owner)];obj_prompt_custom=1;target_antag=[REF(src)]'>Prompt custom objective entry</a><br>" - result += "<a href='?src=[REF(owner)];obj_announce=1'>Announce objectives</a><br>" + result += "<a href='byond://?src=[REF(owner)];obj_add=1;target_antag=[REF(src)]'>Add objective</a><br>" + result += "<a href='byond://?src=[REF(owner)];obj_prompt_custom=1;target_antag=[REF(src)]'>Prompt custom objective entry</a><br>" + result += "<a href='byond://?src=[REF(owner)];obj_announce=1'>Announce objectives</a><br>" return result /datum/mind/proc/get_common_admin_commands() var/common_commands = "<span>Common Commands:</span>" if(ishuman(current)) - common_commands += "<a href='?src=[REF(src)];common=undress'>undress</a>" + common_commands += "<a href='byond://?src=[REF(src)];common=undress'>undress</a>" else if(iscyborg(current)) var/mob/living/silicon/robot/R = current if(R.emagged) - common_commands += "<a href='?src=[REF(src)];silicon=Unemag'>Unemag</a>" + common_commands += "<a href='byond://?src=[REF(src)];silicon=Unemag'>Unemag</a>" else if(isAI(current)) var/mob/living/silicon/ai/A = current if (A.connected_robots.len) for (var/mob/living/silicon/robot/R in A.connected_robots) if (R.emagged) - common_commands += "<a href='?src=[REF(src)];silicon=unemagcyborgs'>Unemag slaved cyborgs</a>" + common_commands += "<a href='byond://?src=[REF(src)];silicon=unemagcyborgs'>Unemag slaved cyborgs</a>" break return common_commands @@ -99,9 +99,9 @@ GLOBAL_VAR(antag_prototypes) var/out = "<B>[name]</B>[(current && (current.real_name != name))?" (as [current.real_name])":""]<br>" out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]<br>" - out += "Assigned role: [job_title_ru(assigned_role.title)]. <a href='?src=[REF(src)];role_edit=1'>Edit</a><br>" + out += "Assigned role: [job_title_ru(assigned_role.title)]. <a href='byond://?src=[REF(src)];role_edit=1'>Edit</a><br>" out += "Faction and special role: <b><font color='red'>[special_role]</font></b><br>" - out += "<a href='?_src_=holder;[HrefToken()];check_teams=1'>Show Teams</a><br><br>" + out += "<a href='byond://?_src_=holder;[HrefToken()];check_teams=1'>Show Teams</a><br><br>" var/special_statuses = get_special_statuses() if(length(special_statuses)) @@ -138,7 +138,7 @@ GLOBAL_VAR(antag_prototypes) continue //Let's skip subtypes of what we already shown. else if(prototype.show_in_antagpanel) if(prototype.can_be_owned(src)) - possible_admin_antags += "<a href='?src=[REF(src)];add_antag=[prototype.type]' title='[prototype.type]'>[prototype.name]</a>" + possible_admin_antags += "<a href='byond://?src=[REF(src)];add_antag=[prototype.type]' title='[prototype.type]'>[prototype.name]</a>" else possible_admin_antags += "<a class='linkOff'>[prototype.name]</a>" else @@ -155,8 +155,8 @@ GLOBAL_VAR(antag_prototypes) else //Show removal and current one priority_sections |= antag_category antag_header_parts += span_bad("[current_antag.name]") - antag_header_parts += "<a href='?src=[REF(src)];remove_antag=[REF(current_antag)]'>Remove</a>" - antag_header_parts += "<a href='?src=[REF(src)];open_antag_vv=[REF(current_antag)]'>Open VV</a>" + antag_header_parts += "<a href='byond://?src=[REF(src)];remove_antag=[REF(current_antag)]'>Remove</a>" + antag_header_parts += "<a href='byond://?src=[REF(src)];open_antag_vv=[REF(current_antag)]'>Open VV</a>" //We aren't antag of this category, grab first prototype to check the prefs (This is pretty vague but really not sure how else to do this) @@ -196,19 +196,19 @@ GLOBAL_VAR(antag_prototypes) var/datum/component/uplink/U = find_syndicate_uplink() if(U) if(!U.uplink_handler.has_objectives) - uplink_info += "<a href='?src=[REF(src)];common=takeuplink'>take</a>" + uplink_info += "<a href='byond://?src=[REF(src)];common=takeuplink'>take</a>" if (check_rights(R_FUN, 0)) - uplink_info += ", <a href='?src=[REF(src)];common=crystals'>[U.uplink_handler.telecrystals]</a> TC" + uplink_info += ", <a href='byond://?src=[REF(src)];common=crystals'>[U.uplink_handler.telecrystals]</a> TC" if(U.uplink_handler.has_progression) - uplink_info += ", <a href='?src=[REF(src)];common=progression'>[U.uplink_handler.progression_points]</a> PR" + uplink_info += ", <a href='byond://?src=[REF(src)];common=progression'>[U.uplink_handler.progression_points]</a> PR" if(U.uplink_handler.has_objectives) - uplink_info += ", <a href='?src=[REF(src)];common=give_objective'>Force Give Objective</a>" + uplink_info += ", <a href='byond://?src=[REF(src)];common=give_objective'>Force Give Objective</a>" else uplink_info += ", [U.uplink_handler.telecrystals] TC" if(U.uplink_handler.has_progression) uplink_info += ", [U.uplink_handler.progression_points] PR" else - uplink_info += "<a href='?src=[REF(src)];common=uplink'>give</a>" + uplink_info += "<a href='byond://?src=[REF(src)];common=uplink'>give</a>" uplink_info += "." //hiel grammar out += uplink_info + "<br>" diff --git a/code/modules/admin/check_antagonists.dm b/code/modules/admin/check_antagonists.dm index 04db519ffb50a..30071504c9199 100644 --- a/code/modules/admin/check_antagonists.dm +++ b/code/modules/admin/check_antagonists.dm @@ -5,9 +5,9 @@ if(!owner) return "Unassigned" if(owner.current) - return "<a href='?_src_=holder;[HrefToken()];adminplayeropts=[REF(owner.current)]'>[owner.current.real_name]</a> " + return "<a href='byond://?_src_=holder;[HrefToken()];adminplayeropts=[REF(owner.current)]'>[owner.current.real_name]</a> " else - return "<a href='?_src_=vars;[HrefToken()];Vars=[REF(owner)]'>[owner.name]</a> " + return "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(owner)]'>[owner.name]</a> " //Whatever interesting things happened to the antag admins should know about //Include additional information about antag in this part @@ -28,12 +28,12 @@ if(!owner) return var/list/parts = list() - parts += "<a href='?priv_msg=[ckey(owner.key)]'>PM</a>" + parts += "<a href='byond://?priv_msg=[ckey(owner.key)]'>PM</a>" if(owner.current) //There's body to follow - parts += "<a href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(owner.current)]'>FLW</a>" + parts += "<a href='byond://?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(owner.current)]'>FLW</a>" else parts += "" - parts += "<a href='?_src_=holder;[HrefToken()];traitor=[REF(owner)]'>Show Objective</a>" + parts += "<a href='byond://?_src_=holder;[HrefToken()];traitor=[REF(owner)]'>Show Objective</a>" return parts //Better as one cell or two/three //Builds table row for the antag @@ -95,26 +95,26 @@ tgui_alert(usr, "The game hasn't started yet!") return var/list/dat = list("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Round Status</title></head><body><h1><B>Round Status</B></h1>") - dat += "<a href='?_src_=holder;[HrefToken()];gamemode_panel=1'>Game Mode Panel</a><br>" + dat += "<a href='byond://?_src_=holder;[HrefToken()];gamemode_panel=1'>Game Mode Panel</a><br>" dat += "Round Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B><BR>" dat += "<B>Emergency shuttle</B><BR>" if(EMERGENCY_IDLE_OR_RECALLED) - dat += "<a href='?_src_=holder;[HrefToken()];call_shuttle=1'>Call Shuttle</a><br>" + dat += "<a href='byond://?_src_=holder;[HrefToken()];call_shuttle=1'>Call Shuttle</a><br>" else var/timeleft = SSshuttle.emergency.timeLeft() if(SSshuttle.emergency.mode == SHUTTLE_CALL) - dat += "ETA: <a href='?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]</a><BR>" - dat += "<a href='?_src_=holder;[HrefToken()];call_shuttle=2'>Send Back</a><br>" + dat += "ETA: <a href='byond://?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]</a><BR>" + dat += "<a href='byond://?_src_=holder;[HrefToken()];call_shuttle=2'>Send Back</a><br>" else - dat += "ETA: <a href='?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]</a><BR>" - dat += "<a href='?_src_=holder;[HrefToken()];end_round=[REF(usr)]'>End Round Now</a><br>" + dat += "ETA: <a href='byond://?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]</a><BR>" + dat += "<a href='byond://?_src_=holder;[HrefToken()];end_round=[REF(usr)]'>End Round Now</a><br>" if(SSticker.delay_end) - dat += "<a href='?_src_=holder;[HrefToken()];undelay_round_end=1'>Undelay Round End</a><br>" + dat += "<a href='byond://?_src_=holder;[HrefToken()];undelay_round_end=1'>Undelay Round End</a><br>" else - dat += "<a href='?_src_=holder;[HrefToken()];delay_round_end=1'>Delay Round End</a><br>" - dat += "<a href='?_src_=holder;[HrefToken()];ctf_toggle=1'>Enable/Disable CTF</a><br>" - dat += "<a href='?_src_=holder;[HrefToken()];rebootworld=1'>Reboot World</a><br>" - dat += "<a href='?_src_=holder;[HrefToken()];check_teams=1'>Check Teams</a>" + dat += "<a href='byond://?_src_=holder;[HrefToken()];delay_round_end=1'>Delay Round End</a><br>" + dat += "<a href='byond://?_src_=holder;[HrefToken()];ctf_toggle=1'>Enable/Disable CTF</a><br>" + dat += "<a href='byond://?_src_=holder;[HrefToken()];rebootworld=1'>Reboot World</a><br>" + dat += "<a href='byond://?_src_=holder;[HrefToken()];check_teams=1'>Check Teams</a>" var/connected_players = GLOB.clients.len var/lobby_players = 0 var/observers = 0 diff --git a/code/modules/admin/greyscale_modify_menu.dm b/code/modules/admin/greyscale_modify_menu.dm index 0bc1ec01f5d4f..c87c424661fd2 100644 --- a/code/modules/admin/greyscale_modify_menu.dm +++ b/code/modules/admin/greyscale_modify_menu.dm @@ -241,14 +241,24 @@ This is highly likely to cause massive amounts of lag as every object in the gam config.EnableAutoRefresh(config_owner_type) /datum/greyscale_modify_menu/proc/ReadColorsFromString(colorString) - var/list/new_split_colors = list() + //length validation var/list/colors = splittext(colorString, "#") - for(var/index in 2 to min(length(colors), config.expected_colors + 1)) + if(length(colors) <= 1) //doesn't even begin with a # so isn't even a color + return FALSE + colors.Cut(1, 2) //removes the white space as a consequence of the string beginning with a # + if(colors.len != config.expected_colors) //not the expected length + return FALSE + + //value validation + var/list/new_split_colors = list() + for(var/index in 1 to config.expected_colors) var/color = "#[colors[index]]" if(!findtext(color, GLOB.is_color) && (!unlocked || !findtext(color, GLOB.is_alpha_color))) return FALSE new_split_colors += color split_colors = new_split_colors + + //all good return TRUE /datum/greyscale_modify_menu/proc/randomize_color(color_index) diff --git a/code/modules/admin/known_alts.dm b/code/modules/admin/known_alts.dm index 4105c7f4edc93..3c51ca68bdf1b 100644 --- a/code/modules/admin/known_alts.dm +++ b/code/modules/admin/known_alts.dm @@ -168,7 +168,7 @@ GLOBAL_DATUM_INIT(known_alts, /datum/known_alts, new) var/list/known_alts_html = list() for (var/known_alt in load_known_alts()) - known_alts_html += "<a href='?src=[REF(src)];[HrefToken()];action=delete;id=[known_alt[4]]'>\[-\] Delete</a> <b>[known_alt[1]]</b> is an alt of <b>[known_alt[2]]</b> (added by <b>[known_alt[3]]</b>)." + known_alts_html += "<a href='byond://?src=[REF(src)];[HrefToken()];action=delete;id=[known_alt[4]]'>\[-\] Delete</a> <b>[known_alt[1]]</b> is an alt of <b>[known_alt[2]]</b> (added by <b>[known_alt[3]]</b>)." var/html = {" <head> @@ -179,7 +179,7 @@ GLOBAL_DATUM_INIT(known_alts, /datum/known_alts, new) <p>Any two ckeys in this panel will not show in "banned connection history".</p> <p>Sometimes players switch account, and it's customary to perma-ban the old one.</p> - <h2>All Known Alts:</h2> <a href='?src=[REF(src)];[HrefToken()];action=add'>\[+\] Add</a><hr> + <h2>All Known Alts:</h2> <a href='byond://?src=[REF(src)];[HrefToken()];action=add'>\[+\] Add</a><hr> [known_alts_html.Join("<br />")] </body> diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm index 6bd97dcaa2005..e474fcff0955d 100644 --- a/code/modules/admin/permissionedit.dm +++ b/code/modules/admin/permissionedit.dm @@ -7,11 +7,11 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm return var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/group/permissions) asset_cache_datum.send(usr) - var/list/output = list("<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url("panels.css")]'><a href='?_src_=holder;[HrefToken()];editrightsbrowser=1'>\[Permissions\]</a>") + var/list/output = list("<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url("panels.css")]'><a href='byond://?_src_=holder;[HrefToken()];editrightsbrowser=1'>\[Permissions\]</a>") if(action) - output += " | <a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a><hr style='background:#000000; border:0; height:3px'>" + output += " | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a> | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a><hr style='background:#000000; border:0; height:3px'>" else - output += "<br><a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><br><a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a>" + output += "<br><a href='byond://?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><br><a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a>" if(action == 1) var/logcount = 0 var/logssperpage = 20 @@ -30,7 +30,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm if(logcount > logssperpage) output += "<br><b>Page: </b>" while(logcount > 0) - output += "|<a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightstarget=[target];editrightsoperation=[operation];editrightspage=[pagecount]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>" + output += "|<a href='byond://?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightstarget=[target];editrightsoperation=[operation];editrightspage=[pagecount]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>" logcount -= logssperpage pagecount++ output += "|" @@ -69,7 +69,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm while(query_check_admin_errors.NextRow()) var/admin_key = query_check_admin_errors.item[1] var/admin_rank = query_check_admin_errors.item[2] - output += "[admin_key] has non-existent rank [admin_rank] | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightschange=[admin_key]'>\[Change Rank\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremove=[admin_key]'>\[Remove\]</a>" + output += "[admin_key] has non-existent rank [admin_rank] | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightschange=[admin_key]'>\[Change Rank\]</a> | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremove=[admin_key]'>\[Remove\]</a>" output += "<hr style='background:#000000; border:0; height:1px'>" qdel(query_check_admin_errors) output += "<h3>Unused ranks</h3>" @@ -79,7 +79,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm return while(query_check_unused_rank.NextRow()) var/admin_rank = query_check_unused_rank.item[1] - output += {"Rank [admin_rank] is not held by any admin | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremoverank=[admin_rank]'>\[Remove\]</a> + output += {"Rank [admin_rank] is not held by any admin | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremoverank=[admin_rank]'>\[Remove\]</a> <br>Permissions: [rights2text(text2num(query_check_unused_rank.item[2])," ")] <br>Denied: [rights2text(text2num(query_check_unused_rank.item[3])," ", "-")] <br>Allowed to edit: [rights2text(text2num(query_check_unused_rank.item[4])," ", "*")] @@ -95,7 +95,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm <body onload='selectTextField();updateSearch();'> <div id='main'><table id='searchable' cellspacing='0'> <tr class='title'> - <th style='width:150px;'>CKEY <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th> + <th style='width:150px;'>CKEY <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th> <th style='width:125px;'>RANK</th> <th>PERMISSIONS</th> </tr> @@ -110,18 +110,18 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm if(D.owner) adm_ckey = D.owner.key if (D.deadmined) - deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=activate;key=[adm_ckey]'>\[RA\]</a>" + deadminlink = " <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=activate;key=[adm_ckey]'>\[RA\]</a>" else - deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=deactivate;key=[adm_ckey]'>\[DA\]</a>" + deadminlink = " <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=deactivate;key=[adm_ckey]'>\[DA\]</a>" var/verify_link = "" if (D.blocked_by_2fa) - verify_link += " | <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=verify;key=[adm_ckey]'>\[2FA VERIFY\]</a>" + verify_link += " | <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=verify;key=[adm_ckey]'>\[2FA VERIFY\]</a>" output += "<tr>" - output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='?src=[REF(src)];[HrefToken()];editrights=remove;key=[adm_ckey]'>\[-\]</a><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=sync;key=[adm_ckey]'>\[SYNC TGDB\]</a>[verify_link]</td>" - output += "<td><a href='?src=[REF(src)];[HrefToken()];editrights=rank;key=[adm_ckey]'>[D.rank_names()]</a></td>" - output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank_flags(), " ")]</a></td>" + output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=remove;key=[adm_ckey]'>\[-\]</a><a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=sync;key=[adm_ckey]'>\[SYNC TGDB\]</a>[verify_link]</td>" + output += "<td><a href='byond://?src=[REF(src)];[HrefToken()];editrights=rank;key=[adm_ckey]'>[D.rank_names()]</a></td>" + output += "<td><a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank_flags(), " ")]</a></td>" output += "</tr>" output += "</table></div><div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div></body>" if(QDELETED(usr)) @@ -140,7 +140,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm permissions_assets.send(usr.client) var/admin_key = href_list["key"] var/admin_ckey = ckey(admin_key) - + var/task = href_list["editrights"] var/datum/admins/target_admin_datum = GLOB.admin_datums[admin_ckey] if(!target_admin_datum) @@ -178,7 +178,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm use_db = FALSE if(QDELETED(usr)) return - + if(target_admin_datum && (task != "sync" && task != "verify") && !check_if_greater_rights_than_holder(target_admin_datum)) message_admins("[key_name_admin(usr)] attempted to change the rank of [admin_key] without sufficient rights.") log_admin("[key_name(usr)] attempted to change the rank of [admin_key] without sufficient rights.") diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 31c34957544e4..ddb02b78b8acc 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -80,19 +80,19 @@ body += "</td><td align='center'>"; - body += "<a href='?_src_=holder;[HrefToken()];adminplayeropts="+ref+"'>PP</a> - " - body += "<a href='?_src_=holder;[HrefToken()];showmessageckey="+ckey+"'>N</a> - " - body += "<a href='?_src_=vars;[HrefToken()];Vars="+ref+"'>VV</a> - " - body += "<a href='?_src_=vars;[HrefToken()];skill="+ref+"'>SP</a> - " - body += "<a href='?_src_=holder;[HrefToken()];traitor="+ref+"'>TP</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];adminplayeropts="+ref+"'>PP</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];showmessageckey="+ckey+"'>N</a> - " + body += "<a href='byond://?_src_=vars;[HrefToken()];Vars="+ref+"'>VV</a> - " + body += "<a href='byond://?_src_=vars;[HrefToken()];skill="+ref+"'>SP</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];traitor="+ref+"'>TP</a> - " if (job == "Cyborg") - body += "<a href='?_src_=holder;[HrefToken()];borgpanel="+ref+"'>BP</a> - " - body += "<a href='?priv_msg="+ckey+"'>PM</a> - " - body += "<a href='?_src_=holder;[HrefToken()];subtlemessage="+ref+"'>SM</a> - " - body += "<a href='?_src_=holder;[HrefToken()];adminplayerobservefollow="+ref+"'>FLW</a> - " - body += "<a href='?_src_=holder;[HrefToken()];individuallog="+ref+"'>LOGS</a><br>" + body += "<a href='byond://?_src_=holder;[HrefToken()];borgpanel="+ref+"'>BP</a> - " + body += "<a href='byond://?priv_msg="+ckey+"'>PM</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];subtlemessage="+ref+"'>SM</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];adminplayerobservefollow="+ref+"'>FLW</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];individuallog="+ref+"'>LOGS</a><br>" if(antagonist > 0) - body += "<font size='2'><a href='?_src_=holder;[HrefToken()];check_antagonist=1'><font color='red'><b>Antagonist</b></font></a></font>"; + body += "<font size='2'><a href='byond://?_src_=holder;[HrefToken()];check_antagonist=1'><font color='red'><b>Antagonist</b></font></a></font>"; body += "</td></tr></table>"; @@ -198,7 +198,7 @@ <tr id='title_tr'> <td align='center'> <font size='5'><b>Player panel</b></font><br> - Hover over a line to see more information - <a href='?_src_=holder;[HrefToken()];check_antagonist=1'>Check antagonists</a> - Kick <a href='?_src_=holder;[HrefToken()];kick_all_from_lobby=1;afkonly=0'>everyone</a>/<a href='?_src_=holder;[HrefToken()];kick_all_from_lobby=1;afkonly=1'>AFKers</a> in lobby + Hover over a line to see more information - <a href='byond://?_src_=holder;[HrefToken()];check_antagonist=1'>Check antagonists</a> - Kick <a href='byond://?_src_=holder;[HrefToken()];kick_all_from_lobby=1;afkonly=0'>everyone</a>/<a href='byond://?_src_=holder;[HrefToken()];kick_all_from_lobby=1;afkonly=1'>AFKers</a> in lobby <p> </td> </tr> diff --git a/code/modules/admin/poll_management.dm b/code/modules/admin/poll_management.dm index 86f075d311340..88a38c90166b4 100644 --- a/code/modules/admin/poll_management.dm +++ b/code/modules/admin/poll_management.dm @@ -71,12 +71,12 @@ * */ /datum/admins/proc/poll_list_panel() - var/list/output = list("Current and future polls<br>Note when editing polls or their options changes are not saved until you press Submit Poll.<br><a href='?_src_=holder;[HrefToken()];newpoll=1'>New Poll</a><a href='?_src_=holder;[HrefToken()];reloadpolls=1'>Reload Polls</a><hr>") + var/list/output = list("Current and future polls<br>Note when editing polls or their options changes are not saved until you press Submit Poll.<br><a href='byond://?_src_=holder;[HrefToken()];newpoll=1'>New Poll</a><a href='byond://?_src_=holder;[HrefToken()];reloadpolls=1'>Reload Polls</a><hr>") for(var/p in GLOB.polls) var/datum/poll_question/poll = p output += {"[poll.question] - <a href='?_src_=holder;[HrefToken()];editpoll=[REF(poll)]'> Edit</a> - <a href='?_src_=holder;[HrefToken()];deletepoll=[REF(poll)]'> Delete</a> + <a href='byond://?_src_=holder;[HrefToken()];editpoll=[REF(poll)]'> Edit</a> + <a href='byond://?_src_=holder;[HrefToken()];deletepoll=[REF(poll)]'> Delete</a> "} if(poll.subtitle) output += "<br>[poll.subtitle]" @@ -204,20 +204,20 @@ <br> "} if(poll.poll_type == POLLTYPE_TEXT) - output += "<a href='?_src_=holder;[HrefToken()];clearpollvotes=[REF(poll)]'>Clear poll responses</a> [poll.poll_votes] players have responded" + output += "<a href='byond://?_src_=holder;[HrefToken()];clearpollvotes=[REF(poll)]'>Clear poll responses</a> [poll.poll_votes] players have responded" else - output += "<a href='?_src_=holder;[HrefToken()];clearpollvotes=[REF(poll)]'>Clear poll votes</a> [poll.poll_votes] players have voted" + output += "<a href='byond://?_src_=holder;[HrefToken()];clearpollvotes=[REF(poll)]'>Clear poll votes</a> [poll.poll_votes] players have voted" if(poll.poll_type == POLLTYPE_TEXT) output += "</div></div>" else - output += "</div></div><hr><a href='?_src_=holder;[HrefToken()];addpolloption=[REF(poll)]'>Add Option</a><br>" + output += "</div></div><hr><a href='byond://?_src_=holder;[HrefToken()];addpolloption=[REF(poll)]'>Add Option</a><br>" if(length(poll.options)) for(var/o in poll.options) var/datum/poll_option/option = o option_count++ output += {"Option [option_count] - <a href='?_src_=holder;[HrefToken()];editpolloption=[REF(option)];parentpoll=[REF(poll)]'> Edit</a> - <a href='?_src_=holder;[HrefToken()];deletepolloption=[REF(option)]'> Delete</a> + <a href='byond://?_src_=holder;[HrefToken()];editpolloption=[REF(option)];parentpoll=[REF(poll)]'> Edit</a> + <a href='byond://?_src_=holder;[HrefToken()];deletepolloption=[REF(option)]'> Delete</a> <br>[option.text] "} if(poll.poll_type == POLLTYPE_RATING) diff --git a/code/modules/admin/sound_emitter.dm b/code/modules/admin/sound_emitter.dm index 9f1d430a46c03..165b882ab46e7 100644 --- a/code/modules/admin/sound_emitter.dm +++ b/code/modules/admin/sound_emitter.dm @@ -61,16 +61,16 @@ /obj/effect/sound_emitter/proc/edit_emitter(mob/user) var/dat = "" - dat += "<b>Label:</b> <a href='?src=[text_ref(src)];edit_label=1'>[maptext ? maptext : "No label set!"]</a><br>" + dat += "<b>Label:</b> <a href='byond://?src=[text_ref(src)];edit_label=1'>[maptext ? maptext : "No label set!"]</a><br>" dat += "<br>" - dat += "<b>Sound File:</b> <a href='?src=[text_ref(src)];edit_sound_file=1'>[sound_file ? sound_file : "No file chosen!"]</a><br>" - dat += "<b>Volume:</b> <a href='?src=[text_ref(src)];edit_volume=1'>[sound_volume]%</a><br>" + dat += "<b>Sound File:</b> <a href='byond://?src=[text_ref(src)];edit_sound_file=1'>[sound_file ? sound_file : "No file chosen!"]</a><br>" + dat += "<b>Volume:</b> <a href='byond://?src=[text_ref(src)];edit_volume=1'>[sound_volume]%</a><br>" dat += "<br>" - dat += "<b>Mode:</b> <a href='?src=[text_ref(src)];edit_mode=1'>[motus_operandi]</a><br>" + dat += "<b>Mode:</b> <a href='byond://?src=[text_ref(src)];edit_mode=1'>[motus_operandi]</a><br>" if(motus_operandi != SOUND_EMITTER_LOCAL) - dat += "<b>Range:</b> <a href='?src=[text_ref(src)];edit_range=1'>[emitter_range]</a>[emitter_range == SOUND_EMITTER_RADIUS ? "<a href='?src=[text_ref(src)];edit_radius=1'>[play_radius]-tile radius</a>" : ""]<br>" + dat += "<b>Range:</b> <a href='byond://?src=[text_ref(src)];edit_range=1'>[emitter_range]</a>[emitter_range == SOUND_EMITTER_RADIUS ? "<a href='byond://?src=[text_ref(src)];edit_radius=1'>[play_radius]-tile radius</a>" : ""]<br>" dat += "<br>" - dat += "<a href='?src=[text_ref(src)];play=1'>Play Sound</a> (interrupts other sound emitter sounds)" + dat += "<a href='byond://?src=[text_ref(src)];play=1'>Play Sound</a> (interrupts other sound emitter sounds)" var/datum/browser/popup = new(user, "emitter", "", 500, 600) popup.set_content(dat) popup.open() diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index 74955324dffd4..a8f16e92daa11 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -689,7 +689,7 @@ var/pagecount = 1 var/list/pagelist = list() while(bancount > 0) - pagelist += "<a href='?_src_=holder;[HrefToken()];unbanpagecount=[pagecount - 1];unbankey=[player_key];unbanadminkey=[admin_key];unbanip=[player_ip];unbancid=[player_cid]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>" + pagelist += "<a href='byond://?_src_=holder;[HrefToken()];unbanpagecount=[pagecount - 1];unbankey=[player_key];unbanadminkey=[admin_key];unbanip=[player_ip];unbancid=[player_cid]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>" bancount -= bansperpage pagecount++ output += pagelist.Join(" | ") @@ -775,13 +775,13 @@ var/un_or_reban_href if(unban_datetime) - un_or_reban_href = "<a href='?_src_=holder;[HrefToken()];rebanid=[ban_id];applies_to_admins=[applies_to_admins];rebankey=[banned_player_key];rebanadminkey=[banning_admin_key];rebanip=[banned_player_ip];rebancid=[banned_player_cid];rebanrole=[role];rebanpage=[page]'>Reban</a>" + un_or_reban_href = "<a href='byond://?_src_=holder;[HrefToken()];rebanid=[ban_id];applies_to_admins=[applies_to_admins];rebankey=[banned_player_key];rebanadminkey=[banning_admin_key];rebanip=[banned_player_ip];rebancid=[banned_player_cid];rebanrole=[role];rebanpage=[page]'>Reban</a>" else - un_or_reban_href = "<a href='?_src_=holder;[HrefToken()];unbanid=[ban_id];unbankey=[banned_player_key];unbanadminkey=[banning_admin_key];unbanip=[banned_player_ip];unbancid=[banned_player_cid];unbanrole=[role];unbanpage=[page]'>Unban</a>" - output += "<a href='?_src_=holder;[HrefToken()];editbanid=[ban_id];editbankey=[banned_player_key];editbanip=[banned_player_ip];editbancid=[banned_player_cid];editbanrole=[role];editbanduration=[duration];editbanadmins=[applies_to_admins];editbanreason=[url_encode(reason)];editbanpage=[page];editbanadminkey=[banning_admin_key]'>Edit</a><br>[un_or_reban_href]" + un_or_reban_href = "<a href='byond://?_src_=holder;[HrefToken()];unbanid=[ban_id];unbankey=[banned_player_key];unbanadminkey=[banning_admin_key];unbanip=[banned_player_ip];unbancid=[banned_player_cid];unbanrole=[role];unbanpage=[page]'>Unban</a>" + output += "<a href='byond://?_src_=holder;[HrefToken()];editbanid=[ban_id];editbankey=[banned_player_key];editbanip=[banned_player_ip];editbancid=[banned_player_cid];editbanrole=[role];editbanduration=[duration];editbanadmins=[applies_to_admins];editbanreason=[url_encode(reason)];editbanpage=[page];editbanadminkey=[banning_admin_key]'>Edit</a><br>[un_or_reban_href]" if(edits) - output += "<br><a href='?_src_=holder;[HrefToken()];unbanlog=[ban_id]'>Edit log</a>" + output += "<br><a href='byond://?_src_=holder;[HrefToken()];unbanlog=[ban_id]'>Edit log</a>" output += "</div></div></div>" qdel(query_unban_search_bans) output += "</div>" diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm index 7aab49d1c3649..f7d0023534529 100644 --- a/code/modules/admin/sql_message_system.dm +++ b/code/modules/admin/sql_message_system.dm @@ -377,10 +377,10 @@ var/list/output = list() var/ruler = "<hr style='background:#000000; border:0; height:3px'>" - var/list/navbar = list("<a href='?_src_=holder;[HrefToken()];nonalpha=1'>All</a><a href='?_src_=holder;[HrefToken()];nonalpha=2'>#</a>") + var/list/navbar = list("<a href='byond://?_src_=holder;[HrefToken()];nonalpha=1'>All</a><a href='byond://?_src_=holder;[HrefToken()];nonalpha=2'>#</a>") for(var/letter in GLOB.alphabet) - navbar += "<a href='?_src_=holder;[HrefToken()];showmessages=[letter]'>[letter]</a>" - navbar += "<a href='?_src_=holder;[HrefToken()];showmemo=1'>Memos</a><a href='?_src_=holder;[HrefToken()];showwatch=1'>Watchlist</a>" + navbar += "<a href='byond://?_src_=holder;[HrefToken()];showmessages=[letter]'>[letter]</a>" + navbar += "<a href='byond://?_src_=holder;[HrefToken()];showmemo=1'>Memos</a><a href='byond://?_src_=holder;[HrefToken()];showwatch=1'>Watchlist</a>" navbar += "<br><form method='GET' name='search' action='?'>\ <input type='hidden' name='_src_' value='holder'>\ [HrefTokenFormField()]\ @@ -391,14 +391,14 @@ if(type == "memo" || type == "watchlist entry") if(type == "memo") output += "<h2><center>Admin memos</h2>" - output += "<a href='?_src_=holder;[HrefToken()];addmemo=1'>Add memo</a></center>" + output += "<a href='byond://?_src_=holder;[HrefToken()];addmemo=1'>Add memo</a></center>" else if(type == "watchlist entry") output += "<h2><center>Watchlist entries</h2>" - output += "<a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a>" + output += "<a href='byond://?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a>" if(filter) - output += "<a href='?_src_=holder;[HrefToken()];showwatch=1'>Unfilter clients</a></center>" + output += "<a href='byond://?_src_=holder;[HrefToken()];showwatch=1'>Unfilter clients</a></center>" else - output += "<a href='?_src_=holder;[HrefToken()];showwatchfilter=1'>Filter offline clients</a></center>" + output += "<a href='byond://?_src_=holder;[HrefToken()];showwatchfilter=1'>Filter offline clients</a></center>" output += ruler var/datum/db_query/query_get_type_messages = SSdbcore.NewQuery({" SELECT @@ -444,11 +444,11 @@ if(expire_timestamp) output += " | Expires [expire_timestamp]" output += "</b>" - output += " <a href='?_src_=holder;[HrefToken()];editmessageexpiryempty=[id]'>Change Expiry Time</a>" - output += " <a href='?_src_=holder;[HrefToken()];deletemessageempty=[id]'>Delete</a>" - output += " <a href='?_src_=holder;[HrefToken()];editmessageempty=[id]'>Edit</a>" + output += " <a href='byond://?_src_=holder;[HrefToken()];editmessageexpiryempty=[id]'>Change Expiry Time</a>" + output += " <a href='byond://?_src_=holder;[HrefToken()];deletemessageempty=[id]'>Delete</a>" + output += " <a href='byond://?_src_=holder;[HrefToken()];editmessageempty=[id]'>Edit</a>" if(editor_key) - output += " <font size='2'>Last edit by [editor_key] <a href='?_src_=holder;[HrefToken()];messageedits=[id]'>(Click here to see edit log)</a></font>" + output += " <font size='2'>Last edit by [editor_key] <a href='byond://?_src_=holder;[HrefToken()];messageedits=[id]'>(Click here to see edit log)</a></font>" output += "<br>[text]<hr style='background:#000000; border:0; height:1px'>" qdel(query_get_type_messages) if(target_ckey) @@ -524,21 +524,21 @@ if(!linkless) if(type == "note") if(severity) - data += "<a href='?_src_=holder;[HrefToken()];editmessageseverity=[id]'>[severity == "none" ? "No" : "[capitalize(severity)]"] Severity</a>" + data += "<a href='byond://?_src_=holder;[HrefToken()];editmessageseverity=[id]'>[severity == "none" ? "No" : "[capitalize(severity)]"] Severity</a>" else - data += "<a href='?_src_=holder;[HrefToken()];editmessageseverity=[id]'>N/A Severity</a>" - data += " <a href='?_src_=holder;[HrefToken()];editmessageexpiry=[id]'>Change Expiry Time</a>" - data += " <a href='?_src_=holder;[HrefToken()];deletemessage=[id]'>Delete</a>" + data += "<a href='byond://?_src_=holder;[HrefToken()];editmessageseverity=[id]'>N/A Severity</a>" + data += " <a href='byond://?_src_=holder;[HrefToken()];editmessageexpiry=[id]'>Change Expiry Time</a>" + data += " <a href='byond://?_src_=holder;[HrefToken()];deletemessage=[id]'>Delete</a>" if(type == "note") - data += " <a href='?_src_=holder;[HrefToken()];secretmessage=[id]'>[secret ? "<b>Secret</b>" : "Not secret"]</a>" + data += " <a href='byond://?_src_=holder;[HrefToken()];secretmessage=[id]'>[secret ? "<b>Secret</b>" : "Not secret"]</a>" if(type == "message sent") data += " <font size='2'>Message has been sent</font>" if(editor_key) data += "|" else - data += " <a href='?_src_=holder;[HrefToken()];editmessage=[id]'>Edit</a>" + data += " <a href='byond://?_src_=holder;[HrefToken()];editmessage=[id]'>Edit</a>" if(editor_key) - data += " <font size='2'>Last edit by [editor_key] <a href='?_src_=holder;[HrefToken()];messageedits=[id]'>(Click here to see edit log)</a></font>" + data += " <font size='2'>Last edit by [editor_key] <a href='byond://?_src_=holder;[HrefToken()];messageedits=[id]'>(Click here to see edit log)</a></font>" data += "</div></center>" data += "<p style='[alphatext]'>[text]</p><hr style='background:#000000; border:0; height:1px; [alphatext]'>" switch(type) @@ -563,12 +563,12 @@ qdel(query_get_message_key) output += "<h2><center>[target_key]</center></h2><center>" if(!linkless) - output += "<a href='?_src_=holder;[HrefToken()];addnote=[target_key]'>Add note</a>" - output += " <a href='?_src_=holder;[HrefToken()];addmessage=[target_key]'>Add message</a>" - output += " <a href='?_src_=holder;[HrefToken()];addwatch=[target_key]'>Add to watchlist</a>" - output += " <a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>Refresh page</a></center>" + output += "<a href='byond://?_src_=holder;[HrefToken()];addnote=[target_key]'>Add note</a>" + output += " <a href='byond://?_src_=holder;[HrefToken()];addmessage=[target_key]'>Add message</a>" + output += " <a href='byond://?_src_=holder;[HrefToken()];addwatch=[target_key]'>Add to watchlist</a>" + output += " <a href='byond://?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>Refresh page</a></center>" else - output += " <a href='?_src_=holder;[HrefToken()];showmessageckeylinkless=[target_ckey]'>Refresh page</a></center>" + output += " <a href='byond://?_src_=holder;[HrefToken()];showmessageckeylinkless=[target_ckey]'>Refresh page</a></center>" output += ruler if(messagedata) output += "<h2>Messages</h2>" @@ -582,14 +582,14 @@ if(!linkless) if (agegate) if (skipped) //the first skipped message is still shown so that we can put this link over it. - output += "<center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1' style='position: relative; top: -3em;'>Show [skipped] hidden messages</a></center>" + output += "<center><a href='byond://?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1' style='position: relative; top: -3em;'>Show [skipped] hidden messages</a></center>" else - output += "<center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1'>Show All</a></center>" + output += "<center><a href='byond://?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1'>Show All</a></center>" else - output += "<center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>Hide Old</a></center>" + output += "<center><a href='byond://?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>Hide Old</a></center>" if(index) var/search - output += "<center><a href='?_src_=holder;[HrefToken()];addmessageempty=1'>Add message</a><a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a><a href='?_src_=holder;[HrefToken()];addnoteempty=1'>Add note</a></center>" + output += "<center><a href='byond://?_src_=holder;[HrefToken()];addmessageempty=1'>Add message</a><a href='byond://?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a><a href='byond://?_src_=holder;[HrefToken()];addnoteempty=1'>Add note</a></center>" output += ruler switch(index) if(1) @@ -619,10 +619,10 @@ var/index_key = query_list_messages.item[2] if(!index_key) index_key = index_ckey - output += "<a href='?_src_=holder;[HrefToken()];showmessageckey=[index_ckey]'>[index_key]</a><br>" + output += "<a href='byond://?_src_=holder;[HrefToken()];showmessageckey=[index_ckey]'>[index_key]</a><br>" qdel(query_list_messages) else if(!type && !target_ckey && !index) - output += "<center><a href='?_src_=holder;[HrefToken()];addmessageempty=1'>Add message</a><a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a><a href='?_src_=holder;[HrefToken()];addnoteempty=1'>Add note</a></center>" + output += "<center><a href='byond://?_src_=holder;[HrefToken()];addmessageempty=1'>Add message</a><a href='byond://?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a><a href='byond://?_src_=holder;[HrefToken()];addnoteempty=1'>Add note</a></center>" output += ruler var/datum/browser/browser = new(usr, "Note panel", "Manage player notes", 1000, 500) notes_assets.send(usr.client) @@ -690,7 +690,7 @@ var/list/text = list() for(var/datum/admin_message/message in get_message_output("message", display_to.ckey)) text += "<font color='[COLOR_RED]' size='3'><b>Admin message left by [span_prefix("[message.admin_key]")] on [message.timestamp]</b></font>" - text += "<br><font color='[COLOR_RED]'>[message.text] <A href='?messageread=[message.id]'>(Click here to verify you have read this message)</A></font><br>" + text += "<br><font color='[COLOR_RED]'>[message.text] <A href='byond://?messageread=[message.id]'>(Click here to verify you have read this message)</A></font><br>" if(length(text)) to_chat(display_to, text.Join()) @@ -707,7 +707,7 @@ for(var/datum/admin_message/message in get_message_output("memo", display_to.ckey)) text += "[span_memo("Memo by <span class='prefix'>[message.admin_key]")] on [message.timestamp]" if(message.editor_key) - text += "<br>[span_memoedit("Last edit by [message.editor_key] <A href='?_src_=holder;[HrefToken()];messageedits=[message.id]'>(Click here to see edit log)</A>")]" + text += "<br>[span_memoedit("Last edit by [message.editor_key] <A href='byond://?_src_=holder;[HrefToken()];messageedits=[message.id]'>(Click here to see edit log)</A>")]" text += "<br>[message.text]</span><br>" if(length(text)) to_chat(display_to, text.Join()) diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm index fede9724ab181..4295080c3f6ca 100644 --- a/code/modules/admin/stickyban.dm +++ b/code/modules/admin/stickyban.dm @@ -348,15 +348,15 @@ return var/timeout if (SSdbcore.Connect()) - timeout = "<a href='?_src_=holder;[HrefToken()];stickyban=[(ban["timeout"] ? "untimeout" : "timeout")]&ckey=[ckey]'>\[[(ban["timeout"] ? "untimeout" : "timeout" )]\]</a>" + timeout = "<a href='byond://?_src_=holder;[HrefToken()];stickyban=[(ban["timeout"] ? "untimeout" : "timeout")]&ckey=[ckey]'>\[[(ban["timeout"] ? "untimeout" : "timeout" )]\]</a>" else - timeout = "<a href='?_src_=holder;[HrefToken()];stickyban=revert&ckey=[ckey]'>\[revert\]</a>" + timeout = "<a href='byond://?_src_=holder;[HrefToken()];stickyban=revert&ckey=[ckey]'>\[revert\]</a>" . = list({" - <a href='?_src_=holder;[HrefToken()];stickyban=remove&ckey=[ckey]'>\[-\]</a> + <a href='byond://?_src_=holder;[HrefToken()];stickyban=remove&ckey=[ckey]'>\[-\]</a> [timeout] <b>[ckey]</b> <br />" - [ban["message"]] <b><a href='?_src_=holder;[HrefToken()];stickyban=edit&ckey=[ckey]'>\[Edit\]</a></b><br /> + [ban["message"]] <b><a href='byond://?_src_=holder;[HrefToken()];stickyban=edit&ckey=[ckey]'>\[Edit\]</a></b><br /> "}) if (ban["admin"]) . += "[ban["admin"]]<br />" @@ -366,12 +366,12 @@ for (var/key in ban["keys"]) if (ckey(key) == ckey) continue - . += "<li><a href='?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]<a href='?_src_=holder;[HrefToken()];stickyban=exempt&ckey=[ckey]&alt=[ckey(key)]'>\[E\]</a></li>" + . += "<li><a href='byond://?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]<a href='byond://?_src_=holder;[HrefToken()];stickyban=exempt&ckey=[ckey]&alt=[ckey(key)]'>\[E\]</a></li>" for (var/key in ban["whitelist"]) if (ckey(key) == ckey) continue - . += "<li><a href='?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]<a href='?_src_=holder;[HrefToken()];stickyban=unexempt&ckey=[ckey]&alt=[ckey(key)]'>\[UE\]</a></li>" + . += "<li><a href='byond://?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]<a href='byond://?_src_=holder;[HrefToken()];stickyban=unexempt&ckey=[ckey]&alt=[ckey(key)]'>\[UE\]</a></li>" . += "</ol>\n" @@ -390,7 +390,7 @@ <title>Sticky Bans</title> </head> <body> - <h2>All Sticky Bans:</h2> <a href='?_src_=holder;[HrefToken()];stickyban=add'>\[+\]</a><br> + <h2>All Sticky Bans:</h2> <a href='byond://?_src_=holder;[HrefToken()];stickyban=add'>\[+\]</a><br> [banhtml.Join("")] </body> "} diff --git a/code/modules/admin/tag.dm b/code/modules/admin/tag.dm index e52112eba1495..ec0ed3b56fa7b 100644 --- a/code/modules/admin/tag.dm +++ b/code/modules/admin/tag.dm @@ -40,8 +40,8 @@ to_chat(owner, span_warning("[target_datum] was not already tagged.")) /// Quick define for readability -#define TAG_DEL(X) "<b>(<A href='?src=[REF(src)];[HrefToken(forceGlobal = TRUE)];del_tag=[REF(X)]'>UNTAG</a>)</b>" -#define TAG_MARK(X) "<b>(<A href='?src=[REF(src)];[HrefToken(forceGlobal = TRUE)];mark_datum=[REF(X)]'>MARK</a>)</b>" +#define TAG_DEL(X) "<b>(<A href='byond://?src=[REF(src)];[HrefToken(forceGlobal = TRUE)];del_tag=[REF(X)]'>UNTAG</a>)</b>" +#define TAG_MARK(X) "<b>(<A href='byond://?src=[REF(src)];[HrefToken(forceGlobal = TRUE)];mark_datum=[REF(X)]'>MARK</a>)</b>" #define TAG_SIMPLE_HEALTH(X) "<font color='#ff0000'><b>Health: [X.health]</b></font>" #define TAG_CARBON_HEALTH(X) "<font color='#ff0000'><b>Health: [X.health]</b></font> (\ <font color='#ff3333'>[X.getBruteLoss()]</font> \ @@ -56,7 +56,7 @@ ADMIN_VERB(display_tags, R_ADMIN, "View Tags", "Display all of the tagged datums var/list/tagged_datums = user.holder.tagged_datums var/list/marked_datum = user.holder.marked_datum - dat += "<br><A href='?src=[REF(user)];[HrefToken(forceGlobal = TRUE)];show_tags=1'>Refresh</a><br>" + dat += "<br><A href='byond://?src=[REF(user)];[HrefToken(forceGlobal = TRUE)];show_tags=1'>Refresh</a><br>" if(LAZYLEN(tagged_datums)) for(var/datum/iter_datum as anything in tagged_datums) index++ diff --git a/code/modules/admin/team_panel.dm b/code/modules/admin/team_panel.dm index 30311c491e6f2..3eba8be949417 100644 --- a/code/modules/admin/team_panel.dm +++ b/code/modules/admin/team_panel.dm @@ -3,22 +3,22 @@ var/list/content = list() for(var/datum/team/T in GLOB.antagonist_teams) content += "<h3>[T.name] - [T.type]</h3>" - content += "<a href='?_src_=holder;[HrefToken()];team_command=rename_team;team=[REF(T)]'>Rename</a>" - content += "<a href='?_src_=holder;[HrefToken()];team_command=delete_team;team=[REF(T)]'>Delete</a>" - content += "<a href='?_src_=holder;[HrefToken()];team_command=communicate;team=[REF(T)]'>Communicate</a>" + content += "<a href='byond://?_src_=holder;[HrefToken()];team_command=rename_team;team=[REF(T)]'>Rename</a>" + content += "<a href='byond://?_src_=holder;[HrefToken()];team_command=delete_team;team=[REF(T)]'>Delete</a>" + content += "<a href='byond://?_src_=holder;[HrefToken()];team_command=communicate;team=[REF(T)]'>Communicate</a>" for(var/command in T.get_admin_commands()) - content += "<a href='?src=[REF(T)];command=[command]'>[command]</a>" + content += "<a href='byond://?src=[REF(T)];command=[command]'>[command]</a>" content += "<br>" content += "Objectives:<br><ol>" for(var/datum/objective/O in T.objectives) - content += "<li>[O.explanation_text] - <a href='?_src_=holder;[HrefToken()];team_command=remove_objective;team=[REF(T)];tobjective=[REF(O)]'>Remove</a></li>" - content += "</ol><a href='?_src_=holder;[HrefToken()];team_command=add_objective;team=[REF(T)]'>Add Objective</a><br>" + content += "<li>[O.explanation_text] - <a href='byond://?_src_=holder;[HrefToken()];team_command=remove_objective;team=[REF(T)];tobjective=[REF(O)]'>Remove</a></li>" + content += "</ol><a href='byond://?_src_=holder;[HrefToken()];team_command=add_objective;team=[REF(T)]'>Add Objective</a><br>" content += "Members: <br><ul>" for(var/datum/mind/M in T.members) - content += "<li>[M.name] - <a href='?_src_=holder;[HrefToken()];team_command=remove_member;team=[REF(T)];tmember=[REF(M)]'>Remove Member</a></li>" - content += "</ul><a href='?_src_=holder;[HrefToken()];team_command=add_member;team=[REF(T)]'>Add Member</a>" + content += "<li>[M.name] - <a href='byond://?_src_=holder;[HrefToken()];team_command=remove_member;team=[REF(T)];tmember=[REF(M)]'>Remove Member</a></li>" + content += "</ul><a href='byond://?_src_=holder;[HrefToken()];team_command=add_member;team=[REF(T)]'>Add Member</a>" content += "<hr>" - content += "<a href='?_src_=holder;[HrefToken()];team_command=create_team'>Create Team</a><br>" + content += "<a href='byond://?_src_=holder;[HrefToken()];team_command=create_team'>Create Team</a><br>" return content.Join() diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 019d0ed64aa8a..b9cd44d7c2243 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -847,7 +847,7 @@ exportable_text += "[special_role_description]<br>" exportable_text += ADMIN_FULLMONTY_NONAME(subject) - to_chat(src.owner, examine_block(exportable_text), confidential = TRUE) + to_chat(src.owner, boxed_message(exportable_text), confidential = TRUE) else if(href_list["addjobslot"]) if(!check_rights(R_ADMIN)) @@ -1731,7 +1731,7 @@ if(FAX.fax_id != href_list["destination"]) continue FAX.receive(locate(href_list["print_fax"]), href_list["sender_name"]) - + return else if(href_list["play_internet"]) if(!check_rights(R_SOUND)) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 4ee2b79f04459..f74df71272106 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -722,7 +722,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/sdql2_vv_all, new(null /datum/sdql2_query/proc/SDQL_print(object, list/text_list, print_nulls = TRUE) if(isdatum(object)) - text_list += "<A HREF='?_src_=vars;[HrefToken(forceGlobal = TRUE)];Vars=[REF(object)]'>[REF(object)]</A> : [object]" + text_list += "<A href='byond://?_src_=vars;[HrefToken(forceGlobal = TRUE)];Vars=[REF(object)]'>[REF(object)]</A> : [object]" if(istype(object, /atom)) var/atom/A = object var/turf/T = A.loc diff --git a/code/modules/admin/verbs/admin.dm b/code/modules/admin/verbs/admin.dm index edd362938af58..629423e713faa 100644 --- a/code/modules/admin/verbs/admin.dm +++ b/code/modules/admin/verbs/admin.dm @@ -45,7 +45,7 @@ ADMIN_VERB(cmd_admin_check_player_exp, R_ADMIN, "Player Playtime", "View player var/list/msg = list() msg += "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Playtime Report</title></head><body>Playtime:<BR><UL>" for(var/client/client in sort_list(GLOB.clients, GLOBAL_PROC_REF(cmp_playtime_asc))) - msg += "<LI> [ADMIN_PP(client.mob)] [key_name_admin(client)]: <A href='?_src_=holder;[HrefToken()];getplaytimewindow=[REF(client.mob)]'>" + client.get_exp_living() + "</a></LI>" + msg += "<LI> [ADMIN_PP(client.mob)] [key_name_admin(client)]: <A href='byond://?_src_=holder;[HrefToken()];getplaytimewindow=[REF(client.mob)]'>" + client.get_exp_living() + "</a></LI>" msg += "</UL></BODY></HTML>" user << browse(msg.Join(), "window=Player_playtime_check") diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index f9a081445b8ea..8e7fd97cc1f8b 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -12,28 +12,28 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_ADMIN, "Show Player Panel", mo body += "<body>Options panel for <b>[player]</b>" if(player.client) body += " played by <b>[player.client]</b> " - body += "\[<A href='?_src_=holder;[HrefToken()];editrights=[(GLOB.admin_datums[player.client.ckey] || GLOB.deadmins[player.client.ckey]) ? "rank" : "add"];key=[player.key]'>[player.client.holder ? player.client.holder.rank_names() : "Player"]</A>\]" + body += "\[<A href='byond://?_src_=holder;[HrefToken()];editrights=[(GLOB.admin_datums[player.client.ckey] || GLOB.deadmins[player.client.ckey]) ? "rank" : "add"];key=[player.key]'>[player.client.holder ? player.client.holder.rank_names() : "Player"]</A>\]" if(CONFIG_GET(flag/use_exp_tracking)) - body += "\[<A href='?_src_=holder;[HrefToken()];getplaytimewindow=[REF(player)]'>" + player.client.get_exp_living(FALSE) + "</a>\]" + body += "\[<A href='byond://?_src_=holder;[HrefToken()];getplaytimewindow=[REF(player)]'>" + player.client.get_exp_living(FALSE) + "</a>\]" if(isnewplayer(player)) body += " <B>Hasn't Entered Game</B> " else - body += " \[<A href='?_src_=holder;[HrefToken()];revive=[REF(player)]'>Heal</A>\] " + body += " \[<A href='byond://?_src_=holder;[HrefToken()];revive=[REF(player)]'>Heal</A>\] " if(player.ckey) - body += "<br>\[<A href='?_src_=holder;[HrefToken()];ppbyckey=[player.ckey];ppbyckeyorigmob=[REF(player)]'>Find Updated Panel</A>\]" + body += "<br>\[<A href='byond://?_src_=holder;[HrefToken()];ppbyckey=[player.ckey];ppbyckeyorigmob=[REF(player)]'>Find Updated Panel</A>\]" if(player.client) body += "<br>\[<b>First Seen:</b> [player.client.player_join_date]\]\[<b>Byond account registered on:</b> [player.client.account_join_date]\]" body += "<br><br><b>CentCom Galactic Ban DB: </b> " if(CONFIG_GET(string/centcom_ban_db)) - body += "<a href='?_src_=holder;[HrefToken()];centcomlookup=[player.client.ckey]'>Search</a>" + body += "<a href='byond://?_src_=holder;[HrefToken()];centcomlookup=[player.client.ckey]'>Search</a>" else body += "<i>Disabled</i>" body += "<br><br><b>Show related accounts by:</b> " - body += "\[ <a href='?_src_=holder;[HrefToken()];showrelatedacc=cid;client=[REF(player.client)]'>CID</a> | " - body += "<a href='?_src_=holder;[HrefToken()];showrelatedacc=ip;client=[REF(player.client)]'>IP</a> \]" + body += "\[ <a href='byond://?_src_=holder;[HrefToken()];showrelatedacc=cid;client=[REF(player.client)]'>CID</a> | " + body += "<a href='byond://?_src_=holder;[HrefToken()];showrelatedacc=ip;client=[REF(player.client)]'>IP</a> \]" var/full_version = "Unknown" if(player.client.byond_version) full_version = "[player.client.byond_version].[player.client.byond_build ? player.client.byond_build : "xxx"]" @@ -41,24 +41,24 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_ADMIN, "Show Player Panel", mo body += "<br><br>\[ " - body += "<a href='?_src_=vars;[HrefToken()];Vars=[REF(player)]'>VV</a> - " + body += "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(player)]'>VV</a> - " if(player.mind) - body += "<a href='?_src_=holder;[HrefToken()];traitor=[REF(player)]'>TP</a> - " - body += "<a href='?_src_=holder;[HrefToken()];skill=[REF(player)]'>SKILLS</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];traitor=[REF(player)]'>TP</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];skill=[REF(player)]'>SKILLS</a> - " else - body += "<a href='?_src_=holder;[HrefToken()];initmind=[REF(player)]'>Init Mind</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];initmind=[REF(player)]'>Init Mind</a> - " if (iscyborg(player)) - body += "<a href='?_src_=holder;[HrefToken()];borgpanel=[REF(player)]'>BP</a> - " - body += "<a href='?priv_msg=[player.ckey]'>PM</a> - " - body += "<a href='?_src_=holder;[HrefToken()];subtlemessage=[REF(player)]'>SM</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];borgpanel=[REF(player)]'>BP</a> - " + body += "<a href='byond://?priv_msg=[player.ckey]'>PM</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];subtlemessage=[REF(player)]'>SM</a> - " if (ishuman(player) && player.mind) - body += "<a href='?_src_=holder;[HrefToken()];HeadsetMessage=[REF(player)]'>HM</a> - " - body += "<a href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(player)]'>FLW</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];HeadsetMessage=[REF(player)]'>HM</a> - " + body += "<a href='byond://?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(player)]'>FLW</a> - " //Default to client logs if available var/source = LOGSRC_MOB if(player.ckey) source = LOGSRC_CKEY - body += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(player)];log_src=[source]'>LOGS</a>\] <br>" + body += "<a href='byond://?_src_=holder;[HrefToken()];individuallog=[REF(player)];log_src=[source]'>LOGS</a>\] <br>" body += "<b>Mob type</b> = [player.type]<br><br>" @@ -71,37 +71,37 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_ADMIN, "Show Player Panel", mo body += "<i>None?!</i>" body += "<br><br>" - body += "<A href='?_src_=holder;[HrefToken()];boot2=[REF(player)]'>Kick</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];boot2=[REF(player)]'>Kick</A> | " if(player.client) - body += "<A href='?_src_=holder;[HrefToken()];newbankey=[player.key];newbanip=[player.client.address];newbancid=[player.client.computer_id]'>Ban</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];newbankey=[player.key];newbanip=[player.client.address];newbancid=[player.client.computer_id]'>Ban</A> | " else - body += "<A href='?_src_=holder;[HrefToken()];newbankey=[player.key]'>Ban</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];newbankey=[player.key]'>Ban</A> | " - body += "<A href='?_src_=holder;[HrefToken()];showmessageckey=[player.ckey]'>Notes | Messages | Watchlist</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];showmessageckey=[player.ckey]'>Notes | Messages | Watchlist</A> | " if(player.client) - body += "| <A href='?_src_=holder;[HrefToken()];sendtoprison=[REF(player)]'>Prison</A> | " - body += "\ <A href='?_src_=holder;[HrefToken()];sendbacktolobby=[REF(player)]'>Send back to Lobby</A> | " + body += "| <A href='byond://?_src_=holder;[HrefToken()];sendtoprison=[REF(player)]'>Prison</A> | " + body += "\ <A href='byond://?_src_=holder;[HrefToken()];sendbacktolobby=[REF(player)]'>Send back to Lobby</A> | " var/muted = player.client.prefs.muted body += "<br><b>Mute: </b> " - body += "\[<A href='?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_IC]'><font color='[(muted & MUTE_IC)?"red":"blue"]'>IC</font></a> | " - body += "<A href='?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_OOC]'><font color='[(muted & MUTE_OOC)?"red":"blue"]'>OOC</font></a> | " - body += "<A href='?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_PRAY]'><font color='[(muted & MUTE_PRAY)?"red":"blue"]'>PRAY</font></a> | " - body += "<A href='?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_ADMINHELP]'><font color='[(muted & MUTE_ADMINHELP)?"red":"blue"]'>ADMINHELP</font></a> | " - body += "<A href='?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_INTERNET_REQUEST]'><font color='[(muted & MUTE_INTERNET_REQUEST)?"red":"blue"]'>WEBREQ</font></a> | " - body += "<A href='?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_DEADCHAT]'><font color='[(muted & MUTE_DEADCHAT)?"red":"blue"]'>DEADCHAT</font></a>\]" - body += "(<A href='?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_ALL]'><font color='[(muted & MUTE_ALL)?"red":"blue"]'>toggle all</font></a>)" + body += "\[<A href='byond://?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_IC]'><font color='[(muted & MUTE_IC)?"red":"blue"]'>IC</font></a> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_OOC]'><font color='[(muted & MUTE_OOC)?"red":"blue"]'>OOC</font></a> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_PRAY]'><font color='[(muted & MUTE_PRAY)?"red":"blue"]'>PRAY</font></a> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_ADMINHELP]'><font color='[(muted & MUTE_ADMINHELP)?"red":"blue"]'>ADMINHELP</font></a> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_INTERNET_REQUEST]'><font color='[(muted & MUTE_INTERNET_REQUEST)?"red":"blue"]'>WEBREQ</font></a> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_DEADCHAT]'><font color='[(muted & MUTE_DEADCHAT)?"red":"blue"]'>DEADCHAT</font></a>\]" + body += "(<A href='byond://?_src_=holder;[HrefToken()];mute=[player.ckey];mute_type=[MUTE_ALL]'><font color='[(muted & MUTE_ALL)?"red":"blue"]'>toggle all</font></a>)" body += "<br><br>" - body += "<A href='?_src_=holder;[HrefToken()];jumpto=[REF(player)]'><b>Jump to</b></A> | " - body += "<A href='?_src_=holder;[HrefToken()];getmob=[REF(player)]'>Get</A> | " - body += "<A href='?_src_=holder;[HrefToken()];sendmob=[REF(player)]'>Send To</A>" + body += "<A href='byond://?_src_=holder;[HrefToken()];jumpto=[REF(player)]'><b>Jump to</b></A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];getmob=[REF(player)]'>Get</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];sendmob=[REF(player)]'>Send To</A>" body += "<br><br>" - body += "<A href='?_src_=holder;[HrefToken()];traitor=[REF(player)]'>Traitor panel</A> | " - body += "<A href='?_src_=holder;[HrefToken()];narrateto=[REF(player)]'>Narrate to</A> | " - body += "<A href='?_src_=holder;[HrefToken()];subtlemessage=[REF(player)]'>Subtle message</A> | " - body += "<A href='?_src_=holder;[HrefToken()];playsoundto=[REF(player)]'>Play sound to</A> | " - body += "<A href='?_src_=holder;[HrefToken()];languagemenu=[REF(player)]'>Language Menu</A>" + body += "<A href='byond://?_src_=holder;[HrefToken()];traitor=[REF(player)]'>Traitor panel</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];narrateto=[REF(player)]'>Narrate to</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];subtlemessage=[REF(player)]'>Subtle message</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];playsoundto=[REF(player)]'>Play sound to</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];languagemenu=[REF(player)]'>Language Menu</A>" if(player.client) if(!isnewplayer(player)) @@ -110,39 +110,39 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_ADMIN, "Show Player Panel", mo if(isobserver(player)) body += "<b>Ghost</b> | " else - body += "<A href='?_src_=holder;[HrefToken()];simplemake=observer;mob=[REF(player)]'>Make Ghost</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];simplemake=observer;mob=[REF(player)]'>Make Ghost</A> | " if(ishuman(player) && !ismonkey(player)) body += "<b>Human</b> | " else - body += "<A href='?_src_=holder;[HrefToken()];simplemake=human;mob=[REF(player)]'>Make Human</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;mob=[REF(player)]'>Make Human</A> | " if(ismonkey(player)) body += "<b>Monkey</b> | " else - body += "<A href='?_src_=holder;[HrefToken()];simplemake=monkey;mob=[REF(player)]'>Make Monkey</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];simplemake=monkey;mob=[REF(player)]'>Make Monkey</A> | " if(iscyborg(player)) body += "<b>Cyborg</b> | " else - body += "<A href='?_src_=holder;[HrefToken()];simplemake=robot;mob=[REF(player)]'>Make Cyborg</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];simplemake=robot;mob=[REF(player)]'>Make Cyborg</A> | " if(isAI(player)) body += "<b>AI</b>" else - body += "<A href='?_src_=holder;[HrefToken()];makeai=[REF(player)]'>Make AI</A>" + body += "<A href='byond://?_src_=holder;[HrefToken()];makeai=[REF(player)]'>Make AI</A>" body += "<br><br>" body += "<b>Other actions:</b>" body += "<br>" if(!isnewplayer(player)) - body += "<A href='?_src_=holder;[HrefToken()];forcespeech=[REF(player)]'>Forcesay</A> | " - body += "<A href='?_src_=holder;[HrefToken()];applyquirks=[REF(player)]'>Apply Client Quirks</A> | " - body += "<A href='?_src_=holder;[HrefToken()];tdome1=[REF(player)]'>Thunderdome 1</A> | " - body += "<A href='?_src_=holder;[HrefToken()];tdome2=[REF(player)]'>Thunderdome 2</A> | " - body += "<A href='?_src_=holder;[HrefToken()];tdomeadmin=[REF(player)]'>Thunderdome Admin</A> | " - body += "<A href='?_src_=holder;[HrefToken()];tdomeobserve=[REF(player)]'>Thunderdome Observer</A> | " - body += "<A href='?_src_=holder;[HrefToken()];admincommend=[REF(player)]'>Commend Behavior</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];forcespeech=[REF(player)]'>Forcesay</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];applyquirks=[REF(player)]'>Apply Client Quirks</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];tdome1=[REF(player)]'>Thunderdome 1</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];tdome2=[REF(player)]'>Thunderdome 2</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];tdomeadmin=[REF(player)]'>Thunderdome Admin</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];tdomeobserve=[REF(player)]'>Thunderdome Observer</A> | " + body += "<A href='byond://?_src_=holder;[HrefToken()];admincommend=[REF(player)]'>Commend Behavior</A> | " body += "<br>" body += "</body></html>" @@ -325,15 +325,15 @@ ADMIN_VERB(manage_job_slots, R_ADMIN, "Manage Job Slots", "Manage the number of dat += "</td>" dat += "<td>" if(job.total_positions >= 0) - dat += "<A href='?src=[REF(src)];[HrefToken()];customjobslot=[job.title]'>Custom</A> | " - dat += "<A href='?src=[REF(src)];[HrefToken()];addjobslot=[job.title]'>Add 1</A> | " + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];customjobslot=[job.title]'>Custom</A> | " + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];addjobslot=[job.title]'>Add 1</A> | " if(job.total_positions > job.current_positions) - dat += "<A href='?src=[REF(src)];[HrefToken()];removejobslot=[job.title]'>Remove</A> | " + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];removejobslot=[job.title]'>Remove</A> | " else dat += "Remove | " - dat += "<A href='?src=[REF(src)];[HrefToken()];unlimitjobslot=[job.title]'>Unlimit</A></td>" + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];unlimitjobslot=[job.title]'>Unlimit</A></td>" else - dat += "<A href='?src=[REF(src)];[HrefToken()];limitjobslot=[job.title]'>Limit</A></td>" + dat += "<A href='byond://?src=[REF(src)];[HrefToken()];limitjobslot=[job.title]'>Limit</A></td>" browser.height = min(100 + count * 20, 650) browser.set_content(dat.Join()) @@ -417,20 +417,20 @@ ADMIN_VERB(lag_switch_panel, R_ADMIN, "Show Lag Switches", "Display the controls to_chat(user, span_notice("The Lag Switch subsystem has not yet been initialized.")) return var/list/dat = list("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Lag Switches</title></head><body><h2><B>Lag (Reduction) Switches</B></h2>") - dat += "Automatic Trigger: <a href='?_src_=holder;[HrefToken()];change_lag_switch_option=TOGGLE_AUTO'><b>[SSlag_switch.auto_switch ? "On" : "Off"]</b></a><br/>" - dat += "Population Threshold: <a href='?_src_=holder;[HrefToken()];change_lag_switch_option=NUM'><b>[SSlag_switch.trigger_pop]</b></a><br/>" - dat += "Slowmode Cooldown (toggle On/Off below): <a href='?_src_=holder;[HrefToken()];change_lag_switch_option=SLOWCOOL'><b>[SSlag_switch.slowmode_cooldown/10] seconds</b></a><br/>" - dat += "<br/><b>SET ALL MEASURES: <a href='?_src_=holder;[HrefToken()];change_lag_switch=ALL_ON'>ON</a> | <a href='?_src_=holder;[HrefToken()];change_lag_switch=ALL_OFF'>OFF</a></b><br/>" - dat += "<br/>Disable ghosts zoom and t-ray verbs (except staff): <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_GHOST_ZOOM_TRAY]'><b>[SSlag_switch.measures[DISABLE_GHOST_ZOOM_TRAY] ? "On" : "Off"]</b></a><br/>" - dat += "Disable late joining: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_NON_OBSJOBS]'><b>[SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "On" : "Off"]</b></a><br/>" + dat += "Automatic Trigger: <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch_option=TOGGLE_AUTO'><b>[SSlag_switch.auto_switch ? "On" : "Off"]</b></a><br/>" + dat += "Population Threshold: <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch_option=NUM'><b>[SSlag_switch.trigger_pop]</b></a><br/>" + dat += "Slowmode Cooldown (toggle On/Off below): <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch_option=SLOWCOOL'><b>[SSlag_switch.slowmode_cooldown/10] seconds</b></a><br/>" + dat += "<br/><b>SET ALL MEASURES: <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=ALL_ON'>ON</a> | <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=ALL_OFF'>OFF</a></b><br/>" + dat += "<br/>Disable ghosts zoom and t-ray verbs (except staff): <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_GHOST_ZOOM_TRAY]'><b>[SSlag_switch.measures[DISABLE_GHOST_ZOOM_TRAY] ? "On" : "Off"]</b></a><br/>" + dat += "Disable late joining: <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_NON_OBSJOBS]'><b>[SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "On" : "Off"]</b></a><br/>" dat += "<br/>============! MAD GHOSTS ZONE !============<br/>" - dat += "Disable deadmob keyLoop (except staff, informs dchat): <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_DEAD_KEYLOOP]'><b>[SSlag_switch.measures[DISABLE_DEAD_KEYLOOP] ? "On" : "Off"]</b></a><br/>" + dat += "Disable deadmob keyLoop (except staff, informs dchat): <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_DEAD_KEYLOOP]'><b>[SSlag_switch.measures[DISABLE_DEAD_KEYLOOP] ? "On" : "Off"]</b></a><br/>" dat += "==========================================<br/>" dat += "<br/><b>Measures below can be bypassed with a <abbr title='TRAIT_BYPASS_MEASURES'><u>special trait</u></abbr></b><br/>" - dat += "Slowmode say verb (informs world): <a href='?_src_=holder;[HrefToken()];change_lag_switch=[SLOWMODE_SAY]'><b>[SSlag_switch.measures[SLOWMODE_SAY] ? "On" : "Off"]</b></a><br/>" - dat += "Disable runechat: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_RUNECHAT]'><b>[SSlag_switch.measures[DISABLE_RUNECHAT] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to speaker</span><br/>" - dat += "Disable examine icons: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_USR_ICON2HTML]'><b>[SSlag_switch.measures[DISABLE_USR_ICON2HTML] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to examiner</span><br/>" - dat += "Disable parallax: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_PARALLAX]'><b>[SSlag_switch.measures[DISABLE_PARALLAX] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to character</span><br />" - dat += "Disable footsteps: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_FOOTSTEPS]'><b>[SSlag_switch.measures[DISABLE_FOOTSTEPS] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to character</span><br />" + dat += "Slowmode say verb (informs world): <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=[SLOWMODE_SAY]'><b>[SSlag_switch.measures[SLOWMODE_SAY] ? "On" : "Off"]</b></a><br/>" + dat += "Disable runechat: <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_RUNECHAT]'><b>[SSlag_switch.measures[DISABLE_RUNECHAT] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to speaker</span><br/>" + dat += "Disable examine icons: <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_USR_ICON2HTML]'><b>[SSlag_switch.measures[DISABLE_USR_ICON2HTML] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to examiner</span><br/>" + dat += "Disable parallax: <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_PARALLAX]'><b>[SSlag_switch.measures[DISABLE_PARALLAX] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to character</span><br />" + dat += "Disable footsteps: <a href='byond://?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_FOOTSTEPS]'><b>[SSlag_switch.measures[DISABLE_FOOTSTEPS] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to character</span><br />" dat += "</body></html>" user << browse(dat.Join(), "window=lag_switch_panel;size=420x480") diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 70d3ab342edce..ce3dcbd5c6ed7 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -84,10 +84,10 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(!l2b) return var/list/dat = list("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>[title]</title></head>") - dat += "<A href='?_src_=holder;[HrefToken()];ahelp_tickets=[state]'>Refresh</A><br><br>" + dat += "<A href='byond://?_src_=holder;[HrefToken()];ahelp_tickets=[state]'>Refresh</A><br><br>" for(var/I in l2b) var/datum/admin_help/AH = I - dat += "[span_adminnotice("[span_adminhelp("Ticket #[AH.id]")]: <A href='?_src_=holder;[HrefToken()];ahelp=[REF(AH)];ahelp_action=ticket'>[AH.initiator_key_name]: [AH.name]</A>")]<br>" + dat += "[span_adminnotice("[span_adminhelp("Ticket #[AH.id]")]: <A href='byond://?_src_=holder;[HrefToken()];ahelp=[REF(AH)];ahelp_action=ticket'>[AH.initiator_key_name]: [AH.name]</A>")]<br>" usr << browse(dat.Join(), "window=ahelp_list[state];size=600x480") @@ -370,32 +370,32 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(!ref_src) ref_src = "[REF(src)]" . = ADMIN_FULLMONTY_NONAME(initiator.mob) - . += " (<A href='?_src_=holder;[HrefToken()];showmessageckey=[initiator.ckey]'>NOTES</A>)" + . += " (<A href='byond://?_src_=holder;[HrefToken()];showmessageckey=[initiator.ckey]'>NOTES</A>)" if(state == AHELP_ACTIVE) if (CONFIG_GET(flag/popup_admin_pm)) - . += " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminpopup=[REF(initiator)]'>POPUP</A>)" + . += " (<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminpopup=[REF(initiator)]'>POPUP</A>)" . += ClosureLinks(ref_src) //private /datum/admin_help/proc/ClosureLinks(ref_src) if(!ref_src) ref_src = "[REF(src)]" - . = " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=reject'>REJT</A>)" - . += " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=icissue'>IC</A>)" - . += " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=close'>CLOSE</A>)" - . += " (<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=resolve'>RSLVE</A>)" + . = " (<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=reject'>REJT</A>)" + . += " (<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=icissue'>IC</A>)" + . += " (<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=close'>CLOSE</A>)" + . += " (<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=resolve'>RSLVE</A>)" //private /datum/admin_help/proc/LinkedReplyName(ref_src) if(!ref_src) ref_src = "[REF(src)]" - return "<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=reply'>[initiator_key_name]</A>" + return "<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=reply'>[initiator_key_name]</A>" //private /datum/admin_help/proc/TicketHref(msg, ref_src, action = "ticket") if(!ref_src) ref_src = "[REF(src)]" - return "<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=[action]'>[msg]</A>" + return "<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[ref_src];ahelp_action=[action]'>[msg]</A>" //message from the initiator without a target, all admins will see this //won't bug irc/discord @@ -403,7 +403,12 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) var/ref_src = "[REF(src)]" //Message to be sent to all admins - var/admin_msg = span_adminnotice(span_adminhelp("Ticket [TicketHref("#[id]", ref_src)]</span><b>: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]:</b> [span_linkify(keywords_lookup(msg))]")) + var/admin_msg = fieldset_block( + span_adminhelp("Ticket [TicketHref("#[id]", ref_src)]"), + "<b>[LinkedReplyName(ref_src)]</b>\n\n\ + [span_linkify(keywords_lookup(msg))]\n\n\ + <b class='smaller'>[FullMonty(ref_src)]</b>", + "boxed_message red_box") AddInteraction("<font color='red'>[LinkedReplyName(ref_src)]: [msg]</font>", player_message = "<font color='red'>[LinkedReplyName(ref_src)]: [msg]</font>") log_admin_private("Ticket #[id]: [key_name(initiator)]: [msg]") @@ -575,7 +580,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) // Helper for opening directly to player ticket history dat += "<br><br><b>Player Ticket History:</b>" - dat += "[FOURSPACES]<A href='?_src_=holder;[HrefToken()];player_ticket_history=[initiator_ckey]'>Open</A>" + dat += "[FOURSPACES]<A href='byond://?_src_=holder;[HrefToken()];player_ticket_history=[initiator_ckey]'>Open</A>" // Append any tickets also opened by this user if relevant var/list/related_tickets = GLOB.ahelp_tickets.TicketsByCKey(initiator_ckey) @@ -659,7 +664,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) dat += "CLOSED</b>" else dat += "UNKNOWN</b>" - dat += "\n[FOURSPACES]<A href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];player_ticket_panel=1'>Refresh</A>" + dat += "\n[FOURSPACES]<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];player_ticket_panel=1'>Refresh</A>" dat += "<br><br>Opened at: [gameTimestamp("hh:mm:ss", opened_at)] (Approx [DisplayTimeText(world.time - opened_at)] ago)" if(closed_at) dat += "<br>Closed at: [gameTimestamp("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - closed_at)] ago)" @@ -801,7 +806,7 @@ GLOBAL_DATUM_INIT(admin_help_ui_handler, /datum/admin_help_ui_handler, new) set category = "Admin" set name = "Adminhelp" GLOB.admin_help_ui_handler.ui_interact(mob) - to_chat(src, span_boldnotice("Adminhelp failing to open or work? <a href='?src=[REF(src)];tguiless_adminhelp=1'>Click here</a>")) + to_chat(src, span_boldnotice("Adminhelp failing to open or work? <a href='byond://?src=[REF(src)];tguiless_adminhelp=1'>Click here</a>")) /client/verb/view_latest_ticket() set category = "Admin" @@ -1020,7 +1025,7 @@ GLOBAL_DATUM_INIT(admin_help_ui_handler, /datum/admin_help_ui_handler, new) if(is_special_character(found)) is_antag = 1 founds += "Name: [found.name]([found.real_name]) Key: [found.key] Ckey: [found.ckey] [is_antag ? "(Antag)" : null] " - msg += "[original_word]<font size='1' color='[is_antag ? "red" : "black"]'>(<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminmoreinfo=[REF(found)]'>?</A>|<A HREF='?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminplayerobservefollow=[REF(found)]'>F</A>)</font> " + msg += "[original_word]<font size='1' color='[is_antag ? "red" : "black"]'>(<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminmoreinfo=[REF(found)]'>?</A>|<A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];adminplayerobservefollow=[REF(found)]'>F</A>)</font> " continue msg += "[original_word] " if(external) @@ -1103,7 +1108,7 @@ GLOBAL_DATUM_INIT(admin_help_ui_handler, /datum/admin_help_ui_handler, new) var/datum/datum_check = locate(word_with_brackets) if(!istype(datum_check)) continue - msglist[i] = "<u><a href='?_src_=vars;[HrefToken(forceGlobal = TRUE)];Vars=[word_with_brackets]'>[word]</A></u>" + msglist[i] = "<u><a href='byond://?_src_=vars;[HrefToken(forceGlobal = TRUE)];Vars=[word_with_brackets]'>[word]</A></u>" modified = TRUE if("#") // check if we're linking a ticket @@ -1124,7 +1129,7 @@ GLOBAL_DATUM_INIT(admin_help_ui_handler, /datum/admin_help_ui_handler, new) if(AHELP_RESOLVED) state_word = "Resolved" - msglist[i]= "<u><A href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[REF(ahelp_check)];ahelp_action=ticket'>[word] ([state_word] | [ahelp_check.initiator_key_name])</A></u>" + msglist[i]= "<u><A href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];ahelp=[REF(ahelp_check)];ahelp_action=ticket'>[word] ([state_word] | [ahelp_check.initiator_key_name])</A></u>" modified = TRUE if(modified) diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index abbcbb62ab648..5d2598fc0f7d5 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -387,20 +387,11 @@ ADMIN_VERB(cmd_admin_pm_panel, R_NONE, "Admin PM", "Show a list of clients to PM recipient_ticket_id = recipient_ticket?.id SSblackbox.LogAhelp(recipient_ticket_id, "Ticket Opened", send_message, recipient.ckey, src.ckey) - to_chat(recipient, - type = MESSAGE_TYPE_ADMINPM, - html = "<font color='red' size='4'><b>-- Administrator private message --</b></font>", - confidential = TRUE) - recipient.receive_ahelp( link_to_us, span_linkify(send_message), ) - to_chat(recipient, - type = MESSAGE_TYPE_ADMINPM, - html = span_adminsay("<i>Click on the administrator's name to reply.</i>"), - confidential = TRUE) to_chat(src, type = MESSAGE_TYPE_ADMINPM, html = span_notice("Admin PM to-<b>[their_name_with_link]</b>: [span_linkify(send_message)]"), @@ -707,21 +698,11 @@ ADMIN_VERB(cmd_admin_pm_panel, R_NONE, "Admin PM", "Show a list of clients to PM message_admins("External message from [sender] to [recipient_name_linked] : [message]") log_admin_private("External PM: [sender] -> [recipient_name] : [message]") - to_chat(recipient, - type = MESSAGE_TYPE_ADMINPM, - html = "<font color='red' size='4'><b>-- Administrator private message --</b></font>", - confidential = TRUE) - recipient.receive_ahelp( - "<a href='?priv_msg=[stealthkey]'>[adminname]</a>", + "<a href='byond://?priv_msg=[stealthkey]'>[adminname]</a>", message, ) - to_chat(recipient, - type = MESSAGE_TYPE_ADMINPM, - html = span_adminsay("<i>Click on the administrator's name to reply.</i>"), - confidential = TRUE) - admin_ticket_log(recipient, "<font color='purple'>PM From [tgs_tagged]: [message]</font>", log_in_blackbox = FALSE) window_flash(recipient, ignorepref = TRUE) @@ -766,8 +747,13 @@ ADMIN_VERB(cmd_admin_pm_panel, R_NONE, "Admin PM", "Show a list of clients to PM to_chat( src, type = MESSAGE_TYPE_ADMINPM, - html = "<span class='[span_class]'>Admin PM from-<b>[reply_to]</b>: [message]</span>", - confidential = TRUE, + html = fieldset_block( + span_adminhelp("Administrator private message"), + "<span class='[span_class]'>Admin PM from-<b>[reply_to]</b></span>\n\n\ + <span class='[span_class]'>[message]</span>\n\n\ + <i class='adminsay'>Click on the administrator's name to reply.</i>", + "boxed_message red_box"), + confidential = TRUE ) current_ticket?.player_replied = FALSE diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 13f1995c9ba3d..804613f3f1b36 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -480,8 +480,8 @@ ADMIN_VERB(modify_goals, R_ADMIN, "Modify Goals", "Modify the station goals for /datum/admins/proc/modify_goals() var/dat = "" for(var/datum/station_goal/goal as anything in SSstation.get_station_goals()) - dat += "[goal.name] - <a href='?src=[REF(goal)];[HrefToken()];announce=1'>Announce</a> | <a href='?src=[REF(goal)];[HrefToken()];remove=1'>Remove</a><br>" - dat += "<br><a href='?src=[REF(src)];[HrefToken()];add_station_goal=1'>Add New Goal</a>" + dat += "[goal.name] - <a href='byond://?src=[REF(goal)];[HrefToken()];announce=1'>Announce</a> | <a href='byond://?src=[REF(goal)];[HrefToken()];remove=1'>Remove</a><br>" + dat += "<br><a href='byond://?src=[REF(src)];[HrefToken()];add_station_goal=1'>Add New Goal</a>" usr << browse(dat, "window=goals;size=400x400") ADMIN_VERB(debug_mob_lists, R_DEBUG, "Debug Mob Lists", "For when you just gotta know.", ADMIN_CATEGORY_DEBUG) @@ -743,6 +743,14 @@ ADMIN_VERB(reestablish_tts_connection, R_DEBUG, "Re-establish Connection To TTS" message_admins("[key_name_admin(user)] successfully re-established the connection to the TTS HTTP server.") log_admin("[key_name(user)] successfully re-established the connection to the TTS HTTP server.") +ADMIN_VERB(allow_browser_inspect, R_DEBUG, "Allow Browser Inspect", "Allow browser debugging via inspect", ADMIN_CATEGORY_DEBUG) + if(user.byond_version < 516) + to_chat(user, span_warning("You can only use this on 516!")) + return + + to_chat(user, span_notice("You can now right click to use inspect on browsers.")) + winset(user, null, list("browser-options" = "+devtools")) + /proc/generate_timer_source_output(list/datum/timedevent/events) var/list/per_source = list() diff --git a/code/modules/admin/verbs/individual_logging.dm b/code/modules/admin/verbs/individual_logging.dm index d9df055ba1bb3..eb665d35f658e 100644 --- a/code/modules/admin/verbs/individual_logging.dm +++ b/code/modules/admin/verbs/individual_logging.dm @@ -75,4 +75,4 @@ slabel = "<b>\[[label]\]</b>" //This is necessary because num2text drops digits and rounds on big numbers. If more defines get added in the future it could break again. log_type = num2text(log_type, MAX_BITFLAG_DIGITS) - return "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[log_type];log_src=[log_src]'>[slabel]</a>" + return "<a href='byond://?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[log_type];log_src=[log_src]'>[slabel]</a>" diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm index a27aca0f0147b..3251e9febd27c 100644 --- a/code/modules/admin/verbs/map_template_loadverb.dm +++ b/code/modules/admin/verbs/map_template_loadverb.dm @@ -61,8 +61,8 @@ ADMIN_VERB(map_template_upload, R_DEBUG, "Map Template - Upload", "Upload a map var/report_link if(report) report.show_to(user) - report_link = " - <a href='?src=[REF(report)];[HrefToken(forceGlobal = TRUE)];show=1'>validation report</a>" - to_chat(user, span_warning("Map template '[map]' <a href='?src=[REF(report)];[HrefToken()];show=1'>failed validation</a>."), confidential = TRUE) + report_link = " - <a href='byond://?src=[REF(report)];[HrefToken(forceGlobal = TRUE)];show=1'>validation report</a>" + to_chat(user, span_warning("Map template '[map]' <a href='byond://?src=[REF(report)];[HrefToken()];show=1'>failed validation</a>."), confidential = TRUE) if(report.loadable) var/response = tgui_alert(user, "The map failed validation, would you like to load it anyways?", "Map Errors", list("Cancel", "Upload Anyways")) if(response != "Upload Anyways") diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 8504cd5262cab..73196dbcdb1b6 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -84,7 +84,7 @@ ADMIN_VERB(show_map_reports, R_DEBUG, "Show Map Reports", "Displays a list of ma var/dat = {"<b>List of all map reports:</b><br>"} for(var/datum/map_report/report as anything in GLOB.map_reports) - dat += "[report.tag] ([report.original_path]) - <a href='?src=[REF(report)];[HrefToken()];show=1'>View</a><br>" + dat += "[report.tag] ([report.original_path]) - <a href='byond://?src=[REF(report)];[HrefToken()];show=1'>View</a><br>" user << browse(dat, "window=map_reports") @@ -224,7 +224,7 @@ ADMIN_VERB(create_mapping_job_icons, R_DEBUG, "Generate job landmarks icons", "G ADMIN_VERB_VISIBILITY(debug_z_levels, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) ADMIN_VERB(debug_z_levels, R_DEBUG, "Debug Z-Levels", "Displays a list of all z-levels and their linkages.", ADMIN_CATEGORY_MAPPING) - to_chat(user, examine_block(gather_z_level_information(append_grid = TRUE)), confidential = TRUE) + to_chat(user, boxed_message(gather_z_level_information(append_grid = TRUE)), confidential = TRUE) /// Returns all necessary z-level information. Argument `append_grid` allows the user to see a table showing all of the z-level linkages, which is only visible and useful in-game. /proc/gather_z_level_information(append_grid = FALSE) diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm index 64fe59afd8e85..fc7ba89a0acd3 100644 --- a/code/modules/admin/verbs/secrets.dm +++ b/code/modules/admin/verbs/secrets.dm @@ -348,6 +348,34 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w priority_announce("Принцип неагрессивности действует в полную силу. Любое проявление агрессии запрещено.", null, SSstation.announcer.get_rand_report_sound()) else priority_announce("Принцип неагрессивности отменен.", null, SSstation.announcer.get_rand_report_sound()) + if("send_shuttle_back") + if (!is_funmin) + return + if (SSshuttle.emergency.mode != SHUTTLE_ESCAPE) + to_chat(usr, span_warning("Emergency shuttle not currently in transit!"), confidential = TRUE) + return + var/make_announcement = tgui_alert(usr, "Make a CentCom announcement?", "Emergency shuttle return", list("Yes", "Custom Text", "No")) || "No" + var/announcement_text = "Траектория эвакуационного шаттла изменена, перенаправление курса обратно на [station_name()]." + if (make_announcement == "Custom Text") + announcement_text = tgui_input_text(usr, "Custom CentCom announcement", "Emergency shuttle return", multiline = TRUE) || announcement_text + var/new_timer = tgui_input_number(usr, "How long should the shuttle remain in transit?", "When are we droppin' boys?", 180, 600) + if (isnull(new_timer) || SSshuttle.emergency.mode != SHUTTLE_ESCAPE) + return + SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Send Shuttle Back")) + message_admins("[key_name_admin(holder)] sent the escape shuttle back to the station") + if (make_announcement != "No") + priority_announce( + text = announcement_text, + title = "Принудительное изменение траектории шаттла", + sound = 'sound/announcer/announcement/announce_dig.ogg', + sender_override = "Система оповещения эвакуационного шаттла", + color_override = "grey", + ) + SSshuttle.emergency.timer = INFINITY + if (new_timer > 0) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(return_escape_shuttle), make_announcement), new_timer SECONDS) + else + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(return_escape_shuttle), make_announcement) if("blackout") if(!is_funmin) return @@ -673,6 +701,27 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w T.flick_overlay_static(portal_appearance[GET_TURF_PLANE_OFFSET(T) + 1], 15) playsound(T, 'sound/effects/magic/lightningbolt.ogg', rand(80, 100), TRUE) +/// Docks the emergency shuttle back to the station and resets its' state +/proc/return_escape_shuttle(make_announcement) + if (SSshuttle.emergency.initiate_docking(SSshuttle.getDock("emergency_home"), force = TRUE) != DOCKING_SUCCESS) + message_admins("Emergency shuttle was unable to dock back to the station!") + SSshuttle.emergency.timer = 1 // Prevents softlocks + return + if (make_announcement != "No") + priority_announce( + text = "[SSshuttle.emergency] has returned to the station.", + title = "Emergency Shuttle Override", + sound = ANNOUNCER_SHUTTLEDOCK, + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "grey", + ) + SSshuttle.emergency.mode = SHUTTLE_IDLE + SSshuttle.emergency.timer = 0 + // Docks the pods back (don't ask about physics) + for (var/obj/docking_port/mobile/pod/pod in SSshuttle.mobile_docking_ports) + if (pod.previous) + pod.initiate_docking(pod.previous, force = TRUE) + /datum/everyone_is_an_antag_controller var/chosen_antag = "" var/objective = "" diff --git a/code/modules/admin/verbs/server.dm b/code/modules/admin/verbs/server.dm index 5ac9fd272b45c..133d36c3dd0f0 100644 --- a/code/modules/admin/verbs/server.dm +++ b/code/modules/admin/verbs/server.dm @@ -66,6 +66,12 @@ ADMIN_VERB(restart, R_SERVER, "Reboot World", "Restarts the world immediately.", #undef HARDEST_RESTART #undef TGS_RESTART +ADMIN_VERB(cancel_reboot, R_SERVER, "Cancel Reboot", "Cancels a pending world reboot.", ADMIN_CATEGORY_SERVER) + if(!SSticker.cancel_reboot(user)) + return + log_admin("[key_name(user)] cancelled the pending world reboot.") + message_admins("[key_name_admin(user)] cancelled the pending world reboot.") + ADMIN_VERB(end_round, R_SERVER, "End Round", "Forcibly ends the round and allows the server to restart normally.", ADMIN_CATEGORY_SERVER) var/confirm = tgui_alert(user, "End the round and restart the game world?", "End Round", list("Yes", "Cancel")) if(confirm != "Yes") @@ -131,6 +137,8 @@ ADMIN_VERB(delay_round_end, R_SERVER, "Delay Round End", "Prevent the server fro SSticker.delay_end = TRUE SSticker.admin_delay_notice = delay_reason + if(SSticker.reboot_timer) + SSticker.cancel_reboot(user) log_admin("[key_name(user)] delayed the round end for reason: [SSticker.admin_delay_notice]") message_admins("[key_name_admin(user)] delayed the round end for reason: [SSticker.admin_delay_notice]") diff --git a/code/modules/admin/view_variables/debug_variable_appearance.dm b/code/modules/admin/view_variables/debug_variable_appearance.dm index c5a367e83a064..537ef5e611b51 100644 --- a/code/modules/admin/view_variables/debug_variable_appearance.dm +++ b/code/modules/admin/view_variables/debug_variable_appearance.dm @@ -23,7 +23,7 @@ display_value = "[display_value]:[icon_state]" var/display_ref = get_vv_link_ref() - return "<a href='?_src_=vars;[HrefToken()];Vars=[display_ref]'>[display_name] (<span class='value'>[display_value]</span>) [display_ref]</a>" + return "<a href='byond://?_src_=vars;[HrefToken()];Vars=[display_ref]'>[display_name] (<span class='value'>[display_value]</span>) [display_ref]</a>" /// Returns the ref string to use when displaying this image in the vv menu of something else /image/proc/get_vv_link_ref() diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index 835da1a0b39cb..b776f1b5d7974 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -18,10 +18,10 @@ var/name_part = VV_HTML_ENCODE(name) if(level > 0 || islist(owner)) //handling keys in assoc lists if(istype(name,/datum)) - name_part = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(name)]'>[VV_HTML_ENCODE(name)] [REF(name)]</a>" + name_part = "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(name)]'>[VV_HTML_ENCODE(name)] [REF(name)]</a>" else if(islist(name)) var/list/list_value = name - name_part = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(name)]'> /list ([length(list_value)]) [REF(name)]</a>" + name_part = "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(name)]'> /list ([length(list_value)]) [REF(name)]</a>" . = "[.][name_part] = " @@ -85,9 +85,9 @@ items += debug_variable(key, val, level + 1, sanitize = sanitize) - return "<a href='?_src_=vars;[HrefToken()];[link_vars]'>/list ([list_value.len])</a><ul>[items.Join()]</ul>" + return "<a href='byond://?_src_=vars;[HrefToken()];[link_vars]'>/list ([list_value.len])</a><ul>[items.Join()]</ul>" else - return "<a href='?_src_=vars;[HrefToken()];[link_vars]'>/list ([list_value.len])</a>" + return "<a href='byond://?_src_=vars;[HrefToken()];[link_vars]'>/list ([list_value.len])</a>" if(name in GLOB.bitfields) var/list/flags = list() @@ -103,13 +103,13 @@ /datum/proc/debug_variable_value(name, level, datum/owner, sanitize, display_flags) if("[src]" != "[type]") // If we have a name var, let's use it. - return "<a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>[src] [type] [REF(src)]</a>" + return "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(src)]'>[src] [type] [REF(src)]</a>" else - return "<a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>[type] [REF(src)]</a>" + return "<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(src)]'>[type] [REF(src)]</a>" /datum/weakref/debug_variable_value(name, level, datum/owner, sanitize, display_flags) . = ..() - return "[.] <a href='?_src_=vars;[HrefToken()];Vars=[reference]'>(Resolve)</a>" + return "[.] <a href='byond://?_src_=vars;[HrefToken()];Vars=[reference]'>(Resolve)</a>" /matrix/debug_variable_value(name, level, datum/owner, sanitize, display_flags) return {"<span class='value'> diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index 4f36365312701..52b87fda12512 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -37,7 +37,7 @@ if(!target) to_chat(usr, span_warning("The object you tried to expose to [C] no longer exists (nulled or hard-deled)"), confidential = TRUE) return - message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a <a href='?_src_=vars;datumrefresh=[REF(target)]'>VV window</a>") + message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a <a href='byond://?_src_=vars;datumrefresh=[REF(target)]'>VV window</a>") log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [target]") to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window", confidential = TRUE) C.debug_variables(target) diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index 66ac70f3f62f7..fbebccd445981 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -257,7 +257,7 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the </td> <td width='50%'> <div align='center'> - <a id='refresh_link' href='?_src_=vars; + <a id='refresh_link' href='byond://?_src_=vars; datumrefresh=[refid];[HrefToken()]'>Refresh</a> <form> <select name="file" size="1" diff --git a/code/modules/antagonists/clown_ops/outfits.dm b/code/modules/antagonists/clown_ops/outfits.dm index fb025e40dbd20..10793237c33c9 100644 --- a/code/modules/antagonists/clown_ops/outfits.dm +++ b/code/modules/antagonists/clown_ops/outfits.dm @@ -10,6 +10,7 @@ r_pocket = /obj/item/bikehorn id = /obj/item/card/id/advanced/chameleon backpack_contents = list( + /obj/item/gun/ballistic/automatic/pistol/toy/riot/clandestine = 1, //The clown op equivalent to the Ansem /obj/item/pen/edagger = 1, /obj/item/dnainjector/clumsymut = 1, //in case you want to be clumsy for the memes /obj/item/storage/box/syndie_kit/clownpins = 1, //for any guns that you get your grubby little clown op mitts on diff --git a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm index e7182de5cb8d1..0f90761927b2d 100644 --- a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm @@ -226,7 +226,7 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/star_gazer + /datum/pet_command/attack/star_gazer ) /datum/heretic_knowledge/ultimate/cosmic_final/is_valid_sacrifice(mob/living/carbon/human/sacrifice) @@ -242,7 +242,7 @@ star_gazer_mob.maxHealth = INFINITY star_gazer_mob.health = INFINITY user.AddComponent(/datum/component/death_linked, star_gazer_mob) - star_gazer_mob.AddComponent(/datum/component/obeys_commands, star_gazer_commands) + star_gazer_mob.AddComponent(/datum/component/obeys_commands, star_gazer_commands, radial_menu_lifetime = 15 SECONDS, radial_relative_to_user = TRUE) star_gazer_mob.AddComponent(/datum/component/damage_aura, range = 7, burn_damage = 0.5, simple_damage = 0.5, immune_factions = list(FACTION_HERETIC), current_owner = user) star_gazer_mob.befriend(user) var/datum/action/cooldown/open_mob_commands/commands_action = new /datum/action/cooldown/open_mob_commands() diff --git a/code/modules/antagonists/heretic/knowledge/rust_lore.dm b/code/modules/antagonists/heretic/knowledge/rust_lore.dm index 15c5b2fb53aeb..bfbbcde862d29 100644 --- a/code/modules/antagonists/heretic/knowledge/rust_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/rust_lore.dm @@ -287,12 +287,13 @@ return var/need_mob_update = FALSE - need_mob_update += source.adjustBruteLoss(-5, updating_health = FALSE) - need_mob_update += source.adjustFireLoss(-5, updating_health = FALSE) - need_mob_update += source.adjustToxLoss(-5, updating_health = FALSE, forced = TRUE) - need_mob_update += source.adjustOxyLoss(-5, updating_health = FALSE) - need_mob_update += source.adjustStaminaLoss(-20, updating_stamina = FALSE) + var/base_heal_amt = 2.5 * DELTA_WORLD_TIME(SSmobs) + need_mob_update += source.adjustBruteLoss(-base_heal_amt, updating_health = FALSE) + need_mob_update += source.adjustFireLoss(-base_heal_amt, updating_health = FALSE) + need_mob_update += source.adjustToxLoss(-base_heal_amt, updating_health = FALSE, forced = TRUE) + need_mob_update += source.adjustOxyLoss(-base_heal_amt, updating_health = FALSE) + need_mob_update += source.adjustStaminaLoss(-base_heal_amt * 4, updating_stamina = FALSE) if(source.blood_volume < BLOOD_VOLUME_NORMAL) - source.blood_volume += 5 * seconds_per_tick + source.blood_volume += base_heal_amt if(need_mob_update) source.updatehealth() diff --git a/code/modules/antagonists/nukeop/datums/operative_team.dm b/code/modules/antagonists/nukeop/datums/operative_team.dm index b676bda303dd6..ac65a17dc2d8d 100644 --- a/code/modules/antagonists/nukeop/datums/operative_team.dm +++ b/code/modules/antagonists/nukeop/datums/operative_team.dm @@ -90,12 +90,12 @@ while(!isturf(disk_loc)) if(ismob(disk_loc)) var/mob/M = disk_loc - disk_report += "carried by <a href='?_src_=holder;[HrefToken()];adminplayeropts=[REF(M)]'>[M.real_name]</a> " + disk_report += "carried by <a href='byond://?_src_=holder;[HrefToken()];adminplayeropts=[REF(M)]'>[M.real_name]</a> " if(isobj(disk_loc)) var/obj/O = disk_loc disk_report += "in \a [O.name] " disk_loc = disk_loc.loc - disk_report += "in [disk_loc.loc] at ([disk_loc.x], [disk_loc.y], [disk_loc.z])</td><td><a href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(N)]'>FLW</a></td></tr>" + disk_report += "in [disk_loc.loc] at ([disk_loc.x], [disk_loc.y], [disk_loc.z])</td><td><a href='byond://?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(N)]'>FLW</a></td></tr>" disk_report += "</table>" var/post_report @@ -114,12 +114,12 @@ post_report += "<b>War not declared.</b>" var/obj/item/nuclear_challenge/war_button = war_button_ref?.resolve() if(war_button) - force_war_button = "<a href='?_src_=holder;[HrefToken()];force_war=[REF(war_button)]'>\[Force war\]</a>" + force_war_button = "<a href='byond://?_src_=holder;[HrefToken()];force_war=[REF(war_button)]'>\[Force war\]</a>" else force_war_button = "\[Cannot declare war, challenge button missing!\]" post_report += "\n[force_war_button]" - post_report += "\n<a href='?_src_=holder;[HrefToken()];give_reinforcement=[REF(src)]'>\[Send Reinforcement\]</a>" + post_report += "\n<a href='byond://?_src_=holder;[HrefToken()];give_reinforcement=[REF(src)]'>\[Send Reinforcement\]</a>" var/final_report = ..() final_report += disk_report diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index f1dcfa2279096..206bcf105c55c 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -633,14 +633,14 @@ for(var/datum/mind/N as anything in SSjob.get_living_heads()) var/mob/M = N.current if(M) - heads_report += "<tr><td><a href='?_src_=holder;[HrefToken()];adminplayeropts=[REF(M)]'>[M.real_name]</a>[M.client ? "" : " <i>(No Client)</i>"][M.stat == DEAD ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>" - heads_report += "<td><A href='?priv_msg=[M.ckey]'>PM</A></td>" - heads_report += "<td><A href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(M)]'>FLW</a></td>" + heads_report += "<tr><td><a href='byond://?_src_=holder;[HrefToken()];adminplayeropts=[REF(M)]'>[M.real_name]</a>[M.client ? "" : " <i>(No Client)</i>"][M.stat == DEAD ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>" + heads_report += "<td><A href='byond://?priv_msg=[M.ckey]'>PM</A></td>" + heads_report += "<td><A href='byond://?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(M)]'>FLW</a></td>" var/turf/mob_loc = get_turf(M) heads_report += "<td>[mob_loc.loc]</td></tr>" else - heads_report += "<tr><td><a href='?_src_=vars;[HrefToken()];Vars=[REF(N)]'>[N.name]([N.key])</a><i>Head body destroyed!</i></td>" - heads_report += "<td><A href='?priv_msg=[N.key]'>PM</A></td></tr>" + heads_report += "<tr><td><a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(N)]'>[N.name]([N.key])</a><i>Head body destroyed!</i></td>" + heads_report += "<td><A href='byond://?priv_msg=[N.key]'>PM</A></td></tr>" heads_report += "</table>" return common_part + heads_report diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 2f8cbdcfb9f97..e3e0f532acd86 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -131,16 +131,16 @@ /datum/antagonist/traitor/proc/traitor_objective_to_html(datum/traitor_objective/to_display) var/string = "[to_display.name]" if(to_display.objective_state == OBJECTIVE_STATE_ACTIVE || to_display.objective_state == OBJECTIVE_STATE_INACTIVE) - string += " <a href='?src=[REF(owner)];edit_obj_tc=[REF(to_display)]'>[to_display.telecrystal_reward] TC</a>" - string += " <a href='?src=[REF(owner)];edit_obj_pr=[REF(to_display)]'>[to_display.progression_reward] PR</a>" + string += " <a href='byond://?src=[REF(owner)];edit_obj_tc=[REF(to_display)]'>[to_display.telecrystal_reward] TC</a>" + string += " <a href='byond://?src=[REF(owner)];edit_obj_pr=[REF(to_display)]'>[to_display.progression_reward] PR</a>" else string += ", [to_display.telecrystal_reward] TC" string += ", [to_display.progression_reward] PR" if(to_display.objective_state == OBJECTIVE_STATE_ACTIVE && !istype(to_display, /datum/traitor_objective/ultimate)) - string += " <a href='?src=[REF(owner)];fail_objective=[REF(to_display)]'>Fail this objective</a>" - string += " <a href='?src=[REF(owner)];succeed_objective=[REF(to_display)]'>Succeed this objective</a>" + string += " <a href='byond://?src=[REF(owner)];fail_objective=[REF(to_display)]'>Fail this objective</a>" + string += " <a href='byond://?src=[REF(owner)];succeed_objective=[REF(to_display)]'>Succeed this objective</a>" if(to_display.objective_state == OBJECTIVE_STATE_INACTIVE) - string += " <a href='?src=[REF(owner)];fail_objective=[REF(to_display)]'>Dispose of this objective</a>" + string += " <a href='byond://?src=[REF(owner)];fail_objective=[REF(to_display)]'>Dispose of this objective</a>" if(to_display.skipped) string += " - <b>Skipped</b>" @@ -173,7 +173,7 @@ result += "[traitor_objective_to_html(objective)]<br>" if(!length(uplink_handler.potential_objectives)) result += "EMPTY<br>" - result += "<a href='?src=[REF(owner)];common=give_objective'>Force add objective</a><br>" + result += "<a href='byond://?src=[REF(owner)];common=give_objective'>Force add objective</a><br>" return result /// Returns true if we're allowed to assign ourselves a new objective diff --git a/code/modules/asset_cache/asset_cache_client.dm b/code/modules/asset_cache/asset_cache_client.dm index 3cff8cb41f3e9..20835cd70d7c8 100644 --- a/code/modules/asset_cache/asset_cache_client.dm +++ b/code/modules/asset_cache/asset_cache_client.dm @@ -36,7 +36,7 @@ var/job = ++last_asset_job var/t = 0 var/timeout_time = timeout - src << browse({"<script>window.location.href="?asset_cache_confirm_arrival=[job]"</script>"}, "window=asset_cache_browser&file=asset_cache_send_verify.htm") + src << browse({"<script>window.location.href='byond://?asset_cache_confirm_arrival=[job]'</script>"}, "window=asset_cache_browser&file=asset_cache_send_verify.htm") while(!completed_asset_jobs["[job]"] && t < timeout_time) // Reception is handled in Topic() stoplag(1) // Lock up the caller until this is received. diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 9705246fa593c..f3877a1424d03 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -544,7 +544,7 @@ SSair.add_to_rebuild_queue(src) /obj/machinery/atmospherics/update_name() - if(!override_naming) + if(!override_naming && !HAS_TRAIT(src, TRAIT_WAS_RENAMED)) name = "[GLOB.pipe_color_name[pipe_color]] [initial(name)]" return ..() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/binary_devices.dm b/code/modules/atmospherics/machinery/components/binary_devices/binary_devices.dm index b26f0c028d1af..c8cb2e849caec 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/binary_devices.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/binary_devices.dm @@ -7,6 +7,7 @@ device_type = BINARY layer = GAS_PUMP_LAYER pipe_flags = PIPING_BRIDGE + obj_flags = parent_type::obj_flags | UNIQUE_RENAME /obj/machinery/atmospherics/components/binary/set_init_directions() switch(dir) diff --git a/code/modules/bitrunning/components/avatar_connection.dm b/code/modules/bitrunning/components/avatar_connection.dm index 9fdfe1f629ec2..cefaeef91f3c3 100644 --- a/code/modules/bitrunning/components/avatar_connection.dm +++ b/code/modules/bitrunning/components/avatar_connection.dm @@ -107,8 +107,9 @@ COMSIG_BITRUNNER_ALERT_SEVER, COMSIG_BITRUNNER_CACHE_SEVER, COMSIG_BITRUNNER_LADDER_SEVER, - COMSIG_LIVING_DEATH, COMSIG_LIVING_PILL_CONSUMED, + COMSIG_LIVING_DEATH, + COMSIG_QDELETING, COMSIG_MOB_APPLY_DAMAGE, )) diff --git a/code/modules/buildmode/submodes/advanced.dm b/code/modules/buildmode/submodes/advanced.dm index f4ebb204d6ee0..bb08ddaf5298e 100644 --- a/code/modules/buildmode/submodes/advanced.dm +++ b/code/modules/buildmode/submodes/advanced.dm @@ -3,7 +3,7 @@ var/atom/objholder = null /datum/buildmode_mode/advanced/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Set object type")] -> Right Mouse Button on buildmode button\n\ [span_bold("Copy object type")] -> Left Mouse Button + Alt on turf/obj\n\ [span_bold("Place objects")] -> Left Mouse Button on turf/obj\n\ diff --git a/code/modules/buildmode/submodes/area_edit.dm b/code/modules/buildmode/submodes/area_edit.dm index 0d9ef8dd480bd..e91ea26be7746 100644 --- a/code/modules/buildmode/submodes/area_edit.dm +++ b/code/modules/buildmode/submodes/area_edit.dm @@ -9,7 +9,7 @@ ..() /datum/buildmode_mode/area_edit/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Select corner")] -> Left Mouse Button on obj/turf/mob\n\ [span_bold("Paint area")] -> Left Mouse Button + Alt on turf/obj/mob\n\ [span_bold("Select area to paint")] -> Right Mouse Button on obj/turf/mob\n\ diff --git a/code/modules/buildmode/submodes/basic.dm b/code/modules/buildmode/submodes/basic.dm index b0108a3a37f32..e68ccda926de7 100644 --- a/code/modules/buildmode/submodes/basic.dm +++ b/code/modules/buildmode/submodes/basic.dm @@ -2,7 +2,7 @@ key = "basic" /datum/buildmode_mode/basic/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Construct / Upgrade")] -> Left Mouse Button\n\ [span_bold("Deconstruct / Delete / Downgrade")] -> Right Mouse Button\n\ [span_bold("R-Window")] -> Left Mouse Button + Ctrl\n\ diff --git a/code/modules/buildmode/submodes/boom.dm b/code/modules/buildmode/submodes/boom.dm index 727d001f5cab4..e86d377d5d84c 100644 --- a/code/modules/buildmode/submodes/boom.dm +++ b/code/modules/buildmode/submodes/boom.dm @@ -16,7 +16,7 @@ ) /datum/buildmode_mode/boom/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Set explosion destructiveness")] -> Right Mouse Button on buildmode button\n\ [span_bold("Kaboom")] -> Mouse Button on obj\n\n\ [span_warning("NOTE:")] Using the \"Config/Launch Supplypod\" verb allows you to do this in an IC way (i.e., making a cruise missile come down from the sky and explode wherever you click!)")) diff --git a/code/modules/buildmode/submodes/copy.dm b/code/modules/buildmode/submodes/copy.dm index 88a1160a8a8fb..19dd34d3b4b52 100644 --- a/code/modules/buildmode/submodes/copy.dm +++ b/code/modules/buildmode/submodes/copy.dm @@ -7,7 +7,7 @@ return ..() /datum/buildmode_mode/copy/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Spawn a copy of selected target")] -> Left Mouse Button on obj/turf/mob\n\ [span_bold("Select target to copy")] -> Right Mouse Button on obj/mob")) ) diff --git a/code/modules/buildmode/submodes/delete.dm b/code/modules/buildmode/submodes/delete.dm index 7bb1a1472c0c5..1980375a33cd4 100644 --- a/code/modules/buildmode/submodes/delete.dm +++ b/code/modules/buildmode/submodes/delete.dm @@ -2,7 +2,7 @@ key = "delete" /datum/buildmode_mode/delete/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Delete an object")] -> Left Mouse Button on obj/turf/mob\n\ [span_bold("Delete all objects of a type")] -> Right Mouse Button on obj/turf/mob")) ) diff --git a/code/modules/buildmode/submodes/fill.dm b/code/modules/buildmode/submodes/fill.dm index e2bd3a5c16ad5..1646f6b3a0da5 100644 --- a/code/modules/buildmode/submodes/fill.dm +++ b/code/modules/buildmode/submodes/fill.dm @@ -7,7 +7,7 @@ var/atom/objholder = null /datum/buildmode_mode/fill/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Select corner")] -> Left Mouse Button on turf/obj/mob\n\ [span_bold("Delete region")] -> Left Mouse Button + Alt on turf/obj/mob\n\ [span_bold("Select object type")] -> Right Mouse Button on buildmode button")) diff --git a/code/modules/buildmode/submodes/map_export.dm b/code/modules/buildmode/submodes/map_export.dm index 19c0d57b57f73..9d59263aa47e1 100644 --- a/code/modules/buildmode/submodes/map_export.dm +++ b/code/modules/buildmode/submodes/map_export.dm @@ -22,7 +22,7 @@ to_chat(builder, span_notice("[what_to_change] is now [save_flag & options[what_to_change] ? "ENABLED" : "DISABLED"].")) /datum/buildmode_mode/map_export/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Select corner")] -> Left Mouse Button on obj/turf/mob\n\ [span_bold("Set export options")] -> Right Mouse Button on buildmode button")) ) diff --git a/code/modules/buildmode/submodes/mapgen.dm b/code/modules/buildmode/submodes/mapgen.dm index 102660425c874..d55898724490f 100644 --- a/code/modules/buildmode/submodes/mapgen.dm +++ b/code/modules/buildmode/submodes/mapgen.dm @@ -5,7 +5,7 @@ var/generator_path /datum/buildmode_mode/mapgen/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Select corner")] -> Left Mouse Button on turf/obj/mob\n\ [span_bold("Select generator")] -> Right Mouse Button on buildmode button")) ) diff --git a/code/modules/buildmode/submodes/outfit.dm b/code/modules/buildmode/submodes/outfit.dm index c3d507bf1e6c7..30b0f33cec165 100644 --- a/code/modules/buildmode/submodes/outfit.dm +++ b/code/modules/buildmode/submodes/outfit.dm @@ -7,7 +7,7 @@ return ..() /datum/buildmode_mode/outfit/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Select outfit to equip")] -> Right Mouse Button on buildmode button\n\ [span_bold("Equip the selected outfit")] -> Left Mouse Button on mob/living/carbon/human\n\ [span_bold("Strip and delete current outfit")] -> Right Mouse Button on mob/living/carbon/human")) diff --git a/code/modules/buildmode/submodes/proccall.dm b/code/modules/buildmode/submodes/proccall.dm index 3df1b8105380c..612a44cde4ca7 100644 --- a/code/modules/buildmode/submodes/proccall.dm +++ b/code/modules/buildmode/submodes/proccall.dm @@ -6,7 +6,7 @@ var/list/proc_args = null /datum/buildmode_mode/proccall/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Choose procedure and arguments")] -> Right Mouse Button on buildmode button\n\ [span_bold("Apply procedure on object")] -> Left Mouse Button on machinery")) ) diff --git a/code/modules/buildmode/submodes/smite.dm b/code/modules/buildmode/submodes/smite.dm index 1ea5f415e35f3..7e382926c5969 100644 --- a/code/modules/buildmode/submodes/smite.dm +++ b/code/modules/buildmode/submodes/smite.dm @@ -7,7 +7,7 @@ return ..() /datum/buildmode_mode/smite/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Select smite to use")] -> Right Mouse Button on buildmode button\n\ [span_bold("Smite the mob")] -> Left Mouse Button on mob/living")) ) diff --git a/code/modules/buildmode/submodes/throwing.dm b/code/modules/buildmode/submodes/throwing.dm index 587bf456e2a0c..c1bc4c2184ef3 100644 --- a/code/modules/buildmode/submodes/throwing.dm +++ b/code/modules/buildmode/submodes/throwing.dm @@ -8,7 +8,7 @@ return ..() /datum/buildmode_mode/throwing/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Select")] -> Left Mouse Button on turf/obj/mob\n\ [span_bold("Throw")] -> Right Mouse Button on turf/obj/mob")) ) diff --git a/code/modules/buildmode/submodes/tweakcomps.dm b/code/modules/buildmode/submodes/tweakcomps.dm index 89f233f9687b9..b0e41589917d3 100644 --- a/code/modules/buildmode/submodes/tweakcomps.dm +++ b/code/modules/buildmode/submodes/tweakcomps.dm @@ -4,7 +4,7 @@ var/rating = null /datum/buildmode_mode/tweakcomps/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Choose the rating of the components")] -> Right Mouse Button on buildmode button\n\ [span_bold("Sets the chosen rating of the components on the machinery")] -> Left Mouse Button on machinery")) ) diff --git a/code/modules/buildmode/submodes/variable_edit.dm b/code/modules/buildmode/submodes/variable_edit.dm index f132cd196ce71..4162af69faa43 100644 --- a/code/modules/buildmode/submodes/variable_edit.dm +++ b/code/modules/buildmode/submodes/variable_edit.dm @@ -10,7 +10,7 @@ return ..() /datum/buildmode_mode/varedit/show_help(client/builder) - to_chat(builder, span_purple(examine_block( + to_chat(builder, span_purple(boxed_message( "[span_bold("Select var(type) & value")] -> Right Mouse Button on buildmode button\n\ [span_bold("Set var(type) & value")] -> Left Mouse Button on turf/obj/mob\n\ [span_bold("Reset var's value")] -> Right Mouse Button on turf/obj/mob")) diff --git a/code/modules/cargo/packs/_packs.dm b/code/modules/cargo/packs/_packs.dm index b6c533050f675..bfa95b2a7ed25 100644 --- a/code/modules/cargo/packs/_packs.dm +++ b/code/modules/cargo/packs/_packs.dm @@ -106,7 +106,7 @@ name = "mining order" hidden = TRUE crate_name = "shaft mining delivery crate" - access = list(ACCESS_MINING) + access = ACCESS_MINING /datum/supply_pack/custom/New(purchaser, cost, list/contains) . = ..() @@ -117,7 +117,7 @@ /datum/supply_pack/custom/minerals name = "materials order" crate_name = "galactic materials market delivery crate" - access = list() + access = FALSE crate_type = /obj/structure/closet/crate/cardboard /datum/supply_pack/custom/minerals/New(purchaser, cost, list/contains) diff --git a/code/modules/cargo/packs/livestock.dm b/code/modules/cargo/packs/livestock.dm index 62008d8be48e0..da51ee497f66d 100644 --- a/code/modules/cargo/packs/livestock.dm +++ b/code/modules/cargo/packs/livestock.dm @@ -259,3 +259,10 @@ cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/storage/fish_case/tiziran = 2) crate_name = "tiziran fish crate" + +/datum/supply_pack/critter/turtle + name = "Turtle Crate" + desc = "Cute flora turtles that'll emit good vibes to nearby plants!" + cost = CARGO_CRATE_VALUE * 2 + contains = list(/mob/living/basic/turtle) + crate_name = "flora-turtle crate" diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 4bd8ce5497e2d..062a402cc3f23 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -1086,7 +1086,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( /client/proc/check_panel_loaded() if(stat_panel.is_ready()) return - to_chat(src, span_userdanger("Statpanel failed to load, click <a href='?src=[REF(src)];reload_statbrowser=1'>here</a> to reload the panel ")) + to_chat(src, span_userdanger("Statpanel failed to load, click <a href='byond://?src=[REF(src)];reload_statbrowser=1'>here</a> to reload the panel ")) /** * Initializes dropdown menus on client diff --git a/code/modules/client/preferences/species_features/lizard.dm b/code/modules/client/preferences/species_features/lizard.dm index 1a92d48e9cce6..081f27be50e3a 100644 --- a/code/modules/client/preferences/species_features/lizard.dm +++ b/code/modules/client/preferences/species_features/lizard.dm @@ -128,17 +128,6 @@ var/datum/species/species_type = preferences.read_preference(/datum/preference/choiced/species) return initial(species_type.digitigrade_customization) == DIGITIGRADE_OPTIONAL - -/datum/preference/choiced/lizard_legs/is_accessible(datum/preferences/preferences) - . = ..() - - if(!.) - return - - var/datum/species/species_type = preferences.read_preference(/datum/preference/choiced/species) - - return initial(species_type.digitigrade_customization) & DIGITIGRADE_OPTIONAL - /datum/preference/choiced/lizard_snout savefile_key = "feature_lizard_snout" savefile_identifier = PREFERENCE_CHARACTER diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 8ff3dd2459622..16a263cc14f4a 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -150,7 +150,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car /datum/preferences/proc/announce_conflict(list/notadded) to_chat(parent, "<span class='warningplain'><b><u>Keybinding Conflict</u></b></span>\n\ - <span class='warningplain'><b>There are new <a href='?src=[REF(src)];open_keybindings=1'>keybindings</a> that default to keys you've already bound. The new ones will be unbound.</b></span>") + <span class='warningplain'><b>There are new <a href='byond://?src=[REF(src)];open_keybindings=1'>keybindings</a> that default to keys you've already bound. The new ones will be unbound.</b></span>") for(var/item in notadded) var/datum/keybinding/conflicted = item to_chat(parent, span_danger("[conflicted.category]: [conflicted.full_name] needs updating")) diff --git a/code/modules/client/verbs/who.dm b/code/modules/client/verbs/who.dm index bd023ede6308e..c9e500e7dbc78 100644 --- a/code/modules/client/verbs/who.dm +++ b/code/modules/client/verbs/who.dm @@ -85,7 +85,7 @@ lines += span_bold(header) lines += payload_string - var/finalized_string = examine_block(jointext(lines, "\n")) + var/finalized_string = boxed_message(jointext(lines, "\n")) to_chat(src, finalized_string) /// Proc that generates the applicable string to dispatch to the client for adminwho. diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 41c062170dbda..8f5b4dbf5a912 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -340,7 +340,7 @@ else how_cool_are_your_threads += "[src]'s storage opens when dragged to yourself.\n" if (atom_storage.can_hold?.len) // If pocket type can hold anything, vs only specific items - how_cool_are_your_threads += "[src] can store [atom_storage.max_slots] <a href='?src=[REF(src)];show_valid_pocket_items=1'>item\s</a>.\n" + how_cool_are_your_threads += "[src] can store [atom_storage.max_slots] <a href='byond://?src=[REF(src)];show_valid_pocket_items=1'>item\s</a>.\n" else how_cool_are_your_threads += "[src] can store [atom_storage.max_slots] item\s that are [weight_class_to_text(atom_storage.max_specific_storage)] or smaller.\n" if(atom_storage.quickdraw) @@ -351,7 +351,7 @@ . += how_cool_are_your_threads.Join() if(get_armor().has_any_armor() || (flags_cover & (HEADCOVERSMOUTH|PEPPERPROOF)) || (clothing_flags & STOPSPRESSUREDAMAGE) || (visor_flags & STOPSPRESSUREDAMAGE)) - . += span_notice("Имеется <a href='?src=[REF(src)];list_armor=1'>бирка</a>, указывающая классы защиты.") + . += span_notice("Имеется <a href='byond://?src=[REF(src)];list_armor=1'>бирка</a>, указывающая классы защиты.") /obj/item/clothing/examine_tags(mob/user) . = ..() @@ -456,7 +456,7 @@ readout += "No armor or durability information available." var/formatted_readout = span_notice("<b>PROTECTION CLASSES</b><hr>[jointext(readout, "\n")]") - to_chat(usr, examine_block(formatted_readout)) + to_chat(usr, boxed_message(formatted_readout)) /** * Rounds armor_value down to the nearest 10, divides it by 10 and then converts it to Roman numerals. diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 6d97c116ab11a..7fe2074175d31 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -336,7 +336,7 @@ render_list += "<span class='notice ml-1'>[target.p_Their()] pulse is [pulse_pressure] and [heart_strength].</span>\n" //display our packaged information in an examine block for easy reading - to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO) + to_chat(user, boxed_message(jointext(render_list, "")), type = MESSAGE_TYPE_INFO) /////////// //SCARVES// diff --git a/code/modules/deathmatch/deathmatch_controller.dm b/code/modules/deathmatch/deathmatch_controller.dm index de5132198881a..3ae10ad51d204 100644 --- a/code/modules/deathmatch/deathmatch_controller.dm +++ b/code/modules/deathmatch/deathmatch_controller.dm @@ -23,7 +23,7 @@ /datum/deathmatch_controller/proc/create_new_lobby(mob/host) lobbies[host.ckey] = new /datum/deathmatch_lobby(host) - deadchat_broadcast(" has opened a new deathmatch lobby. <a href=?src=[REF(lobbies[host.ckey])];join=1>(Join)</a>", "<B>[host]</B>") + deadchat_broadcast(" has opened a new deathmatch lobby. <a href=byond://?src=[REF(lobbies[host.ckey])];join=1>(Join)</a>", "<B>[host]</B>") /datum/deathmatch_controller/proc/remove_lobby(ckey) var/lobby = lobbies[ckey] diff --git a/code/modules/error_handler/error_viewer.dm b/code/modules/error_handler/error_viewer.dm index fbaa0ca3faebc..8080f3005dd3c 100644 --- a/code/modules/error_handler/error_viewer.dm +++ b/code/modules/error_handler/error_viewer.dm @@ -71,7 +71,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) if (linear) back_to_param += ";viewruntime_linear=1" - return "<a href='?_src_=holder;[HrefToken()];viewruntime=[REF(src)][back_to_param]'>[linktext]</a>" + return "<a href='byond://?_src_=holder;[HrefToken()];viewruntime=[REF(src)][back_to_param]'>[linktext]</a>" /datum/error_viewer/error_cache var/list/errors = list() @@ -182,12 +182,12 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) var/html = build_header(back_to, linear) html += "[name]<div class='runtime'>[desc]</div>" if (usr_ref) - html += "<br><b>usr</b>: <a href='?_src_=vars;[HrefToken()];Vars=[usr_ref]'>VV</a>" - html += " <a href='?_src_=holder;[HrefToken()];adminplayeropts=[usr_ref]'>PP</a>" - html += " <a href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[usr_ref]'>Follow</a>" + html += "<br><b>usr</b>: <a href='byond://?_src_=vars;[HrefToken()];Vars=[usr_ref]'>VV</a>" + html += " <a href='byond://?_src_=holder;[HrefToken()];adminplayeropts=[usr_ref]'>PP</a>" + html += " <a href='byond://?_src_=holder;[HrefToken()];adminplayerobservefollow=[usr_ref]'>Follow</a>" if (istype(usr_loc)) - html += "<br><b>usr.loc</b>: <a href='?_src_=vars;[HrefToken()];Vars=[REF(usr_loc)]'>VV</a>" - html += " <a href='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[usr_loc.x];Y=[usr_loc.y];Z=[usr_loc.z]'>JMP</a>" + html += "<br><b>usr.loc</b>: <a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(usr_loc)]'>VV</a>" + html += " <a href='byond://?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[usr_loc.x];Y=[usr_loc.y];Z=[usr_loc.z]'>JMP</a>" browse_to(user, html) diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index a1e8aef5b6c91..a5f8675b3b9ad 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -102,7 +102,7 @@ triggering = TRUE // We sleep HERE, in pre-event setup (because there's no sense doing it in run_event() since the event is already running!) for the given amount of time to make an admin has enough time to cancel an event un-fitting of the present round or at least reroll it. - message_admins("Random Event triggering in [DisplayTimeText(RANDOM_EVENT_ADMIN_INTERVENTION_TIME)]: [name]. (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>) (<a href='?src=[REF(src)];different_event=1'>SOMETHING ELSE</a>)") + message_admins("Random Event triggering in [DisplayTimeText(RANDOM_EVENT_ADMIN_INTERVENTION_TIME)]: [name]. (<a href='byond://?src=[REF(src)];cancel=1'>CANCEL</a>) (<a href='byond://?src=[REF(src)];different_event=1'>SOMETHING ELSE</a>)") sleep(RANDOM_EVENT_ADMIN_INTERVENTION_TIME) var/players_amt = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE) if(!can_spawn_event(players_amt)) diff --git a/code/modules/events/holiday/halloween.dm b/code/modules/events/holiday/halloween.dm index 833afd35bbc52..289fa20e2fb0c 100644 --- a/code/modules/events/holiday/halloween.dm +++ b/code/modules/events/holiday/halloween.dm @@ -33,6 +33,10 @@ icon_state = "skeletoncookie" crafting_complexity = FOOD_COMPLEXITY_2 +/obj/item/food/cookie/sugar/spookyskull/Initialize(mapload, seasonal_changes = FALSE) + // Changes default parameter of seasonal_changes to FALSE, pass to parent + return ..(mapload, seasonal_changes) + /obj/item/food/cookie/sugar/spookycoffin name = "coffin cookie" desc = "Spooky! It's got delicious coffee flavouring!" diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm index 5fcfdd07ff350..8190b21c84c4d 100644 --- a/code/modules/fishing/fishing_rod.dm +++ b/code/modules/fishing/fishing_rod.dm @@ -150,7 +150,7 @@ block += get_stat_info(get_percent, gravity_mult, "The lure will sink", "faster", "slower", span_info = TRUE) list_clear_nulls(block) - . += examine_block(block.Join("\n")) + . += boxed_message(block.Join("\n")) if(get_percent && (material_flags & MATERIAL_EFFECTS) && length(custom_materials)) block = list() @@ -159,7 +159,7 @@ if(material.fish_weight_modifier != 1) var/heavier = material.fish_weight_modifier > 1 ? "heavier" : "lighter" block += span_info("Fish made of the same material as this rod tend to be [abs(material.fish_weight_modifier - 1) * 100]% [heavier].") - . += examine_block(block.Join("\n")) + . += boxed_message(block.Join("\n")) block = list() if(HAS_TRAIT(src, TRAIT_ROD_ATTRACT_SHINY_LOVERS)) @@ -171,7 +171,7 @@ if(HAS_TRAIT(src, TRAIT_ROD_LAVA_USABLE)) block += span_info("This fishing rod can be used to fish on lava.") if(length(block)) - . += examine_block(block.Join("\n")) + . += boxed_message(block.Join("\n")) ///Used in examine_more to reduce all the copypasta when getting more information about the various stats of the fishing rod. /obj/item/fishing_rod/proc/get_stat_info(get_percent, value, prefix, easier, harder, suffix = "with this fishing rod", span_info = FALSE, less_is_better = FALSE, offset = 1) diff --git a/code/modules/fishing/sources/_fish_source.dm b/code/modules/fishing/sources/_fish_source.dm index abf3a298462cb..cb0eaecc9890d 100644 --- a/code/modules/fishing/sources/_fish_source.dm +++ b/code/modules/fishing/sources/_fish_source.dm @@ -367,7 +367,10 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) final_table[result] *= rod.hook.get_hook_bonus_multiplicative(result) final_table[result] += rod.hook.get_hook_bonus_additive(result)//Decide on order here so it can be multiplicative - if(ispath(result, /obj/item/fish) || isfish(result)) + if(ispath(result, /mob/living) && bait && (HAS_TRAIT(bait, TRAIT_GOOD_QUALITY_BAIT) || HAS_TRAIT(bait, TRAIT_GREAT_QUALITY_BAIT))) + final_table[result] = round(final_table[result] * result_multiplier, 1) + + else if(ispath(result, /obj/item/fish) || isfish(result)) if(bait) final_table[result] = round(final_table[result] * result_multiplier, 1) var/mult = bait.check_bait(result) diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm index 6f2a38d4d6146..8177651973546 100644 --- a/code/modules/fishing/sources/source_types.dm +++ b/code/modules/fishing/sources/source_types.dm @@ -507,6 +507,7 @@ /obj/item/seeds/random = 1, /mob/living/basic/frog = 1, /mob/living/basic/axolotl = 1, + /mob/living/basic/turtle = 2, ) fish_counts = list( /obj/item/food/grown/grass = 10, diff --git a/code/modules/food_and_drinks/machinery/processor.dm b/code/modules/food_and_drinks/machinery/processor.dm index 62d1432912573..41e029a7a4f52 100644 --- a/code/modules/food_and_drinks/machinery/processor.dm +++ b/code/modules/food_and_drinks/machinery/processor.dm @@ -143,10 +143,14 @@ if(!LAZYLEN(processor_contents)) to_chat(user, span_warning("Внутри [declent_ru(GENITIVE)] пусто!")) return TRUE - processing = TRUE user.visible_message(span_notice("[capitalize(user.declent_ru(NOMINATIVE))] включает [declent_ru(ACCUSATIVE)]."), \ span_notice("Вы включаете [declent_ru(ACCUSATIVE)]."), \ span_hear("Вы слышите кухонный комбайн.")) + processing() + + +/obj/machinery/processor/proc/processing() + processing = TRUE playsound(src.loc, 'sound/machines/blender.ogg', 50, TRUE) use_energy(active_power_usage) var/total_time = 0 @@ -197,6 +201,12 @@ desc = "Промышленный комбайн с наклейкой о том, что он предназначен для научного отдела. Во время работы держите руки подальше от зоны приема." circuit = /obj/item/circuitboard/machine/processor/slime +/obj/machinery/processor/slime/Initialize(mapload) + . = ..() + AddComponent(/datum/component/usb_port, list( + /obj/item/circuit_component/slime_processor, + )) + /obj/machinery/processor/slime/adjust_item_drop_location(atom/movable/atom_to_drop) var/static/list/slimecores = subtypesof(/obj/item/slime_extract) var/i = 0 @@ -249,4 +259,42 @@ SSblackbox.record_feedback("tally", "slime_core_harvested", 1, processed_slime.slime_type.colour) return ..() +/obj/item/circuit_component/slime_processor + display_name = "Slime Processor" + desc = "Allows to activate process and get the amount of processor contents." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL + + ///Activate process + var/datum/port/input/active + ///Amount of processor contents + var/datum/port/output/amount + + var/obj/machinery/processor/slime/attached_processor + +/obj/item/circuit_component/slime_processor/populate_ports() + active = add_input_port("Activate", PORT_TYPE_SIGNAL, trigger = PROC_REF(activate)) + amount = add_output_port("Amount", PORT_TYPE_NUMBER) + +/obj/item/circuit_component/slime_processor/register_usb_parent(atom/movable/parent) + . = ..() + if(istype(parent, /obj/machinery/processor/slime)) + attached_processor = parent + +/obj/item/circuit_component/slime_processor/unregister_usb_parent(atom/movable/parent) + attached_processor = null + return ..() + +/obj/item/circuit_component/slime_processor/proc/activate() + SIGNAL_HANDLER + input_received() + if(attached_processor.processing) + return + if(!LAZYLEN(attached_processor.processor_contents)) + return + attached_processor.processing() + +/obj/item/circuit_component/slime_processor/input_received() + var/list/contents = attached_processor.processor_contents + amount.set_output(LAZYLEN(contents)) + #undef PROCESSOR_SELECT_RECIPE diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index 6d9c380112b7c..ace4fc62aa6f0 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -214,7 +214,7 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf spawning_simulation = TRUE active = (map_id != offline_program) - update_use_power(active + IDLE_POWER_USE) + update_mode_power_usage(ACTIVE_POWER_USE, initial(active_power_usage)) program = map_id clear_projection() @@ -242,6 +242,8 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf program = offline_program clear_projection() + //update_mode_power_usage(ACTIVE_POWER_USE, initial(active_power_usage)) + update_use_power(IDLE_POWER_USE) template = SSmapping.holodeck_templates[offline_program] INVOKE_ASYNC(template, TYPE_PROC_REF(/datum/map_template, load), bottom_left) //this is what actually loads the holodeck simulation into the map @@ -365,6 +367,7 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf return . = ..() if(!. || program == offline_program)//we dont need to scan the holodeck if the holodeck is offline + update_use_power(IDLE_POWER_USE) return if(!floorcheck()) //if any turfs in the floor of the holodeck are broken @@ -383,7 +386,8 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf derez(item) for(var/obj/effect/holodeck_effect/holo_effect as anything in effects) holo_effect.tick() - update_mode_power_usage(ACTIVE_POWER_USE, initial(active_power_usage) + spawned.len * 3 + effects.len * 5) + update_use_power(ACTIVE_POWER_USE) + update_mode_power_usage(ACTIVE_POWER_USE, initial(active_power_usage) + (spawned.len * 15 + effects.len * 25)) /obj/machinery/computer/holodeck/proc/toggle_power(toggleOn = FALSE) if(active == toggleOn) @@ -434,8 +438,8 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf playsound(src, SFX_SPARKS, 75, TRUE) obj_flags |= EMAGGED if (user) - balloon_alert(user, "safety protocols destroyed") // im gonna keep this once since this perfectly describes it, and the to_chat is just flavor - to_chat(user, span_warning("You vastly increase projector power and override the safety and security protocols.")) + balloon_alert(user, "safety protocols destroyed") // im gonna keep this once since this perfectly describes it + to_chat(user, span_warning("You override the safety and security protocols.")) user.log_message("emagged the Holodeck Control Console.", LOG_GAME) message_admins("[ADMIN_LOOKUPFLW(user)] emagged the Holodeck Control Console.") diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm index b982d71030a6f..924cebcee8f84 100644 --- a/code/modules/hydroponics/hydroitemdefines.dm +++ b/code/modules/hydroponics/hydroitemdefines.dm @@ -75,22 +75,22 @@ /obj/item/plant_analyzer/proc/do_plant_stats_scan(atom/scan_target, mob/user) if(istype(scan_target, /obj/machinery/hydroponics)) playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE) - to_chat(user, examine_block(scan_tray_stats(scan_target))) + to_chat(user, boxed_message(scan_tray_stats(scan_target))) return TRUE if(istype(scan_target, /obj/structure/glowshroom)) playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE) var/obj/structure/glowshroom/shroom_plant = scan_target - to_chat(user, examine_block(scan_plant_stats(shroom_plant.myseed))) + to_chat(user, boxed_message(scan_plant_stats(shroom_plant.myseed))) return TRUE if(istype(scan_target, /obj/item/graft)) playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE) - to_chat(user, examine_block(get_graft_text(scan_target))) + to_chat(user, boxed_message(get_graft_text(scan_target))) return TRUE if(isitem(scan_target)) playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE) var/obj/item/scanned_object = scan_target if(scanned_object.get_plant_seed() || istype(scanned_object, /obj/item/seeds)) - to_chat(user, examine_block(scan_plant_stats(scanned_object))) + to_chat(user, boxed_message(scan_plant_stats(scanned_object))) return TRUE if(isliving(scan_target)) playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE) @@ -112,19 +112,19 @@ */ /obj/item/plant_analyzer/proc/do_plant_chem_scan(atom/scan_target, mob/user) if(istype(scan_target, /obj/machinery/hydroponics)) - to_chat(user, examine_block(scan_tray_chems(scan_target))) + to_chat(user, boxed_message(scan_tray_chems(scan_target))) return TRUE if(istype(scan_target, /obj/structure/glowshroom)) var/obj/structure/glowshroom/shroom_plant = scan_target - to_chat(user, examine_block(scan_plant_chems(shroom_plant.myseed))) + to_chat(user, boxed_message(scan_plant_chems(shroom_plant.myseed))) return TRUE if(istype(scan_target, /obj/item/graft)) - to_chat(user, examine_block(get_graft_text(scan_target))) + to_chat(user, boxed_message(get_graft_text(scan_target))) return TRUE if(isitem(scan_target)) var/obj/item/scanned_object = scan_target if(scanned_object.get_plant_seed() || istype(scanned_object, /obj/item/seeds)) - to_chat(user, examine_block(scan_plant_chems(scanned_object))) + to_chat(user, boxed_message(scan_plant_chems(scanned_object))) return TRUE if(isliving(scan_target)) var/mob/living/L = scan_target diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 017feb1c90452..b633985d7b585 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -561,7 +561,7 @@ if(weedlevel == new_weedlevel) return SEND_SIGNAL(src, COMSIG_HYDROTRAY_SET_WEEDLEVEL, new_weedlevel) - weedlevel = new_weedlevel + weedlevel = max(new_weedlevel, 0) if(update_icon) update_appearance() diff --git a/code/modules/interview/interview.dm b/code/modules/interview/interview.dm index a1703b9c06974..78490402e63e8 100644 --- a/code/modules/interview/interview.dm +++ b/code/modules/interview/interview.dm @@ -160,4 +160,4 @@ * Generates a clickable link to open this interview */ /datum/interview/proc/link_self() - return "<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];interview=[REF(src)]'>Interview #[id]</a>" + return "<a href='byond://?_src_=holder;[HrefToken(forceGlobal = TRUE)];interview=[REF(src)]'>Interview #[id]</a>" diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index b75a8ef3171dc..1db95a2ff939a 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -299,7 +299,7 @@ /// Gets the message that shows up when spawning as this job /datum/job/proc/get_spawn_message() SHOULD_NOT_OVERRIDE(TRUE) - return examine_block(span_infoplain(jointext(get_spawn_message_information(), "\n• "))) + return boxed_message(span_infoplain(jointext(get_spawn_message_information(), "\n• "))) /// Returns a list of strings that correspond to chat messages sent to this mob when they join the round. /datum/job/proc/get_spawn_message_information() diff --git a/code/modules/lootpanel/misc.dm b/code/modules/lootpanel/misc.dm index 6e8448b820528..4fc3af2da29bf 100644 --- a/code/modules/lootpanel/misc.dm +++ b/code/modules/lootpanel/misc.dm @@ -7,7 +7,7 @@ var/build = owner.byond_build var/version = owner.byond_version if(build < 515 || (build == 515 && version < 1635)) - to_chat(owner.mob, examine_block(span_info("\ + to_chat(owner.mob, boxed_message(span_info("\ <span class='bolddanger'>Your version of Byond doesn't support fast image loading.</span>\n\ Detected: [version].[build]\n\ Required version for this feature: <b>515.1635</b> or later.\n\ diff --git a/code/modules/mob/dead/new_player/poll.dm b/code/modules/mob/dead/new_player/poll.dm index 9be971204c1e8..6ecd6f12a272a 100644 --- a/code/modules/mob/dead/new_player/poll.dm +++ b/code/modules/mob/dead/new_player/poll.dm @@ -18,7 +18,7 @@ GLOBAL_PROTECT(poll_options) var/datum/poll_question/poll = p if((poll.admin_only && !client.holder) || poll.future_poll) continue - output += "<tr bgcolor='#e2e2e2'><td><a href='?src=[rs];viewpoll=[REF(poll)]'><b>[poll.question]</b></a></td></tr>" + output += "<tr bgcolor='#e2e2e2'><td><a href='byond://?src=[rs];viewpoll=[REF(poll)]'><b>[poll.question]</b></a></td></tr>" output += "</table>" src << browse(jointext(output, ""),"window=playerpolllist;size=500x300") diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index cc03fb05a301d..820f14edebac0 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -436,7 +436,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp A.add_overlay(source) source.layer = old_layer source.plane = old_plane - to_chat(src, span_ghostalert("<a href=?src=[REF(src)];reenter=1>(Click to re-enter)</a>")) + to_chat(src, span_ghostalert("<a href=byond://?src=[REF(src)];reenter=1>(Click to re-enter)</a>")) if(sound) SEND_SOUND(src, sound(sound)) diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 5a16469135bbc..c4749288c698a 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -72,7 +72,7 @@ message += keys.Join(", ") message += "." message = message.Join("") - to_chat(user, examine_block(message)) + to_chat(user, boxed_message(message)) /datum/emote/flip key = "flip" diff --git a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm index 68cd6a231e326..14de9f04068d2 100644 --- a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm +++ b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm @@ -127,7 +127,7 @@ var/static/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, - /datum/pet_command/point_targeting/clean, + /datum/pet_command/clean, ) /mob/living/basic/bot/cleanbot/Initialize(mapload) diff --git a/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm b/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm index 1b6d840062208..0a6a4b03b4354 100644 --- a/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm +++ b/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm @@ -200,14 +200,15 @@ return return ..() -/datum/pet_command/point_targeting/clean +/datum/pet_command/clean command_name = "Clean" command_desc = "Command a cleanbot to clean the mess." + requires_pointing = TRUE radial_icon = 'icons/obj/service/janitor.dmi' radial_icon_state = "mop" speech_commands = list("clean", "mop") -/datum/pet_command/point_targeting/clean/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/clean/set_command_target(mob/living/parent, atom/target) if(isnull(target) || !istype(target, /obj/effect/decal/cleanable)) return if(isnull(parent.ai_controller)) @@ -216,7 +217,7 @@ return return ..() -/datum/pet_command/point_targeting/clean/execute_action(datum/ai_controller/basic_controller/bot/controller) +/datum/pet_command/clean/execute_action(datum/ai_controller/basic_controller/bot/controller) if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET)) controller.queue_behavior(/datum/ai_behavior/execute_clean, BB_CURRENT_PET_TARGET) return SUBTREE_RETURN_FINISH_PLANNING diff --git a/code/modules/mob/living/basic/bots/repairbot/repairbot.dm b/code/modules/mob/living/basic/bots/repairbot/repairbot.dm index 17b257d8c987b..775e22101bc17 100644 --- a/code/modules/mob/living/basic/bots/repairbot/repairbot.dm +++ b/code/modules/mob/living/basic/bots/repairbot/repairbot.dm @@ -49,18 +49,18 @@ ) ///our neutral voicelines var/static/list/neutral_voicelines = list( - REPAIRBOT_VOICED_BRICK = 'sound/voice/repairbot/brick.ogg', - REPAIRBOT_VOICED_ENTROPY = 'sound/voice/repairbot/entropy.ogg', - REPAIRBOT_VOICED_FIX_IT = 'sound/voice/repairbot/fixit.ogg', - REPAIRBOT_VOICED_FIX_TOUCH = 'sound/voice/repairbot/fixtouch.ogg', - REPAIRBOT_VOICED_HOLE = 'sound/voice/repairbot/patchingholes.ogg', - REPAIRBOT_VOICED_PAY = 'sound/voice/repairbot/pay.ogg', + REPAIRBOT_VOICED_BRICK = 'sound/mobs/non-humanoids/repairbot/brick.ogg', + REPAIRBOT_VOICED_ENTROPY = 'sound/mobs/non-humanoids/repairbot/entropy.ogg', + REPAIRBOT_VOICED_FIX_IT = 'sound/mobs/non-humanoids/repairbot/fixit.ogg', + REPAIRBOT_VOICED_FIX_TOUCH = 'sound/mobs/non-humanoids/repairbot/fixtouch.ogg', + REPAIRBOT_VOICED_HOLE = 'sound/mobs/non-humanoids/repairbot/patchingholes.ogg', + REPAIRBOT_VOICED_PAY = 'sound/mobs/non-humanoids/repairbot/pay.ogg', ) ///our emagged voicelines var/static/list/emagged_voicelines = list( - REPAIRBOT_VOICED_ENTROPY = 'sound/voice/repairbot/entropy.ogg', - REPAIRBOT_VOICED_STRINGS = 'sound/voice/repairbot/strings.ogg', - REPAIRBOT_VOICED_PASSION = 'sound/voice/repairbot/passionproject.ogg', + REPAIRBOT_VOICED_ENTROPY = 'sound/mobs/non-humanoids/repairbot/entropy.ogg', + REPAIRBOT_VOICED_STRINGS = 'sound/mobs/non-humanoids/repairbot/strings.ogg', + REPAIRBOT_VOICED_PASSION = 'sound/mobs/non-humanoids/repairbot/passionproject.ogg', ) ///types we can retrieve from our ui var/static/list/retrievable_types = list( diff --git a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm index a2246fe4ba2c9..efbd1a50a3d0e 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm @@ -57,7 +57,7 @@ /datum/pet_command/beehive/enter, /datum/pet_command/beehive/exit, /datum/pet_command/follow/bee, - /datum/pet_command/point_targeting/attack/swirl, + /datum/pet_command/attack/swirl, /datum/pet_command/scatter, ) diff --git a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm index 1081c9b7b63b8..8472098662466 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm @@ -113,8 +113,9 @@ required_distance = 0 ///swirl around the owner in menacing fashion -/datum/pet_command/point_targeting/attack/swirl +/datum/pet_command/attack/swirl command_name = "Swirl" + requires_pointing = TRUE command_desc = "Your pets will swirl around you and attack whoever you point at!" speech_commands = list("swirl", "spiral", "swarm") pointed_reaction = null @@ -123,7 +124,7 @@ ///the owner we will swarm around var/key_to_swarm = BB_SWARM_TARGET -/datum/pet_command/point_targeting/attack/swirl/try_activate_command(mob/living/commander) +/datum/pet_command/attack/swirl/try_activate_command(mob/living/commander, radial_command) var/mob/living/living_pawn = weak_parent.resolve() if(isnull(living_pawn)) return @@ -134,7 +135,7 @@ controller.set_blackboard_key(key_to_swarm, commander) return ..() -/datum/pet_command/point_targeting/attack/swirl/execute_action(datum/ai_controller/controller) +/datum/pet_command/attack/swirl/execute_action(datum/ai_controller/controller) if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET)) return ..() controller.queue_behavior(/datum/ai_behavior/swirl_around_target, BB_SWARM_TARGET) @@ -186,7 +187,7 @@ radial_icon = 'icons/obj/service/hydroponics/equipment.dmi' radial_icon_state = "beebox" -/datum/pet_command/beehive/try_activate_command(mob/living/commander) +/datum/pet_command/beehive/try_activate_command(mob/living/commander, radial_command) var/mob/living/living_pawn = weak_parent.resolve() if(isnull(living_pawn)) return diff --git a/code/modules/mob/living/basic/heretic/star_gazer.dm b/code/modules/mob/living/basic/heretic/star_gazer.dm index 57a0ddfe322d8..7ffd7bc657ef6 100644 --- a/code/modules/mob/living/basic/heretic/star_gazer.dm +++ b/code/modules/mob/living/basic/heretic/star_gazer.dm @@ -103,7 +103,7 @@ can_attack_turfs = TRUE can_attack_dense_objects = TRUE -/datum/pet_command/point_targeting/attack/star_gazer +/datum/pet_command/attack/star_gazer speech_commands = list("attack", "sic", "kill", "slash them") command_feedback = "stares!" pointed_reaction = "stares intensely!" diff --git a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm index b82092147f67d..6056b1919090b 100644 --- a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm +++ b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm @@ -43,11 +43,12 @@ //commands to give when tamed var/static/list/pet_commands = list( /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, /datum/pet_command/good_boy/wolf, /datum/pet_command/follow/wolf, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/attack, + /datum/pet_command/fetch, /datum/pet_command/play_dead, /datum/pet_command/protect_owner, ) diff --git a/code/modules/mob/living/basic/jungle/leaper/leaper.dm b/code/modules/mob/living/basic/jungle/leaper/leaper.dm index 94babd0218e5b..d4f310d07aba1 100644 --- a/code/modules/mob/living/basic/jungle/leaper/leaper.dm +++ b/code/modules/mob/living/basic/jungle/leaper/leaper.dm @@ -40,13 +40,14 @@ ///list of pet commands we can issue var/list/pet_commands = list( /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, /datum/pet_command/follow, /datum/pet_command/untargeted_ability/blood_rain, /datum/pet_command/untargeted_ability/summon_toad, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/use_ability/flop, - /datum/pet_command/point_targeting/use_ability/bubble, + /datum/pet_command/attack, + /datum/pet_command/use_ability/flop, + /datum/pet_command/use_ability/bubble, ) /mob/living/basic/leaper/Initialize(mapload) diff --git a/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm b/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm index e776117a3a596..b5c917bf2a46e 100644 --- a/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm +++ b/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm @@ -39,7 +39,7 @@ ability_key = BB_LEAPER_SUMMON finish_planning = FALSE -/datum/pet_command/point_targeting/use_ability/flop +/datum/pet_command/use_ability/flop command_name = "Flop" command_desc = "Command your pet to belly flop your target!" radial_icon = 'icons/mob/actions/actions_items.dmi' @@ -47,7 +47,7 @@ speech_commands = list("flop", "crush") pet_ability_key = BB_LEAPER_FLOP -/datum/pet_command/point_targeting/use_ability/bubble +/datum/pet_command/use_ability/bubble command_name = "Poison Bubble" command_desc = "Launch poisonous bubbles at your target!" radial_icon = 'icons/obj/weapons/guns/projectiles.dmi' @@ -55,6 +55,9 @@ speech_commands = list("bubble", "shoot") pet_ability_key = BB_LEAPER_BUBBLE +/datum/pet_command/use_ability/bubble/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to shoot a bubble towards [target]!" + /datum/pet_command/untargeted_ability/blood_rain command_name = "Blood Rain" command_desc = "Let it rain poisonous blood!" @@ -63,6 +66,8 @@ speech_commands = list("blood", "rain", "volley") ability_key = BB_LEAPER_VOLLEY +/datum/pet_command/untargeted_ability/blood_rain/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to unleash a volley of rain!" /datum/pet_command/untargeted_ability/summon_toad command_name = "Summon Toads" @@ -71,3 +76,6 @@ radial_icon_state = "frog_trash" speech_commands = list("frogs", "bombers") ability_key = BB_LEAPER_SUMMON + +/datum/pet_command/untargeted_ability/summon_toad/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to summon some explosive frogs!" diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling.dm b/code/modules/mob/living/basic/jungle/seedling/seedling.dm index 0df19c5c27d31..9778aff8753df 100644 --- a/code/modules/mob/living/basic/jungle/seedling/seedling.dm +++ b/code/modules/mob/living/basic/jungle/seedling/seedling.dm @@ -214,9 +214,9 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/use_ability/solarbeam, - /datum/pet_command/point_targeting/use_ability/rapidseeds, + /datum/pet_command/attack, + /datum/pet_command/use_ability/solarbeam, + /datum/pet_command/use_ability/rapidseeds, ) //abilities diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm b/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm index ee93a9c12366f..ae4e7b75c92b0 100644 --- a/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm +++ b/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm @@ -166,7 +166,7 @@ finish_planning = FALSE ///pet commands -/datum/pet_command/point_targeting/use_ability/solarbeam +/datum/pet_command/use_ability/solarbeam command_name = "Launch solarbeam" command_desc = "Command your pet to launch a solarbeam at your target!" radial_icon = 'icons/effects/beam.dmi' @@ -174,10 +174,17 @@ speech_commands = list("beam", "solar") pet_ability_key = BB_SOLARBEAM_ABILITY -/datum/pet_command/point_targeting/use_ability/rapidseeds +/datum/pet_command/use_ability/solarbeam/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to use a solar beam on [target]!" + + +/datum/pet_command/use_ability/rapidseeds command_name = "Rapid seeds" command_desc = "Command your pet to launch a volley of seeds at your target!" radial_icon = 'icons/obj/weapons/guns/projectiles.dmi' radial_icon_state = "seedling" speech_commands = list("rapid", "seeds", "volley") pet_ability_key = BB_RAPIDSEEDS_ABILITY + +/datum/pet_command/use_ability/rapidseeds/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to unleash a volley of seeds on [target]!" diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm index 5a1166962be55..ce1c4e7cf1982 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm @@ -36,7 +36,7 @@ /datum/pet_command/free, /datum/pet_command/grub_spit, /datum/pet_command/follow, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/fetch, ) /mob/living/basic/mining/goldgrub/Initialize(mapload) diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm index 8ea2467a2a813..3d5d73a7343d1 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm @@ -211,6 +211,8 @@ /datum/pet_command/grub_spit command_name = "Spit" + radial_icon = 'icons/obj/ore.dmi' + radial_icon_state = "uranium" command_desc = "Ask your grub pet to spit out its ores." speech_commands = list("spit", "ores") @@ -222,4 +224,7 @@ controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/grub_spit/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to spit its ores!" + #undef BURROW_RANGE diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm index 5bfbbb1051a7f..347e9a95b61ce 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm @@ -61,7 +61,7 @@ if(isnull(ore_food)) balloon_alert(src, "no food!") else - melee_attack(ore_food) + UnarmedAttack(ore_food, TRUE, modifiers) return FALSE /mob/living/basic/mining/gutlunch/proc/after_birth(mob/living/basic/mining/gutlunch/grub/baby, mob/living/partner) @@ -111,11 +111,12 @@ //pet commands when we tame the gutluncher var/static/list/pet_commands = list( /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/breed/gutlunch, + /datum/pet_command/attack, + /datum/pet_command/breed/gutlunch, /datum/pet_command/follow, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/fetch, /datum/pet_command/mine_walls, ) diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm index 261f6d22a021b..4b329a0003aa8 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm @@ -102,10 +102,11 @@ /datum/pet_command/mine_walls command_name = "Mine" + radial_icon_state = "mine" command_desc = "Command your pet to mine down walls." speech_commands = list("mine", "smash") -/datum/pet_command/mine_walls/try_activate_command(mob/living/commander) +/datum/pet_command/mine_walls/try_activate_command(mob/living/commander, radial_command) var/mob/living/parent = weak_parent.resolve() if(isnull(parent)) return @@ -121,10 +122,13 @@ return SUBTREE_RETURN_FINISH_PLANNING controller.queue_behavior(/datum/ai_behavior/find_mineral_wall, BB_CURRENT_PET_TARGET) +/datum/pet_command/mine_walls/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to start mining!" + //pet commands -/datum/pet_command/point_targeting/breed/gutlunch +/datum/pet_command/breed/gutlunch -/datum/pet_command/point_targeting/breed/gutlunch/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/breed/gutlunch/set_command_target(mob/living/parent, atom/target) if(GLOB.gutlunch_count >= MAXIMUM_GUTLUNCH_POP) parent.balloon_alert_to_viewers("can't reproduce anymore!") return diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index 0b8babf82ec30..7e7d3e71819bf 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -32,7 +32,7 @@ /// The type of charging ability we give this mob var/charge_type = /datum/action/cooldown/mob_cooldown/charge/basic_charge/lobster /// The pet command for the charging ability we give this mob - var/charge_command = /datum/pet_command/point_targeting/use_ability/lob_charge + var/charge_command = /datum/pet_command/use_ability/lob_charge /// At which speed do we amputate limbs var/snip_speed = 5 SECONDS ///Lobstrosities are natural anglers. This rapresent their proficiency at fishing when not mindless @@ -72,10 +72,11 @@ var/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, - /datum/pet_command/point_targeting/attack, + /datum/pet_command/move, + /datum/pet_command/attack, charge_command, /datum/pet_command/follow, - /datum/pet_command/point_targeting/fish, + /datum/pet_command/fish, ) AddComponent(/datum/component/happiness) AddComponent(/datum/component/obeys_commands, pet_commands) @@ -153,7 +154,7 @@ ai_controller = /datum/ai_controller/basic_controller/lobstrosity/juvenile snip_speed = 6.5 SECONDS charge_type = /datum/action/cooldown/mob_cooldown/charge/basic_charge/lobster/shrimp - charge_command = /datum/pet_command/point_targeting/use_ability/lob_charge/shrimp + charge_command = /datum/pet_command/use_ability/lob_charge/shrimp base_fishing_level = SKILL_LEVEL_NOVICE /// What do we become when we grow up? var/mob/living/basic/mining/lobstrosity/grow_type = /mob/living/basic/mining/lobstrosity @@ -254,7 +255,7 @@ charger.apply_status_effect(/datum/status_effect/tired_post_charge/lesser) ///Command the lobster to charge at someone. -/datum/pet_command/point_targeting/use_ability/lob_charge +/datum/pet_command/use_ability/lob_charge command_name = "Charge" command_desc = "Command your lobstrosity to charge against someone." radial_icon = 'icons/mob/actions/actions_items.dmi' @@ -265,7 +266,7 @@ pet_ability_key = BB_TARGETED_ACTION ability_behavior = /datum/ai_behavior/pet_use_ability/then_attack/long_ranged -/datum/pet_command/point_targeting/use_ability/lob_charge/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/use_ability/lob_charge/set_command_target(mob/living/parent, atom/target) if (!target) return var/datum/targeting_strategy/targeter = GET_TARGETING_STRATEGY(parent.ai_controller.blackboard[targeting_strategy_key]) @@ -274,5 +275,5 @@ return FALSE return ..() -/datum/pet_command/point_targeting/use_ability/lob_charge/shrimp +/datum/pet_command/use_ability/lob_charge/shrimp ability_behavior = /datum/ai_behavior/pet_use_ability/then_attack/short_ranged diff --git a/code/modules/mob/living/basic/lavaland/mook/mook.dm b/code/modules/mob/living/basic/lavaland/mook/mook.dm index f492c83e74bac..539aa47cb287d 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook.dm @@ -41,8 +41,8 @@ var/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/attack, + /datum/pet_command/fetch, ) /mob/living/basic/mining/mook/Initialize(mapload) diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm index 15da812a0b237..2f374e2dda4b2 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm @@ -1,7 +1,7 @@ ///commands the chief can pick from GLOBAL_LIST_INIT(mook_commands, list( - new /datum/pet_command/point_targeting/attack, - new /datum/pet_command/point_targeting/fetch, + new /datum/pet_command/attack, + new /datum/pet_command/fetch, )) /datum/ai_controller/basic_controller/mook @@ -346,7 +346,7 @@ GLOBAL_LIST_INIT(mook_commands, list( if(!locate(/mob/living/basic/mining/mook) in oview(command_distance, controller.pawn)) return if(controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) - controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_BASIC_MOB_CURRENT_TARGET, /datum/pet_command/point_targeting/attack) + controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_BASIC_MOB_CURRENT_TARGET, /datum/pet_command/attack) return var/atom/ore_target = controller.blackboard[BB_ORE_TARGET] @@ -356,7 +356,7 @@ GLOBAL_LIST_INIT(mook_commands, list( if(get_dist(ore_target, living_pawn) <= 1) return - controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_ORE_TARGET, /datum/pet_command/point_targeting/fetch) + controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_ORE_TARGET, /datum/pet_command/fetch) /datum/ai_behavior/issue_commands action_cooldown = 5 SECONDS diff --git a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm index 8bf54b7165b28..3909a392195a8 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm @@ -47,11 +47,13 @@ GLOBAL_LIST_EMPTY(raptor_population) var/ridable_component = /datum/component/riding/creature/raptor //pet commands when we tame the raptor var/static/list/pet_commands = list( + /datum/pet_command/breed, /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, - /datum/pet_command/point_targeting/attack, + /datum/pet_command/attack, /datum/pet_command/follow, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/fetch, ) ///things we inherited from our parent var/datum/raptor_inheritance/inherited_stats @@ -158,7 +160,7 @@ GLOBAL_LIST_EMPTY(raptor_population) if(isnull(ore_food)) balloon_alert(src, "no food!") else - melee_attack(ore_food) + UnarmedAttack(ore_food, TRUE, modifiers) return FALSE /mob/living/basic/raptor/melee_attack(mob/living/target, list/modifiers, ignore_cooldown) diff --git a/code/modules/mob/living/basic/minebots/minebot.dm b/code/modules/mob/living/basic/minebots/minebot.dm index c9edfb0471f27..b14d1469ccd1f 100644 --- a/code/modules/mob/living/basic/minebots/minebot.dm +++ b/code/modules/mob/living/basic/minebots/minebot.dm @@ -42,13 +42,14 @@ ///the commands our owner can give us var/static/list/pet_commands = list( /datum/pet_command/idle/minebot, + /datum/pet_command/move, /datum/pet_command/protect_owner/minebot, /datum/pet_command/minebot_ability/light, /datum/pet_command/minebot_ability/dump, /datum/pet_command/automate_mining, /datum/pet_command/free/minebot, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/minebot, + /datum/pet_command/attack/minebot, ) ///possible colors the bot can have var/static/list/possible_colors= list( diff --git a/code/modules/mob/living/basic/minebots/minebot_ai.dm b/code/modules/mob/living/basic/minebots/minebot_ai.dm index 8043fda65d0a6..51a4e43f66ab5 100644 --- a/code/modules/mob/living/basic/minebots/minebot_ai.dm +++ b/code/modules/mob/living/basic/minebots/minebot_ai.dm @@ -281,14 +281,16 @@ /datum/pet_command/automate_mining command_name = "Automate mining" command_desc = "Make your minebot automatically mine!" - radial_icon = 'icons/obj/mining.dmi' - radial_icon_state = "pickaxe" + radial_icon_state = "mine" speech_commands = list("mine") callout_type = /datum/callout_option/mine /datum/pet_command/automate_mining/valid_callout_target(mob/living/caller, datum/callout_option/callout, atom/target) return ismineralturf(target) +/datum/pet_command/automate_mining/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to start mining!" + /datum/pet_command/automate_mining/execute_action(datum/ai_controller/controller) controller.set_blackboard_key(BB_AUTOMATED_MINING, TRUE) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) @@ -315,6 +317,9 @@ radial_icon_state = "mech_lights_off" ability_key = BB_MINEBOT_LIGHT_ABILITY +/datum/pet_command/minebot_ability/light/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to toggle its lights!" + /datum/pet_command/minebot_ability/dump command_name = "Dump ore" command_desc = "Make your minebot dump all its ore!" @@ -322,10 +327,13 @@ radial_icon_state = "mech_eject" ability_key = BB_MINEBOT_DUMP_ABILITY -/datum/pet_command/point_targeting/attack/minebot +/datum/pet_command/minebot_ability/light/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to dump its ore!" + +/datum/pet_command/attack/minebot attack_behaviour = /datum/ai_behavior/basic_ranged_attack/minebot -/datum/pet_command/point_targeting/attack/minebot/execute_action(datum/ai_controller/controller) +/datum/pet_command/attack/minebot/execute_action(datum/ai_controller/controller) controller.set_blackboard_key(BB_AUTOMATED_MINING, FALSE) var/mob/living/living_pawn = controller.pawn if(!living_pawn.combat_mode) diff --git a/code/modules/mob/living/basic/pets/dog/_dog.dm b/code/modules/mob/living/basic/pets/dog/_dog.dm index fd8920d2ca0e3..8fb053eef094c 100644 --- a/code/modules/mob/living/basic/pets/dog/_dog.dm +++ b/code/modules/mob/living/basic/pets/dog/_dog.dm @@ -7,10 +7,10 @@ speech_commands = list("good dog") // Set correct attack behaviour -/datum/pet_command/point_targeting/attack/dog +/datum/pet_command/attack/dog attack_behaviour = /datum/ai_behavior/basic_melee_attack/dog -/datum/pet_command/point_targeting/attack/dog/set_command_active(mob/living/parent, mob/living/commander) +/datum/pet_command/attack/dog/set_command_active(mob/living/parent, mob/living/commander) . = ..() parent.ai_controller.set_blackboard_key(BB_DOG_HARASS_HARM, TRUE) @@ -38,11 +38,12 @@ var/static/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, + /datum/pet_command/move, /datum/pet_command/good_boy/dog, /datum/pet_command/follow/dog, /datum/pet_command/perform_trick_sequence, - /datum/pet_command/point_targeting/attack/dog, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/attack/dog, + /datum/pet_command/fetch, /datum/pet_command/play_dead, ) ///icon state of the collar we can wear diff --git a/code/modules/mob/living/basic/pets/fox.dm b/code/modules/mob/living/basic/pets/fox.dm index 737f7b21391fd..fab5e79a3134b 100644 --- a/code/modules/mob/living/basic/pets/fox.dm +++ b/code/modules/mob/living/basic/pets/fox.dm @@ -31,9 +31,10 @@ ///list of our pet commands we follow var/static/list/pet_commands = list( /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack, + /datum/pet_command/attack, /datum/pet_command/perform_trick_sequence, ) diff --git a/code/modules/mob/living/basic/pets/orbie/orbie.dm b/code/modules/mob/living/basic/pets/orbie/orbie.dm index b4099a8c6344c..202bc84d37eb1 100644 --- a/code/modules/mob/living/basic/pets/orbie/orbie.dm +++ b/code/modules/mob/living/basic/pets/orbie/orbie.dm @@ -39,8 +39,9 @@ var/static/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, + /datum/pet_command/move, /datum/pet_command/untargeted_ability/pet_lights, - /datum/pet_command/point_targeting/use_ability/take_photo, + /datum/pet_command/use_ability/take_photo, /datum/pet_command/follow/orbie, /datum/pet_command/perform_trick_sequence, ) diff --git a/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm b/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm index a978b750d5036..aef780533795f 100644 --- a/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm +++ b/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm @@ -123,17 +123,24 @@ return SUBTREE_RETURN_FINISH_PLANNING return ..() -/datum/pet_command/point_targeting/use_ability/take_photo +/datum/pet_command/use_ability/pet_lights/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to toggle its lights!" + +/datum/pet_command/use_ability/take_photo command_name = "Photo" command_desc = "Make your pet take a photo!" - radial_icon = 'icons/mob/simple/pets.dmi' - radial_icon_state = "orbie_lights_action" + radial_icon = 'icons/obj/art/camera.dmi' + radial_icon_state = "camera" speech_commands = list("photo", "picture", "image") command_feedback = "Readys camera mode" pet_ability_key = BB_PHOTO_ABILITY targeting_strategy_key = BB_TARGETING_STRATEGY -/datum/pet_command/point_targeting/use_ability/take_photo/execute_action(datum/ai_controller/controller) +/datum/pet_command/use_ability/take_photo/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to take a photo of [target]!" + + +/datum/pet_command/use_ability/take_photo/execute_action(datum/ai_controller/controller) if(controller.blackboard[BB_VIRTUAL_PET_LEVEL] < 3) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return SUBTREE_RETURN_FINISH_PLANNING @@ -152,6 +159,9 @@ return FALSE return findtext(spoken_text, text_command) +/datum/pet_command/perform_trick_sequence/light/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to dance!" + /datum/pet_command/perform_trick_sequence/execute_action(datum/ai_controller/controller) var/mob/living/living_pawn = controller.pawn var/list/trick_sequence = controller.blackboard[BB_TRICK_SEQUENCE] diff --git a/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm index 77263b1748963..41b928aa75103 100644 --- a/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm +++ b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm @@ -236,3 +236,6 @@ radial_icon_state = "1" speech_commands = list("rune", "revival") ability_key = BB_RUNE_ABILITY + +/datum/pet_command/untargeted_ability/draw_rune/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to draw a rune!" diff --git a/code/modules/mob/living/basic/slime/ai/pet_command.dm b/code/modules/mob/living/basic/slime/ai/pet_command.dm index 211d7aa552cd8..4b50b2b32b9e8 100644 --- a/code/modules/mob/living/basic/slime/ai/pet_command.dm +++ b/code/modules/mob/living/basic/slime/ai/pet_command.dm @@ -1,4 +1,4 @@ -/datum/pet_command/point_targeting/attack/slime +/datum/pet_command/attack/slime speech_commands = list("attack", "sic", "kill", "eat", "feed") command_feedback = "blorbles" pointed_reaction = "and blorbles" @@ -6,7 +6,7 @@ var/hunting_behavior = /datum/ai_behavior/hunt_target/interact_with_target/slime -/datum/pet_command/point_targeting/attack/slime/execute_action(datum/ai_controller/controller) +/datum/pet_command/attack/slime/execute_action(datum/ai_controller/controller) var/mob/living/basic/slime/slime_pawn = controller.pawn if(isslime(slime_pawn) && slime_pawn.can_feed_on(controller.blackboard[BB_CURRENT_PET_TARGET], check_friendship = TRUE)) diff --git a/code/modules/mob/living/basic/slime/slime.dm b/code/modules/mob/living/basic/slime/slime.dm index 010913f44258b..8623f69b0e4cd 100644 --- a/code/modules/mob/living/basic/slime/slime.dm +++ b/code/modules/mob/living/basic/slime/slime.dm @@ -97,7 +97,7 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/slime, + /datum/pet_command/attack/slime, ) /// Our evolve action diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index 7ff033a030e60..9163963bbb281 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -59,7 +59,7 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack + /datum/pet_command/attack ) /// Carp want to eat raw meat var/static/list/desired_food = list(/obj/item/food/meat/slab, /obj/item/food/meat/rawcutlet) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm index 810c45603862b..26894850b1989 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm @@ -1,6 +1,6 @@ #define MAGICARP_SPELL_TARGET_SEEK_RANGE 4 -/datum/pet_command/point_targeting/use_ability/magicarp +/datum/pet_command/use_ability/magicarp pet_ability_key = BB_MAGICARP_SPELL /datum/ai_planning_subtree/attack_obstacle_in_path/carp diff --git a/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm b/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm index 65d16cfb490dd..3b6d1e5e922fd 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm @@ -56,8 +56,8 @@ GLOBAL_LIST_INIT(magicarp_spell_colours, list( /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/use_ability/magicarp, + /datum/pet_command/attack, + /datum/pet_command/use_ability/magicarp, ) /// List of all projectiles we can fire. /// Non-static, because subtypes can have their own lists. diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm index f7997e589695d..74f6c76b459e7 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm @@ -65,7 +65,7 @@ /datum/pet_command/free, /datum/pet_command/protect_owner, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/mouse + /datum/pet_command/attack/mouse ) /// Commands you can give to glockroaches var/static/list/glockroach_commands = list( @@ -73,7 +73,7 @@ /datum/pet_command/free, /datum/pet_command/protect_owner/glockroach, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/glockroach + /datum/pet_command/attack/glockroach ) /datum/action/cooldown/mob_cooldown/riot/IsAvailable(feedback = FALSE) @@ -211,7 +211,7 @@ return TRUE // Command you can give to a mouse to make it kill someone -/datum/pet_command/point_targeting/attack/mouse +/datum/pet_command/attack/mouse speech_commands = list("attack", "sic", "kill", "cheese em") command_feedback = "squeak!" // Frogs and roaches can squeak too it's fine pointed_reaction = "and squeaks aggressively" @@ -219,7 +219,7 @@ attack_behaviour = /datum/ai_behavior/basic_melee_attack // Command you can give to a mouse to make it kill someone -/datum/pet_command/point_targeting/attack/glockroach +/datum/pet_command/attack/glockroach speech_commands = list("attack", "sic", "kill", "cheese em") command_feedback = "squeak!" pointed_reaction = "and cocks its gun" diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index 615f314bf2e4b..5ac15722a5b35 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -117,7 +117,7 @@ var/static/cached_string = null if(isnull(cached_string)) - cached_string = examine_block(jointext(create_login_string(), "\n")) + cached_string = boxed_message(jointext(create_login_string(), "\n")) to_chat(src, cached_string, type = MESSAGE_TYPE_INFO) diff --git a/code/modules/mob/living/basic/turtle/turtle.dm b/code/modules/mob/living/basic/turtle/turtle.dm new file mode 100644 index 0000000000000..4d7c73edec6ca --- /dev/null +++ b/code/modules/mob/living/basic/turtle/turtle.dm @@ -0,0 +1,240 @@ +#define PATH_PEST_KILLER "path_pest_killer" +#define PATH_PLANT_HEALER "path_plant_healer" +#define PATH_PLANT_MUTATOR "path_plant_mutator" +#define REQUIRED_TREE_GROWTH 250 +#define UPPER_BOUND_VOLUME 50 +#define LOWER_BOUND_VOLUME 10 + +/mob/living/basic/turtle + name = "turtle" + desc = "Dog." + icon_state = "turtle" + icon_living = "turtle" + icon_dead = "turtle_dead" + base_icon_state = "turtle" + icon = 'icons/mob/simple/pets.dmi' + butcher_results = list(/obj/item/food/meat/slab = 3, /obj/item/food/pickle = 1, /obj/item/stack/sheet/mineral/wood = 10) + mob_biotypes = MOB_ORGANIC | MOB_PLANT + mobility_flags = MOBILITY_FLAGS_REST_CAPABLE_DEFAULT + health = 100 + maxHealth = 100 + speed = 5 + verb_say = "snaps" + verb_ask = "snaps curiously" + verb_exclaim = "snaps loudly" + verb_yell = "snaps loudly" + faction = list(FACTION_NEUTRAL) + ai_controller = /datum/ai_controller/basic_controller/turtle + ///our displayed tree + var/mutable_appearance/grown_tree + ///growth progress of our tree + var/list/path_growth_progress = list( + PATH_PLANT_HEALER = 0, + PATH_PLANT_MUTATOR = 0, + PATH_PEST_KILLER = 0, + ) + ///what nutrients leads to each evolution path + var/static/list/path_requirements = list( + //plant healers + /datum/reagent/plantnutriment/eznutriment = PATH_PLANT_HEALER, + /datum/reagent/plantnutriment/robustharvestnutriment = PATH_PLANT_HEALER, + /datum/reagent/plantnutriment/endurogrow = PATH_PLANT_HEALER, + //plant mutators + /datum/reagent/plantnutriment/left4zednutriment = PATH_PLANT_MUTATOR, + /datum/reagent/uranium = PATH_PLANT_MUTATOR, + //pest killers + /datum/reagent/toxin/pestkiller = PATH_PEST_KILLER, + ) + ///if we are fully grown, what is our path + var/developed_path + ///our last east/west direction + var/last_direction = WEST + +/mob/living/basic/turtle/Initialize(mapload) + . = ..() + + desc = pick( + "Likely Dog...", + "Praise the Dog!", + "Dog ahead.", + "Could this be a Dog?", + ) + var/static/list/eatable_food = list(/obj/item/seeds) + ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(eatable_food)) + AddElement(/datum/element/basic_eating, food_types = eatable_food) + AddComponent(/datum/component/happiness) + RegisterSignal(src, COMSIG_MOB_PRE_EAT, PROC_REF(pre_eat_food)) + update_appearance() + create_reagents(150, REAGENT_HOLDER_ALIVE) + add_verb(src, /mob/living/proc/toggle_resting) + START_PROCESSING(SSprocessing, src) + +/mob/living/basic/turtle/setDir(newdir) + if(REVERSE_DIR(last_direction) & newdir) + transform = transform.Scale(-1, 1) + last_direction = REVERSE_DIR(last_direction) + return ..() + +/mob/living/basic/turtle/proc/retrieve_destined_path() + var/current_max_growth = 0 + var/destined_path + for(var/evolution_path in path_growth_progress) + if(path_growth_progress[evolution_path] > current_max_growth) + destined_path = evolution_path + current_max_growth = path_growth_progress[evolution_path] + if(isnull(destined_path)) + destined_path = PATH_PLANT_HEALER + return destined_path + +/mob/living/basic/turtle/process(seconds_per_tick) + if(isnull(reagents) || !length(reagents.reagent_list)) //if we have no reagents, default to our highest destined path + set_plant_growth(retrieve_destined_path(), 0.5) + return + + for(var/datum/reagent/existing_reagent as anything in reagents.reagent_list) + var/evolution_path = path_requirements[existing_reagent.type] + + switch(existing_reagent.volume) + if(UPPER_BOUND_VOLUME to INFINITY) + set_plant_growth(evolution_path, 3) + if(LOWER_BOUND_VOLUME to UPPER_BOUND_VOLUME) + set_plant_growth(evolution_path, 2) + if(1 to LOWER_BOUND_VOLUME) + set_plant_growth(evolution_path, 1) + + reagents.remove_reagent(existing_reagent.type, 0.5) + +/mob/living/basic/turtle/proc/set_plant_growth(evolution_path, amount) + path_growth_progress[evolution_path] += amount + if(path_growth_progress[evolution_path] >= REQUIRED_TREE_GROWTH) + evolve_turtle(evolution_path) + +/mob/living/basic/turtle/examine(mob/user) + . = ..() + + if(stat == DEAD) + . += span_notice("Its tree seems to be all withered...") + return + + var/destined_path = retrieve_destined_path() + var/current_max_growth = path_growth_progress[destined_path] + + var/text_to_display = "Its tree seems to be exuding " + switch(destined_path) + if(PATH_PEST_KILLER) + text_to_display += "pest killing" + if(PATH_PLANT_HEALER) + text_to_display += "plant healing" + if(PATH_PLANT_MUTATOR) + text_to_display += "plant mutating" + + text_to_display += " properties... which [current_max_growth >= REQUIRED_TREE_GROWTH ? "seems to be fully grown" : "is yet to develop"]." + . += span_notice(text_to_display) + + +/mob/living/basic/turtle/proc/evolve_turtle(evolution_path) + var/static/list/evolution_gains = list( + PATH_PLANT_HEALER = list( + "tree_appearance" = "healer_tree", + "tree_ability" = /datum/action/cooldown/mob_cooldown/turtle_tree/healer, + ), + PATH_PEST_KILLER = list( + "tree_appearance" = "killer_tree", + "tree_ability" = /datum/action/cooldown/mob_cooldown/turtle_tree/killer, + ), + PATH_PLANT_MUTATOR = list( + "tree_appearance" = "mutator_tree", + "tree_ability" = /datum/action/cooldown/mob_cooldown/turtle_tree/mutator, + ), + ) + + var/tree_icon_state = evolution_gains[evolution_path]["tree_appearance"] + grown_tree = mutable_appearance(icon = 'icons/mob/simple/turtle_trees.dmi', icon_state = tree_icon_state) + + var/new_ability_path = evolution_gains[evolution_path]["tree_ability"] + developed_path = evolution_path + var/datum/action/cooldown/tree_ability = new new_ability_path(src) + tree_ability?.Grant(src) + ai_controller?.set_blackboard_key(BB_TURTLE_TREE_ABILITY, tree_ability) + STOP_PROCESSING(SSprocessing, src) + update_appearance() + +/mob/living/basic/turtle/update_icon_state() + . = ..() + if(stat == DEAD) + return + icon_state = resting ? "[base_icon_state]_resting" : base_icon_state + +/mob/living/basic/turtle/update_overlays() + . = ..() + if(stat == DEAD) + var/mutable_appearance/dead_overlay = mutable_appearance(icon = 'icons/mob/simple/pets.dmi', icon_state = developed_path ? "dead_tree" : "growing_tree") + dead_overlay.pixel_y = -2 + . += dead_overlay + return + var/pixel_offset = resting ? -2 : 2 + var/mutable_appearance/living_tree = grown_tree ? grown_tree : mutable_appearance(icon = icon, icon_state = "growing_tree") + living_tree.pixel_y = pixel_offset + . += living_tree + +/mob/living/basic/turtle/update_resting() + . = ..() + if(stat == DEAD) + return + update_appearance() + +/mob/living/basic/turtle/item_interaction(mob/living/user, obj/item/used_item, list/modifiers) + if(!istype(used_item, /obj/item/reagent_containers)) + return NONE + + if(isnull(used_item.reagents)) + balloon_alert(user, "empty!") + return ITEM_INTERACT_SUCCESS + + if(stat == DEAD) + balloon_alert(user, "its dead!") + return ITEM_INTERACT_SUCCESS + + var/should_transfer = FALSE + for(var/reagent in path_requirements) + if(used_item.reagents.has_reagent(reagent)) + should_transfer = TRUE + break + + if(!should_transfer) + balloon_alert(user, "refuses to drink!") + return ITEM_INTERACT_SUCCESS + + if(!do_after(user, 1.5 SECONDS, target = src)) + return ITEM_INTERACT_SUCCESS + + used_item.reagents.trans_to(reagents, 5) + balloon_alert(user, "drinks happily") + playsound(src, 'sound/items/drink.ogg', vol = 25, vary = TRUE) + return ITEM_INTERACT_SUCCESS + +/mob/living/basic/turtle/proc/pre_eat_food(datum/source, obj/item/seeds/potential_food) + SIGNAL_HANDLER + + if(!istype(potential_food)) + return NONE + if(ispath(potential_food.product, /obj/item/food/grown)) + addtimer(CALLBACK(src, PROC_REF(process_food), potential_food.product), 30 SECONDS) + return NONE + +/mob/living/basic/turtle/proc/process_food(food_path) + if(QDELETED(src) || stat != CONSCIOUS) + return + new food_path(drop_location()) + balloon_alert_to_viewers("spits out some food") + +/mob/living/basic/turtle/death(gibbed) + . = ..() + STOP_PROCESSING(SSprocessing, src) + +#undef PATH_PEST_KILLER +#undef PATH_PLANT_HEALER +#undef PATH_PLANT_MUTATOR +#undef REQUIRED_TREE_GROWTH +#undef UPPER_BOUND_VOLUME +#undef LOWER_BOUND_VOLUME diff --git a/code/modules/mob/living/basic/turtle/turtle_ability.dm b/code/modules/mob/living/basic/turtle/turtle_ability.dm new file mode 100644 index 0000000000000..3c3172b8cd558 --- /dev/null +++ b/code/modules/mob/living/basic/turtle/turtle_ability.dm @@ -0,0 +1,140 @@ +#define TREE_FIELD_DURATION_EFFECT 10 SECONDS +#define WARP_ANIMATE_TIME 0.35 SECONDS + +/datum/action/cooldown/mob_cooldown/turtle_tree + name = "Tree Ability" + desc = "Invoke your tree's special ability." + cooldown_time = 2 MINUTES + click_to_activate = FALSE + button_icon = 'icons/mob/simple/pets.dmi' + button_icon_state = "turtle" + ///type of effect our tree releases + var/effect_path + ///how many times our ability affects surroundings + var/maximum_intervals = 5 + ///time between each interval + var/time_between_intervals = 3 SECONDS + ///range our tree affects + var/tree_range = 5 + ///warp effect to apply some distortion to our field + var/atom/movable/warp_effect/turtle_field/warp + +/datum/action/cooldown/mob_cooldown/turtle_tree/Activate(atom/target) + . = ..() + warp = new(owner) + RegisterSignal(warp, COMSIG_QDELETING, PROC_REF(remove_warp)) + warp.alpha = 0 + owner.vis_contents += warp + + for(var/index in 0 to maximum_intervals) + addtimer(CALLBACK(src, PROC_REF(tree_effect)), time_between_intervals * index) + + animate(warp, transform = matrix(), alpha = warp::alpha, time = WARP_ANIMATE_TIME) + addtimer(CALLBACK(src, PROC_REF(warp_extinguish)), (time_between_intervals * maximum_intervals) + 3 SECONDS) + +/datum/action/cooldown/mob_cooldown/turtle_tree/proc/warp_extinguish() + if(QDELETED(warp)) + return + animate(warp, alpha = 0, time = WARP_ANIMATE_TIME) + addtimer(CALLBACK(src, PROC_REF(remove_warp)), WARP_ANIMATE_TIME) + +/datum/action/cooldown/mob_cooldown/turtle_tree/proc/remove_warp() + SIGNAL_HANDLER + + UnregisterSignal(warp, COMSIG_QDELETING) + warp = null + +///effect we apply on our trees +/datum/action/cooldown/mob_cooldown/turtle_tree/proc/tree_effect() + SHOULD_CALL_PARENT(TRUE) + return (pre_effect_apply()) + +///things we should check for before applying our effects +/datum/action/cooldown/mob_cooldown/turtle_tree/proc/pre_effect_apply() + if(QDELETED(owner) || owner.stat == DEAD) + return FALSE + var/obj/effect/tree_effect = new effect_path + owner.vis_contents += tree_effect + return TRUE + +///healer tree, heals nearby plants by small amounts +/datum/action/cooldown/mob_cooldown/turtle_tree/healer + effect_path = /obj/effect/temp_visual/circle_wave/tree/healer + ///amount we heal plants by + var/heal_amount = 5 + +/datum/action/cooldown/mob_cooldown/turtle_tree/healer/tree_effect() + . = ..() + if(!.) + return + for(var/obj/machinery/hydroponics/hydro in oview(tree_range, owner)) + if(isnull(hydro.myseed)) + continue + hydro.adjust_plant_health(heal_amount) + +///killer tree, kills plant's pests and weeds, aswell as nearby vermin +/datum/action/cooldown/mob_cooldown/turtle_tree/killer + effect_path = /obj/effect/temp_visual/circle_wave/tree/killer + ///amount we heal plants by + var/vermin_damage_amount = 20 + ///type of vermin our field affects + var/static/list/vermin_mob_targets = typecacheof(list( + /mob/living/basic/cockroach, + /mob/living/basic/mouse/rat, + )) + ///how much we reduce weed levels + var/weed_level_reduce = 2 + +/datum/action/cooldown/mob_cooldown/turtle_tree/killer/tree_effect() + . = ..() + if(!.) + return + + for(var/atom/possible_target as anything in oview(tree_range, owner)) + + if(is_type_in_typecache(possible_target, vermin_mob_targets)) + var/mob/living/living_target = possible_target + living_target.apply_damage(vermin_damage_amount) + continue + + if(!istype(possible_target, /obj/machinery/hydroponics)) + continue + + var/obj/machinery/hydroponics/hydro = possible_target + if(isnull(hydro.myseed)) + continue + hydro.set_weedlevel(hydro.weedlevel - weed_level_reduce) + +///mutator tree, mutates nearby plants! +/datum/action/cooldown/mob_cooldown/turtle_tree/mutator + effect_path = /obj/effect/temp_visual/circle_wave/tree/mutator + ///how much we mutate plants + var/mutator_boost = 1 + +/datum/action/cooldown/mob_cooldown/turtle_tree/mutator/tree_effect() + . = ..() + if(!.) + return + for(var/obj/machinery/hydroponics/hydro in oview(tree_range, owner)) + hydro.myseed?.adjust_instability(mutator_boost) + +/atom/movable/warp_effect/turtle_field + alpha = 75 + +///effects we give our tree abilities depending on their type +/obj/effect/temp_visual/circle_wave/tree + vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE + duration = 10 SECONDS + amount_to_scale = 3 + +/obj/effect/temp_visual/circle_wave/tree/healer + color = "#28a3bc" + +/obj/effect/temp_visual/circle_wave/tree/killer + color = "#ce3ebf" + +/obj/effect/temp_visual/circle_wave/tree/mutator + color = "#c49f26" + +#undef TREE_FIELD_DURATION_EFFECT +#undef WARP_ANIMATE_TIME diff --git a/code/modules/mob/living/basic/turtle/turtle_ai.dm b/code/modules/mob/living/basic/turtle/turtle_ai.dm new file mode 100644 index 0000000000000..1af7c3111f78c --- /dev/null +++ b/code/modules/mob/living/basic/turtle/turtle_ai.dm @@ -0,0 +1,92 @@ +/datum/ai_controller/basic_controller/turtle + blackboard = list( + BB_HAPPY_EMOTIONS = list( + "wiggles its tree in excitement!", + "raises its head up high!", + "wags its tail enthusiastically!", + ), + BB_MODERATE_EMOTIONS = list( + "keeps its head level, eyes half-closed.", + "basks in the light peacefully.", + ), + BB_SAD_EMOTIONS = list( + "looks towards the floor in dissapointment...", + "the leaves on its tree droop...", + ), + ) + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk/less_walking + planning_subtrees = list( + /datum/ai_planning_subtree/find_food, + /datum/ai_planning_subtree/express_happiness, + /datum/ai_planning_subtree/use_mob_ability/turtle_tree, + /datum/ai_planning_subtree/find_and_hunt_target/headbutt_people, //playfully headbutt people's legs + /datum/ai_planning_subtree/find_and_hunt_target/sniff_flora, //mmm the aroma + ) + +/datum/ai_planning_subtree/use_mob_ability/turtle_tree + ability_key = BB_TURTLE_TREE_ABILITY + +/datum/ai_planning_subtree/use_mob_ability/turtle_tree/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/happiness_count = controller.blackboard[BB_BASIC_HAPPINESS] * 100 + if(happiness_count > 75) + return ..() + if(!SPT_PROB(happiness_count / 50, seconds_per_tick)) + return + return ..() + +/datum/ai_planning_subtree/find_and_hunt_target/sniff_flora + target_key = BB_TURTLE_FLORA_TARGET + finding_behavior = /datum/ai_behavior/find_hunt_target/sniff_flora + hunting_behavior = /datum/ai_behavior/hunt_target/sniff_flora + hunt_targets = list( + /obj/machinery/hydroponics, + /obj/item/kirbyplants, + ) + hunt_range = 5 + hunt_chance = 45 + +/datum/ai_behavior/find_hunt_target/sniff_flora + action_cooldown = 1 MINUTES + behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + +/datum/ai_behavior/find_hunt_target/sniff_flora/valid_dinner(mob/living/source, obj/machinery/hydroponics/dinner, radius, datum/ai_controller/controller, seconds_per_tick) + if(!istype(dinner)) + return TRUE + if(isnull(dinner.myseed)) + return FALSE + if(dinner.weedlevel > 5 || dinner.pestlevel > 5) //too smelly + return FALSE + return can_see(source, dinner, radius) + +/datum/ai_behavior/hunt_target/sniff_flora + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/sniff_flora/target_caught(mob/living/hunter, atom/hunted) + hunter.manual_emote("Enjoys the sweet scent eminating from [hunted::name]!") + +/datum/ai_planning_subtree/find_and_hunt_target/headbutt_people + target_key = BB_TURTLE_HEADBUTT_VICTIM + finding_behavior = /datum/ai_behavior/find_hunt_target/human_to_headbutt + hunting_behavior = /datum/ai_behavior/hunt_target/headbutt_leg + hunt_targets = list(/mob/living/carbon/human) + hunt_range = 4 + hunt_chance = 45 + +/datum/ai_behavior/find_hunt_target/human_to_headbutt + action_cooldown = 2 MINUTES + behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + +/datum/ai_behavior/find_hunt_target/human_to_headbutt/valid_dinner(mob/living/source, mob/living/carbon/human/dinner, radius, datum/ai_controller/controller, seconds_per_tick) + if(dinner.stat != CONSCIOUS) + return FALSE + if(isnull(dinner.get_bodypart(BODY_ZONE_R_LEG)) && isnull(dinner.get_bodypart(BODY_ZONE_L_LEG))) //no legs to headbutt! + return FALSE + return can_see(source, dinner, radius) + +/datum/ai_behavior/hunt_target/headbutt_leg + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/headbutt_leg/target_caught(mob/living/hunter, atom/hunted) + hunter.manual_emote("playfully headbutts [hunted]'s legs!") + diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index da51117d71a76..9bbd910d144ba 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -425,9 +425,9 @@ visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] осматривает себя."), \ span_notice("Вы проверяете себя на наличие осколков.")) if(I.is_embed_harmless()) - to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>[capitalize(I.declent_ru(NOMINATIVE))] застревает у вас на [LB.declent_ru(PREPOSITIONAL)]!</a>") + to_chat(src, "\t <a href='byond://?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>[capitalize(I.declent_ru(NOMINATIVE))] застревает у вас на [LB.declent_ru(PREPOSITIONAL)]!</a>") else - to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>[capitalize(I.declent_ru(NOMINATIVE))] впивается у вас в [LB.declent_ru(PREPOSITIONAL)]!</a>") + to_chat(src, "\t <a href='byond://?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>[capitalize(I.declent_ru(NOMINATIVE))] впивается у вас в [LB.declent_ru(PREPOSITIONAL)]!</a>") return embeds @@ -662,7 +662,8 @@ if (HAS_TRAIT(src, TRAIT_GENELESS)) return FALSE - if (run_armor_check(attack_flag = BIO, absorb_text = "Ваша броня защищает вас от: [scramble_source]!") >= 100) + if (run_armor_check(attack_flag = BIO, silent = TRUE) >= 100) + to_chat(src, span_warning("Ваша броня поглощает воздействие от [scramble_source]!")) return FALSE if (!length(GLOB.bioscrambler_valid_organs) || !length(GLOB.bioscrambler_valid_parts)) diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 73784cc89f003..d4d6c8d449f9f 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -455,7 +455,7 @@ if(wear_id && !(wear_id.item_flags & EXAMINE_SKIP)) var/obj/item/card/id/id = wear_id.GetID() if(id && get_dist(user, src) <= ID_EXAMINE_DISTANCE) - var/id_href = "<a href='?src=[REF(src)];see_id=1;id_ref=[REF(id)];id_name=[id.registered_name];examine_time=[world.time]'>[wear_id.examine_title(user, declent = ACCUSATIVE)]</a>" + var/id_href = "<a href='byond://?src=[REF(src)];see_id=1;id_ref=[REF(id)];id_name=[id.registered_name];examine_time=[world.time]'>[wear_id.examine_title(user, declent = ACCUSATIVE)]</a>" . += "[t_He] носит [id_href]." else @@ -495,7 +495,7 @@ var/datum/record/crew/target_record = find_record(perpname) if(target_record) . += "Должность: [target_record.rank]" - . += "<a href='?src=[REF(src)];hud=1;photo_front=1;examine_time=[world.time]'>\[Фото спереди\]</a><a href='?src=[REF(src)];hud=1;photo_side=1;examine_time=[world.time]'>\[Фото сбоку\]</a>" + . += "<a href='byond://?src=[REF(src)];hud=1;photo_front=1;examine_time=[world.time]'>\[Фото спереди\]</a><a href='?src=[REF(src)];hud=1;photo_side=1;examine_time=[world.time]'>\[Фото сбоку\]</a>" if(HAS_TRAIT(user, TRAIT_MEDICAL_HUD) && HAS_TRAIT(user, TRAIT_SECURITY_HUD)) title = separator_hr("Медицинский и безопасности анализы") . += get_medhud_examine_info(user, target_record) @@ -526,13 +526,13 @@ . += "<span class='notice ml-1'>Обнаружены кибернетические модификации:</span>" . += "<span class='notice ml-2'>[english_list(cybers, and_text = ", и")]</span>" if(target_record) - . += "<a href='?src=[REF(src)];hud=m;physical_status=1;examine_time=[world.time]'>\[[target_record.physical_status]\]</a>" - . += "<a href='?src=[REF(src)];hud=m;mental_status=1;examine_time=[world.time]'>\[[target_record.mental_status]\]</a>" + . += "<a href='byond://?src=[REF(src)];hud=m;physical_status=1;examine_time=[world.time]'>\[[target_record.physical_status]\]</a>" + . += "<a href='byond://?src=[REF(src)];hud=m;mental_status=1;examine_time=[world.time]'>\[[target_record.mental_status]\]</a>" else . += "\[Запись отсутствует\]" . += "\[Запись отсутствует\]" - . += "<a href='?src=[REF(src)];hud=m;evaluation=1;examine_time=[world.time]'>\[Медицинское обследование\]</a>" - . += "<a href='?src=[REF(src)];hud=m;quirk=1;examine_time=[world.time]'>\[Показать черты\]</a>" + . += "<a href='byond://?src=[REF(src)];hud=m;evaluation=1;examine_time=[world.time]'>\[Медицинское обследование\]</a>" + . += "<a href='byond://?src=[REF(src)];hud=m;quirk=1;examine_time=[world.time]'>\[Показать черты\]</a>" /// Collects information displayed about src when examined by a user with a security HUD. /mob/living/carbon/proc/get_sechud_examine_info(mob/living/user, datum/record/crew/target_record) @@ -546,15 +546,15 @@ if(target_record.security_note) security_note = target_record.security_note if(ishuman(user)) - . += "Криминальный статус: <a href='?src=[REF(src)];hud=s;status=1;examine_time=[world.time]'>\[[wanted_status]\]</a>" + . += "Криминальный статус: <a href='byond://?src=[REF(src)];hud=s;status=1;examine_time=[world.time]'>\[[wanted_status]\]</a>" else . += "Криминальный статус: [wanted_status]" . += "Важные заметки: [security_note]" - . += "Записи охраны: <a href='?src=[REF(src)];hud=s;view=1;examine_time=[world.time]'>\[Показать\]</a>" + . += "Записи охраны: <a href='byond://?src=[REF(src)];hud=s;view=1;examine_time=[world.time]'>\[Показать\]</a>" if(ishuman(user)) - . += "<a href='?src=[REF(src)];hud=s;add_citation=1;examine_time=[world.time]'>\[Добавить штраф\]</a>\ - <a href='?src=[REF(src)];hud=s;add_crime=1;examine_time=[world.time]'>\[Добавить преступление\]</a>\ - <a href='?src=[REF(src)];hud=s;add_note=1;examine_time=[world.time]'>\[Добавить примечание\]</a>" + . += "<a href='byond://?src=[REF(src)];hud=s;add_citation=1;examine_time=[world.time]'>\[Добавить штраф\]</a>\ + <a href='byond://?src=[REF(src)];hud=s;add_crime=1;examine_time=[world.time]'>\[Добавить преступление\]</a>\ + <a href='byond://?src=[REF(src)];hud=s;add_note=1;examine_time=[world.time]'>\[Добавить примечание\]</a>" /mob/living/carbon/human/examine_more(mob/user) . = ..() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b5232351674fd..44080f95f0052 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -141,7 +141,7 @@ id_examine += "</div>" // container id_examine += "</div>" // text - to_chat(viewer, examine_block(span_info(id_examine))) + to_chat(viewer, boxed_message(span_info(id_examine))) ///////HUDs/////// if(href_list["hud"]) @@ -318,7 +318,7 @@ sec_record_message += "\n<b>Преступление:</b> [crime.name]" sec_record_message += "\n<b>Описание:</b> [crime.details]" sec_record_message += "\n[crime.author] добавляет в [crime.time]" - to_chat(human_or_ghost_user, examine_block(sec_record_message)) + to_chat(human_or_ghost_user, boxed_message(sec_record_message)) return if(ishuman(human_or_ghost_user)) var/mob/living/carbon/human/human_user = human_or_ghost_user diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index bc430d081b123..cd87c316a2edd 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -676,7 +676,7 @@ if(quirks.len) combined_msg += span_notice("У вас имеются следующий черты: [get_quirk_string(FALSE, CAT_QUIRK_ALL)].") - to_chat(src, examine_block(combined_msg.Join("\n"))) + to_chat(src, boxed_message(combined_msg.Join("\n"))) /mob/living/carbon/human/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone) if(damage_type != BRUTE && damage_type != BURN) diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm index d3ac3453393f8..bbf8b990a7c28 100644 --- a/code/modules/mob/living/carbon/human/login.dm +++ b/code/modules/mob/living/carbon/human/login.dm @@ -31,5 +31,5 @@ if(LAZYLEN(afk_thefts) >= AFK_THEFT_MAX_MESSAGES) print_msg += span_warning("Возможно кто-то еще мог быть замешан, но это всё, что вы можете вспомнить...") - to_chat(src, examine_block(print_msg.Join("\n"))) + to_chat(src, boxed_message(print_msg.Join("\n"))) LAZYNULL(afk_thefts) diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index a8431d790b7ca..fad518a323465 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -262,12 +262,20 @@ if(HAS_TRAIT(user, TRAIT_KISS_OF_DEATH)) kiss_type = /obj/item/hand_item/kisser/death + var/datum/action/cooldown/ink_spit/ink_action = locate() in user.actions + if(ink_action?.IsAvailable()) + kiss_type = /obj/item/hand_item/kisser/ink + ink_action.StartCooldown() + else + ink_action = null + var/obj/item/kiss_blower = new kiss_type(user) if(user.put_in_hands(kiss_blower)) to_chat(user, span_notice("You ready your kiss-blowing hand.")) else qdel(kiss_blower) to_chat(user, span_warning("You're incapable of blowing a kiss in your current state.")) + ink_action?.ResetCooldown() /datum/emote/living/laugh key = "laugh" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 66fddc5c99e39..90c25f6c01f3f 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -2094,12 +2094,12 @@ GLOBAL_LIST_EMPTY(fire_appearances) . += {" <br><font size='1'>[VV_HREF_TARGETREF(refid, VV_HK_GIVE_DIRECT_CONTROL, "[ckey || "no ckey"]")] / [VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[real_name || "no real name"]", NAMEOF(src, real_name))]</font> <br><font size='1'> - BRUTE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=brute' id='brute'>[getBruteLoss()]</a> - FIRE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=fire' id='fire'>[getFireLoss()]</a> - TOXIN:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=toxin' id='toxin'>[getToxLoss()]</a> - OXY:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=oxygen' id='oxygen'>[getOxyLoss()]</a> - BRAIN:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=brain' id='brain'>[get_organ_loss(ORGAN_SLOT_BRAIN)]</a> - STAMINA:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=stamina' id='stamina'>[getStaminaLoss()]</a> + BRUTE:<font size='1'><a href='byond://?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=brute' id='brute'>[getBruteLoss()]</a> + FIRE:<font size='1'><a href='byond://?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=fire' id='fire'>[getFireLoss()]</a> + TOXIN:<font size='1'><a href='byond://?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=toxin' id='toxin'>[getToxLoss()]</a> + OXY:<font size='1'><a href='byond://?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=oxygen' id='oxygen'>[getOxyLoss()]</a> + BRAIN:<font size='1'><a href='byond://?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=brain' id='brain'>[get_organ_loss(ORGAN_SLOT_BRAIN)]</a> + STAMINA:<font size='1'><a href='byond://?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=stamina' id='stamina'>[getStaminaLoss()]</a> </font> "} diff --git a/code/modules/mob/living/navigation.dm b/code/modules/mob/living/navigation.dm index d68eacbb5fc6b..82c60315e9465 100644 --- a/code/modules/mob/living/navigation.dm +++ b/code/modules/mob/living/navigation.dm @@ -24,40 +24,50 @@ addtimer(CALLBACK(src, PROC_REF(create_navigation)), world.tick_lag) /mob/living/proc/create_navigation() + var/can_go_down = SSmapping.level_trait(z, ZTRAIT_DOWN) + var/can_go_up = SSmapping.level_trait(z, ZTRAIT_UP) var/list/destination_list = list() - for(var/atom/destination in GLOB.navigate_destinations) - if(!isatom(destination) || destination.z != z || get_dist(destination, src) > MAX_NAVIGATE_RANGE) + for(var/atom/destination as anything in GLOB.navigate_destinations) + if(get_dist(destination, src) > MAX_NAVIGATE_RANGE) continue var/destination_name = GLOB.navigate_destinations[destination] + if(destination.z != z && (can_go_down || can_go_up)) // up or down is just a good indicator "we're on the station", we don't need to check specifics + destination_name += ((get_dir_multiz(src, destination) & UP) ? " (Above)" : " (Below)") + destination_list[destination_name] = destination - if(!is_reserved_level(z)) //don't let us path to nearest staircase or ladder on shuttles in transit - if(z > 1) - destination_list["Близлежащий путь вниз"] = DOWN - if(z < world.maxz) - destination_list["Близлежащий путь вверх"] = UP + if(can_go_down) + destination_list["Близлежащий путь вниз"] = DOWN + if(can_go_up) + destination_list["Близлежащий путь вверх"] = UP if(!length(destination_list)) balloon_alert(src, "нет сигнала для навигации!") return var/platform_code = tgui_input_list(src, "Выберите локацию", "Навигация", sort_list(destination_list)) - var/navigate_target = destination_list[platform_code] + var/atom/navigate_target = destination_list[platform_code] - if(isnull(navigate_target)) - return - if(incapacitated) + if(isnull(navigate_target) || incapacitated) return - COOLDOWN_START(src, navigate_cooldown, 15 SECONDS) - if(navigate_target == UP || navigate_target == DOWN) - var/new_target = find_nearest_stair_or_ladder(navigate_target) + + var/finding_zchange = FALSE + COOLDOWN_START(src, navigate_cooldown, 15 SECONDS) + if(navigate_target == UP || navigate_target == DOWN || (isatom(navigate_target) && navigate_target.z != z)) + // lowering the cooldown to 5 seconds if we're navigating to a ladder or staircase instead of a proper destination + // (so we can decide to move to another destination right off the bat, rather than needing to wait) + COOLDOWN_START(src, navigate_cooldown, 5 SECONDS) + var/direction_name = isatom(navigate_target) ? "туда" : (navigate_target == UP ? "вверх" : "вниз") + var/nav_dir = isatom(navigate_target) ? (get_dir_multiz(src, navigate_target) & (UP|DOWN)) : navigate_target + var/atom/new_target = find_nearest_stair_or_ladder(nav_dir) if(!new_target) - balloon_alert(src, "не удалось найти лестницу [navigate_target == UP ? "вверх" : "вниз"]!") + balloon_alert(src, "не удалось найти ступеньки или лестницу ведущую [direction_name]!") return navigate_target = new_target + finding_zchange = TRUE if(!isatom(navigate_target)) stack_trace("Navigate target ([navigate_target]) is not an atom, somehow.") @@ -92,7 +102,9 @@ animate(path_image, 0.5 SECONDS, alpha = 150) addtimer(CALLBACK(src, PROC_REF(shine_navigation)), 0.5 SECONDS) RegisterSignal(src, COMSIG_LIVING_DEATH, PROC_REF(cut_navigation)) - balloon_alert(src, "навигация создана") + if(finding_zchange) + RegisterSignal(src, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(cut_navigation)) + balloon_alert(src, "путь к месту назначания построен") /mob/living/proc/shine_navigation() for(var/i in 1 to length(client.navigation_images)) @@ -107,7 +119,7 @@ for(var/image/navigation_path in client.navigation_images) client.images -= navigation_path client.navigation_images.Cut() - UnregisterSignal(src, COMSIG_LIVING_DEATH) + UnregisterSignal(src, list(COMSIG_LIVING_DEATH, COMSIG_MOVABLE_Z_CHANGED)) /** * Finds nearest ladder or staircase either up or down. diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 3565b3d375d40..5c98909004506 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -619,12 +619,12 @@ if (length(cameras)) var/obj/machinery/camera/cam = cameras[1] if (cam.can_use()) - queueAlarm("--- [alarm_type] alarm detected in [home_name]! (<A HREF=?src=[REF(src)];switchcamera=[REF(cam)]>[cam.c_tag]</A>)", alarm_type) + queueAlarm("--- [alarm_type] alarm detected in [home_name]! (<A href=byond://?src=[REF(src)];switchcamera=[REF(cam)]>[cam.c_tag]</A>)", alarm_type) else var/first_run = FALSE var/dat2 = "" for (var/obj/machinery/camera/camera as anything in cameras) - dat2 += "[(!first_run) ? "" : " | "]<A HREF=?src=[REF(src)];switchcamera=[REF(camera)]>[camera.c_tag]</A>" + dat2 += "[(!first_run) ? "" : " | "]<A href=byond://?src=[REF(src)];switchcamera=[REF(camera)]>[camera.c_tag]</A>" first_run = TRUE queueAlarm("--- [alarm_type] alarm detected in [home_name]! ([dat2])", alarm_type) else @@ -919,7 +919,7 @@ var/list/stored_name = list(null) SEND_SIGNAL(speaker, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, stored_name, FALSE) namepart = stored_name[NAME_PART_INDEX] || "[speaker.GetVoice()]" - var/hrefpart = "<a href='?src=[REF(src)];track=[html_encode(namepart)]'>" + var/hrefpart = "<a href='byond://?src=[REF(src)];track=[html_encode(namepart)]'>" var/jobpart = "Unknown" if(!HAS_TRAIT(speaker, TRAIT_UNKNOWN)) //don't fetch the speaker's job in case they have something that conseals their identity completely diff --git a/code/modules/mob/living/silicon/ai/ai_say.dm b/code/modules/mob/living/silicon/ai/ai_say.dm index 86f62cd67dab6..0c7828a4fa5fb 100644 --- a/code/modules/mob/living/silicon/ai/ai_say.dm +++ b/code/modules/mob/living/silicon/ai/ai_say.dm @@ -1,7 +1,7 @@ /mob/living/silicon/ai/compose_track_href(atom/movable/speaker, namepart) var/mob/M = speaker.GetSource() if(M) - return "<a href='?src=[REF(src)];track=[html_encode(namepart)]'>" + return "<a href='byond://?src=[REF(src)];track=[html_encode(namepart)]'>" return "" /mob/living/silicon/ai/compose_job(atom/movable/speaker, message_langs, raw_message, radio_freq) @@ -84,7 +84,7 @@ var/index = 0 for(var/word in GLOB.vox_sounds) index++ - dat += "<A href='?src=[REF(src)];say_word=[word]'>[capitalize(word)]</A>" + dat += "<A href='byond://?src=[REF(src)];say_word=[word]'>[capitalize(word)]</A>" if(index != GLOB.vox_sounds.len) dat += " / " diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 4adfe057c59fb..3f86c64333e9d 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -135,7 +135,7 @@ sleep(5 SECONDS) to_chat(src, span_notice("Receiving control information from APC.")) sleep(0.2 SECONDS) - to_chat(src, "<A HREF=?src=[REF(src)];emergencyAPC=[TRUE]>APC ready for connection.</A>") + to_chat(src, "<A href=byond://?src=[REF(src)];emergencyAPC=[TRUE]>APC ready for connection.</A>") apc_override = theAPC apc_override.ui_interact(src) setAiRestorePowerRoutine(POWER_RESTORATION_APC_FOUND) diff --git a/code/modules/mob/living/silicon/ai/login.dm b/code/modules/mob/living/silicon/ai/login.dm index f36dc84c08bf8..cd909eab9f531 100644 --- a/code/modules/mob/living/silicon/ai/login.dm +++ b/code/modules/mob/living/silicon/ai/login.dm @@ -4,7 +4,7 @@ return FALSE if(stat != DEAD) if(lacks_power() && apc_override) //Placing this in Login() in case the AI doesn't have this link for whatever reason. - to_chat(usr, "[span_warning("Main power is unavailable, backup power in use. Diagnostics scan complete.")] <A HREF='?src=[REF(src)];emergencyAPC=[TRUE]'>Local APC ready for connection.</A>") + to_chat(usr, "[span_warning("Main power is unavailable, backup power in use. Diagnostics scan complete.")] <A href='byond://?src=[REF(src)];emergencyAPC=[TRUE]'>Local APC ready for connection.</A>") set_eyeobj_visible(TRUE) if(multicam_on) end_multicam() diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm index 1754a89aa5cb9..be8f5e42c383e 100644 --- a/code/modules/mob/living/silicon/laws.dm +++ b/code/modules/mob/living/silicon/laws.dm @@ -2,7 +2,7 @@ laws_sanity_check() var/list/law_box = list(span_bold("Obey these laws:")) law_box += laws.get_law_list(include_zeroth = TRUE) - to_chat(src, examine_block(jointext(law_box, "\n"))) + to_chat(src, boxed_message(jointext(law_box, "\n"))) /mob/living/silicon/proc/try_sync_laws() return @@ -19,7 +19,7 @@ /mob/living/silicon/proc/deadchat_lawchange() var/list/the_laws = laws.get_law_list(include_zeroth = TRUE) var/lawtext = the_laws.Join("<br/>") - deadchat_broadcast("'s <b>laws were changed.</b> <a href='?src=[REF(src)]&dead=1&printlawtext=[url_encode(lawtext)]'>View</a>", span_name("[src]"), follow_target=src, message_type=DEADCHAT_LAWCHANGE) + deadchat_broadcast("'s <b>laws were changed.</b> <a href='byond://?src=[REF(src)]&dead=1&printlawtext=[url_encode(lawtext)]'>View</a>", span_name("[src]"), follow_target=src, message_type=DEADCHAT_LAWCHANGE) /mob/living/silicon/proc/post_lawchange(announce = TRUE) throw_alert(ALERT_NEW_LAW, /atom/movable/screen/alert/newlaw) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 14a920b350ae1..29e5700ba20c7 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -584,13 +584,13 @@ return switch(notifytype) if(AI_NOTIFICATION_NEW_BORG) //New Cyborg - to_chat(connected_ai, "<br><br>[span_notice("NOTICE - New cyborg connection detected: <a href='?src=[REF(connected_ai)];track=[html_encode(name)]'>[name]</a>")]<br>") + to_chat(connected_ai, "<br><br>[span_notice("NOTICE - New cyborg connection detected: <a href='byond://?src=[REF(connected_ai)];track=[html_encode(name)]'>[name]</a>")]<br>") if(AI_NOTIFICATION_NEW_MODEL) //New Model to_chat(connected_ai, "<br><br>[span_notice("NOTICE - Cyborg model change detected: [name] has loaded the [designation] model.")]<br>") if(AI_NOTIFICATION_CYBORG_RENAMED) //New Name to_chat(connected_ai, "<br><br>[span_notice("NOTICE - Cyborg reclassification detected: [oldname] is now designated as [newname].")]<br>") if(AI_NOTIFICATION_AI_SHELL) //New Shell - to_chat(connected_ai, "<br><br>[span_notice("NOTICE - New cyborg shell detected: <a href='?src=[REF(connected_ai)];track=[html_encode(name)]'>[name]</a>")]<br>") + to_chat(connected_ai, "<br><br>[span_notice("NOTICE - New cyborg shell detected: <a href='byond://?src=[REF(connected_ai)];track=[html_encode(name)]'>[name]</a>")]<br>") if(AI_NOTIFICATION_CYBORG_DISCONNECTED) //Tampering with the wires to_chat(connected_ai, "<br><br>[span_notice("NOTICE - Remote telemetry lost with [name].")]<br>") diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 734ec24ef028c..188d104a562f9 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -154,7 +154,7 @@ for(var/alarm_type in alarm_types_show) msg += "[uppertext(alarm_type)]: [alarm_types_show[alarm_type]] alarms detected. - " - msg += "<A href=?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>" + msg += "<A href=byond://?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>" to_chat(src, msg) if(length(alarms_to_clear) < 3) @@ -167,7 +167,7 @@ for(var/alarm_type in alarm_types_clear) msg += "[uppertext(alarm_type)]: [alarm_types_clear[alarm_type]] alarms cleared. - " - msg += "<A href=?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>" + msg += "<A href=byond://?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>" to_chat(src, msg) diff --git a/code/modules/mob/living/silicon/silicon_say.dm b/code/modules/mob/living/silicon/silicon_say.dm index d508c7b84f0f8..e4544219e745a 100644 --- a/code/modules/mob/living/silicon/silicon_say.dm +++ b/code/modules/mob/living/silicon/silicon_say.dm @@ -32,7 +32,7 @@ M, span_binarysay("\ Robotic Talk, \ - <a href='?src=[REF(M)];track=[html_encode(namepart)]'>[span_name("[namepart] ([designation])")]</a> \ + <a href='byond://?src=[REF(M)];track=[html_encode(namepart)]'>[span_name("[namepart] ([designation])")]</a> \ <span class='message'>[quoted_message]</span>\ "), avoid_highlighting = src == M diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 6dbb9879dedc1..fb3e98d510149 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -532,7 +532,7 @@ var/list/result = examinify.examine_more(src) if(!length(result)) result += span_notice("<i>Вы осматриваете [examinify.declent_ru(ACCUSATIVE)] подробнее, но не находите ничего интересного...</i>") - result_combined = examine_block(jointext(result, "<br>")) + result_combined = boxed_message(jointext(result, "<br>")) else client.recent_examines[ref_to_atom] = world.time // set to when we last normal examine'd them @@ -543,7 +543,7 @@ var/list/result = examinify.examine(src) var/atom_title = examinify.examine_title(src, thats = TRUE) SEND_SIGNAL(src, COMSIG_MOB_EXAMINING, examinify, result) - result_combined = (atom_title ? fieldset_block("[span_slightly_larger(atom_title)].", jointext(result, "<br>"), "examine_block") : examine_block(jointext(result, "<br>"))) + result_combined = (atom_title ? fieldset_block("[atom_title]", jointext(result, "<br>"), "boxed_message") : boxed_message(jointext(result, "<br>"))) to_chat(src, span_infoplain(result_combined)) SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, examinify) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 0562fbc6ae926..5b822ab851904 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -324,8 +324,8 @@ to_chat(ghost, span_ghostalert(message)) continue - var/interact_link = click_interact ? " <a href='?src=[REF(ghost)];play=[REF(source)]'>(Play)</a>" : "" - var/view_link = " <a href='?src=[REF(ghost)];view=[REF(source)]'>(View)</a>" + var/interact_link = click_interact ? " <a href='byond://?src=[REF(ghost)];play=[REF(source)]'>(Play)</a>" : "" + var/view_link = " <a href='byond://?src=[REF(ghost)];view=[REF(source)]'>(View)</a>" to_chat(ghost, span_ghostalert("[message][custom_link][interact_link][view_link]")) diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm index 5053b6c6b2cbe..343a09a980d30 100644 --- a/code/modules/modular_computers/computers/item/laptop.dm +++ b/code/modules/modular_computers/computers/item/laptop.dm @@ -29,6 +29,16 @@ if(screen_on) . += span_notice("Alt-click to close it.") +/obj/item/modular_computer/laptop/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + . = ..() + if(screen_on) + context[SCREENTIP_CONTEXT_ALT_LMB] = "Close" + context[SCREENTIP_CONTEXT_RMB] = "Interact" + else + context[SCREENTIP_CONTEXT_RMB] = "Open" + + return CONTEXTUAL_SCREENTIP_SET + /obj/item/modular_computer/laptop/Initialize(mapload) . = ..() @@ -70,13 +80,6 @@ return user.put_in_hand(src, H.held_index) -/obj/item/modular_computer/laptop/attack_hand(mob/user, list/modifiers) - . = ..() - if(.) - return - if(screen_on && isturf(loc)) - return attack_self(user) - /obj/item/modular_computer/laptop/proc/try_toggle_open(mob/living/user) if(issilicon(user)) return @@ -94,6 +97,14 @@ try_toggle_open(user) // Close it. return CLICK_ACTION_SUCCESS +/obj/item/modular_computer/laptop/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + + attack_self(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + /obj/item/modular_computer/laptop/proc/toggle_open(mob/living/user=null) if(screen_on) to_chat(user, span_notice("You close \the [src].")) diff --git a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm index 80bac2c80139f..66ac9eec68fd4 100644 --- a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm +++ b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm @@ -709,7 +709,7 @@ reply = "(<a href='byond://?src=[REF(src)];choice=[reply_href];skiprefresh=1;target=[REF(chat)]'>Reply</a>)" if (isAI(messaged_mob)) - sender_title = "<a href='?src=[REF(messaged_mob)];track=[html_encode(sender_name)]'>[sender_title]</a>" + sender_title = "<a href='byond://?src=[REF(messaged_mob)];track=[html_encode(sender_name)]'>[sender_title]</a>" var/inbound_message = "[signal.format_message()]" diff --git a/code/modules/paperwork/fax.dm b/code/modules/paperwork/fax.dm index f2935853a6db5..62a269d477e46 100644 --- a/code/modules/paperwork/fax.dm +++ b/code/modules/paperwork/fax.dm @@ -1,4 +1,5 @@ GLOBAL_VAR_INIT(nt_fax_department, pick("NT HR Department", "NT Legal Department", "NT Complaint Department", "NT Customer Relations", "Nanotrasen Tech Support", "NT Internal Affairs Dept")) +GLOBAL_VAR_INIT(fax_autoprinting, FALSE) /obj/machinery/fax name = "Fax Machine" @@ -325,7 +326,7 @@ GLOBAL_VAR_INIT(nt_fax_department, pick("NT HR Department", "NT Legal Department history_add("Send", params["name"]) - GLOB.requests.fax_request(usr.client, "sent a fax message from [fax_name]/[fax_id] to [params["name"]]", fax_paper) + GLOB.requests.fax_request(usr.client, "sent a fax message from [fax_name]/[fax_id] to [params["name"]]", list("paper" = fax_paper, "destination_id" = params["id"], "sender_name" = fax_name)) to_chat(GLOB.admins, span_adminnotice("[icon2html(src.icon, GLOB.admins)]<b><font color=green>FAX REQUEST: </font>[ADMIN_FULLMONTY(usr)]:</b> [span_linkify("sent a fax message from [fax_name]/[fax_id][ADMIN_FLW(src)] to [html_encode(params["name"])]")] [ADMIN_SHOW_PAPER(fax_paper)] [ADMIN_PRINT_FAX(fax_paper, fax_name, params["id"])]"), type = MESSAGE_TYPE_PRAYER, @@ -333,6 +334,14 @@ GLOBAL_VAR_INIT(nt_fax_department, pick("NT HR Department", "NT Legal Department for(var/client/staff as anything in GLOB.admins) if(staff?.prefs.read_preference(/datum/preference/toggle/comms_notification)) SEND_SOUND(staff, sound('sound/misc/server-ready.ogg')) + + if(GLOB.fax_autoprinting) + for(var/obj/machinery/fax/admin/FAX as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/fax/admin)) + if(FAX.fax_id != params["id"]) + continue + FAX.receive(fax_paper, fax_name) + break + log_fax(fax_paper, params["id"], params["name"]) loaded_item_ref = null update_appearance() diff --git a/code/modules/plumbing/plumbers/_plumb_machinery.dm b/code/modules/plumbing/plumbers/_plumb_machinery.dm index d3dec8e6c2087..81d5a28d0ecb3 100644 --- a/code/modules/plumbing/plumbers/_plumb_machinery.dm +++ b/code/modules/plumbing/plumbers/_plumb_machinery.dm @@ -102,117 +102,3 @@ user.balloon_alert_to_viewers("finished plunging") reagents.expose(get_turf(src), TOUCH) //splash on the floor reagents.clear_reagents() - -/** - * Specialized reagent container for plumbing. Uses the round robin approach of transferring reagents - * so transfer 5 from 15 water, 15 sugar and 15 plasma becomes 10, 15, 15 instead of 13.3333, 13.3333 13.3333. Good if you hate floating point errors - */ -/datum/reagents/plumbing - -/** - * Same as the parent trans_to except only a few arguments have impact here & the rest of the arguments are discarded. - * Arguments - * - * * atom/target - the target we are transfering to - * * amount - amount to transfer - * * datum/reagent/target_id - the reagent id we want to transfer. if null everything gets transfered - * * methods - this is key for deciding between round-robin or proportional transfer. It does not mean the same as the - * parent proc. LINEAR for round robin(in this technique reagents are missing/lost/not preserved when there isn't enough space to hold them) - * NONE means everything is transfered regardless of how much space is available in the receiver in proportions - */ -/datum/reagents/plumbing/trans_to( - atom/target, - amount = 1, - multiplier = 1, //unused for plumbing - datum/reagent/target_id, - preserve_data = TRUE, //unused for plumbing - no_react = FALSE, //unused for plumbing we always want reactions - mob/transferred_by, //unused for plumbing logging is not important inside plumbing machines - remove_blacklisted = FALSE, //unused for plumbing, we don't care what reagents are inside us - methods = LINEAR, //default round robin technique for transferring reagents - show_message = TRUE, //unused for plumbing, used for logging only - ignore_stomach = FALSE //unused for plumbing, reagents flow only between machines & is not injected to mobs at any point in time -) - if(QDELETED(target) || !total_volume) - return FALSE - - if(!IS_FINITE(amount)) - stack_trace("non finite amount passed to trans_to [amount] amount of reagents") - return FALSE - - if(!isnull(target_id) && !ispath(target_id)) - stack_trace("invalid target reagent id [target_id] passed to trans_to") - return FALSE - - var/datum/reagents/target_holder - if(istype(target, /datum/reagents)) - target_holder = target - else - target_holder = target.reagents - - // Prevents small amount problems, as well as zero and below zero amounts. - amount = round(min(amount, total_volume, target_holder.maximum_volume - target_holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) - if(amount <= 0) - return FALSE - - //Set up new reagents to inherit the old ongoing reactions - transfer_reactions(target_holder) - - var/list/cached_reagents = reagent_list - var/list/reagents_to_remove = list() - var/transfer_amount - var/transfered_amount - var/total_transfered_amount = 0 - - var/round_robin = methods & LINEAR - var/part - var/to_transfer - if(round_robin) - to_transfer = amount - else - part = amount / total_volume - - //first add reagents to target - for(var/datum/reagent/reagent as anything in cached_reagents) - if(round_robin && !to_transfer) - break - - if(!isnull(target_id)) - if(reagent.type == target_id) - force_stop_reagent_reacting(reagent) - transfer_amount = min(amount, reagent.volume) - else - continue - else - if(round_robin) - transfer_amount = min(to_transfer, reagent.volume) - else - transfer_amount = reagent.volume * part - - if(reagent.intercept_reagents_transfer(target_holder, amount)) - update_total() - target_holder.update_total() - continue - - transfered_amount = target_holder.add_reagent(reagent.type, transfer_amount, copy_data(reagent), chem_temp, reagent.purity, reagent.ph, no_react = TRUE, ignore_splitting = reagent.chemical_flags & REAGENT_DONOTSPLIT) //we only handle reaction after every reagent has been transferred. - if(!transfered_amount) - continue - reagents_to_remove += list(list("R" = reagent, "T" = transfer_amount)) - total_transfered_amount += transfered_amount - if(round_robin) - to_transfer -= transfered_amount - - if(!isnull(target_id)) - break - - //remove chemicals that were added above - for(var/list/data as anything in reagents_to_remove) - var/datum/reagent/reagent = data["R"] - transfer_amount = data["T"] - remove_reagent(reagent.type, transfer_amount) - - //handle reactions - target_holder.handle_reactions() - src.handle_reactions() - - return round(total_transfered_amount, CHEMICAL_VOLUME_ROUNDING) diff --git a/code/modules/plumbing/plumbers/_plumb_reagents.dm b/code/modules/plumbing/plumbers/_plumb_reagents.dm new file mode 100644 index 0000000000000..4cce127c8b822 --- /dev/null +++ b/code/modules/plumbing/plumbers/_plumb_reagents.dm @@ -0,0 +1,261 @@ + +/** + * Specialized reagent container for plumbing. Uses the round robin approach of transferring reagents + * so transfer 5 from 15 water, 15 sugar and 15 plasma becomes 10, 15, 15 instead of 13.3333, 13.3333 13.3333. Good if you hate floating point errors + */ +/datum/reagents/plumbing + +/** + * Same as the parent trans_to except only a few arguments have impact here & the rest of the arguments are discarded. + * Arguments + * + * * atom/target - the target we are transfering to + * * amount - amount to transfer + * * datum/reagent/target_id - the reagent id we want to transfer. if null everything gets transfered + * * methods - this is key for deciding between round-robin or proportional transfer. It does not mean the same as the + * parent proc. LINEAR for round robin(in this technique reagents are missing/lost/not preserved when there isn't enough space to hold them) + * NONE means everything is transfered regardless of how much space is available in the receiver in proportions + */ +/datum/reagents/plumbing/trans_to( + atom/target, + amount = 1, + multiplier = 1, //unused for plumbing + datum/reagent/target_id, + preserve_data = TRUE, //unused for plumbing + no_react = FALSE, //unused for plumbing we always want reactions + mob/transferred_by, //unused for plumbing logging is not important inside plumbing machines + remove_blacklisted = FALSE, //unused for plumbing, we don't care what reagents are inside us + methods = LINEAR, //default round robin technique for transferring reagents + show_message = TRUE, //unused for plumbing, used for logging only + ignore_stomach = FALSE //unused for plumbing, reagents flow only between machines & is not injected to mobs at any point in time +) + if(QDELETED(target) || !total_volume) + return FALSE + + if(!IS_FINITE(amount)) + stack_trace("non finite amount passed to trans_to [amount] amount of reagents") + return FALSE + + if(!isnull(target_id) && !ispath(target_id)) + stack_trace("invalid target reagent id [target_id] passed to trans_to") + return FALSE + + var/datum/reagents/target_holder + if(istype(target, /datum/reagents)) + target_holder = target + else + target_holder = target.reagents + + // Prevents small amount problems, as well as zero and below zero amounts. + amount = round(min(amount, total_volume, target_holder.maximum_volume - target_holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) + if(amount <= 0) + return FALSE + + //Set up new reagents to inherit the old ongoing reactions + transfer_reactions(target_holder) + + var/list/cached_reagents = reagent_list + var/list/reagents_to_remove = list() + var/transfer_amount + var/transfered_amount + var/total_transfered_amount = 0 + + var/round_robin = methods & LINEAR + var/part + var/to_transfer + if(round_robin) + to_transfer = amount + else + part = amount / total_volume + + //first add reagents to target + for(var/datum/reagent/reagent as anything in cached_reagents) + if(round_robin && !to_transfer) + break + + if(!isnull(target_id)) + if(reagent.type == target_id) + force_stop_reagent_reacting(reagent) + transfer_amount = min(amount, reagent.volume) + else + continue + else + if(round_robin) + transfer_amount = min(to_transfer, reagent.volume) + else + transfer_amount = reagent.volume * part + + if(reagent.intercept_reagents_transfer(target_holder, amount)) + update_total() + target_holder.update_total() + continue + + transfered_amount = target_holder.add_reagent(reagent.type, transfer_amount, copy_data(reagent), chem_temp, reagent.purity, reagent.ph, no_react = TRUE, ignore_splitting = reagent.chemical_flags & REAGENT_DONOTSPLIT) //we only handle reaction after every reagent has been transferred. + if(!transfered_amount) + continue + reagents_to_remove += list(list("R" = reagent, "T" = transfer_amount)) + total_transfered_amount += transfered_amount + if(round_robin) + to_transfer -= transfered_amount + + if(!isnull(target_id)) + break + + //remove chemicals that were added above + for(var/list/data as anything in reagents_to_remove) + var/datum/reagent/reagent = data["R"] + transfer_amount = data["T"] + remove_reagent(reagent.type, transfer_amount) + + //handle reactions + target_holder.handle_reactions() + src.handle_reactions() + + return round(total_transfered_amount, CHEMICAL_VOLUME_ROUNDING) + +///Excludes catalysts during the emptying process +/datum/reagents/plumbing/reaction_chamber + +///Returns the total volume of reagents without the catalysts +/datum/reagents/plumbing/reaction_chamber/proc/get_catalyst_excluded_volume() + SHOULD_NOT_OVERRIDE(TRUE) + + . = 0 + if(!total_volume) + return + + var/obj/machinery/plumbing/reaction_chamber/reactor = my_atom + var/list/datum/reagent/catalysts = reactor.catalysts + + var/working_volume + var/catalyst_volume + var/list/cached_reagents = reagent_list + for(var/datum/reagent/reagent as anything in cached_reagents) + catalyst_volume = catalysts[reagent.type] + working_volume = reagent.volume + + //regular reagent add to total as normal + if(!catalyst_volume) + . += working_volume + continue + + //only add the excess to total as that's what will get transferred + if(working_volume > catalyst_volume) + . += working_volume - catalyst_volume + . = min(round(., CHEMICAL_VOLUME_ROUNDING), maximum_volume) + +/datum/reagents/plumbing/reaction_chamber/trans_to( + atom/target, + amount = 1, + multiplier = 1, + datum/reagent/target_id, + preserve_data = TRUE, + no_react = FALSE, + mob/transferred_by, + remove_blacklisted = FALSE, + methods = LINEAR, + show_message = TRUE, + ignore_stomach = FALSE +) + var/obj/machinery/plumbing/reaction_chamber/reactor = my_atom + var/list/datum/reagent/catalysts = reactor.catalysts + + //usual stuff + if(!catalysts.len) + return ..() + + if(QDELETED(target)) + return FALSE + + if(!IS_FINITE(amount)) + stack_trace("non finite amount passed to trans_to [amount] amount of reagents") + return FALSE + + if(!isnull(target_id) && !ispath(target_id)) + stack_trace("invalid target reagent id [target_id] passed to trans_to") + return FALSE + + var/datum/reagents/target_holder + if(istype(target, /datum/reagents)) + target_holder = target + else + target_holder = target.reagents + var/list/cached_reagents = reagent_list + + var/actual_volume = get_catalyst_excluded_volume() + + // Prevents small amount problems, as well as zero and below zero amounts. + amount = round(min(amount, actual_volume, target_holder.maximum_volume - target_holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) + if(amount <= 0) + return FALSE + + //Set up new reagents to inherit the old ongoing reactions + transfer_reactions(target_holder) + + var/list/reagents_to_remove = list() + var/working_volume + var/catalyst_volume + var/transfer_amount + var/transfered_amount + var/total_transfered_amount = 0 + + var/round_robin = methods & LINEAR + var/part + var/to_transfer + if(round_robin) + to_transfer = amount + else + part = amount / actual_volume + + //first add reagents to target + for(var/datum/reagent/reagent as anything in cached_reagents) + if(round_robin && !to_transfer) + break + working_volume = reagent.volume + + catalyst_volume = catalysts[reagent.type] + if(catalyst_volume) //we have a working catalyst + if(reagent.volume <= catalyst_volume) //dont transfer since we have the required volume + continue + else + working_volume -= catalyst_volume //dump out the excess + + if(!isnull(target_id)) + if(reagent.type == target_id) + force_stop_reagent_reacting(reagent) + transfer_amount = min(amount, working_volume) + else + continue + else + if(round_robin) + transfer_amount = min(to_transfer, working_volume) + else + transfer_amount = working_volume * part + + if(reagent.intercept_reagents_transfer(target_holder, amount)) + update_total() + target_holder.update_total() + continue + + transfered_amount = target_holder.add_reagent(reagent.type, transfer_amount, copy_data(reagent), chem_temp, reagent.purity, reagent.ph, no_react = TRUE, ignore_splitting = reagent.chemical_flags & REAGENT_DONOTSPLIT) //we only handle reaction after every reagent has been transferred. + if(!transfered_amount) + continue + reagents_to_remove += list(list("R" = reagent, "T" = transfer_amount)) + total_transfered_amount += transfered_amount + if(round_robin) + to_transfer -= transfered_amount + + if(!isnull(target_id)) + break + + //remove chemicals that were added above + for(var/list/data as anything in reagents_to_remove) + var/datum/reagent/reagent = data["R"] + transfer_amount = data["T"] + remove_reagent(reagent.type, transfer_amount) + + //handle reactions + target_holder.handle_reactions() + src.handle_reactions() + + return round(total_transfered_amount, CHEMICAL_VOLUME_ROUNDING) diff --git a/code/modules/plumbing/plumbers/reaction_chamber.dm b/code/modules/plumbing/plumbers/reaction_chamber.dm index 9828c9e697f85..551b95fc0b7d7 100644 --- a/code/modules/plumbing/plumbers/reaction_chamber.dm +++ b/code/modules/plumbing/plumbers/reaction_chamber.dm @@ -9,19 +9,23 @@ icon_state = "reaction_chamber" buffer = 200 reagent_flags = TRANSPARENT | NO_REACT + reagents = /datum/reagents/plumbing/reaction_chamber /** * list of set reagents that the reaction_chamber allows in, and must all be present before mixing is enabled. * example: list(/datum/reagent/water = 20, /datum/reagent/fuel/oil = 50) */ - var/list/required_reagents = list() - + var/list/datum/reagent/required_reagents = list() + ///list of catalyst reagents to take + var/list/datum/reagent/catalysts = list() ///our reagent goal has been reached, so now we lock our inputs and start emptying var/emptying = FALSE - ///towards which temperature do we build (except during draining)? var/target_temperature = 300 +/obj/machinery/plumbing/reaction_chamber/Destroy() + return ..() + /obj/machinery/plumbing/reaction_chamber/Initialize(mapload, bolt, layer) . = ..() AddComponent(/datum/component/plumbing/reaction_chamber, bolt, layer) @@ -36,15 +40,17 @@ SIGNAL_HANDLER UnregisterSignal(reagents, list(COMSIG_REAGENTS_REM_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_CLEAR_REAGENTS, COMSIG_REAGENTS_REACTED, COMSIG_QDELETING)) + return NONE /// Handles stopping the emptying process when the chamber empties. -/obj/machinery/plumbing/reaction_chamber/proc/on_reagent_change(datum/reagents/holder, ...) +/obj/machinery/plumbing/reaction_chamber/proc/on_reagent_change(datum/reagents/plumbing/reaction_chamber/holder, ...) SIGNAL_HANDLER - if(!holder.total_volume && emptying) //we were emptying, but now we aren't + if(!holder.get_catalyst_excluded_volume() && emptying) //we were emptying, but now we aren't emptying = FALSE holder.flags |= NO_REACT + return NONE /obj/machinery/plumbing/reaction_chamber/process(seconds_per_tick) @@ -60,8 +66,15 @@ //do other stuff with final solution handle_reagents(seconds_per_tick) -///For subtypes that want to do additional reagent handling +/** + * For subtypes that want to do additional reagent handling + * Arguments + * + * * seconds_per_tick - passed down from process() + */ /obj/machinery/plumbing/reaction_chamber/proc/handle_reagents(seconds_per_tick) + PROTECTED_PROC(TRUE) + return /obj/machinery/plumbing/reaction_chamber/power_change() @@ -81,11 +94,21 @@ var/list/reagents_data = list() for(var/datum/reagent/required_reagent as anything in required_reagents) //make a list where the key is text, because that looks alot better in the ui than a typepath var/list/reagent_data = list() + if(catalysts[required_reagent]) + continue reagent_data["name"] = initial(required_reagent.name) reagent_data["volume"] = required_reagents[required_reagent] reagents_data += list(reagent_data) + var/list/catalyst_data = list() + for(var/datum/reagent/required_catalyst as anything in catalysts) + var/list/reagent_data = list() + reagent_data["name"] = initial(required_catalyst.name) + reagent_data["volume"] = catalysts[required_catalyst] + catalyst_data += list(reagent_data) + .["reagents"] = reagents_data + .["catalysts"] = catalyst_data .["emptying"] = emptying .["temperature"] = round(reagents.chem_temp, 0.1) .["targetTemp"] = target_temperature @@ -108,9 +131,9 @@ if(!input_reagent) return FALSE - if(!required_reagents.Find(input_reagent)) + if(!required_reagents[input_reagent]) var/input_amount = text2num(params["amount"]) - if(!isnull(input_amount)) + if(input_amount) required_reagents[input_reagent] = input_amount return TRUE return FALSE @@ -129,6 +152,25 @@ return TRUE return FALSE + if("catalyst") + var/reagent = get_chem_id(params["chem"]) + + if(!reagent) + return FALSE + + if(reagent && !catalysts[reagent]) + catalysts[reagent] = required_reagents[reagent] + return TRUE + else + return FALSE + + if("catremove") + var/reagent = get_chem_id(params["chem"]) + if(reagent) + catalysts -= reagent + return TRUE + return FALSE + var/result = handle_ui_act(action, params, ui, state) if(isnull(result)) result = FALSE @@ -136,6 +178,8 @@ /// For custom handling of ui actions from inside a subtype /obj/machinery/plumbing/reaction_chamber/proc/handle_ui_act(action, params, datum/tgui/ui, datum/ui_state/state) + PROTECTED_PROC(TRUE) + return null ///Chemistry version of reaction chamber that allows for acid and base buffers to be used while reacting diff --git a/code/modules/power/floodlight.dm b/code/modules/power/floodlight.dm index 3b09e9a808234..1a8da26999b0d 100644 --- a/code/modules/power/floodlight.dm +++ b/code/modules/power/floodlight.dm @@ -173,6 +173,8 @@ var/light_color = NONSENSICAL_VALUE if(!isnull(color)) light_color = color + if (cached_color_filter) + light_color = apply_matrix_to_color(COLOR_WHITE, cached_color_filter["color"], cached_color_filter["space"] || COLORSPACE_RGB) set_light(light_setting_list[setting], light_power, light_color) /obj/machinery/power/floodlight/add_context( diff --git a/code/modules/projectiles/ammunition/ballistic/revolver.dm b/code/modules/projectiles/ammunition/ballistic/revolver.dm index 6e0c26af7359c..ffcb3df89814e 100644 --- a/code/modules/projectiles/ammunition/ballistic/revolver.dm +++ b/code/modules/projectiles/ammunition/ballistic/revolver.dm @@ -22,6 +22,11 @@ name = ".357 heartseeker bullet casing" projectile_type = /obj/projectile/bullet/c357/heartseeker +/obj/item/ammo_casing/c357/heartseeker/ready_proj(atom/target, mob/living/user, quiet, zone_override, atom/fired_from) + . = ..() + if(!isturf(target)) + loaded_projectile.set_homing_target(target) + // 7.62x38mmR (Nagant Revolver) /obj/item/ammo_casing/n762 diff --git a/code/modules/projectiles/boxes_magazines/external/pistol.dm b/code/modules/projectiles/boxes_magazines/external/pistol.dm index 8b0bc1da7e5b8..05d4c4bf4c99e 100644 --- a/code/modules/projectiles/boxes_magazines/external/pistol.dm +++ b/code/modules/projectiles/boxes_magazines/external/pistol.dm @@ -1,44 +1,4 @@ -/obj/item/ammo_box/magazine/m10mm - name = "pistol magazine (10mm)" - desc = "A gun magazine." - icon_state = "9x19p" - base_icon_state = "9x19p" - ammo_type = /obj/item/ammo_casing/c10mm - caliber = CALIBER_10MM - max_ammo = 8 - multiple_sprites = AMMO_BOX_FULL_EMPTY - multiple_sprite_use_base = TRUE - -/obj/item/ammo_box/magazine/m10mm/fire - name = "pistol magazine (10mm incendiary)" - icon_state = "9x19pI" - base_icon_state = "9x19pI" - desc = "A 10mm pistol magazine. Loaded with rounds which ignite the target." - ammo_type = /obj/item/ammo_casing/c10mm/fire - -/obj/item/ammo_box/magazine/m10mm/hp - name = "pistol magazine (10mm HP)" - icon_state = "9x19pH" - base_icon_state = "9x19pH" - desc= "A 10mm pistol magazine. Loaded with hollow-point rounds, extremely effective against unarmored targets, but nearly useless against protective clothing." - ammo_type = /obj/item/ammo_casing/c10mm/hp - -/obj/item/ammo_box/magazine/m10mm/ap - name = "pistol magazine (10mm AP)" - icon_state = "9x19pA" - base_icon_state = "9x19pA" - desc= "A 10mm pistol magazine. Loaded with rounds which penetrate armour, but are less effective against normal targets." - ammo_type = /obj/item/ammo_casing/c10mm/ap - -/obj/item/ammo_box/magazine/m45 - name = "handgun magazine (.45)" - icon_state = "45-8" - base_icon_state = "45" - ammo_type = /obj/item/ammo_casing/c45 - caliber = CALIBER_45 - max_ammo = 8 - multiple_sprites = AMMO_BOX_PER_BULLET - multiple_sprite_use_base = TRUE +// Makarov (9mm) // /obj/item/ammo_box/magazine/m9mm name = "pistol magazine (9mm)" @@ -46,7 +6,7 @@ base_icon_state = "9x19p" ammo_type = /obj/item/ammo_casing/c9mm caliber = CALIBER_9MM - max_ammo = 8 + max_ammo = 12 multiple_sprites = AMMO_BOX_FULL_EMPTY multiple_sprite_use_base = TRUE @@ -71,6 +31,8 @@ desc= "A gun magazine. Loaded with rounds which penetrate armour, but are less effective against normal targets." ammo_type = /obj/item/ammo_casing/c9mm/ap +// Stechkin APS (9mm) // + /obj/item/ammo_box/magazine/m9mm_aps name = "stechkin pistol magazine (9mm)" icon_state = "9mmaps-15" @@ -86,25 +48,50 @@ /obj/item/ammo_box/magazine/m9mm_aps/fire name = "stechkin pistol magazine (9mm incendiary)" ammo_type = /obj/item/ammo_casing/c9mm/fire - max_ammo = 15 /obj/item/ammo_box/magazine/m9mm_aps/hp name = "stechkin pistol magazine (9mm HP)" ammo_type = /obj/item/ammo_casing/c9mm/hp - max_ammo = 15 /obj/item/ammo_box/magazine/m9mm_aps/ap name = "stechkin pistol magazine (9mm AP)" ammo_type = /obj/item/ammo_casing/c9mm/ap - max_ammo = 15 -/obj/item/ammo_box/magazine/m50 - name = "handgun magazine (.50ae)" - icon_state = "50ae" - ammo_type = /obj/item/ammo_casing/a50ae - caliber = CALIBER_50AE - max_ammo = 7 - multiple_sprites = AMMO_BOX_PER_BULLET +// Ansem (10mm) // + +/obj/item/ammo_box/magazine/m10mm + name = "pistol magazine (10mm)" + desc = "A gun magazine." + icon_state = "9x19p" + base_icon_state = "9x19p" + ammo_type = /obj/item/ammo_casing/c10mm + caliber = CALIBER_10MM + max_ammo = 8 + multiple_sprites = AMMO_BOX_FULL_EMPTY + multiple_sprite_use_base = TRUE + +/obj/item/ammo_box/magazine/m10mm/fire + name = "pistol magazine (10mm incendiary)" + icon_state = "9x19pI" + base_icon_state = "9x19pI" + desc = "A 10mm pistol magazine. Loaded with rounds which ignite the target." + ammo_type = /obj/item/ammo_casing/c10mm/fire + +/obj/item/ammo_box/magazine/m10mm/hp + name = "pistol magazine (10mm HP)" + icon_state = "9x19pH" + base_icon_state = "9x19pH" + desc= "A 10mm pistol magazine. Loaded with hollow-point rounds, extremely effective against unarmored targets, but nearly useless against protective clothing." + ammo_type = /obj/item/ammo_casing/c10mm/hp + +/obj/item/ammo_box/magazine/m10mm/ap + name = "pistol magazine (10mm AP)" + icon_state = "9x19pA" + base_icon_state = "9x19pA" + desc= "A 10mm pistol magazine. Loaded with rounds which penetrate armour, but are less effective against normal targets." + ammo_type = /obj/item/ammo_casing/c10mm/ap + +// Regal Condor (10mm) // /obj/item/ammo_box/magazine/r10mm name = "regal condor magazine (10mm Reaper)" @@ -115,3 +102,25 @@ max_ammo = 8 multiple_sprites = AMMO_BOX_PER_BULLET multiple_sprite_use_base = TRUE + +// M1911 (.45) // + +/obj/item/ammo_box/magazine/m45 + name = "handgun magazine (.45)" + icon_state = "45-8" + base_icon_state = "45" + ammo_type = /obj/item/ammo_casing/c45 + caliber = CALIBER_45 + max_ammo = 8 + multiple_sprites = AMMO_BOX_PER_BULLET + multiple_sprite_use_base = TRUE + +// Desert Eagle (.50 AE) // + +/obj/item/ammo_box/magazine/m50 + name = "handgun magazine (.50ae)" + icon_state = "50ae" + ammo_type = /obj/item/ammo_casing/a50ae + caliber = CALIBER_50AE + max_ammo = 7 + multiple_sprites = AMMO_BOX_PER_BULLET diff --git a/code/modules/projectiles/boxes_magazines/external/toy.dm b/code/modules/projectiles/boxes_magazines/external/toy.dm index 4f666e119b84d..695388280ebc4 100644 --- a/code/modules/projectiles/boxes_magazines/external/toy.dm +++ b/code/modules/projectiles/boxes_magazines/external/toy.dm @@ -20,7 +20,7 @@ /obj/item/ammo_box/magazine/toy/pistol name = "foam force pistol magazine" icon_state = "9x19p" - max_ammo = 8 + max_ammo = 12 multiple_sprites = AMMO_BOX_FULL_EMPTY /obj/item/ammo_box/magazine/toy/pistol/riot diff --git a/code/modules/projectiles/guns/ballistic/toy.dm b/code/modules/projectiles/guns/ballistic/toy.dm index bd84e5f794188..dae77b0936833 100644 --- a/code/modules/projectiles/guns/ballistic/toy.dm +++ b/code/modules/projectiles/guns/ballistic/toy.dm @@ -17,6 +17,7 @@ /obj/item/gun/ballistic/automatic/toy/riot spawn_magazine_type = /obj/item/ammo_box/magazine/toy/smg/riot + /obj/item/gun/ballistic/automatic/pistol/toy name = "foam force pistol" desc = "A small, easily concealable toy handgun. Ages 8 and up." @@ -31,6 +32,9 @@ magazine = new /obj/item/ammo_box/magazine/toy/pistol/riot(src) return ..() +/obj/item/gun/ballistic/automatic/pistol/toy/riot/clandestine + projectile_damage_multiplier = 1.4 + /obj/item/gun/ballistic/shotgun/toy name = "foam force shotgun" desc = "A toy shotgun with wood furniture and a four-shell capacity underneath. Ages 8 and up." diff --git a/code/modules/projectiles/guns/energy/dueling.dm b/code/modules/projectiles/guns/energy/dueling.dm index 9a7fa9aa78bea..95707874e7293 100644 --- a/code/modules/projectiles/guns/energy/dueling.dm +++ b/code/modules/projectiles/guns/energy/dueling.dm @@ -298,15 +298,17 @@ /obj/item/ammo_casing/energy/duel/ready_proj(atom/target, mob/living/user, quiet, zone_override) . = ..() - var/obj/projectile/energy/duel/D = loaded_projectile - D.setting = setting - D.update_appearance() + var/obj/projectile/energy/duel/dueling_projectile = loaded_projectile + dueling_projectile.setting = setting + dueling_projectile.update_appearance() + if(!isturf(target)) + dueling_projectile.set_homing_target(target) /obj/item/ammo_casing/energy/duel/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread, atom/fired_from) . = ..() - var/obj/effect/temp_visual/dueling_chaff/C = new(get_turf(user)) - C.setting = setting - C.update_appearance() + var/obj/effect/temp_visual/dueling_chaff/chaff = new(get_turf(user)) + chaff.setting = setting + chaff.update_appearance() //Projectile @@ -314,7 +316,6 @@ name = "dueling beam" icon_state = "declone" reflectable = FALSE - homing = TRUE var/setting /obj/projectile/energy/duel/update_icon() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 065a4899fc728..f907682305ef5 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -169,8 +169,9 @@ var/impact_light_color_override // Homing - /// If the projectile is homing. Warning - this changes projectile's processing logic, reverting it to segmented processing instead of new raymarching logic - var/homing = FALSE + /// If the projectile is currently homing. Warning - this changes projectile's processing logic, reverting it to segmented processing instead of new raymarching logic + /// This does not actually set up the projectile to home in on a target - you need to set that up with set_homing_target() on the projectile! + VAR_FINAL/homing = FALSE /// Target the projectile is homing on var/atom/homing_target /// Angles per move segment, distance is based on SSprojectiles.pixels_per_decisecond diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm index 6513be9cfb7c8..273a0109c5699 100644 --- a/code/modules/projectiles/projectile/bullets/revolver.dm +++ b/code/modules/projectiles/projectile/bullets/revolver.dm @@ -149,7 +149,6 @@ name = ".357 heartseeker bullet" icon_state = "gauss" damage = 50 - homing = TRUE homing_turn_speed = 120 // admin only really, for ocelot memes diff --git a/code/modules/reagents/chemistry/items.dm b/code/modules/reagents/chemistry/items.dm index 1e712db9c23ef..f7501f36fc47c 100644 --- a/code/modules/reagents/chemistry/items.dm +++ b/code/modules/reagents/chemistry/items.dm @@ -132,7 +132,7 @@ out_message += "<b>[round(reagent.volume, 0.01)]u of [reagent.name]</b>, <b>Purity:</b> [round(reagent.purity, 0.000001)*100]%, [(scanmode?"[(reagent.overdose_threshold?"<b>Overdose:</b> [reagent.overdose_threshold]u, ":"")]<b>Base pH:</b> [initial(reagent.ph)], <b>Current pH:</b> [reagent.ph].":"<b>Current pH:</b> [reagent.ph].")]\n" if(scanmode) out_message += "<b>Analysis:</b> [reagent.description]\n" - to_chat(user, examine_block(span_notice("[out_message.Join()]"))) + to_chat(user, boxed_message(span_notice("[out_message.Join()]"))) desc = "An electrode attached to a small circuit box that will display details of a solution. Can be toggled to provide a description of each of the reagents. The screen currently displays detected vol: [round(cont.volume, 0.01)] detected pH:[round(cont.reagents.ph, 0.1)]." return ITEM_INTERACT_SUCCESS diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 1d1ad36bf3a52..61c200fd3bb98 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -415,7 +415,7 @@ if(amount == -1) // Set custom amount var/mob/user = ui.user //Hold a reference of the user if the UI is closed - amount = tgui_input_number(user, "Enter amount to transfer", "Transfer amount") + amount = FLOOR(tgui_input_number(user, "Enter amount to transfer", "Transfer amount", round_value = FALSE), CHEMICAL_VOLUME_ROUNDING) if(!amount || !user.can_perform_action(src)) return FALSE diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index bd5fc6f06cc7b..755e2b5e31a8f 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -387,7 +387,7 @@ if("mix") mix(5 SECONDS, user) if("examine") - to_chat(user, examine_block(jointext(examine(user), "\n"))) + to_chat(user, boxed_message(jointext(examine(user), "\n"))) /** * Checks if the radial menu can interact with this machine diff --git a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm index e359e301423e8..2093491015641 100644 --- a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm @@ -524,7 +524,25 @@ to_chat(carbies, span_danger("You feel your burns and bruises healing! It stings like hell!")) carbies.add_mood_event("painful_medicine", /datum/mood_event/painful_medicine) - if(HAS_TRAIT_FROM(exposed_mob, TRAIT_HUSK, BURN) && carbies.getFireLoss() < UNHUSK_DAMAGE_THRESHOLD && (carbies.reagents.get_reagent_amount(/datum/reagent/medicine/c2/synthflesh) + reac_volume >= SYNTHFLESH_UNHUSK_AMOUNT)) + + //don't unhusked non husked mobs + if (!HAS_TRAIT_FROM(exposed_mob, TRAIT_HUSK, BURN)) + return + + //don't try to unhusk mobs above burn damage threshold + if (carbies.getFireLoss() > UNHUSK_DAMAGE_THRESHOLD) + return + + var/datum/reagent/synthflesh = carbies.reagents.has_reagent(/datum/reagent/medicine/c2/synthflesh) + var/current_volume = synthflesh ? synthflesh.volume : 0 + var/current_purity = synthflesh ? synthflesh.purity : 0 + + if (methods & TOUCH) //touch does not apply chems to blood, we want to combine the two volumes before attempting to unhusk + current_purity = current_volume > 0 ? (current_volume * current_purity + reac_volume * creation_purity) / (current_volume + reac_volume) : creation_purity + current_volume += reac_volume + + //when purity = 100%, 60u to unhusk, when purity = 60%, 100u to unhusk. + if(current_volume >= SYNTHFLESH_UNHUSK_MAX || current_volume * current_purity >= SYNTHFLESH_UNHUSK_AMOUNT) carbies.cure_husk(BURN) carbies.visible_message(span_nicegreen("A rubbery liquid coats [carbies]'s burns. [carbies] looks a lot healthier!")) //we're avoiding using the phrases "burnt flesh" and "burnt skin" here because carbies could be a skeleton or a golem or something diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm index c401d39f020ed..0ad3b55fb59d3 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm @@ -19,11 +19,17 @@ /datum/reagent/nitroglycerin name = "Nitroglycerin" - description = "Nitroglycerin is a heavy, colorless, oily, explosive liquid obtained by nitrating glycerol." + description = "Nitroglycerin is a heavy, colorless, oily liquid obtained by nitrating glycerol. \ + It is commonly used to treat heart conditions, but also in the creation of explosives." color = COLOR_GRAY taste_description = "oil" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED +/datum/reagent/nitroglycerin/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() + if(affected_mob.adjustOrganLoss(ORGAN_SLOT_HEART, -1 * REM * seconds_per_tick * normalise_creation_purity(), required_organ_flag = affected_organ_flags)) + return UPDATE_MOB_HEALTH + /datum/reagent/stabilizing_agent name = "Stabilizing Agent" description = "Keeps unstable chemicals stable. This does not work on everything." diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index acde1703668e4..105ce859ffd7a 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -207,7 +207,7 @@ var/atom/A = holder.my_atom var/turf/T = get_turf(A) var/message = "Mobs have been spawned in [ADMIN_VERBOSEJMP(T)] by a [reaction_name] reaction." - message += " (<A HREF='?_src_=vars;Vars=[REF(A)]'>VV</A>)" + message += " (<A href='byond://?_src_=vars;Vars=[REF(A)]'>VV</A>)" var/mob/M = get(A, /mob) if(M) diff --git a/code/modules/requests/request_manager.dm b/code/modules/requests/request_manager.dm index 99a9bba1cc84f..3106a925acd2c 100644 --- a/code/modules/requests/request_manager.dm +++ b/code/modules/requests/request_manager.dm @@ -154,6 +154,10 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new) to_chat(usr, "You do not have permission to do this, you require +ADMIN", confidential = TRUE) return + if (action == "toggleprint") + GLOB.fax_autoprinting = !GLOB.fax_autoprinting + return TRUE + // Get the request this relates to var/id = params["id"] != null ? text2num(params["id"]) : null if (!id) @@ -228,9 +232,20 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new) if(request.req_type != REQUEST_FAX) to_chat(usr, "Request doesn't have a paper to read.", confidential = TRUE) return TRUE - var/obj/item/paper/request_message = request.additional_information + var/obj/item/paper/request_message = request.additional_information["paper"] request_message.ui_interact(usr) return TRUE + if ("print") + if (request.req_type != REQUEST_FAX) + to_chat(usr, "Request doesn't have a paper to print.", confidential = TRUE) + return TRUE + for(var/obj/machinery/fax/admin/FAX as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/fax/admin)) + if(FAX.fax_id != request.additional_information["destination_id"]) + continue + var/obj/item/paper/request_message = request.additional_information["paper"] + var/sender_name = request.additional_information["sender_name"] + FAX.receive(request_message, sender_name) + return TRUE if ("play") if(request.req_type != REQUEST_INTERNET_SOUND) to_chat(usr, "Request doesn't have a sound to play.", confidential = TRUE) @@ -257,6 +272,7 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new) "timestamp" = request.timestamp, "timestamp_str" = gameTimestamp(wtime = request.timestamp) )) + data["fax_autoprinting"] = GLOB.fax_autoprinting return data #undef REQUEST_PRAYER diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index 66cbd4b93de5b..d98f62596ea47 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -350,7 +350,7 @@ Due to keyboard shortcuts, the second one is not necessarily the remote eye's lo render_list += "• Alt-click a slime to feed it a potion." render_list += "• Ctrl-click or a dead monkey to recycle it, or the floor to place a new monkey." - to_chat(owner, examine_block(jointext(render_list, "\n"))) + to_chat(owner, boxed_message(jointext(render_list, "\n"))) // // Alternate clicks for slime, monkey and open turf if using a xenobio console diff --git a/code/modules/shuttle/shuttle_consoles/navigation_computer.dm b/code/modules/shuttle/shuttle_consoles/navigation_computer.dm index 7c588e06dc005..3e9bf0cbe3be0 100644 --- a/code/modules/shuttle/shuttle_consoles/navigation_computer.dm +++ b/code/modules/shuttle/shuttle_consoles/navigation_computer.dm @@ -34,7 +34,7 @@ . = ..() actions += new /datum/action/innate/shuttledocker_rotate(src) actions += new /datum/action/innate/shuttledocker_place(src) - + AddElement(/datum/element/nav_computer_icon, 'icons/effects/nav_computer_indicators.dmi', "computer", FALSE) set_init_ports() if(connect_to_shuttle(mapload, SSshuttle.get_containing_shuttle(src))) @@ -124,6 +124,7 @@ SET_PLANE(I, ABOVE_GAME_PLANE, shuttle_turf) I.mouse_opacity = MOUSE_OPACITY_TRANSPARENT the_eye.placement_images[I] = list(x_off, y_off) + gatherNavComputerIcons() return TRUE @@ -134,6 +135,7 @@ var/list/to_add = list() to_add += the_eye.placement_images to_add += the_eye.placed_images + to_add += the_eye.extra_images if(!see_hidden) to_add += SSshuttle.hidden_shuttle_turf_images @@ -147,12 +149,55 @@ var/list/to_remove = list() to_remove += the_eye.placement_images to_remove += the_eye.placed_images + to_remove += the_eye.extra_images if(!see_hidden) to_remove += SSshuttle.hidden_shuttle_turf_images user.client.images -= to_remove user.client.view_size.resetToDefault() +/obj/machinery/computer/camera_advanced/shuttle_docker/proc/shuttle_turf_from_coords(list/coords) + var/mob/eye/camera/remote/shuttle_docker/the_eye = eyeobj + var/shuttleDir = shuttle_port.dir + var/curDir = the_eye.dir + var/list/adjustedCoords = coords.Copy() + + // Rotate coords so they match the current shuttle docking port's dir + if(turn(curDir, -90) == shuttleDir) + adjustedCoords[1] = coords[2] + y_offset + adjustedCoords[2] = -(coords[1] + x_offset) + else if(turn(curDir, 90) == shuttleDir) + adjustedCoords[1] = -(coords[2] + y_offset) + adjustedCoords[2] = coords[1] + x_offset + else if(turn(curDir, 180) == shuttleDir) + adjustedCoords[1] = -(coords[1] + x_offset) + adjustedCoords[2] = -(coords[2] + y_offset) + else + adjustedCoords[1] = coords[1] + x_offset + adjustedCoords[2] = coords[2] + y_offset + + return locate(shuttle_port.x + adjustedCoords[1], shuttle_port.y + adjustedCoords[2], shuttle_port.z) + +/obj/machinery/computer/camera_advanced/shuttle_docker/proc/gatherNavComputerIcons() + var/mob/eye/camera/remote/shuttle_docker/the_eye = eyeobj + var/list/placement_image_cache = the_eye.placement_images + var/list/extra_image_cache = the_eye.extra_images + for(var/i in 1 to placement_image_cache.len) + var/image/placement_image = placement_image_cache[i] + var/list/coords = placement_image_cache[placement_image] + var/turf/shuttle_turf = shuttle_turf_from_coords(coords) + var/list/images_to_add = list() + for(var/atom/atom as anything in shuttle_turf) + SEND_SIGNAL(atom, COMSIG_SHUTTLE_NAV_COMPUTER_IMAGE_REQUESTED, images_to_add) + for(var/i2 in 1 to images_to_add.len) + var/image/extra_image = images_to_add[i2] + extra_image.dir = turn(extra_image.dir, dir2angle(the_eye.dir) - dir2angle(shuttle_port.dir)) + extra_image.loc = locate(the_eye.x + coords[1], the_eye.y + coords[2], the_eye.z) + extra_image.layer = ABOVE_NORMAL_TURF_LAYER + SET_PLANE(extra_image, ABOVE_GAME_PLANE, the_eye) + extra_image.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + extra_image_cache[extra_image] = coords.Copy() + /obj/machinery/computer/camera_advanced/shuttle_docker/proc/placeLandingSpot() if(designating_target_loc || !current_user) return @@ -226,7 +271,7 @@ /obj/machinery/computer/camera_advanced/shuttle_docker/proc/rotateLandingSpot() var/mob/eye/camera/remote/shuttle_docker/the_eye = eyeobj - var/list/image_cache = the_eye.placement_images + var/list/image_cache = the_eye.placement_images + the_eye.extra_images the_eye.setDir(turn(the_eye.dir, -90)) for(var/i in 1 to image_cache.len) var/image/pic = image_cache[i] @@ -235,6 +280,7 @@ coords[1] = coords[2] coords[2] = -Tmp pic.loc = locate(the_eye.x + coords[1], the_eye.y + coords[2], the_eye.z) + pic.dir = turn(pic.dir, -90) var/Tmp = x_offset x_offset = y_offset y_offset = -Tmp @@ -267,6 +313,12 @@ else I.icon_state = "red" . = SHUTTLE_DOCKER_BLOCKED + var/list/extra_image_cache = the_eye.extra_images + for(var/i in 1 to extra_image_cache.len) + var/image/image = extra_image_cache[i] + var/list/coords = extra_image_cache[image] + var/turf/turf = locate(eyeturf.x + coords[1], eyeturf.y + coords[2], eyeturf.z) + image.loc = turf /obj/machinery/computer/camera_advanced/shuttle_docker/proc/checkLandingTurf(turf/T, list/overlappers) // Too close to the map edge is never allowed @@ -322,6 +374,7 @@ use_visibility = FALSE var/list/image/placement_images = list() var/list/image/placed_images = list() + var/list/image/extra_images = list() /mob/eye/camera/remote/shuttle_docker/setLoc(turf/destination, force_update = FALSE) . = ..() diff --git a/code/modules/shuttle/shuttle_consoles/shuttle_console.dm b/code/modules/shuttle/shuttle_consoles/shuttle_console.dm index 5ce62f8c04226..e269e360ba4dc 100644 --- a/code/modules/shuttle/shuttle_consoles/shuttle_console.dm +++ b/code/modules/shuttle/shuttle_consoles/shuttle_console.dm @@ -33,6 +33,7 @@ /obj/machinery/computer/shuttle/Initialize(mapload) . = ..() + AddElement(/datum/element/nav_computer_icon, 'icons/effects/nav_computer_indicators.dmi', "computer", FALSE) connect_to_shuttle(mapload, SSshuttle.get_containing_shuttle(src)) /obj/machinery/computer/shuttle/ui_interact(mob/user, datum/tgui/ui) @@ -216,7 +217,7 @@ return COOLDOWN_START(src, request_cooldown, 1 MINUTES) to_chat(usr, span_notice("Your request has been received by CentCom.")) - to_chat(GLOB.admins, "<b>SHUTTLE: <font color='#3d5bc3'>[ADMIN_LOOKUPFLW(usr)] (<A HREF='?_src_=holder;[HrefToken()];move_shuttle=[shuttleId]'>Move Shuttle</a>)(<A HREF='?_src_=holder;[HrefToken()];unlock_shuttle=[REF(src)]'>Lock/Unlock Shuttle</a>)</b> is requesting to move or unlock the shuttle.</font>") + to_chat(GLOB.admins, "<b>SHUTTLE: <font color='#3d5bc3'>[ADMIN_LOOKUPFLW(usr)] (<A href='byond://?_src_=holder;[HrefToken()];move_shuttle=[shuttleId]'>Move Shuttle</a>)(<A href='byond://?_src_=holder;[HrefToken()];unlock_shuttle=[REF(src)]'>Lock/Unlock Shuttle</a>)</b> is requesting to move or unlock the shuttle.</font>") return TRUE /obj/machinery/computer/shuttle/emag_act(mob/user, obj/item/card/emag/emag_card) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 9dc3c2857e7d3..35a2dd7783767 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -363,7 +363,7 @@ for(var/obj/item/embedded_thing in embedded_objects) var/stuck_word = embedded_thing.is_embed_harmless() ? "прилип" : "застрял" - check_list += "\t <a href='?src=[REF(examiner)];embedded_object=[REF(embedded_thing)];embedded_limb=[REF(src)]' class='warning'>[capitalize(embedded_thing.declent_ru(NOMINATIVE))] [stuck_word] [stuck_word == "застрял" ? "в" : "к"] вашей [declent_ru(DATIVE)]!</a>" + check_list += "\t <a href='byond://?src=[REF(examiner)];embedded_object=[REF(embedded_thing)];embedded_limb=[REF(src)]' class='warning'>[capitalize(embedded_thing.declent_ru(NOMINATIVE))] [stuck_word] [stuck_word == "застрял" ? "в" : "к"] вашей [declent_ru(DATIVE)]!</a>" /obj/item/bodypart/blob_act() receive_damage(max_damage, wound_bonus = CANT_WOUND) diff --git a/code/modules/tgui_panel/external.dm b/code/modules/tgui_panel/external.dm index 3e7dbc3178f2a..e48ddeb223904 100644 --- a/code/modules/tgui_panel/external.dm +++ b/code/modules/tgui_panel/external.dm @@ -19,22 +19,19 @@ // Failed to fix, using tgalert as fallback action = tgalert(src, "Did that work?", "", "Yes", "No, switch to old ui") if (action == "No, switch to old ui") - winset(src, "output", "on-show=&is-disabled=0&is-visible=1") - winset(src, "browseroutput", "is-disabled=1;is-visible=0") + winset(src, "legacy_output_selector", "left=output_legacy") log_tgui(src, "Failed to fix.", context = "verb/fix_tgui_panel") /client/proc/nuke_chat() // Catch all solution (kick the whole thing in the pants) - winset(src, "output", "on-show=&is-disabled=0&is-visible=1") - winset(src, "browseroutput", "is-disabled=1;is-visible=0") + winset(src, "legacy_output_selector", "left=output_legacy") if(!tgui_panel || !istype(tgui_panel)) log_tgui(src, "tgui_panel datum is missing", context = "verb/fix_tgui_panel") tgui_panel = new(src) tgui_panel.initialize(force = TRUE) // Force show the panel to see if there are any errors - winset(src, "output", "is-disabled=1&is-visible=0") - winset(src, "browseroutput", "is-disabled=0;is-visible=1") + winset(src, "legacy_output_selector", "left=output_browser") /client/verb/refresh_tgui() set name = "Refresh TGUI" diff --git a/code/modules/tgui_panel/tgui_panel.dm b/code/modules/tgui_panel/tgui_panel.dm index a680056b0e5e7..a54f56ead0c08 100644 --- a/code/modules/tgui_panel/tgui_panel.dm +++ b/code/modules/tgui_panel/tgui_panel.dm @@ -61,7 +61,7 @@ */ /datum/tgui_panel/proc/on_initialize_timed_out() // Currently does nothing but sending a message to old chat. - SEND_TEXT(client, span_userdanger("Failed to load fancy chat, click <a href='?src=[REF(src)];reload_tguipanel=1'>HERE</a> to attempt to reload it.")) + SEND_TEXT(client, span_userdanger("Failed to load fancy chat, click <a href='byond://?src=[REF(src)];reload_tguipanel=1'>HERE</a> to attempt to reload it.")) /** * private diff --git a/code/modules/uplink/uplink_items/ammunition.dm b/code/modules/uplink/uplink_items/ammunition.dm index 2276485a2b7b5..7000fb7e9a766 100644 --- a/code/modules/uplink/uplink_items/ammunition.dm +++ b/code/modules/uplink/uplink_items/ammunition.dm @@ -7,19 +7,19 @@ surplus = 40 /datum/uplink_item/ammo/toydarts - name = "Box of Riot Darts" - desc = "A box of 40 Donksoft riot darts, for reloading any compatible foam dart magazine. Don't forget to share!" - item = /obj/item/ammo_box/foambox/riot + name = "Donksoft Riot Pistol Ammunition Case" + desc = "A case containing three spare magazines for the Donksoft riot pistol, along with a box of loose riot darts." + item = /obj/item/storage/toolbox/guncase/traitor/ammunition/donksoft cost = 2 - surplus = 0 uplink_item_flags = SYNDIE_TRIPS_CONTRABAND purchasable_from = ~UPLINK_SERIOUS_OPS /datum/uplink_item/ammo/pistol - name = "9mm Handgun Magazine" - desc = "An additional 8-round 9mm magazine, compatible with the Makarov pistol." - item = /obj/item/ammo_box/magazine/m9mm - cost = 1 + name = "9mm Magazine Case" + desc = "A case containing three additional 8-round 9mm magazines, compatible with the Makarov pistol, as well as \ + a box of loose 9mm ammunition." + item = /obj/item/storage/toolbox/guncase/traitor/ammunition + cost = 2 purchasable_from = ~UPLINK_ALL_SYNDIE_OPS uplink_item_flags = SYNDIE_TRIPS_CONTRABAND diff --git a/code/modules/uplink/uplink_items/badass.dm b/code/modules/uplink/uplink_items/badass.dm index 5c5e0390b5046..9a346da2d5351 100644 --- a/code/modules/uplink/uplink_items/badass.dm +++ b/code/modules/uplink/uplink_items/badass.dm @@ -106,3 +106,9 @@ Contains enough special solution to spray a single super-size seditious symbol, subjecting station staff to slippery suffering." item = /obj/item/traitor_spraycan cost = 1 + +/datum/uplink_item/badass/pinpointer + name = "Surplus Pinpointer" + desc = "Provides a surplus pinpointer, left over from the previous models that were abandoned in favor of a SAAS cloud-based PDA app." + item = /obj/item/pinpointer/nuke/syndicate + cost = 2 diff --git a/code/modules/uplink/uplink_items/dangerous.dm b/code/modules/uplink/uplink_items/dangerous.dm index 0c86d8731e00b..092ec4c384782 100644 --- a/code/modules/uplink/uplink_items/dangerous.dm +++ b/code/modules/uplink/uplink_items/dangerous.dm @@ -7,19 +7,22 @@ category = /datum/uplink_category/dangerous /datum/uplink_item/dangerous/foampistol - name = "Toy Pistol with Riot Darts" - desc = "An innocent-looking toy pistol designed to fire foam darts. Comes loaded with riot-grade \ - darts effective at incapacitating a target." - item = /obj/item/gun/ballistic/automatic/pistol/toy/riot - cost = 2 + name = "Donksoft Riot Pistol Case" + desc = "A case containing an innocent-looking toy pistol designed to fire foam darts at higher than normal velocity. \ + Comes loaded with riot-grade darts effective at incapacitating a target, two spare magazines and a box of loose \ + riot darts. Perfect for nonlethal takedowns at range, as well as deniability. While not included in the kit, the \ + pistol is compatible with suppressors, which can be purchased separately." + item = /obj/item/storage/toolbox/guncase/traitor/donksoft + cost = 6 surplus = 10 purchasable_from = ~UPLINK_SERIOUS_OPS /datum/uplink_item/dangerous/pistol - name = "Makarov Pistol" - desc = "A small, easily concealable handgun that uses 9mm auto rounds in 8-round magazines and is compatible \ - with suppressors." - item = /obj/item/gun/ballistic/automatic/pistol + name = "Makarov Pistol Case" + desc = "A weapon case containing an unknown variant of the Makarov pistol, along with two spare magazines and a box of loose 9mm ammunition. \ + Chambered in 9mm. Perfect for frequent skirmishes with security, as well as ensuring you have enough firepower to outlast the competition. \ + While not included in the kit, the pistol is compatible with suppressors, which can be purchased seperately." + item = /obj/item/storage/toolbox/guncase/traitor cost = 7 purchasable_from = ~UPLINK_ALL_SYNDIE_OPS diff --git a/code/modules/vehicles/mecha/equipment/tools/air_tank.dm b/code/modules/vehicles/mecha/equipment/tools/air_tank.dm index f00444ae598b0..6d9765e6b0588 100644 --- a/code/modules/vehicles/mecha/equipment/tools/air_tank.dm +++ b/code/modules/vehicles/mecha/equipment/tools/air_tank.dm @@ -79,11 +79,10 @@ var/datum/gas_mixture/tank_air = internal_tank.return_air() var/datum/gas_mixture/cabin_air = chassis.cabin_air var/release_pressure = internal_tank.release_pressure - var/cabin_pressure = cabin_air.return_pressure() - if(cabin_pressure < release_pressure) + if(cabin_air.return_pressure() < release_pressure) tank_air.release_gas_to(cabin_air, release_pressure) - if(cabin_pressure) - cabin_air.pump_gas_to(external_air, PUMP_MAX_PRESSURE, GAS_CO2) + if(cabin_air.has_gas(/datum/gas/carbon_dioxide)) + cabin_air.pump_gas_to(external_air, PUMP_MAX_PRESSURE, /datum/gas/carbon_dioxide) /obj/item/mecha_parts/mecha_equipment/air_tank/proc/process_pump(seconds_per_tick) if(!tank_pump_active) diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm index c30e67a274633..651ccf999bb70 100644 --- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm @@ -217,31 +217,32 @@ attempt_refill(usr) return TRUE +///Maximum range the RCD can construct at. +#define RCD_RANGE 3 + /obj/item/mecha_parts/mecha_equipment/rcd name = "mounted RCD" desc = "An exosuit-mounted Rapid Construction Device." icon_state = "mecha_rcd" equip_cooldown = 0 // internal RCD already handles it energy_drain = 0 // internal RCD handles power consumption based on matter use - range = MECHA_MELEE|MECHA_RANGED + range = MECHA_MELEE | MECHA_RANGED item_flags = NO_MAT_REDEMPTION - ///Maximum range the RCD can construct at. - var/rcd_range = 3 + + ///The location the mech was when it began using the rcd + var/atom/initial_location = FALSE ///Whether or not to deconstruct instead. var/deconstruct_active = FALSE - ///The type of internal RCD this equipment uses. - var/rcd_type = /obj/item/construction/rcd/exosuit ///The internal RCD item used by this equipment. - var/obj/item/construction/rcd/internal_rcd + var/obj/item/construction/rcd/exosuit/internal_rcd /obj/item/mecha_parts/mecha_equipment/rcd/Initialize(mapload) . = ..() - internal_rcd = new rcd_type(src) - GLOB.rcd_list += src + internal_rcd = new(src) /obj/item/mecha_parts/mecha_equipment/rcd/Destroy() - GLOB.rcd_list -= src - qdel(internal_rcd) + initial_location = null + QDEL_NULL(internal_rcd) return ..() /obj/item/mecha_parts/mecha_equipment/rcd/get_snowflake_data() @@ -277,16 +278,31 @@ internal_rcd.ui_interact(driver) return TRUE + +/obj/item/mecha_parts/mecha_equipment/rcd/do_after_checks(atom/target) + // Checks if mech moved during operation + if(chassis.loc != initial_location) + return FALSE + + // Cancel build if design changes + if(!deconstruct_active && internal_rcd.blueprint_changed) + return FALSE + + return ..() + /obj/item/mecha_parts/mecha_equipment/rcd/action(mob/source, atom/target, list/modifiers) if(!action_checks(target)) return - if(get_dist(chassis, target) > rcd_range) + // No meson action! + if (!(target in view(RCD_RANGE, get_turf(chassis)))) + return + if(get_dist(chassis, target) > RCD_RANGE) balloon_alert(source, "out of range!") return - if(!internal_rcd) // if it somehow went missing - internal_rcd = new rcd_type(src) - stack_trace("Exosuit-mounted RCD had no internal RCD!") + initial_location = chassis.loc + ..() // do this now because the do_after can take a while + var/construction_mode = internal_rcd.mode if(deconstruct_active) // deconstruct isn't in the RCD menu so switch it to deconstruct mode and set it back when it's done internal_rcd.mode = RCD_DECONSTRUCT @@ -294,11 +310,13 @@ internal_rcd.mode = construction_mode return TRUE -/obj/item/mecha_parts/mecha_equipment/rcd/attackby(obj/item/attacking_item, mob/user, params) +/obj/item/mecha_parts/mecha_equipment/rcd/interact_with_atom(obj/item/attacking_item, mob/living/user, list/modifiers) + . = NONE if(istype(attacking_item, /obj/item/rcd_upgrade)) internal_rcd.install_upgrade(attacking_item, user) - return - return ..() + return ITEM_INTERACT_SUCCESS + +#undef RCD_RANGE //Dunno where else to put this so shrug /obj/item/mecha_parts/mecha_equipment/ripleyupgrade diff --git a/code/modules/vehicles/mecha/mecha_ai_interaction.dm b/code/modules/vehicles/mecha/mecha_ai_interaction.dm index 168b2e0ea029d..4b4d92f06a268 100644 --- a/code/modules/vehicles/mecha/mecha_ai_interaction.dm +++ b/code/modules/vehicles/mecha/mecha_ai_interaction.dm @@ -9,7 +9,7 @@ to_chat(user, "[B.get_mecha_info()]") break //Nothing like a big, red link to make the player feel powerful! - to_chat(user, "<a href='?src=[REF(user)];ai_take_control=[REF(src)]'>[span_userdanger("ASSUME DIRECT CONTROL?")]</a><br>") + to_chat(user, "<a href='byond://?src=[REF(user)];ai_take_control=[REF(src)]'>[span_userdanger("ASSUME DIRECT CONTROL?")]</a><br>") return examine(user) if(length(return_occupants()) >= max_occupants) @@ -23,7 +23,7 @@ if(!can_control_mech) to_chat(user, span_warning("You cannot control exosuits without AI control beacons installed.")) return - to_chat(user, "<a href='?src=[REF(user)];ai_take_control=[REF(src)]'>[span_boldnotice("Take control of exosuit?")]</a><br>") + to_chat(user, "<a href='byond://?src=[REF(user)];ai_take_control=[REF(src)]'>[span_boldnotice("Take control of exosuit?")]</a><br>") /obj/vehicle/sealed/mecha/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) . = ..() diff --git a/code/modules/vending/mail.dm b/code/modules/vending/mail.dm index 1e091a3128756..6bc3648b056d1 100644 --- a/code/modules/vending/mail.dm +++ b/code/modules/vending/mail.dm @@ -46,11 +46,13 @@ /obj/machinery/mailsorter/proc/get_unload_turf() return get_step(src, output_dir) +/// Opening the maintenance panel. /obj/machinery/mailsorter/screwdriver_act(mob/living/user, obj/item/tool) default_deconstruction_screwdriver(user, "[base_icon_state]-off", base_icon_state, tool) update_appearance(UPDATE_OVERLAYS) return ITEM_INTERACT_SUCCESS +/// Deconstructing the mail sorter. /obj/machinery/mailsorter/crowbar_act(mob/living/user, obj/item/tool) default_deconstruction_crowbar(tool) return ITEM_INTERACT_SUCCESS @@ -63,11 +65,15 @@ . += span_notice("Alt-click to rotate the output direction.") /obj/machinery/mailsorter/Destroy() + QDEL_LIST(mail_list) + . = ..() + +/obj/machinery/mailsorter/on_deconstruction(disassembled) drop_all_mail() . = ..() -/// Drops all enevlopes on the machine turf. Only occurs when the machine is broken. -/obj/machinery/mailsorter/proc/drop_all_mail(damage_flag) +/// Drops all enevlopes on the machine turf. +/obj/machinery/mailsorter/proc/drop_all_mail() if(!isturf(get_turf(src))) QDEL_LIST(mail_list) return @@ -90,10 +96,6 @@ /obj/machinery/mailsorter/proc/accept_check(obj/item/weapon) var/static/list/accepted_items = list( /obj/item/mail, - /obj/item/mail/envelope, - /obj/item/mail/junkmail, - /obj/item/mail/mail_strike, - /obj/item/mail/traitor, /obj/item/paper, ) return is_type_in_list(weapon, accepted_items) @@ -151,10 +153,13 @@ if (some_recipient) var/datum/job/recipient_job = some_recipient.assigned_role var/datum/job_department/primary_department = recipient_job.departments_list?[1] - var/datum/job_department/main_department = primary_department.department_name - if (main_department == sorting_dept) - sorted_mail.Add(some_mail) - sorted ++ + if (primary_department == null) // permabrig is temporary, tide is forever + unable_to_sort ++ + else + var/datum/job_department/main_department = primary_department.department_name + if (main_department == sorting_dept) + sorted_mail.Add(some_mail) + sorted ++ else unable_to_sort ++ if (length(sorted_mail) == 0) diff --git a/code/modules/wiremod/shell/brain_computer_interface.dm b/code/modules/wiremod/shell/brain_computer_interface.dm index b31f3ce151bcd..1ade714552f75 100644 --- a/code/modules/wiremod/shell/brain_computer_interface.dm +++ b/code/modules/wiremod/shell/brain_computer_interface.dm @@ -208,7 +208,7 @@ SIGNAL_HANDLER if (isobserver(mob)) - examine_text += span_notice("[source.p_They()] [source.p_have()] <a href='?src=[REF(src)];open_bci=1'>\a [parent] implanted in [source.p_them()]</a>.") + examine_text += span_notice("[source.p_They()] [source.p_have()] <a href='byond://?src=[REF(src)];open_bci=1'>\a [parent] implanted in [source.p_them()]</a>.") /obj/item/circuit_component/bci_core/Topic(href, list/href_list) ..() diff --git a/html/changelogs/AutoChangeLog-pr-88568.yml b/html/changelogs/AutoChangeLog-pr-88568.yml new file mode 100644 index 0000000000000..0be95af6bb764 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88568.yml @@ -0,0 +1,4 @@ +author: "timothymtorres" +delete-after: True +changes: + - bugfix: "Fix holodeck computer using wrong power settings and not updating properly" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88574.yml b/html/changelogs/AutoChangeLog-pr-88574.yml deleted file mode 100644 index 7f7b8f9c8e78e..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88574.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Lobby button sprites" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88578.yml b/html/changelogs/AutoChangeLog-pr-88578.yml new file mode 100644 index 0000000000000..34877c2d38dfe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88578.yml @@ -0,0 +1,4 @@ +author: "Wallem" +delete-after: True +changes: + - rscadd: "Rare collectors radios have been reported around Nanotrasen stations!" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-88597.yml b/html/changelogs/AutoChangeLog-pr-88597.yml new file mode 100644 index 0000000000000..1310118179f3a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88597.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "skull cookies are visible again" \ No newline at end of file diff --git a/html/changelogs/archive/2024-12.yml b/html/changelogs/archive/2024-12.yml index 7fdad3175732a..f79a0fb07e5b2 100644 --- a/html/changelogs/archive/2024-12.yml +++ b/html/changelogs/archive/2024-12.yml @@ -471,3 +471,153 @@ - bugfix: Poultice works on dead people SmArtKar: - bugfix: Fixed an airlock unlocking runtime +2024-12-21: + Deadgebert: + - balance: Synthflesh required for unhusking now between 60u and 100u depending + on purity. + Melbert: + - bugfix: Lobby button sprites +2024-12-22: + Absolucy: + - rscadd: Added a notice for clients on BYOND 516 that 516 is still in beta, and + UI elements may not be fully compatible yet. + - qol: Rust heretic healing (leeching walk, rust ascension) now, so server lag shouldn't + fuck you over nearly as much if you're relying on the healing. + Cruix: + - rscadd: Shuttle navigation computers now show the location of airlocks, turrets, + and the shuttle control consoles on the ship outline while placing a custom + landing location. + Darkened-Earth: + - bugfix: Alarm ranchers have wrangled up a rogue fire alarm in Meta class station + custom offices and relocated it to a safe habitat + Gaxeer: + - bugfix: modular computer laptops can now be interacted with RMB, instead of picked + up + - qol: modular computer laptops can now be interacted with RMB when open, or opened + with RMB when closed. Also screentips for this added + Kocma-san: + - rscadd: added a "print" button to the request manager + - rscadd: admin fax can now send exotic items + - rscadd: added "Auto-print Faxes" button to the request manager, which allows you + to enable automatic printing of requests on the admin fax + - bugfix: fixed a bug where pressing the print button would cause the receive animation + to appear on all admin faxes. + - bugfix: fix radio sound output when receiving a message + - sound: the sound of receiving your own messages over the radio is no longer played + Melbert: + - rscadd: Nitroglycerin now heals heart damage. + SmArtKar: + - bugfix: Fixed floodlights not being affected by spraycan painting + - balance: Mech-mounted RCD no longer has wallhacks + - balance: Reinforced walls now take double the time to get deconstructed when using + an RCD + - map: Added a Condi-Master to Birdshot's bar + - bugfix: Fixed shoes slot being semi-transparent when you have digitigrade legs + - spellcheck: Bioscrambler no longer informs you about "your armor softening the + blow!" + - bugfix: Chemmaster no longer rounds reagent amounts when trying to transfer a + custom amount + Sparex: + - map: Added lifting benches/workout benches to the fitness room for IceboxStation.dmm + SyncIt21: + - bugfix: fixed runtime when sealing mecha cabin with air tank installed + - bugfix: personal ordered crates can be unlocked & relocked as many times again + after the 1st attempt + - bugfix: greyscale modify menu has better validation for player entered colours + - code_imp: improved code for mecha rcd + - bugfix: mecha rcd will cancel its action when the mech is rotated or moves during + the action + TealSeer: + - qol: Atmos devices like valves and pumps can now be renamed with a pen. + UnokiAs: + - rscadd: Make spears able to break open lockers in melee. + grungussuss: + - rscdel: screenshake from explosions will no longer happen when it's really far + and not on a station area (turf) + mcbalaam: + - bugfix: The mail sorter no longer runtimes processing assistant mail + timothymtorres: + - spellcheck: Update teleporter machine desc to be accurate + - spellcheck: Fix holodeck emag message claiming to increase power + - rscadd: Add power efficiency when stasis bed stock parts are upgraded +2024-12-23: + AyIong: + - bugfix: Fixed scrollbar colors and background position in TGUI on Byond 516 + Ben10Omintrix: + - rscadd: adds flora-turtles. obtainable through cargo or by fishing from the hydroponics + tray + - qol: holding shift and hovering over your pet will display a list of commands + you can click from + - bugfix: fixes the fishing pet command not working + DATA-xPUNGED: + - map: removed the sec record computer from the Icemoon Listening Post. + Melbert: + - balance: Carpenter hammer force 20 -> 17 + - balance: Carpenter hammer throwforce 20 -> 14 + - balance: Carpenter hammer demo mod 1.25 -> 1.15 + NecromancerAnne (code), SmArtKar (sprites): + - balance: Makarovs and Toy Pistols come in weapon cases. Complete with spare ammo. + - balance: Basic ammo for either weapon comes in weapon cases of three extra magazines + at an affordable price. + - balance: Donksoft Toy Pistols from the uplink are much stronger than their standard + counterparts, but now priced at 6 TC. + - balance: Makarovs and Toy pistols have a magazine capacity of 12 rounds. + - balance: Gun/Ammo cases from the traitor uplink can be destroyed by activating + the disposal bomb. Press Alt-Right-Click on the case to start the timer. + Rhials: + - rscadd: Nukie uplinks now offer an OG-style nuke pinpointer in their Badassery + shop section. + TealSeer: + - qol: The time until the server reboots is now visible in the status tab. + - admin: Added a cancel reboot verb to the server tab. + grungussuss: + - code_imp: removed an extra proc override in digitigrade legs preference logic + code +2024-12-24: + SmArtKar: + - admin: Admins can now return the shuttle back to the station without ending the + round + - bugfix: Fixed moth wing stabilization working in zero-g as long as you keep moving + - bugfix: Fixed showers not passively washing objects + SyncIt21: + - bugfix: rolling tables can be rolled up again + carlarctg: + - rscadd: Kissing while you have the ink infusion ability off cooldown gives you + an ink kiss +2024-12-25: + Absolucy, ShadowLarkens, S34N: + - bugfix: Fixed chat rapidly flickering in BYOND 516. + AyIong: + - qol: AdminPMs, admin tickets, vote results and started vote notification are now + much more visible in the chat. + - qol: Boxed messages in chat (like examine), has been restyled. + Ghommie: + - bugfix: Fixed aquariums auto-feeding. + Hatterhat: + - bugfix: .357 Heartseeker homes in on people if you click on them, instead of not + homing in at all. + KazooBard: + - qol: Selecting which spells to cast with hotkeys, and using them in general is + faster. + LT3: + - bugfix: You can no longer hug yourself to overcome fear of the dark + Melbert: + - balance: Lava no longer burns mobs thrown over it + - qol: Navigate verb better indicates areas on a separate level. Selecting an area + on a different level will direct you to the nearest staircase (as with "Nearest + Way Up/Down") + - qol: Navigating to a staircase or ladder will shorten the cooldown of navigate + and clear your existing path for you upon finding it + SyncIt21: + - bugfix: Big manipulator respects storage limits of storages when dropping stuff + into them + araeotu: + - rscadd: slime processor now have usb port and circuit component + - code_imp: the process code of processor now separate from interact + grungussuss: + - balance: computers can now be used as cover, firing a projectile over them is + now possible, while they may block projectiles if you are not adjacent to them + when firing. + - bugfix: computer laptops will not block projectiles + lovegreenstuff: + - rscadd: catalyst function for plumbing reaction chambers diff --git a/html/statbrowser.css b/html/statbrowser.css index d8c0f92b626f4..d49cb3d6e2667 100644 --- a/html/statbrowser.css +++ b/html/statbrowser.css @@ -1,3 +1,13 @@ +.light:root { + --scrollbar-base: #f2f2f2; + --scrollbar-thumb: #a7a7a7; +} + +html, +body { + scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-base); +} + body { font-family: Verdana, Geneva, Tahoma, sans-serif; font-size: 12px; @@ -177,9 +187,16 @@ img { margin-bottom: 1em; } -/* Dark theme colors */ +/** + * MARK: Dark theme colors + */ +.dark:root { + --scrollbar-base: #151515; + --scrollbar-thumb: #363636; +} + body.dark { - background-color: #131313; + background-color: #151515; color: #b2c4dd; scrollbar-base-color: #1c1c1c; scrollbar-face-color: #3b3b3b; @@ -201,7 +218,7 @@ body.dark { } .dark #menu { - background-color: #131313; + background-color: #151515; } .dark #menu.tabs-classic .button.active { diff --git a/html/statbrowser.js b/html/statbrowser.js index 3fe115943a702..d33713f65f746 100644 --- a/html/statbrowser.js +++ b/html/statbrowser.js @@ -705,9 +705,11 @@ function draw_verbs(cat) { function set_theme(which) { if (which == "light") { document.body.className = ""; + document.documentElement.className = 'light'; set_style_sheet("browserOutput_white"); } else if (which == "dark") { document.body.className = "dark"; + document.documentElement.className = 'dark'; set_style_sheet("browserOutput"); } } diff --git a/icons/effects/mouse_pointers/pet_paw.dmi b/icons/effects/mouse_pointers/pet_paw.dmi new file mode 100644 index 0000000000000..a4443a6896721 Binary files /dev/null and b/icons/effects/mouse_pointers/pet_paw.dmi differ diff --git a/icons/effects/nav_computer_indicators.dmi b/icons/effects/nav_computer_indicators.dmi new file mode 100644 index 0000000000000..ff6a616c2968c Binary files /dev/null and b/icons/effects/nav_computer_indicators.dmi differ diff --git a/icons/hud/radial_pets.dmi b/icons/hud/radial_pets.dmi new file mode 100644 index 0000000000000..a9ce7a1d0062c Binary files /dev/null and b/icons/hud/radial_pets.dmi differ diff --git a/icons/mob/simple/pets.dmi b/icons/mob/simple/pets.dmi index b7e8642387228..512a48e813b0d 100644 Binary files a/icons/mob/simple/pets.dmi and b/icons/mob/simple/pets.dmi differ diff --git a/icons/mob/simple/turtle_trees.dmi b/icons/mob/simple/turtle_trees.dmi new file mode 100644 index 0000000000000..3e5cf1d4065fa Binary files /dev/null and b/icons/mob/simple/turtle_trees.dmi differ diff --git a/icons/obj/devices/voice.dmi b/icons/obj/devices/voice.dmi index 4188d7867eebd..807308a76180b 100644 Binary files a/icons/obj/devices/voice.dmi and b/icons/obj/devices/voice.dmi differ diff --git a/icons/obj/storage/case.dmi b/icons/obj/storage/case.dmi index 94b7251f93f46..65b40a403ea2e 100644 Binary files a/icons/obj/storage/case.dmi and b/icons/obj/storage/case.dmi differ diff --git a/interface/skin.dmf b/interface/skin.dmf index 429c0a1374a5c..7124e67cec605 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -224,7 +224,7 @@ window "infowindow" window "outputwindow" elem "outputwindow" type = MAIN - pos = 281,0 + pos = 0,0 size = 640x480 anchor1 = -1,-1 anchor2 = -1,-1 @@ -281,15 +281,26 @@ window "outputwindow" command = ".winset \"mebutton.is-checked=true ? input.command=\"!me \\\"\" : input.command=\"\"mebutton.is-checked=true ? saybutton.is-checked=false\"\"mebutton.is-checked=true ? oocbutton.is-checked=false\"" is-flat = true button-type = pushbox - elem "browseroutput" - type = BROWSER + elem "legacy_output_selector" + type = CHILD pos = 0,0 size = 640x456 anchor1 = 0,0 anchor2 = 100,100 - is-visible = false - is-disabled = true - saved-params = "" + saved-params = "splitter" + left = "output_legacy" + is-vert = false + +window "output_legacy" + elem "output_legacy" + type = MAIN + pos = 0,0 + size = 640x456 + anchor1 = -1,-1 + anchor2 = -1,-1 + background-color = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true elem "output" type = OUTPUT pos = 0,0 @@ -299,6 +310,25 @@ window "outputwindow" is-default = true saved-params = "" +window "output_browser" + elem "output_browser" + type = MAIN + pos = 0,0 + size = 640x456 + anchor1 = -1,-1 + anchor2 = -1,-1 + background-color = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "browseroutput" + type = BROWSER + pos = 0,0 + size = 640x456 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = none + saved-params = "" + window "popupwindow" elem "popupwindow" type = MAIN diff --git a/modular_bandastation/modular_bandastation.dme b/modular_bandastation/modular_bandastation.dme index 24d327b88b3ad..044bbdd910d3d 100644 --- a/modular_bandastation/modular_bandastation.dme +++ b/modular_bandastation/modular_bandastation.dme @@ -42,6 +42,7 @@ #include "automatic_crew_transfer/_automatic_crew_transfer.dme" #include "outfits/_outfits.dme" #include "overrides/_overrides.dme" +#include "species/_species.dme" // --- PRIME --- // diff --git a/modular_bandastation/species/_species.dm b/modular_bandastation/species/_species.dm new file mode 100644 index 0000000000000..1c0f176f9de2c --- /dev/null +++ b/modular_bandastation/species/_species.dm @@ -0,0 +1,4 @@ +/datum/modpack/species + name = "Species" + desc = "Добавление архитектуры для новых видов и конфигурирования существующих." + author = "Podvaldeda" diff --git a/modular_bandastation/species/_species.dme b/modular_bandastation/species/_species.dme new file mode 100644 index 0000000000000..a461cce87321c --- /dev/null +++ b/modular_bandastation/species/_species.dme @@ -0,0 +1,3 @@ +#include "_species.dm" + +#include "code/lizardperson/sprite_accesories/hair.dm" diff --git a/modular_bandastation/species/code/lizardperson/sprite_accesories/hair.dm b/modular_bandastation/species/code/lizardperson/sprite_accesories/hair.dm new file mode 100644 index 0000000000000..bbf5f33f31797 --- /dev/null +++ b/modular_bandastation/species/code/lizardperson/sprite_accesories/hair.dm @@ -0,0 +1,116 @@ +// MARK: Frills +/datum/sprite_accessory/frills/divinity + name = "Divinity" + icon = 'modular_bandastation/species/icons/lizardperson/frills.dmi' + icon_state = "divinity" + +/datum/sprite_accessory/frills/horns + name = "Horns" + icon = 'modular_bandastation/species/icons/lizardperson/frills.dmi' + icon_state = "horns" + +/datum/sprite_accessory/frills/hornsdouble + name = "Horns Double" + icon = 'modular_bandastation/species/icons/lizardperson/frills.dmi' + icon_state = "hornsdouble" + +/datum/sprite_accessory/frills/big + name = "Big" + icon = 'modular_bandastation/species/icons/lizardperson/frills.dmi' + icon_state = "big" + +/datum/sprite_accessory/frills/cobrahood + name = "Cobrahood" + icon = 'modular_bandastation/species/icons/lizardperson/frills.dmi' + icon_state = "cobrahood" + +/datum/sprite_accessory/frills/cobraears + name = "Cobraears" + icon = 'modular_bandastation/species/icons/lizardperson/frills.dmi' + icon_state = "cobraears" + +/datum/sprite_accessory/frills/neck + name = "Neck" + icon = 'modular_bandastation/species/icons/lizardperson/frills.dmi' + icon_state = "neck" + +/datum/sprite_accessory/frills/neckfull + name = "Neck Full" + icon = 'modular_bandastation/species/icons/lizardperson/frills.dmi' + icon_state = "neckfull" + +/datum/sprite_accessory/frills/cobraslim + name = "Cobraslim" + icon = 'modular_bandastation/species/icons/lizardperson/frills.dmi' + icon_state = "cobraslim" + +// MARK: Horns +/datum/sprite_accessory/horns/guilmon + name = "Guilmon" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "guilmon" + +/datum/sprite_accessory/horns/drake + name = "Drake" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "drake" + +/datum/sprite_accessory/horns/knight + name = "Knight" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "knight" + +/datum/sprite_accessory/horns/uni + name = "Uni" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "uni" + +/datum/sprite_accessory/horns/oni + name = "Oni" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "oni" + +/datum/sprite_accessory/horns/onilarge + name = "Oni Large" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "onilarge" + +/datum/sprite_accessory/horns/broken + name = "Broken" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "broken" + +/datum/sprite_accessory/horns/rbroken + name = "Right Broken" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "rbroken" + +/datum/sprite_accessory/horns/lbroken + name = "Left Broken" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "lbroken" + +/datum/sprite_accessory/horns/dragon + name = "Dragon" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "dragon" + +/datum/sprite_accessory/horns/lifted + name = "Lifted" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "lifted" + +/datum/sprite_accessory/horns/newcurly + name = "New Curly" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "newcurly" + +/datum/sprite_accessory/horns/upwardshorns + name = "Upwards Horns" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "upwardshorns" + +/datum/sprite_accessory/horns/sideswept + name = "Side Swept" + icon = 'modular_bandastation/species/icons/lizardperson/horns.dmi' + icon_state = "sideswept" diff --git a/modular_bandastation/species/icons/lizardperson/frills.dmi b/modular_bandastation/species/icons/lizardperson/frills.dmi new file mode 100644 index 0000000000000..cb22343bc7df8 Binary files /dev/null and b/modular_bandastation/species/icons/lizardperson/frills.dmi differ diff --git a/modular_bandastation/species/icons/lizardperson/horns.dmi b/modular_bandastation/species/icons/lizardperson/horns.dmi new file mode 100644 index 0000000000000..38c86e31f2e40 Binary files /dev/null and b/modular_bandastation/species/icons/lizardperson/horns.dmi differ diff --git a/sound/voice/repairbot/brick.ogg b/sound/mobs/non-humanoids/repairbot/brick.ogg similarity index 100% rename from sound/voice/repairbot/brick.ogg rename to sound/mobs/non-humanoids/repairbot/brick.ogg diff --git a/sound/voice/repairbot/cantanymore.ogg b/sound/mobs/non-humanoids/repairbot/cantanymore.ogg similarity index 100% rename from sound/voice/repairbot/cantanymore.ogg rename to sound/mobs/non-humanoids/repairbot/cantanymore.ogg diff --git a/sound/voice/repairbot/entropy.ogg b/sound/mobs/non-humanoids/repairbot/entropy.ogg similarity index 100% rename from sound/voice/repairbot/entropy.ogg rename to sound/mobs/non-humanoids/repairbot/entropy.ogg diff --git a/sound/voice/repairbot/fixit.ogg b/sound/mobs/non-humanoids/repairbot/fixit.ogg similarity index 100% rename from sound/voice/repairbot/fixit.ogg rename to sound/mobs/non-humanoids/repairbot/fixit.ogg diff --git a/sound/voice/repairbot/fixtouch.ogg b/sound/mobs/non-humanoids/repairbot/fixtouch.ogg similarity index 100% rename from sound/voice/repairbot/fixtouch.ogg rename to sound/mobs/non-humanoids/repairbot/fixtouch.ogg diff --git a/sound/voice/repairbot/passionproject.ogg b/sound/mobs/non-humanoids/repairbot/passionproject.ogg similarity index 100% rename from sound/voice/repairbot/passionproject.ogg rename to sound/mobs/non-humanoids/repairbot/passionproject.ogg diff --git a/sound/voice/repairbot/patchingholes.ogg b/sound/mobs/non-humanoids/repairbot/patchingholes.ogg similarity index 100% rename from sound/voice/repairbot/patchingholes.ogg rename to sound/mobs/non-humanoids/repairbot/patchingholes.ogg diff --git a/sound/voice/repairbot/pay.ogg b/sound/mobs/non-humanoids/repairbot/pay.ogg similarity index 100% rename from sound/voice/repairbot/pay.ogg rename to sound/mobs/non-humanoids/repairbot/pay.ogg diff --git a/sound/voice/repairbot/strings.ogg b/sound/mobs/non-humanoids/repairbot/strings.ogg similarity index 100% rename from sound/voice/repairbot/strings.ogg rename to sound/mobs/non-humanoids/repairbot/strings.ogg diff --git a/strings/tips.txt b/strings/tips.txt index 5f33cb87bc7fe..e6fc672c5c494 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -227,6 +227,7 @@ Basketball requires skill. Spinning drains stamina, reduces accuracy, but gives Basketball requires teamwork. Passing the ball with LMB is instant and costs no stamina. Clicking on a windoor rather then bumping into it will keep it open, you can click it again to close it. Different weapons have different strengths. Some weapons, such as spears, floor tiles, and throwing stars, deal more damage when thrown compared to when attacked normally. +Spears are capable of breaking into secure lockers by striking them in melee! Don't be afraid to ask for help, whether from your peers or from admins. Experiment with different setups of the Supermatter engine to maximize output, but don't risk the crew's safety to do so! Felinids get temporarily distracted by laser pointers. Use this to your advantage when being pursued by one. diff --git a/tgstation.dme b/tgstation.dme index e375ea6b7d043..35d1d5cb738d6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -187,6 +187,7 @@ #include "code\__DEFINES\pronouns.dm" #include "code\__DEFINES\qdel.dm" #include "code\__DEFINES\quirks.dm" +#include "code\__DEFINES\radial_defines.dm" #include "code\__DEFINES\radiation.dm" #include "code\__DEFINES\radio.dm" #include "code\__DEFINES\radioactive_nebula.dm" @@ -1539,6 +1540,7 @@ #include "code\datums\elements\movement_turf_changer.dm" #include "code\datums\elements\movetype_handler.dm" #include "code\datums\elements\muffles_speech.dm" +#include "code\datums\elements\nav_computer_icon.dm" #include "code\datums\elements\nerfed_pulling.dm" #include "code\datums\elements\no_crit_hitting.dm" #include "code\datums\elements\noisy_movement.dm" @@ -5163,6 +5165,9 @@ #include "code\modules\mob\living\basic\trooper\syndicate.dm" #include "code\modules\mob\living\basic\trooper\trooper.dm" #include "code\modules\mob\living\basic\trooper\trooper_ai.dm" +#include "code\modules\mob\living\basic\turtle\turtle.dm" +#include "code\modules\mob\living\basic\turtle\turtle_ability.dm" +#include "code\modules\mob\living\basic\turtle\turtle_ai.dm" #include "code\modules\mob\living\basic\vermin\axolotl.dm" #include "code\modules\mob\living\basic\vermin\butterfly.dm" #include "code\modules\mob\living\basic\vermin\cockroach.dm" @@ -5527,6 +5532,7 @@ #include "code\modules\photography\photos\photo.dm" #include "code\modules\plumbing\ducts.dm" #include "code\modules\plumbing\plumbers\_plumb_machinery.dm" +#include "code\modules\plumbing\plumbers\_plumb_reagents.dm" #include "code\modules\plumbing\plumbers\acclimator.dm" #include "code\modules\plumbing\plumbers\bottler.dm" #include "code\modules\plumbing\plumbers\destroyer.dm" diff --git a/tgui/packages/tgui-panel/index.tsx b/tgui/packages/tgui-panel/index.tsx index a70a53bac251e..9fccceb4d2178 100644 --- a/tgui/packages/tgui-panel/index.tsx +++ b/tgui/packages/tgui-panel/index.tsx @@ -75,14 +75,8 @@ const setupApp = () => { Byond.subscribe((type, payload) => store.dispatch({ type, payload })); // Unhide the panel - Byond.winset('output', { - 'is-visible': false, - }); - Byond.winset('browseroutput', { - 'is-visible': true, - 'is-disabled': false, - pos: '0x0', - size: '0x0', + Byond.winset('legacy_output_selector', { + left: 'output_browser', }); // Resize the panel to match the non-browser output diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss index ae77e4200e713..31435912422f2 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss @@ -42,6 +42,10 @@ a.popt { text-decoration: none; } +.center { + text-align: center; +} + /* POPUPS */ .popup { @@ -775,6 +779,10 @@ em { font-size: 60%; } +.smaller { + font-size: 80%; +} + .slightly_larger { font-size: 115%; } @@ -972,16 +980,70 @@ em { margin-left: 2.5em; } -.examine_block { - background: hsl(220, 5.3%, 11.2%); - border: 1px solid hsl(213.6, 37.9%, 74.1%); - margin: 0.5em; - padding: 0.5em 0.75em; -} - .tooltip { font-style: italic; - border-bottom: 1px dashed #fff; + border-bottom: 1px dashed; +} + +.fieldset_legend { + position: relative; + max-width: 95%; + font-size: 120%; + padding: 0.2em 0.5em; + background: #151515; // Chat background color + border: 1px solid; + border-color: inherit; + border-radius: 0.33em; + z-index: 1; + + // "Mask" a half of the border + // It very rough but it only possible way i see with IE compat + // Replace it with normal mask-image when 516 got stable + &:before { + content: ''; + position: absolute; + left: 0; + height: 1.15em; + width: 100%; + background: #151515; // Chat background color + transform: translateY(-50%) scaleX(1.05); + z-index: -1; + } +} + +.boxed_message { + background: hsl(220, 10%, 10%); + border: 1em * calc(1px / 12px) solid; + border-left: 1em * calc(4px / 12px) solid; + border-color: hsla(220, 40%, 75%, 0.25); + margin: 0.5em 0; + padding: 0.5em 0.75em; + border-radius: 0.33em; + + &.red_box { + background: hsl(0, 20%, 10%); + border-color: hsla(0, 100%, 50%, 0.5); + } + + &.green_box { + background: hsl(140, 20%, 10%); + border-color: hsla(120, 100%, 50%, 0.5); + } + + &.blue_box { + background: hsl(220, 20%, 10%); + border-color: hsla(225, 90%, 65%, 0.5); + } + + &.purple_box { + background: hsl(260, 25%, 12.5%); + border-color: hsla(260, 100%, 75%, 0.5); + } + + hr { + margin: 0.5em -0.75em; + border-color: inherit; + } } // Provides a horizontal bar with text in the middle @@ -1188,11 +1250,19 @@ $border-width-px: $border-width * 1px; } .chat_alert_#{$color-name} .minor_announcement_text { - background-color: darken(map.get($alert-stripe-colors, $color-name), 5); + background-color: color.adjust( + map.get($alert-stripe-colors, $color-name), + $lightness: -5%, + $space: hsl + ); } .chat_alert_#{$color-name} .major_announcement_text { - background-color: darken(map.get($alert-stripe-colors, $color-name), 5); + background-color: color.adjust( + map.get($alert-stripe-colors, $color-name), + $lightness: -5%, + $space: hsl + ); } } diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss index d554ed4735998..94fc00add3ce6 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss @@ -990,16 +990,42 @@ h2.alert { margin-left: 3em; } -.examine_block { - background: hsl(202.5, 44.4%, 96.5%); - border: 1px solid hsl(215.5, 39.3%, 11%); - margin: 0.5em; - padding: 0.5em 0.75em; -} - .tooltip { font-style: italic; - border-bottom: 1px dashed #000; + border-bottom: 1px dashed; +} + +.fieldset_legend { + background: #ffffff; // Chat background color + + &:before { + background: #ffffff; // Chat background color + } +} + +.boxed_message { + background: hsl(220, 100%, 97.5%); + border-color: hsla(220, 75%, 25%, 0.5); + + &.red_box { + background: hsl(0, 100%, 97.5%); + border-color: hsla(0, 100%, 50%, 0.5); + } + + &.green_box { + background: hsl(140, 100%, 97.5%); + border-color: hsl(120, 100%, 33%, 0.5); + } + + &.blue_box { + background: hsl(220, 100%, 97.5%); + border-color: hsla(225, 100%, 50%, 0.5); + } + + &.purple_box { + background: hsl(260, 100%, 97.5%); + border-color: hsla(260, 100%, 50%, 0.5); + } } // Provides a horizontal bar with text in the middle @@ -1206,16 +1232,18 @@ $border-width-px: $border-width * 1px; } .chat_alert_#{$color-name} .minor_announcement_text { - background-color: lighten( + background-color: color.adjust( map.get($alert-stripe-alternate-colors, $color-name), - 5 + $lightness: 5%, + $space: hsl ); } .chat_alert_#{$color-name} .major_announcement_text { - background-color: lighten( + background-color: color.adjust( map.get($alert-stripe-alternate-colors, $color-name), - 5 + $lightness: 5%, + $space: hsl ); } } diff --git a/tgui/packages/tgui-say/styles/button.scss b/tgui/packages/tgui-say/styles/button.scss index 89e1cceca943a..69802c045ec5e 100644 --- a/tgui/packages/tgui-say/styles/button.scss +++ b/tgui/packages/tgui-say/styles/button.scss @@ -15,7 +15,11 @@ padding: 0; width: 2.6rem; &:hover { - background-color: lighten(colors.$button, 10%); + background-color: color.adjust( + colors.$button, + $lightness: 10%, + $space: hsl + ); } } diff --git a/tgui/packages/tgui-say/styles/colors.scss b/tgui/packages/tgui-say/styles/colors.scss index 0f8ab028f250d..021241188d775 100644 --- a/tgui/packages/tgui-say/styles/colors.scss +++ b/tgui/packages/tgui-say/styles/colors.scss @@ -55,7 +55,7 @@ $channel_keys: map.keys($_channel_map) !default; $channel-map: (); @each $channel in $channel_keys { - $channel-map: map-merge( + $channel-map: map.merge( $channel-map, ( $channel: map.get($_channel_map, $channel), diff --git a/tgui/packages/tgui-say/styles/main.scss b/tgui/packages/tgui-say/styles/main.scss index 8e164aa21fa7f..bafc850e242a0 100644 --- a/tgui/packages/tgui-say/styles/main.scss +++ b/tgui/packages/tgui-say/styles/main.scss @@ -26,14 +26,14 @@ } @each $channel, $color in colors.$channel-map { - $darkened: darken($color, 20%); + $darkened: color.adjust($color, $lightness: -20%, $space: hsl); .button-#{$channel} { - border-color: darken($color, 10%); + border-color: color.adjust($color, $lightness: -10%, $space: hsl); color: $color; &:hover { - border-color: lighten($color, 10%); - color: lighten($color, 5%); + border-color: color.adjust($color, $lightness: 10%, $space: hsl); + color: color.adjust($color, $lightness: 5%, $space: hsl); } } @@ -50,11 +50,11 @@ animation: gradient 10s linear infinite; background: linear-gradient( to right, - darken($color, 35%), + color.adjust($color, $lightness: -35%, $space: hsl), $color, - lighten($color, 10%), + color.adjust($color, $lightness: 10%, $space: hsl), $color, - darken($color, 35%) + color.adjust($color, $lightness: -35%, $space: hsl) ); background-position: 0% 0%; background-size: 500% auto; diff --git a/tgui/packages/tgui/interfaces/ChemMixingChamber.tsx b/tgui/packages/tgui/interfaces/ChemMixingChamber.tsx index 765862ab4b86c..2f9a9cd901630 100644 --- a/tgui/packages/tgui/interfaces/ChemMixingChamber.tsx +++ b/tgui/packages/tgui/interfaces/ChemMixingChamber.tsx @@ -13,7 +13,7 @@ import { BooleanLike } from 'tgui-core/react'; import { useBackend } from '../backend'; import { Window } from '../layouts'; -type Reagent = { +export type Reagent = { name: string; volume: number; }; diff --git a/tgui/packages/tgui/interfaces/ChemReactionChamber.tsx b/tgui/packages/tgui/interfaces/ChemReactionChamber.tsx index cdc2b6fac97b9..255e669efcf04 100644 --- a/tgui/packages/tgui/interfaces/ChemReactionChamber.tsx +++ b/tgui/packages/tgui/interfaces/ChemReactionChamber.tsx @@ -13,12 +13,13 @@ import { round, toFixed } from 'tgui-core/math'; import { useBackend } from '../backend'; import { Window } from '../layouts'; -import { MixingData } from './ChemMixingChamber'; +import { MixingData, Reagent } from './ChemMixingChamber'; type ReactingData = MixingData & { ph: number; reagentAcidic: number; reagentAlkaline: number; + catalysts: Reagent[]; }; export const ChemReactionChamber = (props) => { @@ -36,8 +37,9 @@ export const ChemReactionChamber = (props) => { reagentAlkaline, } = data; const reagents = data.reagents || []; + const catalysts = data.catalysts || []; return ( - <Window width={290} height={400}> + <Window width={290} height={520}> <Window.Content> <Stack vertical fill> <Stack.Item> @@ -130,8 +132,9 @@ export const ChemReactionChamber = (props) => { <Stack.Item grow> <Section title="Settings" - fill - scrollable + height="220px" + maxHeight="220px" + overflow="hidden" buttons={ (isReacting && ( <Box inline bold color={'purple'}> @@ -189,7 +192,6 @@ export const ChemReactionChamber = (props) => { <Stack fill> <Stack.Item grow> <Button - content="Add Reagent" color="good" icon="plus" onClick={() => @@ -197,7 +199,9 @@ export const ChemReactionChamber = (props) => { amount: reagentQuantity, }) } - /> + > + Add Reagent + </Button> </Stack.Item> <Stack.Item> <NumberInput @@ -224,6 +228,24 @@ export const ChemReactionChamber = (props) => { <Stack.Item mt={0.25} grow> {reagent.volume} </Stack.Item> + + <Stack.Item> + <Button + color="transparent" + tooltip={` + This button converts this reagent entry into a catalyst. + Catalyst reagents are not removed from the reaction chamber + on completion. Useful for certain reactions.`} + tooltipPosition="bottom-start" + onClick={() => + act('catalyst', { + chem: reagent.name, + }) + } + > + C + </Button> + </Stack.Item> <Stack.Item> <Button icon="minus" @@ -243,6 +265,43 @@ export const ChemReactionChamber = (props) => { </Stack> </Section> </Stack.Item> + <Stack.Item> + <Section + title="Catalysts" + height="150px" + maxHeight="150px" + overflow="hidden" + > + <Stack.Item> + <Stack vertical fill> + {catalysts.map((reagent) => ( + <Stack.Item key={reagent.name}> + <Stack fill> + <Stack.Item mt={0.25} textColor="label"> + {reagent.name + ':'} + </Stack.Item> + <Stack.Item mt={0.25} grow> + {reagent.volume} + </Stack.Item> + <Stack.Item> + <Button + color="bad" + onClick={() => + act('catremove', { + chem: reagent.name, + }) + } + > + C + </Button> + </Stack.Item> + </Stack> + </Stack.Item> + ))} + </Stack> + </Stack.Item> + </Section> + </Stack.Item> </Stack> </Window.Content> </Window> diff --git a/tgui/packages/tgui/interfaces/RequestManager.tsx b/tgui/packages/tgui/interfaces/RequestManager.tsx index 9a009106788b7..5bc63512f3fbb 100644 --- a/tgui/packages/tgui/interfaces/RequestManager.tsx +++ b/tgui/packages/tgui/interfaces/RequestManager.tsx @@ -3,6 +3,7 @@ * @copyright 2021 bobbahbrown (https://github.com/bobbahbrown) * @license MIT */ +import { BooleanLike } from 'common/react'; import { createSearch, decodeHtmlEntities } from 'common/string'; import { useState } from 'react'; @@ -12,6 +13,7 @@ import { Window } from '../layouts'; type Data = { requests: Request[]; + fax_autoprinting: BooleanLike; }; type Request = { @@ -72,6 +74,15 @@ export const RequestManager = (props) => { buttons={ <Stack> <Stack.Item> + <Button.Checkbox + checked={data.fax_autoprinting} + onClick={() => act('toggleprint')} + tooltip={ + 'Enables automatic printing of fax requests to the admin fax machine. By default, this fax is located in the briefing room at the central command station' + } + > + Auto-print Faxes + </Button.Checkbox> <Input value={searchText} onInput={(_, value) => setSearchText(value)} @@ -146,7 +157,12 @@ const RequestControls = (props) => { </Button> )} {request.req_type === 'request_fax' && ( - <Button onClick={() => act('show', { id: request.id })}>SHOW</Button> + <> + <Button onClick={() => act('show', { id: request.id })}>SHOW</Button> + <Button onClick={() => act('print', { id: request.id })}> + PRINT + </Button> + </> )} {request.req_type === 'request_internet_sound' && ( <Button onClick={() => act('play', { id: request.id })}>PLAY</Button> diff --git a/tgui/packages/tgui/interfaces/Secrets.jsx b/tgui/packages/tgui/interfaces/Secrets.jsx index 3e3ccd70cc0ff..fbe0f56a9124a 100644 --- a/tgui/packages/tgui/interfaces/Secrets.jsx +++ b/tgui/packages/tgui/interfaces/Secrets.jsx @@ -425,13 +425,13 @@ const FunTab = (props) => { /> </Stack.Item> <Stack.Item> - <NoticeBox - mb={-0.5} + <Button + icon="house" + lineHeight={lineHeightNormal} width={buttonWidthNormal} - height={lineHeightNormal} - > - Your admin button here, coder! - </NoticeBox> + content="Send Shuttle Back" + onClick={() => act('send_shuttle_back')} + /> </Stack.Item> </Stack> </Stack.Item> diff --git a/tgui/packages/tgui/layouts/Layout.tsx b/tgui/packages/tgui/layouts/Layout.tsx index 173ed1cbb432d..f3f395e540eca 100644 --- a/tgui/packages/tgui/layouts/Layout.tsx +++ b/tgui/packages/tgui/layouts/Layout.tsx @@ -21,6 +21,7 @@ type Props = Partial<{ export function Layout(props: Props) { const { className, theme = 'nanotrasen', children, ...rest } = props; + document.documentElement.className = `theme-${theme}`; return ( <div className={'theme-' + theme}> diff --git a/tgui/packages/tgui/styles/layouts/Layout.scss b/tgui/packages/tgui/styles/layouts/Layout.scss index ecf750ecc0740..745112eab47c8 100644 --- a/tgui/packages/tgui/styles/layouts/Layout.scss +++ b/tgui/packages/tgui/styles/layouts/Layout.scss @@ -5,12 +5,28 @@ @use 'sass:color'; @use '../base'; +@use '../functions.scss' as *; +$luminance: luminance(base.$color-bg); $scrollbar-color-multiplier: 1 !default; +$scrollbar-base: color.scale( + base.$color-bg, + $lightness: -33% * $scrollbar-color-multiplier +); +$scrollbar-face: color.scale( + base.$color-bg, + $lightness: if($luminance > 0.05, 30%, 10%) * $scrollbar-color-multiplier +); +// Fancy scrollbar +html, +body { + scrollbar-color: $scrollbar-face $scrollbar-base; +} + +// Remove with 516, IE legacy code .Layout, .Layout * { - // Fancy scrollbar scrollbar-base-color: color.scale( base.$color-bg, $lightness: -25% * $scrollbar-color-multiplier diff --git a/tgui/packages/tgui/styles/layouts/TitleBar.scss b/tgui/packages/tgui/styles/layouts/TitleBar.scss index 517f2b8ad811e..8fd7239d55b1f 100644 --- a/tgui/packages/tgui/styles/layouts/TitleBar.scss +++ b/tgui/packages/tgui/styles/layouts/TitleBar.scss @@ -105,7 +105,7 @@ $shadow-color: hsla(0, 0%, 0%, 0.1) !default; min-width: base.rem(20px); padding: 2px 4px; padding: base.rem(2px) base.rem(4px); - background-color: darken(colors.$good, 10%); + background-color: color.adjust(colors.$good, $lightness: -10%, $space: hsl); color: hsl(120, 100%, 100%); text-align: center; } diff --git a/tgui/packages/tgui/styles/main.scss b/tgui/packages/tgui/styles/main.scss index d1e2148ccb35d..e54a7ac719ad8 100644 --- a/tgui/packages/tgui/styles/main.scss +++ b/tgui/packages/tgui/styles/main.scss @@ -67,7 +67,7 @@ // NT Theme .Layout__content { background-image: url('../assets/bg-nanotrasen.svg'); - background-size: 70%; + background-size: 70% 70%; background-position: center; background-repeat: no-repeat; } diff --git a/tools/UpdatePaths/Scripts/repaths_a357_to_c357.txt b/tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt similarity index 100% rename from tools/UpdatePaths/Scripts/repaths_a357_to_c357.txt rename to tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt diff --git a/tools/ci/check_grep.sh b/tools/ci/check_grep.sh index 05718cfccd885..89d803c45dc7d 100644 --- a/tools/ci/check_grep.sh +++ b/tools/ci/check_grep.sh @@ -125,6 +125,14 @@ if $grep 'allocate\(/mob/living/carbon/human[,\)]' $unit_test_files || st=1 fi; +section "516 Href Styles" +part "byond href styles" +if $grep "href[\s='\"\\\\]*\?" $code_files ; then + echo + echo -e "${RED}ERROR: BYOND requires internal href links to begin with \"byond://\".${NC}" + st=1 +fi; + section "common mistakes" part "global vars" if $grep '^/*var/' $code_files; then