Merge remote-tracking branch 'upstream/master' into cool-ipcs
This commit is contained in:
@@ -0,0 +1 @@
|
||||
#define EXTOOLS (world.system_type == MS_WINDOWS ? "byond-extools.dll" : "libbyond-extools.so")
|
||||
@@ -281,8 +281,6 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
|
||||
#define CALCULATE_ADJACENT_TURFS(T) SSadjacent_air.queue[T] = 1
|
||||
#endif
|
||||
|
||||
#define EXTOOLS (world.system_type == MS_WINDOWS ? "byond-extools.dll" : "libbyond-extools.so")
|
||||
|
||||
GLOBAL_VAR(atmos_extools_initialized) // this must be an uninitialized (null) one or init_monstermos will be called twice because reasons
|
||||
#define ATMOS_EXTOOLS_CHECK if(!GLOB.atmos_extools_initialized){\
|
||||
GLOB.atmos_extools_initialized=TRUE;\
|
||||
|
||||
@@ -99,7 +99,8 @@
|
||||
#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
|
||||
|
||||
@@ -2,19 +2,6 @@
|
||||
|
||||
#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"
|
||||
@@ -64,4 +51,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,6 +1,7 @@
|
||||
//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"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#define COMSIG_ELEMENT_DETACH "element_detach"
|
||||
|
||||
/// sent to the component itself when unregistered from a parent
|
||||
#define COMSIG_COMPONENT_UNREGISTER_PARENT "component_unregister_parent"
|
||||
#define COMSIG_COMPONENT_UNREGISTER_PARENT "component_unregister_parent"
|
||||
/// sent to the component itself when registered to a parent
|
||||
#define COMSIG_COMPONENT_REGISTER_PARENT "component_register_parent"
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
// /atom signals
|
||||
//from base of atom/proc/Initialize(): sent any time a new atom is created
|
||||
#define COMSIG_ATOM_CREATED "atom_created"
|
||||
//from SSatoms InitAtom - Only if the atom was not deleted or failed initialization
|
||||
#define COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE "atom_init_success"
|
||||
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
|
||||
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
|
||||
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
|
||||
@@ -184,6 +186,7 @@
|
||||
// #define HEARING_SOURCE 8
|
||||
#define COMSIG_MOVABLE_DISPOSING "movable_disposing" //called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source)
|
||||
#define COMSIG_MOVABLE_TELEPORTED "movable_teleported" //from base of do_teleport(): (channel, turf/origin, turf/destination)
|
||||
#define COMSIG_MOVABLE_CHASM_DROP "movable_chasm_drop" //from base of /datum/component/chasm/drop() (/datum/component/chasm)
|
||||
|
||||
// /mind signals
|
||||
#define COMSIG_PRE_MIND_TRANSFER "pre_mind_transfer" //from base of mind/transfer_to() before it's done: (new_character, old_character)
|
||||
@@ -287,6 +290,10 @@
|
||||
#define COMPONENT_INTERRUPT_LIFE_BIOLOGICAL 1 // interrupt biological processes
|
||||
#define COMPONENT_INTERRUPT_LIFE_PHYSICAL 2 // interrupt physical handling
|
||||
|
||||
#define COMSIG_LIVING_BIOLOGICAL_LIFE "biological_life" //from base of mob/living/BiologicalLife() (seconds, times_fired)
|
||||
|
||||
#define COMSIG_LIVING_PHYSICAL_LIFE "physical_life" //from base of mob/living/PhysicalLife() (seconds, times_fired)
|
||||
|
||||
// /mob/living/carbon physiology signals
|
||||
#define COMSIG_CARBON_GAIN_WOUND "carbon_gain_wound" //from /datum/wound/proc/apply_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L)
|
||||
#define COMSIG_CARBON_LOSE_WOUND "carbon_lose_wound" //from /datum/wound/proc/remove_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#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"
|
||||
@@ -16,6 +17,7 @@
|
||||
#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"
|
||||
@@ -26,3 +28,5 @@
|
||||
#define DYE_CMO "cmo"
|
||||
#define DYE_REDCOAT "redcoat"
|
||||
#define DYE_CLOWN "clown"
|
||||
#define DYE_CHAP "chap"
|
||||
#define DYE_CENTCOM "centcom"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define TOXIC (1<<11)
|
||||
#define PINEAPPLE (1<<12)
|
||||
#define BREAKFAST (1<<13)
|
||||
#define ANTITOXIC (1<<14)
|
||||
|
||||
#define DRINK_NICE 1
|
||||
#define DRINK_GOOD 2
|
||||
|
||||
@@ -41,11 +41,13 @@
|
||||
#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)
|
||||
|
||||
@@ -116,6 +116,7 @@ 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
|
||||
|
||||
@@ -318,9 +319,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, "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(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_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]")
|
||||
|
||||
#define INCREMENT_TALLY(L, stat) if(L[stat]){L[stat]++}else{L[stat] = 1}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Anomaly core types
|
||||
/// Bluespace cores
|
||||
#define ANOMALY_CORE_BLUESPACE /obj/item/assembly/signaler/anomaly/bluespace
|
||||
/// Gravitational cores
|
||||
#define ANOMALY_CORE_GRAVITATIONAL /obj/item/assembly/signaler/anomaly/grav
|
||||
/// Flux
|
||||
#define ANOMALY_CORE_FLUX /obj/item/assembly/signaler/anomaly/flux
|
||||
/// Vortex
|
||||
#define ANOMALY_CORE_VORTEX /obj/item/assembly/signaler/anomaly/vortex
|
||||
/// Pyro
|
||||
#define ANOMALY_CORE_PYRO /obj/item/assembly/signaler/anomaly/pyro
|
||||
|
||||
// Max amounts of cores you can make
|
||||
#define MAX_CORES_BLUESPACE 8
|
||||
#define MAX_CORES_GRAVITATIONAL 8
|
||||
#define MAX_CORES_FLUX 8
|
||||
#define MAX_CORES_VORTEX 8
|
||||
#define MAX_CORES_PYRO 8
|
||||
|
||||
/// chance supermatter anomalies drop real cores
|
||||
#define SUPERMATTER_ANOMALY_DROP_CHANCE 20
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
#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
|
||||
|
||||
@@ -93,7 +93,6 @@
|
||||
// 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
|
||||
|
||||
@@ -26,3 +26,10 @@
|
||||
#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, \
|
||||
))))
|
||||
@@ -17,7 +17,7 @@
|
||||
var/matrix/mtrx=new()
|
||||
return mtrx.Scale(0.65)
|
||||
|
||||
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.
|
||||
/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.
|
||||
for(var/spath in subtypesof(/datum/species))
|
||||
var/datum/species/S = new spath()
|
||||
var/list/wlist = S.whitelist
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#define EXTOOLS_LOGGING // rust_g is used as a fallback if this is undefined
|
||||
|
||||
/proc/extools_log_write()
|
||||
|
||||
/proc/extools_finalize_logging()
|
||||
@@ -681,3 +681,11 @@
|
||||
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)
|
||||
|
||||
@@ -4,10 +4,15 @@
|
||||
#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
|
||||
#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text)
|
||||
#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text)
|
||||
#ifdef EXTOOLS_LOGGING
|
||||
// proc hooked, so we can just put in standard TRUE and FALSE
|
||||
#define WRITE_LOG(log, text) extools_log_write(log,text,TRUE)
|
||||
#define WRITE_LOG_NO_FORMAT(log, text) extools_log_write(log,text,FALSE)
|
||||
#else
|
||||
//This is an external call, "true" and "false" are how rust parses out booleans
|
||||
#define WRITE_LOG(log, text) rustg_log_write(log, text, "true")
|
||||
#define WRITE_LOG_NO_FORMAT(log, text) rustg_log_write(log, text, "false")
|
||||
|
||||
#endif
|
||||
//print a warning message to world.log
|
||||
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [UNLINT(src)] usr: [usr].")
|
||||
/proc/warning(msg)
|
||||
@@ -216,7 +221,11 @@
|
||||
|
||||
/* Close open log handles. This should be called as late as possible, and no logging should hapen after. */
|
||||
/proc/shutdown_logging()
|
||||
#ifdef EXTOOLS_LOGGING
|
||||
extools_finalize_logging()
|
||||
#else
|
||||
rustg_log_close_all()
|
||||
#endif
|
||||
|
||||
|
||||
/* Helper procs for building detailed log lines */
|
||||
|
||||
@@ -71,3 +71,18 @@
|
||||
|
||||
/proc/pathflatten(path)
|
||||
return replacetext(path, "/", "_")
|
||||
|
||||
/// Returns the md5 of a file at a given path.
|
||||
/proc/md5filepath(path)
|
||||
. = md5(file(path))
|
||||
|
||||
/// Save file as an external file then md5 it.
|
||||
/// Used because md5ing files stored in the rsc sometimes gives incorrect md5 results.
|
||||
/proc/md5asfile(file)
|
||||
var/static/notch = 0
|
||||
// its importaint this code can handle md5filepath sleeping instead of hard blocking, if it's converted to use rust_g.
|
||||
var/filename = "tmp/md5asfile.[world.realtime].[world.timeofday].[world.time].[world.tick_usage].[notch]"
|
||||
notch = WRAP(notch+1, 0, 2^15)
|
||||
fcopy(file, filename)
|
||||
. = md5filepath(filename)
|
||||
fdel(filename)
|
||||
|
||||
+38
-17
@@ -1103,24 +1103,36 @@ 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
|
||||
|
||||
//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")
|
||||
|
||||
/// 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)
|
||||
if (!isicon(icon))
|
||||
return FALSE
|
||||
WRITE_FILE(GLOB.iconCache[iconKey], icon)
|
||||
var/iconData = GLOB.iconCache.ExportText(iconKey)
|
||||
WRITE_FILE(GLOB.dummySave["dummy"], icon)
|
||||
var/iconData = GLOB.dummySave.ExportText("dummy")
|
||||
var/list/partial = splittext(iconData, "{")
|
||||
return replacetext(copytext_char(partial[2], 3, -5), "\n", "")
|
||||
|
||||
/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving = FALSE)
|
||||
/proc/icon2html(thing, target, icon_state, dir = SOUTH, frame = 1, moving = FALSE, sourceonly = FALSE)
|
||||
if (!thing)
|
||||
return
|
||||
|
||||
var/key
|
||||
var/icon/I = thing
|
||||
|
||||
if (!target)
|
||||
return
|
||||
if (target == world)
|
||||
@@ -1136,17 +1148,26 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
|
||||
if (!isicon(I))
|
||||
if (isfile(thing)) //special snowflake
|
||||
var/name = sanitize_filename("[generate_asset_name(thing)].png")
|
||||
if(!SSassets.cache[name])
|
||||
register_asset(name, thing)
|
||||
if (!SSassets.cache[name])
|
||||
SSassets.transport.register_asset(name, thing)
|
||||
for (var/thing2 in targets)
|
||||
send_asset(thing2, key)
|
||||
return "<img class='icon icon-misc' src=\"[url_encode(name)]\">"
|
||||
SSassets.transport.send_assets(thing2, name)
|
||||
if(sourceonly)
|
||||
return SSassets.transport.get_asset_url(name)
|
||||
return "<img class='icon icon-misc' src='[SSassets.transport.get_asset_url(name)]'>"
|
||||
var/atom/A = thing
|
||||
if (isnull(dir))
|
||||
dir = A.dir
|
||||
|
||||
I = A.icon
|
||||
if (isnull(icon_state))
|
||||
icon_state = A.icon_state
|
||||
I = A.icon
|
||||
if (!(icon_state in icon_states(I, 1)))
|
||||
icon_state = initial(A.icon_state)
|
||||
if (isnull(dir))
|
||||
dir = initial(A.dir)
|
||||
|
||||
if (isnull(dir))
|
||||
dir = A.dir
|
||||
|
||||
if (ishuman(thing)) // Shitty workaround for a BYOND issue.
|
||||
var/icon/temp = I
|
||||
I = icon()
|
||||
@@ -1162,11 +1183,11 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
|
||||
|
||||
key = "[generate_asset_name(I)].png"
|
||||
if(!SSassets.cache[key])
|
||||
register_asset(key, I)
|
||||
SSassets.transport.register_asset(key, I)
|
||||
for (var/thing2 in targets)
|
||||
send_asset(thing2, key)
|
||||
SSassets.transport.send_assets(thing2, key)
|
||||
|
||||
return "<img class='icon icon-[icon_state]' src=\"[url_encode(key)]\">"
|
||||
return "<img class='icon icon-[icon_state]' src='[SSassets.transport.get_asset_url(key)]'>"
|
||||
|
||||
/proc/icon2base64html(thing)
|
||||
if (!thing)
|
||||
|
||||
@@ -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(0)
|
||||
roundend_report.open(FALSE)
|
||||
|
||||
/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> (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>[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 += 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> (Played by: <b>[robo.mind.key]</b>)[robo.stat == DEAD ? " <span class='redtext'>(Deactivated)</span>" : ""][borg_num ?", ":""]<br>"
|
||||
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>"
|
||||
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> (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>[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:"
|
||||
|
||||
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.key]</b> was <b>[ply.name]</b>[jobtext] and"
|
||||
var/text = "<b>[ply.hide_ckey ? "<b>[ply.name]</b>[jobtext] " : "[ply.key]</b> was <b>[ply.name]</b>[jobtext] and "]"
|
||||
if(ply.current)
|
||||
if(ply.current.stat == DEAD)
|
||||
text += " <span class='redtext'>died</span>"
|
||||
|
||||
+14
-10
@@ -462,16 +462,14 @@
|
||||
else
|
||||
. = max(0, min(255, 138.5177312231 * log(temp - 10) - 305.0447927307))
|
||||
|
||||
/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/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/color2hex(color) //web colors
|
||||
if(!color)
|
||||
@@ -620,6 +618,12 @@
|
||||
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
|
||||
|
||||
@@ -107,13 +107,8 @@ 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,
|
||||
|
||||
@@ -13,6 +13,7 @@ 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
|
||||
|
||||
@@ -184,14 +184,23 @@
|
||||
|
||||
/obj/screen/alert/hot
|
||||
name = "Too Hot"
|
||||
desc = "You're flaming hot! Get somewhere cooler and take off any insulating clothing like a fire suit."
|
||||
desc = "The air around you is pretty toasty! Consider putting on some insulating clothing, or moving to a cooler area."
|
||||
icon_state = "hot"
|
||||
|
||||
/obj/screen/alert/cold
|
||||
name = "Too Cold"
|
||||
desc = "You're freezing cold! Get somewhere warmer and take off any insulating clothing like a space suit."
|
||||
desc = "The air around you is pretty cold! Consider wearing a coat, or moving to a warmer area."
|
||||
icon_state = "cold"
|
||||
|
||||
/obj/screen/alert/sweat
|
||||
name = "Sweating"
|
||||
desc = "You're sweating! Get somewhere cooler and take off any insulating clothing like a fire suit."
|
||||
icon_state = "sweat"
|
||||
|
||||
/obj/screen/alert/shiver
|
||||
name = "Shivering"
|
||||
desc = "You're shivering! Get somewhere warmer and take off any insulating clothing like a space suit."
|
||||
|
||||
/obj/screen/alert/lowpressure
|
||||
name = "Low Pressure"
|
||||
desc = "The air around you is hazardously thin. A space suit would protect you."
|
||||
|
||||
@@ -14,13 +14,15 @@
|
||||
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())
|
||||
@@ -50,6 +52,11 @@
|
||||
break
|
||||
loadmaplist(CONFIG_MAPS_FILE)
|
||||
LoadMOTD()
|
||||
// LoadPolicy()
|
||||
// LoadChatFilter()
|
||||
|
||||
if (Master)
|
||||
Master.OnConfigLoad()
|
||||
|
||||
/datum/controller/configuration/proc/full_wipe()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
@@ -135,7 +142,7 @@
|
||||
|
||||
if(entry == "$include")
|
||||
if(!value)
|
||||
log_config("LINE [linenumber]: Invalid $include directive: [value]")
|
||||
log_config("LINE [linenumber]: Warning: Invalid $include directive: [value]")
|
||||
else
|
||||
LoadEntries(value, stack)
|
||||
++.
|
||||
@@ -143,7 +150,7 @@
|
||||
|
||||
var/datum/config_entry/E = _entries[entry]
|
||||
if(!E)
|
||||
log_config("LINE [linenumber]: Unknown setting: '[entry]'")
|
||||
log_config("LINE [linenumber]: Unknown setting in configuration: '[entry]'")
|
||||
continue
|
||||
|
||||
if(lockthis)
|
||||
@@ -153,9 +160,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] 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 [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)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/message_admins, "This server is using deprecated configuration settings. Please check the logs and update accordingly."), 0)
|
||||
DelayedMessageAdmins("This server is using deprecated configuration settings. Please check the logs and update accordingly.")
|
||||
warned_deprecated_configs = TRUE
|
||||
if(good_update)
|
||||
value = new_value
|
||||
@@ -163,7 +170,7 @@
|
||||
else
|
||||
warning("[new_ver.type] is deprecated but gave no proper return for DeprecationUpdate()")
|
||||
|
||||
var/validated = E.ValidateAndSet(value, TRUE)
|
||||
var/validated = E.ValidateAndSet(value)
|
||||
if(!validated)
|
||||
log_config("LINE [linenumber]: Failed to validate setting \"[value]\" for [entry]")
|
||||
else
|
||||
@@ -195,13 +202,7 @@
|
||||
statclick = new/obj/effect/statclick/debug(null, "Edit", src)
|
||||
stat("[name]:", statclick)
|
||||
|
||||
/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
|
||||
|
||||
/// Your typical GET but returns a config.
|
||||
/datum/controller/configuration/proc/GetEntryDatum(entry_type)
|
||||
var/datum/config_entry/E = entry_type
|
||||
var/entry_is_abstract = initial(E.abstract_type) == entry_type
|
||||
@@ -210,8 +211,24 @@
|
||||
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
|
||||
@@ -236,7 +253,6 @@
|
||||
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)
|
||||
@@ -258,7 +274,37 @@
|
||||
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]"
|
||||
@@ -305,6 +351,8 @@
|
||||
currentmap.voteweight = text2num(data)
|
||||
if ("default","defaultmap")
|
||||
defaultmap = currentmap
|
||||
//if ("votable")
|
||||
// currentmap.votable = TRUE
|
||||
if ("endmap")
|
||||
LAZYINITLIST(maplist)
|
||||
maplist[currentmap.map_name] = currentmap
|
||||
@@ -326,6 +374,7 @@
|
||||
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
|
||||
@@ -334,6 +383,32 @@
|
||||
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)
|
||||
@@ -367,32 +442,6 @@
|
||||
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)
|
||||
@@ -418,7 +467,6 @@
|
||||
/*
|
||||
/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...")
|
||||
@@ -428,8 +476,8 @@
|
||||
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,6 +368,10 @@
|
||||
|
||||
/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
|
||||
@@ -384,6 +388,10 @@
|
||||
/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
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/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)
|
||||
@@ -16,4 +16,4 @@
|
||||
|
||||
/datum/controller/proc/Recover()
|
||||
|
||||
/datum/controller/proc/stat_entry()
|
||||
/datum/controller/proc/stat_entry()
|
||||
|
||||
@@ -76,7 +76,11 @@ 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)
|
||||
random_seed = (TEST_RUN_PARAMETER in world.params) ? 29051994 : rand(1, 1e9)
|
||||
#ifdef UNIT_TESTS
|
||||
random_seed = 29051994
|
||||
#else
|
||||
random_seed = rand(1, 1e9)
|
||||
#endif
|
||||
rand_seed(random_seed)
|
||||
|
||||
var/list/_subsystems = list()
|
||||
@@ -184,9 +188,6 @@ 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)
|
||||
|
||||
@@ -219,6 +220,9 @@ 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)
|
||||
@@ -643,3 +647,8 @@ 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()
|
||||
|
||||
@@ -1,39 +1,91 @@
|
||||
/**
|
||||
* # 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
|
||||
|
||||
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)
|
||||
/// Name of the subsystem - you must change this
|
||||
name = "fire coderbus"
|
||||
|
||||
var/initialized = FALSE //set to TRUE after it has been initialized, will obviously never be set if the subsystem doesn't initialize
|
||||
/// 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
|
||||
|
||||
//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
|
||||
/// 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
|
||||
var/can_fire = TRUE
|
||||
|
||||
// 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
|
||||
var/datum/controller/subsystem/queue_prev
|
||||
|
||||
///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
|
||||
|
||||
var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out!
|
||||
/*
|
||||
* 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
|
||||
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.
|
||||
|
||||
|
||||
//Do not override
|
||||
///datum/controller/subsystem/New()
|
||||
@@ -46,6 +98,7 @@
|
||||
|
||||
//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)
|
||||
@@ -87,7 +140,7 @@
|
||||
queue_node_flags = queue_node.flags
|
||||
|
||||
if (queue_node_flags & SS_TICKER)
|
||||
if (!(SS_flags & SS_TICKER))
|
||||
if ((SS_flags & (SS_TICKER|SS_BACKGROUND)) != SS_TICKER)
|
||||
continue
|
||||
if (queue_node_priority < SS_priority)
|
||||
break
|
||||
@@ -155,6 +208,9 @@
|
||||
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)
|
||||
|
||||
|
||||
@@ -4,6 +4,23 @@ 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))
|
||||
@@ -11,8 +28,6 @@ SUBSYSTEM_DEF(assets)
|
||||
if (type != initial(A._abstract))
|
||||
get_asset_datum(type)
|
||||
|
||||
preload = cache.Copy() //don't preload assets generated during the round
|
||||
transport.Initialize(cache)
|
||||
|
||||
for(var/client/C in GLOB.clients)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, preload, FALSE), 10)
|
||||
..()
|
||||
|
||||
@@ -90,6 +90,8 @@ SUBSYSTEM_DEF(atoms)
|
||||
qdeleted = TRUE
|
||||
else if(!(A.flags_1 & INITIALIZED_1))
|
||||
BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT
|
||||
else
|
||||
SEND_SIGNAL(A,COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE)
|
||||
|
||||
return qdeleted || QDELING(A)
|
||||
|
||||
|
||||
@@ -5,91 +5,35 @@ SUBSYSTEM_DEF(chat)
|
||||
priority = FIRE_PRIORITY_CHAT
|
||||
init_order = INIT_ORDER_CHAT
|
||||
|
||||
var/list/payload = list()
|
||||
|
||||
var/list/payload_by_client = list()
|
||||
|
||||
/datum/controller/subsystem/chat/fire()
|
||||
for(var/i in payload)
|
||||
var/client/C = i
|
||||
C << output(payload[C], "browseroutput:output")
|
||||
payload -= C
|
||||
|
||||
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"])
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
|
||||
/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE, trailing_newline = TRUE, confidential = TRUE)
|
||||
if(!target || !message)
|
||||
return
|
||||
|
||||
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
|
||||
|
||||
/datum/controller/subsystem/chat/proc/queue(target, text, flags)
|
||||
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
|
||||
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,
|
||||
)))
|
||||
return
|
||||
var/client/client = CLIENT_FROM_VAR(target)
|
||||
if(client)
|
||||
LAZYADD(payload_by_client[client], list(list(
|
||||
"text" = text,
|
||||
"flags" = flags,
|
||||
)))
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
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
|
||||
@@ -294,6 +294,17 @@ SUBSYSTEM_DEF(research)
|
||||
//[88nodes * 5000points/node] / [1.5hr * 90min/hr * 60s/min]
|
||||
//Around 450000 points max???
|
||||
|
||||
/// The global list of raw anomaly types that have been refined, for hard limits.
|
||||
var/list/created_anomaly_types = list()
|
||||
/// The hard limits of cores created for each anomaly type. For faster code lookup without switch statements.
|
||||
var/list/anomaly_hard_limit_by_type = list(
|
||||
ANOMALY_CORE_BLUESPACE = MAX_CORES_BLUESPACE,
|
||||
ANOMALY_CORE_PYRO = MAX_CORES_PYRO,
|
||||
ANOMALY_CORE_GRAVITATIONAL = MAX_CORES_GRAVITATIONAL,
|
||||
ANOMALY_CORE_VORTEX = MAX_CORES_VORTEX,
|
||||
ANOMALY_CORE_FLUX = MAX_CORES_FLUX
|
||||
)
|
||||
|
||||
/datum/controller/subsystem/research/Initialize()
|
||||
point_types = TECHWEB_POINT_TYPE_LIST_ASSOCIATIVE_NAMES
|
||||
initialize_all_techweb_designs()
|
||||
|
||||
@@ -76,9 +76,7 @@ SUBSYSTEM_DEF(server_maint)
|
||||
if(!thing)
|
||||
continue
|
||||
var/client/C = thing
|
||||
var/datum/chatOutput/co = C.chatOutput
|
||||
if(co)
|
||||
co.ehjax_send(data = "roundrestart")
|
||||
C?.tgui_panel?.send_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()
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/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/span
|
||||
var/span_flag
|
||||
|
||||
/datum/accent/span/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/span/sans
|
||||
span_flag = SPAN_SANS
|
||||
|
||||
/datum/accent/span/papyrus
|
||||
span_flag = SPAN_PAPYRUS
|
||||
|
||||
/datum/accent/span/robot
|
||||
span_flag = 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
|
||||
+17
-20
@@ -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, var/atom/nref = null)
|
||||
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null)
|
||||
|
||||
user = nuser
|
||||
window_id = nwindow_id
|
||||
@@ -27,7 +27,6 @@
|
||||
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
|
||||
@@ -35,22 +34,21 @@
|
||||
/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])
|
||||
register_asset(asset_name, file)
|
||||
|
||||
if (!SSassets.cache[asset_name])
|
||||
SSassets.transport.register_asset(asset_name, file)
|
||||
|
||||
/datum/browser/proc/add_script(name, file)
|
||||
scripts["[ckey(name)].js"] = file
|
||||
register_asset("[ckey(name)].js", file)
|
||||
SSassets.transport.register_asset("[ckey(name)].js", file)
|
||||
|
||||
/datum/browser/proc/set_content(ncontent)
|
||||
content = ncontent
|
||||
@@ -60,15 +58,13 @@
|
||||
|
||||
/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='[file]'>"
|
||||
head_content += "<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url(file)]'>"
|
||||
|
||||
|
||||
for (file in scripts)
|
||||
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]);'"
|
||||
head_content += "<script type='text/javascript' src='[SSassets.transport.get_asset_url(file)]'></script>"
|
||||
|
||||
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
@@ -79,7 +75,7 @@
|
||||
</head>
|
||||
<body scroll=auto>
|
||||
<div class='uiWrapper'>
|
||||
[title ? "<div class='uiTitleWrapper'><div [title_attributes]><tt>[title]</tt></div></div>" : ""]
|
||||
[title ? "<div class='uiTitleWrapper'><div class='uiTitle'><tt>[title]</tt></div></div>" : ""]
|
||||
<div class='uiContent'>
|
||||
"}
|
||||
//" This is here because else the rest of the file looks like a string in notepad++.
|
||||
@@ -105,10 +101,11 @@
|
||||
var/window_size = ""
|
||||
if(width && height)
|
||||
window_size = "size=[width]x[height];"
|
||||
common_asset.send(user)
|
||||
if(stylesheets.len)
|
||||
send_asset_list(user, stylesheets)
|
||||
SSassets.transport.send_assets(user, stylesheets)
|
||||
if(scripts.len)
|
||||
send_asset_list(user, scripts)
|
||||
SSassets.transport.send_assets(user, scripts)
|
||||
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
|
||||
if(use_onclose)
|
||||
setup_onclose()
|
||||
@@ -169,7 +166,7 @@
|
||||
return Button3
|
||||
|
||||
//Same shit, but it returns the button number, could at some point support unlimited button amounts.
|
||||
/proc/askuser(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
|
||||
/proc/askuser(mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
|
||||
if (!istype(User))
|
||||
if (istype(User, /client/))
|
||||
var/client/C = User
|
||||
@@ -188,7 +185,7 @@
|
||||
var/selectedbutton = 0
|
||||
var/stealfocus
|
||||
|
||||
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, StealFocus = 1, Timeout = 6000)
|
||||
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null, StealFocus = 1, Timeout = 6000)
|
||||
..()
|
||||
stealfocus = StealFocus
|
||||
if (!StealFocus)
|
||||
|
||||
@@ -76,19 +76,11 @@
|
||||
return FALSE
|
||||
if(M.is_flying())
|
||||
return FALSE
|
||||
if(ishuman(AM))
|
||||
var/mob/living/carbon/human/H = AM
|
||||
if(istype(H.belt, /obj/item/wormhole_jaunter))
|
||||
var/obj/item/wormhole_jaunter/J = H.belt
|
||||
//To freak out any bystanders
|
||||
H.visible_message("<span class='boldwarning'>[H] falls into [parent]!</span>")
|
||||
J.chasm_react(H)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/component/chasm/proc/drop(atom/movable/AM)
|
||||
//Make sure the item is still there after our sleep
|
||||
if(!AM || QDELETED(AM))
|
||||
if(!AM || QDELETED(AM) || SEND_SIGNAL(AM, COMSIG_MOVABLE_CHASM_DROP, src))
|
||||
return
|
||||
falling_atoms[AM] = (falling_atoms[AM] || 0) + 1
|
||||
var/turf/T = target_turf
|
||||
|
||||
@@ -273,6 +273,16 @@
|
||||
time = 30
|
||||
category = CAT_CLOTHING
|
||||
|
||||
/datum/crafting_recipe/twinsheath
|
||||
name = "Twin Sword Sheath"
|
||||
result = /obj/item/storage/belt/sabre/twin
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 3,
|
||||
/obj/item/stack/sheet/leather = 8)
|
||||
tools = list(TOOL_WIRECUTTER)
|
||||
time = 70
|
||||
category = CAT_CLOTHING
|
||||
|
||||
|
||||
/datum/crafting_recipe/durathread_reinforcement_kit
|
||||
name = "Durathread Reinforcement Kit"
|
||||
result = /obj/item/armorkit
|
||||
|
||||
@@ -120,6 +120,53 @@
|
||||
category = CAT_MISC
|
||||
always_availible = FALSE // Disabled til learned
|
||||
|
||||
/datum/crafting_recipe/furnace
|
||||
name = "Sandstone Furnace"
|
||||
result = /obj/structure/furnace
|
||||
time = 300
|
||||
reqs = list(/obj/item/stack/sheet/mineral/sandstone = 15,
|
||||
/obj/item/stack/sheet/metal = 4,
|
||||
/obj/item/stack/rods = 2)
|
||||
tools = list(TOOL_CROWBAR)
|
||||
subcategory = CAT_MISCELLANEOUS
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/tableanvil
|
||||
name = "Table Anvil"
|
||||
result = /obj/structure/anvil/obtainable/table
|
||||
time = 300
|
||||
reqs = list(/obj/item/stack/sheet/metal = 4,
|
||||
/obj/item/stack/rods = 2)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WRENCH, TOOL_WELDER)
|
||||
subcategory = CAT_MISCELLANEOUS
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/sandvil
|
||||
name = "Sandstone Anvil"
|
||||
result = /obj/structure/anvil/obtainable/sandstone
|
||||
time = 300
|
||||
reqs = list(/obj/item/stack/sheet/mineral/sandstone = 24)
|
||||
tools = list(TOOL_CROWBAR)
|
||||
subcategory = CAT_MISCELLANEOUS
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/basaltblock
|
||||
name = "Sintered Basalt Block"
|
||||
result = /obj/item/basaltblock
|
||||
time = 200
|
||||
reqs = list(/obj/item/stack/ore/glass/basalt = 50)
|
||||
tools = list(TOOL_WELDER)
|
||||
subcategory = CAT_MISCELLANEOUS
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/basaltanvil
|
||||
name = "Basalt Anvil"
|
||||
result = /obj/structure/anvil/obtainable/basalt
|
||||
time = 200
|
||||
reqs = list(/obj/item/basaltblock = 5)
|
||||
tools = list(TOOL_CROWBAR)
|
||||
subcategory = CAT_MISCELLANEOUS
|
||||
category = CAT_MISC
|
||||
///////////////////
|
||||
//Tools & Storage//
|
||||
///////////////////
|
||||
@@ -175,6 +222,17 @@
|
||||
subcategory = CAT_TOOL
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/toolboxhammer
|
||||
name = "Toolbox Hammer"
|
||||
result = /obj/item/melee/smith/hammer/toolbox
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WRENCH, TOOL_WELDER)
|
||||
reqs = list(/obj/item/storage/toolbox = 1,
|
||||
/obj/item/stack/sheet/metal = 4,
|
||||
/obj/item/stack/rods = 2)
|
||||
time = 40
|
||||
subcategory = CAT_TOOL
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/papersack
|
||||
name = "Paper Sack"
|
||||
result = /obj/item/storage/box/papersack
|
||||
@@ -358,6 +416,25 @@
|
||||
//Unsorted//
|
||||
////////////
|
||||
|
||||
|
||||
|
||||
/datum/crafting_recipe/stick
|
||||
name = "Stick"
|
||||
time = 30
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 1)
|
||||
result = /obj/item/stick
|
||||
subcategory = CAT_MISCELLANEOUS
|
||||
category = CAT_MISC
|
||||
|
||||
|
||||
/datum/crafting_recipe/swordhilt
|
||||
name = "Sword Hilt"
|
||||
time = 30
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 2)
|
||||
result = /obj/item/swordhandle
|
||||
subcategory = CAT_MISCELLANEOUS
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/blackcarpet
|
||||
name = "Black Carpet"
|
||||
reqs = list(/obj/item/stack/tile/carpet = 50, /obj/item/toy/crayon/black = 1)
|
||||
|
||||
@@ -45,8 +45,9 @@
|
||||
|
||||
/datum/fantasy_affix/tactical/apply(datum/component/fantasy/comp, newName)
|
||||
var/obj/item/master = comp.parent
|
||||
master.AddElement(/datum/element/tactical)
|
||||
comp.appliedElements += list(/datum/element/tactical)
|
||||
var/list/dat = list(/datum/element/tactical)
|
||||
master._AddElement(dat)
|
||||
comp.appliedElements += list(dat)
|
||||
return "tactical [newName]"
|
||||
|
||||
/datum/fantasy_affix/pyromantic
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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)
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
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,4 +1,4 @@
|
||||
//Thing meant for allowing datums and objects to access a NTnet network datum.
|
||||
//Thing meant for allowing datums and objects to access an NTnet network datum.
|
||||
/datum/proc/ntnet_receive(datum/netdata/data)
|
||||
return
|
||||
|
||||
|
||||
@@ -113,9 +113,9 @@ Bonus
|
||||
symptom_delay_max = 90
|
||||
var/chems = FALSE
|
||||
var/explosion_power = 1
|
||||
threshold_desc = "<b>Resistance 9:</b> Doubles the intensity of the effect, but reduces its frequency.<br>\
|
||||
<b>Stage Speed 8:</b> Increases explosion radius when the host is wet.<br>\
|
||||
<b>Transmission 8:</b> Additionally synthesizes chlorine trifluoride and napalm inside the host."
|
||||
threshold_desc = list("Resistance 9" = "Doubles the intensity of the effect, but reduces its frequency.",
|
||||
"Stage Speed 8" = "Increases explosion radius when the host is wet.",
|
||||
"Transmission 8" = "Additionally synthesizes chlorine trifluoride and napalm inside the host.")
|
||||
|
||||
/datum/symptom/alkali/Start(datum/disease/advance/A)
|
||||
if(!..())
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
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)
|
||||
@@ -39,21 +40,28 @@
|
||||
/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))
|
||||
UnregisterSignal(A, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE,
|
||||
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, removing = FALSE)
|
||||
if(num_decals_per_atom[target] == 1 && !removing)
|
||||
RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlay, TRUE)
|
||||
target.update_icon()
|
||||
/datum/element/decal/proc/apply(atom/target)
|
||||
if(target.flags_1 & INITIALIZED_1)
|
||||
target.update_icon() //could use some queuing here now maybe.
|
||||
else if(!QDELETED(target) && num_decals_per_atom[target] == 1)
|
||||
RegisterSignal(target, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE, .proc/late_update_icon)
|
||||
if(isitem(target))
|
||||
addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE)
|
||||
|
||||
/datum/element/decal/proc/late_update_icon(atom/source)
|
||||
source.update_icon()
|
||||
UnregisterSignal(source,COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE)
|
||||
|
||||
/datum/element/decal/proc/apply_overlay(atom/source, list/overlay_list)
|
||||
pic.dir = first_dir == NORTH ? source.dir : turn(first_dir, dir2angle(source.dir))
|
||||
if(first_dir)
|
||||
pic.dir = first_dir == SOUTH ? source.dir : turn(first_dir, dir2angle(source.dir)-180) //Never turn a dir by 0.
|
||||
for(var/i in 1 to num_decals_per_atom[source])
|
||||
overlay_list += pic
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
A.AddElement(/datum/element/update_icon_updates_onmob)
|
||||
RegisterSignal(A, COMSIG_ITEM_WORN_OVERLAYS, .proc/apply_worn_overlays)
|
||||
if(suits_with_helmet_typecache[A.type])
|
||||
RegisterSignal(A, COMSIG_SUIT_MADE_HELMET, .proc/register_helmet)
|
||||
RegisterSignal(A, COMSIG_SUIT_MADE_HELMET, .proc/register_helmet) //you better work now you slut
|
||||
else if(_flags & POLYCHROMIC_ACTION && ismob(A)) //in the event mob update icon procs are ever standarized.
|
||||
var/datum/action/polychromic/P = new(A)
|
||||
RegisterSignal(P, COMSIG_ACTION_TRIGGER, .proc/activate_action)
|
||||
@@ -166,6 +166,15 @@
|
||||
examine_list += "<span class='notice'>Alt-click to recolor it.</span>"
|
||||
|
||||
/datum/element/polychromic/proc/register_helmet(atom/source, obj/item/clothing/head/H)
|
||||
if(!isitem(H)) //backup in case if it messes up somehow
|
||||
if(istype(source,/obj/item/clothing/suit/hooded)) //so how come it be like this, where toggleable headslots are named separately (helmet/hood) anyways?
|
||||
var/obj/item/clothing/suit/hooded/sourcesuit = source
|
||||
H = sourcesuit.hood
|
||||
else if(istype(source,/obj/item/clothing/suit/space/hardsuit))
|
||||
var/obj/item/clothing/suit/space/hardsuit/sourcesuit = source
|
||||
H = sourcesuit.helmet
|
||||
else
|
||||
return
|
||||
suit_by_helmet[H] = source
|
||||
helmet_by_suit[source] = H
|
||||
colors_by_atom[H] = colors_by_atom[source]
|
||||
|
||||
@@ -102,8 +102,9 @@
|
||||
|
||||
/datum/emote/proc/can_run_emote(mob/user, status_check = TRUE, intentional = FALSE)
|
||||
. = TRUE
|
||||
if(!is_type_in_typecache(user, mob_type_allowed_typecache))
|
||||
return FALSE
|
||||
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_blacklist_typecache))
|
||||
return FALSE
|
||||
if(status_check && !is_type_in_typecache(user, mob_type_ignore_stat_typecache))
|
||||
|
||||
@@ -35,23 +35,24 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
value_per_unit = 0.025
|
||||
beauty_modifier = 0.075
|
||||
|
||||
///Slight force increase
|
||||
///Slight force decrease. It's gold, it's soft as fuck.
|
||||
/datum/material/gold
|
||||
name = "gold"
|
||||
desc = "Gold"
|
||||
color = list(340/255, 240/255, 50/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //gold is shiny, but not as bright as bananium
|
||||
strength_modifier = 1.2
|
||||
strength_modifier = 0.8
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/gold
|
||||
value_per_unit = 0.0625
|
||||
beauty_modifier = 0.15
|
||||
armor_modifiers = list("melee" = 1.1, "bullet" = 1.1, "laser" = 1.15, "energy" = 1.15, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 0.7, "acid" = 1.1)
|
||||
|
||||
///Has no special properties
|
||||
///Small force increase, for diamond swords
|
||||
/datum/material/diamond
|
||||
name = "diamond"
|
||||
desc = "Highly pressurized carbon"
|
||||
color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
strength_modifier = 1.1
|
||||
alpha = 132
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/diamond
|
||||
@@ -106,6 +107,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
name = "bluespace crystal"
|
||||
desc = "Crystals with bluespace properties"
|
||||
color = list(119/255, 217/255, 396/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
integrity_modifier = 0.2 //these things shatter when thrown.
|
||||
alpha = 200
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE)
|
||||
beauty_modifier = 0.5
|
||||
@@ -139,7 +141,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
name = "titanium"
|
||||
desc = "Titanium"
|
||||
color = "#b3c0c7"
|
||||
strength_modifier = 1.3
|
||||
strength_modifier = 1.1
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/titanium
|
||||
value_per_unit = 0.0625
|
||||
@@ -203,7 +205,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
name = "adamantine"
|
||||
desc = "A powerful material made out of magic, I mean science!"
|
||||
color = "#6d7e8e"
|
||||
strength_modifier = 1.5
|
||||
strength_modifier = 1.3
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/adamantine
|
||||
value_per_unit = 0.25
|
||||
@@ -276,16 +278,29 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
desc = "Mir'ntrath barhah Nar'sie."
|
||||
color = "#3C3434"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
strength_modifier = 1.2
|
||||
sheet_type = /obj/item/stack/sheet/runed_metal
|
||||
value_per_unit = 0.75
|
||||
armor_modifiers = list("melee" = 1.2, "bullet" = 1.2, "laser" = 1, "energy" = 1, "bomb" = 1.2, "bio" = 1.2, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = -0.15
|
||||
texture_layer_icon_state = "runed"
|
||||
|
||||
/datum/material/brass
|
||||
name = "brass"
|
||||
desc = "Tybel gb-Ratvar"
|
||||
color = "#917010"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
strength_modifier = 1.3 // Replicant Alloy is very good for skull beatings..
|
||||
sheet_type = /obj/item/stack/tile/brass
|
||||
value_per_unit = 0.75
|
||||
armor_modifiers = list("melee" = 1.4, "bullet" = 1.4, "laser" = 0, "energy" = 0, "bomb" = 1.4, "bio" = 1.2, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5) //But it has.. a few problems that can't easily be compensated for.
|
||||
beauty_modifier = 0.3 //It really beats the cold plain plating of the station, doesn't it?
|
||||
|
||||
/datum/material/bronze
|
||||
name = "bronze"
|
||||
desc = "Clock Cult? Never heard of it."
|
||||
color = "#92661A"
|
||||
strength_modifier = 1.1
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/bronze
|
||||
value_per_unit = 0.025
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
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
|
||||
@@ -69,6 +71,7 @@
|
||||
///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
|
||||
@@ -137,6 +140,8 @@
|
||||
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)
|
||||
|
||||
@@ -780,6 +785,7 @@
|
||||
if(!mind.name)
|
||||
mind.name = real_name
|
||||
mind.current = src
|
||||
mind.hide_ckey = client?.prefs?.hide_ckey
|
||||
|
||||
/mob/living/carbon/mind_initialize()
|
||||
..()
|
||||
|
||||
@@ -204,6 +204,11 @@
|
||||
mood_change = -1
|
||||
timeout = 2 MINUTES
|
||||
|
||||
/datum/mood_event/plush_bite
|
||||
description = "<span class='warning'>IT BIT ME!! OW!</span>\n"
|
||||
mood_change = -3
|
||||
timeout = 2 MINUTES
|
||||
|
||||
//Cursed stuff below
|
||||
|
||||
/datum/mood_event/emptypred
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
/**
|
||||
* Automatic skill increase, multiplied by skill affinity if existing.
|
||||
* Only works if skill is numerical.
|
||||
* Only works if skill is numerical or levelled..
|
||||
*/
|
||||
/datum/mind/proc/auto_gain_experience(skill, value, maximum, silent = FALSE)
|
||||
if(!ispath(skill, /datum/skill))
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/datum/skill/level/dorfy/blacksmithing
|
||||
name = "Blacksmithing"
|
||||
desc = "Making metal into fancy shapes using heat and force. Higher levels increase both your working speed at an anvil as well as the quality of your works."
|
||||
name_color = COLOR_FLOORTILE_GRAY
|
||||
skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
|
||||
ui_category = SKILL_UI_CAT_MISC
|
||||
@@ -580,4 +580,63 @@
|
||||
/datum/status_effect/regenerative_core/on_remove()
|
||||
. = ..()
|
||||
REMOVE_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "regenerative_core")
|
||||
owner.updatehealth()
|
||||
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()
|
||||
|
||||
@@ -536,6 +536,38 @@
|
||||
if(100)
|
||||
H.adjustOrganLoss(ORGAN_SLOT_BRAIN,20)
|
||||
|
||||
/datum/status_effect/corrosion_curse/lesser
|
||||
id = "corrosion_curse_lesser"
|
||||
duration = 20 SECONDS
|
||||
|
||||
/datum/status_effect/corrosion_curse/lesser/tick()
|
||||
. = ..()
|
||||
if(!ishuman(owner))
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/chance = rand(0,100)
|
||||
switch(chance)
|
||||
if(0 to 19)
|
||||
H.adjustBruteLoss(6)
|
||||
if(20 to 29)
|
||||
H.Dizzy(10)
|
||||
if(30 to 39)
|
||||
H.adjustOrganLoss(ORGAN_SLOT_LIVER,2)
|
||||
if(40 to 49)
|
||||
H.adjustOrganLoss(ORGAN_SLOT_HEART,2)
|
||||
if(50 to 59)
|
||||
H.adjustOrganLoss(ORGAN_SLOT_STOMACH,2)
|
||||
if(60 to 69)
|
||||
H.adjustOrganLoss(ORGAN_SLOT_EYES,5)
|
||||
if(70 to 79)
|
||||
H.adjustOrganLoss(ORGAN_SLOT_EARS,5)
|
||||
if(80 to 89)
|
||||
H.adjustOrganLoss(ORGAN_SLOT_LUNGS,5)
|
||||
if(90 to 99)
|
||||
H.adjustOrganLoss(ORGAN_SLOT_TONGUE,5)
|
||||
if(100)
|
||||
H.adjustOrganLoss(ORGAN_SLOT_BRAIN,10)
|
||||
|
||||
/datum/status_effect/amok
|
||||
id = "amok"
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
|
||||
@@ -6,10 +6,6 @@ GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (30 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_min, (10 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_max, (30 MINUTES))
|
||||
|
||||
GLOBAL_VAR_INIT(dynamic_event_delay_min, (10 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_event_delay_max, (30 MINUTES)) // this is on top of regular events, so can't be quite as often
|
||||
|
||||
|
||||
// -- Roundstart injection delays
|
||||
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_min, (2 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_max, (30 MINUTES))
|
||||
@@ -58,7 +54,7 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
// Threat logging vars
|
||||
/// Starting threat level, for things that increase it but can bring it back down.
|
||||
var/initial_threat_level = 0
|
||||
/// Target threat level right now. Events and antags will try to keep the round at this level.
|
||||
/// Target threat level right now. Antags will try to keep the round at this level.
|
||||
var/threat_level = 0
|
||||
/// The current antag threat. Recalculated every time a ruletype starts or ends.
|
||||
var/threat = 0
|
||||
@@ -80,8 +76,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
var/list/latejoin_rules = list()
|
||||
/// List of midround rules used for selecting the rules.
|
||||
var/list/midround_rules = list()
|
||||
/// List of events used for reducing threat without causing antag injection (necessarily).
|
||||
var/list/events = list()
|
||||
/** # Pop range per requirement.
|
||||
* If the value is five the range is:
|
||||
* 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+
|
||||
@@ -119,8 +113,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
var/latejoin_injection_cooldown = 0
|
||||
/// When world.time is over this number the mode tries to inject a midround ruleset.
|
||||
var/midround_injection_cooldown = 0
|
||||
/// When wor.dtime is over this number the mode tries to do an event.
|
||||
var/event_injection_cooldown = 0
|
||||
/// When TRUE GetInjectionChance returns 100.
|
||||
var/forced_injection = FALSE
|
||||
/// Forced ruleset to be executed for the next latejoin.
|
||||
@@ -184,7 +176,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
dat += "<br>Injection Timers: (<b>[storyteller.get_injection_chance(TRUE)]%</b> chance)<BR>"
|
||||
dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)/10] seconds"] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
|
||||
dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)/10] seconds"] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
|
||||
dat += "Event: [(event_injection_cooldown-world.time)>60*10 ? "[round((event_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(event_injection_cooldown-world.time)/10] seconds"] <a href='?src=\ref[src];[HrefToken()];forceevent=1'>\[Now!\]</a><BR>"
|
||||
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
|
||||
|
||||
/datum/game_mode/dynamic/Topic(href, href_list)
|
||||
@@ -204,10 +195,7 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
var/threatadd = input("Specify how much threat to add (negative to subtract). This can inflate the threat level.", "Adjust Threat", 0) as null|num
|
||||
if(!threatadd)
|
||||
return
|
||||
if(threatadd > 0)
|
||||
create_threat(threatadd)
|
||||
else
|
||||
remove_threat(threatadd)
|
||||
create_threat(threatadd)
|
||||
else if (href_list["injectlate"])
|
||||
latejoin_injection_cooldown = 0
|
||||
forced_injection = TRUE
|
||||
@@ -216,10 +204,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
midround_injection_cooldown = 0
|
||||
forced_injection = TRUE
|
||||
message_admins("[key_name(usr)] forced a midround injection.", 1)
|
||||
else if (href_list["forceevent"])
|
||||
event_injection_cooldown = 0
|
||||
// events always happen anyway
|
||||
message_admins("[key_name(usr)] forced an event.", 1)
|
||||
else if (href_list["threatlog"])
|
||||
show_threatlog(usr)
|
||||
else if (href_list["stacking_limit"])
|
||||
@@ -377,8 +361,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
generate_threat()
|
||||
|
||||
storyteller.start_injection_cooldowns()
|
||||
SSevents.frequency_lower = storyteller.event_frequency_lower // 6 minutes by default
|
||||
SSevents.frequency_upper = storyteller.event_frequency_upper // 20 minutes by default
|
||||
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
|
||||
initial_threat_level = threat_level
|
||||
return TRUE
|
||||
@@ -397,9 +379,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
if ("Midround")
|
||||
if (ruleset.weight)
|
||||
midround_rules += ruleset
|
||||
if("Event")
|
||||
if(ruleset.weight)
|
||||
events += ruleset
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
|
||||
roundstart_pop_ready++
|
||||
@@ -596,8 +575,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
latejoin_rules = remove_from_list(latejoin_rules, rule.type)
|
||||
else if(rule.ruletype == "Midround")
|
||||
midround_rules = remove_from_list(midround_rules, rule.type)
|
||||
else if(rule.ruletype == "Event")
|
||||
events = remove_from_list(events,rule.type)
|
||||
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_midround_latejoin_rule, rule), rule.delay)
|
||||
return TRUE
|
||||
|
||||
@@ -706,17 +683,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
picking_midround_latejoin_rule(drafted_rules)
|
||||
// get_injection_chance can do things on fail
|
||||
|
||||
if(event_injection_cooldown < world.time)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Attempted event injections")
|
||||
event_injection_cooldown = storyteller.get_event_cooldown() + world.time
|
||||
message_admins("DYNAMIC: Doing event injection.")
|
||||
log_game("DYNAMIC: Doing event injection.")
|
||||
update_playercounts()
|
||||
var/list/drafted_rules = storyteller.event_draft()
|
||||
if(drafted_rules.len > 0)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Successful event injections")
|
||||
picking_midround_latejoin_rule(drafted_rules)
|
||||
|
||||
/// Updates current_players.
|
||||
/datum/game_mode/dynamic/proc/update_playercounts()
|
||||
current_players[CURRENT_LIVING_PLAYERS] = list()
|
||||
|
||||
@@ -1,454 +0,0 @@
|
||||
/datum/dynamic_ruleset/event
|
||||
ruletype = "Event"
|
||||
var/typepath // typepath of the event
|
||||
var/triggering
|
||||
var/earliest_start = 20 MINUTES
|
||||
|
||||
/datum/dynamic_ruleset/event/get_blackbox_info()
|
||||
var/list/ruleset_data = list()
|
||||
ruleset_data["name"] = name
|
||||
ruleset_data["rule_type"] = ruletype
|
||||
ruleset_data["cost"] = total_cost
|
||||
ruleset_data["weight"] = weight
|
||||
ruleset_data["scaled_times"] = scaled_times
|
||||
ruleset_data["event_type"] = typepath
|
||||
ruleset_data["population_tier"] = indice_pop
|
||||
return ruleset_data
|
||||
|
||||
/datum/dynamic_ruleset/event/execute()
|
||||
var/datum/round_event/E = new typepath()
|
||||
E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
|
||||
// E.control = src // can't be done! we just don't use events that require these, those can be from_ghost almost always
|
||||
|
||||
testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
|
||||
deadchat_broadcast("<span class='deadsay'><b>[name]</b> has just been triggered by dynamic!</span>")
|
||||
log_game("Random Event triggering: [name] ([typepath])")
|
||||
|
||||
return E
|
||||
|
||||
/datum/dynamic_ruleset/event/ready(forced = FALSE)
|
||||
if (!forced)
|
||||
if(earliest_start >= world.time-SSticker.round_start_time)
|
||||
return FALSE
|
||||
var/job_check = 0
|
||||
if (enemy_roles.len > 0)
|
||||
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
|
||||
if (M.stat == DEAD)
|
||||
continue // Dead players cannot count as opponents
|
||||
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles))
|
||||
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
|
||||
|
||||
var/threat = round(mode.threat_level/10)
|
||||
if (job_check < required_enemies[threat])
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough enemy roles")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// PIRATES //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/pirates
|
||||
name = "Space Pirates"
|
||||
config_tag = "pirates"
|
||||
typepath = /datum/round_event/pirates
|
||||
antag_flag = ROLE_TRAITOR
|
||||
enemy_roles = list("AI","Security Officer","Head of Security","Captain")
|
||||
required_enemies = list(2,2,1,1,0,0,0,0,0,0)
|
||||
weight = 5
|
||||
cost = 10
|
||||
earliest_start = 30 MINUTES
|
||||
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
|
||||
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
||||
property_weights = list("story_potential" = 1, "trust" = 1, "chaos" = 1)
|
||||
high_population_requirement = 15
|
||||
|
||||
/datum/dynamic_ruleset/event/pirates/ready(forced = FALSE)
|
||||
if (!SSmapping.empty_space)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// SPIDERS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/spiders
|
||||
name = "Spider Infestation"
|
||||
config_tag = "spiders"
|
||||
typepath = /datum/round_event/spider_infestation
|
||||
enemy_roles = list("AI","Security Officer","Head of Security","Captain")
|
||||
required_enemies = list(2,2,1,1,0,0,0,0,0,0)
|
||||
weight = 5
|
||||
cost = 10
|
||||
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
||||
high_population_requirement = 15
|
||||
property_weights = list("chaos" = 1, "valid" = 1)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// CLOGGED VENTS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/ventclog
|
||||
name = "Clogged Vents"
|
||||
config_tag = "ventclog"
|
||||
typepath = /datum/round_event/vent_clog
|
||||
enemy_roles = list("Chemist","Medical Doctor","Chief Medical Officer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
cost = 2
|
||||
weight = 4
|
||||
repeatable_weight_decrease = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5) // yes, can happen on fake-extended
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("chaos" = 1, "extended" = 2)
|
||||
|
||||
/datum/dynamic_ruleset/event/ventclog/ready()
|
||||
if(mode.threat_level > 30 && mode.threat >= 5 && prob(20))
|
||||
name = "Clogged Vents: Threatening"
|
||||
cost = 5
|
||||
required_enemies = list(3,3,3,2,2,2,1,1,1,1)
|
||||
typepath = /datum/round_event/vent_clog/threatening
|
||||
else if(mode.threat_level > 15 && mode.threat > 15 && prob(30))
|
||||
name = "Clogged Vents: Catastrophic"
|
||||
cost = 15
|
||||
required_enemies = list(2,2,1,1,1,1,0,0,0,0)
|
||||
typepath = /datum/round_event/vent_clog/catastrophic
|
||||
else
|
||||
cost = 2
|
||||
name = "Clogged Vents: Normal"
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
typepath = /datum/round_event/vent_clog
|
||||
return ..()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// ION STORM //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/ion_storm
|
||||
name = "Ion Storm"
|
||||
config_tag = "ion_storm"
|
||||
typepath = /datum/round_event/ion_storm
|
||||
enemy_roles = list("Research Director","Captain","Chief Engineer")
|
||||
required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
||||
weight = 4
|
||||
// no repeatable weight decrease. too variable to be unfun multiple times in one round
|
||||
cost = 1
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("story_potential" = 1, "extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// METEORS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/meteor_wave
|
||||
name = "Meteor Wave"
|
||||
config_tag = "meteor_wave"
|
||||
typepath = /datum/round_event/meteor_wave
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Captain","Cyborg")
|
||||
required_enemies = list(3,3,3,3,3,3,3,3,3,3)
|
||||
cost = 15
|
||||
weight = 3
|
||||
earliest_start = 25 MINUTES
|
||||
repeatable_weight_decrease = 2
|
||||
requirements = list(60,50,40,30,30,30,30,30,30,30)
|
||||
high_population_requirement = 30
|
||||
property_weights = list("extended" = -2)
|
||||
|
||||
/datum/dynamic_ruleset/event/meteor_wave/ready()
|
||||
if(world.time-SSticker.round_start_time > 35 MINUTES && mode.threat_level > 40 && mode.threat >= 25 && prob(30))
|
||||
name = "Meteor Wave: Threatening"
|
||||
cost = 25
|
||||
typepath = /datum/round_event/meteor_wave/threatening
|
||||
else if(world.time-SSticker.round_start_time > 45 MINUTES && mode.threat_level > 50 && mode.threat >= 40 && prob(30))
|
||||
name = "Meteor Wave: Catastrophic"
|
||||
cost = 40
|
||||
typepath = /datum/round_event/meteor_wave/catastrophic
|
||||
else
|
||||
name = "Meteor Wave: Normal"
|
||||
cost = 15
|
||||
typepath = /datum/round_event/meteor_wave
|
||||
return ..()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// ANOMALIES //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_bluespace
|
||||
name = "Anomaly: Bluespace"
|
||||
config_tag = "anomaly_bluespace"
|
||||
typepath = /datum/round_event/anomaly/anomaly_bluespace
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_flux
|
||||
name = "Anomaly: Hyper-Energetic Flux"
|
||||
config_tag = "anomaly_flux"
|
||||
typepath = /datum/round_event/anomaly/anomaly_flux
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 5
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_gravitational
|
||||
name = "Anomaly: Gravitational"
|
||||
config_tag = "anomaly_gravitational"
|
||||
typepath = /datum/round_event/anomaly/anomaly_grav
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_pyroclastic
|
||||
name = "Anomaly: Pyroclastic"
|
||||
config_tag = "anomaly_pyroclastic"
|
||||
typepath = /datum/round_event/anomaly/anomaly_pyro
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 5
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_vortex
|
||||
name = "Anomaly: Vortex"
|
||||
config_tag = "anomaly_vortex"
|
||||
typepath = /datum/round_event/anomaly/anomaly_vortex
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 5
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// WOW THAT'S A LOT OF EVENTS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/brand_intelligence
|
||||
name = "Brand Intelligence"
|
||||
config_tag = "brand_intelligence"
|
||||
typepath = /datum/round_event/brand_intelligence
|
||||
weight = 1
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 2
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
|
||||
required_enemies = list(1,1,1,1,0,0,0,0,0,0)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = -1, "chaos" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/carp_migration
|
||||
name = "Carp Migration"
|
||||
config_tag = "carp_migration"
|
||||
typepath = /datum/round_event/carp_migration
|
||||
weight = 7
|
||||
repeatable_weight_decrease = 3
|
||||
cost = 4
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
earliest_start = 10 MINUTES
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/communications_blackout
|
||||
name = "Communications Blackout"
|
||||
config_tag = "communications_blackout"
|
||||
typepath = /datum/round_event/communications_blackout
|
||||
cost = 4
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 3
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1, "chaos" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/processor_overload
|
||||
name = "Processor Overload"
|
||||
config_tag = "processor_overload"
|
||||
typepath = /datum/round_event/processor_overload
|
||||
cost = 4
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 3
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1, "chaos" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/space_dust
|
||||
name = "Minor Space Dust"
|
||||
config_tag = "space_dust"
|
||||
typepath = /datum/round_event/space_dust
|
||||
cost = 2
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
earliest_start = 0 MINUTES
|
||||
property_weights = list("extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/major_dust
|
||||
name = "Major Space Dust"
|
||||
config_tag = "major_dust"
|
||||
typepath = /datum/round_event/meteor_wave/major_dust
|
||||
cost = 4
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/electrical_storm
|
||||
name = "Electrical Storm"
|
||||
config_tag = "electrical_storm"
|
||||
typepath = /datum/round_event/electrical_storm
|
||||
cost = 1
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/heart_attack
|
||||
name = "Random Heart Attack"
|
||||
config_tag = "heart_attack"
|
||||
typepath = /datum/round_event/heart_attack
|
||||
cost = 3
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Medical Doctor","Chief Medical Officer")
|
||||
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
|
||||
requirements = list(101,101,101,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/radiation_storm
|
||||
name = "Radiation Storm"
|
||||
config_tag = "radiation_storm"
|
||||
typepath = /datum/round_event/radiation_storm
|
||||
cost = 3
|
||||
weight = 1
|
||||
enemy_roles = list("Chemist","Chief Medical Officer","Geneticist","Medical Doctor","AI","Captain")
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
property_weights = list("extended" = 1,"chaos" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/portal_storm_syndicate
|
||||
name = "Portal Storm"
|
||||
config_tag = "portal_storm"
|
||||
typepath = /datum/round_event/portal_storm/syndicate_shocktroop
|
||||
cost = 10
|
||||
weight = 1
|
||||
enemy_roles = list("Head of Security","Security Officer","AI","Captain","Shaft Miner")
|
||||
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
|
||||
requirements = list(101,101,101,30,30,30,30,30,30,30)
|
||||
high_population_requirement = 30
|
||||
earliest_start = 30 MINUTES
|
||||
property_weights = list("teamwork" = 1,"chaos" = 1, "extended" = -1)
|
||||
|
||||
/datum/dynamic_ruleset/event/wormholes
|
||||
name = "Wormholes"
|
||||
config_tag = "wormhole"
|
||||
typepath = /datum/round_event/wormholes
|
||||
cost = 3
|
||||
weight = 4
|
||||
enemy_roles = list("AI","Medical Doctor","Station Engineer","Head of Personnel","Captain")
|
||||
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/swarmers
|
||||
name = "Swarmers"
|
||||
config_tag = "swarmer"
|
||||
typepath = /datum/round_event/spawn_swarmer
|
||||
cost = 10
|
||||
weight = 1
|
||||
earliest_start = 30 MINUTES
|
||||
enemy_roles = list("AI","Security Officer","Head of Security","Captain","Station Engineer","Atmos Technician","Chief Engineer")
|
||||
required_enemies = list(4,4,4,4,3,3,2,2,1,1)
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 5
|
||||
property_weights = list("extended" = -2)
|
||||
|
||||
/datum/dynamic_ruleset/event/sentient_disease
|
||||
name = "Sentient Disease"
|
||||
config_tag = "sentient_disease"
|
||||
typepath = /datum/round_event/ghost_role/sentient_disease
|
||||
enemy_roles = list("Virologist","Chief Medical Officer","Captain","Chemist")
|
||||
required_enemies = list(2,1,1,1,0,0,0,0,0,0)
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
cost = 5
|
||||
requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"!
|
||||
property_weights = list("story_potential" = 1, "extended" = 1, "valid" = -2)
|
||||
high_population_requirement = 5
|
||||
|
||||
/datum/dynamic_ruleset/event/revenant
|
||||
name = "Revenant"
|
||||
config_tag = "revenant"
|
||||
typepath = /datum/round_event/ghost_role/revenant
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Captain","Chaplain","AI")
|
||||
required_enemies = list(2,1,1,1,0,0,0,0,0,0)
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
cost = 5
|
||||
requirements = list(30,30,30,30,20,15,15,15,15,15)
|
||||
high_population_requirement = 15
|
||||
property_weights = list("story_potential" = -2, "extended" = -1)
|
||||
@@ -200,13 +200,15 @@
|
||||
/datum/dynamic_ruleset/latejoin/heretic_smuggler
|
||||
name = "Heretic Smuggler"
|
||||
antag_datum = /datum/antagonist/heretic
|
||||
antag_flag = ROLE_HERETIC
|
||||
antag_flag = "latejoin_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 = 10
|
||||
requirements = list(40,30,20,10,10,10,10,10,10,10)
|
||||
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)
|
||||
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")
|
||||
enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg","Bartender")
|
||||
required_enemies = list(3,2,2,2,2,1,1,1,1,0)
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
|
||||
@@ -151,16 +151,18 @@
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/heretics
|
||||
name = "Heretics"
|
||||
antag_flag = ROLE_HERETIC
|
||||
antag_flag = "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 = 20
|
||||
cost = 25
|
||||
scaling_cost = 15
|
||||
requirements = list(50,45,45,40,35,20,20,15,10,10)
|
||||
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)
|
||||
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:
|
||||
Property weights are added to the config weight of the ruleset. They 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 its own class for a good reason.
|
||||
"conversion" -- Basically a bool. Conversion antags, well, convert. It's in its own class 'cause people kinda hate conversion.
|
||||
*/
|
||||
|
||||
/datum/dynamic_storyteller/proc/start_injection_cooldowns()
|
||||
@@ -39,9 +39,6 @@ Property weights are:
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
|
||||
mode.midround_injection_cooldown = round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
|
||||
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
mode.event_injection_cooldown = (round(clamp(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
|
||||
|
||||
/datum/dynamic_storyteller/proc/calculate_threat()
|
||||
var/threat = 0
|
||||
for(var/datum/antagonist/A in GLOB.antagonists)
|
||||
@@ -99,10 +96,6 @@ Property weights are:
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
|
||||
return round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max))
|
||||
|
||||
/datum/dynamic_storyteller/proc/get_event_cooldown()
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
return round(clamp(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max))
|
||||
|
||||
/datum/dynamic_storyteller/proc/get_latejoin_cooldown()
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
|
||||
return round(clamp(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max))
|
||||
@@ -126,8 +119,9 @@ Property weights 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]
|
||||
if(property_weight > 0)
|
||||
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult
|
||||
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
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/midround_draft()
|
||||
@@ -144,21 +138,24 @@ Property weights 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]
|
||||
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
|
||||
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
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer)
|
||||
@@ -180,27 +177,17 @@ Property weights are:
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
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
|
||||
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
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/event_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for(var/datum/dynamic_ruleset/event/rule in mode.events)
|
||||
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && (mode.threat_level + 20 - mode.threat) >= rule.cost && rule.ready())
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
if(property_weight > 0)
|
||||
drafted_rules[rule] = rule.get_weight() + property_weight * rule.weight_mult
|
||||
return drafted_rules
|
||||
|
||||
|
||||
/datum/dynamic_storyteller/chaotic
|
||||
name = "Chaotic"
|
||||
config_tag = "chaotic"
|
||||
@@ -263,9 +250,6 @@ Property weights are:
|
||||
/datum/dynamic_storyteller/random/get_midround_cooldown()
|
||||
return rand(GLOB.dynamic_midround_delay_min/2, GLOB.dynamic_midround_delay_max*2)
|
||||
|
||||
/datum/dynamic_storyteller/random/get_event_cooldown()
|
||||
return rand(GLOB.dynamic_event_delay_min/2, GLOB.dynamic_event_delay_max*2)
|
||||
|
||||
/datum/dynamic_storyteller/random/get_latejoin_cooldown()
|
||||
return rand(GLOB.dynamic_latejoin_delay_min/2, GLOB.dynamic_latejoin_delay_max*2)
|
||||
|
||||
@@ -311,13 +295,6 @@ Property weights are:
|
||||
drafted_rules[rule] = 1
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/random/event_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for(var/datum/dynamic_ruleset/event/rule in mode.events)
|
||||
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && rule.ready())
|
||||
drafted_rules[rule] = 1
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/story
|
||||
name = "Story"
|
||||
config_tag = "story"
|
||||
@@ -327,12 +304,6 @@ Property weights 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"
|
||||
@@ -363,7 +334,7 @@ Property weights are:
|
||||
/datum/dynamic_storyteller/no_antag
|
||||
name = "Extended"
|
||||
config_tag = "semiextended"
|
||||
desc = "No standard antags. Threatening events may still spawn."
|
||||
desc = "No standard antags."
|
||||
curve_centre = -5
|
||||
curve_width = 0.5
|
||||
flags = NO_ASSASSIN | FORCE_IF_WON
|
||||
@@ -375,15 +346,3 @@ Property weights are:
|
||||
|
||||
/datum/dynamic_storyteller/no_antag/get_injection_chance(dry_run)
|
||||
return 0
|
||||
|
||||
/datum/dynamic_storyteller/extended
|
||||
name = "Super Extended"
|
||||
config_tag = "extended"
|
||||
desc = "No antags. No dangerous events."
|
||||
curve_centre = -20
|
||||
weight = 0
|
||||
curve_width = 0.5
|
||||
|
||||
/datum/dynamic_storyteller/extended/on_start()
|
||||
..()
|
||||
GLOB.dynamic_forced_extended = TRUE
|
||||
|
||||
@@ -112,7 +112,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
var/turf/T = get_turf(loc)
|
||||
ram_turf(T)
|
||||
|
||||
if(prob(10) && !isspaceturf(T))//randomly takes a 'hit' from ramming
|
||||
if(prob(10) && !isspaceturf(T) && !istype(T, /turf/closed/mineral) && !istype(T, /turf/open/floor/plating/asteroid))//randomly takes a 'hit' from ramming
|
||||
get_hit()
|
||||
|
||||
/obj/effect/meteor/Destroy()
|
||||
@@ -136,7 +136,8 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
if(A)
|
||||
ram_turf(get_turf(A))
|
||||
playsound(src.loc, meteorsound, 40, 1)
|
||||
get_hit()
|
||||
if(!istype(A, /turf/closed/mineral) && !istype(A, /turf/open/floor/plating/asteroid))
|
||||
get_hit()
|
||||
|
||||
/obj/effect/meteor/proc/ram_turf(turf/T)
|
||||
//first bust whatever is in the turf
|
||||
|
||||
@@ -551,4 +551,4 @@ Class Procs:
|
||||
AM.pixel_y = -8 + (round( . / 3)*8)
|
||||
|
||||
/obj/machinery/rust_heretic_act()
|
||||
take_damage(500, BRUTE, "melee", 1)
|
||||
take_damage(500, BRUTE, "melee", 1)
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
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)
|
||||
|
||||
@@ -178,9 +178,12 @@
|
||||
table[y1][x1] += 10
|
||||
if(href_list["same_board"]) //Reset the board... kinda
|
||||
if(game_status != MINESWEEPER_GAME_PLAYING)
|
||||
mine_sound = TRUE
|
||||
game_status = MINESWEEPER_GAME_PLAYING
|
||||
if(table[y1][x1] >= 10) //If revealed, become unrevealed!
|
||||
playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10)
|
||||
if(mine_sound)
|
||||
playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10)
|
||||
mine_sound = FALSE
|
||||
table[y1][x1] -= 10
|
||||
if(table[y1][x1] > 10 && !reset_board)
|
||||
safe_squares_revealed += 1
|
||||
|
||||
@@ -160,7 +160,6 @@
|
||||
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
|
||||
|
||||
|
||||
@@ -353,7 +353,6 @@ 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)
|
||||
|
||||
@@ -276,7 +276,6 @@
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
#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"
|
||||
@@ -6,6 +18,7 @@
|
||||
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
|
||||
@@ -16,22 +29,10 @@
|
||||
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
|
||||
@@ -46,7 +47,7 @@
|
||||
/obj/machinery/computer/communications/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(!usr.canUseTopic(src))
|
||||
if(!usr.canUseTopic(src, !issilicon(usr)))
|
||||
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!")
|
||||
@@ -132,15 +133,20 @@
|
||||
|
||||
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/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.", "")
|
||||
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.", "")
|
||||
if(!input || !(usr in view(1,src)) || !checkCCcooldown())
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
send2otherserver("[station_name()]", input,"Comms_Console")
|
||||
if(dest == "all")
|
||||
send2otherserver("[station_name()]", input,"Comms_Console")
|
||||
else
|
||||
send2otherserver("[station_name()]", input,"Comms_Console", list(dest))
|
||||
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.")
|
||||
@@ -156,12 +162,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, "It's a bit late to buy a new shuttle, don't you think?")
|
||||
to_chat(usr, "<span class='alert'>It's a bit late to buy a new shuttle, don't you think?</span>")
|
||||
return
|
||||
if(SSshuttle.shuttle_purchased)
|
||||
to_chat(usr, "A replacement shuttle has already been purchased.")
|
||||
to_chat(usr, "<span class='alert'>A replacement shuttle has already been purchased.</span>")
|
||||
else if(!S.prerequisites_met())
|
||||
to_chat(usr, "You have not met the requirements for purchasing this shuttle.")
|
||||
to_chat(usr, "<span class='alert'>You have not met the requirements for purchasing this shuttle.</span>")
|
||||
else
|
||||
var/points_to_check
|
||||
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
|
||||
@@ -183,7 +189,7 @@
|
||||
|
||||
if("callshuttle")
|
||||
state = STATE_DEFAULT
|
||||
if(authenticated)
|
||||
if(authenticated && SSshuttle.canEvac(usr))
|
||||
state = STATE_CALLSHUTTLE
|
||||
if("callshuttle2")
|
||||
if(authenticated)
|
||||
@@ -284,12 +290,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, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
CentCom_announce(input, usr)
|
||||
to_chat(usr, "<span class='notice'>Message transmitted to Central Command.</span>")
|
||||
for(var/client/X in GLOB.admins)
|
||||
@@ -302,7 +308,7 @@
|
||||
|
||||
// OMG SYNDICATE ...LETTERHEAD
|
||||
if("MessageSyndicate")
|
||||
if((authenticated==2) && (obj_flags & EMAGGED))
|
||||
if((authenticated) && (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)
|
||||
@@ -332,7 +338,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)
|
||||
@@ -347,7 +353,9 @@
|
||||
aicurrmsg = null
|
||||
aistate = STATE_DEFAULT
|
||||
if("ai-callshuttle")
|
||||
aistate = STATE_CALLSHUTTLE
|
||||
aistate = STATE_DEFAULT
|
||||
if(SSshuttle.canEvac(usr))
|
||||
aistate = STATE_CALLSHUTTLE
|
||||
if("ai-callshuttle2")
|
||||
SSshuttle.requestEvac(usr, href_list["call"])
|
||||
aistate = STATE_DEFAULT
|
||||
@@ -460,9 +468,8 @@
|
||||
|
||||
|
||||
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) || (hasSiliconAccessInArea(user) && !in_range(user,src)))
|
||||
if(issilicon(user))
|
||||
var/dat2 = interact_ai(user) // give the AI a different interact proc to limit its access
|
||||
if(dat2)
|
||||
dat += dat2
|
||||
@@ -493,9 +500,15 @@
|
||||
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/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> \]"
|
||||
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> \]"
|
||||
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> \]"
|
||||
@@ -721,8 +734,13 @@
|
||||
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))
|
||||
if(!input || !user.canUseTopic(src, !issilicon(usr)))
|
||||
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)
|
||||
|
||||
@@ -771,3 +789,15 @@
|
||||
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
|
||||
|
||||
@@ -217,9 +217,6 @@
|
||||
// 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.
|
||||
@@ -266,6 +263,10 @@
|
||||
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()
|
||||
@@ -357,7 +358,7 @@
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/ui_act(action, var/list/params)
|
||||
/obj/machinery/computer/scan_consolenew/ui_act(action, list/params)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
@@ -482,6 +483,7 @@
|
||||
// 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
|
||||
|
||||
@@ -178,7 +178,6 @@
|
||||
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)
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
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,7 +66,6 @@
|
||||
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
|
||||
|
||||
|
||||
@@ -250,7 +250,6 @@
|
||||
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,7 +103,6 @@ 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)
|
||||
@@ -185,7 +184,6 @@ 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)
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
|
||||
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)
|
||||
@@ -308,7 +307,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
|
||||
|
||||
@@ -74,12 +74,6 @@
|
||||
/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()
|
||||
@@ -90,14 +84,6 @@
|
||||
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,7 +260,6 @@
|
||||
|
||||
/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,7 +29,6 @@
|
||||
. = ..()
|
||||
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()
|
||||
|
||||
|
||||
@@ -38,3 +38,14 @@
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
drive()
|
||||
|
||||
/obj/machinery/mass_driver/pressure_plate
|
||||
name = "pressure plated mass driver"
|
||||
var/drive_delay = 10
|
||||
|
||||
/obj/machinery/mass_driver/pressure_plate/Crossed(atom/movable/O)
|
||||
. = ..()
|
||||
if(isliving(O))
|
||||
var/mob/living/L = O
|
||||
to_chat(L, "<span class='warning'>You feel something click beneath you!</span>")
|
||||
addtimer(CALLBACK(src, .proc/drive), drive_delay)
|
||||
@@ -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,7 +271,6 @@ 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)
|
||||
@@ -279,7 +278,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)
|
||||
@@ -358,7 +357,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
|
||||
@@ -539,7 +538,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
|
||||
|
||||
@@ -132,7 +132,6 @@
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
/obj/mecha/proc/get_armour_facing(relative_dir)
|
||||
switch(relative_dir)
|
||||
if(0) // BACKSTAB!
|
||||
if(180) // BACKSTAB!
|
||||
return facing_modifiers[BACK_ARMOUR]
|
||||
if(45, 90, 270, 315)
|
||||
return facing_modifiers[SIDE_ARMOUR]
|
||||
if(225, 180, 135)
|
||||
if(0, 45) // direct or 45 degrees off
|
||||
return facing_modifiers[FRONT_ARMOUR]
|
||||
return 1 //always return non-0
|
||||
return facing_modifiers[SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side
|
||||
|
||||
/obj/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
. = ..()
|
||||
@@ -43,7 +41,7 @@
|
||||
break
|
||||
|
||||
if(attack_dir)
|
||||
var/facing_modifier = get_armour_facing(dir2angle(attack_dir) - dir2angle(src))
|
||||
var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir)))
|
||||
booster_damage_modifier /= facing_modifier
|
||||
booster_deflection_modifier *= facing_modifier
|
||||
if(prob(deflect_chance * booster_deflection_modifier))
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
var/countdown_colour
|
||||
var/obj/effect/countdown/anomaly/countdown
|
||||
|
||||
/obj/effect/anomaly/Initialize(mapload, new_lifespan)
|
||||
/// chance we drop a core when neutralized
|
||||
var/core_drop_chance = 100
|
||||
|
||||
/obj/effect/anomaly/Initialize(mapload, new_lifespan, core_drop_chance = 100)
|
||||
. = ..()
|
||||
GLOB.poi_list |= src
|
||||
START_PROCESSING(SSobj, src)
|
||||
impact_area = get_area(src)
|
||||
src.core_drop_chance = core_drop_chance
|
||||
|
||||
if (!impact_area)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
@@ -54,6 +58,8 @@
|
||||
GLOB.poi_list.Remove(src)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
qdel(countdown)
|
||||
if(aSignal)
|
||||
QDEL_NULL(aSignal)
|
||||
return ..()
|
||||
|
||||
/obj/effect/anomaly/proc/anomalyEffect()
|
||||
@@ -70,12 +76,12 @@
|
||||
/obj/effect/anomaly/proc/anomalyNeutralize()
|
||||
new /obj/effect/particle_effect/smoke/bad(loc)
|
||||
|
||||
for(var/atom/movable/O in src)
|
||||
O.forceMove(drop_location())
|
||||
if(prob(core_drop_chance))
|
||||
aSignal.forceMove(drop_location())
|
||||
aSignal = null
|
||||
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/effect/anomaly/attackby(obj/item/I, mob/user, params)
|
||||
if(I.tool_behaviour == TOOL_ANALYZER) //revert if runtimed
|
||||
to_chat(user, "<span class='notice'>Analyzing... [src]'s unstable field is fluctuating along frequency [format_frequency(aSignal.frequency)], code [aSignal.code].</span>")
|
||||
@@ -285,7 +291,7 @@
|
||||
S.rabid = TRUE
|
||||
S.amount_grown = SLIME_EVOLUTION_THRESHOLD
|
||||
S.Evolve()
|
||||
offer_control(S)
|
||||
offer_control(S,POLL_IGNORE_SENTIENCE_POTION)
|
||||
|
||||
/////////////////////
|
||||
|
||||
|
||||
@@ -46,4 +46,5 @@
|
||||
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, turn(dir, -dir2angle(T.dir)), CLEAN_GOD, color, null, null, alpha)
|
||||
var/turn_dir = 180 - dir2angle(T.dir) //Turning a dir by 0 results in a roulette of random dirs.
|
||||
T.AddElement(/datum/element/decal, icon, icon_state, turn_dir ? turn(dir, turn_dir) : dir, CLEAN_GOD, color, null, null, alpha)
|
||||
|
||||
@@ -242,7 +242,6 @@ 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)
|
||||
|
||||
@@ -28,39 +28,37 @@
|
||||
/// 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_MOVED, .proc/sweep)
|
||||
RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, .proc/sweep)
|
||||
|
||||
/// triggered on unwield of two handed item
|
||||
/obj/item/broom/proc/on_unwield(obj/item/source, mob/user)
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_PRE_MOVE)
|
||||
|
||||
/obj/item/broom/afterattack(atom/A, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
sweep(user, A, FALSE)
|
||||
sweep(user, A)
|
||||
|
||||
/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))
|
||||
/obj/item/broom/proc/sweep(datum/source, atom/newLoc)
|
||||
if(!ismob(source) || !isturf(newLoc) || (get_dist(source, newLoc) > 1))
|
||||
return
|
||||
if (locate(/obj/structure/table) in target.contents)
|
||||
var/turf/target = newLoc
|
||||
var/atom/movable/AM
|
||||
var/sweep_dir = get_dir(source, target)
|
||||
if(!sweep_dir)
|
||||
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)
|
||||
garbage.Move(get_step(target, user.dir), user.dir)
|
||||
i++
|
||||
if(i >= 20)
|
||||
step(garbage, sweep_dir)
|
||||
if(++i > 20)
|
||||
break
|
||||
if(i >= 1)
|
||||
if(i)
|
||||
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
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
var/ignores_timeout = FALSE
|
||||
var/response_timer_id = null
|
||||
var/approval_time = 600
|
||||
var/allow_unicode = FALSE
|
||||
|
||||
var/static/regex/standard_station_regex
|
||||
|
||||
@@ -48,6 +49,9 @@
|
||||
|
||||
if(!new_name)
|
||||
return
|
||||
if(!allow_unicode && (length(new_name) != length_char(new_name)))
|
||||
to_chat(user, "Unicode is not allowed. Adminhelp if you want to use it so badly.")
|
||||
return
|
||||
log_game("[key_name(user)] has proposed to name the station as \
|
||||
[new_name]")
|
||||
|
||||
|
||||
@@ -390,7 +390,7 @@
|
||||
|
||||
/obj/item/circuitboard/machine/thermomachine/examine()
|
||||
. = ..()
|
||||
. += "<span class='notice'>It is set to layer [pipe_layer].</span>"
|
||||
. += "<span class='notice'>It is set to layer [pipe_layer]. Use a Multitool on the circuit to change this.</span>"
|
||||
|
||||
/obj/item/circuitboard/machine/thermomachine/heater
|
||||
name = "Heater (Machine Board)"
|
||||
@@ -1146,3 +1146,8 @@
|
||||
build_path = /obj/machinery/atmospherics/components/unary/shuttle/heater
|
||||
req_components = list(/obj/item/stock_parts/micro_laser = 2,
|
||||
/obj/item/stock_parts/matter_bin = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/explosive_compressor
|
||||
name = "Explosive Compressor (Machine Board)"
|
||||
build_path = /obj/machinery/research/explosive_compressor
|
||||
req_components = list(/obj/item/stock_parts/matter_bin = 3)
|
||||
|
||||
@@ -735,7 +735,11 @@
|
||||
if(isobj(target))
|
||||
if(actually_paints)
|
||||
var/list/hsl = rgb2hsl(hex2num(copytext(paint_color,2,4)),hex2num(copytext(paint_color,4,6)),hex2num(copytext(paint_color,6,8)))
|
||||
if(hsl[3] < 0.25 && !istype(target, /obj/structure/window) && !istype(target, /obj/effect/decal/cleanable/crayon)) //Colors too dark are rejected
|
||||
var/static/whitelisted = typecacheof(list(/obj/structure/window,
|
||||
/obj/effect/decal/cleanable/crayon,
|
||||
/obj/machinery/door/window)
|
||||
)
|
||||
if(hsl[3] < 0.25 && !whitelisted[target]) //Colors too dark are rejected
|
||||
to_chat(usr, "<span class='warning'>A color that dark on an object like this? Surely not...</span>")
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -394,8 +394,6 @@
|
||||
to_chat(user, "<span class='warning'>[src] are recharging!</span>")
|
||||
return
|
||||
|
||||
user.stop_pulling() //User has hands full, and we don't care about anyone else pulling on it, their problem. CLEAR!!
|
||||
|
||||
if(user.a_intent == INTENT_DISARM)
|
||||
do_disarm(M, user)
|
||||
return
|
||||
@@ -447,8 +445,7 @@
|
||||
if(do_after(user, isnull(defib?.disarm_shock_time)? disarm_shock_time : defib.disarm_shock_time, target = M))
|
||||
M.visible_message("<span class='danger'>[user] zaps [M] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] zaps [M] with [src]!</span>")
|
||||
M.adjustStaminaLoss(50)
|
||||
M.DefaultCombatKnockdown(100)
|
||||
M.DefaultCombatKnockdown(140)
|
||||
M.updatehealth() //forces health update before next life tick
|
||||
playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
M.emote("gasp")
|
||||
|
||||
@@ -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/goonchat)
|
||||
var/datum/asset/spritesheet/emoji_s = get_asset_datum(/datum/asset/spritesheet/chat)
|
||||
emoji_s.send(user) //Already sent by chat but no harm doing this
|
||||
|
||||
user.set_machine(src)
|
||||
|
||||
@@ -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/goonchat)
|
||||
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
|
||||
var/list/collate = list("<br><table>")
|
||||
for(var/emoji in sortList(icon_states(icon('icons/emoji.dmi'))))
|
||||
var/tag = sheet.icon_tag("emoji-[emoji]")
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/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,9 +16,6 @@
|
||||
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)
|
||||
@@ -201,17 +198,7 @@
|
||||
else
|
||||
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
|
||||
/obj/item/electropack/ui_act(action, params)
|
||||
if(action == "power") // DO. NOT.
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -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/fusion_power = round(cached_scan_results["fusion"], 0.01)
|
||||
var/tier = fusionpower2text(fusion_power)
|
||||
var/instability = round(cached_scan_results["fusion"], 0.01)
|
||||
var/tier = instability2text(instability)
|
||||
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'>Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.</span>")
|
||||
to_chat(user, "<span class='notice'>Instability of the last fusion reaction: [instability]\n This indicates it was [tier].</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)] °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/fusion_power = round(cached_scan_results["fusion"], 0.01)
|
||||
var/tier = fusionpower2text(fusion_power)
|
||||
var/instability = round(cached_scan_results["fusion"], 0.01)
|
||||
var/tier = instability2text(instability)
|
||||
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'>Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.</span>")
|
||||
to_chat(user, "<span class='notice'>Instability of the last fusion reaction: [instability]\n This indicates it was [tier].</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
|
||||
|
||||
@@ -289,3 +289,9 @@
|
||||
. = TRUE
|
||||
|
||||
update_icon()
|
||||
|
||||
/**
|
||||
* Returns if this is ready to be detonated. Checks if both tanks are in place.
|
||||
*/
|
||||
/obj/item/transfer_valve/proc/ready()
|
||||
return tank_one && tank_two
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
wound_bonus = -110
|
||||
bare_wound_bonus = 20
|
||||
block_parry_data = /datum/block_parry_data/dual_esword
|
||||
block_chance = 60
|
||||
var/hacked = FALSE
|
||||
/// Can this reflect all energy projectiles?
|
||||
var/can_reflect = TRUE
|
||||
@@ -38,7 +39,8 @@
|
||||
var/wielded = FALSE // track wielded status on item
|
||||
var/slowdown_wielded = 0
|
||||
|
||||
/datum/block_parry_data/dual_esword
|
||||
/datum/block_parry_data/dual_esword // please run at the man going apeshit with his funny doublesword
|
||||
can_block_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST | BLOCK_DIR_WEST | BLOCK_DIR_EAST
|
||||
block_damage_absorption = 2
|
||||
block_damage_multiplier = 0.15
|
||||
block_damage_multiplier_override = list(
|
||||
@@ -50,10 +52,10 @@
|
||||
block_lock_sprinting = TRUE
|
||||
// no attacking while blocking
|
||||
block_lock_attacking = TRUE
|
||||
block_projectile_mitigation = 75
|
||||
block_projectile_mitigation = 85
|
||||
// more efficient vs projectiles
|
||||
block_stamina_efficiency_override = list(
|
||||
TEXT_ATTACK_TYPE_PROJECTILE = 4
|
||||
TEXT_ATTACK_TYPE_PROJECTILE = 6
|
||||
)
|
||||
|
||||
parry_time_windup = 0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user