This commit is contained in:
EmeraldSundisk
2020-09-02 14:07:09 -07:00
parent d6d708c142
commit 0efa9eb5e5
531 changed files with 10708 additions and 18524 deletions
+1 -2
View File
@@ -99,8 +99,7 @@
#define NO_ASS_SLAP (1<<10)
#define BIMBOFICATION (1<<11)
#define NO_AUTO_WAG (1<<12)
#define GENITAL_EXAMINE (1<<13)
#define VORE_EXAMINE (1<<14)
#define TOGGLES_CITADEL 0
//belly sound pref things
+14 -1
View File
@@ -2,6 +2,19 @@
#define COLOR_INPUT_DISABLED "#F0F0F0"
#define COLOR_INPUT_ENABLED "#D3B5B5"
#define COLOR_DARKMODE_INFO_BUTTONS_BG "#40628A"
#define COLOR_DARKMODE_ISSUE_BUTTON_BG "#A92C2C"
#define COLOR_DARKMODE_BACKGROUND "#272727"
#define COLOR_DARKMODE_DARKBACKGROUND "#242424"
#define COLOR_DARKMODE_TEXT "#E0E0E0"
#define COLOR_WHITEMODE_INFO_BUTTONS_BG "#90B3DD"
#define COLOR_WHITEMODE_ISSUE_BUTTON_BG "#EF7F7F"
#define COLOR_WHITEMODE_BACKGROUND "#F0F0F0"
#define COLOR_WHITEMODE_DARKBACKGROUND "#E6E6E6"
#define COLOR_WHITEMODE_TEXT "#000000"
#define COLOR_FLOORTILE_GRAY "#8D8B8B"
#define COLOR_ALMOST_BLACK "#333333"
#define COLOR_BLACK "#000000"
@@ -51,4 +64,4 @@
#define COLOR_ASSEMBLY_LBLUE "#5D99BE"
#define COLOR_ASSEMBLY_BLUE "#38559E"
#define COLOR_ASSEMBLY_PURPLE "#6F6192"
#define COLOR_ASSEMBLY_PINK "#ff4adc"
#define COLOR_ASSEMBLY_PINK "#ff4adc"
-1
View File
@@ -1,7 +1,6 @@
//config files
#define CONFIG_GET(X) global.config.Get(/datum/config_entry/##X)
#define CONFIG_SET(X, Y) global.config.Set(/datum/config_entry/##X, ##Y)
/// Gets the datum of the object, for when editing a const define.
#define CONFIG_GET_ENTRY(X) global.config.GetEntryDatum(/datum/config_entry/##X)
#define CONFIG_MAPS_FILE "maps.txt"
-4
View File
@@ -4,7 +4,6 @@
#define DYE_REGISTRY_SNEAKERS "sneakers"
#define DYE_REGISTRY_FANNYPACK "fannypack"
#define DYE_REGISTRY_BEDSHEET "bedsheet"
#define DYE_LAWYER_SPECIAL "lawyer_special"
#define DYE_RED "red"
#define DYE_ORANGE "orange"
@@ -17,7 +16,6 @@
#define DYE_RAINBOW "rainbow"
#define DYE_MIME "mime"
#define DYE_COSMIC "cosmic"
#define DYE_SYNDICATE "syndicate"
#define DYE_QM "qm"
#define DYE_LAW "law"
#define DYE_CAPTAIN "captain"
@@ -28,5 +26,3 @@
#define DYE_CMO "cmo"
#define DYE_REDCOAT "redcoat"
#define DYE_CLOWN "clown"
#define DYE_CHAP "chap"
#define DYE_CENTCOM "centcom"
-2
View File
@@ -41,13 +41,11 @@
#define MC_HDD "HDD"
#define MC_SDD "SDD"
#define MC_CARD "CARD"
#define MC_CARD2 "CARD2"
#define MC_NET "NET"
#define MC_PRINT "PRINT"
#define MC_CELL "CELL"
#define MC_CHARGE "CHARGE"
#define MC_AI "AI"
#define MC_SENSORS "SENSORS"
//NTNet stuff, for modular computers
// NTNet module-configuration values. Do not change these. If you need to add another use larger number (5..6..7 etc)
+3 -4
View File
@@ -116,7 +116,6 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
#define CRAYON_FONT "Comic Sans MS"
#define PRINTER_FONT "Times New Roman"
#define SIGNFONT "Times New Roman"
#define CHARCOAL_FONT "Candara"
#define RESIZE_DEFAULT_SIZE 1
@@ -319,9 +318,9 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define SHELTER_DEPLOY_ANCHORED_OBJECTS "anchored objects"
//debug printing macros
#define debug_world(msg) if (GLOB.Debug2) to_chat(world, "<span class=\"filter_debuglog\">DEBUG: [msg]</span>")
#define debug_usr(msg) if (GLOB.Debug2&&usr) to_chat(usr, "<span class=\"filter_debuglog\">DEBUG: [msg]</span>")
#define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.admins, "<span class=\"filter_debuglog\">DEBUG: [msg]</span>")
#define debug_world(msg) if (GLOB.Debug2) to_chat(world, "DEBUG: [msg]")
#define debug_usr(msg) if (GLOB.Debug2&&usr) to_chat(usr, "DEBUG: [msg]")
#define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.admins, "DEBUG: [msg]")
#define debug_world_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]")
#define INCREMENT_TALLY(L, stat) if(L[stat]){L[stat]++}else{L[stat] = 1}
+2 -1
View File
@@ -64,6 +64,7 @@
#define DEFAULT_BODYPART_ICON 'icons/mob/human_parts.dmi'
#define DEFAULT_BODYPART_ICON_ORGANIC 'icons/mob/human_parts_greyscale.dmi'
#define DEFAULT_BODYPART_ICON_ROBOTIC 'icons/mob/augmentation/augments.dmi'
#define DEFAULT_BODYPART_ICON_CITADEL 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
#define MONKEY_BODYPART "monkey"
#define ALIEN_BODYPART "alien"
@@ -332,4 +333,4 @@
/// If you examine the same atom twice in this timeframe, we call examine_more() instead of examine()
#define EXAMINE_MORE_TIME 1 SECONDS
#define SILENCE_RANGED_MESSAGE (1<<0)
#define SILENCE_RANGED_MESSAGE (1<<0)
-7
View File
@@ -1,7 +0,0 @@
#define ROCKPAPERSCISSORS_RANGE 3
#define ROCKPAPERSCISSORS_TIME_LIMIT 20 SECONDS
#define ROCKPAPERSCISSORS_LOSE "lose"
#define ROCKPAPERSCISSORS_WIN "win"
#define ROCKPAPERSCISSORS_TIE "tie"
#define ROCKPAPERSCISSORS_NOT_DECIDED "not_decided"
-2
View File
@@ -30,8 +30,6 @@
#define STATUS_EFFECT_FLESHMEND /datum/status_effect/fleshmend //Very fast healing; suppressed by fire, and heals less fire damage
#define STATUS_EFFECT_PANACEA /datum/status_effect/panacea //Anatomic panacea that directly heals, rather than injecting a small chemical cocktail
#define STATUS_EFFECT_EXERCISED /datum/status_effect/exercised //Prevents heart disease
#define STATUS_EFFECT_HIPPOCRATIC_OATH /datum/status_effect/hippocraticOath //Gives you an aura of healing as well as regrowing the Rod of Asclepius if lost
-3
View File
@@ -24,10 +24,7 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list(
// Let's keep all of this in one place. given what we put above anyways..
// volume amount for items
/// volume for a data disk
#define ITEM_VOLUME_DISK 1
/// volume for a shotgun stripper clip holding 4 shells
#define ITEM_VOLUME_STRIPPER_CLIP (DEFAULT_VOLUME_NORMAL * 0.5)
// #define SAMPLE_VOLUME_AMOUNT 2
+1
View File
@@ -93,6 +93,7 @@
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
#define FIRE_PRIORITY_VORE 5
#define FIRE_PRIORITY_PING 10
#define FIRE_PRIORITY_IDLE_NPC 10
#define FIRE_PRIORITY_SERVER_MAINT 10
#define FIRE_PRIORITY_RESEARCH 10
-7
View File
@@ -26,10 +26,3 @@
#define TGUI_WINDOW_ID(index) "tgui-window-[index]"
/// Get a pool index of the provided window id
#define TGUI_WINDOW_INDEX(window_id) text2num(copytext(window_id, 13))
/// Creates a message packet for sending via output()
#define TGUI_CREATE_MESSAGE(type, payload) ( \
url_encode(json_encode(list( \
"type" = type, \
"payload" = payload, \
))))
+1 -1
View File
@@ -17,7 +17,7 @@
var/matrix/mtrx=new()
return mtrx.Scale(0.65)
/proc/get_racelist(mob/user)//This proc returns a list of species that 'user' has available to them. It searches the list of ckeys attached to the 'whitelist' var for a species and also checks if they're an admin.
proc/get_racelist(var/mob/user)//This proc returns a list of species that 'user' has available to them. It searches the list of ckeys attached to the 'whitelist' var for a species and also checks if they're an admin.
for(var/spath in subtypesof(/datum/species))
var/datum/species/S = new spath()
var/list/wlist = S.whitelist
-8
View File
@@ -681,11 +681,3 @@
continue
if(istype(D, path))
return TRUE
/proc/safe_json_encode(list/L, default = "")
. = default
return json_encode(L)
/proc/safe_json_decode(string, default = list())
. = default
return json_decode(string)
+12 -23
View File
@@ -1103,26 +1103,15 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
alpha += 25
obj_flags &= ~FROZEN
/// Save file used in icon2base64. Used for converting icons to base64.
GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of icons for the browser output
/// Generate a filename for this asset
/// The same asset will always lead to the same asset name
/// (Generated names do not include file extention.)
/proc/generate_asset_name(file)
return "asset.[md5(fcopy_rsc(file))]"
/**
* Converts an icon to base64. Operates by putting the icon in the iconCache savefile,
* exporting it as text, and then parsing the base64 from that.
* (This relies on byond automatically storing icons in savefiles as base64)
*/
/proc/icon2base64(icon/icon)
//Converts an icon to base64. Operates by putting the icon in the iconCache savefile,
// exporting it as text, and then parsing the base64 from that.
// (This relies on byond automatically storing icons in savefiles as base64)
/proc/icon2base64(icon/icon, iconKey = "misc")
if (!isicon(icon))
return FALSE
WRITE_FILE(GLOB.dummySave["dummy"], icon)
var/iconData = GLOB.dummySave.ExportText("dummy")
WRITE_FILE(GLOB.iconCache[iconKey], icon)
var/iconData = GLOB.iconCache.ExportText(iconKey)
var/list/partial = splittext(iconData, "{")
return replacetext(copytext_char(partial[2], 3, -5), "\n", "")
@@ -1148,10 +1137,10 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
if (isfile(thing)) //special snowflake
var/name = sanitize_filename("[generate_asset_name(thing)].png")
if(!SSassets.cache[name])
SSassets.transport.register_asset(name, thing)
register_asset(name, thing)
for (var/thing2 in targets)
SSassets.transport.send_assets(thing2, name)
return "<img class='icon icon-misc' src='[SSassets.transport.get_asset_url(name)]'>"
send_asset(thing2, key)
return "<img class='icon icon-misc' src=\"[url_encode(name)]\">"
var/atom/A = thing
if (isnull(dir))
dir = A.dir
@@ -1173,11 +1162,11 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
key = "[generate_asset_name(I)].png"
if(!SSassets.cache[key])
SSassets.transport.register_asset(key, I)
register_asset(key, I)
for (var/thing2 in targets)
SSassets.transport.send_assets(thing2, key)
send_asset(thing2, key)
return "<img class='icon icon-[icon_state]' src='[SSassets.transport.get_asset_url(key)]'>"
return "<img class='icon icon-[icon_state]' src=\"[url_encode(key)]\">"
/proc/icon2base64html(thing)
if (!thing)
+5 -5
View File
@@ -358,7 +358,7 @@
roundend_report.stylesheets = list()
roundend_report.add_stylesheet("roundend", 'html/browser/roundend.css')
roundend_report.add_stylesheet("font-awesome", 'html/font-awesome/css/all.min.css')
roundend_report.open(FALSE)
roundend_report.open(0)
/datum/controller/subsystem/ticker/proc/personal_report(client/C, popcount)
var/list/parts = list()
@@ -402,7 +402,7 @@
for (var/i in GLOB.ai_list)
var/mob/living/silicon/ai/aiPlayer = i
if(aiPlayer.mind)
parts += "<b>[aiPlayer.name]</b>[aiPlayer.mind.hide_ckey ? "" : " (Played by: <b>[aiPlayer.mind.key]</b>)"]'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was <span class='redtext'>deactivated</span>"] were:"
parts += "<b>[aiPlayer.name]</b> (Played by: <b>[aiPlayer.mind.key]</b>)'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was <span class='redtext'>deactivated</span>"] were:"
parts += aiPlayer.laws.get_law_list(include_zeroth=TRUE)
parts += "<b>Total law changes: [aiPlayer.law_change_counter]</b>"
@@ -413,14 +413,14 @@
for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
borg_num--
if(robo.mind)
robolist += "<b>[robo.name]</b>[robo.mind.hide_ckey ? "" : " (Played by: <b>[robo.mind.key]</b>)"] [robo.stat == DEAD ? " <span class='redtext'>(Deactivated)</span>" : ""][borg_num ?", ":""]<br>"
robolist += "<b>[robo.name]</b> (Played by: <b>[robo.mind.key]</b>)[robo.stat == DEAD ? " <span class='redtext'>(Deactivated)</span>" : ""][borg_num ?", ":""]<br>"
parts += "[robolist]"
if(!borg_spacer)
borg_spacer = TRUE
for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
if (!robo.connected_ai && robo.mind)
parts += "[borg_spacer?"<br>":""]<b>[robo.name]</b>[robo.mind.hide_ckey ? "" : " (Played by: <b>[robo.mind.key]</b>)"] [(robo.stat != DEAD)? "<span class='greentext'>survived</span> as an AI-less borg!" : "was <span class='redtext'>unable to survive</span> the rigors of being a cyborg without an AI."] Its laws were:"
parts += "[borg_spacer?"<br>":""]<b>[robo.name]</b> (Played by: <b>[robo.mind.key]</b>) [(robo.stat != DEAD)? "<span class='greentext'>survived</span> as an AI-less borg!" : "was <span class='redtext'>unable to survive</span> the rigors of being a cyborg without an AI."] Its laws were:"
if(robo) //How the hell do we lose robo between here and the world messages directly above this?
parts += robo.laws.get_law_list(include_zeroth=TRUE)
@@ -529,7 +529,7 @@
var/jobtext = ""
if(ply.assigned_role)
jobtext = " the <b>[ply.assigned_role]</b>"
var/text = "<b>[ply.hide_ckey ? "<b>[ply.name]</b>[jobtext] " : "[ply.key]</b> was <b>[ply.name]</b>[jobtext] and "]"
var/text = "<b>[ply.key]</b> was <b>[ply.name]</b>[jobtext] and"
if(ply.current)
if(ply.current.stat == DEAD)
text += " <span class='redtext'>died</span>"
+10 -14
View File
@@ -462,14 +462,16 @@
else
. = max(0, min(255, 138.5177312231 * log(temp - 10) - 305.0447927307))
/proc/instability2text(instability) //used when displaying fusion power on analyzers
switch(instability)
if(0 to 2)
return "stable, meaning that its heat will always increase."
if(2 to 3)
return "metastable, meaning that its heat will trend upwards."
if (3 to INFINITY)
return "unstable, meaning that its heat will trend downwards."
/proc/fusionpower2text(power) //used when displaying fusion power on analyzers
switch(power)
if(0 to 5)
return "low"
if(5 to 20)
return "mid"
if(20 to 50)
return "high"
if(50 to INFINITY)
return "super"
/proc/color2hex(color) //web colors
if(!color)
@@ -618,12 +620,6 @@
else //regex everything else (works for /proc too)
return lowertext(replacetext("[the_type]", "[type2parent(the_type)]/", ""))
/// Return html to load a url.
/// for use inside of browse() calls to html assets that might be loaded on a cdn.
/proc/url2htmlloader(url)
return {"<html><head><meta http-equiv="refresh" content="0;URL='[url]'"/></head><body onLoad="parent.location='[url]'"></body></html>"}
/proc/strtohex(str)
if(!istext(str)||!str)
return
-5
View File
@@ -278,8 +278,3 @@ GLOBAL_LIST_INIT(all_mutant_parts, list("tail_lizard" = "Tail", "mam_tail" = "Ta
GLOBAL_LIST_INIT(unlocked_mutant_parts, list("horns", "insect_fluff"))
//parts in either of the above two lists that require a second option that allows them to be coloured
GLOBAL_LIST_INIT(colored_mutant_parts, list("insect_wings" = "wings_color", "deco_wings" = "wings_color", "horns" = "horns_color"))
//species ids that have greyscale sprites
GLOBAL_LIST_INIT(greyscale_limb_types, list("human","moth","lizard","pod","plant","jelly","slime","golem","lum","stargazer","mush","ethereal","snail","c_golem","b_golem","mammal","xeno","ipc","insect","synthliz","avian","aquatic"))
//species ids that need snowflake coloring applied
@@ -107,8 +107,13 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
/obj/item/toy/eightball = 1,
/obj/item/reagent_containers/pill/floorpill = 1,
/obj/item/reagent_containers/food/snacks/cannedpeaches/maint = 2,
/obj/item/storage/daki = 3, //VERY IMPORTANT CIT CHANGE - adds bodypillows to maint
/obj/item/storage/pill_bottle/penis_enlargement = 2,
/obj/item/storage/pill_bottle/breast_enlargement = 2,
/obj/item/clothing/shoes/wheelys = 1,
/obj/item/clothing/shoes/kindleKicks = 1,
/obj/item/autosurgeon/penis = 1,
/obj/item/autosurgeon/testicles = 1,
/obj/item/storage/box/marshmallow = 2,
/obj/item/clothing/gloves/tackler/offbrand = 1,
/obj/item/stack/sticky_tape = 1,
-4
View File
@@ -13,7 +13,6 @@ GLOBAL_LIST_EMPTY(deliverybeacontags) //list of all tags associated with d
GLOBAL_LIST_EMPTY(nuke_list)
GLOBAL_LIST_EMPTY(alarmdisplay) //list of all machines or programs that can display station alerts
GLOBAL_LIST_EMPTY(singularities) //list of all singularities on the station (actually technically all engines)
GLOBAL_LIST_EMPTY(grounding_rods) //list of all grounding rods on the station
GLOBAL_LIST(chemical_reactions_list) //list of all /datum/chemical_reaction datums. Used during chemical reactions
GLOBAL_LIST(chemical_reagents_list) //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
@@ -42,6 +41,3 @@ GLOBAL_LIST_EMPTY(ai_status_displays)
GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects
GLOBAL_LIST_EMPTY(alert_consoles) // Station alert consoles, /obj/machinery/computer/station_alert
//list of everyone playing rock paper scissors
GLOBAL_LIST_EMPTY(rockpaperscissors_players)
+1 -1
View File
@@ -32,4 +32,4 @@
/mob/camera/blob/AltClickOn(atom/A) //Remove a blob
var/turf/T = get_turf(A)
if(T)
remove_blob(T)
remove_blob(T)
+44 -92
View File
@@ -14,15 +14,13 @@
var/list/modes // allowed modes
var/list/gamemode_cache
var/list/votable_modes // votable modes
// var/list/ic_filter_regex
var/list/storyteller_cache
var/list/mode_names
var/list/mode_reports
var/list/mode_false_report_weight
var/motd
// var/policy
// var/static/regex/ic_filter_regex
/datum/controller/configuration/proc/admin_reload()
if(IsAdminAdvancedProcCall())
@@ -52,11 +50,6 @@
break
loadmaplist(CONFIG_MAPS_FILE)
LoadMOTD()
// LoadPolicy()
// LoadChatFilter()
if (Master)
Master.OnConfigLoad()
/datum/controller/configuration/proc/full_wipe()
if(IsAdminAdvancedProcCall())
@@ -142,7 +135,7 @@
if(entry == "$include")
if(!value)
log_config("LINE [linenumber]: Warning: Invalid $include directive: [value]")
log_config("LINE [linenumber]: Invalid $include directive: [value]")
else
LoadEntries(value, stack)
++.
@@ -150,7 +143,7 @@
var/datum/config_entry/E = _entries[entry]
if(!E)
log_config("LINE [linenumber]: Unknown setting in configuration: '[entry]'")
log_config("LINE [linenumber]: Unknown setting: '[entry]'")
continue
if(lockthis)
@@ -160,9 +153,9 @@
var/datum/config_entry/new_ver = entries_by_type[E.deprecated_by]
var/new_value = E.DeprecationUpdate(value)
var/good_update = istext(new_value)
log_config("LINE [linenumber]: Entry [entry] is deprecated and will be removed soon. Migrate to [new_ver.name]![good_update ? " Suggested new value is: [new_value]" : ""]")
log_config("LINE [linenumber]: [entry] is deprecated and will be removed soon. Migrate to [new_ver.name]![good_update ? " Suggested new value is: [new_value]" : ""]")
if(!warned_deprecated_configs)
DelayedMessageAdmins("This server is using deprecated configuration settings. Please check the logs and update accordingly.")
addtimer(CALLBACK(GLOBAL_PROC, /proc/message_admins, "This server is using deprecated configuration settings. Please check the logs and update accordingly."), 0)
warned_deprecated_configs = TRUE
if(good_update)
value = new_value
@@ -170,7 +163,7 @@
else
warning("[new_ver.type] is deprecated but gave no proper return for DeprecationUpdate()")
var/validated = E.ValidateAndSet(value)
var/validated = E.ValidateAndSet(value, TRUE)
if(!validated)
log_config("LINE [linenumber]: Failed to validate setting \"[value]\" for [entry]")
else
@@ -202,7 +195,13 @@
statclick = new/obj/effect/statclick/debug(null, "Edit", src)
stat("[name]:", statclick)
/// Your typical GET but returns a config.
/datum/controller/configuration/proc/Get(entry_type)
var/datum/config_entry/E = GetEntryDatum(entry_type)
if((E.protection & CONFIG_ENTRY_HIDDEN) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "[REF(src)]")
log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]")
return
return E.config_entry_value
/datum/controller/configuration/proc/GetEntryDatum(entry_type)
var/datum/config_entry/E = entry_type
var/entry_is_abstract = initial(E.abstract_type) == entry_type
@@ -211,24 +210,8 @@
E = entries_by_type[entry_type]
if(!E)
CRASH("Missing config entry for [entry_type]!")
if((E.protection & CONFIG_ENTRY_HIDDEN) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "[REF(src)]")
log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]")
return
return E
/datum/controller/configuration/proc/Get(entry_type)
var/datum/config_entry/E = entry_type
var/entry_is_abstract = initial(E.abstract_type) == entry_type
if(entry_is_abstract)
CRASH("Tried to retrieve an abstract config_entry: [entry_type]")
E = entries_by_type[entry_type]
if(!E)
CRASH("Missing config entry for [entry_type]!")
if((E.protection & CONFIG_ENTRY_HIDDEN) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "[REF(src)]")
log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]")
return
return E.config_entry_value
/datum/controller/configuration/proc/Set(entry_type, new_val)
var/datum/config_entry/E = entry_type
var/entry_is_abstract = initial(E.abstract_type) == entry_type
@@ -253,6 +236,7 @@
for(var/T in gamemode_cache)
// I wish I didn't have to instance the game modes in order to look up
// their information, but it is the only way (at least that I know of).
// for future reference: just use initial() lol
var/datum/game_mode/M = new T()
if(M.config_tag)
@@ -274,37 +258,7 @@
var/tm_info = GLOB.revdata.GetTestMergeInfo()
if(motd || tm_info)
motd = motd ? "[motd]<br>[tm_info]" : tm_info
/*
Policy file should be a json file with a single object.
Value is raw html.
Possible keywords :
Job titles / Assigned roles (ghost spawners for example) : Assistant , Captain , Ash Walker
Mob types : /mob/living/simple_animal/hostile/carp
Antagonist types : /datum/antagonist/highlander
Species types : /datum/species/lizard
special keywords defined in _DEFINES/admin.dm
Example config:
{
"Assistant" : "Don't kill everyone",
"/datum/antagonist/highlander" : "<b>Kill everyone</b>",
"Ash Walker" : "Kill all spacemans"
}
*/
/*
/datum/controller/configuration/proc/LoadPolicy()
policy = list()
var/rawpolicy = file2text("[directory]/policy.json")
if(rawpolicy)
var/parsed = safe_json_decode(rawpolicy)
if(!parsed)
log_config("JSON parsing failure for policy.json")
DelayedMessageAdmins("JSON parsing failure for policy.json")
else
policy = parsed
*/
/datum/controller/configuration/proc/loadmaplist(filename)
log_config("Loading config file [filename]...")
filename = "[directory]/[filename]"
@@ -351,8 +305,6 @@ Example config:
currentmap.voteweight = text2num(data)
if ("default","defaultmap")
defaultmap = currentmap
//if ("votable")
// currentmap.votable = TRUE
if ("endmap")
LAZYINITLIST(maplist)
maplist[currentmap.map_name] = currentmap
@@ -374,7 +326,6 @@ Example config:
return new T
return new /datum/game_mode/extended()
/// For dynamic.
/datum/controller/configuration/proc/pick_storyteller(storyteller_name)
for(var/T in storyteller_cache)
var/datum/dynamic_storyteller/S = T
@@ -383,32 +334,6 @@ Example config:
return T
return /datum/dynamic_storyteller/classic
/// Same with this
/datum/controller/configuration/proc/get_runnable_storytellers()
var/list/datum/dynamic_storyteller/runnable_storytellers = new
var/list/probabilities = Get(/datum/config_entry/keyed_list/storyteller_weight)
var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust)
var/list/min_player_counts = Get(/datum/config_entry/keyed_list/storyteller_min_players)
for(var/T in storyteller_cache)
var/datum/dynamic_storyteller/S = T
var/config_tag = initial(S.config_tag)
var/probability = (config_tag in probabilities) ? probabilities[config_tag] : initial(S.weight)
var/min_players = (config_tag in min_player_counts) ? min_player_counts[config_tag] : initial(S.min_players)
if(probability <= 0)
continue
if(length(GLOB.player_list) < min_players)
continue
if(SSpersistence.saved_storytellers.len == repeated_mode_adjust.len)
var/name = initial(S.name)
var/recent_round = min(SSpersistence.saved_storytellers.Find(name),3)
var/adjustment = 0
while(recent_round)
adjustment += repeated_mode_adjust[recent_round]
recent_round = SSpersistence.saved_modes.Find(name,recent_round+1,0)
probability *= ((100-adjustment)/100)
runnable_storytellers[S] = probability
return runnable_storytellers
/datum/controller/configuration/proc/get_runnable_modes()
var/list/datum/game_mode/runnable_modes = new
var/list/probabilities = Get(/datum/config_entry/keyed_list/probability)
@@ -442,6 +367,32 @@ Example config:
runnable_modes[M] = final_weight
return runnable_modes
/datum/controller/configuration/proc/get_runnable_storytellers()
var/list/datum/dynamic_storyteller/runnable_storytellers = new
var/list/probabilities = Get(/datum/config_entry/keyed_list/storyteller_weight)
var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust)
var/list/min_player_counts = Get(/datum/config_entry/keyed_list/storyteller_min_players)
for(var/T in storyteller_cache)
var/datum/dynamic_storyteller/S = T
var/config_tag = initial(S.config_tag)
var/probability = (config_tag in probabilities) ? probabilities[config_tag] : initial(S.weight)
var/min_players = (config_tag in min_player_counts) ? min_player_counts[config_tag] : initial(S.min_players)
if(probability <= 0)
continue
if(length(GLOB.player_list) < min_players)
continue
if(SSpersistence.saved_storytellers.len == repeated_mode_adjust.len)
var/name = initial(S.name)
var/recent_round = min(SSpersistence.saved_storytellers.Find(name),3)
var/adjustment = 0
while(recent_round)
adjustment += repeated_mode_adjust[recent_round]
recent_round = SSpersistence.saved_modes.Find(name,recent_round+1,0)
probability *= ((100-adjustment)/100)
runnable_storytellers[S] = probability
return runnable_storytellers
/datum/controller/configuration/proc/get_runnable_midround_modes(crew)
var/list/datum/game_mode/runnable_modes = new
var/list/probabilities = Get(/datum/config_entry/keyed_list/probability)
@@ -467,6 +418,7 @@ Example config:
/*
/datum/controller/configuration/proc/LoadChatFilter()
var/list/in_character_filter = list()
if(!fexists("[directory]/in_character_filter.txt"))
return
log_config("Loading config file in_character_filter.txt...")
@@ -476,8 +428,8 @@ Example config:
if(findtextEx(line,"#",1,2))
continue
in_character_filter += REGEX_QUOTE(line)
ic_filter_regex = in_character_filter.len ? regex("\\b([jointext(in_character_filter, "|")])\\b", "i") : null
syncChatRegexes()
*/
//Message admins when you can.
/datum/controller/configuration/proc/DelayedMessageAdmins(text)
addtimer(CALLBACK(GLOBAL_PROC, /proc/message_admins, text), 0)
@@ -368,10 +368,6 @@
/datum/config_entry/flag/allow_map_voting
/datum/config_entry/number/client_warn_version
config_entry_value = null
min_val = 500
/datum/config_entry/number/client_warn_version
config_entry_value = null
min_val = 500
@@ -388,10 +384,6 @@
/datum/config_entry/string/client_error_message
config_entry_value = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
/datum/config_entry/number/client_error_build
config_entry_value = null
min_val = 0
/datum/config_entry/number/minute_topic_limit
config_entry_value = null
min_val = 0
@@ -1,30 +0,0 @@
/datum/config_entry/keyed_list/external_rsc_urls
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_FLAG
/datum/config_entry/flag/asset_simple_preload
/datum/config_entry/string/asset_transport
/datum/config_entry/string/asset_transport/ValidateAndSet(str_val)
return (lowertext(str_val) in list("simple", "webroot")) && ..(lowertext(str_val))
/datum/config_entry/string/asset_cdn_webroot
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/asset_cdn_webroot/ValidateAndSet(str_var)
if (!str_var || trim(str_var) == "")
return FALSE
if (str_var && str_var[length(str_var)] != "/")
str_var += "/"
return ..(str_var)
/datum/config_entry/string/asset_cdn_url
protection = CONFIG_ENTRY_LOCKED
default = null
/datum/config_entry/string/asset_cdn_url/ValidateAndSet(str_var)
if (!str_var || trim(str_var) == "")
return FALSE
if (str_var && str_var[length(str_var)] != "/")
str_var += "/"
return ..(str_var)
+1 -1
View File
@@ -16,4 +16,4 @@
/datum/controller/proc/Recover()
/datum/controller/proc/stat_entry()
/datum/controller/proc/stat_entry()
+4 -13
View File
@@ -76,11 +76,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
if(!random_seed)
#ifdef UNIT_TESTS
random_seed = 29051994
#else
random_seed = rand(1, 1e9)
#endif
random_seed = (TEST_RUN_PARAMETER in world.params) ? 29051994 : rand(1, 1e9)
rand_seed(random_seed)
var/list/_subsystems = list()
@@ -188,6 +184,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
if(delay)
sleep(delay)
if(tgs_prime)
world.TgsInitializationComplete()
if(init_sss)
init_subtypes(/datum/controller/subsystem, subsystems)
@@ -220,9 +219,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
world.fps = CONFIG_GET(number/fps)
var/initialized_tod = REALTIMEOFDAY
if(tgs_prime)
world.TgsInitializationComplete()
if(sleep_offline_after_initializations)
world.sleep_offline = TRUE
sleep(1)
@@ -647,8 +643,3 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
processing = CONFIG_GET(number/mc_tick_rate/base_mc_tick_rate)
else if (client_count > CONFIG_GET(number/mc_tick_rate/high_pop_mc_mode_amount))
processing = CONFIG_GET(number/mc_tick_rate/high_pop_mc_tick_rate)
/datum/controller/master/proc/OnConfigLoad()
for (var/thing in subsystems)
var/datum/controller/subsystem/SS = thing
SS.OnConfigLoad()
+25 -81
View File
@@ -1,91 +1,39 @@
/**
* # Subsystem base class
*
* Defines a subsystem to be managed by the [Master Controller][/datum/controller/master]
*
* Simply define a child of this subsystem, using the [SUBSYSTEM_DEF] macro, and the MC will handle registration.
* Changing the name is required
**/
/datum/controller/subsystem
// Metadata; you should define these.
name = "fire coderbus" //name of the subsystem
var/init_order = INIT_ORDER_DEFAULT //order of initialization. Higher numbers are initialized first, lower numbers later. Use defines in __DEFINES/subsystems.dm for easy understanding of order.
var/wait = 20 //time to wait (in deciseconds) between each call to fire(). Must be a positive integer.
var/priority = FIRE_PRIORITY_DEFAULT //When mutiple subsystems need to run in the same tick, higher priority subsystems will run first and be given a higher share of the tick before MC_TICK_CHECK triggers a sleep
/// Name of the subsystem - you must change this
name = "fire coderbus"
var/flags = 0 //see MC.dm in __DEFINES Most flags must be set on world start to take full effect. (You can also restart the mc to force them to process again)
/// Order of initialization. Higher numbers are initialized first, lower numbers later. Use or create defines such as [INIT_ORDER_DEFAULT] so we can see the order in one file.
var/init_order = INIT_ORDER_DEFAULT
var/initialized = FALSE //set to TRUE after it has been initialized, will obviously never be set if the subsystem doesn't initialize
/// Time to wait (in deciseconds) between each call to fire(). Must be a positive integer.
var/wait = 20
/// Priority Weight: When mutiple subsystems need to run in the same tick, higher priority subsystems will be given a higher share of the tick before MC_TICK_CHECK triggers a sleep, higher priority subsystems also run before lower priority subsystems
var/priority = FIRE_PRIORITY_DEFAULT
/// [Subsystem Flags][SS_NO_INIT] to control binary behavior. Flags must be set at compile time or before preinit finishes to take full effect. (You can also restart the mc to force them to process again)
var/flags = 0
/// This var is set to TRUE after the subsystem has been initialized.
var/initialized = FALSE
/// Set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later
/// use the [SS_NO_FIRE] flag instead for systems that never fire to keep it from even being added to list that is checked every tick
//set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later
// use the SS_NO_FIRE flag instead for systems that never fire to keep it from even being added to the list
var/can_fire = TRUE
///Bitmap of what game states can this subsystem fire at. See [RUNLEVELS_DEFAULT] for more details.
var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire
/*
* The following variables are managed by the MC and should not be modified directly.
*/
/// Last world.time the subsystem completed a run (as in wasn't paused by [MC_TICK_CHECK])
var/last_fire = 0
/// Scheduled world.time for next fire()
var/next_fire = 0
/// Running average of the amount of milliseconds it takes the subsystem to complete a run (including all resumes but not the time spent paused)
var/cost = 0
/// Running average of the amount of tick usage in percents of a tick it takes the subsystem to complete a run
var/tick_usage = 0
/// Running average of the amount of tick usage (in percents of a game tick) the subsystem has spent past its allocated time without pausing
var/tick_overrun = 0
/// Tracks the current execution state of the subsystem. Used to handle subsystems that sleep in fire so the mc doesn't run them again while they are sleeping
var/state = SS_IDLE
/// Tracks how many fires the subsystem has consecutively paused on in the current run
var/paused_ticks = 0
/// Tracks how much of a tick the subsystem has consumed in the current run
var/paused_tick_usage
/// Tracks how many fires the subsystem takes to complete a run on average.
var/ticks = 1
/// Tracks the amount of completed runs for the subsystem
var/times_fired = 0
/// Time the subsystem entered the queue, (for timing and priority reasons)
var/queued_time = 0
/// Priority at the time the subsystem entered the queue. Needed to avoid changes in priority (by admins and the like) from breaking things.
var/queued_priority
/// How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out!
var/static/list/failure_strikes
/// Next subsystem in the queue of subsystems to run this tick
// Bookkeeping variables; probably shouldn't mess with these.
var/last_fire = 0 //last world.time we called fire()
var/next_fire = 0 //scheduled world.time for next fire()
var/cost = 0 //average time to execute
var/tick_usage = 0 //average tick usage
var/tick_overrun = 0 //average tick overrun
var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc.
var/paused_ticks = 0 //ticks this ss is taking to run right now.
var/paused_tick_usage //total tick_usage of all of our runs while pausing this run
var/ticks = 1 //how many ticks does this ss take to run on avg.
var/times_fired = 0 //number of times we have called fire()
var/queued_time = 0 //time we entered the queue, (for timing and priority reasons)
var/queued_priority //we keep a running total to make the math easier, if priority changes mid-fire that would break our running total, so we store it here
//linked list stuff for the queue
var/datum/controller/subsystem/queue_next
/// Previous subsystem in the queue of subsystems to run this tick
var/datum/controller/subsystem/queue_prev
//Do not blindly add vars here to the bottom, put it where it goes above
//If your var only has two values, put it in as a flag.
var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire
var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out!
//Do not override
///datum/controller/subsystem/New()
@@ -98,7 +46,6 @@
//This is used so the mc knows when the subsystem sleeps. do not override.
/datum/controller/subsystem/proc/ignite(resumed = 0)
SHOULD_NOT_OVERRIDE(TRUE)
set waitfor = 0
. = SS_SLEEPING
fire(resumed)
@@ -140,7 +87,7 @@
queue_node_flags = queue_node.flags
if (queue_node_flags & SS_TICKER)
if ((SS_flags & (SS_TICKER|SS_BACKGROUND)) != SS_TICKER)
if (!(SS_flags & SS_TICKER))
continue
if (queue_node_priority < SS_priority)
break
@@ -208,9 +155,6 @@
if(SS_SLEEPING)
state = SS_PAUSING
/// Called after the config has been loaded or reloaded.
/datum/controller/subsystem/proc/OnConfigLoad()
/datum/controller/subsystem/proc/subsystem_log(msg)
return log_subsystem(name, msg)
+3 -18
View File
@@ -4,23 +4,6 @@ SUBSYSTEM_DEF(assets)
flags = SS_NO_FIRE
var/list/cache = list()
var/list/preload = list()
var/datum/asset_transport/transport = new()
/datum/controller/subsystem/assets/OnConfigLoad()
var/newtransporttype = /datum/asset_transport
switch (CONFIG_GET(string/asset_transport))
if ("webroot")
newtransporttype = /datum/asset_transport/webroot
if (newtransporttype == transport.type)
return
var/datum/asset_transport/newtransport = new newtransporttype ()
if (newtransport.validate_config())
transport = newtransport
transport.Load()
/datum/controller/subsystem/assets/Initialize(timeofday)
for(var/type in typesof(/datum/asset))
@@ -28,6 +11,8 @@ SUBSYSTEM_DEF(assets)
if (type != initial(A._abstract))
get_asset_datum(type)
transport.Initialize(cache)
preload = cache.Copy() //don't preload assets generated during the round
for(var/client/C in GLOB.clients)
addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, preload, FALSE), 10)
..()
+82 -26
View File
@@ -5,35 +5,91 @@ SUBSYSTEM_DEF(chat)
priority = FIRE_PRIORITY_CHAT
init_order = INIT_ORDER_CHAT
var/list/payload_by_client = list()
var/list/payload = list()
/datum/controller/subsystem/chat/fire()
for(var/key in payload_by_client)
var/client/client = key
var/payload = payload_by_client[key]
payload_by_client -= key
if(client)
// Send to tgchat
client.tgui_panel?.window.send_message("chat/message", payload)
// Send to old chat
for(var/msg in payload)
SEND_TEXT(client, msg["text"])
for(var/i in payload)
var/client/C = i
C << output(payload[C], "browseroutput:output")
payload -= C
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/chat/proc/queue(target, text, flags)
if(islist(target))
for(var/_target in target)
var/client/client = CLIENT_FROM_VAR(_target)
if(client)
LAZYADD(payload_by_client[client], list(list(
"text" = text,
"flags" = flags,
)))
/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE, trailing_newline = TRUE, confidential = TRUE)
if(!target || !message)
return
var/client/client = CLIENT_FROM_VAR(target)
if(client)
LAZYADD(payload_by_client[client], list(list(
"text" = text,
"flags" = flags,
)))
if(!istext(message))
stack_trace("to_chat called with invalid input type")
return
if(target == world)
target = GLOB.clients
//Some macros remain in the string even after parsing and fuck up the eventual output
var/original_message = message
//url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
//Do the double-encoding here to save nanoseconds
var/twiceEncoded
if(islist(target))
var/sanitized_message = FALSE
for(var/I in target)
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
if(!C)
continue
//Send it to the old style output window.
SEND_TEXT(C, original_message)
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
continue
if(!sanitized_message)
message = replacetext(message, "\improper", "")
message = replacetext(message, "\proper", "")
if(handle_whitespace)
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
if (trailing_newline)
message += "<br>"
twiceEncoded = url_encode(url_encode(message))
sanitized_message = TRUE
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
C.chatOutput.messageQueue += message
continue
payload[C] += twiceEncoded
else
var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
if(!C)
return
//Send it to the old style output window.
SEND_TEXT(C, original_message)
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
return
message = replacetext(message, "\improper", "")
message = replacetext(message, "\proper", "")
if(handle_whitespace)
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
if (trailing_newline)
message += "<br>"
twiceEncoded = url_encode(url_encode(message))
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
C.chatOutput.messageQueue += message
return
payload[C] += twiceEncoded
+33
View File
@@ -0,0 +1,33 @@
SUBSYSTEM_DEF(ping)
name = "Ping"
priority = FIRE_PRIORITY_PING
wait = 3 SECONDS
flags = SS_NO_INIT
runlevels = RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/currentrun = list()
/datum/controller/subsystem/ping/stat_entry()
..("P:[GLOB.clients.len]")
/datum/controller/subsystem/ping/fire(resumed = 0)
if (!resumed)
src.currentrun = GLOB.clients.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while (currentrun.len)
var/client/C = currentrun[currentrun.len]
currentrun.len--
if (!C || !C.chatOutput || !C.chatOutput.loaded)
if (MC_TICK_CHECK)
return
continue
// softPang isn't handled anywhere but it'll always reset the opts.lastPang.
C.chatOutput.ehjax_send(data = C.is_afk(29) ? "softPang" : "pang")
if (MC_TICK_CHECK)
return
@@ -4,26 +4,16 @@ PROCESSING_SUBSYSTEM_DEF(instruments)
init_order = INIT_ORDER_INSTRUMENTS
flags = SS_KEEP_TIMING
priority = FIRE_PRIORITY_INSTRUMENTS
/// List of all instrument data, associative id = datum
var/static/list/datum/instrument/instrument_data = list()
/// List of all song datums.
var/static/list/datum/instrument/instrument_data = list() //id = datum
var/static/list/datum/song/songs = list()
/// Max lines in songs
var/static/musician_maxlines = 600
/// Max characters per line in songs
var/static/musician_maxlinechars = 300
/// Deciseconds between hearchecks. Too high and instruments seem to lag when people are moving around in terms of who can hear it. Too low and the server lags from this.
var/static/musician_hearcheck_mindelay = 5
/// Maximum instrument channels total instruments are allowed to use. This is so you don't have instruments deadlocking all sound channels.
var/static/max_instrument_channels = MAX_INSTRUMENT_CHANNELS
/// Current number of channels allocated for instruments
var/static/current_instrument_channels = 0
/// Single cached list for synthesizer instrument ids, so you don't have to have a new list with every synthesizer.
var/static/list/synthesizer_instrument_ids
/datum/controller/subsystem/processing/instruments/Initialize()
initialize_instrument_data()
synthesizer_instrument_ids = get_allowed_instrument_ids()
return ..()
/datum/controller/subsystem/processing/instruments/proc/on_song_new(datum/song/S)
@@ -39,10 +29,7 @@ PROCESSING_SUBSYSTEM_DEF(instruments)
continue
I = new path
I.Initialize()
if(!I.id)
qdel(I)
continue
instrument_data[I.id] = I
instrument_data[I.id || "[I.type]"] = I
CHECK_TICK
/datum/controller/subsystem/processing/instruments/proc/get_instrument(id_or_path)
+3 -1
View File
@@ -76,7 +76,9 @@ SUBSYSTEM_DEF(server_maint)
if(!thing)
continue
var/client/C = thing
C?.tgui_panel?.send_roundrestart()
var/datum/chatOutput/co = C.chatOutput
if(co)
co.ehjax_send(data = "roundrestart")
if(server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
C << link("byond://[server]")
var/datum/tgs_version/tgsversion = world.TgsVersion()
-106
View File
@@ -1,106 +0,0 @@
/datum/accent
/datum/accent/proc/modify_speech(list/speech_args, datum/source, mob/living/carbon/owner) //transforms the message in some way
return speech_args
/datum/accent/lizard/modify_speech(list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
var/static/regex/lizard_hiss = new("s+", "g")
var/static/regex/lizard_hiSS = new("S+", "g")
if(message[1] != "*")
message = lizard_hiss.Replace(message, "sss")
message = lizard_hiSS.Replace(message, "SSS")
speech_args[SPEECH_MESSAGE] = message
return speech_args
/datum/accent/fly/modify_speech(list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
var/static/regex/fly_buzz = new("z+", "g")
var/static/regex/fly_buZZ = new("Z+", "g")
if(message[1] != "*")
message = fly_buzz.Replace(message, "zzz")
message = fly_buZZ.Replace(message, "ZZZ")
speech_args[SPEECH_MESSAGE] = message
return speech_args
/datum/accent/abductor/modify_speech(list/speech_args, datum/source)
var/message = speech_args[SPEECH_MESSAGE]
var/mob/living/carbon/human/user = source
var/rendered = "<span class='abductor'><b>[user.name]:</b> [message]</span>"
user.log_talk(message, LOG_SAY, tag="abductor")
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
var/obj/item/organ/tongue/T = H.getorganslot(ORGAN_SLOT_TONGUE)
if(!T || T.type != type)
continue
if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor")
var/datum/antagonist/abductor/A = user.mind.has_antag_datum(/datum/antagonist/abductor)
if(!A || !(H.mind in A.team.members))
continue
to_chat(H, rendered)
for(var/mob/M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, user)
to_chat(M, "[link] [rendered]")
speech_args[SPEECH_MESSAGE] = ""
return speech_args
/datum/accent/zombie/modify_speech(list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
var/list/message_list = splittext(message, " ")
var/maxchanges = max(round(message_list.len / 1.5), 2)
for(var/i = rand(maxchanges / 2, maxchanges), i > 0, i--)
var/insertpos = rand(1, message_list.len - 1)
var/inserttext = message_list[insertpos]
if(!(copytext(inserttext, -3) == "..."))//3 == length("...")
message_list[insertpos] = inserttext + "..."
if(prob(20) && message_list.len > 3)
message_list.Insert(insertpos, "[pick("BRAINS", "Brains", "Braaaiinnnsss", "BRAAAIIINNSSS")]...")
speech_args[SPEECH_MESSAGE] = jointext(message_list, " ")
return speech_args
/datum/accent/alien/modify_speech(list/speech_args, datum/source)
playsound(source, "hiss", 25, 1, 1)
return speech_args
/datum/accent/fluffy/modify_speech(list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
if(message[1] != "*")
message = replacetext(message, "ne", "nye")
message = replacetext(message, "nu", "nyu")
message = replacetext(message, "na", "nya")
message = replacetext(message, "no", "nyo")
message = replacetext(message, "ove", "uv")
message = replacetext(message, "l", "w")
message = replacetext(message, "r", "w")
speech_args[SPEECH_MESSAGE] = lowertext(message)
return speech_args
/datum/accent/bone
var/span_flag
/datum/accent/bone/modify_speech(list/speech_args)
speech_args[SPEECH_SPANS] = span_flag
return speech_args
//bone tongues either have the sans accent or the papyrus accent
/datum/accent/bone/sans
span_flag = SPAN_SANS
/datum/accent/bone/papyrus
span_flag = SPAN_PAPYRUS
/datum/accent/robot/modify_speech(list/speech_args)
speech_args[SPEECH_SPANS] = SPAN_ROBOT
/datum/accent/dullahan/modify_speech(list/speech_args, datum/source, mob/living/carbon/owner)
if(owner)
if(isdullahan(owner))
var/datum/species/dullahan/D = owner.dna.species
if(isobj(D.myhead.loc))
var/obj/O = D.myhead.loc
O.say(speech_args[SPEECH_MESSAGE])
speech_args[SPEECH_MESSAGE] = ""
return speech_args
+20 -17
View File
@@ -8,14 +8,14 @@
var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
var/stylesheets[0]
var/scripts[0]
var/title_image
var/head_elements
var/body_elements
var/head_content = ""
var/content = ""
var/static/datum/asset/simple/namespaced/common/common_asset = get_asset_datum(/datum/asset/simple/namespaced/common)
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null)
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
user = nuser
window_id = nwindow_id
@@ -27,6 +27,7 @@
height = nheight
if (nref)
ref = nref
add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs
/datum/browser/proc/add_head_content(nhead_content)
head_content = nhead_content
@@ -34,21 +35,22 @@
/datum/browser/proc/set_window_options(nwindow_options)
window_options = nwindow_options
/datum/browser/proc/set_title_image(ntitle_image)
//title_image = ntitle_image
/datum/browser/proc/add_stylesheet(name, file)
if(istype(name, /datum/asset/spritesheet))
var/datum/asset/spritesheet/sheet = name
stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
else
var/asset_name = "[name].css"
stylesheets[asset_name] = file
if (!SSassets.cache[asset_name])
SSassets.transport.register_asset(asset_name, file)
if(!SSassets.cache[asset_name])
register_asset(asset_name, file)
/datum/browser/proc/add_script(name, file)
scripts["[ckey(name)].js"] = file
SSassets.transport.register_asset("[ckey(name)].js", file)
register_asset("[ckey(name)].js", file)
/datum/browser/proc/set_content(ncontent)
content = ncontent
@@ -58,13 +60,15 @@
/datum/browser/proc/get_header()
var/file
head_content += "<link rel='stylesheet' type='text/css' href='[common_asset.get_url_mappings()["common.css"]]'>"
for (file in stylesheets)
head_content += "<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url(file)]'>"
head_content += "<link rel='stylesheet' type='text/css' href='[file]'>"
for (file in scripts)
head_content += "<script type='text/javascript' src='[SSassets.transport.get_asset_url(file)]'></script>"
head_content += "<script type='text/javascript' src='[file]'></script>"
var/title_attributes = "class='uiTitle'"
if (title_image)
title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'"
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
@@ -75,7 +79,7 @@
</head>
<body scroll=auto>
<div class='uiWrapper'>
[title ? "<div class='uiTitleWrapper'><div class='uiTitle'><tt>[title]</tt></div></div>" : ""]
[title ? "<div class='uiTitleWrapper'><div [title_attributes]><tt>[title]</tt></div></div>" : ""]
<div class='uiContent'>
"}
//" This is here because else the rest of the file looks like a string in notepad++.
@@ -101,11 +105,10 @@
var/window_size = ""
if(width && height)
window_size = "size=[width]x[height];"
common_asset.send(user)
if(stylesheets.len)
SSassets.transport.send_assets(user, stylesheets)
send_asset_list(user, stylesheets)
if(scripts.len)
SSassets.transport.send_assets(user, scripts)
send_asset_list(user, scripts)
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
if(use_onclose)
setup_onclose()
@@ -166,7 +169,7 @@
return Button3
//Same shit, but it returns the button number, could at some point support unlimited button amounts.
/proc/askuser(mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
/proc/askuser(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
@@ -185,7 +188,7 @@
var/selectedbutton = 0
var/stealfocus
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null, StealFocus = 1, Timeout = 6000)
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, StealFocus = 1, Timeout = 6000)
..()
stealfocus = StealFocus
if (!StealFocus)
-22
View File
@@ -1,22 +0,0 @@
// This used to be in paper.dm, it was some snowflake code that was
// used ONLY on april's fool. I moved it to a component so it could be
// used in other places
/datum/component/honkspam
dupe_mode = COMPONENT_DUPE_UNIQUE
var/spam_flag = FALSE
/datum/component/honkspam/Initialize()
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact)
/datum/component/honkspam/proc/reset_spamflag()
spam_flag = FALSE
/datum/component/honkspam/proc/interact(mob/user)
if(!spam_flag)
spam_flag = TRUE
var/obj/item/parent_item = parent
playsound(parent_item.loc, 'sound/items/bikehorn.ogg', 50, TRUE)
addtimer(CALLBACK(src, .proc/reset_spamflag), 2 SECONDS)
-87
View File
@@ -1,87 +0,0 @@
/**
The label component.
This component is used to manage labels applied by the hand labeler.
Atoms can only have one instance of this component, and therefore only one label at a time.
This is to avoid having names like "Backpack (label1) (label2) (label3)". This is annoying and abnoxious to read.
When a player clicks the atom with a hand labeler to apply a label, this component gets applied to it.
If the labeler is off, the component will be removed from it, and the label will be removed from its name.
*/
/datum/component/label
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/// The name of the label the player is applying to the parent.
var/label_name
/datum/component/label/Initialize(_label_name)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
label_name = _label_name
apply_label()
/datum/component/label/RegisterWithParent()
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/OnAttackby)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/Examine)
/datum/component/label/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE))
/**
This proc will fire after the parent is hit by a hand labeler which is trying to apply another label.
Since the parent already has a label, it will remove the old one from the parent's name, and apply the new one.
*/
/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, _label_name)
remove_label()
if(new_comp)
label_name = new_comp.label_name
else
label_name = _label_name
apply_label()
/**
This proc will trigger when any object is used to attack the parent.
If the attacking object is not a hand labeler, it will return.
If the attacking object is a hand labeler it will restore the name of the parent to what it was before this component was added to it, and the component will be deleted.
Arguments:
* source: The parent.
* attacker: The object that is hitting the parent.
* user: The mob who is wielding the attacking object.
*/
/datum/component/label/proc/OnAttackby(datum/source, obj/item/attacker, mob/user)
// If the attacking object is not a hand labeler or its mode is 1 (has a label ready to apply), return.
// The hand labeler should be off (mode is 0), in order to remove a label.
var/obj/item/hand_labeler/labeler = attacker
if(!istype(labeler) || labeler.mode)
return
remove_label()
playsound(parent, 'sound/items/poster_ripped.ogg', 20, TRUE)
to_chat(user, "<span class='warning'>You remove the label from [parent].</span>")
qdel(src) // Remove the component from the object.
/**
This proc will trigger when someone examines the parent.
It will attach the text found in the body of the proc to the `examine_list` and display it to the player examining the parent.
Arguments:
* source: The parent.
* user: The mob exmaining the parent.
* examine_list: The current list of text getting passed from the parent's normal examine() proc.
*/
/datum/component/label/proc/Examine(datum/source, mob/user, list/examine_list)
examine_list += "<span class='notice'>It has a label with some words written on it. Use a hand labeler to remove it.</span>"
/// Applies a label to the name of the parent in the format of: "parent_name (label)"
/datum/component/label/proc/apply_label()
var/atom/owner = parent
owner.name += " ([label_name])"
/// Removes the label from the parent's name
/datum/component/label/proc/remove_label()
var/atom/owner = parent
owner.name = replacetext(owner.name, "([label_name])", "") // Remove the label text from the parent's name, wherever it's located.
owner.name = trim(owner.name) // Shave off any white space from the beginning or end of the parent's name.
+1 -1
View File
@@ -1,4 +1,4 @@
//Thing meant for allowing datums and objects to access an NTnet network datum.
//Thing meant for allowing datums and objects to access a NTnet network datum.
/datum/proc/ntnet_receive(datum/netdata/data)
return
+5 -5
View File
@@ -32,7 +32,6 @@
RegisterSignal(A, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_react)
if(description)
RegisterSignal(A, COMSIG_PARENT_EXAMINE, .proc/examine)
RegisterSignal(A, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlay, TRUE)
num_decals_per_atom[A]++
apply(A)
@@ -40,20 +39,21 @@
/datum/element/decal/Detach(datum/target)
var/atom/A = target
num_decals_per_atom[A]--
apply(A, TRUE)
if(!num_decals_per_atom[A])
UnregisterSignal(A, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE, COMSIG_ATOM_UPDATE_OVERLAYS))
LAZYREMOVE(num_decals_per_atom, A)
apply(A)
return ..()
/datum/element/decal/proc/apply(atom/target)
/datum/element/decal/proc/apply(atom/target, removing = FALSE)
if(num_decals_per_atom[target] == 1 && !removing)
RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlay, TRUE)
target.update_icon()
if(isitem(target))
addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE)
/datum/element/decal/proc/apply_overlay(atom/source, list/overlay_list)
if(first_dir)
pic.dir = turn(first_dir, -dir2angle(source.dir))
pic.dir = first_dir == NORTH ? source.dir : turn(first_dir, dir2angle(source.dir))
for(var/i in 1 to num_decals_per_atom[source])
overlay_list += pic
+2 -3
View File
@@ -102,9 +102,8 @@
/datum/emote/proc/can_run_emote(mob/user, status_check = TRUE, intentional = FALSE)
. = TRUE
if(mob_type_allowed_typecache) //empty list = anyone can use it unless specifically blacklisted
if(!is_type_in_typecache(user, mob_type_allowed_typecache))
return FALSE
if(!is_type_in_typecache(user, mob_type_allowed_typecache))
return FALSE
if(is_type_in_typecache(user, mob_type_blacklist_typecache))
return FALSE
if(status_check && !is_type_in_typecache(user, mob_type_ignore_stat_typecache))
+5 -31
View File
@@ -103,21 +103,13 @@ GLOBAL_LIST_EMPTY(explosions)
// 3/7/14 will calculate to 80 + 35
var/far_dist = 0
far_dist += heavy_impact_range * 15 // Large explosions carry further
far_dist += heavy_impact_range * 5
far_dist += devastation_range * 20
if(!silent)
var/frequency = get_rand_frequency()
var/sound/explosion_sound = sound(get_sfx("explosion"))
var/sound/far_explosion_sound = sound('sound/effects/explosionfar.ogg')
var/sound/creaking_explosion_sound = sound(get_sfx("explosion_creaking"))
var/sound/hull_creaking_sound = sound(get_sfx("hull_creaking"))
var/sound/explosion_echo_sound = sound('sound/effects/explosion_distant.ogg')
var/on_station = SSmapping.level_trait(epicenter.z, ZTRAIT_STATION)
var/creaking_explosion = FALSE
if(prob(devastation_range*30+heavy_impact_range*5) && on_station) // Huge explosions are near guaranteed to make the station creak and whine, smaller ones might.
creaking_explosion = TRUE // prob over 100 always returns true
for(var/mob/M in GLOB.player_list)
// Double check for client
@@ -134,29 +126,11 @@ GLOBAL_LIST_EMPTY(explosions)
shake_camera(M, 25, clamp(baseshakeamount, 0, 10))
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
else if(dist <= far_dist)
var/far_volume = clamp(far_dist/2, 40, 60) // Volume is based on explosion size and dist
if(creaking_explosion)
M.playsound_local(epicenter, null, far_volume, 1, frequency, S = creaking_explosion_sound, distance_multiplier = 0)
else if(prob(75))
M.playsound_local(epicenter, null, far_volume, 1, frequency, S = far_explosion_sound, distance_multiplier = 0) // Far sound
else
M.playsound_local(epicenter, null, far_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0) // Echo sound
if(baseshakeamount > 0 || devastation_range)
if(!baseshakeamount) // Devastating explosions rock the station and ground
baseshakeamount = devastation_range*3
var/far_volume = clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
M.playsound_local(epicenter, null, far_volume, 1, frequency, falloff = 5, S = far_explosion_sound)
if(baseshakeamount > 0)
shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5))
else if(M.can_hear() && !isspaceturf(get_turf(M)) && heavy_impact_range) // Big enough explosions echo throughout the hull
var/echo_volume = 40
if(devastation_range)
baseshakeamount = devastation_range
shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5))
echo_volume = 60
M.playsound_local(epicenter, null, echo_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0)
if(creaking_explosion) // 5 seconds after the bang, the station begins to creak
addtimer(CALLBACK(M, /mob/proc/playsound_local, epicenter, null, rand(25, 40), 1, frequency, null, null, FALSE, hull_creaking_sound, null, null, null, null, 0), 5 SECONDS)
EX_PREPROCESS_CHECK_TICK
//postpone processing for a bit
-6
View File
@@ -41,8 +41,6 @@
var/special_role
var/list/restricted_roles = list()
var/hide_ckey = FALSE //hide ckey from round-end report
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
var/linglink
@@ -71,7 +69,6 @@
///What character we spawned in as- either at roundstart or latejoin, so we know for persistent scars if we ended as the same person or not
var/mob/original_character
/datum/mind/New(var/key)
skill_holder = new(src)
src.key = key
@@ -140,8 +137,6 @@
if(L.client?.prefs && L.client.prefs.auto_ooc && L.client.prefs.chat_toggles & CHAT_OOC)
DISABLE_BITFIELD(L.client.prefs.chat_toggles,CHAT_OOC)
hide_ckey = current.client?.prefs?.hide_ckey
SEND_SIGNAL(src, COMSIG_MIND_TRANSFER, new_character, old_character)
SEND_SIGNAL(new_character, COMSIG_MOB_ON_NEW_MIND)
@@ -785,7 +780,6 @@
if(!mind.name)
mind.name = real_name
mind.current = src
mind.hide_ckey = client?.prefs?.hide_ckey
/mob/living/carbon/mind_initialize()
..()
-2
View File
@@ -90,8 +90,6 @@
to_chat(user, "<span class='boldnotice'>You catch some drifting memories of their past conversations...</span>")
for(var/spoken_memory in recent_speech)
to_chat(user, "<span class='notice'>[recent_speech[spoken_memory]]</span>")
if(usr in GLOB.rockpaperscissors_players)
to_chat(user, "<span class='notice'>They're planning on playing [GLOB.rockpaperscissors_players[usr][1]]</span>")
if(iscarbon(M))
var/mob/living/carbon/human/H = M
to_chat(user, "<span class='boldnotice'>You find that their intent is to [H.a_intent]...</span>")
+1 -60
View File
@@ -580,63 +580,4 @@
/datum/status_effect/regenerative_core/on_remove()
. = ..()
REMOVE_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "regenerative_core")
owner.updatehealth()
/datum/status_effect/panacea
id = "Anatomic Panacea"
duration = 100
tick_interval = 10
alert_type = /obj/screen/alert/status_effect/panacea
/obj/screen/alert/status_effect/panacea
name = "Panacea"
desc = "We purge the impurities from our body."
icon_state = "panacea"
// Changeling's anatomic panacea now in buff form. Directly fixes issues instead of injecting chems
/datum/status_effect/panacea/tick()
var/mob/living/carbon/M = owner
//Heal brain damage and toxyloss, alongside trauma
owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, -8)
owner.adjustToxLoss(-6, forced = TRUE)
M.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
//Purges 50 rads per tick
if(owner.radiation > 0)
owner.radiation -= min(owner.radiation, 50)
//Mutadone effects
owner.jitteriness = 0
if(owner.has_dna())
M.dna.remove_all_mutations(mutadone = TRUE)
if(!QDELETED(owner)) //We were a monkey, now a human
..()
// Purges toxins
for(var/datum/reagent/toxin/R in owner.reagents.reagent_list)
owner.reagents.remove_reagent(R.type, 5)
//Antihol effects
M.reagents.remove_all_type(/datum/reagent/consumable/ethanol, 10, 0, 1)
M.drunkenness = max(M.drunkenness - 10, 0)
owner.dizziness = 0
owner.drowsyness = 0
owner.slurring = 0
owner.confused = 0
//Organ and disease cure moved from panacea.dm to buff proc
var/list/bad_organs = list(
owner.getorgan(/obj/item/organ/body_egg),
owner.getorgan(/obj/item/organ/zombie_infection))
for(var/o in bad_organs)
var/obj/item/organ/O = o
if(!istype(O))
continue
O.Remove()
if(iscarbon(owner))
var/mob/living/carbon/C = owner
C.vomit(0, toxic = TRUE)
O.forceMove(get_turf(owner))
if(isliving(owner))
var/mob/living/L = owner
for(var/thing in L.diseases)
var/datum/disease/D = thing
if(D.severity == DISEASE_SEVERITY_POSITIVE)
continue
D.cure()
owner.updatehealth()
@@ -200,15 +200,13 @@
/datum/dynamic_ruleset/latejoin/heretic_smuggler
name = "Heretic Smuggler"
antag_datum = /datum/antagonist/heretic
antag_flag = "latejoin_heretic"
antag_flag = ROLE_HERETIC
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
restricted_roles = list("AI","Cyborg")
required_candidates = 1
weight = 4
cost = 25
requirements = list(60,60,60,55,50,50,50,50,50,50)
high_population_requirement = 50
property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2)
cost = 10
requirements = list(40,30,20,10,10,10,10,10,10,10)
repeatable = TRUE
//////////////////////////////////////////////
@@ -538,7 +538,7 @@
name = "Slaughter Demon"
config_tag = "slaughter_demon"
antag_flag = ROLE_ALIEN
enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg","Bartender")
enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg")
required_enemies = list(3,2,2,2,2,1,1,1,1,0)
required_candidates = 1
weight = 4
@@ -151,18 +151,16 @@
/datum/dynamic_ruleset/roundstart/heretics
name = "Heretics"
antag_flag = "heretic"
antag_flag = ROLE_HERETIC
antag_datum = /datum/antagonist/heretic
protected_roles = list("Prisoner","Security Officer", "Warden", "Detective", "Head of Security", "Captain")
restricted_roles = list("AI", "Cyborg")
required_candidates = 1
weight = 3
cost = 25
cost = 20
scaling_cost = 15
requirements = list(60,60,60,55,50,50,50,50,50,50)
property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2)
requirements = list(50,45,45,40,35,20,20,15,10,10)
antag_cap = list(1,1,1,1,2,2,2,2,3,3)
high_population_requirement = 50
/datum/dynamic_ruleset/roundstart/heretics/pre_execute()
@@ -22,14 +22,14 @@
var/datum/game_mode/dynamic/mode = null // Cached as soon as it's made, by dynamic.
/**
Property weights are added to the config weight of the ruleset. They are:
Property weights are:
"story_potential" -- essentially how many different ways the antag can be played.
"trust" -- How much it makes the crew trust each other. Negative values means they're suspicious. Team antags are like this.
"chaos" -- How chaotic it makes the round. Has some overlap with "valid" and somewhat contradicts "extended".
"valid" -- How likely the non-antag-enemy crew are to get involved, e.g. nukies encouraging the warden to
let everyone into the armory, wizard moving around and being a nuisance, nightmare busting lights.
"extended" -- How much the antag is conducive to a long round. Nukies and cults are bad for this; Wizard is less bad; and so on.
"conversion" -- Basically a bool. Conversion antags, well, convert. It's in its own class 'cause people kinda hate conversion.
"conversion" -- Basically a bool. Conversion antags, well, convert. It's its own class for a good reason.
*/
/datum/dynamic_storyteller/proc/start_injection_cooldowns()
@@ -126,9 +126,8 @@ Property weights are added to the config weight of the ruleset. They are:
for(var/property in property_weights)
if(property in rule.property_weights) // just treat it as 0 if it's not in there
property_weight += rule.property_weights[property] * property_weights[property]
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult
if(calced_weight > 0) // negatives in the list might cause problems
drafted_rules[rule] = calced_weight
if(property_weight > 0)
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult
return drafted_rules
/datum/dynamic_storyteller/proc/midround_draft()
@@ -145,24 +144,21 @@ Property weights are added to the config weight of the ruleset. They are:
for(var/property in property_weights)
if(property in rule.property_weights) // just treat it as 0 if it's not in there
property_weight += rule.property_weights[property] * property_weights[property]
var/threat_weight = 1
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
var/cost_difference = rule.cost-(mode.threat_level-mode.threat)
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
pick this particular ruleset.
Let's use a toy example: there's 60 threat level and 10 threat spent.
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
is 2.26 times as likely to be picked, all other things considered.
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
*/
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,abs(cost_difference),0)))
if(cost_difference > 0)
threat_weight /= (1+(cost_difference*0.1))
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult * threat_weight
if(calced_weight > 0)
drafted_rules[rule] = calced_weight
if(property_weight > 0)
var/threat_weight = 1
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
pick this particular ruleset.
Let's use a toy example: there's 60 threat level and 10 threat spent.
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
is 2.26 times as likely to be picked, all other things considered.
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
*/
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight
return drafted_rules
/datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer)
@@ -184,15 +180,12 @@ Property weights are added to the config weight of the ruleset. They are:
for(var/property in property_weights)
if(property in rule.property_weights)
property_weight += rule.property_weights[property] * property_weights[property]
var/threat_weight = 1
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))
var/cost_difference = rule.cost-(mode.threat_level-mode.threat)
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,abs(cost_difference),0)))
if(cost_difference > 0)
threat_weight /= (1+(cost_difference*0.1))
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult * threat_weight
if(calced_weight > 0)
drafted_rules[rule] = calced_weight
if(property_weight > 0)
var/threat_weight = 1
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight
return drafted_rules
/datum/dynamic_storyteller/proc/event_draft()
@@ -203,9 +196,8 @@ Property weights are added to the config weight of the ruleset. They are:
for(var/property in property_weights)
if(property in rule.property_weights)
property_weight += rule.property_weights[property] * property_weights[property]
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult
if(calced_weight > 0)
drafted_rules[rule] = calced_weight
if(property_weight > 0)
drafted_rules[rule] = rule.get_weight() + property_weight * rule.weight_mult
return drafted_rules
@@ -335,6 +327,12 @@ Property weights are added to the config weight of the ruleset. They are:
flags = USE_PREV_ROUND_WEIGHTS
property_weights = list("story_potential" = 2)
/datum/dynamic_storyteller/story/calculate_threat()
var/current_time = (world.time / SSautotransfer.targettime)*180
mode.threat_level = round((mode.initial_threat_level*(sin(current_time)/2)+0.75),0.1)
return ..()
/datum/dynamic_storyteller/classic
name = "Classic"
config_tag = "classic"
@@ -49,6 +49,7 @@
dat += "</b></center>"
var/datum/browser/popup = new(user, "arcade", "Space Villain 2000")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/arcade/battle/Topic(href, href_list)
@@ -160,6 +160,7 @@
dat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
var/datum/browser/popup = new(user, "arcade", "The Orion Trail",400,700)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
return
+1
View File
@@ -353,6 +353,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
dat = list("<tt>", header.Join(), body, "<br></tt>")
var/datum/browser/popup = new(user, "id_com", src.name, 900, 620)
popup.set_content(dat.Join())
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/card/Topic(href, href_list)
+1
View File
@@ -276,6 +276,7 @@
var/datum/browser/popup = new(user, "cloning", "Cloning System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/cloning/Topic(href, href_list)
+30 -60
View File
@@ -1,15 +1,3 @@
#define STATE_DEFAULT 1
#define STATE_CALLSHUTTLE 2
#define STATE_CANCELSHUTTLE 3
#define STATE_MESSAGELIST 4
#define STATE_VIEWMESSAGE 5
#define STATE_DELMESSAGE 6
#define STATE_STATUSDISPLAY 7
#define STATE_ALERT_LEVEL 8
#define STATE_CONFIRM_LEVEL 9
#define STATE_TOGGLE_EMERGENCY 10
#define STATE_PURCHASE 11
// The communications computer
/obj/machinery/computer/communications
name = "communications console"
@@ -18,7 +6,6 @@
icon_keyboard = "tech_key"
req_access = list(ACCESS_HEADS)
circuit = /obj/item/circuitboard/computer/communications
light_color = LIGHT_COLOR_BLUE
var/auth_id = "Unknown" //Who is currently logged in?
var/list/datum/comm_message/messages = list()
var/datum/comm_message/currmsg
@@ -29,10 +16,22 @@
var/ai_message_cooldown = 0
var/tmp_alertlevel = 0
var/static/security_level_cd // used to stop mass spam.
var/const/STATE_DEFAULT = 1
var/const/STATE_CALLSHUTTLE = 2
var/const/STATE_CANCELSHUTTLE = 3
var/const/STATE_MESSAGELIST = 4
var/const/STATE_VIEWMESSAGE = 5
var/const/STATE_DELMESSAGE = 6
var/const/STATE_STATUSDISPLAY = 7
var/const/STATE_ALERT_LEVEL = 8
var/const/STATE_CONFIRM_LEVEL = 9
var/const/STATE_TOGGLE_EMERGENCY = 10
var/const/STATE_PURCHASE = 11
var/stat_msg1
var/stat_msg2
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/communications/proc/checkCCcooldown()
var/obj/item/circuitboard/computer/communications/CM = circuit
@@ -47,7 +46,7 @@
/obj/machinery/computer/communications/Topic(href, href_list)
if(..())
return
if(!usr.canUseTopic(src, !issilicon(usr)))
if(!usr.canUseTopic(src))
return
if(!is_station_level(z) && !is_reserved_level(z)) //Can only use in transit and on SS13
to_chat(usr, "<span class='boldannounce'>Unable to establish a connection</span>: \black You're too far away from the station!")
@@ -133,20 +132,15 @@
if("crossserver")
if(authenticated==2)
var/dest = href_list["cross_dest"]
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return
var/warning = dest == "all" ? "Please choose a message to transmit to allied stations." : "Please choose a message to transmit to [dest] sector station."
var/input = stripped_multiline_input(usr, "[warning] Please be aware that this process is very expensive, and abuse will lead to... termination.", "Send a message to an allied station.", "")
var/input = stripped_multiline_input(usr, "Please choose a message to transmit to allied stations. Please be aware that this process is very expensive, and abuse will lead to... termination.", "Send a message to an allied station.", "")
if(!input || !(usr in view(1,src)) || !checkCCcooldown())
return
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
if(dest == "all")
send2otherserver("[station_name()]", input,"Comms_Console")
else
send2otherserver("[station_name()]", input,"Comms_Console", list(dest))
send2otherserver("[station_name()]", input,"Comms_Console")
minor_announce(input, title = "Outgoing message to allied station")
usr.log_talk(input, LOG_SAY, tag="message to the other server")
message_admins("[ADMIN_LOOKUPFLW(usr)] has sent a message to the other server.")
@@ -162,12 +156,12 @@
var/datum/map_template/shuttle/S = locate(href_list["chosen_shuttle"]) in shuttles
if(S && istype(S))
if(SSshuttle.emergency.mode != SHUTTLE_RECALL && SSshuttle.emergency.mode != SHUTTLE_IDLE)
to_chat(usr, "<span class='alert'>It's a bit late to buy a new shuttle, don't you think?</span>")
to_chat(usr, "It's a bit late to buy a new shuttle, don't you think?")
return
if(SSshuttle.shuttle_purchased)
to_chat(usr, "<span class='alert'>A replacement shuttle has already been purchased.</span>")
to_chat(usr, "A replacement shuttle has already been purchased.")
else if(!S.prerequisites_met())
to_chat(usr, "<span class='alert'>You have not met the requirements for purchasing this shuttle.</span>")
to_chat(usr, "You have not met the requirements for purchasing this shuttle.")
else
var/points_to_check
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
@@ -189,7 +183,7 @@
if("callshuttle")
state = STATE_DEFAULT
if(authenticated && SSshuttle.canEvac(usr))
if(authenticated)
state = STATE_CALLSHUTTLE
if("callshuttle2")
if(authenticated)
@@ -290,12 +284,12 @@
if("MessageCentCom")
if(authenticated)
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
return
var/input = stripped_input(usr, "Please choose a message to transmit to CentCom via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "Send a message to CentCom.", "")
if(!input || !(usr in view(1,src)) || !checkCCcooldown())
return
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
CentCom_announce(input, usr)
to_chat(usr, "<span class='notice'>Message transmitted to Central Command.</span>")
for(var/client/X in GLOB.admins)
@@ -308,7 +302,7 @@
// OMG SYNDICATE ...LETTERHEAD
if("MessageSyndicate")
if((authenticated) && (obj_flags & EMAGGED))
if((authenticated==2) && (obj_flags & EMAGGED))
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
@@ -338,7 +332,7 @@
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
return
var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self-Destruct Code Request.","")
var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self Destruct Code Request.","")
if(!input || !(usr in view(1,src)) || !checkCCcooldown())
return
Nuke_request(input, usr)
@@ -353,9 +347,7 @@
aicurrmsg = null
aistate = STATE_DEFAULT
if("ai-callshuttle")
aistate = STATE_DEFAULT
if(SSshuttle.canEvac(usr))
aistate = STATE_CALLSHUTTLE
aistate = STATE_CALLSHUTTLE
if("ai-callshuttle2")
SSshuttle.requestEvac(usr, href_list["call"])
aistate = STATE_DEFAULT
@@ -468,8 +460,9 @@
var/datum/browser/popup = new(user, "communications", "Communications Console", 400, 500)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
if(issilicon(user))
if(issilicon(user) || (hasSiliconAccessInArea(user) && !in_range(user,src)))
var/dat2 = interact_ai(user) // give the AI a different interact proc to limit its access
if(dat2)
dat += dat2
@@ -500,15 +493,9 @@
if (authenticated==2)
dat += "<BR><BR><B>Captain Functions</B>"
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=announce'>Make a Captain's Announcement</A> \]"
var/list/cross_servers = CONFIG_GET(keyed_list/cross_server)
var/our_id = CONFIG_GET(string/cross_comms_name)
if(cross_servers.len)
for(var/server in cross_servers)
if(server == our_id)
continue
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=crossserver=all;cross_dest=[server]'>Send a message to station in [server] sector.</A> \]"
if(cross_servers.len > 2)
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=crossserver;cross_dest=all'>Send a message to all allied stations</A> \]"
var/cross_servers_count = length(CONFIG_GET(keyed_list/cross_server))
if(cross_servers_count)
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=crossserver'>Send a message to [cross_servers_count == 1 ? "an " : ""]allied station[cross_servers_count > 1 ? "s" : ""]</A> \]"
if(SSmapping.config.allow_custom_shuttles)
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=purchase_menu'>Purchase Shuttle</A> \]"
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=changeseclevel'>Change Alert Level</A> \]"
@@ -734,13 +721,8 @@
to_chat(user, "<span class='alert'>Intercomms recharging. Please stand by.</span>")
return
var/input = stripped_input(user, "Please choose a message to announce to the station crew.", "What?")
if(!input || !user.canUseTopic(src, !issilicon(usr)))
if(!input || !user.canUseTopic(src))
return
if(!(user.can_speak())) //No more cheating, mime/random mute guy!
input = "..."
to_chat(user, "<span class='warning'>You find yourself unable to speak.</span>")
else
input = user.treat_message(input) //Adds slurs and so on. Someone should make this use languages too.
SScommunications.make_announcement(user, is_silicon, input)
deadchat_broadcast("<span class='deadsay'><span class='name'>[user.real_name]</span> made an priority announcement from <span class='name'>[get_area_name(usr, TRUE)]</span>.</span>", user)
@@ -789,15 +771,3 @@
content = new_content
if(new_possible_answers)
possible_answers = new_possible_answers
#undef STATE_DEFAULT
#undef STATE_CALLSHUTTLE
#undef STATE_CANCELSHUTTLE
#undef STATE_MESSAGELIST
#undef STATE_VIEWMESSAGE
#undef STATE_DELMESSAGE
#undef STATE_STATUSDISPLAY
#undef STATE_ALERT_LEVEL
#undef STATE_CONFIRM_LEVEL
#undef STATE_TOGGLE_EMERGENCY
#undef STATE_PURCHASE
+4 -6
View File
@@ -217,6 +217,9 @@
// already discovered mutations
stored_research = SSresearch.science_tech
/obj/machinery/computer/scan_consolenew/examine(mob/user)
. = ..()
/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, datum/tgui/ui)
// Most of ui_interact is spent setting variables for passing to the tgui
// interface.
@@ -263,10 +266,6 @@
if(!ui)
ui = new(user, src, "DnaConsole")
ui.open()
/obj/machinery/computer/scan_consolenew/ui_assets()
. = ..() || list()
. += get_asset_datum(/datum/asset/simple/genetics)
/obj/machinery/computer/scan_consolenew/ui_data(mob/user)
var/list/data = list()
@@ -358,7 +357,7 @@
return data
/obj/machinery/computer/scan_consolenew/ui_act(action, list/params)
/obj/machinery/computer/scan_consolenew/ui_act(action, var/list/params)
if(..())
return TRUE
@@ -483,7 +482,6 @@
// Resolve mutation's BYOND path from the alias
var/alias = params["alias"]
var/path = GET_MUTATION_TYPE_FROM_ALIAS(alias)
// Make sure the occupant still has this mutation
if(!(path in scanner_occupant.dna.mutation_index))
return
+1
View File
@@ -178,6 +178,7 @@
dat += "<A href='?src=[REF(src)];login=1'>{Log In}</A>"
var/datum/browser/popup = new(user, "med_rec", "Medical Records Console", 600, 400)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/med_data/Topic(href, href_list)
+1
View File
@@ -67,6 +67,7 @@
add_fingerprint(usr)
var/datum/browser/popup = new(user, "computer", title, 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/pod/process()
@@ -66,6 +66,7 @@
dat += "<HR><A href='?src=[REF(src)];lock=1'>{Log Out}</A>"
var/datum/browser/popup = new(user, "computer", "Prisoner Management Console", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
+1
View File
@@ -250,6 +250,7 @@
dat += "<A href='?src=[REF(src)];choice=Log In'>{Log In}</A>"
var/datum/browser/popup = new(user, "secure_rec", "Security Records Console", 600, 400)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
@@ -103,6 +103,7 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
var/datum/browser/popup = new(user, "computer", "Telecrystal Upload/Receive Station", 700, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/telecrystals/uplinker/Topic(href, href_list)
@@ -184,6 +185,7 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
var/datum/browser/popup = new(user, "computer", "Team Telecrystal Management Console", 700, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/telecrystals/boss/Topic(href, href_list)
+2 -1
View File
@@ -76,6 +76,7 @@
var/datum/browser/popup = new(user, "cryopod_console", "Cryogenic System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/cryopod/Topic(href, href_list)
@@ -307,7 +308,7 @@
var/mob/living/mob_occupant = occupant
var/list/obj/item/cryo_items = list()
investigate_log("Despawning [key_name(mob_occupant)].", INVESTIGATE_CRYOGENICS)
//Handle Borg stuff first
+14
View File
@@ -74,6 +74,12 @@
/obj/machinery/door/firedoor/Bumped(atom/movable/AM)
if(panel_open || operating || welded)
return
if(ismob(AM))
var/mob/user = AM
if(density && !welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user)))
add_fingerprint(user)
open()
return TRUE
return FALSE
/obj/machinery/door/firedoor/power_change()
@@ -84,6 +90,14 @@
stat |= NOPOWER
/obj/machinery/door/firedoor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user)))
add_fingerprint(user)
if(density)
emergency_close_timer = world.time + 30 // prevent it from instaclosing again if in space
open()
else
close()
return TRUE
if(operating || !density)
return
@@ -260,6 +260,7 @@
/obj/machinery/doorButtons/airlock_controller/ui_interact(mob/user)
var/datum/browser/popup = new(user, "computer", name)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.set_content(returnText())
popup.open()
@@ -29,6 +29,7 @@
. = ..()
user.set_machine(src)
var/datum/browser/popup = new(user, "computer", name) // Set up the popup browser window
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.set_content(return_text())
popup.open()
+3 -16
View File
@@ -3,14 +3,13 @@
/obj/machinery/iv_drip
name = "\improper IV drip"
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. Alt-Click to change the transfer rate."
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate."
icon = 'icons/obj/iv_drip.dmi'
icon_state = "iv_drip"
anchored = FALSE
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
var/mob/living/carbon/attached
var/mode = IV_INJECTING
var/dripfeed = FALSE
var/obj/item/reagent_containers/beaker
var/static/list/drip_containers = typecacheof(list(/obj/item/reagent_containers/blood,
/obj/item/reagent_containers/food,
@@ -133,11 +132,9 @@
if(mode)
if(beaker.reagents.total_volume)
var/transfer_amount = 5
if (dripfeed)
transfer_amount = 1
if(istype(beaker, /obj/item/reagent_containers/blood))
// speed up transfer on blood packs
transfer_amount *= 2
transfer_amount = 10
var/fraction = min(transfer_amount/beaker.reagents.total_volume, 1) //the fraction that is transfered of the total volume
beaker.reagents.reaction(attached, INJECT, fraction, FALSE) //make reagents reacts, but don't spam messages
beaker.reagents.trans_to(attached, transfer_amount)
@@ -172,16 +169,6 @@
else
toggle_mode()
/obj/machinery/iv_drip/AltClick(mob/living/user)
if(!user.canUseTopic(src, be_close=TRUE))
return
if(dripfeed)
dripfeed = FALSE
to_chat(usr, "<span class='notice'>You loosen the valve to speed up the [src].</span>")
else
dripfeed = TRUE
to_chat(usr, "<span class='notice'>You tighten the valve to slowly drip-feed the contents of [src].</span>")
/obj/machinery/iv_drip/attack_robot(mob/user)
if(Adjacent(user))
attack_hand(user)
@@ -240,7 +227,7 @@
/obj/machinery/iv_drip/telescopic
name = "telescopic IV drip"
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down.Alt-Click with a beaker attached to change the transfer rate."
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down."
icon_state = "iv_drip"
/obj/machinery/iv_drip/telescopic/update_icon_state()
+6 -5
View File
@@ -218,10 +218,10 @@ GLOBAL_LIST_EMPTY(allConsoles)
dat += "<b>Message Authentication</b> <br><br>"
dat += "<b>Message for [dpt]:</b> [message] <br><br>"
dat += "<div class='notice'>You may authenticate your message now by scanning your ID or your stamp</div> <br>"
dat += "<b>Validated by:</b> [msgVerified ? "<span class='good'><b>[msgVerified]</b></span>" : "<i>Not Validated</i>"] <br>"
dat += "<b>Stamped by:</b> [msgStamped ? "<span class='boldnotice'>[msgStamped]</span>" : "<i>Not Stamped</i>"] <br><br>"
dat += "<a href='?src=[REF(src)];department=[dpt]'>Send Message</a> <br><br>"
dat += "<a href='?src=[REF(src)];setScreen=0'><< Discard Message</a> <br>"
@@ -271,6 +271,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
var/datum/browser/popup = new(user, "req_console", "[department] Requests Console", 450, 440)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/requests_console/Topic(href, href_list)
@@ -278,7 +279,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
return
usr.set_machine(src)
add_fingerprint(usr)
if(href_list["write"])
dpt = ckey(reject_bad_text(href_list["write"])) //write contains the string of the receiving department's name
var/new_message = stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN)
@@ -357,7 +358,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
workingServer = TRUE
if(!workingServer)
screen = 7
screen = 7
say("NOTICE: No server detected! Please contact your local engineering team.")
updateUsrDialog()
return
@@ -538,7 +539,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
to_chat(user, "<span class='warning'>You are not authorized to send announcements!</span>")
updateUsrDialog()
return
if(istype(O, /obj/item/stamp))
if(screen == 9)
var/obj/item/stamp/T = O
+1
View File
@@ -132,6 +132,7 @@
var/datum/browser/popup = new(user, "slotmachine", "Slot Machine")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/slot_machine/Topic(href, href_list)
+6 -4
View File
@@ -1,10 +1,12 @@
/obj/mecha/proc/get_armour_facing(relative_dir)
switch(relative_dir)
if(180) // BACKSTAB!
if(0) // BACKSTAB!
return facing_modifiers[BACK_ARMOUR]
if(0, 45) // direct or 45 degrees off
if(45, 90, 270, 315)
return facing_modifiers[SIDE_ARMOUR]
if(225, 180, 135)
return facing_modifiers[FRONT_ARMOUR]
return facing_modifiers[SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side
return 1 //always return non-0
/obj/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
@@ -41,7 +43,7 @@
break
if(attack_dir)
var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir)))
var/facing_modifier = get_armour_facing(dir2angle(attack_dir) - dir2angle(src))
booster_damage_modifier /= facing_modifier
booster_deflection_modifier *= facing_modifier
if(prob(deflect_chance * booster_deflection_modifier))
+1 -1
View File
@@ -285,7 +285,7 @@
S.rabid = TRUE
S.amount_grown = SLIME_EVOLUTION_THRESHOLD
S.Evolve()
offer_control(S,POLL_IGNORE_SENTIENCE_POTION)
offer_control(S)
/////////////////////
+1 -1
View File
@@ -46,4 +46,4 @@
var/turf/T = loc
if(!istype(T)) //you know this will happen somehow
CRASH("Turf decal initialized in an object/nullspace")
T.AddElement(/datum/element/decal, icon, icon_state, dir, CLEAN_GOD, color, null, null, alpha)
T.AddElement(/datum/element/decal, icon, icon_state, turn(dir, -dir2angle(T.dir)), CLEAN_GOD, color, null, null, alpha)
+1
View File
@@ -242,6 +242,7 @@ RLD
var/datum/browser/popup = new(user, "rcd_access", "Access Control", 900, 500, src)
popup.set_content(t1)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/item/construction/rcd/Topic(href, href_list)
+18 -16
View File
@@ -28,37 +28,39 @@
/// triggered on wield of two handed item
/obj/item/broom/proc/on_wield(obj/item/source, mob/user)
to_chat(user, "<span class='notice'>You brace the [src] against the ground in a firm sweeping stance.</span>")
RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, .proc/sweep)
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/sweep)
/// triggered on unwield of two handed item
/obj/item/broom/proc/on_unwield(obj/item/source, mob/user)
UnregisterSignal(user, COMSIG_MOVABLE_PRE_MOVE)
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
/obj/item/broom/afterattack(atom/A, mob/user, proximity)
. = ..()
if(!proximity)
return
sweep(user, A)
sweep(user, A, FALSE)
/obj/item/broom/proc/sweep(datum/source, atom/newLoc)
if(!ismob(source) || !isturf(newLoc) || (get_dist(source, newLoc) > 1))
/obj/item/broom/proc/sweep(mob/user, atom/A, moving = TRUE)
var/turf/target
if (!moving)
if (isturf(A))
target = A
else
target = A.loc
else
target = user.loc
if (!isturf(target))
return
var/turf/target = newLoc
var/atom/movable/AM
var/sweep_dir = get_dir(source, target)
if(!sweep_dir)
if (locate(/obj/structure/table) in target.contents)
return
for(var/i in target.contents)
AM = i
if(AM.density) // eh good enough heuristic check
return
var/i = 0
for(var/obj/item/garbage in target.contents)
if(!garbage.anchored)
step(garbage, sweep_dir)
if(++i > 20)
garbage.Move(get_step(target, user.dir), user.dir)
i++
if(i >= 20)
break
if(i)
if(i >= 1)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 30, TRUE, -1)
/obj/item/broom/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) //bless you whoever fixes this copypasta
+1 -1
View File
@@ -266,7 +266,7 @@ GLOBAL_LIST_EMPTY(PDAs)
var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/simple/pda)
assets.send(user)
var/datum/asset/spritesheet/emoji_s = get_asset_datum(/datum/asset/spritesheet/chat)
var/datum/asset/spritesheet/emoji_s = get_asset_datum(/datum/asset/spritesheet/goonchat)
emoji_s.send(user) //Already sent by chat but no harm doing this
user.set_machine(src)
+1 -1
View File
@@ -590,7 +590,7 @@ Code:
var/static/list/emoji_icon_states
var/static/emoji_table
if(!emoji_table)
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat)
var/list/collate = list("<br><table>")
for(var/emoji in sortList(icon_states(icon('icons/emoji.dmi'))))
var/tag = sheet.icon_tag("emoji-[emoji]")
@@ -1,207 +0,0 @@
/obj/item/storage/portable_chem_mixer
name = "Portable Chemical Mixer"
desc = "A portable device that dispenses and mixes chemicals. All necessary reagents need to be supplied with beakers. A label indicates that a screwdriver is required to open it for refills. This device can be worn on a belt. The letters 'S&T' are imprinted on the side."
icon = 'icons/obj/chemical.dmi'
icon_state = "portablechemicalmixer_open"
w_class = WEIGHT_CLASS_HUGE
slot_flags = ITEM_SLOT_BELT
custom_price = 2000
custom_premium_price = 2000
var/obj/item/reagent_containers/beaker = null ///Creating an empty slot for a beaker that can be added to dispense into
var/amount = 30 ///The amount of reagent that is to be dispensed currently
var/list/dispensable_reagents = list() ///List in which all currently dispensable reagents go
/obj/item/storage/portable_chem_mixer/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 50
STR.insert_preposition = "in"
STR.can_hold = typecacheof(list(
/obj/item/reagent_containers/glass/beaker,
))
/obj/item/storage/portable_chem_mixer/Destroy()
QDEL_NULL(beaker)
return ..()
/obj/item/storage/portable_chem_mixer/ex_act(severity, target)
if(severity < 3)
..()
/obj/item/storage/portable_chem_mixer/attackby(obj/item/I, mob/user, params)
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if (I.tool_behaviour == TOOL_SCREWDRIVER)
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !locked)
if (!locked)
update_contents()
if (locked)
replace_beaker(user)
update_icon()
I.play_tool_sound(src, 50)
return
else if (istype(I, /obj/item/reagent_containers) && !(I.item_flags & ABSTRACT) && I.is_open_container() && locked)
var/obj/item/reagent_containers/B = I
. = TRUE //no afterattack
if(!user.transferItemToLoc(B, src))
return
replace_beaker(user, B)
update_icon()
updateUsrDialog()
return
return ..()
/**
* Updates the contents of the portable chemical mixer
*
* A list of dispensable reagents is created by iterating through each source beaker in the portable chemical beaker and reading its contents
*/
/obj/item/storage/portable_chem_mixer/proc/update_contents()
dispensable_reagents.Cut()
for (var/obj/item/reagent_containers/glass/beaker/B in contents)
var/key = B.reagents.get_master_reagent_id()
if (!(key in dispensable_reagents))
dispensable_reagents[key] = list()
dispensable_reagents[key]["reagents"] = list()
dispensable_reagents[key]["reagents"] += B.reagents
return
/obj/item/storage/portable_chem_mixer/update_icon_state()
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if (!locked)
icon_state = "portablechemicalmixer_open"
else if (beaker)
icon_state = "portablechemicalmixer_full"
else
icon_state = "portablechemicalmixer_empty"
/obj/item/storage/portable_chem_mixer/AltClick(mob/living/user)
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if (!locked)
return ..()
if(!can_interact(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
replace_beaker(user)
update_icon()
/**
* Replaces the beaker of the portable chemical mixer with another beaker, or simply adds the new beaker if none is in currently
*
* Checks if a valid user and a valid new beaker exist and attempts to replace the current beaker in the portable chemical mixer with the one in hand. Simply places the new beaker in if no beaker is currently loaded
* Arguments:
* * mob/living/user - The user who is trying to exchange beakers
* * obj/item/reagent_containers/new_beaker - The new beaker that the user wants to put into the device
*/
/obj/item/storage/portable_chem_mixer/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
if(!user)
return FALSE
if(beaker)
user.put_in_hands(beaker)
beaker = null
if(new_beaker)
beaker = new_beaker
return TRUE
/obj/item/storage/portable_chem_mixer/attack_hand(mob/user)
if (loc != user)
return ..()
if(SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
ui_interact(user)
return
/obj/item/storage/portable_chem_mixer/attack_self(mob/user)
if(loc == user)
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if (locked)
ui_interact(user)
return
else
to_chat(user, "<span class='notice'>The portable chemical mixer is currently open and its contents can be accessed.</span>")
return
return
/obj/item/storage/portable_chem_mixer/MouseDrop(obj/over_object)
. = ..()
if(ismob(loc))
var/mob/M = loc
if(!M.incapacitated() && istype(over_object, /obj/screen/inventory/hand))
var/obj/screen/inventory/hand/H = over_object
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
/obj/item/storage/portable_chem_mixer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "PortableChemMixer", name)
if(user.hallucinating())
// to not ruin the immersion by constantly changing the fake chemicals
ui.set_autoupdate(FALSE)
ui.open()
/obj/item/storage/portable_chem_mixer/ui_data(mob/user)
var/list/data = list()
data["amount"] = amount
data["isBeakerLoaded"] = beaker ? 1 : 0
data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null
data["beakerMaxVolume"] = beaker ? beaker.volume : null
data["beakerTransferAmounts"] = beaker ? beaker.possible_transfer_amounts : null
var/chemicals[0]
var/is_hallucinating = user.hallucinating()
if(user.hallucinating())
is_hallucinating = TRUE
for(var/re in dispensable_reagents)
var/value = dispensable_reagents[re]
var/datum/reagent/temp = GLOB.chemical_reagents_list[re]
if(temp)
var/chemname = temp.name
var/total_volume = 0
for (var/datum/reagents/rs in value["reagents"])
total_volume += rs.total_volume
if(is_hallucinating && prob(5))
chemname = "[pick_list_replacements("hallucination.json", "chemicals")]"
chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name), "volume" = total_volume )))
data["chemicals"] = chemicals
var/beakerContents[0]
if(beaker)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
beakerContents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = R.volume))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
return data
/obj/item/storage/portable_chem_mixer/ui_act(action, params)
if(..())
return
switch(action)
if("amount")
var/target = text2num(params["target"])
amount = target
. = TRUE
if("dispense")
var/reagent_name = params["reagent"]
var/datum/reagent/reagent = GLOB.name2reagent[reagent_name]
var/entry = dispensable_reagents[reagent]
if(beaker)
var/datum/reagents/R = beaker.reagents
var/actual = min(amount, 1000, R.maximum_volume - R.total_volume)
// todo: add check if we have enough reagent left
for (var/datum/reagents/source in entry["reagents"])
var/to_transfer = min(source.total_volume, actual)
source.trans_to(beaker, to_transfer)
actual -= to_transfer
if (actual <= 0)
break
. = TRUE
if("remove")
var/amount = text2num(params["amount"])
beaker.reagents.remove_all(amount)
. = TRUE
if("eject")
replace_beaker(usr)
update_icon()
. = TRUE
@@ -16,6 +16,9 @@
var/on = TRUE
var/shock_cooldown = FALSE
var/ui_x = 260
var/ui_y = 137
/obj/item/electropack/suicide_act(mob/living/carbon/user)
user.visible_message("<span class='suicide'>[user] hooks [user.p_them()]self to the electropack and spams the trigger! It looks like [user.p_theyre()] trying to commit suicide!</span>")
return (FIRELOSS)
@@ -198,7 +201,17 @@
else
return ..()
/obj/item/electropack/ui_act(action, params)
if(action == "power") // DO. NOT.
return FALSE
return ..()
/obj/item/electropack/shockcollar/ui_interact(mob/user) //note to src: use tgooey
var/dat = {"
<TT>
<B>Frequency/Code</B> for shock collar:<BR>
Frequency:
[format_frequency(src.frequency)]
<A href='byond://?src=[REF(src)];set=freq'>Set</A><BR>
Code:
[src.code]
<A href='byond://?src=[REF(src)];set=code'>Set</A><BR>
</TT>"}
user << browse(dat, "window=radio")
onclose(user, "radio")
return
+7 -7
View File
@@ -729,10 +729,10 @@ GENETICS SCANNER
to_chat(user, "<span class='notice'>[target] is empty!</span>")
if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected
var/instability = round(cached_scan_results["fusion"], 0.01)
var/tier = instability2text(instability)
var/fusion_power = round(cached_scan_results["fusion"], 0.01)
var/tier = fusionpower2text(fusion_power)
to_chat(user, "<span class='boldnotice'>Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.</span>")
to_chat(user, "<span class='notice'>Instability of the last fusion reaction: [instability]\n This indicates it was [tier].</span>")
to_chat(user, "<span class='notice'>Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.</span>")
return
/obj/item/analyzer/proc/scan_turf(mob/user, turf/location)
@@ -783,10 +783,10 @@ GENETICS SCANNER
to_chat(user, "<span class='info'>Temperature: [round(environment.return_temperature()-T0C, 0.01)] &deg;C ([round(environment.return_temperature(), 0.01)] K)</span>")
if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected
var/instability = round(cached_scan_results["fusion"], 0.01)
var/tier = instability2text(instability)
var/fusion_power = round(cached_scan_results["fusion"], 0.01)
var/tier = fusionpower2text(fusion_power)
to_chat(user, "<span class='boldnotice'>Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.</span>")
to_chat(user, "<span class='notice'>Instability of the last fusion reaction: [instability]\n This indicates it was [tier].</span>")
to_chat(user, "<span class='notice'>Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.</span>")
/obj/item/analyzer/ranged
desc = "A hand-held scanner which uses advanced spectroscopy and infrared readings to analyze gases as a distance. Alt-Click to use the built in barometer function."
@@ -992,4 +992,4 @@ GENETICS SCANNER
#undef SCANMODE_CHEMICAL
#undef SCANMODE_WOUND
#undef SCANNER_CONDENSED
#undef SCANNER_VERBOSE
#undef SCANNER_VERBOSE
-3
View File
@@ -234,9 +234,6 @@
/obj/item/melee/rapier/attack(mob/living/target, mob/living/user)
. = ..()
if(iscarbon(target))
if(HAS_TRAIT(user, TRAIT_PACIFISM))
visible_message("<span class='warning'>[user] gently taps [target] with [src].</span>",null,null,COMBAT_MESSAGE_RANGE)
log_combat(user, target, "slept", src)
var/mob/living/carbon/H = target
H.Dizzy(10)
H.adjustStaminaLoss(30)
+3 -6
View File
@@ -291,8 +291,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
force = 7 //how much harm mode damage we do
var/stamina_damage_increment = 4 //how much extra damage do we do when in non-harm mode
force = 9
throwforce = 10
damtype = STAMINA
attack_verb = list("whacked", "smacked", "struck")
@@ -343,19 +342,17 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
/obj/item/melee/bokken/Initialize()
. = ..()
AddElement(/datum/element/sword_point)
if(!harm) //if initialised in non-harm mode, setup force accordingly
force = force + stamina_damage_increment
/obj/item/melee/bokken/attack_self(mob/user)
harm = !harm
if(harm)
force -= stamina_damage_increment
force -= 2
damtype = BRUTE
attack_verb = list("bashed", "smashed", "attacked")
bare_wound_bonus = 15 // having your leg smacked by a wooden stick is probably not great for it if it's naked
wound_bonus = 0
else
force += stamina_damage_increment
force += 2
damtype = STAMINA
attack_verb = list("whacked", "smacked", "struck")
bare_wound_bonus = 0
+1 -9
View File
@@ -143,18 +143,10 @@
var/amt = max(0, ((force - (move_resist * MOVE_FORCE_CRUSH_RATIO)) / (move_resist * MOVE_FORCE_CRUSH_RATIO)) * 10)
take_damage(amt, BRUTE)
#define BLACKLISTED_OBJECTS list(/obj/machinery/power/apc, /obj/machinery/airalarm, /obj/machinery/power/smes, /obj/structure/cable)
/obj/attack_slime(mob/living/simple_animal/slime/user)
if(!user.is_adult)
return
if(src.type in BLACKLISTED_OBJECTS)
return
if(istype(src, /obj/machinery/atmospherics))
return
attack_generic(user, rand(10, 15), BRUTE, "melee", 1)
#undef BLACKLISTED_OBJECTS
attack_generic(user, rand(10, 15), "melee", 1)
/obj/mech_melee_attack(obj/mecha/M)
M.do_attack_animation(src)
+11 -13
View File
@@ -304,20 +304,18 @@
/obj/proc/reskin_obj(mob/M)
if(!LAZYLEN(unique_reskin))
return
var/list/skins = list()
for(var/S in unique_reskin)
skins[S] = image(icon = icon, icon_state = unique_reskin[S])
var/choice = show_radial_menu(M, src, skins, custom_check = CALLBACK(src, .proc/check_skinnable, M), radius = 40, require_near = TRUE)
if(!choice)
return FALSE
icon_state = unique_reskin[choice]
current_skin = choice
return
var/dat = "<b>Reskin options for [name]:</b>\n"
for(var/V in unique_reskin)
var/output = icon2html(src, M, unique_reskin[V])
dat += "[V]: <span class='reallybig'>[output]</span>\n"
to_chat(M, dat)
/obj/proc/check_skinnable(/mob/M)
if(current_skin || !always_reskinnable)
return FALSE
return TRUE
var/choice = input(M, always_reskinnable ? "Choose the a reskin for [src]" : "Warning, you can only reskin [src] once!","Reskin Object") as null|anything in unique_reskin
if(QDELETED(src) || !choice || (current_skin && !always_reskinnable) || M.incapacitated() || !in_range(M,src) || !unique_reskin[choice] || unique_reskin[choice] == current_skin)
return
current_skin = choice
icon_state = unique_reskin[choice]
to_chat(M, "[src] is now skinned as '[choice]'.")
/obj/update_overlays()
. = ..()
@@ -4,6 +4,25 @@
req_access = list(ACCESS_ALL_PERSONAL_LOCKERS)
var/registered_name = null
/obj/structure/closet/secure_closet/personal/examine(mob/user)
. = ..()
if(registered_name)
. += "<span class='notice'>The display reads, \"Owned by [registered_name]\".</span>"
/obj/structure/closet/secure_closet/personal/check_access(obj/item/I)
. = ..()
if(!I || !istype(I))
return
if(istype(I,/obj/item/modular_computer/tablet))
var/obj/item/modular_computer/tablet/ourTablet = I
var/obj/item/computer_hardware/card_slot/card_slot = ourTablet.all_components[MC_CARD]
if(card_slot)
return registered_name == card_slot.stored_card.registered_name || registered_name == card_slot.stored_card2.registered_name
var/obj/item/card/id/ID = I.GetID()
if(ID && registered_name == ID.registered_name)
return TRUE
return FALSE
/obj/structure/closet/secure_closet/personal/PopulateContents()
..()
if(prob(50))
@@ -35,24 +54,15 @@
/obj/structure/closet/secure_closet/personal/attackby(obj/item/W, mob/user, params)
var/obj/item/card/id/I = W.GetID()
if(istype(I))
if(broken)
to_chat(user, "<span class='danger'>It appears to be broken.</span>")
return
if(!I || !I.registered_name)
return
if(allowed(user) || !registered_name || (istype(I) && (registered_name == I.registered_name)))
//they can open all lockers, or nobody owns this, or they own this locker
locked = !locked
update_icon()
if(!registered_name)
registered_name = I.registered_name
desc = "Owned by [I.registered_name]."
else
to_chat(user, "<span class='danger'>Access Denied.</span>")
else
if(!I || !istype(I))
return ..()
if(!can_lock(user, FALSE)) //Can't do anything if there isn't a lock!
return
if(I.registered_name && !registered_name)
to_chat(user, "<span class='notice'>You claim [src].</span>")
registered_name = I.registered_name
else
..()
/obj/structure/closet/secure_closet/personal/handle_lock_addition() //If lock construction is successful we don't care what access the electronics had, so we override it
if(..())
+1 -5
View File
@@ -86,10 +86,6 @@
/obj/structure/grille/attack_animal(mob/user)
. = ..()
if(!user.CheckActionCooldown(CLICK_CD_MELEE))
return
user.DelayNextAction(flush = TRUE)
user.do_attack_animation(src)
if(!shock(user, 70) && !QDELETED(src)) //Last hit still shocks but shouldn't deal damage to the grille)
take_damage(rand(5,10), BRUTE, "melee", 1)
@@ -118,12 +114,12 @@
/obj/structure/grille/attack_alien(mob/living/user)
if(!user.CheckActionCooldown(CLICK_CD_MELEE))
return
user.DelayNextAction(flush = TRUE)
user.do_attack_animation(src)
user.visible_message("<span class='warning'>[user] mangles [src].</span>", null, null, COMBAT_MESSAGE_RANGE)
if(!shock(user, 70))
take_damage(20, BRUTE, "melee", 1)
/obj/structure/grille/CanPass(atom/movable/mover, turf/target)
if(istype(mover) && (mover.pass_flags & PASSGRILLE))
return TRUE
-4
View File
@@ -130,10 +130,6 @@
/proc/get_sfx(soundin)
if(istext(soundin))
switch(soundin)
if ("explosion_creaking") // from skyrat-ss13/skyrat13/pull/3295
soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg')
if ("hull_creaking") // from skyrat-ss13/skyrat13/pull/3295
soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg')
if ("shatter")
soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg')
if ("explosion")
+13
View File
@@ -20,6 +20,8 @@ GLOBAL_LIST(topic_status_cache)
log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!")
SetupExternalRSC()
GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
@@ -85,6 +87,17 @@ GLOBAL_LIST(topic_status_cache)
#endif
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/addtimer, cb, 10 SECONDS))
/world/proc/SetupExternalRSC()
#if (PRELOAD_RSC == 0)
GLOB.external_rsc_urls = world.file2list("[global.config.directory]/external_rsc_urls.txt","\n")
var/i=1
while(i<=GLOB.external_rsc_urls.len)
if(GLOB.external_rsc_urls[i])
i++
else
GLOB.external_rsc_urls.Cut(i,i+1)
#endif
/world/proc/SetupLogs()
var/override_dir = params[OVERRIDE_LOG_DIRECTORY_PARAMETER]
if(!override_dir)
+1 -1
View File
@@ -206,7 +206,7 @@
for(var/datum/ntnet_conversation/chan in chat_channels)
if(chan.id == id)
return chan
// Resets the IDS alarm
/datum/ntnet/proc/resetIDS()
intrusion_detection_alarm = FALSE
+101 -132
View File
@@ -1,12 +1,12 @@
////////////////////////////////
/proc/message_admins(msg)
msg = "<span class=\"admin filter_adminlog\"><span class=\"prefix\">ADMIN LOG:</span> <span class=\"message linkify\">[msg]</span></span>"
to_chat(GLOB.admins, msg, confidential = TRUE)
msg = "<span class=\"admin\"><span class=\"prefix\">ADMIN LOG:</span> <span class=\"message linkify\">[msg]</span></span>"
to_chat(GLOB.admins, msg)
/proc/relay_msg_admins(msg)
msg = "<span class=\"admin filter_adminlog\"><span class=\"prefix\">RELAY:</span> <span class=\"message linkify\">[msg]</span></span>"
to_chat(GLOB.admins, msg, confidential = TRUE)
msg = "<span class=\"admin\"><span class=\"prefix\">RELAY:</span> <span class=\"message linkify\">[msg]</span></span>"
to_chat(GLOB.admins, msg)
///////////////////////////////////////////////////////////////////////////////////////////////Panels
@@ -22,7 +22,7 @@
log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].")
if(!M)
to_chat(usr, "<span class='warning'>You seem to be selecting a mob that doesn't exist anymore.</span>", confidential = TRUE)
to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.")
return
var/body = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Options for [M.key]</title></head>"
@@ -65,7 +65,6 @@
body += "<a href='?_src_=vars;[HrefToken()];Vars=[REF(M)]'>VV</a> - "
if(M.mind)
body += "<a href='?_src_=holder;[HrefToken()];traitor=[REF(M)]'>TP</a> - "
// body += "<a href='?_src_=holder;[HrefToken()];skill=[REF(M)]'>SKILLS</a> - "
else
body += "<a href='?_src_=holder;[HrefToken()];initmind=[REF(M)]'>Init Mind</a> - "
if (iscyborg(M))
@@ -123,7 +122,6 @@
body += "<A href='?_src_=holder;[HrefToken()];traitor=[REF(M)]'>Traitor panel</A> | "
body += "<A href='?_src_=holder;[HrefToken()];narrateto=[REF(M)]'>Narrate to</A> | "
body += "<A href='?_src_=holder;[HrefToken()];subtlemessage=[REF(M)]'>Subtle message</A> | "
// body += "<A href='?_src_=holder;[HrefToken()];playsoundto=[REF(M)]'>Play sound to</A> | "
body += "<A href='?_src_=holder;[HrefToken()];languagemenu=[REF(M)]'>Language Menu</A>"
if (M.client)
@@ -218,7 +216,7 @@
if (!istype(src, /datum/admins))
src = usr.client.holder
if (!istype(src, /datum/admins))
to_chat(usr, "Error: you are not an admin!", confidential = TRUE)
to_chat(usr, "Error: you are not an admin!")
return
var/dat
dat = text("<HEAD><TITLE>Admin Newscaster</TITLE></HEAD><H3>Admin Newscaster Unit</H3>")
@@ -244,7 +242,7 @@
dat+="<BR><HR><A href='?src=[REF(src)];[HrefToken()];ac_set_signature=1'>The newscaster recognises you as:<BR> <FONT COLOR='green'>[src.admin_signature]</FONT></A>"
if(1)
dat+= "Station Feed Channels<HR>"
if( !length(GLOB.news_network.network_channels) )
if( isemptylist(GLOB.news_network.network_channels) )
dat+="<I>No active channels found...</I>"
else
for(var/datum/news/feed_channel/CHANNEL in GLOB.news_network.network_channels)
@@ -297,7 +295,7 @@
dat+="<FONT COLOR='red'><B>ATTENTION: </B></FONT>This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.<BR>"
dat+="No further feed story additions are allowed while the D-Notice is in effect.</FONT><BR><BR>"
else
if( !length(src.admincaster_feed_channel.messages) )
if( isemptylist(src.admincaster_feed_channel.messages) )
dat+="<I>No feed messages found in channel...</I><BR>"
else
var/i = 0
@@ -319,7 +317,7 @@
dat+="<FONT SIZE=1>NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.<BR>"
dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.</FONT>"
dat+="<HR>Select Feed channel to get Stories from:<BR>"
if(!length(GLOB.news_network.network_channels))
if(isemptylist(GLOB.news_network.network_channels))
dat+="<I>No feed channels found active...</I><BR>"
else
for(var/datum/news/feed_channel/CHANNEL in GLOB.news_network.network_channels)
@@ -330,7 +328,7 @@
dat+="<FONT SIZE=1>A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's"
dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed"
dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.</FONT><HR>"
if(!length(GLOB.news_network.network_channels))
if(isemptylist(GLOB.news_network.network_channels))
dat+="<I>No feed channels found active...</I><BR>"
else
for(var/datum/news/feed_channel/CHANNEL in GLOB.news_network.network_channels)
@@ -341,7 +339,7 @@
dat+="<B>[src.admincaster_feed_channel.channel_name]: </B><FONT SIZE=1>\[ created by: <FONT COLOR='maroon'>[src.admincaster_feed_channel.returnAuthor(-1)]</FONT> \]</FONT><BR>"
dat+="<FONT SIZE=2><A href='?src=[REF(src)];[HrefToken()];ac_censor_channel_author=[REF(src.admincaster_feed_channel)]'>[(src.admincaster_feed_channel.authorCensor) ? ("Undo Author censorship") : ("Censor channel Author")]</A></FONT><HR>"
if( !length(src.admincaster_feed_channel.messages) )
if( isemptylist(src.admincaster_feed_channel.messages) )
dat+="<I>No feed messages found in channel...</I><BR>"
else
for(var/datum/news/feed_message/MESSAGE in src.admincaster_feed_channel.messages)
@@ -358,7 +356,7 @@
dat+="<FONT COLOR='red'><B>ATTENTION: </B></FONT>This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.<BR>"
dat+="No further feed story additions are allowed while the D-Notice is in effect.</FONT><BR><BR>"
else
if( !length(src.admincaster_feed_channel.messages) )
if( isemptylist(src.admincaster_feed_channel.messages) )
dat+="<I>No feed messages found in channel...</I><BR>"
else
for(var/datum/news/feed_message/MESSAGE in src.admincaster_feed_channel.messages)
@@ -428,6 +426,7 @@
"}
if(GLOB.master_mode == "secret")
dat += "<A href='?src=[REF(src)];[HrefToken()];f_secret=1'>(Force Secret Mode)</A><br>"
if(GLOB.master_mode == "dynamic")
if(SSticker.current_state <= GAME_STATE_PREGAME)
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart=1'>(Force Roundstart Rulesets)</A><br>"
@@ -450,6 +449,7 @@
dat += "<hr/>"
if(SSticker.IsRoundInProgress())
dat += "<a href='?src=[REF(src)];[HrefToken()];gamemode_panel=1'>(Game Mode Panel)</a><BR>"
dat += {"
<BR>
<A href='?src=[REF(src)];[HrefToken()];create_object=1'>Create Object</A><br>
@@ -461,7 +461,7 @@
if(marked_datum && istype(marked_datum, /atom))
dat += "<A href='?src=[REF(src)];[HrefToken()];dupe_marked_datum=1'>Duplicate Marked Datum</A><br>"
usr << browse(dat, "window=admin2;size=240x280")
usr << browse(dat, "window=admin2;size=210x200")
return
/////////////////////////////////////////////////////////////////////////////////////////////////admins2.dm merge
@@ -475,42 +475,33 @@
if (!usr.client.holder)
return
var/localhost_addresses = list("127.0.0.1", "::1")
var/list/options = list("Regular Restart", "Regular Restart (with delay)", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)")
var/list/options = list("Regular Restart", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)")
if(world.TgsAvailable())
options += "Server Restart (Kill and restart DD)";
var/rebootconfirm
if(SSticker.admin_delay_notice)
if(alert(usr, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") != "Yes")
return FALSE
var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options
if(result)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Reboot World") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]."
switch(result)
if("Regular Restart")
if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses)))
if(alert("Are you sure you want to restart the server?","This server is live","Restart","Cancel") != "Restart")
return FALSE
SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10)
if("Regular Restart (with delay)")
var/delay = input("What delay should the restart have (in seconds)?", "Restart Delay", 5) as num|null
if(!delay)
return FALSE
if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses)))
if(alert("Are you sure you want to restart the server?","This server is live","Restart","Cancel") != "Restart")
return FALSE
SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", delay * 10)
if("Hard Restart (No Delay, No Feeback Reason)")
to_chat(world, "World reboot - [init_by]")
world.Reboot()
if("Hardest Restart (No actions, just reboot)")
to_chat(world, "Hard world reboot - [init_by]")
world.Reboot(fast_track = TRUE)
if("Server Restart (Kill and restart DD)")
to_chat(world, "Server restart - [init_by]")
world.TgsEndProcess()
if(alert(usr, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") == "Yes")
rebootconfirm = TRUE
else
rebootconfirm = TRUE
if(rebootconfirm)
var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options
if(result)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Reboot World") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]."
switch(result)
if("Regular Restart")
SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10)
if("Hard Restart (No Delay, No Feeback Reason)")
to_chat(world, "World reboot - [init_by]")
world.Reboot()
if("Hardest Restart (No actions, just reboot)")
to_chat(world, "Hard world reboot - [init_by]")
world.Reboot(fast_track = TRUE)
if("Server Restart (Kill and restart DD)")
to_chat(world, "Server restart - [init_by]")
world.TgsEndProcess()
/datum/admins/proc/end_round()
set category = "Server"
@@ -538,7 +529,7 @@
if(message)
if(!check_rights(R_SERVER,0))
message = adminscrub(message,500)
to_chat(world, "<span class='adminnotice'><b>[usr.client.holder.fakekey ? "Administrator" : usr.key] Announces:</b></span>\n \t [message]", confidential = TRUE)
to_chat(world, "<span class='adminnotice'><b>[usr.client.holder.fakekey ? "Administrator" : usr.key] Announces:</b></span>\n \t [message]")
log_admin("Announce: [key_name(usr)] : [message]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Announce") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -560,7 +551,7 @@
else
message_admins("[key_name(usr)] set the admin notice.")
log_admin("[key_name(usr)] set the admin notice:\n[new_admin_notice]")
to_chat(world, "<span class='adminnotice'><b>Admin Notice:</b>\n \t [new_admin_notice]</span>", confidential = TRUE)
to_chat(world, "<span class ='adminnotice'><b>Admin Notice:</b>\n \t [new_admin_notice]</span>")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Admin Notice") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
GLOB.admin_notice = new_admin_notice
return
@@ -607,29 +598,20 @@
set desc="Start the round RIGHT NOW"
set name="Start Now"
if(SSticker.current_state == GAME_STATE_PREGAME || SSticker.current_state == GAME_STATE_STARTUP)
if(!SSticker.start_immediately)
var/localhost_addresses = list("127.0.0.1", "::1")
if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses)))
if(alert("Are you sure you want to start the round?","Start Now","Start Now","Cancel") != "Start Now")
return FALSE
SSticker.start_immediately = TRUE
log_admin("[usr.key] has started the game.")
var/msg = ""
if(SSticker.current_state == GAME_STATE_STARTUP)
msg = " (The server is still setting up, but the round will be \
started as soon as possible.)"
message_admins("<font color='blue'>[usr.key] has started the game.[msg]</font>")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Start Now") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return TRUE
SSticker.start_immediately = FALSE
SSticker.SetTimeLeft(1800)
to_chat(world, "<b>The game will start in 180 seconds.</b>")
SEND_SOUND(world, sound(get_announcer_sound("attention")))
message_admins("<font color='blue'>[usr.key] has cancelled immediate game start. Game will start in 180 seconds.</font>")
log_admin("[usr.key] has cancelled immediate game start.")
SSticker.start_immediately = TRUE
log_admin("[usr.key] has started the game.")
var/msg = ""
if(SSticker.current_state == GAME_STATE_STARTUP)
msg = " (The server is still setting up, but the round will be \
started as soon as possible.)"
message_admins("<font color='blue'>\
[usr.key] has started the game.[msg]</font>")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Start Now") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return 1
else
to_chat(usr, "<font color='red'>Error: Start Now: Game has already started.</font>")
return FALSE
return 0
/datum/admins/proc/toggleenter()
set category = "Server"
@@ -637,9 +619,9 @@
set name="Toggle Entering"
GLOB.enter_allowed = !( GLOB.enter_allowed )
if (!( GLOB.enter_allowed ))
to_chat(world, "<B>New players may no longer enter the game.</B>", confidential = TRUE)
to_chat(world, "<B>New players may no longer enter the game.</B>")
else
to_chat(world, "<B>New players may now enter the game.</B>", confidential = TRUE)
to_chat(world, "<B>New players may now enter the game.</B>")
log_admin("[key_name(usr)] toggled new player game entering.")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled new player game entering.</span>")
world.update_status()
@@ -652,9 +634,9 @@
var/alai = CONFIG_GET(flag/allow_ai)
CONFIG_SET(flag/allow_ai, !alai)
if (alai)
to_chat(world, "<B>The AI job is no longer chooseable.</B>", confidential = TRUE)
to_chat(world, "<B>The AI job is no longer chooseable.</B>")
else
to_chat(world, "<B>The AI job is chooseable now.</B>", confidential = TRUE)
to_chat(world, "<B>The AI job is chooseable now.</B>")
log_admin("[key_name(usr)] toggled AI allowed.")
world.update_status()
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle AI", "[!alai ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -672,7 +654,7 @@
aiPlayer.end_multicam()
log_admin("[key_name(usr)] toggled AI multicam.")
world.update_status()
to_chat(GLOB.ai_list | GLOB.admins, "<B>The AI [almcam ? "no longer" : "now"] has multicam.</B>", confidential = TRUE)
to_chat(GLOB.ai_list | GLOB.admins, "<B>The AI [almcam ? "no longer" : "now"] has multicam.</B>")
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Multicam", "[!almcam ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/datum/admins/proc/toggleaban()
@@ -682,9 +664,9 @@
var/new_nores = !CONFIG_GET(flag/norespawn)
CONFIG_SET(flag/norespawn, new_nores)
if (!new_nores)
to_chat(world, "<B>You may now respawn.</B>", confidential = TRUE)
to_chat(world, "<B>You may now respawn.</B>")
else
to_chat(world, "<B>You may no longer respawn :(</B>", confidential = TRUE)
to_chat(world, "<B>You may no longer respawn :(</B>")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled respawn to [!new_nores ? "On" : "Off"].</span>")
log_admin("[key_name(usr)] toggled respawn to [!new_nores ? "On" : "Off"].")
world.update_status()
@@ -693,7 +675,7 @@
/datum/admins/proc/delay()
set category = "Server"
set desc="Delay the game start"
set name="Delay Pre-Game"
set name="Delay pre-game"
var/newtime = input("Set a new time in seconds. Set -1 for indefinite delay.","Set Delay",round(SSticker.GetTimeLeft()/10)) as num|null
if(SSticker.current_state > GAME_STATE_PREGAME)
@@ -701,12 +683,11 @@
if(newtime)
newtime = newtime*10
SSticker.SetTimeLeft(newtime)
SSticker.start_immediately = FALSE
if(newtime < 0)
to_chat(world, "<b>The game start has been delayed.</b>", confidential = TRUE)
to_chat(world, "<b>The game start has been delayed.</b>")
log_admin("[key_name(usr)] delayed the round start.")
else
to_chat(world, "<b>The game will start in [DisplayTimeText(newtime)].</b>", confidential = TRUE)
to_chat(world, "<b>The game will start in [DisplayTimeText(newtime)].</b>")
SEND_SOUND(world, sound(get_announcer_sound("attention")))
log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delay Game Start") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -743,28 +724,20 @@
set desc = "(atom path) Spawn an atom"
set name = "Spawn"
if(!check_rights(R_SPAWN) || !object)
return
var/list/preparsed = splittext(object,":")
var/path = preparsed[1]
var/amount = 1
if(preparsed.len > 1)
amount = clamp(text2num(preparsed[2]),1, 50) //50 at a time!
var/chosen = pick_closest_path(path)
if(!chosen)
if(!check_rights(R_SPAWN))
return
var/turf/T = get_turf(usr)
var/chosen = pick_closest_path(object)
if(!chosen)
return
if(ispath(chosen, /turf))
T.ChangeTurf(chosen)
else
for(var/i in 1 to amount)
var/atom/A = new chosen(T)
A.flags_1 |= ADMIN_SPAWNED_1
var/atom/A = new chosen(T)
A.flags_1 |= ADMIN_SPAWNED_1
log_admin("[key_name(usr)] spawned [amount] x [chosen] at [AREACOORD(usr)]")
log_admin("[key_name(usr)] spawned [chosen] at [AREACOORD(usr)]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/datum/admins/proc/podspawn_atom(object as text)
@@ -809,18 +782,20 @@
log_admin("[key_name(usr)] spawned cargo pack [chosen] at [AREACOORD(usr)]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Cargo") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/datum/admins/proc/show_traitor_panel(mob/target_mob in GLOB.mob_list)
/datum/admins/proc/show_traitor_panel(mob/M in GLOB.mob_list)
set category = "Admin"
set desc = "Edit mobs's memory and role"
set name = "Show Traitor Panel"
var/datum/mind/target_mind = target_mob.mind
if(!target_mind)
to_chat(usr, "This mob has no mind!", confidential = TRUE)
if(!istype(M))
to_chat(usr, "This can only be used on instances of type /mob")
return
if(!istype(target_mob) && !istype(target_mind))
to_chat(usr, "This can only be used on instances of type /mob and /mind", confidential = TRUE)
if(!M.mind)
to_chat(usr, "This mob has no mind!")
return
target_mind.traitor_panel()
M.mind.traitor_panel()
SSblackbox.record_feedback("tally", "admin_verb", 1, "Traitor Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -830,9 +805,9 @@
set name="Toggle tinted welding helmes"
GLOB.tinted_weldhelh = !( GLOB.tinted_weldhelh )
if (GLOB.tinted_weldhelh)
to_chat(world, "<B>The tinted_weldhelh has been enabled!</B>", confidential = TRUE)
to_chat(world, "<B>The tinted_weldhelh has been enabled!</B>")
else
to_chat(world, "<B>The tinted_weldhelh has been disabled!</B>", confidential = TRUE)
to_chat(world, "<B>The tinted_weldhelh has been disabled!</B>")
log_admin("[key_name(usr)] toggled tinted_weldhelh.")
message_admins("[key_name_admin(usr)] toggled tinted_weldhelh.")
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Tinted Welding Helmets", "[GLOB.tinted_weldhelh ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -844,9 +819,9 @@
var/new_guest_ban = !CONFIG_GET(flag/guest_ban)
CONFIG_SET(flag/guest_ban, new_guest_ban)
if (new_guest_ban)
to_chat(world, "<B>Guests may no longer enter the game.</B>", confidential = TRUE)
to_chat(world, "<B>Guests may no longer enter the game.</B>")
else
to_chat(world, "<B>Guests may now enter the game.</B>", confidential = TRUE)
to_chat(world, "<B>Guests may now enter the game.</B>")
log_admin("[key_name(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.</span>")
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Guests", "[!new_guest_ban ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -857,37 +832,37 @@
var/mob/living/silicon/S = i
ai_number++
if(isAI(S))
to_chat(usr, "<b>AI [key_name(S, usr)]'s laws:</b>", confidential = TRUE)
to_chat(usr, "<b>AI [key_name(S, usr)]'s laws:</b>")
else if(iscyborg(S))
var/mob/living/silicon/robot/R = S
to_chat(usr, "<b>CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [key_name(R.connected_ai)])":"(Independent)"]: laws:</b>", confidential = TRUE)
to_chat(usr, "<b>CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [key_name(R.connected_ai)])":"(Independent)"]: laws:</b>")
else if (ispAI(S))
to_chat(usr, "<b>pAI [key_name(S, usr)]'s laws:</b>", confidential = TRUE)
to_chat(usr, "<b>pAI [key_name(S, usr)]'s laws:</b>")
else
to_chat(usr, "<b>SOMETHING SILICON [key_name(S, usr)]'s laws:</b>", confidential = TRUE)
to_chat(usr, "<b>SOMETHING SILICON [key_name(S, usr)]'s laws:</b>")
if (S.laws == null)
to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.", confidential = TRUE)
to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.")
else
S.laws.show_laws(usr)
if(!ai_number)
to_chat(usr, "<b>No AIs located</b>" , confidential = TRUE)
to_chat(usr, "<b>No AIs located</b>" )
/datum/admins/proc/output_all_devil_info()
var/devil_number = 0
for(var/datum/mind/D in SSticker.mode.devils)
devil_number++
var/datum/antagonist/devil/devil = D.has_antag_datum(/datum/antagonist/devil)
to_chat(usr, "Devil #[devil_number]:<br><br>" + devil.printdevilinfo(), confidential = TRUE)
to_chat(usr, "Devil #[devil_number]:<br><br>" + devil.printdevilinfo())
if(!devil_number)
to_chat(usr, "<b>No Devils located</b>" , confidential = TRUE)
to_chat(usr, "<b>No Devils located</b>" )
/datum/admins/proc/output_devil_info(mob/living/M)
if(is_devil(M))
var/datum/antagonist/devil/devil = M.mind.has_antag_datum(/datum/antagonist/devil)
to_chat(usr, devil.printdevilinfo(), confidential = TRUE)
to_chat(usr, devil.printdevilinfo())
else
to_chat(usr, "<b>[M] is not a devil.", confidential = TRUE)
to_chat(usr, "<b>[M] is not a devil.")
/datum/admins/proc/manage_free_slots()
if(!check_rights())
@@ -990,21 +965,21 @@
if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk
continue
if(message)
to_chat(C, message, confidential = TRUE)
to_chat(C, message)
kicked_client_names.Add("[C.key]")
qdel(C)
return kicked_client_names
//returns TRUE to let the dragdrop code know we are trapping this event
//returns FALSE if we don't plan to trap the event
//returns 1 to let the dragdrop code know we are trapping this event
//returns 0 if we don't plan to trap the event
/datum/admins/proc/cmd_ghost_drag(mob/dead/observer/frommob, mob/tomob)
//this is the exact two check rights checks required to edit a ckey with vv.
if (!check_rights(R_VAREDIT,0) || !check_rights(R_SPAWN|R_DEBUG,0))
return FALSE
return 0
if (!frommob.ckey)
return FALSE
return 0
var/question = ""
if (tomob.ckey)
@@ -1013,18 +988,12 @@
var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No")
if (ask != "Yes")
return TRUE
return 1
if (!frommob || !tomob) //make sure the mobs don't go away while we waited for a response
return TRUE
return 1
// Disassociates observer mind from the body mind
if(tomob.client)
tomob.ghostize(FALSE)
else
for(var/mob/dead/observer/ghost in GLOB.dead_mob_list)
if(tomob.mind == ghost.mind)
ghost.mind = null
tomob.ghostize(0)
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has put [frommob.key] in control of [tomob.name].</span>")
log_admin("[key_name(usr)] stuffed [frommob.key] into [tomob.name].")
@@ -1033,7 +1002,7 @@
tomob.ckey = frommob.ckey
qdel(frommob)
return TRUE
return 1
/client/proc/adminGreet(logout)
if(SSticker.HasRoundStarted())
+11 -31
View File
@@ -4,39 +4,19 @@
var/F = file("[GLOB.log_directory]/[subject].html")
WRITE_FILE(F, "<small>[TIME_STAMP("hh:mm:ss", FALSE)] [REF(src)] ([x],[y],[z])</small> || [src] [message]<br>")
/client/proc/investigate_show()
/client/proc/investigate_show(subject in list("notes, memos, watchlist", INVESTIGATE_RCD, INVESTIGATE_RESEARCH, INVESTIGATE_EXONET, INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS, INVESTIGATE_RADIATION, INVESTIGATE_CIRCUIT, INVESTIGATE_NANITES, INVESTIGATE_CRYOGENICS) )
set name = "Investigate"
set category = "Admin"
if(!holder)
return
var/list/investigates = list(INVESTIGATE_RCD, INVESTIGATE_RESEARCH, INVESTIGATE_EXONET, INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS, INVESTIGATE_RADIATION, INVESTIGATE_CIRCUIT, INVESTIGATE_NANITES, INVESTIGATE_CRYOGENICS)
var/list/logs_present = list("notes, memos, watchlist")
var/list/logs_missing = list("---")
for(var/subject in investigates)
var/temp_file = file("[GLOB.log_directory]/[subject].html")
if(fexists(temp_file))
logs_present += subject
switch(subject)
if("notes, memos, watchlist")
if(!check_rights(R_ADMIN))
return
browse_messages()
else
logs_missing += "[subject] (empty)"
var/list/combined = sortList(logs_present) + sortList(logs_missing)
var/selected = input("Investigate what?", "Investigate") as null|anything in combined
if(!(selected in combined) || selected == "---")
return
selected = replacetext(selected, " (empty)", "")
if(selected == "notes, memos, watchlist" && check_rights(R_ADMIN))
browse_messages()
return
var/F = file("[GLOB.log_directory]/[selected].html")
if(!fexists(F))
to_chat(src, "<span class='danger'>No [selected] logfile was found.</span>", confidential = TRUE)
return
src << browse(F,"window=investigate[selected];size=800x300")
var/F = file("[GLOB.log_directory]/[subject].html")
if(!fexists(F))
to_chat(src, "<span class='danger'>No [subject] logfile was found.</span>")
return
src << browse(F,"window=investigate[subject];size=800x300")
+21 -24
View File
@@ -3,7 +3,7 @@
set desc = "Area to jump to"
set category = "Admin"
if(!src.holder)
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
to_chat(src, "Only administrators may use this command.")
return
if(!A)
@@ -15,22 +15,20 @@
continue
turfs.Add(T)
if(length(turfs))
var/turf/T = pick(turfs)
usr.forceMove(T)
log_admin("[key_name(usr)] jumped to [AREACOORD(T)]")
message_admins("[key_name_admin(usr)] jumped to [AREACOORD(T)]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Area") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
else
to_chat(src, "Nowhere to jump to!", confidential = TRUE)
var/turf/T = safepick(turfs)
if(!T)
to_chat(src, "Nowhere to jump to!")
return
usr.forceMove(T)
log_admin("[key_name(usr)] jumped to [AREACOORD(A)]")
message_admins("[key_name_admin(usr)] jumped to [AREACOORD(A)]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Area") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/jumptoturf(turf/T in world)
set name = "Jump to Turf"
set category = "Admin"
if(!src.holder)
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
to_chat(src, "Only administrators may use this command.")
return
log_admin("[key_name(usr)] jumped to [AREACOORD(T)]")
@@ -44,7 +42,7 @@
set name = "Jump to Mob"
if(!src.holder)
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
to_chat(src, "Only administrators may use this command.")
return
log_admin("[key_name(usr)] jumped to [key_name(M)]")
@@ -56,14 +54,14 @@
SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
A.forceMove(M.loc)
else
to_chat(A, "This mob is not located in the game world.", confidential = TRUE)
to_chat(A, "This mob is not located in the game world.")
/client/proc/jumptocoord(tx as num, ty as num, tz as num)
set category = "Admin"
set name = "Jump to Coordinate"
if (!holder)
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
to_chat(src, "Only administrators may use this command.")
return
if(src.mob)
@@ -78,7 +76,7 @@
set name = "Jump to Key"
if(!src.holder)
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
to_chat(src, "Only administrators may use this command.")
return
var/list/keys = list()
@@ -86,7 +84,7 @@
keys += M.client
var/client/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys)
if(!selection)
to_chat(src, "No keys found.", confidential = TRUE)
to_chat(src, "No keys found.")
return
var/mob/M = selection.mob
log_admin("[key_name(usr)] jumped to [key_name(M)]")
@@ -101,7 +99,7 @@
set name = "Get Mob"
set desc = "Mob to teleport"
if(!src.holder)
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
to_chat(src, "Only administrators may use this command.")
return
var/atom/loc = get_turf(usr)
@@ -118,7 +116,7 @@
set desc = "Key to teleport"
if(!src.holder)
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
to_chat(src, "Only administrators may use this command.")
return
var/list/keys = list()
@@ -144,17 +142,16 @@
set category = "Admin"
set name = "Send Mob"
if(!src.holder)
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
to_chat(src, "Only administrators may use this command.")
return
var/area/A = input(usr, "Pick an area.", "Pick an area") in GLOB.sortedAreas|null
if(A && istype(A))
var/list/turfs = get_area_turfs(A)
if(length(turfs) && M.forceMove(pick(turfs)))
if(M.forceMove(safepick(get_area_turfs(A))))
log_admin("[key_name(usr)] teleported [key_name(M)] to [AREACOORD(M)]")
var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [AREACOORD(M)]"
log_admin("[key_name(usr)] teleported [key_name(M)] to [AREACOORD(A)]")
var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [AREACOORD(A)]"
message_admins(msg)
admin_ticket_log(M, msg)
else
to_chat(src, "Failed to move mob to a valid location.", confidential = TRUE)
to_chat(src, "Failed to move mob to a valid location.")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Send Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+83 -112
View File
@@ -1,11 +1,12 @@
#define EXTERNALREPLYCOUNT 2
#define IRCREPLYCOUNT 2
//allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm
/client/proc/cmd_admin_pm_context(mob/M in GLOB.mob_list)
set category = null
set name = "Admin PM Mob"
if(!holder)
to_chat(src, "<span class='danger'>Error: Admin-PM-Context: Only administrators may use this command.</span>", confidential = TRUE)
to_chat(src, "<span class='danger'>Error: Admin-PM-Context: Only administrators may use this command.</span>")
return
if( !ismob(M) || !M.client )
return
@@ -17,7 +18,7 @@
set category = "Admin"
set name = "Admin PM"
if(!holder)
to_chat(src, "<span class='danger'>Error: Admin-PM-Panel: Only administrators may use this command.</span>", confidential = TRUE)
to_chat(src, "<span class='danger'>Error: Admin-PM-Panel: Only administrators may use this command.</span>")
return
var/list/client/targets[0]
for(var/client/T)
@@ -36,7 +37,7 @@
/client/proc/cmd_ahelp_reply(whom)
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>", confidential = TRUE)
to_chat(src, "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>")
return
var/client/C
if(istext(whom))
@@ -47,61 +48,45 @@
C = whom
if(!C)
if(holder)
to_chat(src, "<span class='danger'>Error: Admin-PM: Client not found.</span>", confidential = TRUE)
to_chat(src, "<span class='danger'>Error: Admin-PM: Client not found.</span>")
return
var/datum/admin_help/AH = C.current_ticket
if(AH)
message_admins("[key_name_admin(src)] has started replying to [key_name_admin(C, 0, 0)]'s admin help.")
message_admins("[key_name_admin(src)] has started replying to [key_name(C, 0, 0)]'s admin help.")
var/msg = input(src,"Message:", "Private message to [C.holder?.fakekey ? "an Administrator" : key_name(C, 0, 0)].") as message|null
if (!msg)
message_admins("[key_name_admin(src)] has cancelled their reply to [key_name_admin(C, 0, 0)]'s admin help.")
message_admins("[key_name_admin(src)] has cancelled their reply to [key_name(C, 0, 0)]'s admin help.")
return
if(!C) //We lost the client during input, disconnected or relogged.
if(GLOB.directory[AH.initiator_ckey]) // Client has reconnected, lets try to recover
whom = GLOB.directory[AH.initiator_ckey]
else
to_chat(src, "<span class='danger'>Error: Admin-PM: Client not found.</span>", confidential = TRUE)
to_chat(src, "<span class='danger'><b>Message not sent:</b></span><br>[msg]", confidential = TRUE)
AH.AddInteraction("<b>No client found, message not sent:</b><br>[msg]")
return
cmd_admin_pm(whom, msg)
//takes input from cmd_admin_pm_context, cmd_admin_pm_panel or /client/Topic and sends them a PM.
//Fetching a message if needed. src is the sender and C is the target client
/client/proc/cmd_admin_pm(whom, msg)
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>", confidential = TRUE)
to_chat(src, "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>")
return
if(!holder && !current_ticket) //no ticket? https://www.youtube.com/watch?v=iHSPf6x1Fdo
to_chat(src, "<span class='danger'>You can no longer reply to this ticket, please open another one by using the Adminhelp verb if need be.</span>", confidential = TRUE)
to_chat(src, "<span class='notice'>Message: [msg]</span>", confidential = TRUE)
to_chat(src, "<span class='danger'>You can no longer reply to this ticket, please open another one by using the Adminhelp verb if need be.</span>")
to_chat(src, "<span class='notice'>Message: [msg]</span>")
return
var/client/recipient
var/recipient_ckey // Stored in case client is deleted between this and after the message is input
var/datum/admin_help/recipient_ticket // Stored in case client is deleted between this and after the message is input
var/external = 0
var/irc = 0
if(istext(whom))
if(whom[1] == "@")
whom = findStealthKey(whom)
if(whom == "IRCKEY")
external = 1
irc = 1
else
recipient = GLOB.directory[whom]
else if(istype(whom, /client))
recipient = whom
if(!recipient)
to_chat(src, "<span class='danger'>Error: Admin-PM: Client not found.</span>", confidential = TRUE)
return
recipient_ckey = recipient.ckey
recipient_ticket = recipient.current_ticket
if(external)
if(irc)
if(!ircreplyamount) //to prevent people from spamming irc/discord
return
if(!msg)
@@ -110,11 +95,21 @@
if(!msg)
return
if(holder)
to_chat(src, "<span class='danger'>Error: Use the admin IRC/Discord channel, nerd.</span>", confidential = TRUE)
to_chat(src, "<span class='danger'>Error: Use the admin IRC channel, nerd.</span>")
return
else
if(!recipient)
if(holder)
to_chat(src, "<span class='danger'>Error: Admin-PM: Client not found.</span>")
if(msg)
to_chat(src, msg)
return
else if(msg) // you want to continue if there's no message instead of returning now
current_ticket.MessageNoRecipient(msg)
return
//get message text, limit it's length.and clean/escape html
if(!msg)
msg = input(src,"Message:", "Private message to [recipient.holder?.fakekey ? "an Administrator" : key_name(recipient, 0, 0)].") as message|null
@@ -122,30 +117,22 @@
if(!msg)
return
if(!recipient)
if(GLOB.directory[recipient_ckey]) // Client has reconnected, lets try to recover
recipient = GLOB.directory[recipient_ckey]
else
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>")
return
if(!recipient)
if(holder)
to_chat(src, "<span class='danger'>Error: Admin-PM: Client not found.</span>", confidential = TRUE)
to_chat(src, "<span class='danger'><b>Message not sent:</b></span><br>[msg]", confidential = TRUE)
if(recipient_ticket)
recipient_ticket.AddInteraction("<b>No client found, message not sent:</b><br>[msg]")
return
to_chat(src, "<span class='danger'>Error: Admin-PM: Client not found.</span>")
else
current_ticket.MessageNoRecipient(msg)
return
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>", confidential = TRUE)
return
return
if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
return
//clean the message if it's not sent by a high-rank admin
if(!check_rights(R_SERVER|R_DEBUG,0)||external)//no sending html to the poor bots
if(!check_rights(R_SERVER|R_DEBUG,0)||irc)//no sending html to the poor bots
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
if(!msg)
return
@@ -157,33 +144,28 @@
var/keywordparsedmsg = keywords_lookup(msg)
if(external)
to_chat(src, "<span class='notice'>PM to-<b>Admins</b>: <span class='linkify'>[rawmsg]</span></span>", confidential = TRUE)
var/datum/admin_help/AH = admin_ticket_log(src, "<font color='red'>Reply PM from-<b>[key_name(src, TRUE, TRUE)]</b> to <i>External</i>: [keywordparsedmsg]</font>")
if(irc)
to_chat(src, "<span class='notice'>PM to-<b>Admins</b>: <span class='linkify'>[rawmsg]</span></span>")
var/datum/admin_help/AH = admin_ticket_log(src, "<font color='red'>Reply PM from-<b>[key_name(src, TRUE, TRUE)] to <i>IRC</i>: [keywordparsedmsg]</font>")
ircreplyamount--
send2irc("[AH ? "#[AH.id] " : ""]Reply: [ckey]", rawmsg)
else
var/badmin = FALSE //Lets figure out if an admin is getting bwoinked.
if(holder && recipient.holder && !current_ticket) //Both are admins, and this is not a reply to our own ticket.
badmin = TRUE
if(recipient.holder && !badmin)
if(holder)
to_chat(recipient, "<span class='danger'>Admin PM from-<b>[key_name(src, recipient, 1)]</b>: <span class='linkify'>[keywordparsedmsg]</span></span>", confidential = TRUE)
to_chat(src, "<span class='notice'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: <span class='linkify'>[keywordparsedmsg]</span></span>", confidential = TRUE)
if(recipient.holder)
if(holder) //both are admins
to_chat(recipient, "<span class='danger'>Admin PM from-<b>[key_name(src, recipient, 1)]</b>: <span class='linkify'>[keywordparsedmsg]</span></span>")
to_chat(src, "<span class='notice'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: <span class='linkify'>[keywordparsedmsg]</span></span>")
//omg this is dumb, just fill in both their tickets
var/interaction_message = "<font color='purple'>PM from-<b>[key_name(src, recipient, 1)]</b> to-<b>[key_name(recipient, src, 1)]</b>: [keywordparsedmsg]</font>"
admin_ticket_log(src, interaction_message)
if(recipient != src) //reeee
admin_ticket_log(recipient, interaction_message)
// SSblackbox.LogAhelp(current_ticket.id, "Reply", msg, recipient.ckey, src.ckey)
else //recipient is an admin but sender is not
var/replymsg = "Reply PM from-<b>[key_name(src, recipient, 1)]</b>: <span class='linkify'>[keywordparsedmsg]</span>"
admin_ticket_log(src, "<font color='red'>[replymsg]</font>")
to_chat(recipient, "<span class='danger'>[replymsg]</span>", confidential = TRUE)
to_chat(src, "<span class='notice'>PM to-<b>Admins</b>: <span class='linkify'>[msg]</span></span>", confidential = TRUE)
// SSblackbox.LogAhelp(current_ticket.id, "Reply", msg, recipient.ckey, src.ckey)
to_chat(recipient, "<span class='danger'>[replymsg]</span>")
to_chat(src, "<span class='notice'>PM to-<b>Admins</b>: <span class='linkify'>[msg]</span></span>")
//play the receiving admin the adminhelp sound (if they have them enabled)
if(recipient.prefs.toggles & SOUND_ADMINHELP)
@@ -191,88 +173,78 @@
else
if(holder) //sender is an admin but recipient is not. Do BIG RED TEXT
//var/already_logged = FALSE
if(!recipient.current_ticket)
new /datum/admin_help(msg, recipient, TRUE)
//already_logged = TRUE
// SSblackbox.LogAhelp(recipient.current_ticket.id, "Ticket Opened", msg, recipient.ckey, src.ckey)
to_chat(recipient, "<font color='red' size='4'><b>-- Administrator private message --</b></font>", confidential = TRUE)
to_chat(recipient, "<span class='adminsay'>Admin PM from-<b>[key_name(src, recipient, 0)]</b>: <span class='linkify'>[msg]</span></span>", confidential = TRUE)
to_chat(recipient, "<span class='adminsay'><i>Click on the administrator's name to reply.</i></span>", confidential = TRUE)
to_chat(src, "<span class='notice'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: <span class='linkify'>[msg]</span></span>", confidential = TRUE)
to_chat(recipient, "<font color='red' size='4'><b>-- Administrator private message --</b></font>")
to_chat(recipient, "<span class='danger'>Admin PM from-<b>[key_name(src, recipient, 0)]</b>: <span class='linkify'>[msg]</span></span>")
to_chat(recipient, "<span class='danger'><i>Click on the administrator's name to reply.</i></span>")
to_chat(src, "<span class='notice'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: <span class='linkify'>[msg]</span></span>")
admin_ticket_log(recipient, "<font color='purple'>PM From [key_name_admin(src)]: [keywordparsedmsg]</font>")
// if(!already_logged) //Reply to an existing ticket
// SSblackbox.LogAhelp(recipient.current_ticket.id, "Reply", msg, recipient.ckey, src.ckey)
//always play non-admin recipients the adminhelp sound
SEND_SOUND(recipient, sound('sound/effects/adminhelp.ogg'))
//AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn
if(CONFIG_GET(flag/popup_admin_pm))
INVOKE_ASYNC(src, .proc/popup_admin_pm, recipient, msg)
spawn() //so we don't hold the caller proc up. Please functionalize this
var/sender = src
var/sendername = key
var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as message|null //show message and await a reply
if(recipient && reply)
if(sender)
recipient.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them
else
adminhelp(reply) //sender has left, adminhelp instead
return
else //neither are admins
to_chat(src, "<span class='danger'>Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.</span>", confidential = TRUE)
to_chat(src, "<span class='danger'>Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.</span>")
return
if(external)
log_admin_private("PM: [key_name(src)]->External: [rawmsg]")
if(irc)
log_admin_private("PM: [key_name(src)]->IRC: [rawmsg]")
for(var/client/X in GLOB.admins)
to_chat(X, "<span class='notice'><B>PM: [key_name(src, X, 0)]-&gt;External:</B> [keywordparsedmsg]</span>", confidential = TRUE)
to_chat(X, "<span class='notice'><B>PM: [key_name(src, X, 0)]-&gt;IRC:</B> [keywordparsedmsg]</span>")
else
window_flash(recipient, ignorepref = TRUE)
log_admin_private("PM: [key_name(src)]->[key_name(recipient)]: [rawmsg]")
//we don't use message_admins here because the sender/receiver might get it too
for(var/client/X in GLOB.admins)
if(X.key!=key && X.key!=recipient.key) //check client/X is an admin and isn't the sender or recipient
to_chat(X, "<span class='notice'><B>PM: [key_name(src, X, 0)]-&gt;[key_name(recipient, X, 0)]:</B> [keywordparsedmsg]</span>" , confidential = TRUE)
/client/proc/popup_admin_pm(client/recipient, msg)
var/sender = src
var/sendername = key
var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as message|null //show message and await a reply
if(recipient && reply)
if(sender)
recipient.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them
else
adminhelp(reply) //sender has left, adminhelp instead
to_chat(X, "<span class='notice'><B>PM: [key_name(src, X, 0)]-&gt;[key_name(recipient, X, 0)]:</B> [keywordparsedmsg]</span>" )
#define IRC_AHELP_USAGE "Usage: ticket <close|resolve|icissue|reject|reopen \[ticket #\]|list>"
/proc/IrcPm(target,msg,sender)
return TgsPm(target,msg,sender) //compatability moment.
#define TGS_AHELP_USAGE "Usage: ticket <close|resolve|icissue|reject|reopen \[ticket #\]|list>"
/proc/TgsPm(target,msg,sender)
target = ckey(target)
var/client/C = GLOB.directory[target]
var/datum/admin_help/ticket = C ? C.current_ticket : GLOB.ahelp_tickets.CKey2ActiveTicket(target)
var/compliant_msg = trim(lowertext(msg))
var/tgs_tagged = "[sender](TGS/External)"
var/irc_tagged = "[sender](IRC)"
var/list/splits = splittext(compliant_msg, " ")
if(splits.len && splits[1] == "ticket")
if(splits.len < 2)
return TGS_AHELP_USAGE
return IRC_AHELP_USAGE
switch(splits[2])
if("close")
if(ticket)
ticket.Close(tgs_tagged)
ticket.Close(irc_tagged)
return "Ticket #[ticket.id] successfully closed"
if("resolve")
if(ticket)
ticket.Resolve(tgs_tagged)
ticket.Resolve(irc_tagged)
return "Ticket #[ticket.id] successfully resolved"
if("icissue")
if(ticket)
ticket.ICIssue(tgs_tagged)
ticket.ICIssue(irc_tagged)
return "Ticket #[ticket.id] successfully marked as IC issue"
if("reject")
if(ticket)
ticket.Reject(tgs_tagged)
ticket.Reject(irc_tagged)
return "Ticket #[ticket.id] successfully rejected"
if("reopen")
if(ticket)
@@ -281,7 +253,7 @@
if(!isnull(fail))
fail = text2num(splits[3])
if(isnull(fail))
return "Error: No/Invalid ticket id specified. [TGS_AHELP_USAGE]"
return "Error: No/Invalid ticket id specified. [IRC_AHELP_USAGE]"
var/datum/admin_help/AH = GLOB.ahelp_tickets.TicketByID(fail)
if(!AH)
return "Error: Ticket #[fail] not found"
@@ -303,42 +275,41 @@
. += "#[AH.id]"
return
else
return TGS_AHELP_USAGE
return IRC_AHELP_USAGE
return "Error: Ticket could not be found"
var/static/stealthkey
var/adminname = CONFIG_GET(flag/show_irc_name) ? tgs_tagged : "Administrator"
var/adminname = CONFIG_GET(flag/show_irc_name) ? irc_tagged : "Administrator"
if(!C)
return "Error: No client"
if(!stealthkey)
stealthkey = GenTgsStealthKey()
stealthkey = GenIrcStealthKey()
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
if(!msg)
return "Error: No message"
message_admins("External message from [sender] to [key_name_admin(C)] : [msg]")
log_admin_private("External PM: [sender] -> [key_name(C)] : [msg]")
message_admins("IRC message from [sender] to [key_name_admin(C)] : [msg]")
log_admin_private("IRC PM: [sender] -> [key_name(C)] : [msg]")
msg = emoji_parse(msg)
to_chat(C, "<font color='red' size='4'><b>-- Administrator private message --</b></font>", confidential = TRUE)
to_chat(C, "<span class='adminsay'>Admin PM from-<b><a href='?priv_msg=[stealthkey]'>[adminname]</A></b>: [msg]</span>", confidential = TRUE)
to_chat(C, "<span class='adminsay'><i>Click on the administrator's name to reply.</i></span>", confidential = TRUE)
to_chat(C, "<font color='red' size='4'><b>-- Administrator private message --</b></font>")
to_chat(C, "<span class='adminsay'>Admin PM from-<b><a href='?priv_msg=[stealthkey]'>[adminname]</A></b>: [msg]</span>")
to_chat(C, "<span class='adminsay'><i>Click on the administrator's name to reply.</i></span>")
admin_ticket_log(C, "<font color='purple'>PM From [tgs_tagged]: [msg]</font>")
admin_ticket_log(C, "<font color='purple'>PM From [irc_tagged]: [msg]</font>")
window_flash(C, ignorepref = TRUE)
//always play non-admin recipients the adminhelp sound
SEND_SOUND(C, 'sound/effects/adminhelp.ogg')
// C.externalreplyamount = EXTERNALREPLYCOUNT
C.ircreplyamount = EXTERNALREPLYCOUNT
C.ircreplyamount = IRCREPLYCOUNT
return "Message Successful"
/proc/GenTgsStealthKey()
/proc/GenIrcStealthKey()
var/num = (rand(0,1000))
var/i = 0
while(i == 0)
@@ -351,4 +322,4 @@
GLOB.stealthminID["IRCKEY"] = stealth
return stealth
#undef EXTERNALREPLYCOUNT
#undef IRCREPLYCOUNT
+1 -1
View File
@@ -13,7 +13,7 @@
msg = keywords_lookup(msg)
msg = "<span class='adminsay'><span class='prefix'>ADMIN:</span> <EM>[key_name(usr, 1)]</EM> [ADMIN_FLW(mob)]: <span class='message linkify'>[msg]</span></span>"
to_chat(GLOB.admins, msg, confidential = TRUE)
to_chat(GLOB.admins, msg)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Asay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+1 -1
View File
@@ -5,7 +5,7 @@
var/mob/living/target = M
if(!isliving(target))
to_chat(usr, "This can only be used on instances of type /mob/living", confidential = TRUE)
to_chat(usr, "This can only be used on instances of type /mob/living")
return
explosion(target.loc, 0, 0, 0, 0)
+10 -10
View File
@@ -7,9 +7,9 @@
return
if (!istype(borgo, /mob/living/silicon/robot))
borgo = input("Select a borg", "Select a borg", null, null) as null|anything in sortNames(GLOB.silicon_mobs)
borgo = input("Select a borg", "Select a borg", null, null) as null|anything in GLOB.silicon_mobs
if (!istype(borgo, /mob/living/silicon/robot))
to_chat(usr, "<span class='warning'>Borg is required for borgpanel</span>", confidential = TRUE)
to_chat(usr, "<span class='warning'>Borg is required for borgpanel</span>")
var/datum/borgpanel/borgpanel = new(usr, borgo)
@@ -25,18 +25,18 @@
if(!istype(to_borg))
qdel(src)
CRASH("Borg panel is only available for borgs")
user = CLIENT_FROM_VAR(to_user)
if (!user)
CRASH("Borg panel attempted to open to a mob without a client")
borg = to_borg
/datum/borgpanel/ui_state(mob/user)
return GLOB.admin_state
/datum/borgpanel/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
/datum/borgpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, "BorgPanel")
ui = new(user, src, ui_key, "BorgPanel", "Borg Panel", 700, 700, master_ui, state)
ui.open()
/datum/borgpanel/ui_data(mob/user)
@@ -53,13 +53,13 @@
.["upgrades"] = list()
for (var/upgradetype in subtypesof(/obj/item/borg/upgrade)-/obj/item/borg/upgrade/hypospray) //hypospray is a dummy parent for hypospray upgrades
var/obj/item/borg/upgrade/upgrade = upgradetype
if (initial(upgrade.module_type) && !is_type_in_list(borg.module, initial(upgrade.module_type))) // Upgrade requires a different module
if (initial(upgrade.module_type) && !istype(borg.module, initial(upgrade.module_type))) // Upgrade requires a different module
continue
var/installed = FALSE
if (locate(upgradetype) in borg)
installed = TRUE
.["upgrades"] += list(list("name" = initial(upgrade.name), "installed" = installed, "type" = upgradetype))
.["laws"] = borg.laws ? borg.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE) : list()
.["laws"] = borg.laws ? borg.laws.get_law_list(include_zeroth = TRUE) : list()
.["channels"] = list()
for (var/k in GLOB.radiochannels)
if (k == RADIO_CHANNEL_COMMON)
+8 -19
View File
@@ -2,16 +2,16 @@
set category = "Special Verbs"
set name = "Dsay"
set hidden = 1
if(!holder)
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
if(!src.holder)
to_chat(src, "Only administrators may use this command.")
return
if(!mob)
if(!src.mob)
return
if(prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<span class='danger'>You cannot send DSAY messages (muted).</span>", confidential = TRUE)
to_chat(src, "<span class='danger'>You cannot send DSAY messages (muted).</span>")
return
if (handle_spam_prevention(msg,MUTE_DEADCHAT))
if (src.handle_spam_prevention(msg,MUTE_DEADCHAT))
return
msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
@@ -23,25 +23,14 @@
var/rendered = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <span class='name'>[uppertext(holder.rank)]([src.holder.fakekey ? pick(nicknames) : src.key])</span> says, <span class='message'>\"[emoji_parse(msg)]\"</span></span>"
// var/rank_name = holder.rank
// var/admin_name = key
// if(holder.fakekey)
// rank_name = pick(strings("admin_nicknames.json", "ranks", "config")) please use this soon.
// admin_name = pick(strings("admin_nicknames.json", "names", "config"))
// var/rendered = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <span class='name'>[rank_name]([admin_name])</span> says, <span class='message'>\"[emoji_parse(msg)]\"</span></span>"
for (var/mob/M in GLOB.player_list)
if(isnewplayer(M))
continue
if (M.stat == DEAD || (M.client.holder && (M.client.prefs.chat_toggles & CHAT_DEAD))) //admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above
to_chat(M, rendered, confidential = TRUE)
if (M.stat == DEAD || (M.client && M.client.holder && (M.client.prefs.chat_toggles & CHAT_DEAD))) //admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above
to_chat(M, rendered)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Dsay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/get_dead_say()
var/msg = input(src, null, "dsay \"text\"") as text|null
if (isnull(msg))
return
var/msg = input(src, null, "dsay \"text\"") as text
dsay(msg)
+2 -2
View File
@@ -31,5 +31,5 @@
src << ftp(file(path))
else
return
to_chat(src, "Attempting to send [path], this may take a fair few minutes if the file is very large.", confidential = TRUE)
return
to_chat(src, "Attempting to send [path], this may take a fair few minutes if the file is very large.")
return
+81 -43
View File
@@ -34,7 +34,9 @@
for(var/mob/M in GLOB.player_list)
if(M.client.prefs.toggles & SOUND_MIDI)
admin_sound.volume = vol * M.client.admin_music_volume
var/user_vol = M.client.chatOutput.adminMusicVolume
if(user_vol)
admin_sound.volume = vol * (user_vol / 100)
SEND_SOUND(M, admin_sound)
admin_sound.volume = vol
@@ -67,7 +69,7 @@
if(istext(web_sound_input))
var/web_sound_url = ""
var/stop_web_sounds = FALSE
var/list/music_extra_data = list()
var/pitch
if(length(web_sound_input))
web_sound_input = trim(web_sound_input)
@@ -95,10 +97,11 @@
var/webpage_url = title
if (data["webpage_url"])
webpage_url = "<a href=\"[data["webpage_url"]]\">[title]</a>"
music_extra_data["start"] = data["start_time"]
music_extra_data["end"] = data["end_time"]
music_extra_data["link"] = data["webpage_url"]
music_extra_data["title"] = data["title"]
var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num
if(!freq)
freq = 1
pitch = freq
var/res = alert(usr, "Show the title of and link to this song to the players?\n[title]",, "No", "Yes", "Cancel")
switch(res)
@@ -127,11 +130,11 @@
for(var/m in GLOB.player_list)
var/mob/M = m
var/client/C = M.client
if(C.prefs.toggles & SOUND_MIDI)
if((C.prefs.toggles & SOUND_MIDI) && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded)
if(!stop_web_sounds)
C.tgui_panel?.play_music(web_sound_url, music_extra_data)
C.chatOutput.sendMusic(web_sound_url, pitch)
else
C.tgui_panel?.stop_music()
C.chatOutput.stopMusic()
SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Internet Sound")
@@ -141,7 +144,7 @@
if(!check_rights(R_SOUNDS))
return
var/web_sound_input = input("Enter content stream URL (must be a direct link)", "Play Internet Sound via direct URL") as text|null
var/web_sound_input = input("Enter content stream URL (fetch this from local youtube-dl!)", "Play Internet Sound via direct URL") as text|null
if(istext(web_sound_input))
if(!length(web_sound_input))
log_admin("[key_name(src)] stopped web sound")
@@ -149,37 +152,34 @@
var/mob/M
for(var/i in GLOB.player_list)
M = i
M?.client?.tgui_panel?.stop_music()
M?.client?.chatOutput?.stopMusic()
return
var/list/music_extra_data = list()
web_sound_input = trim(web_sound_input)
if(web_sound_input && (findtext(web_sound_input, ":") && !findtext(web_sound_input, GLOB.is_http_protocol)))
to_chat(src, "<span class='boldwarning'>Non-http(s) URIs are not allowed.</span>", confidential = TRUE)
return
var/list/explode = splittext(web_sound_input, "/") //if url=="https://fixthisshit.com/pogchamp.ogg"then title="pogchamp.ogg"
var/title = "[explode[explode.len]]"
if(!findtext(title, ".mp3") && !findtext(title, ".mp4")) // IE sucks.
to_chat(src, "<span class='warning'>The format is not .mp3/.mp4, IE 8 and above can only support the .mp3/.mp4 format, the music might not play.</span>", confidential = TRUE)
if(length(title) > 50) //kev no.
title = "Unknown.mp3"
music_extra_data["title"] = title
SSblackbox.record_feedback("nested tally", "played_url", 1, list("[ckey]", "[web_sound_input]"))
log_admin("[key_name(src)] played web sound: [web_sound_input]")
message_admins("[key_name(src)] played web sound: [web_sound_input]")
for(var/m in GLOB.player_list)
var/mob/M = m
var/client/C = M.client
if(C.prefs.toggles & SOUND_MIDI)
C.tgui_panel?.play_music(web_sound_input, music_extra_data)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Manual Play Internet Sound")
else
if(web_sound_input && !findtext(web_sound_input, GLOB.is_http_protocol))
to_chat(src, "<span class='boldwarning'>BLOCKED: Content URL not using http(s) protocol</span>")
return
var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num
if(isnull(freq))
return
if(!freq)
freq = 1
SSblackbox.record_feedback("nested tally", "played_url", 1, list("[ckey]", "[web_sound_input]"))
var/logstr = "[key_name(src)] played web sound at freq [freq]: [web_sound_input]"
log_admin(logstr)
message_admins(logstr)
var/mob/M
var/client/C
var/datum/chatOutput/O
for(var/i in GLOB.player_list)
M = i
C = M.client
if(!(C?.prefs?.toggles & SOUND_MIDI))
continue
O = C.chatOutput
if(!O || O.broken || !O.loaded)
continue
O.sendMusic(web_sound_input, freq)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Manual Play Internet Sound")
/client/proc/set_round_end_sound(S as sound)
set category = "Fun"
@@ -193,6 +193,42 @@
message_admins("[key_name_admin(src)] set the round end sound to [S]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Round End Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/play_web_sound_manual()
set category = "Fun"
set name = "Manual Play Internet Sound"
if(!check_rights(R_SOUNDS))
return
var/web_sound_input = input("Enter youtube-dl fetched content URL (supported sites only, leave blank to stop playing)", "Send youtube-dl media link") as text|null
if(!istext(web_sound_input))
return
web_sound_input = trim(web_sound_input)
if(!length(web_sound_input))
log_admin("[key_name(src)] stopped web sound")
message_admins("[key_name(src)] stopped web sound")
for(var/m in GLOB.player_list)
var/mob/M = m
var/client/C = M.client
if((C.prefs.toggles & SOUND_MIDI) && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded)
C.chatOutput.stopMusic()
return
var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num
if(!freq)
return
if(web_sound_input && !findtext(web_sound_input, GLOB.is_http_protocol))
to_chat(src, "<span class='boldwarning'>BLOCKED: Content URL not using http(s) protocol</span>")
to_chat(src, "<span class='warning'>The media provider returned a content URL that isn't using the HTTP or HTTPS protocol</span>")
return
SSblackbox.record_feedback("nested tally", "played_url_manual", 1, list("[ckey]", "[web_sound_input]"))
log_admin("[key_name(src)] manually played web sound: [web_sound_input]")
message_admins("[key_name(src)] manually played web sound: <a href='web_sound_input'>HREF</a>")
for(var/m in GLOB.player_list)
var/mob/M = m
var/client/C = M.client
if((C.prefs.toggles & SOUND_MIDI) && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded)
C.chatOutput.sendMusic(web_sound_input, freq)
/client/proc/stop_sounds()
set category = "Debug"
set name = "Stop All Playing Sounds"
@@ -202,7 +238,9 @@
log_admin("[key_name(src)] stopped all currently playing sounds.")
message_admins("[key_name_admin(src)] stopped all currently playing sounds.")
for(var/mob/M in GLOB.player_list)
SEND_SOUND(M, sound(null))
var/client/C = M.client
C?.tgui_panel?.stop_music()
if(M.client)
SEND_SOUND(M, sound(null))
var/client/C = M.client
if(C && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded)
C.chatOutput.stopMusic()
SSblackbox.record_feedback("tally", "admin_verb", 1, "Stop All Playing Sounds") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -38,7 +38,7 @@
var/var_value = O.vars[variable]
if(variable in GLOB.VVckey_edit)
to_chat(src, "It's forbidden to mass-modify ckeys. It'll crash everyone's client you dummy.", confidential = TRUE)
to_chat(src, "It's forbidden to mass-modify ckeys. It'll crash everyone's client you dummy.")
return
if(variable in GLOB.VVlocked)
if(!check_rights(R_DEBUG))
@@ -56,11 +56,11 @@
default = vv_get_class(variable, var_value)
if(isnull(default))
to_chat(src, "Unable to determine variable type.", confidential = TRUE)
to_chat(src, "Unable to determine variable type.")
else
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.", confidential = TRUE)
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
to_chat(src, "Variable contains: [var_value]", confidential = TRUE)
to_chat(src, "Variable contains: [var_value]")
if(default == VV_NUM)
var/dir_text = ""
@@ -75,7 +75,7 @@
dir_text += "WEST"
if(dir_text)
to_chat(src, "If a direction, direction is: [dir_text]", confidential = TRUE)
to_chat(src, "If a direction, direction is: [dir_text]")
var/value = vv_get_value(default_class = default)
var/new_value = value["value"]
@@ -97,9 +97,9 @@
switch(class)
if(VV_RESTORE_DEFAULT)
to_chat(src, "Finding items...", confidential = TRUE)
to_chat(src, "Finding items...")
var/list/items = get_all_of_type(O.type, method)
to_chat(src, "Changing [items.len] items...", confidential = TRUE)
to_chat(src, "Changing [items.len] items...")
for(var/thing in items)
if (!thing)
continue
@@ -123,9 +123,9 @@
for(var/V in varsvars)
new_value = replacetext(new_value,"\[[V]]","[O.vars[V]]")
to_chat(src, "Finding items...", confidential = TRUE)
to_chat(src, "Finding items...")
var/list/items = get_all_of_type(O.type, method)
to_chat(src, "Changing [items.len] items...", confidential = TRUE)
to_chat(src, "Changing [items.len] items...")
for(var/thing in items)
if (!thing)
continue
@@ -151,9 +151,9 @@
many = FALSE
var/type = value["type"]
to_chat(src, "Finding items...", confidential = TRUE)
to_chat(src, "Finding items...")
var/list/items = get_all_of_type(O.type, method)
to_chat(src, "Changing [items.len] items...", confidential = TRUE)
to_chat(src, "Changing [items.len] items...")
for(var/thing in items)
if (!thing)
continue
@@ -169,9 +169,9 @@
CHECK_TICK
else
to_chat(src, "Finding items...", confidential = TRUE)
to_chat(src, "Finding items...")
var/list/items = get_all_of_type(O.type, method)
to_chat(src, "Changing [items.len] items...", confidential = TRUE)
to_chat(src, "Changing [items.len] items...")
for(var/thing in items)
if (!thing)
continue
@@ -185,20 +185,20 @@
var/count = rejected+accepted
if (!count)
to_chat(src, "No objects found", confidential = TRUE)
to_chat(src, "No objects found")
return
if (!accepted)
to_chat(src, "Every object rejected your edit", confidential = TRUE)
to_chat(src, "Every object rejected your edit")
return
if (rejected)
to_chat(src, "[rejected] out of [count] objects rejected your edit", confidential = TRUE)
to_chat(src, "[rejected] out of [count] objects rejected your edit")
log_world("### MassVarEdit by [src]: [O.type] (A/R [accepted]/[rejected]) [variable]=[html_encode("[O.vars[variable]]")]([list2params(value)])")
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
//not using global lists as vv is a debug function and debug functions should rely on as less things as possible.
/proc/get_all_of_type(T, subtypes = TRUE)
/proc/get_all_of_type(var/T, subtypes = TRUE)
var/list/typecache = list()
typecache[T] = 1
if (subtypes)
@@ -253,7 +253,7 @@
CHECK_TICK
else if (ispath(T, /client))
for(var/client/thing in GLOB.clients)
for(var/client/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
@@ -17,7 +17,7 @@ GLOBAL_PROTECT(VVpixelmovement)
//FALSE = no subtypes, strict exact type pathing (or the type doesn't have subtypes)
//TRUE = Yes subtypes
//NULL = User cancelled at the prompt or invalid type given
/client/proc/vv_subtype_prompt(type)
/client/proc/vv_subtype_prompt(var/type)
if (!ispath(type))
return
var/list/subtypes = subtypesof(type)
@@ -102,7 +102,7 @@ GLOBAL_PROTECT(VVpixelmovement)
L[var_value] = mod_list_add_ass(O) //hehe
if (O)
if (O.vv_edit_var(objectvar, L) == FALSE)
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
to_chat(src, "Your edit was rejected by the object.")
return
log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: ADDED=[var_value]")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]")
@@ -112,7 +112,7 @@ GLOBAL_PROTECT(VVpixelmovement)
if(!check_rights(R_VAREDIT))
return
if(!istype(L, /list))
to_chat(src, "Not a List.", confidential = TRUE)
to_chat(src, "Not a List.")
return
if(L.len > 1000)
@@ -121,6 +121,7 @@ GLOBAL_PROTECT(VVpixelmovement)
return
var/is_normal_list = IS_NORMAL_LIST(L)
var/list/names = list()
for (var/i in 1 to L.len)
var/key = L[i]
@@ -144,7 +145,7 @@ GLOBAL_PROTECT(VVpixelmovement)
L = L.Copy()
listclearnulls(L)
if (!O.vv_edit_var(objectvar, L))
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
to_chat(src, "Your edit was rejected by the object.")
return
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR NULLS")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR NULLS")
@@ -154,7 +155,7 @@ GLOBAL_PROTECT(VVpixelmovement)
if(variable == "(CLEAR DUPES)")
L = uniqueList(L)
if (!O.vv_edit_var(objectvar, L))
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
to_chat(src, "Your edit was rejected by the object.")
return
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR DUPES")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR DUPES")
@@ -164,7 +165,7 @@ GLOBAL_PROTECT(VVpixelmovement)
if(variable == "(SHUFFLE)")
L = shuffle(L)
if (!O.vv_edit_var(objectvar, L))
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
to_chat(src, "Your edit was rejected by the object.")
return
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: SHUFFLE")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: SHUFFLE")
@@ -201,9 +202,9 @@ GLOBAL_PROTECT(VVpixelmovement)
default = vv_get_class(objectvar, variable)
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.", confidential = TRUE)
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
to_chat(src, "Variable contains: [variable]", confidential = TRUE)
to_chat(src, "Variable contains: [variable]")
if(default == VV_NUM)
var/dir_text = ""
@@ -219,7 +220,7 @@ GLOBAL_PROTECT(VVpixelmovement)
dir_text += "WEST"
if(dir_text)
to_chat(usr, "If a direction, direction is: [dir_text]", confidential = TRUE)
to_chat(usr, "If a direction, direction is: [dir_text]")
var/original_var = variable
@@ -247,7 +248,7 @@ GLOBAL_PROTECT(VVpixelmovement)
L.Cut(index, index+1)
if (O)
if (O.vv_edit_var(objectvar, L))
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
to_chat(src, "Your edit was rejected by the object.")
return
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: REMOVED=[html_encode("[original_var]")]")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: REMOVED=[original_var]")
@@ -259,7 +260,6 @@ GLOBAL_PROTECT(VVpixelmovement)
for(var/V in varsvars)
new_var = replacetext(new_var,"\[[V]]","[O.vars[V]]")
if(is_normal_list)
if(assoc)
L[assoc_key] = new_var
@@ -269,7 +269,7 @@ GLOBAL_PROTECT(VVpixelmovement)
L[new_var] = old_assoc_value
if (O)
if (O.vv_edit_var(objectvar, L) == FALSE)
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
to_chat(src, "Your edit was rejected by the object.")
return
log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: [original_var]=[new_var]")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]")
@@ -297,7 +297,7 @@ GLOBAL_PROTECT(VVpixelmovement)
if(param_var_name)
if(!(param_var_name in O.vars))
to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this datum ([O])", confidential = TRUE)
to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this datum ([O])")
return
variable = param_var_name
@@ -322,11 +322,11 @@ GLOBAL_PROTECT(VVpixelmovement)
var/default = vv_get_class(variable, var_value)
if(isnull(default))
to_chat(src, "Unable to determine variable type.", confidential = TRUE)
to_chat(src, "Unable to determine variable type.")
else
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.", confidential = TRUE)
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
to_chat(src, "Variable contains: [var_value]", confidential = TRUE)
to_chat(src, "Variable contains: [var_value]")
if(default == VV_NUM)
var/dir_text = ""
@@ -341,7 +341,7 @@ GLOBAL_PROTECT(VVpixelmovement)
dir_text += "WEST"
if(dir_text)
to_chat(src, "If a direction, direction is: [dir_text]", confidential = TRUE)
to_chat(src, "If a direction, direction is: [dir_text]")
if(autodetect_class && default != VV_NULL)
if (default == VV_TEXT)
@@ -378,7 +378,7 @@ GLOBAL_PROTECT(VVpixelmovement)
if (O.vv_edit_var(variable, var_new) == FALSE)
to_chat(src, "Your edit was rejected by the object.", confidential = TRUE)
to_chat(src, "Your edit was rejected by the object.")
return
vv_update_display(O, "varedited", VV_MSG_EDITED)
log_world("### VarEdit by [key_name(src)]: [O.type] [variable]=[var_value] => [var_new]")
+8 -11
View File
@@ -25,7 +25,7 @@
var/mob/M = locate(href_list["rename"]) in GLOB.mob_list
if(!istype(M))
to_chat(usr, "This can only be used on instances of type /mob", confidential = TRUE)
to_chat(usr, "This can only be used on instances of type /mob")
return
var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN)
@@ -43,7 +43,7 @@
var/atom/A = locate(href_list["rotatedatum"])
if(!istype(A))
to_chat(usr, "This can only be done to instances of type /atom", confidential = TRUE)
to_chat(usr, "This can only be done to instances of type /atom")
return
switch(href_list["rotatedir"])
@@ -60,13 +60,13 @@
var/mob/living/carbon/monkey/Mo = locate(href_list["makehuman"]) in GLOB.mob_list
if(!istype(Mo))
to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey", confidential = TRUE)
to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey")
return
if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
return
if(!Mo)
to_chat(usr, "Mob doesn't exist anymore", confidential = TRUE)
to_chat(usr, "Mob doesn't exist anymore")
return
holder.Topic(href, list("humanone"=href_list["makehuman"]))
@@ -80,13 +80,10 @@
var/Text = href_list["adjustDamage"]
var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num|null
if (isnull(amount))
return
var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num
if(!L)
to_chat(usr, "Mob doesn't exist anymore", confidential = TRUE)
to_chat(usr, "Mob doesn't exist anymore")
return
var/newamt
@@ -113,7 +110,7 @@
L.adjustStaminaLoss(amount)
newamt = L.getStaminaLoss()
else
to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]", confidential = TRUE)
to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]")
return
if(amount != 0)
@@ -127,5 +124,5 @@
//Finally, refresh if something modified the list.
if(href_list["datumrefresh"])
var/datum/DAT = locate(href_list["datumrefresh"])
if(istype(DAT, /datum) || istype(DAT, /client) || islist(DAT))
if(istype(DAT, /datum) || istype(DAT, /client))
debug_variables(DAT)
@@ -34,11 +34,11 @@
if (!C)
return
if(!target)
to_chat(usr, "<span class='warning'>The object you tried to expose to [C] no longer exists (nulled or hard-deled)</span>", confidential = TRUE)
to_chat(usr, "<span class='warning'>The object you tried to expose to [C] no longer exists (nulled or hard-deled)</span>")
return
message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a <a href='?_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)
to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window")
C.debug_variables(target)
if(check_rights(R_DEBUG))
if(href_list[VV_HK_DELETE])
@@ -46,33 +46,31 @@
if (isturf(src)) // show the turf that took its place
usr.client.debug_variables(src)
return
#ifdef REFERENCE_TRACKING //people with debug can only access this putnam!
if(href_list[VV_HK_VIEW_REFERENCES])
var/datum/D = locate(href_list[VV_HK_TARGET])
if(!D)
to_chat(usr, "<span class='warning'>Unable to locate item.</span>")
return
usr.client.holder.view_refs(target)
#ifdef REFERENCE_TRACKING
if(href_list[VV_HK_VIEW_REFERENCES])
var/datum/D = locate(href_list[VV_HK_TARGET])
if(!D)
to_chat(usr, "<span class='warning'>Unable to locate item.</span>")
return
#endif
usr.client.holder.view_refs(target)
return
#endif
if(href_list[VV_HK_MARK])
usr.client.mark_datum(target)
if(href_list[VV_HK_ADDCOMPONENT])
if(!check_rights(NONE))
return
var/list/names = list()
var/list/componentsubtypes = sortList(subtypesof(/datum/component), /proc/cmp_typepaths_asc)
var/list/componentsubtypes = subtypesof(/datum/component)
names += "---Components---"
names += componentsubtypes
names += "---Elements---"
names += sortList(subtypesof(/datum/element), /proc/cmp_typepaths_asc)
names += subtypesof(/datum/element)
var/result = input(usr, "Choose a component/element to add","better know what ur fuckin doin pal") as null|anything in names
if(!usr || !result || result == "---Components---" || result == "---Elements---")
return
if(QDELETED(src))
to_chat(usr, "That thing doesn't exist anymore!", confidential = TRUE)
to_chat(usr, "That thing doesn't exist anymore!")
return
var/list/lst = get_callproc_args()
if(!lst)
@@ -85,7 +83,7 @@
else
datumname = "element"
target._AddElement(lst)
log_admin("[key_name(usr)] has added [result] [datumname] to [key_name(target)].")
message_admins("<span class='notice'>[key_name_admin(usr)] has added [result] [datumname] to [key_name_admin(target)].</span>")
log_admin("[key_name(usr)] has added [result] [datumname] to [key_name(src)].")
message_admins("<span class='notice'>[key_name_admin(usr)] has added [result] [datumname] to [key_name_admin(src)].</span>")
if(href_list[VV_HK_CALLPROC])
usr.client.callproc_datum(target)
@@ -1,3 +1,4 @@
/client/proc/debug_variables(datum/D in world)
set category = "Debug"
set name = "View Variables"
@@ -5,7 +6,7 @@
var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round.
if(!usr.client || !usr.client.holder) //This is usr because admins can call the proc on other clients, even if they're not admins, to show them VVs.
to_chat(usr, "<span class='danger'>You need to be an administrator to access this.</span>", confidential = TRUE)
to_chat(usr, "<span class='danger'>You need to be an administrator to access this.</span>")
return
if(!D)
@@ -25,6 +26,7 @@
if(istype(D, /atom))
sprite = getFlatIcon(D)
hash = md5(sprite)
if(sprite)
hash = md5(sprite)
src << browse_rsc(sprite, "vv[hash].png")
@@ -95,7 +97,7 @@
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>[title]</title>
<link rel="stylesheet" type="text/css" href="[SSassets.transport.get_asset_url("view_variables.css")]">
<link rel="stylesheet" type="text/css" href="view_variables.css">
</head>
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
<script type="text/javascript">
@@ -120,13 +122,11 @@
}
return "";
}
// main search functionality
var last_filter = "";
function updateSearch() {
var filter = document.getElementById('filter').value.toLowerCase();
var vars_ol = document.getElementById("vars");
if (filter === last_filter) {
// An event triggered an update but nothing has changed.
return;
@@ -146,7 +146,6 @@
while (vars_ol.hasChildNodes()) {
vars_ol.removeChild(vars_ol.lastChild);
}
for (var i = 0; i < complete_list.length; ++i) {
try {
var li = complete_list\[i];
@@ -156,12 +155,9 @@
} catch(err) {}
}
}
last_filter = filter;
document.cookie="[refid][cookieoffset]search="+encodeURIComponent(filter);
}
// onkeydown
function handle_keydown() {
if(event.keyCode == 116) { //F5 (to refresh properly)
@@ -171,12 +167,10 @@
}
return true;
}
// onkeyup
function handle_keyup() {
updateSearch();
}
// onchange
function handle_dropdown(list) {
var value = list.options\[list.selectedIndex].value;
@@ -186,7 +180,6 @@
list.selectedIndex = 0;
document.getElementById('filter').focus();
}
// byjax
function replace_span(what) {
var idx = what.indexOf(':');
@@ -3,19 +3,41 @@
desc = "Expels impurifications from our form; curing diseases, removing parasites, sobering us, purging toxins and radiation, and resetting our genetic code completely."
helptext = "Can be used while unconscious."
chemical_cost = 20
dna_cost = 2
dna_cost = 1
req_stat = UNCONSCIOUS
action_icon = 'icons/mob/actions/actions_changeling.dmi'
action_icon_state = "ling_anatomic_panacea"
action_background_icon_state = "bg_ling"
//Heals the things that the other regenerative abilities don't.
/obj/effect/proc_holder/changeling/panacea/sting_action(mob/living/user)
if(user.has_status_effect(STATUS_EFFECT_PANACEA))
to_chat(user, "<span class='warning'>We are already cleansing our impurities!</span>")
return
/obj/effect/proc_holder/changeling/panacea/sting_action(mob/user)
to_chat(user, "<span class='notice'>We cleanse impurities from our form.</span>")
user.apply_status_effect(STATUS_EFFECT_PANACEA)
return TRUE
//buffs.dm has the code for anatomic panacea
var/list/bad_organs = list(
user.getorgan(/obj/item/organ/body_egg),
user.getorgan(/obj/item/organ/zombie_infection))
for(var/o in bad_organs)
var/obj/item/organ/O = o
if(!istype(O))
continue
O.Remove()
if(iscarbon(user))
var/mob/living/carbon/C = user
C.vomit(0, toxic = TRUE)
O.forceMove(get_turf(user))
user.reagents.add_reagent(/datum/reagent/medicine/mutadone, 10)
user.reagents.add_reagent(/datum/reagent/medicine/pen_acid/pen_jelly, 20)
user.reagents.add_reagent(/datum/reagent/medicine/antihol, 10)
user.reagents.add_reagent(/datum/reagent/medicine/mannitol, 25)
if(isliving(user))
var/mob/living/L = user
for(var/thing in L.diseases)
var/datum/disease/D = thing
if(D.severity == DISEASE_SEVERITY_POSITIVE)
continue
D.cure()
return TRUE

Some files were not shown because too many files have changed in this diff Show More