mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-20 18:47:20 +01:00
Merge branch 'master' into tgglassfloors
This commit is contained in:
@@ -28,26 +28,26 @@
|
||||
admin = 1
|
||||
|
||||
//Guest Checking
|
||||
if(!GLOB.guests_allowed && IsGuestKey(key))
|
||||
if(GLOB.configuration.general.guest_ban && IsGuestKey(key))
|
||||
log_adminwarn("Failed Login: [key] [computer_id] [address] - Guests not allowed")
|
||||
// message_admins("<span class='notice'>Failed Login: [key] - Guests not allowed</span>")
|
||||
INVOKE_ASYNC(GLOBAL_PROC, .proc/log_connection, ckey(key), address, computer_id, CONNECTION_TYPE_DROPPED_BANNED)
|
||||
return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a BYOND account.")
|
||||
|
||||
//check if the IP address is a known proxy/vpn, and the user is not whitelisted
|
||||
if(check_ipintel && config.ipintel_email && config.ipintel_whitelist && ipintel_is_banned(key, address))
|
||||
if(check_ipintel && GLOB.configuration.ipintel.contact_email && GLOB.configuration.ipintel.whitelist_mode && SSipintel.ipintel_is_banned(key, address))
|
||||
log_adminwarn("Failed Login: [key] [computer_id] [address] - Proxy/VPN")
|
||||
var/mistakemessage = ""
|
||||
if(config.banappeals)
|
||||
mistakemessage = "\nIf you have to use one, request whitelisting at: [config.banappeals]"
|
||||
if(GLOB.configuration.url.banappeals_url)
|
||||
mistakemessage = "\nIf you have to use one, request whitelisting at: [GLOB.configuration.url.banappeals_url]"
|
||||
INVOKE_ASYNC(GLOBAL_PROC, .proc/log_connection, ckey(key), address, computer_id, CONNECTION_TYPE_DROPPED_IPINTEL)
|
||||
return list("reason"="using proxy or vpn", "desc"="\nReason: Proxies/VPNs are not allowed here. [mistakemessage]")
|
||||
|
||||
|
||||
// If 2FA is enabled, makes sure they were authed within the last minute
|
||||
if(check_2fa && config._2fa_auth_host)
|
||||
if(check_2fa && GLOB.configuration.system._2fa_auth_host)
|
||||
// First see if they exist at all
|
||||
var/datum/db_query/check_query = SSdbcore.NewQuery("SELECT 2fa_status, ip FROM [format_table_name("player")] WHERE ckey=:ckey", list("ckey" = ckey(key)))
|
||||
var/datum/db_query/check_query = SSdbcore.NewQuery("SELECT 2fa_status, ip FROM player WHERE ckey=:ckey", list("ckey" = ckey(key)))
|
||||
|
||||
if(!check_query.warn_execute())
|
||||
message_admins("Failed to do a DB 2FA check for [key]. You have been warned.")
|
||||
@@ -71,7 +71,7 @@
|
||||
// Have it set to always check, or their IP is different
|
||||
if(_2fa_enabled && (always_check || (address != last_ip)))
|
||||
// They have 2FA enabled, lets make sure they have authed within the last minute
|
||||
var/datum/db_query/verify_query = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("2fa_secrets")] WHERE (last_time BETWEEN NOW() - INTERVAL 1 MINUTE AND NOW()) AND ckey=:ckey LIMIT 1", list(
|
||||
var/datum/db_query/verify_query = SSdbcore.NewQuery("SELECT ckey FROM 2fa_secrets WHERE (last_time BETWEEN NOW() - INTERVAL 1 MINUTE AND NOW()) AND ckey=:ckey LIMIT 1", list(
|
||||
"ckey" = ckey(key)
|
||||
))
|
||||
|
||||
@@ -87,7 +87,24 @@
|
||||
|
||||
qdel(verify_query)
|
||||
|
||||
if(config.ban_legacy_system)
|
||||
if(SSdbcore.IsConnected())
|
||||
// If we have a DB, see if the player has been seen before
|
||||
var/datum/db_query/exist_query = SSdbcore.NewQuery("SELECT ckey FROM player WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
// If we didnt execute, skip this part
|
||||
if(!exist_query.warn_execute())
|
||||
qdel(exist_query)
|
||||
else
|
||||
if(!exist_query.NextRow()) // If there isnt a row, they aint been seen before
|
||||
if(GLOB.panic_bunker_enabled)
|
||||
qdel(exist_query)
|
||||
var/threshold = GLOB.configuration.general.panic_bunker_threshold
|
||||
return list("reason" = "panic bunker", "desc" = "Server is not accepting connections from never-before-seen players until player count is less than [threshold]. Please try again later.")
|
||||
|
||||
qdel(exist_query)
|
||||
|
||||
if(!GLOB.configuration.general.use_database_bans)
|
||||
//Ban Checking
|
||||
. = CheckBan(ckey(key), computer_id, address)
|
||||
if(.)
|
||||
@@ -120,7 +137,7 @@
|
||||
sql_query_params["cid"] = computer_id
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"
|
||||
SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype, ban_round_id FROM [format_table_name("ban")]
|
||||
SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype, ban_round_id FROM ban
|
||||
WHERE (ckey=:ckeytext [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR bantype = 'ADMIN_PERMABAN'
|
||||
OR ((bantype = 'TEMPBAN' OR bantype = 'ADMIN_TEMPBAN') AND expiration_time > Now())) AND isnull(unbanned)"}, sql_query_params)
|
||||
|
||||
@@ -159,8 +176,8 @@
|
||||
expires = " The ban is for [duration] minutes and expires on [expiration] (server time)."
|
||||
else
|
||||
var/appealmessage = ""
|
||||
if(config.banappeals)
|
||||
appealmessage = " You may appeal it at <a href='[config.banappeals]'>[config.banappeals]</a>."
|
||||
if(GLOB.configuration.url.banappeals_url)
|
||||
appealmessage = " You may appeal it at <a href='[GLOB.configuration.url.banappeals_url]'>[GLOB.configuration.url.banappeals_url]</a>."
|
||||
expires = " This ban does not expire automatically and must be appealed.[appealmessage]"
|
||||
|
||||
var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime][ban_round_id ? " (Round [ban_round_id])" : ""].[expires]"
|
||||
|
||||
@@ -10,8 +10,8 @@ GLOBAL_PROTECT(banlist_savefile) // Obvious reasons
|
||||
|
||||
. = list()
|
||||
var/appeal
|
||||
if(config && config.banappeals)
|
||||
appeal = "\nFor more information on your ban, or to appeal, head to <a href='[config.banappeals]'>[config.banappeals]</a>"
|
||||
if(GLOB.configuration.url.banappeals_url)
|
||||
appeal = "\nFor more information on your ban, or to appeal, head to <a href='[GLOB.configuration.url.banappeals_url]'>[GLOB.configuration.url.banappeals_url]</a>"
|
||||
GLOB.banlist_savefile.cd = "/base"
|
||||
if( "[ckey][id]" in GLOB.banlist_savefile.dir )
|
||||
GLOB.banlist_savefile.cd = "[ckey][id]"
|
||||
|
||||
+29
-23
@@ -91,8 +91,8 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
else
|
||||
body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\] "
|
||||
body += "\[<A href='?_src_=holder;getplaytimewindow=[M.UID()]'>" + M.client.get_exp_type(EXP_TYPE_CREW) + " as [EXP_TYPE_CREW]</a>\]"
|
||||
body += "<br>BYOND account registration date: [M.client.byondacc_date || "ERROR"] [M.client.byondacc_age <= config.byond_account_age_threshold ? "<b>" : ""]([M.client.byondacc_age] days old)[M.client.byondacc_age <= config.byond_account_age_threshold ? "</b>" : ""]"
|
||||
body += "<br>Global Ban DB Lookup: [config.centcom_ban_db_url ? "<a href='?_src_=holder;open_ccbdb=[M.client.ckey]'>Lookup</a>" : "<i>Disabled</i>"]"
|
||||
body += "<br>BYOND account registration date: [M.client.byondacc_date || "ERROR"] [M.client.byondacc_age <= GLOB.configuration.general.byond_account_age_threshold ? "<b>" : ""]([M.client.byondacc_age] days old)[M.client.byondacc_age <= GLOB.configuration.general.byond_account_age_threshold ? "</b>" : ""]"
|
||||
body += "<br>Global Ban DB Lookup: [GLOB.configuration.url.centcom_ban_db_url ? "<a href='?_src_=holder;open_ccbdb=[M.client.ckey]'>Lookup</a>" : "<i>Disabled</i>"]"
|
||||
|
||||
body += "<br>"
|
||||
|
||||
@@ -127,7 +127,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
body += "<A href='?_src_=holder;appearanceban=[M.UID()];dbbanaddckey=[M.ckey]'>Appearance Ban</A> | "
|
||||
body += "<A href='?_src_=holder;shownoteckey=[M.ckey]'>Notes</A> | "
|
||||
body += "<A href='?_src_=holder;viewkarma=[M.ckey]'>View Karma</A> | "
|
||||
if(config.forum_playerinfo_url)
|
||||
if(GLOB.configuration.url.forum_playerinfo_url)
|
||||
body += "<A href='?_src_=holder;webtools=[M.ckey]'>WebInfo</A> | "
|
||||
if(M.client)
|
||||
if(check_watchlist(M.client.ckey))
|
||||
@@ -315,7 +315,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
return
|
||||
var/key = stripped_input(usr, "Enter ckey to add/remove, or leave blank to cancel:", "VPN Whitelist add/remove", max_length=32)
|
||||
if(key)
|
||||
vpn_whitelist_panel(key)
|
||||
SSipintel.vpn_whitelist_panel(key)
|
||||
|
||||
/datum/admins/proc/Jobbans()
|
||||
if(!check_rights(R_BAN))
|
||||
@@ -462,8 +462,8 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
config.looc_allowed = !(config.looc_allowed)
|
||||
if(config.looc_allowed)
|
||||
GLOB.looc_enabled = !(GLOB.looc_enabled)
|
||||
if(GLOB.looc_enabled)
|
||||
to_chat(world, "<B>The LOOC channel has been globally enabled!</B>")
|
||||
else
|
||||
to_chat(world, "<B>The LOOC channel has been globally disabled!</B>")
|
||||
@@ -478,8 +478,8 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
config.dsay_allowed = !(config.dsay_allowed)
|
||||
if(config.dsay_allowed)
|
||||
GLOB.dsay_enabled = !(GLOB.dsay_enabled)
|
||||
if(GLOB.dsay_enabled)
|
||||
to_chat(world, "<B>Deadchat has been globally enabled!</B>")
|
||||
else
|
||||
to_chat(world, "<B>Deadchat has been globally disabled!</B>")
|
||||
@@ -495,7 +495,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
config.dooc_allowed = !( config.dooc_allowed )
|
||||
GLOB.dooc_enabled = !(GLOB.dooc_enabled)
|
||||
log_admin("[key_name(usr)] toggled Dead OOC.")
|
||||
message_admins("[key_name_admin(usr)] toggled Dead OOC.", 1)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Dead OOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
@@ -508,7 +508,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
config.disable_ooc_emoji = !(config.disable_ooc_emoji)
|
||||
GLOB.configuration.general.enable_ooc_emoji = !(GLOB.configuration.general.enable_ooc_emoji)
|
||||
log_admin("[key_name(usr)] toggled OOC Emoji.")
|
||||
message_admins("[key_name_admin(usr)] toggled OOC Emoji.", 1)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle OOC Emoji")
|
||||
@@ -525,7 +525,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
alert("Unable to start the game as it is not set up.")
|
||||
return
|
||||
|
||||
if(config.start_now_confirmation)
|
||||
if(GLOB.configuration.general.start_now_confirmation)
|
||||
if(alert(usr, "This is a live server. Are you sure you want to start now?", "Start game", "Yes", "No") != "Yes")
|
||||
return
|
||||
|
||||
@@ -568,8 +568,9 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
config.allow_ai = !( config.allow_ai )
|
||||
if(!( config.allow_ai ))
|
||||
|
||||
GLOB.configuration.jobs.allow_ai = !(GLOB.configuration.jobs.allow_ai)
|
||||
if(!GLOB.configuration.jobs.allow_ai)
|
||||
to_chat(world, "<B>The AI job is no longer chooseable.</B>")
|
||||
else
|
||||
to_chat(world, "<B>The AI job is chooseable now.</B>")
|
||||
@@ -586,13 +587,13 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
if(!check_rights(R_SERVER))
|
||||
return
|
||||
|
||||
GLOB.abandon_allowed = !( GLOB.abandon_allowed )
|
||||
if(GLOB.abandon_allowed)
|
||||
GLOB.configuration.general.respawn_enabled = !(GLOB.configuration.general.respawn_enabled)
|
||||
if(GLOB.configuration.general.respawn_enabled)
|
||||
to_chat(world, "<B>You may now respawn.</B>")
|
||||
else
|
||||
to_chat(world, "<B>You may no longer respawn :(</B>")
|
||||
message_admins("[key_name_admin(usr)] toggled respawn to [GLOB.abandon_allowed ? "On" : "Off"].", 1)
|
||||
log_admin("[key_name(usr)] toggled respawn to [GLOB.abandon_allowed ? "On" : "Off"].")
|
||||
to_chat(world, "<B>You may no longer respawn</B>")
|
||||
message_admins("[key_name_admin(usr)] toggled respawn to [GLOB.configuration.general.respawn_enabled ? "On" : "Off"].", 1)
|
||||
log_admin("[key_name(usr)] toggled respawn to [GLOB.configuration.general.respawn_enabled ? "On" : "Off"].")
|
||||
world.update_status()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Respawn") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -724,13 +725,13 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
if(!check_rights(R_SERVER))
|
||||
return
|
||||
|
||||
GLOB.guests_allowed = !( GLOB.guests_allowed )
|
||||
if(!( GLOB.guests_allowed ))
|
||||
GLOB.configuration.general.guest_ban = !(GLOB.configuration.general.guest_ban)
|
||||
if(GLOB.configuration.general.guest_ban)
|
||||
to_chat(world, "<B>Guests may no longer enter the game.</B>")
|
||||
else
|
||||
to_chat(world, "<B>Guests may now enter the game.</B>")
|
||||
log_admin("[key_name(usr)] toggled guests game entering [GLOB.guests_allowed ? "" : "dis"]allowed.")
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] toggled guests game entering [GLOB.guests_allowed ? "" : "dis"]allowed.</span>", 1)
|
||||
log_admin("[key_name(usr)] toggled guests game entering [GLOB.configuration?.general.guest_ban ? "dis" : ""]allowed.")
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] toggled guests game entering [GLOB.configuration?.general.guest_ban ? "dis" : ""]allowed.</span>", 1)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Guests") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/output_ai_laws()
|
||||
@@ -787,9 +788,15 @@ GLOBAL_VAR_INIT(gamma_ship_location, 1) // 0 = station , 1 = space
|
||||
if(GLOB.gamma_ship_location == 1)
|
||||
fromArea = locate(/area/shuttle/gamma/space)
|
||||
toArea = locate(/area/shuttle/gamma/station)
|
||||
for(var/obj/machinery/door/airlock/hatch/gamma/H in GLOB.airlocks)
|
||||
H.unlock(TRUE)
|
||||
GLOB.event_announcement.Announce("Central Command has deployed the Gamma Armory shuttle.", new_sound = 'sound/AI/commandreport.ogg')
|
||||
else
|
||||
fromArea = locate(/area/shuttle/gamma/station)
|
||||
toArea = locate(/area/shuttle/gamma/space)
|
||||
for(var/obj/machinery/door/airlock/hatch/gamma/H in GLOB.airlocks)
|
||||
H.lock(TRUE)
|
||||
GLOB.event_announcement.Announce("Central Command has recalled the Gamma Armory shuttle.", new_sound = 'sound/AI/commandreport.ogg')
|
||||
fromArea.move_contents_to(toArea)
|
||||
|
||||
for(var/obj/machinery/mech_bay_recharge_port/P in toArea)
|
||||
@@ -917,4 +924,3 @@ GLOBAL_VAR_INIT(gamma_ship_location, 1) // 0 = station , 1 = space
|
||||
continue
|
||||
result[1]++
|
||||
return result
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
watchlist_show()
|
||||
|
||||
if("hrefs") //persistant logs and stuff
|
||||
if(config && config.log_hrefs)
|
||||
if(GLOB.configuration.logging.href_logging)
|
||||
if(GLOB.world_href_log)
|
||||
src << browse(file(GLOB.world_href_log), "window=investigate[subject];size=800x300")
|
||||
else
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
switch(task)
|
||||
if("Write")
|
||||
var/datum/db_query/query_memocheck = SSdbcore.NewQuery(
|
||||
"SELECT ckey FROM [format_table_name("memo")] WHERE ckey=:ckey",
|
||||
"SELECT ckey FROM memo WHERE ckey=:ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
return
|
||||
|
||||
var/datum/db_query/query_memoadd = SSdbcore.NewQuery(
|
||||
"INSERT INTO [format_table_name("memo")] (ckey, memotext, timestamp) VALUES (:ckey, :memotext, NOW())",
|
||||
"INSERT INTO memo (ckey, memotext, timestamp) VALUES (:ckey, :memotext, NOW())",
|
||||
list(
|
||||
"ckey" = ckey,
|
||||
"memotext" = memotext
|
||||
@@ -57,7 +57,7 @@
|
||||
qdel(query_memoadd)
|
||||
|
||||
if("Edit")
|
||||
var/datum/db_query/query_memolist = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("memo")]")
|
||||
var/datum/db_query/query_memolist = SSdbcore.NewQuery("SELECT ckey FROM memo")
|
||||
|
||||
if(!query_memolist.warn_execute())
|
||||
qdel(query_memolist)
|
||||
@@ -78,7 +78,7 @@
|
||||
return
|
||||
|
||||
var/datum/db_query/query_memofind = SSdbcore.NewQuery(
|
||||
"SELECT memotext FROM [format_table_name("memo")] WHERE ckey=:ckey",
|
||||
"SELECT memotext FROM memo WHERE ckey=:ckey",
|
||||
list("ckey" = target_ckey)
|
||||
)
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
var/edit_text = "Edited by [target_ckey] on [SQLtime()] from<br>[old_memo]<br>to<br>[new_memo]<hr>"
|
||||
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("memo")] SET memotext=:newmemo, last_editor=:lasteditor, edits=CONCAT(IFNULL(edits,''),:edittext) WHERE ckey=:targetckey",
|
||||
"UPDATE memo SET memotext=:newmemo, last_editor=:lasteditor, edits=CONCAT(IFNULL(edits,''),:edittext) WHERE ckey=:targetckey",
|
||||
list(
|
||||
"newmemo" = new_memo,
|
||||
"lasteditor" = ckey,
|
||||
@@ -120,7 +120,7 @@
|
||||
qdel(query_memofind)
|
||||
|
||||
if("Show")
|
||||
var/datum/db_query/query_memoshow = SSdbcore.NewQuery("SELECT ckey, memotext, timestamp, last_editor FROM [format_table_name("memo")]")
|
||||
var/datum/db_query/query_memoshow = SSdbcore.NewQuery("SELECT ckey, memotext, timestamp, last_editor FROM memo")
|
||||
if(!query_memoshow.warn_execute())
|
||||
qdel(query_memoshow)
|
||||
return
|
||||
@@ -141,7 +141,7 @@
|
||||
qdel(query_memoshow)
|
||||
|
||||
if("Remove")
|
||||
var/datum/db_query/query_memodellist = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("memo")]")
|
||||
var/datum/db_query/query_memodellist = SSdbcore.NewQuery("SELECT ckey FROM memo")
|
||||
if(!query_memodellist.warn_execute())
|
||||
qdel(query_memodellist)
|
||||
return
|
||||
@@ -161,7 +161,7 @@
|
||||
return
|
||||
|
||||
var/datum/db_query/query_memodel = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("memo")] WHERE ckey=:ckey",
|
||||
"DELETE FROM memo WHERE ckey=:ckey",
|
||||
list("ckey" = target_ckey)
|
||||
)
|
||||
|
||||
|
||||
@@ -7,25 +7,15 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
|
||||
|
||||
var/previous_rights = 0
|
||||
|
||||
//load text from file
|
||||
var/list/Lines = file2list("config/admin_ranks.txt")
|
||||
|
||||
//process each line seperately
|
||||
for(var/line in Lines)
|
||||
if(!length(line)) continue
|
||||
if(copytext(line,1,2) == "#") continue
|
||||
|
||||
var/list/List = splittext(line,"+")
|
||||
if(!List.len) continue
|
||||
|
||||
var/rank = ckeyEx(List[1])
|
||||
switch(rank)
|
||||
if(null,"") continue
|
||||
if("Removed") continue //Reserved
|
||||
// Process each rank set seperately
|
||||
// key: rank name | value: list of rights
|
||||
for(var/rankname in GLOB.configuration.admin.rank_rights_map)
|
||||
var/list/rank_right_tokens = GLOB.configuration.admin.rank_rights_map[rankname]
|
||||
|
||||
var/rights = 0
|
||||
for(var/i=2, i<=List.len, i++)
|
||||
switch(ckey(List[i]))
|
||||
for(var/right_token in rank_right_tokens)
|
||||
var/token = lowertext(splittext(right_token, "+")[2])
|
||||
switch(token)
|
||||
if("@","prev") rights |= previous_rights
|
||||
if("buildmode","build") rights |= R_BUILDMODE
|
||||
if("admin") rights |= R_ADMIN
|
||||
@@ -46,7 +36,7 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
|
||||
if("proccall") rights |= R_PROCCALL
|
||||
if("viewruntimes") rights |= R_VIEWRUNTIMES
|
||||
|
||||
GLOB.admin_ranks[rank] = rights
|
||||
GLOB.admin_ranks[rankname] = rights
|
||||
previous_rights = rights
|
||||
|
||||
#ifdef TESTING
|
||||
@@ -73,29 +63,13 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
|
||||
if(config.admin_legacy_system)
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
load_admin_ranks()
|
||||
|
||||
//load text from file
|
||||
var/list/Lines = file2list("config/admins.txt")
|
||||
|
||||
//process each line seperately
|
||||
for(var/line in Lines)
|
||||
if(!length(line)) continue
|
||||
if(copytext(line,1,2) == "#") continue
|
||||
|
||||
//Split the line at every "-"
|
||||
var/list/List = splittext(line, "-")
|
||||
if(!List.len) continue
|
||||
|
||||
//ckey is before the first "-"
|
||||
var/ckey = ckey(List[1])
|
||||
if(!ckey) continue
|
||||
|
||||
//rank follows the first "-"
|
||||
var/rank = ""
|
||||
if(List.len >= 2)
|
||||
rank = ckeyEx(List[2])
|
||||
for(var/iterator_key in GLOB.configuration.admin.ckey_rank_map)
|
||||
var/ckey = ckey(iterator_key) // Snip out formatting
|
||||
var/rank = GLOB.configuration.admin.ckey_rank_map[iterator_key]
|
||||
|
||||
//load permissions associated with this rank
|
||||
var/rights = GLOB.admin_ranks[rank]
|
||||
@@ -113,11 +87,11 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
|
||||
//The current admin system uses SQL
|
||||
if(!SSdbcore.IsConnected())
|
||||
log_world("Failed to connect to database in load_admins(). Reverting to legacy system.")
|
||||
config.admin_legacy_system = 1
|
||||
GLOB.configuration.admin.use_database_admins = FALSE
|
||||
load_admins()
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, admin_rank, level, flags FROM [format_table_name("admin")]")
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, admin_rank, level, flags FROM admin")
|
||||
if(!query.warn_execute(async=run_async))
|
||||
qdel(query)
|
||||
return
|
||||
@@ -141,7 +115,7 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
|
||||
|
||||
if(!GLOB.admin_datums)
|
||||
log_world("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.")
|
||||
config.admin_legacy_system = 1
|
||||
GLOB.configuration.admin.use_database_admins = FALSE
|
||||
load_admins()
|
||||
return
|
||||
|
||||
|
||||
@@ -137,7 +137,6 @@ GLOBAL_LIST_INIT(admin_verbs_server, list(
|
||||
/client/proc/toggle_antagHUD_restrictions,
|
||||
/client/proc/set_ooc,
|
||||
/client/proc/reset_ooc,
|
||||
/client/proc/toggledrones,
|
||||
/client/proc/set_next_map
|
||||
))
|
||||
GLOBAL_LIST_INIT(admin_verbs_debug, list(
|
||||
@@ -403,7 +402,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
if(!check_rights(R_BAN))
|
||||
return
|
||||
|
||||
if(config.ban_legacy_system)
|
||||
if(!GLOB.configuration.general.use_database_bans)
|
||||
holder.unbanpanel()
|
||||
else
|
||||
holder.DB_ban_panel()
|
||||
@@ -679,28 +678,20 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
|
||||
var/datum/admins/D = GLOB.admin_datums[ckey]
|
||||
var/rank = null
|
||||
if(config.admin_legacy_system)
|
||||
//load text from file
|
||||
var/list/Lines = file2list("config/admins.txt")
|
||||
for(var/line in Lines)
|
||||
if(findtext(line, "#")) // Skip comments
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
for(var/iterator_key in GLOB.configuration.admin.ckey_rank_map)
|
||||
var/_ckey = ckey(iterator_key) // Snip out formatting
|
||||
if(ckey != _ckey)
|
||||
continue
|
||||
|
||||
var/list/splitline = splittext(line, " - ")
|
||||
if(length(splitline) != 2) // Always 'ckey - rank'
|
||||
continue
|
||||
if(lowertext(splitline[1]) == ckey)
|
||||
rank = ckeyEx(splitline[2])
|
||||
break
|
||||
continue
|
||||
|
||||
rank = GLOB.configuration.admin.ckey_rank_map[iterator_key]
|
||||
break
|
||||
else
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(src, "Warning, MYSQL database is not connected.")
|
||||
return
|
||||
|
||||
var/datum/db_query/rank_read = SSdbcore.NewQuery(
|
||||
"SELECT admin_rank FROM [format_table_name("admin")] WHERE ckey=:ckey",
|
||||
"SELECT admin_rank FROM admin WHERE ckey=:ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
|
||||
@@ -713,7 +704,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
|
||||
qdel(rank_read)
|
||||
if(!D)
|
||||
if(config.admin_legacy_system)
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
if(GLOB.admin_ranks[rank] == null)
|
||||
error("Error while re-adminning [src], admin rank ([rank]) does not exist.")
|
||||
to_chat(src, "Error while re-adminning, admin rank ([rank]) does not exist.")
|
||||
@@ -726,7 +717,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
return
|
||||
|
||||
var/datum/db_query/admin_read = SSdbcore.NewQuery(
|
||||
"SELECT ckey, admin_rank, flags FROM [format_table_name("admin")] WHERE ckey=:ckey",
|
||||
"SELECT ckey, admin_rank, flags FROM admin WHERE ckey=:ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
|
||||
@@ -773,13 +764,13 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
if(!check_rights(R_SERVER))
|
||||
return
|
||||
|
||||
if(config)
|
||||
if(config.log_hrefs)
|
||||
config.log_hrefs = 0
|
||||
to_chat(src, "<b>Stopped logging hrefs</b>")
|
||||
else
|
||||
config.log_hrefs = 1
|
||||
to_chat(src, "<b>Started logging hrefs</b>")
|
||||
// Why would we ever turn this off?
|
||||
if(GLOB.configuration.logging.href_logging)
|
||||
GLOB.configuration.logging.href_logging = FALSE
|
||||
to_chat(src, "<b>Stopped logging hrefs</b>")
|
||||
else
|
||||
GLOB.configuration.logging.href_logging = TRUE
|
||||
to_chat(src, "<b>Started logging hrefs</b>")
|
||||
|
||||
/client/proc/check_ai_laws()
|
||||
set name = "Check AI Laws"
|
||||
@@ -956,17 +947,6 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
else
|
||||
to_chat(usr, "You now will get admin ticket messages.")
|
||||
|
||||
/client/proc/toggledrones()
|
||||
set name = "Toggle Maintenance Drones"
|
||||
set category = "Server"
|
||||
|
||||
if(!check_rights(R_SERVER))
|
||||
return
|
||||
|
||||
config.allow_drone_spawn = !(config.allow_drone_spawn)
|
||||
log_admin("[key_name(usr)] has [config.allow_drone_spawn ? "enabled" : "disabled"] maintenance drones.")
|
||||
message_admins("[key_name_admin(usr)] has [config.allow_drone_spawn ? "enabled" : "disabled"] maintenance drones.")
|
||||
|
||||
/client/proc/toggledebuglogs()
|
||||
set name = "Toggle Debug Log Messages"
|
||||
set category = "Preferences"
|
||||
|
||||
@@ -40,8 +40,9 @@ DEBUG
|
||||
appearance_loadbanfile()
|
||||
*/
|
||||
// AA 2020-11-25: This entire proc isnt even called. What the actual fuck.
|
||||
// AA 2021-05-23: This entire proc STILL isnt even called. I am going to screan.
|
||||
/proc/appearance_loadbanfile()
|
||||
if(config.ban_legacy_system)
|
||||
if(!GLOB.configuration.general.use_database_bans)
|
||||
var/savefile/S=new("data/appearance_full.ban")
|
||||
S["keys[0]"] >> GLOB.appearance_keylist
|
||||
log_admin("Loading appearance_rank")
|
||||
@@ -53,12 +54,12 @@ DEBUG
|
||||
else
|
||||
if(!SSdbcore.IsConnected())
|
||||
log_world("Database connection failed. Reverting to the legacy ban system.")
|
||||
config.ban_legacy_system = 1
|
||||
GLOB.configuration.general.use_database_bans = FALSE
|
||||
appearance_loadbanfile()
|
||||
return
|
||||
|
||||
//appearance bans
|
||||
var/datum/db_query/appearanceban_query = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("ban")] WHERE bantype = 'APPEARANCE_BAN' AND NOT unbanned = 1")
|
||||
var/datum/db_query/appearanceban_query = SSdbcore.NewQuery("SELECT ckey FROM ban WHERE bantype = 'APPEARANCE_BAN' AND NOT unbanned = 1")
|
||||
|
||||
if(!appearanceban_query.warn_execute())
|
||||
qdel(appearanceban_query)
|
||||
|
||||
@@ -17,7 +17,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
return
|
||||
GLOB.jobban_keylist.Add(text("[M.ckey] - [rank] ## [reason]"))
|
||||
jobban_assoc_insert(M.ckey, rank, reason)
|
||||
if(config.ban_legacy_system)
|
||||
if(!GLOB.configuration.general.use_database_bans)
|
||||
jobban_savebanfile()
|
||||
|
||||
/proc/jobban_client_fullban(ckey, rank)
|
||||
@@ -25,7 +25,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
return
|
||||
GLOB.jobban_keylist.Add(text("[ckey] - [rank]"))
|
||||
jobban_assoc_insert(ckey, rank)
|
||||
if(config.ban_legacy_system)
|
||||
if(!GLOB.configuration.general.use_database_bans)
|
||||
jobban_savebanfile()
|
||||
|
||||
//returns a reason if M is banned from rank, returns 0 otherwise
|
||||
@@ -33,7 +33,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
if(!M || !rank)
|
||||
return 0
|
||||
|
||||
if(config.guest_jobban && guest_jobbans(rank))
|
||||
if(GLOB.configuration.jobs.guest_job_ban && guest_jobbans(rank))
|
||||
if(IsGuestKey(M.key))
|
||||
return "Guest Job-ban"
|
||||
|
||||
@@ -46,7 +46,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
if(!ckey || !rank)
|
||||
return null
|
||||
|
||||
if(config.guest_jobban && guest_jobbans(rank))
|
||||
if(GLOB.configuration.jobs.guest_job_ban && guest_jobbans(rank))
|
||||
if(IsGuestKey(ckey))
|
||||
return "Guest Job-ban"
|
||||
|
||||
@@ -56,7 +56,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
return null
|
||||
|
||||
/proc/jobban_loadbanfile()
|
||||
if(config.ban_legacy_system)
|
||||
if(!GLOB.configuration.general.use_database_bans)
|
||||
var/savefile/S=new("data/job_full.ban")
|
||||
S["keys[0]"] >> GLOB.jobban_keylist
|
||||
log_admin("Loading jobban_rank")
|
||||
@@ -74,12 +74,12 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
else
|
||||
if(!SSdbcore.IsConnected())
|
||||
log_world("Database connection failed. Reverting to the legacy ban system.")
|
||||
config.ban_legacy_system = 1
|
||||
GLOB.configuration.general.use_database_bans = FALSE
|
||||
jobban_loadbanfile()
|
||||
return
|
||||
|
||||
//Job permabans
|
||||
var/datum/db_query/permabans = SSdbcore.NewQuery("SELECT ckey, job FROM [format_table_name("ban")] WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)")
|
||||
var/datum/db_query/permabans = SSdbcore.NewQuery("SELECT ckey, job FROM ban WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)")
|
||||
|
||||
if(!permabans.warn_execute(async=FALSE))
|
||||
qdel(permabans)
|
||||
@@ -94,7 +94,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
qdel(permabans)
|
||||
|
||||
// Job tempbans
|
||||
var/datum/db_query/tempbans = SSdbcore.NewQuery("SELECT ckey, job FROM [format_table_name("ban")] WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()")
|
||||
var/datum/db_query/tempbans = SSdbcore.NewQuery("SELECT ckey, job FROM ban WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()")
|
||||
|
||||
if(!tempbans.warn_execute(async=FALSE))
|
||||
qdel(tempbans)
|
||||
@@ -132,7 +132,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
else
|
||||
log_runtime(EXCEPTION("Failed to remove malformed job ban from associative list: [X]"))
|
||||
GLOB.jobban_keylist.Remove(GLOB.jobban_keylist[i])
|
||||
if(config.ban_legacy_system)
|
||||
if(!GLOB.configuration.general.use_database_bans)
|
||||
jobban_savebanfile()
|
||||
return 1
|
||||
return 0
|
||||
@@ -144,7 +144,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
|
||||
if(!client || !ckey)
|
||||
return
|
||||
if(config.ban_legacy_system)
|
||||
if(!GLOB.configuration.general.use_database_bans)
|
||||
//using the legacy .txt ban system
|
||||
to_chat(src, "The server is using the legacy ban system. Ask an administrator for help!")
|
||||
|
||||
@@ -152,7 +152,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
//using the SQL ban system
|
||||
var/is_actually_banned = FALSE
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery({"
|
||||
SELECT bantime, bantype, reason, job, duration, expiration_time, a_ckey FROM [format_table_name("ban")]
|
||||
SELECT bantime, bantype, reason, job, duration, expiration_time, a_ckey FROM ban
|
||||
WHERE ckey LIKE :ckey AND ((bantype like 'JOB_TEMPBAN' AND expiration_time > Now()) OR (bantype like 'JOB_PERMABAN')) AND isnull(unbanned)
|
||||
ORDER BY bantime DESC LIMIT 100"},
|
||||
list("ckey" = ckey)
|
||||
@@ -182,7 +182,7 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
qdel(select_query)
|
||||
|
||||
if(is_actually_banned)
|
||||
if(config.banappeals)
|
||||
to_chat(src, "<span class='warning'>You can appeal the bans at: [config.banappeals]</span>")
|
||||
if(GLOB.configuration.url.banappeals_url)
|
||||
to_chat(src, "<span class='warning'>You can appeal the bans at: [GLOB.configuration.url.banappeals_url]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You have no active jobbans!</span>")
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
/datum/admins/proc/create_ccbdb_lookup(ckey)
|
||||
// Bail if disabled
|
||||
if(!config.centcom_ban_db_url)
|
||||
if(!GLOB.configuration.url.centcom_ban_db_url)
|
||||
to_chat(usr, "<span class='warning'>The CentCom Ban DB lookup is disabled. Please inform a maintainer or server host.</span>")
|
||||
return
|
||||
// Bail if no ckey is supplied
|
||||
@@ -22,7 +22,7 @@
|
||||
return
|
||||
|
||||
var/datum/callback/cb = CALLBACK(src, /datum/admins/.proc/ccbdb_lookup_callback, usr, ckey)
|
||||
SShttp.create_async_request(RUSTG_HTTP_METHOD_GET, "[config.centcom_ban_db_url][ckey]", proc_callback=cb)
|
||||
SShttp.create_async_request(RUSTG_HTTP_METHOD_GET, "[GLOB.configuration.url.centcom_ban_db_url][ckey]", proc_callback=cb)
|
||||
|
||||
/**
|
||||
* CCBDB Lookup Callback
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
var/has_note = FALSE
|
||||
var/raw_text = ""
|
||||
// Now lets see if we have a note logging the infraction in the past
|
||||
var/datum/db_query/check_existing_note = SSdbcore.NewQuery("SELECT notetext FROM [format_table_name("notes")] WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
var/datum/db_query/check_existing_note = SSdbcore.NewQuery("SELECT notetext FROM notes WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
"ckey" = cookie_holder_ckey,
|
||||
"ackey" = COOKIERECORD_PSUEDO_CKEY
|
||||
))
|
||||
@@ -99,7 +99,7 @@
|
||||
serialized_text = serialized_list.Join("<br>")
|
||||
|
||||
if(has_note) // They have a note. Update.
|
||||
var/datum/db_query/update_existing_note = SSdbcore.NewQuery("UPDATE [format_table_name("notes")] SET notetext=:nt, timestamp=NOW(), round_id=:rid WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
var/datum/db_query/update_existing_note = SSdbcore.NewQuery("UPDATE notes SET notetext=:nt, timestamp=NOW(), round_id=:rid WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
"nt" = serialized_text,
|
||||
"rid" = GLOB.round_id,
|
||||
"ckey" = cookie_holder_ckey,
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
message_admins("<font color='red'>[key_name_admin(usr)] attempted to add a ban based on a non-existent mob, with no ckey provided. Report this bug.",1)
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id FROM player WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -131,7 +131,7 @@
|
||||
adminwho += ", [C]"
|
||||
|
||||
if(maxadminbancheck)
|
||||
var/datum/db_query/adm_query = SSdbcore.NewQuery("SELECT count(id) AS num FROM [format_table_name("ban")] WHERE (a_ckey=:a_ckey) AND (bantype = 'ADMIN_PERMABAN' OR (bantype = 'ADMIN_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)", list(
|
||||
var/datum/db_query/adm_query = SSdbcore.NewQuery("SELECT count(id) AS num FROM ban WHERE (a_ckey=:a_ckey) AND (bantype = 'ADMIN_PERMABAN' OR (bantype = 'ADMIN_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)", list(
|
||||
"a_ckey" = a_ckey
|
||||
))
|
||||
if(!adm_query.warn_execute())
|
||||
@@ -146,7 +146,7 @@
|
||||
qdel(adm_query)
|
||||
|
||||
var/datum/db_query/query_insert = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("ban")] (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`,`ban_round_id`,`unbanned_round_id`)
|
||||
INSERT INTO ban (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`,`ban_round_id`,`unbanned_round_id`)
|
||||
VALUES (null, Now(), :serverip, :bantype_str, :reason, :job, :duration, :rounds, Now() + INTERVAL :duration MINUTE, :ckey, :computerid, :ip, :a_ckey, :a_computerid, :a_ip, :who, :adminwho, '', null, null, null, null, null, :roundid, null)
|
||||
"}, list(
|
||||
// Get ready for parameters
|
||||
@@ -233,7 +233,7 @@
|
||||
else
|
||||
bantype_sql = "bantype = '[bantype_str]'"
|
||||
|
||||
var/sql = "SELECT id FROM [format_table_name("ban")] WHERE ckey=:ckey AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
|
||||
var/sql = "SELECT id FROM ban WHERE ckey=:ckey AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
|
||||
var/list/sql_params = list(
|
||||
"ckey" = ckey
|
||||
)
|
||||
@@ -283,7 +283,7 @@
|
||||
to_chat(usr, "Cancelled")
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, duration, reason, job FROM [format_table_name("ban")] WHERE id=:banid", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, duration, reason, job FROM ban WHERE id=:banid", list(
|
||||
"banid" = banid
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -318,7 +318,7 @@
|
||||
return
|
||||
|
||||
var/edit_reason = "- [eckey] changed ban reason from <cite><b>\\\"[reason]\\\"</b></cite> to <cite><b>\\\"[value]\\\"</b></cite><BR>"
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE [format_table_name("ban")] SET reason=:value, edits = CONCAT(IFNULL(edits,''), :edittext) WHERE id=:banid", list(
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE ban SET reason=:value, edits = CONCAT(IFNULL(edits,''), :edittext) WHERE id=:banid", list(
|
||||
"edittext" = edit_reason,
|
||||
"banid" = banid,
|
||||
"value" = value
|
||||
@@ -337,7 +337,7 @@
|
||||
return
|
||||
|
||||
var/edittext = "- [eckey] changed ban duration from [duration] to [value]<br>"
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE [format_table_name("ban")] SET duration=:value, edits = CONCAT(IFNULL(edits, ''), :edittext), expiration_time = DATE_ADD(bantime, INTERVAL :value MINUTE) WHERE id=:banid", list(
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE ban SET duration=:value, edits = CONCAT(IFNULL(edits, ''), :edittext), expiration_time = DATE_ADD(bantime, INTERVAL :value MINUTE) WHERE id=:banid", list(
|
||||
"edittext" = edittext,
|
||||
"banid" = banid,
|
||||
"value" = value
|
||||
@@ -373,7 +373,7 @@
|
||||
var/ban_number = 0 //failsafe
|
||||
|
||||
var/pckey
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("ban")] WHERE id=:banid", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM ban WHERE id=:banid", list(
|
||||
"banid" = id
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -400,7 +400,7 @@
|
||||
var/unban_computerid = src.owner:computer_id
|
||||
var/unban_ip = src.owner:address
|
||||
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE [format_table_name("ban")] SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey=:unban_ckey, unbanned_computerid=:unban_computerid, unbanned_ip=:unban_ip, unbanned_round_id=:roundid WHERE id=:id", list(
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE ban SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey=:unban_ckey, unbanned_computerid=:unban_computerid, unbanned_ip=:unban_ip, unbanned_round_id=:roundid WHERE id=:id", list(
|
||||
"unban_ckey" = unban_ckey,
|
||||
"unban_computerid" = unban_computerid,
|
||||
"unban_ip" = unban_ip,
|
||||
@@ -587,7 +587,7 @@
|
||||
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery({"
|
||||
SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid, ban_round_id, unbanned_round_id
|
||||
FROM [format_table_name("ban")] WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100"}, sql_params)
|
||||
FROM ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100"}, sql_params)
|
||||
|
||||
if(!select_query.warn_execute())
|
||||
qdel(select_query)
|
||||
@@ -673,7 +673,7 @@
|
||||
/proc/flag_account_for_forum_sync(ckey)
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
var/datum/db_query/adm_query = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET fupdate = 1 WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/adm_query = SSdbcore.NewQuery("UPDATE player SET fupdate = 1 WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
// We do nothing with output here so we dont need to wrap the warn_execute() inside an if statement
|
||||
|
||||
@@ -1,247 +0,0 @@
|
||||
/datum/ipintel
|
||||
var/ip
|
||||
var/intel = 0
|
||||
var/cache = FALSE
|
||||
var/cacheminutesago = 0
|
||||
var/cachedate = ""
|
||||
var/cacherealtime = 0
|
||||
|
||||
/datum/ipintel/New()
|
||||
cachedate = SQLtime()
|
||||
cacherealtime = world.realtime
|
||||
|
||||
/datum/ipintel/proc/is_valid()
|
||||
. = FALSE
|
||||
if(intel < 0)
|
||||
return
|
||||
if(intel <= config.ipintel_rating_bad)
|
||||
if(world.realtime < cacherealtime + (config.ipintel_save_good HOURS))
|
||||
return TRUE
|
||||
else
|
||||
if(world.realtime < cacherealtime + (config.ipintel_save_bad HOURS))
|
||||
return TRUE
|
||||
|
||||
/proc/get_ip_intel(ip, bypasscache = FALSE, updatecache = TRUE)
|
||||
var/datum/ipintel/res = new()
|
||||
res.ip = ip
|
||||
. = res
|
||||
if(!ip || !config.ipintel_email || !SSipintel.enabled)
|
||||
return
|
||||
if(!bypasscache)
|
||||
var/datum/ipintel/cachedintel = SSipintel.cache[ip]
|
||||
if(cachedintel && cachedintel.is_valid())
|
||||
cachedintel.cache = TRUE
|
||||
return cachedintel
|
||||
|
||||
if(SSdbcore.IsConnected())
|
||||
var/datum/db_query/query_get_ip_intel = SSdbcore.NewQuery({"
|
||||
SELECT date, intel, TIMESTAMPDIFF(MINUTE,date,NOW())
|
||||
FROM [format_table_name("ipintel")]
|
||||
WHERE
|
||||
ip = INET_ATON(:ip)
|
||||
AND ((
|
||||
intel < :rating_bad
|
||||
AND
|
||||
date + INTERVAL :save_good HOUR > NOW()
|
||||
) OR (
|
||||
intel >= :rating_bad
|
||||
AND
|
||||
date + INTERVAL :save_bad HOUR > NOW()
|
||||
))
|
||||
"}, list(
|
||||
"ip" = ip,
|
||||
"rating_bad" = config.ipintel_rating_bad,
|
||||
"save_good" = config.ipintel_save_good,
|
||||
"save_bad" = config.ipintel_save_bad,
|
||||
))
|
||||
if(!query_get_ip_intel.warn_execute())
|
||||
qdel(query_get_ip_intel)
|
||||
return
|
||||
if(query_get_ip_intel.NextRow())
|
||||
res.cache = TRUE
|
||||
res.cachedate = query_get_ip_intel.item[1]
|
||||
res.intel = text2num(query_get_ip_intel.item[2])
|
||||
res.cacheminutesago = text2num(query_get_ip_intel.item[3])
|
||||
res.cacherealtime = world.realtime - (text2num(query_get_ip_intel.item[3])*10*60)
|
||||
SSipintel.cache[ip] = res
|
||||
qdel(query_get_ip_intel)
|
||||
return
|
||||
qdel(query_get_ip_intel)
|
||||
res.intel = ip_intel_query(ip)
|
||||
if(updatecache && res.intel >= 0)
|
||||
SSipintel.cache[ip] = res
|
||||
if(SSdbcore.IsConnected())
|
||||
var/datum/db_query/query_add_ip_intel = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("ipintel")] (ip, intel) VALUES (INET_ATON(:ip), :intel)
|
||||
ON DUPLICATE KEY UPDATE intel = VALUES(intel), date = NOW()"},
|
||||
list(
|
||||
"ip" = ip,
|
||||
"intel" = res.intel
|
||||
)
|
||||
)
|
||||
query_add_ip_intel.warn_execute()
|
||||
qdel(query_add_ip_intel)
|
||||
|
||||
|
||||
/proc/ip_intel_query(ip, retryed=0)
|
||||
. = -1 //default
|
||||
if(!ip)
|
||||
return
|
||||
if(SSipintel.throttle > world.timeofday)
|
||||
return
|
||||
if(!SSipintel.enabled)
|
||||
return
|
||||
|
||||
// Do not refactor this to use SShttp, because that requires the subsystem to be firing for requests to be made, and this will be triggered before the MC has finished loading
|
||||
var/list/http[] = world.Export("http://[config.ipintel_domain]/check.php?ip=[ip]&contact=[config.ipintel_email]&format=json&flags=b")
|
||||
|
||||
if(http)
|
||||
var/status = text2num(http["STATUS"])
|
||||
|
||||
if(status == 200)
|
||||
var/response = json_decode(file2text(http["CONTENT"]))
|
||||
if(response)
|
||||
if(response["status"] == "success")
|
||||
var/intelnum = text2num(response["result"])
|
||||
if(isnum(intelnum))
|
||||
return text2num(response["result"])
|
||||
else
|
||||
ipintel_handle_error("Bad intel from server: [response["result"]].", ip, retryed)
|
||||
if(!retryed)
|
||||
sleep(25)
|
||||
return .(ip, 1)
|
||||
else
|
||||
ipintel_handle_error("Bad response from server: [response["status"]].", ip, retryed)
|
||||
if(!retryed)
|
||||
sleep(25)
|
||||
return .(ip, 1)
|
||||
|
||||
else if(status == 429)
|
||||
ipintel_handle_error("Error #429: We have exceeded the rate limit.", ip, 1)
|
||||
return
|
||||
else
|
||||
ipintel_handle_error("Unknown status code: [status].", ip, retryed)
|
||||
if(!retryed)
|
||||
sleep(25)
|
||||
return .(ip, 1)
|
||||
else
|
||||
ipintel_handle_error("Unable to connect to API.", ip, retryed)
|
||||
if(!retryed)
|
||||
sleep(25)
|
||||
return .(ip, 1)
|
||||
|
||||
|
||||
/proc/ipintel_handle_error(error, ip, retryed)
|
||||
if(retryed)
|
||||
SSipintel.errors++
|
||||
error += " Could not check [ip]. Disabling IPINTEL for [SSipintel.errors] minute[( SSipintel.errors == 1 ? "" : "s" )]"
|
||||
SSipintel.throttle = world.timeofday + (2 * SSipintel.errors MINUTES)
|
||||
else
|
||||
error += " Attempting retry on [ip]."
|
||||
log_ipintel(error)
|
||||
|
||||
/proc/log_ipintel(text)
|
||||
log_game("IPINTEL: [text]")
|
||||
log_debug("IPINTEL: [text]")
|
||||
|
||||
|
||||
/proc/ipintel_is_banned(t_ckey, t_ip)
|
||||
if(!config.ipintel_email)
|
||||
return FALSE
|
||||
if(!config.ipintel_whitelist)
|
||||
return FALSE
|
||||
if(!SSdbcore.IsConnected())
|
||||
return FALSE
|
||||
if(!ipintel_badip_check(t_ip))
|
||||
return FALSE
|
||||
if(vpn_whitelist_check(t_ckey))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/proc/ipintel_badip_check(target_ip)
|
||||
var/rating_bad = config.ipintel_rating_bad
|
||||
if(!rating_bad)
|
||||
log_debug("ipintel_badip_check reports misconfigured rating_bad directive")
|
||||
return FALSE
|
||||
var/valid_hours = config.ipintel_save_bad
|
||||
if(!valid_hours)
|
||||
log_debug("ipintel_badip_check reports misconfigured ipintel_save_bad directive")
|
||||
return FALSE
|
||||
var/datum/db_query/query_get_ip_intel = SSdbcore.NewQuery({"
|
||||
SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:target_ip)
|
||||
AND intel >= :rating_bad AND (date + INTERVAL :valid_hours HOUR) > NOW()"},
|
||||
list(
|
||||
"target_ip" = target_ip,
|
||||
"rating_bad" = rating_bad,
|
||||
"valid_hours" = valid_hours
|
||||
)
|
||||
)
|
||||
if(!query_get_ip_intel.warn_execute())
|
||||
log_debug("ipintel_badip_check reports failed query execution")
|
||||
qdel(query_get_ip_intel)
|
||||
return FALSE
|
||||
if(!query_get_ip_intel.NextRow())
|
||||
qdel(query_get_ip_intel)
|
||||
return FALSE
|
||||
qdel(query_get_ip_intel)
|
||||
return TRUE
|
||||
|
||||
/proc/vpn_whitelist_check(target_ckey)
|
||||
if(!config.ipintel_whitelist)
|
||||
return FALSE
|
||||
var/datum/db_query/query_whitelist_check = SSdbcore.NewQuery("SELECT * FROM [format_table_name("vpn_whitelist")] WHERE ckey=:ckey", list(
|
||||
"ckey" = target_ckey
|
||||
))
|
||||
if(!query_whitelist_check.warn_execute())
|
||||
qdel(query_whitelist_check)
|
||||
return FALSE
|
||||
if(query_whitelist_check.NextRow())
|
||||
qdel(query_whitelist_check)
|
||||
return TRUE // At least one row in the whitelist names their ckey. That means they are whitelisted.
|
||||
qdel(query_whitelist_check)
|
||||
return FALSE
|
||||
|
||||
/proc/vpn_whitelist_add(target_ckey)
|
||||
var/reason_string = input(usr, "Enter link to the URL of their whitelist request on the forum.","Reason required") as message|null
|
||||
if(!reason_string)
|
||||
return FALSE
|
||||
var/datum/db_query/query_whitelist_add = SSdbcore.NewQuery("INSERT INTO [format_table_name("vpn_whitelist")] (ckey,reason) VALUES (:targetckey, :reason)", list(
|
||||
"targetckey" = target_ckey,
|
||||
"reason" = reason_string
|
||||
))
|
||||
if(!query_whitelist_add.warn_execute())
|
||||
qdel(query_whitelist_add)
|
||||
return FALSE
|
||||
qdel(query_whitelist_add)
|
||||
return TRUE
|
||||
|
||||
/proc/vpn_whitelist_remove(target_ckey)
|
||||
var/datum/db_query/query_whitelist_remove = SSdbcore.NewQuery("DELETE FROM [format_table_name("vpn_whitelist")] WHERE ckey=:targetckey", list(
|
||||
"targetckey" = target_ckey
|
||||
))
|
||||
if(!query_whitelist_remove.warn_execute())
|
||||
qdel(query_whitelist_remove)
|
||||
return FALSE
|
||||
qdel(query_whitelist_remove)
|
||||
return TRUE
|
||||
|
||||
/proc/vpn_whitelist_panel(target_ckey as text)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(!target_ckey)
|
||||
return
|
||||
var/is_already_whitelisted = vpn_whitelist_check(target_ckey)
|
||||
if(is_already_whitelisted)
|
||||
var/confirm = alert("[target_ckey] is already whitelisted. Remove them?", "Confirm Removal", "No", "Yes")
|
||||
if(!confirm || confirm != "Yes")
|
||||
to_chat(usr, "VPN whitelist alteration cancelled.")
|
||||
return
|
||||
else if(vpn_whitelist_remove(target_ckey))
|
||||
to_chat(usr, "[target_ckey] was removed from the VPN whitelist.")
|
||||
else
|
||||
to_chat(usr, "VPN whitelist unchanged.")
|
||||
else
|
||||
if(vpn_whitelist_add(target_ckey))
|
||||
to_chat(usr, "[target_ckey] was added to the VPN whitelist.")
|
||||
else
|
||||
to_chat(usr, "VPN whitelist unchanged.")
|
||||
@@ -52,7 +52,8 @@
|
||||
usr << browse(output,"window=editrights;size=600x500")
|
||||
|
||||
/datum/admins/proc/log_admin_rank_modification(adm_ckey, new_rank)
|
||||
if(config.admin_legacy_system) return
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
return
|
||||
|
||||
if(!usr.client)
|
||||
return
|
||||
@@ -75,7 +76,7 @@
|
||||
if(!istext(adm_ckey) || !istext(new_rank))
|
||||
return
|
||||
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id FROM [format_table_name("admin")] WHERE ckey=:adm_ckey", list(
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id FROM admin WHERE ckey=:adm_ckey", list(
|
||||
"adm_ckey" = adm_ckey
|
||||
))
|
||||
if(!select_query.warn_execute())
|
||||
@@ -90,7 +91,7 @@
|
||||
qdel(select_query)
|
||||
flag_account_for_forum_sync(adm_ckey)
|
||||
if(new_admin)
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin")] (`id`, `ckey`, `admin_rank`, `level`, `flags`) VALUES (null, :adm_ckey, :new_rank, -1, 0)", list(
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO admin (`id`, `ckey`, `admin_rank`, `level`, `flags`) VALUES (null, :adm_ckey, :new_rank, -1, 0)", list(
|
||||
"adm_ckey" = adm_ckey,
|
||||
"new_rank" = new_rank
|
||||
))
|
||||
@@ -100,7 +101,7 @@
|
||||
qdel(insert_query)
|
||||
|
||||
var/logtxt = "Added new admin [adm_ckey] to rank [new_rank]"
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , :uckey, :uip, :logtxt)", list(
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , :uckey, :uip, :logtxt)", list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt
|
||||
@@ -113,7 +114,7 @@
|
||||
to_chat(usr, "<span class='notice'>New admin added.</span>")
|
||||
else
|
||||
if(!isnull(admin_id) && isnum(admin_id))
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET admin_rank=:new_rank WHERE id=:admin_id", list(
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE admin SET admin_rank=:new_rank WHERE id=:admin_id", list(
|
||||
"new_rank" = new_rank,
|
||||
"admin_id" = admin_id,
|
||||
))
|
||||
@@ -123,7 +124,7 @@
|
||||
qdel(insert_query)
|
||||
|
||||
var/logtxt = "Edited the rank of [adm_ckey] to [new_rank]"
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , :uckey, :uip, :logtxt)", list(
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , :uckey, :uip, :logtxt)", list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
"logtxt" = logtxt,
|
||||
@@ -140,7 +141,7 @@
|
||||
message_admins("[key_name(usr)] attempted to edit admin ranks via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to edit admin ranks via advanced proc-call")
|
||||
return
|
||||
if(config.admin_legacy_system)
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
return
|
||||
|
||||
if(!usr.client)
|
||||
@@ -167,7 +168,7 @@
|
||||
if(!istext(adm_ckey) || !isnum(new_permission))
|
||||
return
|
||||
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id, flags FROM [format_table_name("admin")] WHERE ckey=:adm_ckey", list(
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id, flags FROM admin WHERE ckey=:adm_ckey", list(
|
||||
"adm_ckey" = adm_ckey
|
||||
))
|
||||
if(!select_query.warn_execute())
|
||||
@@ -186,7 +187,7 @@
|
||||
|
||||
flag_account_for_forum_sync(adm_ckey)
|
||||
if(admin_rights & new_permission) //This admin already has this permission, so we are removing it.
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET flags=:newflags WHERE id=:admin_id", list(
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE admin SET flags=:newflags WHERE id=:admin_id", list(
|
||||
"newflags" = (admin_rights & ~new_permission),
|
||||
"admin_id" = admin_id
|
||||
))
|
||||
@@ -197,7 +198,7 @@
|
||||
|
||||
var/logtxt = "Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]"
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
@@ -209,7 +210,7 @@
|
||||
qdel(log_query)
|
||||
to_chat(usr, "<span class='notice'>Permission removed.</span>")
|
||||
else //This admin doesn't have this permission, so we are adding it.
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET flags=:newflags WHERE id=:admin_id", list(
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE admin SET flags=:newflags WHERE id=:admin_id", list(
|
||||
"newflags" = (admin_rights | new_permission),
|
||||
"admin_id" = admin_id
|
||||
))
|
||||
@@ -220,7 +221,7 @@
|
||||
|
||||
var/logtxt = "Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]"
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
INSERT INTO admin_log (`datetime` ,`adminckey` ,`adminip` ,`log`)
|
||||
VALUES (Now() , :uckey, :uip, :logtxt)"}, list(
|
||||
"uckey" = usr.ckey,
|
||||
"uip" = usr.client.address,
|
||||
@@ -239,7 +240,7 @@
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET lastadminrank=:admin_rank WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET lastadminrank=:admin_rank WHERE ckey=:ckey", list(
|
||||
"admin_rank" = newrank,
|
||||
"ckey" = ckey
|
||||
))
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
var/mob/M = blob.current
|
||||
if(M)
|
||||
dat += "<tr><td>[ADMIN_PP(M,"[M.real_name]")][M.client ? "" : " <i>(ghost)</i>"][M.stat == 2 ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>"
|
||||
dat += "<td><A href='?priv_msg=[M.client?.ckey]'>PM</A></td>"
|
||||
dat += "<td><A href='?priv_msg=[M.client?.ckey]'>PM</A> [ADMIN_FLW(M, "FLW")]</td>"
|
||||
else
|
||||
dat += "<tr><td><i>Blob not found!</i></td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
@@ -81,6 +81,9 @@
|
||||
<b>Create Weather</b><BR>
|
||||
<A href='?src=[UID()];secretsfun=weatherashstorm'>Weather - Ash Storm</A>
|
||||
<BR>
|
||||
<b>Reinforce Station</b><BR>
|
||||
<A href='?src=[UID()];secretsfun=gammashuttle'>Move the Gamma Armory</A>
|
||||
<BR>
|
||||
</center>"}
|
||||
|
||||
if(2)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
else
|
||||
target_ckey = ckey(target_ckey)
|
||||
|
||||
var/datum/db_query/query_find_ckey = SSdbcore.NewQuery("SELECT ckey, exp FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query_find_ckey = SSdbcore.NewQuery("SELECT ckey, exp FROM player WHERE ckey=:ckey", list(
|
||||
"ckey" = target_ckey
|
||||
))
|
||||
|
||||
@@ -54,14 +54,14 @@
|
||||
adminckey = ckey(adminckey)
|
||||
|
||||
if(!server)
|
||||
if(config && config.server_name)
|
||||
server = config.server_name
|
||||
if(GLOB.configuration.general.server_name)
|
||||
server = GLOB.configuration.general.server_name
|
||||
|
||||
// Force cast this to 1/0 incase someone tries to feed bad data
|
||||
automated = !!automated
|
||||
|
||||
var/datum/db_query/query_noteadd = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("notes")] (ckey, timestamp, notetext, adminckey, server, crew_playtime, round_id, automated)
|
||||
INSERT INTO notes (ckey, timestamp, notetext, adminckey, server, crew_playtime, round_id, automated)
|
||||
VALUES (:targetckey, NOW(), :notetext, :adminkey, :server, :crewnum, :roundid, :automated)
|
||||
"}, list(
|
||||
"targetckey" = target_ckey,
|
||||
@@ -95,7 +95,7 @@
|
||||
if(!note_id)
|
||||
return
|
||||
note_id = text2num(note_id)
|
||||
var/datum/db_query/query_find_note_del = SSdbcore.NewQuery("SELECT ckey, notetext, adminckey FROM [format_table_name("notes")] WHERE id=:note_id", list(
|
||||
var/datum/db_query/query_find_note_del = SSdbcore.NewQuery("SELECT ckey, notetext, adminckey FROM notes WHERE id=:note_id", list(
|
||||
"note_id" = note_id
|
||||
))
|
||||
if(!query_find_note_del.warn_execute())
|
||||
@@ -107,7 +107,7 @@
|
||||
adminckey = query_find_note_del.item[3]
|
||||
qdel(query_find_note_del)
|
||||
|
||||
var/datum/db_query/query_del_note = SSdbcore.NewQuery("DELETE FROM [format_table_name("notes")] WHERE id=:note_id", list(
|
||||
var/datum/db_query/query_del_note = SSdbcore.NewQuery("DELETE FROM notes WHERE id=:note_id", list(
|
||||
"note_id" = note_id
|
||||
))
|
||||
if(!query_del_note.warn_execute())
|
||||
@@ -130,7 +130,7 @@
|
||||
return
|
||||
note_id = text2num(note_id)
|
||||
var/target_ckey
|
||||
var/datum/db_query/query_find_note_edit = SSdbcore.NewQuery("SELECT ckey, notetext, adminckey, automated FROM [format_table_name("notes")] WHERE id=:note_id", list(
|
||||
var/datum/db_query/query_find_note_edit = SSdbcore.NewQuery("SELECT ckey, notetext, adminckey, automated FROM notes WHERE id=:note_id", list(
|
||||
"note_id" = note_id
|
||||
))
|
||||
if(!query_find_note_edit.warn_execute())
|
||||
@@ -148,7 +148,7 @@
|
||||
if(!new_note)
|
||||
return
|
||||
var/edit_text = "Edited by [usr.ckey] on [SQLtime()] from \"[old_note]\" to \"[new_note]\"<hr>"
|
||||
var/datum/db_query/query_update_note = SSdbcore.NewQuery("UPDATE [format_table_name("notes")] SET notetext=:new_note, last_editor=:akey, edits = CONCAT(IFNULL(edits,''),:edit_text) WHERE id=:note_id", list(
|
||||
var/datum/db_query/query_update_note = SSdbcore.NewQuery("UPDATE notes SET notetext=:new_note, last_editor=:akey, edits = CONCAT(IFNULL(edits,''),:edit_text) WHERE id=:note_id", list(
|
||||
"new_note" = new_note,
|
||||
"akey" = usr.ckey,
|
||||
"edit_text" = edit_text,
|
||||
@@ -182,7 +182,7 @@
|
||||
var/target_sql_ckey = ckey(target_ckey)
|
||||
var/datum/db_query/query_get_notes = SSdbcore.NewQuery({"
|
||||
SELECT id, timestamp, notetext, adminckey, last_editor, server, crew_playtime, round_id, automated
|
||||
FROM [format_table_name("notes")] WHERE ckey=:targetkey ORDER BY timestamp"}, list(
|
||||
FROM notes WHERE ckey=:targetkey ORDER BY timestamp"}, list(
|
||||
"targetkey" = target_sql_ckey
|
||||
))
|
||||
if(!query_get_notes.warn_execute())
|
||||
@@ -226,7 +226,7 @@
|
||||
search = "^\[^\[:alpha:\]\]"
|
||||
else
|
||||
search = "^[index]"
|
||||
var/datum/db_query/query_list_notes = SSdbcore.NewQuery("SELECT DISTINCT ckey FROM [format_table_name("notes")] WHERE ckey REGEXP :search ORDER BY ckey", list(
|
||||
var/datum/db_query/query_list_notes = SSdbcore.NewQuery("SELECT DISTINCT ckey FROM notes WHERE ckey REGEXP :search ORDER BY ckey", list(
|
||||
"search" = search
|
||||
))
|
||||
if(!query_list_notes.warn_execute())
|
||||
|
||||
+42
-42
@@ -287,19 +287,19 @@
|
||||
if(null,"") return
|
||||
if("*New Rank*")
|
||||
new_rank = input("Please input a new rank", "New custom rank", null, null) as null|text
|
||||
if(config.admin_legacy_system)
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
new_rank = ckeyEx(new_rank)
|
||||
if(!new_rank)
|
||||
to_chat(usr, "<font color='red'>Error: Topic 'editrights': Invalid rank</font>")
|
||||
return
|
||||
if(config.admin_legacy_system)
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
if(GLOB.admin_ranks.len)
|
||||
if(new_rank in GLOB.admin_ranks)
|
||||
rights = GLOB.admin_ranks[new_rank] //we typed a rank which already exists, use its rights
|
||||
else
|
||||
GLOB.admin_ranks[new_rank] = 0 //add the new rank to admin_ranks
|
||||
else
|
||||
if(config.admin_legacy_system)
|
||||
if(!GLOB.configuration.admin.use_database_admins)
|
||||
new_rank = ckeyEx(new_rank)
|
||||
rights = GLOB.admin_ranks[new_rank] //we input an existing rank, use its rights
|
||||
|
||||
@@ -538,8 +538,8 @@
|
||||
to_chat(M, "<span class='warning'><big><b>You have been appearance banned by [usr.client.ckey].</b></big></span>")
|
||||
to_chat(M, "<span class='danger'>The reason is: [reason]</span>")
|
||||
to_chat(M, "<span class='warning'>Appearance ban can be lifted only upon request.</span>")
|
||||
if(config.banappeals)
|
||||
to_chat(M, "<span class='warning'>To try to resolve this matter head to [config.banappeals]</span>")
|
||||
if(GLOB.configuration.url.banappeals_url)
|
||||
to_chat(M, "<span class='warning'>To try to resolve this matter head to [GLOB.configuration.url.banappeals_url]</span>")
|
||||
else
|
||||
to_chat(M, "<span class='warning'>No ban appeals URL has been set.</span>")
|
||||
if("No")
|
||||
@@ -877,7 +877,7 @@
|
||||
if(notbannedlist.len) //at least 1 unbanned job exists in joblist so we have stuff to ban.
|
||||
switch(alert("Temporary Ban of [M.ckey]?",,"Yes","No", "Cancel"))
|
||||
if("Yes")
|
||||
if(config.ban_legacy_system)
|
||||
if(!GLOB.configuration.general.use_database_bans)
|
||||
to_chat(usr, "<span class='warning'>Your server is using the legacy banning system, which does not support temporary job bans. Consider upgrading. Aborting ban.</span>")
|
||||
return
|
||||
var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null
|
||||
@@ -928,7 +928,7 @@
|
||||
//Unbanning joblist
|
||||
//all jobs in joblist are banned already OR we didn't give a reason (implying they shouldn't be banned)
|
||||
if(joblist.len) //at least 1 banned job exists in joblist so we have stuff to unban.
|
||||
if(!config.ban_legacy_system)
|
||||
if(GLOB.configuration.general.use_database_bans)
|
||||
to_chat(usr, "<span class='warning'>Unfortunately, database based unbanning cannot be done through this panel</span>")
|
||||
DB_ban_panel(M.ckey)
|
||||
return
|
||||
@@ -1002,8 +1002,8 @@
|
||||
|
||||
else if(href_list["webtools"])
|
||||
var/target_ckey = href_list["webtools"]
|
||||
if(config.forum_playerinfo_url)
|
||||
var/url_to_open = config.forum_playerinfo_url + target_ckey
|
||||
if(GLOB.configuration.url.forum_playerinfo_url)
|
||||
var/url_to_open = "[GLOB.configuration.url.forum_playerinfo_url][target_ckey]"
|
||||
if(alert("Open [url_to_open]",,"Yes","No")=="Yes")
|
||||
usr.client << link(url_to_open)
|
||||
|
||||
@@ -1017,7 +1017,7 @@
|
||||
|
||||
else if(href_list["noteedits"])
|
||||
var/note_id = text2num(href_list["noteedits"])
|
||||
var/datum/db_query/query_noteedits = SSdbcore.NewQuery("SELECT edits FROM [format_table_name("notes")] WHERE id=:note_id", list(
|
||||
var/datum/db_query/query_noteedits = SSdbcore.NewQuery("SELECT edits FROM notes WHERE id=:note_id", list(
|
||||
"note_id" = note_id
|
||||
))
|
||||
if(!query_noteedits.warn_execute())
|
||||
@@ -1067,8 +1067,8 @@
|
||||
DB_ban_record(BANTYPE_TEMP, M, mins, reason)
|
||||
if(M.client)
|
||||
M.client.link_forum_account(TRUE)
|
||||
if(config.banappeals)
|
||||
to_chat(M, "<span class='warning'>To try to resolve this matter head to [config.banappeals]</span>")
|
||||
if(GLOB.configuration.url.banappeals_url)
|
||||
to_chat(M, "<span class='warning'>To try to resolve this matter head to [GLOB.configuration.url.banappeals_url]</span>")
|
||||
else
|
||||
to_chat(M, "<span class='warning'>No ban appeals URL has been set.</span>")
|
||||
log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.")
|
||||
@@ -1084,8 +1084,8 @@
|
||||
to_chat(M, "<span class='warning'>This ban does not expire automatically and must be appealed.</span>")
|
||||
if(M.client)
|
||||
M.client.link_forum_account(TRUE)
|
||||
if(config.banappeals)
|
||||
to_chat(M, "<span class='warning'>To try to resolve this matter head to [config.banappeals]</span>")
|
||||
if(GLOB.configuration.url.banappeals_url)
|
||||
to_chat(M, "<span class='warning'>To try to resolve this matter head to [GLOB.configuration.url.banappeals_url]</span>")
|
||||
else
|
||||
to_chat(M, "<span class='warning'>No ban appeals URL has been set.</span>")
|
||||
log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis ban does not expire automatically and must be appealed.")
|
||||
@@ -1132,7 +1132,7 @@
|
||||
|
||||
else if(href_list["watcheditlog"])
|
||||
var/target_ckey = href_list["watcheditlog"]
|
||||
var/datum/db_query/query_watchedits = SSdbcore.NewQuery("SELECT edits FROM [format_table_name("watch")] WHERE ckey=:targetkey", list(
|
||||
var/datum/db_query/query_watchedits = SSdbcore.NewQuery("SELECT edits FROM watch WHERE ckey=:targetkey", list(
|
||||
"targetkey" = target_ckey
|
||||
))
|
||||
if(!query_watchedits.warn_execute())
|
||||
@@ -1163,8 +1163,8 @@
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
var/dat = {"<b>What mode do you wish to play?</b><hr>"}
|
||||
for(var/mode in config.modes)
|
||||
dat += {"<A href='?src=[UID()];c_mode2=[mode]'>[config.mode_names[mode]]</A><br>"}
|
||||
for(var/mode in GLOB.configuration.gamemode.gamemodes)
|
||||
dat += {"<A href='?src=[UID()];c_mode2=[mode]'>[GLOB.configuration.gamemode.gamemode_names[mode]]</A><br>"}
|
||||
dat += {"<A href='?src=[UID()];c_mode2=secret'>Secret</A><br>"}
|
||||
dat += {"<A href='?src=[UID()];c_mode2=random'>Random</A><br>"}
|
||||
dat += {"Now: [GLOB.master_mode]"}
|
||||
@@ -1178,8 +1178,8 @@
|
||||
if(GLOB.master_mode != "secret")
|
||||
return alert(usr, "The game mode has to be secret!", null, null, null, null)
|
||||
var/dat = {"<b>What game mode do you want to force secret to be? Use this if you want to change the game mode, but want the players to believe it's secret. This will only work if the current game mode is secret.</b><hr>"}
|
||||
for(var/mode in config.modes)
|
||||
dat += {"<A href='?src=[UID()];f_secret2=[mode]'>[config.mode_names[mode]]</A><br>"}
|
||||
for(var/mode in GLOB.configuration.gamemode.gamemodes)
|
||||
dat += {"<A href='?src=[UID()];f_secret2=[mode]'>[GLOB.configuration.gamemode.gamemode_names[mode]]</A><br>"}
|
||||
dat += {"<A href='?src=[UID()];f_secret2=secret'>Random (default)</A><br>"}
|
||||
dat += {"Now: [GLOB.secret_force_mode]"}
|
||||
usr << browse(dat, "window=f_secret")
|
||||
@@ -2165,7 +2165,7 @@
|
||||
if(!istype(M))
|
||||
to_chat(usr, "<span class='warning'>This can only be used on instances of type /mob/living</span>")
|
||||
return
|
||||
var/ptypes = list("Lightning bolt", "Fire Death", "Gib")
|
||||
var/ptypes = list("Lightning bolt", "Fire Death", "Gib", "Dust")
|
||||
if(ishuman(M))
|
||||
H = M
|
||||
ptypes += "Brain Damage"
|
||||
@@ -2180,7 +2180,6 @@
|
||||
ptypes += "Crew Traitor"
|
||||
ptypes += "Floor Cluwne"
|
||||
ptypes += "Shamebrero"
|
||||
ptypes += "Dust"
|
||||
var/punishment = input(owner, "How would you like to smite [M]?", "Its good to be baaaad...", "") as null|anything in ptypes
|
||||
if(!(punishment in ptypes))
|
||||
return
|
||||
@@ -2203,6 +2202,9 @@
|
||||
if("Gib")
|
||||
M.gib(FALSE)
|
||||
logmsg = "gibbed."
|
||||
if("Dust")
|
||||
M.dust()
|
||||
logmsg = "dust"
|
||||
|
||||
// These smiting types are only valid for ishuman() mobs
|
||||
if("Brain Damage")
|
||||
@@ -2292,9 +2294,6 @@
|
||||
var/obj/item/clothing/head/sombrero/shamebrero/S = new(H.loc)
|
||||
H.equip_to_slot_or_del(S, slot_head)
|
||||
logmsg = "shamebrero"
|
||||
if("Dust")
|
||||
H.dust()
|
||||
logmsg = "dust"
|
||||
if(logmsg)
|
||||
log_admin("[key_name(owner)] smited [key_name(M)] with: [logmsg]")
|
||||
message_admins("[key_name_admin(owner)] smited [key_name_admin(M)] with: [logmsg]")
|
||||
@@ -2510,7 +2509,7 @@
|
||||
if("Central Command")
|
||||
stamptype = "icon"
|
||||
stampvalue = "cent"
|
||||
sendername = command_name()
|
||||
sendername = "NAS Trurl"
|
||||
if("Syndicate")
|
||||
stamptype = "icon"
|
||||
stampvalue = "syndicate"
|
||||
@@ -2840,7 +2839,7 @@
|
||||
else if(href_list["memoeditlist"])
|
||||
if(!check_rights(R_SERVER)) return
|
||||
var/sql_key = href_list["memoeditlist"]
|
||||
var/datum/db_query/query_memoedits = SSdbcore.NewQuery("SELECT edits FROM [format_table_name("memo")] WHERE (ckey=:sql_key)", list(
|
||||
var/datum/db_query/query_memoedits = SSdbcore.NewQuery("SELECT edits FROM memo WHERE (ckey=:sql_key)", list(
|
||||
"sql_key" = sql_key
|
||||
))
|
||||
if(!query_memoedits.warn_execute())
|
||||
@@ -3008,21 +3007,16 @@
|
||||
if("togglebombcap")
|
||||
SSblackbox.record_feedback("tally", "admin_secrets_fun_used", 1, "Bomb Cap")
|
||||
|
||||
var/newBombCap = input(usr,"What would you like the new bomb cap to be. (entered as the light damage range (the 3rd number in common (1,2,3) notation)) Must be between 4 and 128)", "New Bomb Cap", GLOB.max_ex_light_range) as num|null
|
||||
var/newBombCap = input(usr,"What would you like the new bomb cap to be. (entered as the light damage range (the 3rd number in common (1,2,3) notation)) Must be between 4 and 128)", "New Bomb Cap", GLOB.configuration.general.bomb_cap) as num|null
|
||||
if(newBombCap < 4)
|
||||
return
|
||||
if(newBombCap > 128)
|
||||
newBombCap = 128
|
||||
|
||||
GLOB.max_ex_devastation_range = round(newBombCap/4)
|
||||
GLOB.max_ex_heavy_range = round(newBombCap/2)
|
||||
GLOB.max_ex_light_range = newBombCap
|
||||
//I don't know why these are their own variables, but fuck it, they are.
|
||||
GLOB.max_ex_flash_range = newBombCap
|
||||
GLOB.max_ex_flame_range = newBombCap
|
||||
GLOB.configuration.general.bomb_cap = newBombCap
|
||||
|
||||
message_admins("<span class='boldannounce'>[key_name_admin(usr)] changed the bomb cap to [GLOB.max_ex_devastation_range], [GLOB.max_ex_heavy_range], [GLOB.max_ex_light_range]</span>")
|
||||
log_admin("[key_name(usr)] changed the bomb cap to [GLOB.max_ex_devastation_range], [GLOB.max_ex_heavy_range], [GLOB.max_ex_light_range]")
|
||||
message_admins("<span class='boldannounce'>[key_name_admin(usr)] changed the bomb cap to [GLOB.configuration.general.bomb_cap / 4], [GLOB.configuration.general.bomb_cap / 2], [GLOB.configuration.general.bomb_cap]</span>")
|
||||
log_admin("[key_name(usr)] changed the bomb cap to [GLOB.configuration.general.bomb_cap / 4], [GLOB.configuration.general.bomb_cap / 2], [GLOB.configuration.general.bomb_cap]")
|
||||
|
||||
if("flicklights")
|
||||
SSblackbox.record_feedback("tally", "admin_secrets_fun_used", 1, "Flicker Lights")
|
||||
@@ -3220,6 +3214,12 @@
|
||||
message_admins("[key_name_admin(usr)] moved the centcom ferry")
|
||||
log_admin("[key_name(usr)] moved the centcom ferry")
|
||||
|
||||
if("gammashuttle")
|
||||
SSblackbox.record_feedback("tally", "admin_secrets_fun_used", 1, "Send Gamma Armory")
|
||||
message_admins("[key_name_admin(usr)] moved the gamma armory")
|
||||
log_admin("[key_name(usr)] moved the gamma armory")
|
||||
move_gamma_ship()
|
||||
|
||||
if(usr)
|
||||
log_admin("[key_name(usr)] used secret [href_list["secretsfun"]]")
|
||||
if(ok)
|
||||
@@ -3299,7 +3299,7 @@
|
||||
var/val = alert(usr, "What do you want to set night shift to? This will override the automatic system until set to automatic again.", "Night Shift", "On", "Off", "Automatic")
|
||||
switch(val)
|
||||
if("Automatic")
|
||||
if(config.enable_night_shifts)
|
||||
if(GLOB.configuration.general.enable_night_shifts)
|
||||
SSnightshift.can_fire = TRUE
|
||||
SSnightshift.fire()
|
||||
else
|
||||
@@ -3378,7 +3378,7 @@
|
||||
if(!newname)
|
||||
return
|
||||
G.name = newname
|
||||
var/description = input("Enter [command_name()] message contents:") as message|null
|
||||
var/description = input("Enter NAS Trurl message contents:") as message|null
|
||||
if(!description)
|
||||
return
|
||||
G.report_message = description
|
||||
@@ -3398,7 +3398,7 @@
|
||||
var/isbn = text2num(href_list["library_book_id"])
|
||||
|
||||
if(href_list["view_library_book"])
|
||||
var/datum/db_query/query_view_book = SSdbcore.NewQuery("SELECT content, title FROM [format_table_name("library")] WHERE id=:isbn", list(
|
||||
var/datum/db_query/query_view_book = SSdbcore.NewQuery("SELECT content, title FROM library WHERE id=:isbn", list(
|
||||
"isbn" = isbn
|
||||
))
|
||||
if(!query_view_book.warn_execute())
|
||||
@@ -3425,7 +3425,7 @@
|
||||
return
|
||||
|
||||
else if(href_list["unflag_library_book"])
|
||||
var/datum/db_query/query_unflag_book = SSdbcore.NewQuery("UPDATE [format_table_name("library")] SET flagged = 0 WHERE id=:isbn", list(
|
||||
var/datum/db_query/query_unflag_book = SSdbcore.NewQuery("UPDATE library SET flagged = 0 WHERE id=:isbn", list(
|
||||
"isbn" = isbn
|
||||
))
|
||||
if(!query_unflag_book.warn_execute())
|
||||
@@ -3437,7 +3437,7 @@
|
||||
message_admins("[key_name_admin(usr)] has unflagged the book [isbn].")
|
||||
|
||||
else if(href_list["delete_library_book"])
|
||||
var/datum/db_query/query_delbook = SSdbcore.NewQuery("DELETE FROM [format_table_name("library")] WHERE id=:isbn", list(
|
||||
var/datum/db_query/query_delbook = SSdbcore.NewQuery("DELETE FROM library WHERE id=:isbn", list(
|
||||
"isbn" = isbn
|
||||
))
|
||||
if(!query_delbook.warn_execute())
|
||||
@@ -3505,7 +3505,7 @@
|
||||
var/unlocked_jobs = ""
|
||||
var/unlocked_species = ""
|
||||
// Get their totals
|
||||
var/datum/db_query/query_get_totals = SSdbcore.NewQuery("SELECT karma, karmaspent FROM [format_table_name("karmatotals")] WHERE byondkey=:ckey", list(
|
||||
var/datum/db_query/query_get_totals = SSdbcore.NewQuery("SELECT karma, karmaspent FROM karmatotals WHERE byondkey=:ckey", list(
|
||||
"ckey" = target_ckey
|
||||
))
|
||||
if(!query_get_totals.warn_execute())
|
||||
@@ -3519,7 +3519,7 @@
|
||||
qdel(query_get_totals)
|
||||
|
||||
// Now get their unlocks
|
||||
var/datum/db_query/query_get_unlocks = SSdbcore.NewQuery("SELECT job, species FROM [format_table_name("whitelist")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query_get_unlocks = SSdbcore.NewQuery("SELECT job, species FROM whitelist WHERE ckey=:ckey", list(
|
||||
"ckey" = target_ckey
|
||||
))
|
||||
if(!query_get_unlocks.warn_execute())
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
C.adminhelped = 0
|
||||
|
||||
//AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn
|
||||
if(config.popup_admin_pm)
|
||||
if(GLOB.configuration.general.popup_admin_pm)
|
||||
spawn(0) //so we don't hold the caller proc up
|
||||
var/sender = src
|
||||
var/sendername = key
|
||||
|
||||
@@ -34,7 +34,7 @@ GLOBAL_VAR_INIT(sent_syndicate_infiltration_team, 0)
|
||||
return
|
||||
var/tctext = input(src, "How much TC do you want to give each team member? Suggested: 20-30. They cannot trade TC.") as num
|
||||
var/tcamount = text2num(tctext)
|
||||
tcamount = between(0, tcamount, 1000)
|
||||
tcamount = clamp(tcamount, 0, 1000)
|
||||
if(GLOB.sent_syndicate_infiltration_team == 1)
|
||||
if(alert("A Syndicate Infiltration Team has already been sent. Sure you want to send another?",,"Yes","No")=="No")
|
||||
return
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
/datum/admins/proc/makeTraitors()
|
||||
var/datum/game_mode/traitor/temp = new
|
||||
|
||||
if(config.protect_roles_from_antagonist)
|
||||
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
|
||||
temp.restricted_jobs += temp.protected_jobs
|
||||
|
||||
var/list/mob/living/carbon/human/candidates = list()
|
||||
@@ -76,7 +76,7 @@
|
||||
/datum/admins/proc/makeChangelings()
|
||||
|
||||
var/datum/game_mode/changeling/temp = new
|
||||
if(config.protect_roles_from_antagonist)
|
||||
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
|
||||
temp.restricted_jobs += temp.protected_jobs
|
||||
|
||||
var/list/mob/living/carbon/human/candidates = list()
|
||||
@@ -106,7 +106,7 @@
|
||||
/datum/admins/proc/makeRevs()
|
||||
|
||||
var/datum/game_mode/revolution/temp = new
|
||||
if(config.protect_roles_from_antagonist)
|
||||
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
|
||||
temp.restricted_jobs += temp.protected_jobs
|
||||
|
||||
var/list/mob/living/carbon/human/candidates = list()
|
||||
@@ -156,7 +156,7 @@
|
||||
/datum/admins/proc/makeCult()
|
||||
|
||||
var/datum/game_mode/cult/temp = new
|
||||
if(config.protect_roles_from_antagonist)
|
||||
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
|
||||
temp.restricted_jobs += temp.protected_jobs
|
||||
|
||||
var/list/mob/living/carbon/human/candidates = list()
|
||||
@@ -517,7 +517,7 @@
|
||||
/datum/admins/proc/makeVampires()
|
||||
|
||||
var/datum/game_mode/vampire/temp = new
|
||||
if(config.protect_roles_from_antagonist)
|
||||
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
|
||||
temp.restricted_jobs += temp.protected_jobs
|
||||
|
||||
var/list/mob/living/carbon/human/candidates = list()
|
||||
@@ -527,8 +527,8 @@
|
||||
if(!antnum || antnum <= 0)
|
||||
return
|
||||
|
||||
log_admin("[key_name(owner)] tried making Vampires with One-Click-Antag")
|
||||
message_admins("[key_name_admin(owner)] tried making Vampires with One-Click-Antag")
|
||||
log_admin("[key_name(owner)] tried making [antnum] Vampires with One-Click-Antag")
|
||||
message_admins("[key_name_admin(owner)] tried making [antnum] Vampires with One-Click-Antag")
|
||||
|
||||
for(var/mob/living/carbon/human/applicant in GLOB.player_list)
|
||||
if(CandCheck(ROLE_VAMPIRE, applicant, temp))
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
return
|
||||
|
||||
if(istype(O,/obj/singularity))
|
||||
if(config.forbid_singulo_possession)
|
||||
if(GLOB.configuration.general.forbid_singulo_possession) // I love how this needs to exist
|
||||
to_chat(usr, "It is forbidden to possess singularities.")
|
||||
return
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
|
||||
/proc/cmd_admin_mute(mob/M as mob, mute_type, automute = 0)
|
||||
if(automute)
|
||||
if(!config.automute_on)
|
||||
if(!GLOB.configuration.general.enable_auto_mute)
|
||||
return
|
||||
else
|
||||
if(!usr || !usr.client)
|
||||
@@ -276,21 +276,21 @@
|
||||
return
|
||||
|
||||
var/action=""
|
||||
if(config.antag_hud_allowed)
|
||||
if(GLOB.configuration.general.allow_antag_hud)
|
||||
for(var/mob/dead/observer/g in get_ghosts())
|
||||
if(g.antagHUD)
|
||||
g.antagHUD = FALSE // Disable it on those that have it enabled
|
||||
g.has_enabled_antagHUD = FALSE // We'll allow them to respawn
|
||||
to_chat(g, "<span class='danger'>The Administrator has disabled AntagHUD </span>")
|
||||
config.antag_hud_allowed = 0
|
||||
to_chat(g, "<span class='danger'>The Administrators have disabled AntagHUD </span>")
|
||||
GLOB.configuration.general.allow_antag_hud = FALSE
|
||||
to_chat(src, "<span class='danger'>AntagHUD usage has been disabled</span>")
|
||||
action = "disabled"
|
||||
else
|
||||
for(var/mob/dead/observer/g in get_ghosts())
|
||||
if(!g.client.holder) // Add the verb back for all non-admin ghosts
|
||||
to_chat(g, "<span class='boldnotice'>The Administrator has enabled AntagHUD </span>")// Notify all observers they can now use AntagHUD
|
||||
to_chat(g, "<span class='boldnotice'>The Administrators have enabled AntagHUD </span>")// Notify all observers they can now use AntagHUD
|
||||
|
||||
config.antag_hud_allowed = 1
|
||||
GLOB.configuration.general.allow_antag_hud = TRUE
|
||||
action = "enabled"
|
||||
to_chat(src, "<span class='boldnotice'>AntagHUD usage has been enabled</span>")
|
||||
|
||||
@@ -307,11 +307,11 @@
|
||||
return
|
||||
|
||||
var/action=""
|
||||
if(config.antag_hud_restricted)
|
||||
if(GLOB.configuration.general.restrict_antag_hud_rejoin)
|
||||
for(var/mob/dead/observer/g in get_ghosts())
|
||||
to_chat(g, "<span class='boldnotice'>The administrator has lifted restrictions on joining the round if you use AntagHUD</span>")
|
||||
action = "lifted restrictions"
|
||||
config.antag_hud_restricted = 0
|
||||
GLOB.configuration.general.restrict_antag_hud_rejoin = FALSE
|
||||
to_chat(src, "<span class='boldnotice'>AntagHUD restrictions have been lifted</span>")
|
||||
else
|
||||
for(var/mob/dead/observer/g in get_ghosts())
|
||||
@@ -320,7 +320,7 @@
|
||||
g.antagHUD = FALSE
|
||||
g.has_enabled_antagHUD = FALSE
|
||||
action = "placed restrictions"
|
||||
config.antag_hud_restricted = 1
|
||||
GLOB.configuration.general.restrict_antag_hud_rejoin = TRUE
|
||||
to_chat(src, "<span class='danger'>AntagHUD restrictions have been enabled</span>")
|
||||
|
||||
log_admin("[key_name(usr)] has [action] on joining the round if they use AntagHUD")
|
||||
@@ -941,14 +941,14 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
if(!check_rights(R_SERVER|R_EVENT))
|
||||
return
|
||||
|
||||
if(!config.allow_random_events)
|
||||
config.allow_random_events = 1
|
||||
if(!GLOB.configuration.event.enable_random_events)
|
||||
GLOB.configuration.event.enable_random_events = TRUE
|
||||
to_chat(usr, "Random events enabled")
|
||||
message_admins("Admin [key_name_admin(usr)] has enabled random events.", 1)
|
||||
message_admins("Admin [key_name_admin(usr)] has enabled random events.")
|
||||
else
|
||||
config.allow_random_events = 0
|
||||
GLOB.configuration.event.enable_random_events = FALSE
|
||||
to_chat(usr, "Random events disabled")
|
||||
message_admins("Admin [key_name_admin(usr)] has disabled random events.", 1)
|
||||
message_admins("Admin [key_name_admin(usr)] has disabled random events.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Random Events") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/reset_all_tcs()
|
||||
@@ -1031,7 +1031,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
if(H.client == null || H.stat == DEAD) // No clientless or dead
|
||||
continue
|
||||
mins_afk = round(H.client.inactivity / 600)
|
||||
if(mins_afk < config.list_afk_minimum)
|
||||
if(mins_afk < 5)
|
||||
continue
|
||||
if(H.job)
|
||||
job_string = H.job
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
var/new_ckey = ckey(clean_input("Who would you like to add to the watchlist?","Enter a ckey",null))
|
||||
if(!new_ckey)
|
||||
return
|
||||
var/datum/db_query/query_watchfind = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ckey=:new_ckey", list(
|
||||
var/datum/db_query/query_watchfind = SSdbcore.NewQuery("SELECT ckey FROM player WHERE ckey=:new_ckey", list(
|
||||
"new_ckey" = new_ckey
|
||||
))
|
||||
if(!query_watchfind.warn_execute())
|
||||
@@ -27,7 +27,7 @@
|
||||
if(!adminckey)
|
||||
return
|
||||
var/datum/db_query/query_watchadd = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("watch")] (ckey, reason, adminckey, timestamp)
|
||||
INSERT INTO watch (ckey, reason, adminckey, timestamp)
|
||||
VALUES (:targetkey, :reason, :adminkey, NOW())"},
|
||||
list(
|
||||
"targetkey" = target_ckey,
|
||||
@@ -50,7 +50,7 @@
|
||||
/client/proc/watchlist_remove(target_ckey, browse = 0)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/datum/db_query/query_watchdel = SSdbcore.NewQuery("DELETE FROM [format_table_name("watch")] WHERE ckey=:target_ckey", list(
|
||||
var/datum/db_query/query_watchdel = SSdbcore.NewQuery("DELETE FROM watch WHERE ckey=:target_ckey", list(
|
||||
"target_ckey" = target_ckey
|
||||
))
|
||||
if(!query_watchdel.warn_execute())
|
||||
@@ -68,7 +68,7 @@
|
||||
/client/proc/watchlist_edit(target_ckey, browse = 0)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/datum/db_query/query_watchreason = SSdbcore.NewQuery("SELECT reason FROM [format_table_name("watch")] WHERE ckey=:target_ckey", list(
|
||||
var/datum/db_query/query_watchreason = SSdbcore.NewQuery("SELECT reason FROM watch WHERE ckey=:target_ckey", list(
|
||||
"target_ckey" = target_ckey
|
||||
))
|
||||
if(!query_watchreason.warn_execute())
|
||||
@@ -82,7 +82,7 @@
|
||||
var/sql_ckey = usr.ckey
|
||||
var/edit_text = "Edited by [sql_ckey] on [SQLtime()] from \"[watch_reason]\" to \"[new_reason]\""
|
||||
|
||||
var/datum/db_query/query_watchupdate = SSdbcore.NewQuery("UPDATE [format_table_name("watch")] SET reason=:new_reason, last_editor=:sql_ckey, edits = CONCAT(IFNULL(edits,''), :edit_text) WHERE ckey=:target_ckey", list(
|
||||
var/datum/db_query/query_watchupdate = SSdbcore.NewQuery("UPDATE watch SET reason=:new_reason, last_editor=:sql_ckey, edits = CONCAT(IFNULL(edits,''), :edit_text) WHERE ckey=:target_ckey", list(
|
||||
"new_reason" = new_reason,
|
||||
"sql_ckey" = sql_ckey,
|
||||
"edit_text" = edit_text,
|
||||
@@ -114,7 +114,7 @@
|
||||
else
|
||||
search = "^."
|
||||
|
||||
var/datum/db_query/query_watchlist = SSdbcore.NewQuery("SELECT ckey, reason, adminckey, timestamp, last_editor FROM [format_table_name("watch")] WHERE ckey REGEXP :search ORDER BY ckey", list(
|
||||
var/datum/db_query/query_watchlist = SSdbcore.NewQuery("SELECT ckey, reason, adminckey, timestamp, last_editor FROM watch WHERE ckey REGEXP :search ORDER BY ckey", list(
|
||||
"search" = search
|
||||
))
|
||||
if(!query_watchlist.warn_execute())
|
||||
@@ -134,7 +134,7 @@
|
||||
qdel(query_watchlist)
|
||||
|
||||
/proc/check_watchlist(target_ckey)
|
||||
var/datum/db_query/query_watch = SSdbcore.NewQuery("SELECT reason FROM [format_table_name("watch")] WHERE ckey=:target_ckey", list(
|
||||
var/datum/db_query/query_watch = SSdbcore.NewQuery("SELECT reason FROM watch WHERE ckey=:target_ckey", list(
|
||||
"target_ckey" = target_ckey
|
||||
))
|
||||
if(!query_watch.warn_execute())
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
|
||||
|
||||
var/objective_amount = config.traitor_objectives_amount
|
||||
var/objective_amount = GLOB.configuration.gamemode.traitor_objectives_amount
|
||||
|
||||
if(is_hijacker && objective_count <= objective_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
|
||||
if (!(locate(/datum/objective/hijack) in objectives))
|
||||
@@ -154,7 +154,7 @@
|
||||
|
||||
objective_count += forge_single_objective()
|
||||
|
||||
for(var/i = objective_count, i < config.traitor_objectives_amount)
|
||||
for(var/i = objective_count, i < GLOB.configuration.gamemode.traitor_objectives_amount)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
@@ -248,7 +248,7 @@
|
||||
owner.announce_objectives()
|
||||
if(should_give_codewords)
|
||||
give_codewords()
|
||||
to_chat(owner.current, "<span class='motd'>For more information, check the wiki page: ([config.wikiurl]/index.php/Traitor)</span>")
|
||||
to_chat(owner.current, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Traitor)</span>")
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/update_traitor_icons_added(datum/mind/traitor_mind)
|
||||
|
||||
@@ -228,7 +228,12 @@
|
||||
for(var/mob/living/L in T)
|
||||
L.adjust_fire_stacks(3)
|
||||
L.IgniteMob()
|
||||
L.bodytemperature = max(temp / 3, L.bodytemperature)
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/M = L
|
||||
var/heatBlockPercent = 1 - M.get_heat_protection(temp)
|
||||
M.bodytemperature += (temp - M.bodytemperature) * heatBlockPercent / 3
|
||||
else
|
||||
L.bodytemperature = (2 * L.bodytemperature + temp) / 3
|
||||
|
||||
/proc/fireflash_s(atom/center, radius, temp, falloff)
|
||||
if(temp < T0C + 60)
|
||||
@@ -291,7 +296,12 @@
|
||||
for(var/mob/living/L in T)
|
||||
L.adjust_fire_stacks(3)
|
||||
L.IgniteMob()
|
||||
L.bodytemperature = (2 * L.bodytemperature + temp) / 3
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/M = L
|
||||
var/heatBlockPercent = 1 - M.get_heat_protection(temp)
|
||||
M.bodytemperature += (temp - M.bodytemperature) * heatBlockPercent / 3
|
||||
else
|
||||
L.bodytemperature = (2 * L.bodytemperature + temp) / 3
|
||||
|
||||
if(T.density)
|
||||
continue
|
||||
|
||||
@@ -112,6 +112,7 @@
|
||||
|
||||
var/target_temperature = T20C
|
||||
var/regulating_temperature = 0
|
||||
var/thermostat_state = FALSE
|
||||
|
||||
var/list/TLV = list()
|
||||
|
||||
@@ -329,8 +330,8 @@
|
||||
var/datum/gas_mixture/gas = location.remove_air(0.25 * environment.total_moles())
|
||||
if(!gas)
|
||||
return
|
||||
if(!regulating_temperature)
|
||||
regulating_temperature = 1
|
||||
if(!regulating_temperature && thermostat_state == TRUE)
|
||||
regulating_temperature = TRUE
|
||||
visible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.", "You hear a click and a faint electronic hum.")
|
||||
|
||||
if(target_temperature > MAX_TEMPERATURE)
|
||||
@@ -339,25 +340,26 @@
|
||||
if(target_temperature < MIN_TEMPERATURE)
|
||||
target_temperature = MIN_TEMPERATURE
|
||||
|
||||
var/heat_capacity = gas.heat_capacity()
|
||||
var/energy_used = max(abs(heat_capacity * (gas.temperature - target_temperature) ), MAX_ENERGY_CHANGE)
|
||||
if(thermostat_state == TRUE)
|
||||
var/heat_capacity = gas.heat_capacity()
|
||||
var/energy_used = max(abs(heat_capacity * (gas.temperature - target_temperature) ), MAX_ENERGY_CHANGE)
|
||||
|
||||
//Use power. Assuming that each power unit represents 1000 watts....
|
||||
use_power(energy_used/1000, ENVIRON)
|
||||
//Use power. Assuming that each power unit represents 1000 watts....
|
||||
use_power(energy_used / 1000, ENVIRON)
|
||||
|
||||
//We need to cool ourselves.
|
||||
if(heat_capacity)
|
||||
if(environment.temperature > target_temperature)
|
||||
gas.temperature -= energy_used / heat_capacity
|
||||
else
|
||||
gas.temperature += energy_used / heat_capacity
|
||||
//We need to cool ourselves.
|
||||
if(heat_capacity)
|
||||
if(environment.temperature > target_temperature)
|
||||
gas.temperature -= energy_used / heat_capacity
|
||||
else
|
||||
gas.temperature += energy_used / heat_capacity
|
||||
|
||||
if(abs(environment.temperature - target_temperature) <= 0.5)
|
||||
regulating_temperature = FALSE
|
||||
visible_message("[src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.", "You hear a click as a faint electronic humming stops.")
|
||||
|
||||
environment.merge(gas)
|
||||
|
||||
if(abs(environment.temperature - target_temperature) <= 0.5)
|
||||
regulating_temperature = 0
|
||||
visible_message("\The [src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.", "You hear a click as a faint electronic humming stops.")
|
||||
|
||||
/obj/machinery/alarm/update_icon()
|
||||
if(wiresexposed)
|
||||
icon_state = "alarmx"
|
||||
@@ -642,6 +644,7 @@
|
||||
data["pressure"] = environment_pressure
|
||||
data["temperature"] = environment.temperature
|
||||
data["temperature_c"] = round(environment.temperature - T0C, 0.1)
|
||||
data["thermostat_state"] = thermostat_state
|
||||
|
||||
var/list/percentages = list()
|
||||
percentages["oxygen"] = oxygen_percent
|
||||
@@ -931,6 +934,8 @@
|
||||
else
|
||||
target_temperature = input_temperature
|
||||
|
||||
if("thermostat_state")
|
||||
thermostat_state = !thermostat_state
|
||||
|
||||
/obj/machinery/alarm/emag_act(mob/user)
|
||||
if(!emagged)
|
||||
|
||||
@@ -20,7 +20,10 @@ Pipelines + Other Objects -> Pipe network
|
||||
on_blueprints = TRUE
|
||||
var/nodealert = 0
|
||||
var/can_unwrench = 0
|
||||
|
||||
/// If the machine is currently operating or not.
|
||||
var/on = FALSE
|
||||
/// The amount of pressure the machine wants to operate at.
|
||||
var/target_pressure = 0
|
||||
var/connect_types[] = list(1) //1=regular, 2=supply, 3=scrubber
|
||||
var/connected_to = 1 //same as above, currently not used for anything
|
||||
var/icon_connect_type = "" //"-supply" or "-scrubbers"
|
||||
@@ -373,3 +376,35 @@ Pipelines + Other Objects -> Pipe network
|
||||
//Used for certain children of obj/machinery/atmospherics to not show pipe vision when mob is inside it.
|
||||
/obj/machinery/atmospherics/proc/can_see_pipes()
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Turns the machine either on, or off. If this is done by a user, display a message to them.
|
||||
*
|
||||
* NOTE: Only applies to atmospherics machines which can be toggled on or off, such as pumps, or other devices.
|
||||
*
|
||||
* Arguments:
|
||||
* * user - the mob who is toggling the machine.
|
||||
*/
|
||||
/obj/machinery/atmospherics/proc/toggle(mob/living/user)
|
||||
if(!powered())
|
||||
return
|
||||
on = !on
|
||||
update_icon()
|
||||
if(user)
|
||||
to_chat(user, "<span class='notice'>You toggle [src] [on ? "on" : "off"].</span>")
|
||||
|
||||
/**
|
||||
* Maxes the output pressure of the machine. If this is done by a user, display a message to them.
|
||||
*
|
||||
* NOTE: Only applies to atmospherics machines which allow a `target_pressure` to be set, such as pumps, or other devices.
|
||||
*
|
||||
* Arguments:
|
||||
* * user - the mob who is setting the output pressure to maximum.
|
||||
*/
|
||||
/obj/machinery/atmospherics/proc/set_max(mob/living/user)
|
||||
if(!powered())
|
||||
return
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
update_icon()
|
||||
if(user)
|
||||
to_chat(user, "<span class='notice'>You set the target pressure of [src] to maximum.</span>")
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
can_unwrench = 1
|
||||
var/side_inverted = 0
|
||||
|
||||
/obj/machinery/atmospherics/binary/circulator/detailed_examine()
|
||||
return "This generates electricity, depending on the difference in temperature between each side of the machine. The meter in \
|
||||
the center of the machine gives an indicator of how much electricity is being generated."
|
||||
|
||||
// Creating a custom circulator pipe subtype to be delivered through cargo
|
||||
/obj/item/pipe/circulator
|
||||
name = "circulator/heat exchanger fitting"
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
connect_types = list(1,2,3) //connects to regular, supply and scrubbers pipes
|
||||
|
||||
var/on = 0
|
||||
var/pump_direction = 1 //0 = siphoning, 1 = releasing
|
||||
|
||||
var/external_pressure_bound = ONE_ATMOSPHERE
|
||||
@@ -206,23 +205,23 @@
|
||||
pump_direction = 1
|
||||
|
||||
if(signal.data["set_input_pressure"] != null)
|
||||
input_pressure_min = between(
|
||||
0,
|
||||
input_pressure_min = clamp(
|
||||
text2num(signal.data["set_input_pressure"]),
|
||||
0,
|
||||
ONE_ATMOSPHERE*50
|
||||
)
|
||||
|
||||
if(signal.data["set_output_pressure"] != null)
|
||||
output_pressure_max = between(
|
||||
0,
|
||||
output_pressure_max = clamp(
|
||||
text2num(signal.data["set_output_pressure"]),
|
||||
0,
|
||||
ONE_ATMOSPHERE*50
|
||||
)
|
||||
|
||||
if(signal.data["set_external_pressure"] != null)
|
||||
external_pressure_bound = between(
|
||||
0,
|
||||
external_pressure_bound = clamp(
|
||||
text2num(signal.data["set_external_pressure"]),
|
||||
0,
|
||||
ONE_ATMOSPHERE*50
|
||||
)
|
||||
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
|
||||
can_unwrench = 1
|
||||
|
||||
var/on = 0
|
||||
var/target_pressure = ONE_ATMOSPHERE
|
||||
target_pressure = ONE_ATMOSPHERE
|
||||
|
||||
var/id = null
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/detailed_examine()
|
||||
return "This is a one-way regulator, allowing gas to flow only at a specific pressure and flow rate. If the light is green, it is flowing."
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/atmos_init()
|
||||
..()
|
||||
if(frequency)
|
||||
@@ -100,9 +102,9 @@
|
||||
on = !on
|
||||
|
||||
if("set_output_pressure" in signal.data)
|
||||
target_pressure = between(
|
||||
0,
|
||||
target_pressure = clamp(
|
||||
text2num(signal.data["set_output_pressure"]),
|
||||
0,
|
||||
ONE_ATMOSPHERE*50
|
||||
)
|
||||
|
||||
@@ -171,11 +173,6 @@
|
||||
if(.)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/proc/toggle()
|
||||
if(powered())
|
||||
on = !on
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/attackby(obj/item/W, mob/user, params)
|
||||
if(!istype(W, /obj/item/wrench))
|
||||
return ..()
|
||||
|
||||
@@ -21,50 +21,31 @@ Thus, the two variables affect pump operation are set in New():
|
||||
|
||||
can_unwrench = 1
|
||||
|
||||
var/on = 0
|
||||
var/target_pressure = ONE_ATMOSPHERE
|
||||
target_pressure = ONE_ATMOSPHERE
|
||||
|
||||
var/id = null
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/detailed_examine()
|
||||
return "This moves gas from one pipe to another. A higher target pressure demands more energy. The side with the red end is the output."
|
||||
|
||||
// So we can CtrlClick without triggering the anchored message.
|
||||
/obj/machinery/atmospherics/binary/pump/can_be_pulled(user, grab_state, force, show_message)
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/CtrlClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(!in_range(src, user) && !issilicon(usr))
|
||||
return
|
||||
if(!ishuman(usr) && !issilicon(usr))
|
||||
return
|
||||
toggle()
|
||||
if(can_use_shortcut(user))
|
||||
toggle(user)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/AICtrlClick()
|
||||
toggle()
|
||||
return ..()
|
||||
/obj/machinery/atmospherics/binary/pump/AICtrlClick(mob/living/silicon/user)
|
||||
toggle(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/AltClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(!in_range(src, user) && !issilicon(usr))
|
||||
return
|
||||
if(!ishuman(usr) && !issilicon(usr))
|
||||
return
|
||||
set_max()
|
||||
return
|
||||
if(can_use_shortcut(user))
|
||||
set_max(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/AIAltClick()
|
||||
set_max()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/proc/toggle()
|
||||
if(powered())
|
||||
on = !on
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/proc/set_max()
|
||||
if(powered())
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
update_icon()
|
||||
/obj/machinery/atmospherics/binary/pump/AIAltClick(mob/living/silicon/user)
|
||||
set_max(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/Destroy()
|
||||
if(SSradio)
|
||||
@@ -155,9 +136,9 @@ Thus, the two variables affect pump operation are set in New():
|
||||
on = !on
|
||||
|
||||
if(signal.data["set_output_pressure"])
|
||||
target_pressure = between(
|
||||
0,
|
||||
target_pressure = clamp(
|
||||
text2num(signal.data["set_output_pressure"]),
|
||||
0,
|
||||
ONE_ATMOSPHERE*50
|
||||
)
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
req_one_access_txt = "24;10"
|
||||
|
||||
/obj/machinery/atmospherics/binary/valve/detailed_examine()
|
||||
return "Click this to turn the valve. If red, the pipes on each end are separated. Otherwise, they are connected."
|
||||
|
||||
/obj/machinery/atmospherics/binary/valve/open
|
||||
open = 1
|
||||
icon_state = "map_valve1"
|
||||
|
||||
@@ -21,50 +21,28 @@ Thus, the two variables affect pump operation are set in New():
|
||||
|
||||
can_unwrench = 1
|
||||
|
||||
var/on = 0
|
||||
var/transfer_rate = 200
|
||||
|
||||
var/id = null
|
||||
|
||||
// So we can CtrlClick without triggering the anchored message.
|
||||
/obj/machinery/atmospherics/binary/volume_pump/can_be_pulled(user, grab_state, force, show_message)
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/CtrlClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(!in_range(src, user) && !issilicon(usr))
|
||||
return
|
||||
if(!ishuman(usr) && !issilicon(usr))
|
||||
return
|
||||
toggle()
|
||||
if(can_use_shortcut(user))
|
||||
toggle(user)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/AICtrlClick()
|
||||
toggle()
|
||||
return ..()
|
||||
/obj/machinery/atmospherics/binary/volume_pump/AICtrlClick(mob/living/silicon/user)
|
||||
toggle(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/AltClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(!in_range(src, user) && !issilicon(usr))
|
||||
return
|
||||
if(!ishuman(usr) && !issilicon(usr))
|
||||
return
|
||||
set_max()
|
||||
return
|
||||
if(can_use_shortcut(user))
|
||||
set_max(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/AIAltClick()
|
||||
set_max()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/proc/toggle()
|
||||
if(powered())
|
||||
on = !on
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/proc/set_max()
|
||||
if(powered())
|
||||
transfer_rate = MAX_TRANSFER_RATE
|
||||
update_icon()
|
||||
/obj/machinery/atmospherics/binary/volume_pump/AIAltClick(mob/living/silicon/user)
|
||||
set_max(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/Destroy()
|
||||
if(SSradio)
|
||||
@@ -153,9 +131,9 @@ Thus, the two variables affect pump operation are set in New():
|
||||
on = !on
|
||||
|
||||
if(signal.data["set_transfer_rate"])
|
||||
transfer_rate = between(
|
||||
0,
|
||||
transfer_rate = clamp(
|
||||
text2num(signal.data["set_transfer_rate"]),
|
||||
0,
|
||||
air1.volume
|
||||
)
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
icon = 'icons/atmos/filter.dmi'
|
||||
icon_state = "map"
|
||||
can_unwrench = TRUE
|
||||
/// The amount of pressure the filter wants to operate at.
|
||||
var/target_pressure = ONE_ATMOSPHERE
|
||||
|
||||
target_pressure = ONE_ATMOSPHERE
|
||||
/// The type of gas we want to filter. Valid values that go here are from the `FILTER` defines at the top of the file.
|
||||
var/filter_type = FILTER_TOXINS
|
||||
/// A list of available filter options. Used with `ui_data`.
|
||||
@@ -31,45 +31,24 @@
|
||||
"N2O" = FILTER_N2O
|
||||
)
|
||||
|
||||
// So we can CtrlClick without triggering the anchored message.
|
||||
/obj/machinery/atmospherics/trinary/filter/can_be_pulled(user, grab_state, force, show_message)
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/CtrlClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(!in_range(src, user) && !issilicon(usr))
|
||||
return
|
||||
if(!ishuman(usr) && !issilicon(usr))
|
||||
return
|
||||
toggle()
|
||||
if(can_use_shortcut(user))
|
||||
toggle(user)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/AICtrlClick()
|
||||
toggle()
|
||||
return ..()
|
||||
/obj/machinery/atmospherics/trinary/filter/AICtrlClick(mob/living/silicon/user)
|
||||
toggle(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/AltClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(!in_range(src, user) && !issilicon(usr))
|
||||
return
|
||||
if(!ishuman(usr) && !issilicon(usr))
|
||||
return
|
||||
set_max()
|
||||
return
|
||||
if(can_use_shortcut(user))
|
||||
set_max(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/AIAltClick()
|
||||
set_max()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/proc/toggle()
|
||||
if(powered())
|
||||
on = !on
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/proc/set_max()
|
||||
if(powered())
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
update_icon()
|
||||
/obj/machinery/atmospherics/trinary/filter/AIAltClick(mob/living/silicon/user)
|
||||
set_max(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/Destroy()
|
||||
if(SSradio)
|
||||
|
||||
@@ -6,56 +6,35 @@
|
||||
|
||||
name = "gas mixer"
|
||||
|
||||
var/target_pressure = ONE_ATMOSPHERE
|
||||
target_pressure = ONE_ATMOSPHERE
|
||||
var/node1_concentration = 0.5
|
||||
var/node2_concentration = 0.5
|
||||
|
||||
//node 3 is the outlet, nodes 1 & 2 are intakes
|
||||
|
||||
// So we can CtrlClick without triggering the anchored message.
|
||||
/obj/machinery/atmospherics/trinary/mixer/can_be_pulled(user, grab_state, force, show_message)
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/CtrlClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(!in_range(src, user) && !issilicon(usr))
|
||||
return
|
||||
if(!ishuman(usr) && !issilicon(usr))
|
||||
return
|
||||
toggle()
|
||||
if(can_use_shortcut(user))
|
||||
toggle(user)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/AICtrlClick()
|
||||
toggle()
|
||||
return ..()
|
||||
/obj/machinery/atmospherics/trinary/mixer/AICtrlClick(mob/living/silicon/user)
|
||||
toggle(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/AltClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(!in_range(src, user) && !issilicon(usr))
|
||||
return
|
||||
if(!ishuman(usr) && !issilicon(usr))
|
||||
return
|
||||
set_max()
|
||||
return
|
||||
if(can_use_shortcut(user))
|
||||
set_max(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/AIAltClick()
|
||||
set_max()
|
||||
return ..()
|
||||
/obj/machinery/atmospherics/trinary/mixer/AIAltClick(mob/living/silicon/user)
|
||||
set_max(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/flipped
|
||||
icon_state = "mmap"
|
||||
flipped = 1
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/proc/toggle()
|
||||
if(powered())
|
||||
on = !on
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/proc/set_max()
|
||||
if(powered())
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/update_icon(safety = 0)
|
||||
..()
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
initialize_directions = SOUTH|NORTH|WEST
|
||||
use_power = IDLE_POWER_USE
|
||||
|
||||
var/on = 0
|
||||
layer = GAS_FILTER_LAYER
|
||||
|
||||
var/datum/gas_mixture/air1
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
var/state = TVALVE_STATE_STRAIGHT
|
||||
|
||||
/obj/machinery/atmospherics/trinary/tvalve/detailed_examine()
|
||||
return "Click this to toggle the mode. The direction with the green light is where the gas will flow."
|
||||
|
||||
/obj/machinery/atmospherics/trinary/tvalve/bypass
|
||||
icon_state = "map_tvalve1"
|
||||
state = TVALVE_STATE_SIDE
|
||||
|
||||
@@ -13,12 +13,11 @@
|
||||
interact_offline = 1
|
||||
max_integrity = 350
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 30, "acid" = 30)
|
||||
var/on = FALSE
|
||||
var/temperature_archived
|
||||
var/mob/living/carbon/occupant = null
|
||||
var/obj/item/reagent_containers/glass/beaker = null
|
||||
/// Holds two bitflags, AUTO_EJECT_DEAD and AUTO_EJECT_HEALTHY. Used to determine if the cryo cell will auto-eject dead and/or completely health patients.
|
||||
var/auto_eject_prefs = NONE
|
||||
/// Holds two bitflags, AUTO_EJECT_DEAD and AUTO_EJECT_HEALTHY. Used to determine if the cryo cell will auto-eject dead and/or completely healthy patients.
|
||||
var/auto_eject_prefs = AUTO_EJECT_HEALTHY | AUTO_EJECT_DEAD
|
||||
|
||||
var/next_trans = 0
|
||||
var/current_heat_capacity = 50
|
||||
@@ -28,6 +27,23 @@
|
||||
|
||||
light_color = LIGHT_COLOR_WHITE
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/detailed_examine()
|
||||
return "The cryogenic chamber, or 'cryo', treats most damage types, most notably genetic damage. It also stabilizes patients \
|
||||
in critical condition by placing them in stasis, so they can be treated at a later time.<br>\
|
||||
<br>\
|
||||
In order for it to work, it must be loaded with chemicals, and the temperature of the solution must reach a certain point. Additionally, it \
|
||||
requires a supply of pure oxygen, provided by canisters that are attached. The most commonly used chemicals in the chambers is Cryoxadone, which \
|
||||
heals most damage types including genetic damage.<br>\
|
||||
<br>\
|
||||
Activating the freezer nearby, and setting it to a temperature setting below 150, is recommended before operation! Further, any clothing the patient \
|
||||
is wearing that act as an insulator will reduce its effectiveness, and should be removed.<br>\
|
||||
<br>\
|
||||
Clicking the tube with a beaker full of chemicals in hand will place it in its storage to distribute when it is activated.<br>\
|
||||
<br>\
|
||||
Click your target with Grab intent, then click on the tube, with an empty hand, to place them in it. Click the tube again to open the menu. \
|
||||
Press the button on the menu to activate it. Once they have reached 100 health, right-click the cell and click 'Eject Occupant' to remove them. \
|
||||
Remember to turn it off, once you've finished, to save power and chemicals!"
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/power_change()
|
||||
..()
|
||||
if(!(stat & (BROKEN|NOPOWER)))
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
req_one_access_txt = "24;10"
|
||||
|
||||
var/on = 0
|
||||
var/injecting = 0
|
||||
|
||||
var/volume_rate = 50
|
||||
@@ -30,6 +29,10 @@
|
||||
if(id && !id_tag)//I'm not dealing with any more merge conflicts
|
||||
id_tag = id
|
||||
|
||||
/obj/machinery/atmospherics/unary/outlet_injector/detailed_examine()
|
||||
return "Outputs the pipe's gas into the atmosphere, similar to an air vent. It can be controlled by a nearby atmospherics computer. \
|
||||
A green light on it means it is on."
|
||||
|
||||
/obj/machinery/atmospherics/unary/outlet_injector/Destroy()
|
||||
if(SSradio)
|
||||
SSradio.remove_object(src, frequency)
|
||||
@@ -135,7 +138,7 @@
|
||||
|
||||
if(signal.data["set_volume_rate"] != null)
|
||||
var/number = text2num(signal.data["set_volume_rate"])
|
||||
volume_rate = between(0, number, air_contents.volume)
|
||||
volume_rate = clamp(number, 0, air_contents.volume)
|
||||
|
||||
if(signal.data["status"])
|
||||
broadcast_status()
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
dir = SOUTH
|
||||
initialize_directions = SOUTH
|
||||
|
||||
var/on = 0
|
||||
|
||||
var/oxygen_content = 10
|
||||
|
||||
/obj/machinery/atmospherics/unary/oxygen_generator/update_icon()
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
if(!node)
|
||||
return 0
|
||||
|
||||
var/turf/T = loc
|
||||
if(T.density) //No, you should not be able to get free air from walls
|
||||
return
|
||||
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
|
||||
var/pressure_delta = air_contents.return_pressure() - environment.return_pressure()
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
var/obj/machinery/portable_atmospherics/connected_device
|
||||
|
||||
var/on = 0
|
||||
|
||||
/obj/machinery/atmospherics/unary/portables_connector/Destroy()
|
||||
if(connected_device)
|
||||
connected_device.disconnect()
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 30)
|
||||
layer = OBJ_LAYER
|
||||
|
||||
///Check if the device should be on or off
|
||||
var/on = FALSE
|
||||
|
||||
var/icon_state_off = "freezer"
|
||||
var/icon_state_on = "freezer_1"
|
||||
var/icon_state_open = "freezer-o"
|
||||
@@ -40,6 +37,11 @@
|
||||
RefreshParts()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/unary/thermomachine/detailed_examine()
|
||||
return "Cools or heats the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \
|
||||
It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \
|
||||
screwdriver, and then using a crowbar."
|
||||
|
||||
/obj/machinery/atmospherics/unary/thermomachine/proc/swap_function()
|
||||
cooling = !cooling
|
||||
if(cooling)
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
req_one_access_txt = "24;10"
|
||||
|
||||
var/on = 0
|
||||
var/pump_direction = 1 //0 = siphoning, 1 = releasing
|
||||
|
||||
var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
|
||||
@@ -47,6 +46,9 @@
|
||||
|
||||
connect_types = list(1,2) //connects to regular and supply pipes
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_pump/detailed_examine()
|
||||
return "This pumps the contents of the attached pipe out into the atmosphere, if needed. It can be controlled from an Air Alarm."
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_pump/on
|
||||
on = 1
|
||||
icon_state = "map_vent_out"
|
||||
@@ -128,6 +130,9 @@
|
||||
..()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return FALSE
|
||||
var/turf/T = loc
|
||||
if(T.density) //No, you should not be able to get free air from walls
|
||||
return
|
||||
if(!node)
|
||||
on = FALSE
|
||||
//broadcast_status() // from now air alarm/control computer should request update purposely --rastaf0
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
var/list/turf/simulated/adjacent_turfs = list()
|
||||
|
||||
var/on = 0
|
||||
var/scrubbing = 1 //0 = siphoning, 1 = scrubbing
|
||||
var/scrub_O2 = 0
|
||||
var/scrub_N2 = 0
|
||||
@@ -51,6 +50,10 @@
|
||||
assign_uid()
|
||||
id_tag = num2text(uid)
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_scrubber/detailed_examine()
|
||||
return "This filters the atmosphere of harmful gas. Filtered gas goes to the pipes connected to it, typically a scrubber pipe. \
|
||||
It can be controlled from an Air Alarm. It can be configured to drain all air rapidly with a 'panic syphon' from an air alarm."
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_scrubber/Destroy()
|
||||
if(initial_loc && frequency == ATMOS_VENTSCRUB)
|
||||
initial_loc.air_scrub_info -= id_tag
|
||||
@@ -193,6 +196,10 @@
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
var/turf/T = loc
|
||||
if(T.density) //No, you should not be able to get free air from walls
|
||||
return
|
||||
|
||||
if(!node)
|
||||
on = 0
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
if(!target)
|
||||
target = locate(/obj/machinery/atmospherics/pipe) in loc
|
||||
|
||||
/obj/machinery/meter/detailed_examine()
|
||||
return "Measures the volume and temperature of the pipe under the meter."
|
||||
|
||||
/obj/machinery/meter/process_atmos()
|
||||
if(!target)
|
||||
icon_state = "meterX"
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
..()
|
||||
initialize_directions = dir
|
||||
|
||||
/obj/machinery/atmospherics/pipe/cap/detailed_examine()
|
||||
return "This is a cosmetic attachment, as pipes currently do not spill their contents into the air."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/cap/hide(i)
|
||||
if(level == 1 && istype(loc, /turf/simulated))
|
||||
invisibility = i ? INVISIBILITY_MAXIMUM : 0
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
level = 1
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/New()
|
||||
|
||||
..()
|
||||
|
||||
alpha = 255
|
||||
@@ -31,6 +30,9 @@
|
||||
if(WEST)
|
||||
initialize_directions = NORTH|EAST|SOUTH
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/detailed_examine()
|
||||
return "A normal pipe with three ends to connect to."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/atmos_init()
|
||||
..()
|
||||
for(var/D in GLOB.cardinal)
|
||||
@@ -170,6 +172,10 @@
|
||||
icon_connect_type = "-scrubbers"
|
||||
color = PIPE_COLOR_RED
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers/detailed_examine()
|
||||
return "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/visible/supply
|
||||
name="Air supply pipe manifold"
|
||||
desc = "A manifold composed of supply pipes"
|
||||
@@ -179,6 +185,10 @@
|
||||
icon_connect_type = "-supply"
|
||||
color = PIPE_COLOR_BLUE
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/visible/supply/detailed_examine()
|
||||
return "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/visible/yellow
|
||||
color = PIPE_COLOR_YELLOW
|
||||
|
||||
@@ -211,6 +221,10 @@
|
||||
icon_connect_type = "-scrubbers"
|
||||
color = PIPE_COLOR_RED
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers/detailed_examine()
|
||||
return "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/hidden/supply
|
||||
name="Air supply pipe manifold"
|
||||
desc = "A manifold composed of supply pipes"
|
||||
@@ -220,6 +234,10 @@
|
||||
icon_connect_type = "-supply"
|
||||
color = PIPE_COLOR_BLUE
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/hidden/supply/detailed_examine()
|
||||
return "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/hidden/yellow
|
||||
color = PIPE_COLOR_YELLOW
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
alpha = 255
|
||||
icon = null
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/detailed_examine()
|
||||
return "This is a four-way pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion()
|
||||
return list(node1, node2, node3, node4)
|
||||
|
||||
@@ -179,6 +182,10 @@
|
||||
icon_connect_type = "-scrubbers"
|
||||
color = PIPE_COLOR_RED
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers/detailed_examine()
|
||||
return "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/visible/supply
|
||||
name="4-way air supply pipe manifold"
|
||||
desc = "A manifold composed of supply pipes"
|
||||
@@ -188,6 +195,10 @@
|
||||
icon_connect_type = "-supply"
|
||||
color = PIPE_COLOR_BLUE
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/visible/supply/detailed_examine()
|
||||
return "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow
|
||||
color = PIPE_COLOR_YELLOW
|
||||
|
||||
@@ -214,6 +225,10 @@
|
||||
icon_connect_type = "-scrubbers"
|
||||
color = PIPE_COLOR_RED
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers/detailed_examine()
|
||||
return "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply
|
||||
name="4-way air supply pipe manifold"
|
||||
desc = "A manifold composed of supply pipes"
|
||||
@@ -223,6 +238,10 @@
|
||||
icon_connect_type = "-supply"
|
||||
color = PIPE_COLOR_BLUE
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply/detailed_examine()
|
||||
return "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow
|
||||
color = PIPE_COLOR_YELLOW
|
||||
|
||||
|
||||
@@ -36,6 +36,12 @@
|
||||
qdel(parent)
|
||||
parent = null
|
||||
|
||||
/obj/machinery/atmospherics/pipe/detailed_examine()
|
||||
return "This pipe, and all other pipes, can be connected or disconnected by a wrench. The internal pressure of the pipe must \
|
||||
be below 300 kPa to do this. More pipes can be obtained from the pipe dispenser.<br> \
|
||||
Most pipes and atmospheric devices can be connected or disconnected with a wrench. The pipe's pressure must not be too high, \
|
||||
or if it is a device, it must be turned off first."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/analyzer))
|
||||
atmosanalyzer_scan(parent.air, user)
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
var/icon_temperature = T20C //stop small changes in temperature causing icon refresh
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/detailed_examine()
|
||||
return "This radiates heat from the pipe's gas to space, cooling it down."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/process_atmos()
|
||||
var/environment_temperature = 0
|
||||
var/datum/gas_mixture/pipe_air = return_air()
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
icon_connect_type = "-scrubbers"
|
||||
color = PIPE_COLOR_RED
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers/detailed_examine()
|
||||
return "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/supply
|
||||
name = "Air supply pipe"
|
||||
desc = "A one meter section of supply pipe"
|
||||
@@ -21,12 +25,19 @@
|
||||
icon_connect_type = "-supply"
|
||||
color = PIPE_COLOR_BLUE
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/supply/detailed_examine()
|
||||
return "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/universal
|
||||
name="Universal pipe adapter"
|
||||
desc = "An adapter for regular, supply and scrubbers pipes"
|
||||
connect_types = list(1,2,3)
|
||||
icon_state = "map_universal"
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/universal/detailed_examine()
|
||||
return "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(safety = 0)
|
||||
..()
|
||||
|
||||
|
||||
@@ -9,3 +9,6 @@
|
||||
alert_pressure = 900*ONE_ATMOSPHERE
|
||||
|
||||
level = 2
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/insulated/detailed_examine()
|
||||
return "This is completely useless, use a normal pipe." //Sorry, but it's true.
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
icon_connect_type = "-scrubbers"
|
||||
color = PIPE_COLOR_RED
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/scrubbers/detailed_examine()
|
||||
return "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/supply
|
||||
name = "Air supply pipe"
|
||||
desc = "A one meter section of supply pipe"
|
||||
@@ -20,6 +24,10 @@
|
||||
icon_connect_type = "-supply"
|
||||
color = PIPE_COLOR_BLUE
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/supply/detailed_examine()
|
||||
return "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/yellow
|
||||
color = PIPE_COLOR_YELLOW
|
||||
|
||||
@@ -44,6 +52,9 @@
|
||||
connect_types = list(1,2,3)
|
||||
icon_state = "map_universal"
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/universal/detailed_examine()
|
||||
return "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/universal/update_icon(safety = 0)
|
||||
..()
|
||||
|
||||
|
||||
@@ -101,6 +101,14 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
|
||||
color_index = list()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/detailed_examine()
|
||||
return "The canister can be connected to a connector port with a wrench. Tanks of gas (the kind you can hold in your hand) \
|
||||
can be filled by the canister, by using the tank on the canister, increasing the release pressure, then opening the valve until it is full, and then close it. \
|
||||
*DO NOT* remove the tank until the valve is closed. A gas analyzer can be used to check the contents of the canister."
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/detailed_examine_antag()
|
||||
return "Canisters can be damaged, spilling their contents into the air, or you can just leave the release valve open."
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proc/check_change()
|
||||
var/old_flag = update_flag
|
||||
update_flag = 0
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
/// The desired pressure the pump should be outputting, either into the atmosphere, or into a holding tank.
|
||||
var/target_pressure = 101.325
|
||||
|
||||
/obj/machinery/portable_atmospherics/pump/detailed_examine()
|
||||
return "Invaluable for filling air in a room rapidly after a breach repair. The internal gas container can be filled by \
|
||||
connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \
|
||||
replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the air pump."
|
||||
|
||||
/obj/machinery/portable_atmospherics/pump/update_icon()
|
||||
overlays = 0
|
||||
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
/// Is this scrubber acting on the 3x3 area around it.
|
||||
var/widenet = FALSE
|
||||
|
||||
/obj/machinery/portable_atmospherics/scrubber/detailed_examine()
|
||||
return "Filters the air, placing harmful gases into the internal gas container. The container can be emptied by \
|
||||
connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \
|
||||
replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the scrubber."
|
||||
|
||||
/obj/machinery/portable_atmospherics/scrubber/emp_act(severity)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
..(severity)
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
var/death_cooldown = 0 // How long you have to wait after dying before using it again, in deciseconds. People that join as observers are not included.
|
||||
|
||||
/obj/effect/mob_spawn/attack_ghost(mob/user)
|
||||
var/mob/dead/observer/O = user
|
||||
if(SSticker.current_state != GAME_STATE_PLAYING || !loc || !ghost_usable)
|
||||
return
|
||||
if(!uses)
|
||||
@@ -48,9 +47,6 @@
|
||||
if(cannotPossess(user))
|
||||
to_chat(user, "<span class='warning'>Upon using the antagHUD you forfeited the ability to join the round.</span>")
|
||||
return
|
||||
if(!O.can_reenter_corpse)
|
||||
to_chat(user, "<span class='warning'>You have forfeited the right to respawn.</span>")
|
||||
return
|
||||
if(time_check(user))
|
||||
return
|
||||
var/ghost_role = alert("Become [mob_name]? (Warning, You can no longer be cloned!)",,"Yes","No")
|
||||
|
||||
@@ -47,7 +47,7 @@ GLOBAL_DATUM_INIT(the_gateway, /obj/machinery/gateway/centerstation, null)
|
||||
/obj/machinery/gateway/centerstation/Initialize()
|
||||
..()
|
||||
update_icon()
|
||||
wait = world.time + config.gateway_delay
|
||||
wait = world.time + GLOB.configuration.gateway.away_mission_delay
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/machinery/gateway/centerstation/LateInitialize()
|
||||
|
||||
@@ -124,6 +124,13 @@
|
||||
if(.)
|
||||
return
|
||||
if(isgolem(user) && can_transfer)
|
||||
var/datum/species/golem/g = user.dna.species
|
||||
if(g.owner)
|
||||
has_owner = TRUE
|
||||
owner = g.owner
|
||||
else
|
||||
has_owner = FALSE
|
||||
owner = null
|
||||
var/transfer_choice = alert("Transfer your soul to [src]? (Warning, your old body will die!)",,"Yes","No")
|
||||
if(transfer_choice != "Yes")
|
||||
return
|
||||
@@ -144,9 +151,17 @@
|
||||
return
|
||||
if(QDELETED(src) || uses <= 0 || user.stat >= 1 || QDELETED(I))
|
||||
return
|
||||
if(istype(src, /obj/effect/mob_spawn/human/golem/servant))
|
||||
if(istype(src, /obj/effect/mob_spawn/human/golem/servant) && !isgolem(user))
|
||||
has_owner = FALSE
|
||||
flavour_text = null
|
||||
if(isgolem(user) && can_transfer)
|
||||
var/datum/species/golem/g = user.dna.species
|
||||
if(g.owner)
|
||||
has_owner = TRUE
|
||||
owner = g.owner
|
||||
else
|
||||
has_owner = FALSE
|
||||
owner = null
|
||||
flavour_text = null
|
||||
user.visible_message("<span class='notice'>As [user] applies the potion on the golem shell, a faint light leaves them, moving to [src] and animating it!</span>",
|
||||
"<span class='notice'>You apply the potion to [src], feeling your mind leave your body!</span>")
|
||||
message_admins("[key_name(user)] used [I] to transfer their mind into [src]")
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
GLOBAL_LIST_INIT(potentialRandomZlevels, generateMapList(filename = "config/away_mission_config.txt"))
|
||||
|
||||
// Call this before you remove the last dirt on a z level - that way, all objects
|
||||
// will have proper atmos and other important enviro things
|
||||
/proc/late_setup_level(turfs, smoothTurfs)
|
||||
@@ -38,39 +36,6 @@ GLOBAL_LIST_INIT(potentialRandomZlevels, generateMapList(filename = "config/away
|
||||
qdel(otherthing)
|
||||
T.ChangeTurf(T.baseturf)
|
||||
|
||||
/proc/generateMapList(filename)
|
||||
var/list/potentialMaps = list()
|
||||
var/list/Lines = file2list(filename)
|
||||
|
||||
if(!Lines.len)
|
||||
return
|
||||
for(var/t in Lines)
|
||||
if(!t)
|
||||
continue
|
||||
|
||||
t = trim(t)
|
||||
if(length(t) == 0)
|
||||
continue
|
||||
else if(copytext(t, 1, 2) == "#")
|
||||
continue
|
||||
|
||||
var/pos = findtext(t, " ")
|
||||
var/name = null
|
||||
|
||||
if(pos)
|
||||
name = lowertext(copytext(t, 1, pos))
|
||||
|
||||
else
|
||||
name = lowertext(t)
|
||||
|
||||
if(!name)
|
||||
continue
|
||||
|
||||
potentialMaps.Add(t)
|
||||
|
||||
return potentialMaps
|
||||
|
||||
|
||||
/datum/map_template/ruin/proc/try_to_place(z,allowed_areas)
|
||||
var/sanity = PLACEMENT_TRIES
|
||||
while(sanity > 0)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// This is in its own file as it has so much stuff to contend with
|
||||
/client/proc/edit_2fa()
|
||||
if(!config._2fa_auth_host)
|
||||
if(!GLOB.configuration.system._2fa_auth_host)
|
||||
alert(usr, "This server does not have 2FA enabled.")
|
||||
return
|
||||
// Client does not have 2FA enabled. Set it up.
|
||||
if(prefs._2fa_status == _2FA_DISABLED)
|
||||
// Get us an auth token
|
||||
var/datum/http_response/qrcr = wrap_http_get("[config._2fa_auth_host]/generateQR?ckey=[ckey]")
|
||||
var/datum/http_response/qrcr = wrap_http_get("[GLOB.configuration.system._2fa_auth_host]/generateQR?ckey=[ckey]")
|
||||
// If this fails, shits gone bad
|
||||
if(qrcr.errored)
|
||||
alert(usr, "Something has gone VERY wrong ingame. Please inform the server host.\nError details: [qrcr.error]")
|
||||
@@ -27,13 +27,13 @@
|
||||
var/entered_code = input(usr, "Please enter a code from your auth app. Failure to enter the code correctly will abort 2FA setup.", "2FA Validation")
|
||||
if(!entered_code)
|
||||
// Cleanup so they can start again
|
||||
var/datum/db_query/dbq = SSdbcore.NewQuery("DELETE FROM [format_table_name("2fa_secrets")] WHERE ckey=:ckey", list("ckey" = ckey))
|
||||
var/datum/db_query/dbq = SSdbcore.NewQuery("DELETE FROM 2fa_secrets WHERE ckey=:ckey", list("ckey" = ckey))
|
||||
dbq.warn_execute()
|
||||
alert(usr, "2FA Setup aborted!")
|
||||
B.close()
|
||||
return
|
||||
|
||||
var/datum/http_response/vr = wrap_http_get("[config._2fa_auth_host]/validateCode?ckey=[ckey]&code=[entered_code]")
|
||||
var/datum/http_response/vr = wrap_http_get("[GLOB.configuration.system._2fa_auth_host]/validateCode?ckey=[ckey]&code=[entered_code]")
|
||||
// If this fails, shits gone bad
|
||||
if(vr.errored)
|
||||
alert(usr, "Something has gone VERY wrong ingame. Please inform the server host.\nError details: [vr.error]")
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
if(vr.status_code != 200)
|
||||
// Cleanup so they can start again
|
||||
var/datum/db_query/dbq = SSdbcore.NewQuery("DELETE FROM [format_table_name("2fa_secrets")] WHERE ckey=:ckey", list("ckey" = ckey))
|
||||
var/datum/db_query/dbq = SSdbcore.NewQuery("DELETE FROM 2fa_secrets WHERE ckey=:ckey", list("ckey" = ckey))
|
||||
dbq.warn_execute()
|
||||
|
||||
// See if its unauthorised. I used 400 for that dont at me
|
||||
@@ -86,7 +86,7 @@
|
||||
alert(usr, "2FA deactivation aborted!")
|
||||
return
|
||||
|
||||
var/datum/http_response/vr = wrap_http_get("[config._2fa_auth_host]/validateCode?ckey=[ckey]&code=[entered_code]")
|
||||
var/datum/http_response/vr = wrap_http_get("[GLOB.configuration.system._2fa_auth_host]/validateCode?ckey=[ckey]&code=[entered_code]")
|
||||
// If this fails, shits gone bad
|
||||
if(vr.errored)
|
||||
alert(usr, "Something has gone VERY wrong ingame. Please inform the server host.\nError details: [vr.error]")
|
||||
@@ -101,7 +101,7 @@
|
||||
return
|
||||
|
||||
// If we are here, they authed properly
|
||||
var/datum/db_query/dbq = SSdbcore.NewQuery("DELETE FROM [format_table_name("2fa_secrets")] WHERE ckey=:ckey", list("ckey" = ckey))
|
||||
var/datum/db_query/dbq = SSdbcore.NewQuery("DELETE FROM 2fa_secrets WHERE ckey=:ckey", list("ckey" = ckey))
|
||||
dbq.warn_execute()
|
||||
prefs._2fa_status = _2FA_DISABLED
|
||||
prefs.save_preferences(src)
|
||||
|
||||
@@ -56,7 +56,6 @@
|
||||
|
||||
var/global/obj/screen/click_catcher/void
|
||||
|
||||
var/karma = 0
|
||||
var/karma_spent = 0
|
||||
var/karma_tab = 0
|
||||
|
||||
@@ -69,6 +68,9 @@
|
||||
//datum that controls the displaying and hiding of tooltips
|
||||
var/datum/tooltip/tooltips
|
||||
|
||||
/// Persistent storage for the flavour text of examined atoms.
|
||||
var/list/description_holders = list()
|
||||
|
||||
// Their chat window, sort of important.
|
||||
// See /goon/code/datums/browserOutput.dm
|
||||
var/datum/chatOutput/chatOutput
|
||||
|
||||
@@ -122,11 +122,12 @@
|
||||
|
||||
|
||||
//Logs all hrefs
|
||||
if(config && config.log_hrefs)
|
||||
if(GLOB.configuration.logging.href_logging)
|
||||
log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]")
|
||||
|
||||
if(href_list["karmashop"])
|
||||
if(config.disable_karma)
|
||||
if(!GLOB.configuration.general.enable_karma)
|
||||
to_chat(src, "Karma is disabled on this server.")
|
||||
return
|
||||
|
||||
switch(href_list["karmashop"])
|
||||
@@ -218,7 +219,7 @@
|
||||
to_chat(src, "<span class='danger'>You are sending messages to quickly. Please wait [wait_time] [wait_time == 1 ? "second" : "seconds"] before sending another message.</span>")
|
||||
return 1
|
||||
last_message_time = world.time
|
||||
if(config.automute_on && !check_rights(R_ADMIN, 0) && last_message == message)
|
||||
if(GLOB.configuration.general.enable_auto_mute && !check_rights(R_ADMIN, 0) && last_message == message)
|
||||
last_message_count++
|
||||
if(last_message_count >= SPAM_TRIGGER_AUTOMUTE)
|
||||
to_chat(src, "<span class='danger'>You have exceeded the spam filter limit for identical messages. An auto-mute was applied.</span>")
|
||||
@@ -259,7 +260,7 @@
|
||||
return null
|
||||
if(byond_version < MIN_CLIENT_VERSION) // Too out of date to play at all. Unfortunately, we can't send them a message here.
|
||||
version_blocked = TRUE
|
||||
if(byond_build < config.minimum_client_build)
|
||||
if(byond_build < GLOB.configuration.general.minimum_client_build)
|
||||
version_blocked = TRUE
|
||||
|
||||
var/show_update_prompt = FALSE
|
||||
@@ -274,7 +275,7 @@
|
||||
GLOB.directory[ckey] = src
|
||||
//Admin Authorisation
|
||||
// Automatically makes localhost connection an admin
|
||||
if(!config.disable_localhost_admin)
|
||||
if(GLOB.configuration.admin.enable_localhost_autoadmin)
|
||||
if(is_connecting_from_localhost())
|
||||
new /datum/admins("!LOCALHOST!", R_HOST, ckey) // Makes localhost rank
|
||||
holder = GLOB.admin_datums[ckey]
|
||||
@@ -306,10 +307,6 @@
|
||||
spawn() // Goonchat does some non-instant checks in start()
|
||||
chatOutput.start()
|
||||
|
||||
if( (world.address == address || !address) && !GLOB.host )
|
||||
GLOB.host = key
|
||||
world.update_status()
|
||||
|
||||
if(holder)
|
||||
on_holder_add()
|
||||
add_admin_verbs()
|
||||
@@ -383,7 +380,7 @@
|
||||
playercount += 1
|
||||
|
||||
// Update the state of the panic bunker based on current playercount
|
||||
var/threshold = config.panic_bunker_threshold
|
||||
var/threshold = GLOB.configuration.general.panic_bunker_threshold
|
||||
|
||||
if((playercount > threshold) && (GLOB.panic_bunker_enabled == FALSE))
|
||||
GLOB.panic_bunker_enabled = TRUE
|
||||
@@ -445,7 +442,7 @@
|
||||
return
|
||||
|
||||
//Donator stuff.
|
||||
var/datum/db_query/query_donor_select = SSdbcore.NewQuery("SELECT ckey, tier, active FROM `[format_table_name("donators")]` WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query_donor_select = SSdbcore.NewQuery("SELECT ckey, tier, active FROM donators WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
|
||||
@@ -466,7 +463,7 @@
|
||||
|
||||
/client/proc/donor_loadout_points()
|
||||
if(donator_level > 0 && prefs)
|
||||
prefs.max_gear_slots = config.max_loadout_points + 5
|
||||
prefs.max_gear_slots = GLOB.configuration.general.base_loadout_points + 5
|
||||
|
||||
/client/proc/log_client_to_db(connectiontopic)
|
||||
set waitfor = FALSE // This needs to run async because any sleep() inside /client/New() breaks stuff badly
|
||||
@@ -476,7 +473,7 @@
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM player WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -491,7 +488,7 @@
|
||||
break
|
||||
|
||||
qdel(query)
|
||||
var/datum/db_query/query_ip = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip=:address", list(
|
||||
var/datum/db_query/query_ip = SSdbcore.NewQuery("SELECT ckey FROM player WHERE ip=:address", list(
|
||||
"address" = address
|
||||
))
|
||||
if(!query_ip.warn_execute())
|
||||
@@ -504,7 +501,7 @@
|
||||
|
||||
qdel(query_ip)
|
||||
|
||||
var/datum/db_query/query_cid = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE computerid=:cid", list(
|
||||
var/datum/db_query/query_cid = SSdbcore.NewQuery("SELECT ckey FROM player WHERE computerid=:cid", list(
|
||||
"cid" = computer_id
|
||||
))
|
||||
if(!query_cid.warn_execute())
|
||||
@@ -551,7 +548,7 @@
|
||||
if(!client_address) // Localhost can sometimes have no address set
|
||||
client_address = "127.0.0.1"
|
||||
//Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET lastseen = Now(), ip=:sql_ip, computerid=:sql_cid, lastadminrank=:sql_ar WHERE id=:sql_id", list(
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET lastseen = Now(), ip=:sql_ip, computerid=:sql_cid, lastadminrank=:sql_ar WHERE id=:sql_id", list(
|
||||
"sql_ip" = client_address,
|
||||
"sql_cid" = computer_id,
|
||||
"sql_ar" = admin_rank,
|
||||
@@ -566,15 +563,7 @@
|
||||
INVOKE_ASYNC(src, /client/.proc/get_byond_account_date, FALSE) // Async to avoid other procs in the client chain being delayed by a web request
|
||||
else
|
||||
//New player!! Need to insert all the stuff
|
||||
|
||||
// Check new peeps for panic bunker
|
||||
if(GLOB.panic_bunker_enabled)
|
||||
var/threshold = config.panic_bunker_threshold
|
||||
src << "Server is not accepting connections from never-before-seen players until player count is less than [threshold]. Please try again later."
|
||||
qdel(src)
|
||||
return // Dont insert or they can just go in again
|
||||
|
||||
var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, :ckey, Now(), Now(), :ip, :cid, :rank)", list(
|
||||
var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, :ckey, Now(), Now(), :ip, :cid, :rank)", list(
|
||||
"ckey" = ckey,
|
||||
"ip" = address,
|
||||
"cid" = computer_id,
|
||||
@@ -593,33 +582,36 @@
|
||||
|
||||
/client/proc/check_ip_intel()
|
||||
set waitfor = 0 //we sleep when getting the intel, no need to hold up the client connection while we sleep
|
||||
if(config.ipintel_email)
|
||||
if(config.ipintel_maxplaytime && config.use_exp_tracking)
|
||||
if(GLOB.configuration.ipintel.enabled)
|
||||
if(GLOB.configuration.ipintel.playtime_ignore_threshold && GLOB.configuration.jobs.enable_exp_tracking)
|
||||
var/living_hours = get_exp_type_num(EXP_TYPE_LIVING) / 60
|
||||
if(living_hours >= config.ipintel_maxplaytime)
|
||||
if(living_hours >= GLOB.configuration.ipintel.playtime_ignore_threshold)
|
||||
return
|
||||
|
||||
if(is_connecting_from_localhost())
|
||||
log_debug("check_ip_intel: skip check for player [key_name_admin(src)] connecting from localhost.")
|
||||
return
|
||||
|
||||
if(vpn_whitelist_check(ckey))
|
||||
if(SSipintel.vpn_whitelist_check(ckey))
|
||||
log_debug("check_ip_intel: skip check for player [key_name_admin(src)] [address] on whitelist.")
|
||||
return
|
||||
|
||||
var/datum/ipintel/res = get_ip_intel(address)
|
||||
var/datum/ipintel/res = SSipintel.get_ip_intel(address)
|
||||
ip_intel = res.intel
|
||||
verify_ip_intel()
|
||||
|
||||
/client/proc/verify_ip_intel()
|
||||
if(ip_intel >= config.ipintel_rating_bad)
|
||||
var/detailsurl = config.ipintel_detailsurl ? "(<a href='[config.ipintel_detailsurl][address]'>IP Info</a>)" : ""
|
||||
if(config.ipintel_whitelist)
|
||||
if(ip_intel >= GLOB.configuration.ipintel.bad_rating)
|
||||
var/detailsurl = GLOB.configuration.ipintel.details_url ? "(<a href='[GLOB.configuration.ipintel.details_url][address]'>IP Info</a>)" : ""
|
||||
if(GLOB.configuration.ipintel.whitelist_mode)
|
||||
// Do not move this to isBanned(). This may sound weird, but:
|
||||
// This needs to happen after their account is put into the DB
|
||||
// This way, admins can then note people
|
||||
spawn(40) // This is necessary because without it, they won't see the message, and addtimer cannot be used because the timer system may not have initialized yet
|
||||
message_admins("<span class='adminnotice'>IPIntel: [key_name_admin(src)] on IP [address] was rejected. [detailsurl]</span>")
|
||||
var/blockmsg = "<B>Error: proxy/VPN detected. Proxy/VPN use is not allowed here. Deactivate it before you reconnect.</B>"
|
||||
if(config.banappeals)
|
||||
blockmsg += "\nIf you are not actually using a proxy/VPN, or have no choice but to use one, request whitelisting at: [config.banappeals]"
|
||||
if(GLOB.configuration.url.banappeals_url)
|
||||
blockmsg += "\nIf you are not actually using a proxy/VPN, or have no choice but to use one, request whitelisting at: [GLOB.configuration.url.banappeals_url]"
|
||||
to_chat(src, blockmsg)
|
||||
qdel(src)
|
||||
else
|
||||
@@ -627,16 +619,16 @@
|
||||
|
||||
|
||||
/client/proc/check_forum_link()
|
||||
if(!config.forum_link_url || !prefs || prefs.fuid)
|
||||
if(!GLOB.configuration.url.forum_link_url || !prefs || prefs.fuid)
|
||||
return
|
||||
if(config.use_exp_tracking)
|
||||
if(GLOB.configuration.jobs.enable_exp_tracking)
|
||||
var/living_hours = get_exp_type_num(EXP_TYPE_LIVING) / 60
|
||||
if(living_hours < 20)
|
||||
return
|
||||
to_chat(src, "<B>You have no verified forum account. <a href='?src=[UID()];link_forum_account=true'>VERIFY FORUM ACCOUNT</a></B>")
|
||||
|
||||
/client/proc/create_oauth_token()
|
||||
var/datum/db_query/query_find_token = SSdbcore.NewQuery("SELECT token FROM [format_table_name("oauth_tokens")] WHERE ckey=:ckey limit 1", list(
|
||||
var/datum/db_query/query_find_token = SSdbcore.NewQuery("SELECT token FROM oauth_tokens WHERE ckey=:ckey limit 1", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
// These queries have log_error=FALSE to avoid auth tokens being in plaintext logs
|
||||
@@ -651,7 +643,7 @@
|
||||
|
||||
var/tokenstr = md5("[rand(0,9999)][world.time][rand(0,9999)][ckey][rand(0,9999)][address][rand(0,9999)][computer_id][rand(0,9999)]")
|
||||
|
||||
var/datum/db_query/query_insert_token = SSdbcore.NewQuery("INSERT INTO [format_table_name("oauth_tokens")] (ckey, token) VALUES(:ckey, :tokenstr)", list(
|
||||
var/datum/db_query/query_insert_token = SSdbcore.NewQuery("INSERT INTO oauth_tokens (ckey, token) VALUES(:ckey, :tokenstr)", list(
|
||||
"ckey" = ckey,
|
||||
"tokenstr" = tokenstr,
|
||||
))
|
||||
@@ -663,7 +655,7 @@
|
||||
return tokenstr
|
||||
|
||||
/client/proc/link_forum_account(fromban)
|
||||
if(!config.forum_link_url)
|
||||
if(!GLOB.configuration.url.forum_link_url)
|
||||
return
|
||||
if(IsGuestKey(key))
|
||||
to_chat(src, "Guest keys cannot be linked.")
|
||||
@@ -672,7 +664,7 @@
|
||||
if(!fromban)
|
||||
to_chat(src, "Your forum account is already set.")
|
||||
return
|
||||
var/datum/db_query/query_find_link = SSdbcore.NewQuery("SELECT fuid FROM [format_table_name("player")] WHERE ckey=:ckey LIMIT 1", list(
|
||||
var/datum/db_query/query_find_link = SSdbcore.NewQuery("SELECT fuid FROM player WHERE ckey=:ckey LIMIT 1", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_find_link.warn_execute())
|
||||
@@ -689,7 +681,7 @@
|
||||
if(!tokenid)
|
||||
to_chat(src, "link_forum_account: unable to create token")
|
||||
return
|
||||
var/url = "[config.forum_link_url][tokenid]"
|
||||
var/url = "[GLOB.configuration.url.forum_link_url][tokenid]"
|
||||
if(fromban)
|
||||
url += "&fwd=appeal"
|
||||
to_chat(src, {"Now opening a window to verify your information with the forums, so that you can appeal your ban. If the window does not load, please copy/paste this link: <a href="[url]">[url]</a>"})
|
||||
@@ -709,7 +701,7 @@
|
||||
if(connection != "seeker") //Invalid connection type.
|
||||
return null
|
||||
topic = params2list(topic)
|
||||
if(!config.check_randomizer)
|
||||
if(!GLOB.configuration.general.enabled_cid_randomiser_buster)
|
||||
return
|
||||
// Stash o' ckeys
|
||||
var/static/cidcheck = list()
|
||||
@@ -721,7 +713,7 @@
|
||||
var/oldcid = cidcheck[ckey]
|
||||
|
||||
if(!oldcid)
|
||||
var/datum/db_query/query_cidcheck = SSdbcore.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query_cidcheck = SSdbcore.NewQuery("SELECT computerid FROM player WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_cidcheck.warn_execute())
|
||||
@@ -791,7 +783,7 @@
|
||||
var/const/adminckey = "CID-Error"
|
||||
|
||||
// Check for notes in the last day - only 1 note per 24 hours
|
||||
var/datum/db_query/query_get_notes = SSdbcore.NewQuery("SELECT id from [format_table_name("notes")] WHERE ckey=:ckey AND adminckey=:adminckey AND timestamp + INTERVAL 1 DAY < NOW()", list(
|
||||
var/datum/db_query/query_get_notes = SSdbcore.NewQuery("SELECT id from notes WHERE ckey=:ckey AND adminckey=:adminckey AND timestamp + INTERVAL 1 DAY < NOW()", list(
|
||||
"ckey" = ckey,
|
||||
"adminckey" = adminckey
|
||||
))
|
||||
@@ -804,7 +796,7 @@
|
||||
qdel(query_get_notes)
|
||||
|
||||
// Only add a note if their most recent note isn't from the randomizer blocker, either
|
||||
var/datum/db_query/query_get_note = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey=:ckey ORDER BY timestamp DESC LIMIT 1", list(
|
||||
var/datum/db_query/query_get_note = SSdbcore.NewQuery("SELECT adminckey FROM notes WHERE ckey=:ckey ORDER BY timestamp DESC LIMIT 1", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_get_note.warn_execute())
|
||||
@@ -842,8 +834,8 @@
|
||||
//Send resources to the client.
|
||||
/client/proc/send_resources()
|
||||
// Change the way they should download resources.
|
||||
if(config.resource_urls)
|
||||
preload_rsc = pick(config.resource_urls)
|
||||
if(length(GLOB.configuration.url.rsc_urls))
|
||||
preload_rsc = pick(GLOB.configuration.url.rsc_urls)
|
||||
else
|
||||
preload_rsc = 1 // If config.resource_urls is not set, preload like normal.
|
||||
// Most assets are now handled through global_cache.dm
|
||||
@@ -949,7 +941,7 @@
|
||||
void.UpdateGreed(actualview[1],actualview[2])
|
||||
|
||||
/client/proc/send_ssd_warning(mob/M)
|
||||
if(!config.ssd_warning)
|
||||
if(!GLOB.configuration.general.ssd_warning)
|
||||
return FALSE
|
||||
if(ssd_warning_acknowledged)
|
||||
return FALSE
|
||||
@@ -1054,7 +1046,7 @@
|
||||
*/
|
||||
/client/proc/get_byond_account_date(notify = FALSE)
|
||||
// First we see if the client has a saved date in the DB
|
||||
var/datum/db_query/query_date = SSdbcore.NewQuery("SELECT byond_date, DATEDIFF(Now(), byond_date) FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query_date = SSdbcore.NewQuery("SELECT byond_date, DATEDIFF(Now(), byond_date) FROM player WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_date.warn_execute())
|
||||
@@ -1080,7 +1072,7 @@
|
||||
byondacc_date = byond_data["general"]["joined"]
|
||||
|
||||
// Now save it
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET byond_date=:date WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET byond_date=:date WHERE ckey=:ckey", list(
|
||||
"date" = byondacc_date,
|
||||
"ckey" = ckey
|
||||
))
|
||||
@@ -1090,7 +1082,7 @@
|
||||
qdel(query_update)
|
||||
|
||||
// Now retrieve the age again because BYOND doesnt have native methods for this
|
||||
var/datum/db_query/query_age = SSdbcore.NewQuery("SELECT DATEDIFF(Now(), byond_date) FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query_age = SSdbcore.NewQuery("SELECT DATEDIFF(Now(), byond_date) FROM player WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_age.warn_execute())
|
||||
@@ -1102,7 +1094,7 @@
|
||||
qdel(query_age)
|
||||
|
||||
// Notify admins on new clients connecting, if the byond account age is less than a config value
|
||||
if(notify && (byondacc_age < config.byond_account_age_threshold))
|
||||
if(notify && (byondacc_age < GLOB.configuration.general.byond_account_age_threshold))
|
||||
message_admins("[key] has just connected for the first time. BYOND account registered on [byondacc_date] ([byondacc_age] days old)")
|
||||
|
||||
/client/proc/show_update_notice()
|
||||
@@ -1125,7 +1117,7 @@
|
||||
tos_consent = TRUE
|
||||
return TRUE
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("privacy")] WHERE ckey=:ckey AND consent=1", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM privacy WHERE ckey=:ckey AND consent=1", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -1149,7 +1141,7 @@
|
||||
*/
|
||||
/client/proc/cid_count_check()
|
||||
// If the config is 0, disable this
|
||||
if(config.max_client_cid_history == 0)
|
||||
if(GLOB.configuration.general.max_client_cid_history == 0)
|
||||
return
|
||||
|
||||
// If we have no DB, dont even bother
|
||||
@@ -1169,11 +1161,11 @@
|
||||
cidcount = query_cidcheck.item[1]
|
||||
qdel(query_cidcheck)
|
||||
|
||||
if(cidcount > config.max_client_cid_history)
|
||||
if(cidcount > GLOB.configuration.general.max_client_cid_history)
|
||||
// Check their notes for CID tracking in the past
|
||||
var/has_note = FALSE
|
||||
var/note_text = ""
|
||||
var/datum/db_query/query_find_track_note = SSdbcore.NewQuery("SELECT notetext FROM [format_table_name("notes")] WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
var/datum/db_query/query_find_track_note = SSdbcore.NewQuery("SELECT notetext FROM notes WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
"ckey" = ckey,
|
||||
"ackey" = CIDTRACKING_PSUEDO_CKEY
|
||||
))
|
||||
@@ -1190,7 +1182,7 @@
|
||||
var/new_text = "Connected on the date of this note with unique CID #[cidcount]"
|
||||
// Only update the note if the text is different. Otherwise it bumps the timestamp when it shouldnt
|
||||
if(note_text != new_text)
|
||||
var/datum/db_query/query_update_track_note = SSdbcore.NewQuery("UPDATE [format_table_name("notes")] SET notetext=:notetext, timestamp=NOW(), round_id=:rid WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
var/datum/db_query/query_update_track_note = SSdbcore.NewQuery("UPDATE notes SET notetext=:notetext, timestamp=NOW(), round_id=:rid WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
"notetext" = new_text,
|
||||
"ckey" = ckey,
|
||||
"ackey" = CIDTRACKING_PSUEDO_CKEY,
|
||||
@@ -1208,7 +1200,7 @@
|
||||
|
||||
var/show_warning = TRUE
|
||||
// Check if they have a note that matches the warning suppressor
|
||||
var/datum/db_query/query_find_note = SSdbcore.NewQuery("SELECT id FROM [format_table_name("notes")] WHERE ckey=:ckey AND notetext=:notetext", list(
|
||||
var/datum/db_query/query_find_note = SSdbcore.NewQuery("SELECT id FROM notes WHERE ckey=:ckey AND notetext=:notetext", list(
|
||||
"ckey" = ckey,
|
||||
"notetext" = CIDWARNING_SUPPRESSED_NOTETEXT
|
||||
))
|
||||
|
||||
@@ -34,13 +34,13 @@
|
||||
description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races."
|
||||
path = /obj/item/clothing/glasses/tajblind/eng
|
||||
cost = 2
|
||||
|
||||
|
||||
/datum/gear/racial/taj/cargo
|
||||
display_name = "khaki veil"
|
||||
description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races. It is light and comfy!"
|
||||
path = /obj/item/clothing/glasses/tajblind/cargo
|
||||
cost = 2
|
||||
|
||||
|
||||
/datum/gear/racial/footwraps
|
||||
display_name = "cloth footwraps"
|
||||
path = /obj/item/clothing/shoes/footwraps
|
||||
|
||||
@@ -108,6 +108,11 @@
|
||||
path = /obj/item/clothing/suit/armor/secjacket
|
||||
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Security Pod Pilot")
|
||||
|
||||
/datum/gear/suit/secbomberjacket
|
||||
display_name = "security bomber jacket"
|
||||
path = /obj/item/clothing/suit/jacket/pilot
|
||||
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Security Pod Pilot")
|
||||
|
||||
/datum/gear/suit/ianshirt
|
||||
display_name = "Ian Shirt"
|
||||
path = /obj/item/clothing/suit/ianshirt
|
||||
|
||||
@@ -38,7 +38,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
return 0
|
||||
if(!role)
|
||||
return 0
|
||||
if(!config.use_age_restriction_for_antags)
|
||||
if(!GLOB.configuration.gamemode.antag_account_age_restriction)
|
||||
return 0
|
||||
if(!isnum(C.player_age))
|
||||
return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced
|
||||
@@ -214,7 +214,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
parent = C
|
||||
b_type = pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
|
||||
|
||||
max_gear_slots = config.max_loadout_points
|
||||
max_gear_slots = GLOB.configuration.general.base_loadout_points
|
||||
var/loaded_preferences_successfully = FALSE
|
||||
if(istype(C))
|
||||
if(!IsGuestKey(C.key))
|
||||
@@ -473,7 +473,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
dat += "<b>Ghost PDA:</b> <a href='?_src_=prefs;preference=ghost_pda'><b>[(toggles & PREFTOGGLE_CHAT_GHOSTPDA) ? "All PDA Messages" : "No PDA Messages"]</b></a><br>"
|
||||
if(check_rights(R_ADMIN,0))
|
||||
dat += "<b>OOC Color:</b> <span style='border: 1px solid #161616; background-color: [ooccolor ? ooccolor : GLOB.normal_ooc_colour];'> </span> <a href='?_src_=prefs;preference=ooccolor;task=input'><b>Change</b></a><br>"
|
||||
if(config.allow_Metadata)
|
||||
if(GLOB.configuration.general.allow_character_metadata)
|
||||
dat += "<b>OOC Notes:</b> <a href='?_src_=prefs;preference=metadata;task=input'><b>Edit</b></a><br>"
|
||||
dat += "<b>Parallax (Fancy Space):</b> <a href='?_src_=prefs;preference=parallax'>"
|
||||
switch (parallax)
|
||||
@@ -1102,9 +1102,9 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
ResetJobs()
|
||||
SetChoices(user)
|
||||
if("learnaboutselection")
|
||||
if(config.wikiurl)
|
||||
if(GLOB.configuration.url.wiki_url)
|
||||
if(alert("Would you like to open the Job selection info in your browser?", "Open Job Selection", "Yes", "No") == "Yes")
|
||||
user << link("[config.wikiurl]/index.php/Job_Selection_and_Assignment")
|
||||
user << link("[GLOB.configuration.url.wiki_url]/index.php/Job_Selection_and_Assignment")
|
||||
else
|
||||
to_chat(user, "<span class='danger'>The Wiki URL is not set in the server configuration.</span>")
|
||||
if("random")
|
||||
@@ -1321,17 +1321,10 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
if("species")
|
||||
var/list/new_species = list("Human", "Tajaran", "Skrell", "Unathi", "Diona", "Vulpkanin")
|
||||
var/prev_species = species
|
||||
// var/whitelisted = 0
|
||||
|
||||
if(config.usealienwhitelist) //If we're using the whitelist, make sure to check it!
|
||||
for(var/Spec in GLOB.whitelisted_species)
|
||||
if(is_alien_whitelisted(user,Spec))
|
||||
new_species += Spec
|
||||
// whitelisted = 1
|
||||
// if(!whitelisted)
|
||||
// alert(user, "You cannot change your species as you need to be whitelisted. If you wish to be whitelisted contact an admin in-game, on the forums, or on IRC.")
|
||||
else //Not using the whitelist? Aliens for everyone!
|
||||
new_species += GLOB.whitelisted_species
|
||||
for(var/species in GLOB.whitelisted_species)
|
||||
if(is_alien_whitelisted(user, species))
|
||||
new_species += species
|
||||
|
||||
species = input("Please select a species", "Character Generation", null) in sortTim(new_species, /proc/cmp_text_asc)
|
||||
var/datum/species/NS = GLOB.all_species[species]
|
||||
@@ -1414,18 +1407,6 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
if("language")
|
||||
// var/languages_available
|
||||
var/list/new_languages = list("None")
|
||||
/*
|
||||
if(config.usealienwhitelist)
|
||||
for(var/L in GLOB.all_languages)
|
||||
var/datum/language/lang = GLOB.all_languages[L]
|
||||
if((!(lang.flags & RESTRICTED)) && (is_alien_whitelisted(user, L)||(!( lang.flags & WHITELISTED ))))
|
||||
new_languages += lang
|
||||
languages_available = 1
|
||||
|
||||
if(!(languages_available))
|
||||
alert(user, "There are not currently any available secondary languages.")
|
||||
else
|
||||
*/
|
||||
for(var/L in GLOB.all_languages)
|
||||
var/datum/language/lang = GLOB.all_languages[L]
|
||||
if(!(lang.flags & RESTRICTED))
|
||||
@@ -2029,8 +2010,8 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
|
||||
if("afk_watch")
|
||||
if(!(toggles2 & PREFTOGGLE_2_AFKWATCH))
|
||||
to_chat(user, "<span class='info'>You will now get put into cryo dorms after [config.auto_cryo_afk] minutes. \
|
||||
Then after [config.auto_despawn_afk] minutes you will be fully despawned. You will receive a visual and auditory warning before you will be put into cryodorms.</span>")
|
||||
to_chat(user, "<span class='info'>You will now get put into cryo dorms after [GLOB.configuration.afk.auto_cryo_minutes] minutes. \
|
||||
Then after [GLOB.configuration.afk.auto_despawn_minutes] minutes you will be fully despawned. You will receive a visual and auditory warning before you will be put into cryodorms.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='info'>Automatic cryoing turned off.</span>")
|
||||
toggles2 ^= PREFTOGGLE_2_AFKWATCH
|
||||
@@ -2162,14 +2143,6 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
if(be_random_name)
|
||||
real_name = random_name(gender,species)
|
||||
|
||||
if(config.humans_need_surnames)
|
||||
var/firstspace = findtext(real_name, " ")
|
||||
var/name_length = length(real_name)
|
||||
if(!firstspace) //we need a surname
|
||||
real_name += " [pick(GLOB.last_names)]"
|
||||
else if(firstspace == name_length)
|
||||
real_name += "[pick(GLOB.last_names)]"
|
||||
|
||||
character.add_language(language)
|
||||
|
||||
|
||||
@@ -2326,7 +2299,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
|
||||
/datum/preferences/proc/open_load_dialog(mob/user)
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot, real_name FROM [format_table_name("characters")] WHERE ckey=:ckey ORDER BY slot", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot, real_name FROM characters WHERE ckey=:ckey ORDER BY slot", list(
|
||||
"ckey" = user.ckey
|
||||
))
|
||||
var/list/slotnames[max_save_slots]
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
fuid,
|
||||
parallax,
|
||||
2fa_status
|
||||
FROM [format_table_name("player")]
|
||||
FROM player
|
||||
WHERE ckey=:ckey"}, list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
@@ -80,7 +80,7 @@
|
||||
deltimer(volume_mixer_saving)
|
||||
volume_mixer_saving = null
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"UPDATE [format_table_name("player")]
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"UPDATE player
|
||||
SET
|
||||
ooccolor=:ooccolour,
|
||||
UI_style=:ui_style,
|
||||
@@ -126,14 +126,15 @@
|
||||
qdel(query)
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/load_character(client/C,slot)
|
||||
/datum/preferences/proc/load_character(client/C, slot)
|
||||
saved = FALSE
|
||||
|
||||
if(!slot) slot = default_slot
|
||||
if(!slot)
|
||||
slot = default_slot
|
||||
slot = sanitize_integer(slot, 1, max_save_slots, initial(default_slot))
|
||||
if(slot != default_slot)
|
||||
default_slot = slot
|
||||
var/datum/db_query/firstquery = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET default_slot=:slot WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/firstquery = SSdbcore.NewQuery("UPDATE player SET default_slot=:slot WHERE ckey=:ckey", list(
|
||||
"slot" = slot,
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
@@ -142,6 +143,10 @@
|
||||
return
|
||||
qdel(firstquery)
|
||||
|
||||
if(!C) // If the client disconnected during the query, try again later.
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
// Let's not have this explode if you sneeze on the DB
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"SELECT
|
||||
OOC_Notes,
|
||||
@@ -196,7 +201,7 @@
|
||||
body_accessory,
|
||||
gear,
|
||||
autohiss
|
||||
FROM [format_table_name("characters")] WHERE ckey=:ckey AND slot=:slot"}, list(
|
||||
FROM characters WHERE ckey=:ckey AND slot=:slot"}, list(
|
||||
"ckey" = C.ckey,
|
||||
"slot" = slot
|
||||
))
|
||||
@@ -360,7 +365,7 @@
|
||||
if(!isemptylist(loadout_gear))
|
||||
gearlist = list2params(loadout_gear)
|
||||
|
||||
var/datum/db_query/firstquery = SSdbcore.NewQuery("SELECT slot FROM [format_table_name("characters")] WHERE ckey=:ckey ORDER BY slot", list(
|
||||
var/datum/db_query/firstquery = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey ORDER BY slot", list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
if(!firstquery.warn_execute())
|
||||
@@ -368,7 +373,7 @@
|
||||
return
|
||||
while(firstquery.NextRow())
|
||||
if(text2num(firstquery.item[1]) == default_slot)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"UPDATE [format_table_name("characters")]
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"UPDATE characters
|
||||
SET
|
||||
OOC_Notes=:metadata,
|
||||
real_name=:real_name,
|
||||
@@ -493,7 +498,7 @@
|
||||
qdel(firstquery)
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("characters")] (ckey, slot, OOC_Notes, real_name, name_is_always_random, gender,
|
||||
INSERT INTO characters (ckey, slot, OOC_Notes, real_name, name_is_always_random, gender,
|
||||
age, species, language,
|
||||
hair_colour, secondary_hair_colour,
|
||||
facial_hair_colour, secondary_facial_hair_colour,
|
||||
@@ -615,7 +620,7 @@
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/load_random_character_slot(client/C)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot FROM [format_table_name("characters")] WHERE ckey=:ckey ORDER BY slot", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey ORDER BY slot", list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
var/list/saves = list()
|
||||
@@ -637,7 +642,7 @@
|
||||
/datum/preferences/proc/clear_character_slot(client/C)
|
||||
. = FALSE
|
||||
// Is there a character in that slot?
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot FROM [format_table_name("characters")] WHERE ckey=:ckey AND slot=:slot", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey AND slot=:slot", list(
|
||||
"ckey" = C.ckey,
|
||||
"slot" = default_slot
|
||||
))
|
||||
@@ -652,7 +657,7 @@
|
||||
|
||||
qdel(query)
|
||||
|
||||
var/datum/db_query/delete_query = SSdbcore.NewQuery("DELETE FROM [format_table_name("characters")] WHERE ckey=:ckey AND slot=:slot", list(
|
||||
var/datum/db_query/delete_query = SSdbcore.NewQuery("DELETE FROM characters WHERE ckey=:ckey AND slot=:slot", list(
|
||||
"ckey" = C.ckey,
|
||||
"slot" = default_slot
|
||||
))
|
||||
@@ -673,7 +678,7 @@
|
||||
volume_mixer_saving = null
|
||||
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("player")] SET volume_mixer=:volume_mixer WHERE ckey=:ckey",
|
||||
"UPDATE player SET volume_mixer=:volume_mixer WHERE ckey=:ckey",
|
||||
list(
|
||||
"volume_mixer" = serialize_volume_mixer(volume_mixer),
|
||||
"ckey" = parent.ckey
|
||||
|
||||
@@ -394,8 +394,7 @@ BLIND // can't see anything
|
||||
if(H.l_hand && H.r_hand) //If both hands are occupied, drop the object on the ground.
|
||||
user.unEquip(src)
|
||||
else //Otherwise, put it in an available hand, the active one preferentially.
|
||||
src.loc = user
|
||||
H.head = null
|
||||
user.unEquip(src)
|
||||
user.put_in_hands(src)
|
||||
else
|
||||
icon_state += "_up"
|
||||
@@ -420,8 +419,7 @@ BLIND // can't see anything
|
||||
if(H.l_hand && H.r_hand) //If both hands are occupied, drop the object on the ground.
|
||||
user.unEquip(src)
|
||||
else //Otherwise, put it in an available hand, the active one preferentially.
|
||||
src.loc = user
|
||||
user.wear_mask = null
|
||||
user.unEquip(src)
|
||||
user.put_in_hands(src)
|
||||
H.wear_mask_update(src, toggle_off = mask_adjusted)
|
||||
usr.update_inv_wear_mask()
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
desc = "An Ahdominian made veil that allows the user to see while obscuring their eyes. This one has an in-built security HUD."
|
||||
icon_state = "tajblind_sec"
|
||||
item_state = "tajblind_sec"
|
||||
flash_protect = FLASH_PROTECTION_FLASH
|
||||
flags_cover = GLASSESCOVERSEYES
|
||||
actions_types = list(/datum/action/item_action/toggle)
|
||||
up = 0
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
resistance_flags = NONE
|
||||
|
||||
/obj/item/clothing/gloves/color/yellow/power
|
||||
description_antag = "These are a pair of power gloves, and can be used to fire bolts of electricity while standing over powered power cables."
|
||||
var/old_mclick_override
|
||||
var/datum/middleClickOverride/power_gloves/mclick_override = new /datum/middleClickOverride/power_gloves
|
||||
var/last_shocked = 0
|
||||
var/shock_delay = 40
|
||||
var/unlimited_power = FALSE // Does this really need explanation?
|
||||
|
||||
/obj/item/clothing/gloves/color/yellow/power/detailed_examine_antag()
|
||||
return "These are a pair of power gloves, and can be used to fire bolts of electricity while standing over powered power cables."
|
||||
|
||||
/obj/item/clothing/gloves/color/yellow/power/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
strip_delay = 80
|
||||
|
||||
/obj/item/clothing/suit/armor/hos/alt
|
||||
name = "armored trenchoat"
|
||||
name = "armored trenchcoat"
|
||||
desc = "A trenchcoat enhanced with a special lightweight kevlar. The epitome of tactical plainclothes."
|
||||
icon_state = "hostrench_open"
|
||||
item_state = "hostrench_open"
|
||||
|
||||
@@ -803,7 +803,7 @@
|
||||
max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT
|
||||
strip_delay = 60
|
||||
put_on_delay = 40
|
||||
armor = list(melee = 25, bullet = 15, laser = 25, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 50, acid = 50)
|
||||
armor = list(melee = 15, bullet = 5, laser = 15, energy = 5, bomb = 15, bio = 0, rad = 0, fire = 30, acid = 30)
|
||||
//End of inheritance from Security armour.
|
||||
|
||||
/obj/item/clothing/suit/jacket/leather
|
||||
@@ -967,11 +967,13 @@
|
||||
|
||||
//Syndicate Chaplain Robe (WOLOLO!)
|
||||
/obj/item/clothing/suit/hooded/chaplain_hoodie/missionary_robe
|
||||
description_antag = "This robe is made of reinforced fibers, granting it superior protection. The robes also wirelessly generate power for the neurotransmitter in the linked missionary staff while being worn."
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
armor = list(melee = 10, bullet = 10, laser = 5, energy = 5, bomb = 0, bio = 0, rad = 15, fire = 30, acid = 30)
|
||||
var/obj/item/nullrod/missionary_staff/linked_staff = null
|
||||
|
||||
/obj/item/clothing/suit/hooded/chaplain_hoodie/missionary_robe/detailed_examine_antag()
|
||||
return "This robe is made of reinforced fibers, granting it superior protection. The robes also wirelessly generate power for the neurotransmitter in the linked missionary staff while being worn."
|
||||
|
||||
/obj/item/clothing/suit/hooded/chaplain_hoodie/missionary_robe/Destroy()
|
||||
if(linked_staff) //delink on destruction
|
||||
linked_staff.robes = null
|
||||
|
||||
@@ -1470,13 +1470,13 @@
|
||||
|
||||
|
||||
/obj/item/clothing/head/fluff/lfbowler //Lightfire: Hyperion
|
||||
name = "Classy bowler hat"
|
||||
desc = "a very classy looking bowler hat"
|
||||
name = "classy bowler hat"
|
||||
desc = "A very classy looking bowler hat."
|
||||
icon = 'icons/obj/custom_items.dmi'
|
||||
icon_state = "bowler_lightfire"
|
||||
|
||||
/obj/item/clothing/under/fluff/lfvicsuit //Lightfire: Hyperion
|
||||
name = "Classy victorian suit"
|
||||
name = "classy victorian suit"
|
||||
desc = "A blue and black victorian suit with silver buttons, very fancy!"
|
||||
icon = 'icons/obj/custom_items.dmi'
|
||||
lefthand_file = 'icons/mob/inhands/fluff_lefthand.dmi'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
// Grab the info we want.
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"
|
||||
SELECT cuiPath, cuiPropAdjust, cuiJobMask, cuiDescription, cuiItemName FROM [format_table_name("customuseritems")]
|
||||
SELECT cuiPath, cuiPropAdjust, cuiJobMask, cuiDescription, cuiItemName FROM customuseritems
|
||||
WHERE cuiCKey=:ckey AND (cuiRealName=:realname OR cuiRealName='*')"}, list(
|
||||
"ckey" = M.ckey,
|
||||
"realname" = M.real_name
|
||||
|
||||
@@ -115,8 +115,7 @@ GLOBAL_DATUM(error_cache, /datum/ErrorViewer/ErrorCache)
|
||||
|
||||
// Show the error to admins with debug messages turned on, but only if one
|
||||
// from the same source hasn't been shown too recently
|
||||
// (Also, make sure config is initialized, or log_debug will runtime)
|
||||
if(config && error_source.next_message_at <= world.time)
|
||||
if(error_source.next_message_at <= world.time)
|
||||
var/const/viewtext = "\[view]" // Nesting these in other brackets went poorly
|
||||
log_debug("Runtime in [e.file],[e.line]: [html_encode(e.name)] [error_entry.makeLink(viewtext)]")
|
||||
error_source.next_message_at = world.time + ERROR_MSG_DELAY
|
||||
|
||||
@@ -30,6 +30,6 @@
|
||||
SSticker.mode.update_blob_icons_added(B.mind)
|
||||
|
||||
to_chat(B, "<span class='userdanger'>You are now a mouse, infected with blob spores. Find somewhere isolated... before you burst and become the blob! Use ventcrawl (alt-click on vents) to move around.</span>")
|
||||
to_chat(B, "<span class='motd'>For more information, check the wiki page: ([config.wikiurl]/index.php/Blob)</span>")
|
||||
to_chat(B, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Blob)</span>")
|
||||
notify_ghosts("Infected Mouse has appeared in [get_area(B)].", source = B)
|
||||
successSpawn = TRUE
|
||||
|
||||
@@ -40,11 +40,6 @@
|
||||
|
||||
return clamp((weight + job_weight) * weight_mod, min_weight, max_weight)
|
||||
|
||||
/datum/event_meta/alien/get_weight(list/active_with_role)
|
||||
if(GLOB.aliens_allowed)
|
||||
return ..(active_with_role)
|
||||
return 0
|
||||
|
||||
/*/datum/event_meta/ninja/get_weight(var/list/active_with_role)
|
||||
if(toggle_space_ninja)
|
||||
return ..(active_with_role)
|
||||
|
||||
@@ -29,7 +29,8 @@ GLOBAL_LIST_EMPTY(event_last_fired)
|
||||
if(delayed)
|
||||
next_event_time += (world.time - last_world_time)
|
||||
else if(world.time > next_event_time)
|
||||
start_event()
|
||||
if(GLOB.configuration.event.enable_random_events)
|
||||
start_event()
|
||||
|
||||
last_world_time = world.time
|
||||
|
||||
@@ -66,7 +67,7 @@ GLOBAL_LIST_EMPTY(event_last_fired)
|
||||
|
||||
for(var/event_meta in last_event_time) if(possible_events[event_meta])
|
||||
var/time_passed = world.time - GLOB.event_last_fired[event_meta]
|
||||
var/weight_modifier = max(0, (config.expected_round_length - time_passed) / 300)
|
||||
var/weight_modifier = max(0, (GLOB.configuration.event.expected_round_length - time_passed) / 300)
|
||||
var/new_weight = max(possible_events[event_meta] - weight_modifier, 0)
|
||||
|
||||
if(new_weight)
|
||||
@@ -84,9 +85,9 @@ GLOBAL_LIST_EMPTY(event_last_fired)
|
||||
|
||||
/datum/event_container/proc/set_event_delay()
|
||||
// If the next event time has not yet been set and we have a custom first time start
|
||||
if(next_event_time == 0 && config.event_first_run[severity])
|
||||
var/lower = config.event_first_run[severity]["lower"]
|
||||
var/upper = config.event_first_run[severity]["upper"]
|
||||
if(next_event_time == 0 && GLOB.configuration.event.first_run_times[severity])
|
||||
var/lower = GLOB.configuration.event.first_run_times[severity]["lower"]
|
||||
var/upper = GLOB.configuration.event.first_run_times[severity]["upper"]
|
||||
var/event_delay = rand(lower, upper)
|
||||
next_event_time = world.time + event_delay
|
||||
// Otherwise, follow the standard setup process
|
||||
@@ -110,7 +111,7 @@ GLOBAL_LIST_EMPTY(event_last_fired)
|
||||
|
||||
playercount_modifier = playercount_modifier * delay_modifier
|
||||
|
||||
var/event_delay = rand(config.event_delay_lower[severity], config.event_delay_upper[severity]) * playercount_modifier
|
||||
var/event_delay = rand(GLOB.configuration.event.delay_lower_bound[severity], GLOB.configuration.event.delay_upper_bound[severity]) * playercount_modifier
|
||||
next_event_time = world.time + event_delay
|
||||
|
||||
log_debug("Next event of severity [GLOB.severity_to_string[severity]] in [(next_event_time - world.time)/600] minutes.")
|
||||
@@ -182,7 +183,6 @@ GLOBAL_LIST_EMPTY(event_last_fired)
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Swarmer Spawn", /datum/event/spawn_swarmer, 150, is_one_shot = TRUE),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Morph Spawn", /datum/event/spawn_morph, 40, list(ASSIGNMENT_SECURITY = 10), is_one_shot = TRUE),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Disease Outbreak", /datum/event/disease_outbreak, 0, list(ASSIGNMENT_MEDICAL = 150), TRUE),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Headcrabs", /datum/event/headcrabs, 0, list(ASSIGNMENT_SECURITY = 20)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Door Runtime", /datum/event/door_runtime, 50, list(ASSIGNMENT_ENGINEER = 25, ASSIGNMENT_AI = 150), TRUE)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
#define HEADCRAB_NORMAL 0
|
||||
#define HEADCRAB_FASTMIX 1
|
||||
#define HEADCRAB_FAST 2
|
||||
#define HEADCRAB_POISONMIX 3
|
||||
#define HEADCRAB_POISON 4
|
||||
#define HEADCRAB_SPAWNER 5
|
||||
|
||||
/datum/event/headcrabs
|
||||
announceWhen = 10
|
||||
endWhen = 11
|
||||
var/locstring
|
||||
var/headcrab_type
|
||||
|
||||
/datum/event/headcrabs/start()
|
||||
var/list/availableareas = list()
|
||||
for(var/area/maintenance/A in world)
|
||||
availableareas += A
|
||||
var/area/randomarea = pick(availableareas)
|
||||
var/list/turf/simulated/floor/turfs = list()
|
||||
for(var/turf/simulated/floor/F in randomarea)
|
||||
if(turf_clear(F))
|
||||
turfs += F
|
||||
var/list/spawn_types = list()
|
||||
var/max_number
|
||||
headcrab_type = rand(0, 5)
|
||||
switch(headcrab_type)
|
||||
if(HEADCRAB_NORMAL)
|
||||
spawn_types = list(/mob/living/simple_animal/hostile/headcrab)
|
||||
max_number = 6
|
||||
if(HEADCRAB_FASTMIX)
|
||||
spawn_types = list(/mob/living/simple_animal/hostile/headcrab, /mob/living/simple_animal/hostile/headcrab/fast)
|
||||
max_number = 8
|
||||
if(HEADCRAB_FAST)
|
||||
spawn_types = list(/mob/living/simple_animal/hostile/headcrab/fast)
|
||||
max_number = 6
|
||||
if(HEADCRAB_POISONMIX)
|
||||
spawn_types = list(/mob/living/simple_animal/hostile/headcrab, /mob/living/simple_animal/hostile/headcrab/poison)
|
||||
max_number = 4
|
||||
if(HEADCRAB_POISON)
|
||||
spawn_types = list(/mob/living/simple_animal/hostile/headcrab/poison)
|
||||
max_number = 3
|
||||
if(HEADCRAB_SPAWNER)
|
||||
spawn_types = list(/obj/structure/spawner/headcrab)
|
||||
max_number = 2
|
||||
|
||||
|
||||
var/num = rand(2,max_number)
|
||||
|
||||
while(turfs.len > 0 && num > 0)
|
||||
var/turf/simulated/floor/T = pick(turfs)
|
||||
turfs.Remove(T)
|
||||
num--
|
||||
var/spawn_type = pick(spawn_types)
|
||||
new spawn_type(T)
|
||||
|
||||
|
||||
/datum/event/headcrabs/announce()
|
||||
GLOB.event_announcement.Announce("Bioscans indicate that headcrabs have been breeding on the station. Clear them out, before this starts to affect productivity", "Lifesign Alert")
|
||||
|
||||
#undef HEADCRAB_NORMAL
|
||||
#undef HEADCRAB_FASTMIX
|
||||
#undef HEADCRAB_FAST
|
||||
#undef HEADCRAB_POISONMIX
|
||||
#undef HEADCRAB_POISON
|
||||
#undef HEADCRAB_SPAWNER
|
||||
@@ -21,7 +21,7 @@
|
||||
var/mob/living/simple_animal/SA = pick(potential)
|
||||
var/mob/SG = pick(candidates)
|
||||
|
||||
var/sentience_report = "<font size=3><b>[command_name()] Medium-Priority Update</b></font>"
|
||||
var/sentience_report = "<font size=3><b>NAS Trurl Medium-Priority Update</b></font>"
|
||||
|
||||
var/data = pick("scans from our long-range sensors", "our sophisticated probabilistic models", "our omnipotence", "the communications traffic on your station", "energy emissions we detected", "\[REDACTED\]", "Steve")
|
||||
var/pets = pick("animals", "pets", "simple animals", "lesser lifeforms", "\[REDACTED\]")
|
||||
@@ -40,7 +40,7 @@
|
||||
SA.health = SA.maxHealth
|
||||
SA.del_on_death = FALSE
|
||||
greet_sentient(SA)
|
||||
print_command_report(sentience_report, "[command_name()] Update", FALSE)
|
||||
print_command_report(sentience_report, "NAS Trurl Update", FALSE)
|
||||
|
||||
/datum/event/sentience/proc/greet_sentient(mob/living/carbon/human/M)
|
||||
to_chat(M, "<span class='userdanger'>Hello world!</span>")
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/S = new spider_type(vent.loc)
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
S.key = M.key
|
||||
to_chat(S, "<span class='motd'>For more information, check the wiki page: ([config.wikiurl]/index.php/Terror_Spider)</span>")
|
||||
to_chat(S, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Terror_Spider)</span>")
|
||||
spawncount--
|
||||
successSpawn = TRUE
|
||||
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
|
||||
/obj/machinery/atmospherics/pipe
|
||||
description_info = "This pipe, and all other pipes, can be connected or disconnected by a wrench. The internal pressure of the pipe must \
|
||||
be below 300 kPa to do this. More pipes can be obtained from the pipe dispenser."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/New() //This is needed or else 20+ lines of copypasta to dance around inheritence.
|
||||
..()
|
||||
description_info += "<br>Most pipes and atmospheric devices can be connected or disconnected with a wrench. The pipe's pressure must not be too high, \
|
||||
or if it is a device, it must be turned off first."
|
||||
|
||||
//HE pipes
|
||||
/obj/machinery/atmospherics/pipe/simple/heat_exchanging
|
||||
description_info = "This radiates heat from the pipe's gas to space, cooling it down."
|
||||
|
||||
//Supply/Scrubber pipes
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/scrubbers
|
||||
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/supply
|
||||
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/supply
|
||||
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers
|
||||
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
//Universal adapters
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/universal
|
||||
description_info = "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/universal
|
||||
description_info = "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes."
|
||||
|
||||
//Three way manifolds
|
||||
/obj/machinery/atmospherics/pipe/manifold
|
||||
description_info = "A normal pipe with three ends to connect to."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers
|
||||
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/visible/supply
|
||||
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers
|
||||
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold/hidden/supply
|
||||
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
//Insulated pipes
|
||||
/obj/machinery/atmospherics/pipe/simple/insulated
|
||||
description_info = "This is completely useless, use a normal pipe." //Sorry, but it's true.
|
||||
|
||||
//Four way manifolds
|
||||
/obj/machinery/atmospherics/pipe/manifold4w
|
||||
description_info = "This is a four-way pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers
|
||||
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply
|
||||
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers
|
||||
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
|
||||
a Universal Adapter pipe."
|
||||
|
||||
//Endcaps
|
||||
/obj/machinery/atmospherics/pipe/cap
|
||||
description_info = "This is a cosmetic attachment, as pipes currently do not spill their contents into the air."
|
||||
|
||||
//T-shaped valves
|
||||
/obj/machinery/atmospherics/trinary/tvalve
|
||||
description_info = "Click this to toggle the mode. The direction with the green light is where the gas will flow."
|
||||
|
||||
//Normal valves
|
||||
/obj/machinery/atmospherics/binary/valve
|
||||
description_info = "Click this to turn the valve. If red, the pipes on each end are separated. Otherwise, they are connected."
|
||||
|
||||
//TEG ports
|
||||
/obj/machinery/atmospherics/binary/circulator
|
||||
description_info = "This generates electricity, depending on the difference in temperature between each side of the machine. The meter in \
|
||||
the center of the machine gives an indicator of how much electricity is being generated."
|
||||
|
||||
//Passive gates
|
||||
/obj/machinery/atmospherics/binary/passive_gate
|
||||
description_info = "This is a one-way regulator, allowing gas to flow only at a specific pressure and flow rate. If the light is green, it is flowing."
|
||||
|
||||
//Normal pumps (high power one inherits from this)
|
||||
/obj/machinery/atmospherics/binary/pump
|
||||
description_info = "This moves gas from one pipe to another. A higher target pressure demands more energy. The side with the red end is the output."
|
||||
|
||||
//Vents
|
||||
/obj/machinery/atmospherics/unary/vent_pump
|
||||
description_info = "This pumps the contents of the attached pipe out into the atmosphere, if needed. It can be controlled from an Air Alarm."
|
||||
|
||||
//Freezer and Heater
|
||||
/obj/machinery/atmospherics/unary/thermomachine
|
||||
description_info = "Cools or heats the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \
|
||||
It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \
|
||||
screwdriver, and then using a crowbar."
|
||||
|
||||
//Gas injectors
|
||||
/obj/machinery/atmospherics/unary/outlet_injector
|
||||
description_info = "Outputs the pipe's gas into the atmosphere, similar to an air vent. It can be controlled by a nearby atmospherics computer. \
|
||||
A green light on it means it is on."
|
||||
|
||||
//Scrubbers
|
||||
/obj/machinery/atmospherics/unary/vent_scrubber
|
||||
description_info = "This filters the atmosphere of harmful gas. Filtered gas goes to the pipes connected to it, typically a scrubber pipe. \
|
||||
It can be controlled from an Air Alarm. It can be configured to drain all air rapidly with a 'panic syphon' from an air alarm."
|
||||
|
||||
//Canisters
|
||||
/obj/machinery/portable_atmospherics/canister
|
||||
description_info = "The canister can be connected to a connector port with a wrench. Tanks of gas (the kind you can hold in your hand) \
|
||||
can be filled by the canister, by using the tank on the canister, increasing the release pressure, then opening the valve until it is full, and then close it. \
|
||||
*DO NOT* remove the tank until the valve is closed. A gas analyzer can be used to check the contents of the canister."
|
||||
|
||||
description_antag = "Canisters can be damaged, spilling their contents into the air, or you can just leave the release valve open."
|
||||
|
||||
//Portable pumps
|
||||
/obj/machinery/portable_atmospherics/pump
|
||||
description_info = "Invaluable for filling air in a room rapidly after a breach repair. The internal gas container can be filled by \
|
||||
connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \
|
||||
replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the air pump."
|
||||
|
||||
//Portable scrubbers
|
||||
/obj/machinery/portable_atmospherics/scrubber
|
||||
description_info = "Filters the air, placing harmful gases into the internal gas container. The container can be emptied by \
|
||||
connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \
|
||||
replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the scrubber. "
|
||||
|
||||
//Meters
|
||||
/obj/machinery/meter
|
||||
description_info = "Measures the volume and temperature of the pipe under the meter."
|
||||
|
||||
//Pipe dispensers
|
||||
/obj/machinery/pipedispenser
|
||||
description_info = "This can be moved by using a wrench. You will need to wrench it again when you want to use it. You can put \
|
||||
excess (atmospheric) pipes into the dispenser, as well. The dispenser requires electricity to function."
|
||||
@@ -1,35 +0,0 @@
|
||||
/obj/machinery/power/supermatter_crystal
|
||||
description_info = "When energized by a laser (or something hitting it), it emits radiation and heat. If the heat reaches above 7000 kelvin, it will send an alert and start taking damage. \
|
||||
After integrity falls to zero percent, it will delaminate, causing a massive explosion, station-wide radiation spikes, and hallucinations. \
|
||||
Supermatter reacts badly to oxygen in the atmosphere. It'll also heat up really quick if it is in vacuum.<br>\
|
||||
<br>\
|
||||
Supermatter cores are extremely dangerous to be close to, and requires protection to handle properly. The protection you will need is:<br>\
|
||||
Optical meson scanners on your eyes, to prevent hallucinations when looking at the supermatter.<br>\
|
||||
Radiation helmet and suit, as the supermatter is radioactive.<br>\
|
||||
<br>\
|
||||
Touching the supermatter will result in *instant death*, with no corpse left behind! You can drag the supermatter, but anything else will kill you. \
|
||||
It is advised to obtain a genetic backup before trying to drag it."
|
||||
|
||||
description_antag = "Exposing the supermatter to oxygen or vacuum will cause it to start rapidly heating up. Sabotaging the supermatter and making it explode will \
|
||||
cause a period of lag as the explosion is processed by the server, as well as irradiating the entire station and causing hallucinations to happen. \
|
||||
Wearing radiation equipment will protect you from most of the delamination effects sans explosion."
|
||||
|
||||
/obj/machinery/power/apc
|
||||
description_info = "An APC (Area Power Controller) regulates and supplies backup power for the area they are in. Their power channels are divided \
|
||||
out into 'environmental' (Items that manipulate airflow and temperature), 'lighting' (the lights), and 'equipment' (Everything else that consumes power). \
|
||||
Power consumption and backup power cell charge can be seen from the interface, further controls (turning a specific channel on, off or automatic, \
|
||||
toggling the APC's ability to charge the backup cell, or toggling power for the entire area via master breaker) first requires the interface to be unlocked \
|
||||
with an ID with Engineering access or by one of the station's robots or the artificial intelligence."
|
||||
|
||||
description_antag = "This can be emagged to unlock it. It will cause the APC to have a blue error screen. \
|
||||
Wires can be pulsed remotely with a signaler attached to it. A powersink will also drain any APCs connected to the same wire the powersink is on."
|
||||
|
||||
/obj/item/inflatable
|
||||
description_info = "Inflate by using it in your hand. The inflatable barrier will inflate on your tile. To deflate it, use the 'deflate' verb."
|
||||
|
||||
/obj/structure/inflatable
|
||||
description_info = "To remove these safely, use the 'deflate' verb. Hitting these with any objects will probably puncture and break it forever."
|
||||
|
||||
/obj/structure/inflatable/door
|
||||
description_info = "Click the door to open or close it. It only stops air while closed.<br>\
|
||||
To remove these safely, use the 'deflate' verb. Hitting these with any objects will probably puncture and break it forever."
|
||||
@@ -1,42 +0,0 @@
|
||||
/obj/machinery/bodyscanner
|
||||
description_info = "The advanced scanner detects and reports internal injuries such as bone fractures, internal bleeding, and organ damage. \
|
||||
This is useful if you are about to perform surgery.<br>\
|
||||
<br>\
|
||||
Click your target with Grab intent, then click on the scanner to place them in it. Click the red terminal to operate. \
|
||||
Right-click the scanner and click 'Eject Occupant' to remove them. You can enter the scanner yourself in a similar way, using the 'Enter Body Scanner' \
|
||||
verb."
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell
|
||||
description_info = "The cryogenic chamber, or 'cryo', treats most damage types, most notably genetic damage. It also stabilizes patients \
|
||||
in critical condition by placing them in stasis, so they can be treated at a later time.<br>\
|
||||
<br>\
|
||||
In order for it to work, it must be loaded with chemicals, and the temperature of the solution must reach a certain point. Additionally, it \
|
||||
requires a supply of pure oxygen, provided by canisters that are attached. The most commonly used chemicals in the chambers is Cryoxadone, which \
|
||||
heals most damage types including genetic damage.<br>\
|
||||
<br>\
|
||||
Activating the freezer nearby, and setting it to a temperature setting below 150, is recommended before operation! Further, any clothing the patient \
|
||||
is wearing that act as an insulator will reduce its effectiveness, and should be removed.<br>\
|
||||
<br>\
|
||||
Clicking the tube with a beaker full of chemicals in hand will place it in its storage to distribute when it is activated.<br>\
|
||||
<br>\
|
||||
Click your target with Grab intent, then click on the tube, with an empty hand, to place them in it. Click the tube again to open the menu. \
|
||||
Press the button on the menu to activate it. Once they have reached 100 health, right-click the cell and click 'Eject Occupant' to remove them. \
|
||||
Remember to turn it off, once you've finished, to save power and chemicals!"
|
||||
|
||||
/obj/machinery/optable
|
||||
description_info = "Click your target with Grab intent, then click on the table with an empty hand, to place them on it."
|
||||
|
||||
/obj/machinery/computer/operating
|
||||
description_info = "This console gives information on the status of the patient on the adjacent operating table, notably their consciousness."
|
||||
|
||||
/obj/machinery/sleeper
|
||||
description_info = "The sleeper allows you to clean the blood by means of dialysis, and to administer medication in a controlled environment.<br>\
|
||||
<br>\
|
||||
Click your target with Grab intent, then click on the sleeper to place them in it. Click the green console, with an empty hand, to open the menu. \
|
||||
Click 'Start Dialysis' to begin filtering unwanted chemicals from the occupant's blood. The beaker contained will begin to fill with their \
|
||||
contaminated blood, and will need to be emptied when full.<br>\
|
||||
<br>\
|
||||
You can also inject common medicines directly into their bloodstream.\
|
||||
<br>\
|
||||
Right-click the cell and click 'Eject Occupant' to remove them. You can enter the cell yourself by right clicking and selecting 'Enter Sleeper'. \
|
||||
Note that you cannot control the sleeper while inside of it."
|
||||
@@ -1,8 +0,0 @@
|
||||
/mob/living/silicon/robot/drone
|
||||
description_info = "Drones are player-controlled synthetics which are lawed to maintain the station and not \
|
||||
interact with anyone else, except for other drones. They hold a wide array of tools to build, repair, maintain, and clean. \
|
||||
They function similarly to other synthetics, in that they require recharging regularly, have laws, and are resilient to many hazards, \
|
||||
such as fire, radiation, vacuum, and more. Ghosts can join the round as a maintenance drone by using the appropriate verb in the 'ghost' tab. \
|
||||
An inactive drone can be rebooted by swiping an ID card on it with engineering or robotics access."
|
||||
|
||||
description_antag = "An Electromagnetic Sequencer can be used to subvert the drone to your cause."
|
||||
@@ -1,24 +0,0 @@
|
||||
/obj/item/stack/rods
|
||||
description_info = "Made from metal sheets. You can build a grille by using it in your hand. \
|
||||
Clicking on a floor without any tiles will reinforce the floor. You can make reinforced glass by combining rods and normal glass sheets."
|
||||
|
||||
/obj/item/stack/sheet/glass
|
||||
description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets."
|
||||
|
||||
/obj/item/stack/sheet/glass/cyborg
|
||||
description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets.<br>\
|
||||
As a synthetic, you can acquire more sheets of glass by recharging."
|
||||
|
||||
/obj/item/stack/sheet/rglass
|
||||
description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage."
|
||||
|
||||
/obj/item/stack/sheet/rglass/cyborg
|
||||
description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage.<br>\
|
||||
As a synthetic, you can gain more reinforced glass by recharging."
|
||||
|
||||
/obj/item/stack/sheet/metal/cyborg
|
||||
description_info = "Use in your hand to bring up the recipe menu. If you have enough sheets, click on something on the list to build it.<br>\
|
||||
You can replenish your supply of metal as a synthetic by recharging."
|
||||
|
||||
/obj/item/stack/sheet
|
||||
description_info = "Use in your hand to bring up the recipe menu. If you have enough sheets, click on something on the list to build it."
|
||||
@@ -1,21 +0,0 @@
|
||||
/obj/structure/girder
|
||||
description_info = "Use metal sheets on this to build a normal wall. Adding plasteel instead will make a reinforced wall.<br>\
|
||||
A false wall can be made by using a crowbar on this girder, and then adding metal or plasteel.<br>\
|
||||
You can dismantle the girder with a wrench."
|
||||
|
||||
/obj/structure/girder/reinforced
|
||||
description_info = "Add another sheet of plasteel to finish."
|
||||
|
||||
/obj/structure/grille
|
||||
description_info = "A powered and knotted wire underneath this will cause the grille to shock anyone not wearing insulated gloves.<br>\
|
||||
Wirecutters will turn the grille into metal rods instantly. Grilles are made with metal rods."
|
||||
|
||||
/obj/structure/lattice
|
||||
description_info = "Add a metal floor tile to build a floor on top of the lattice.<br>\
|
||||
Lattices can be made by applying metal rods to a space tile."
|
||||
|
||||
/obj/structure/bed
|
||||
description_info = "Click and drag yourself (or anyone) to this to buckle in. Click on this with an empty hand to undo the buckles.<br>\
|
||||
<br>\
|
||||
Anyone with restraints, such as handcuffs, will not be able to unbuckle themselves. They must use the Resist button, or verb, to break free of \
|
||||
the buckles, instead."
|
||||
@@ -1,3 +0,0 @@
|
||||
/turf/simulated/wall
|
||||
description_info = "You can deconstruct this by welding it, and then wrenching the girder.<br>\
|
||||
You can build a wall by using metal sheets and making a girder, then adding more metal or plasteel."
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
Note: This file is meant for actual weapons (guns, swords, etc), and not the stupid 'every obj is a weapon, except when it's not' thing.
|
||||
*/
|
||||
|
||||
//******
|
||||
//*Guns*
|
||||
//******
|
||||
|
||||
//This contains a lot of copypasta but I'm told it's better then a lot of New()s appending the var.
|
||||
/obj/item/gun
|
||||
description_info = "This is a gun."
|
||||
|
||||
/obj/item/gun/energy
|
||||
description_info = "This is an energy weapon. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger."
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/crossbow
|
||||
description_info = "This is an energy weapon. To fire the weapon, have your gun mode set to 'fire', \
|
||||
then click where you want to fire."
|
||||
description_antag = "This is a stealthy weapon which fires poisoned bolts at your target. When it hits someone, they will suffer a stun effect, in \
|
||||
addition to toxins. The energy crossbow recharges itself slowly, and can be concealed in your pocket or bag."
|
||||
|
||||
/obj/item/gun/energy/gun
|
||||
description_info = "This is an energy weapon. Most energy weapons can fire through windows harmlessly. To switch between stun and lethal, click the weapon \
|
||||
in your hand. To recharge this weapon, use a weapon recharger."
|
||||
|
||||
/obj/item/gun/energy/gun/advtaser
|
||||
description_info = "This is an energy weapon. To recharge this weapon, use a weapon recharger. \
|
||||
To switch between insta-stun and disabler beams, click the weapon in your hand. This weapon can only fire through glass if it is set to disabler beams."
|
||||
|
||||
/obj/item/gun/energy/gun/nuclear
|
||||
description_info = "This is an energy weapon. Most energy weapons can fire through windows harmlessly. To switch between stun and lethal, click the weapon \
|
||||
in your hand. Unlike most weapons, this weapon recharges itself."
|
||||
|
||||
/obj/item/gun/energy/laser/captain
|
||||
description_info = "This is an energy weapon. Most energy weapons can fire through windows harmlessly. Unlike most weapons, this weapon recharges itself."
|
||||
|
||||
/obj/item/gun/energy/sniperrifle
|
||||
description_info = "This is an energy weapon. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger. \
|
||||
To use the scope, use the appropriate verb in the object tab."
|
||||
|
||||
/obj/item/gun/projectile
|
||||
description_info = "This is a ballistic weapon. To reload, click the weapon in your hand to unload (if needed), then add the appropriate ammo. The description \
|
||||
will tell you what caliber you need."
|
||||
|
||||
/obj/item/gun/projectile/shotgun/pump
|
||||
description_info = "This is a ballistic weapon. After firing, you will need to pump the gun, by clicking on the gun in your hand. To reload, load more shotgun \
|
||||
shells into the gun."
|
||||
|
||||
/obj/item/toy/russian_revolver/trick_revolver //oh no
|
||||
description_info = "This is a ballistic weapon. To reload, click the weapon in your hand to unload (if needed), then add the appropriate ammo. The description \
|
||||
will tell you what caliber you need."
|
||||
|
||||
//*******
|
||||
//*Melee*
|
||||
//*******
|
||||
|
||||
/obj/item/melee/baton
|
||||
description_info = "The baton needs to be turned on to apply the stunning effect. Use it in your hand to toggle it on or off. If your intent is \
|
||||
set to 'harm', you will inflict damage when using it, regardless if it is on or not. Each stun reduces the baton's charge, which can be replenished by \
|
||||
putting it inside a weapon recharger."
|
||||
|
||||
/obj/item/melee/energy/sword
|
||||
description_antag = "The energy sword is a very strong melee weapon, capable of severing limbs easily, if they are targeted. It can also has a chance \
|
||||
to block projectiles and melee attacks while it is on and being held. The sword can be toggled on or off by using it in your hand. While it is off, \
|
||||
it can be concealed in your pocket or bag."
|
||||
|
||||
/obj/item/melee/cultblade
|
||||
description_antag = "This sword is a powerful weapon, capable of severing limbs easily, if they are targeted. Nonbelievers are unable to use this weapon."
|
||||
@@ -1,62 +1,54 @@
|
||||
/* This code is responsible for the examine tab. When someone examines something, it copies the examined object's description_info,
|
||||
description_fluff, and description_antag, and shows it in a new tab.
|
||||
/**
|
||||
* Used for showing a more detailed description in the 'Examine' tab after examining the atom.
|
||||
*
|
||||
* Shown as blue text in the Examine tab.
|
||||
*/
|
||||
/atom/proc/detailed_examine()
|
||||
return null
|
||||
|
||||
In this file, some atom and mob stuff is defined here. It is defined here instead of in the normal files, to keep the whole system self-contained.
|
||||
This means that this file can be unchecked, along with the other examine files, and can be removed entirely with no effort.
|
||||
*/
|
||||
/**
|
||||
* Used for showing a more detailed description to antags in the 'Examine' after examining the atom.
|
||||
*
|
||||
* Shown as red text in the Examine tab.
|
||||
*/
|
||||
/atom/proc/detailed_examine_antag()
|
||||
return null
|
||||
|
||||
/**
|
||||
* Used for showing flavour text in the 'Examine' tab after examining the atom.
|
||||
*
|
||||
* Shown as green text in the Examine tab. The custom flavour text of `/mob` subtypes override this.
|
||||
*/
|
||||
/atom/proc/detailed_examine_fluff()
|
||||
return null
|
||||
|
||||
/atom/
|
||||
var/description_info = null //Helpful blue text.
|
||||
var/description_fluff = null //Green text about the atom's fluff, if any exists.
|
||||
var/description_antag = null //Malicious red text, for the antags.
|
||||
|
||||
//Override these if you need special behaviour for a specific type.
|
||||
/atom/proc/get_description_info()
|
||||
if(description_info)
|
||||
return description_info
|
||||
return
|
||||
|
||||
/atom/proc/get_description_fluff()
|
||||
if(description_fluff)
|
||||
return description_fluff
|
||||
return
|
||||
|
||||
/atom/proc/get_description_antag()
|
||||
if(description_antag)
|
||||
return description_antag
|
||||
return
|
||||
|
||||
/mob/living/get_description_fluff()
|
||||
/mob/detailed_examine_fluff()
|
||||
if(flavor_text) //Get flavor text for the green text.
|
||||
return flavor_text
|
||||
else //No flavor text? Try for hardcoded fluff instead.
|
||||
else //No flavor text? Try for hardcoded fluff instead.
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/get_description_fluff()
|
||||
/mob/living/carbon/human/detailed_examine_fluff()
|
||||
return print_flavor_text()
|
||||
|
||||
/* The examine panel itself */
|
||||
|
||||
/client/var/description_holders[0]
|
||||
|
||||
/client/proc/update_description_holders(atom/A, update_antag_info=0)
|
||||
description_holders["info"] = A.get_description_info()
|
||||
description_holders["fluff"] = A.get_description_fluff()
|
||||
description_holders["antag"] = (update_antag_info)? A.get_description_antag() : ""
|
||||
|
||||
/client/proc/update_description_holders(atom/A, update_antag_info = FALSE)
|
||||
description_holders["name"] = "[A.name]"
|
||||
description_holders["icon"] = "[bicon(A)]"
|
||||
description_holders["desc"] = A.desc
|
||||
|
||||
description_holders["info"] = A.detailed_examine()
|
||||
description_holders["fluff"] = A.detailed_examine_fluff()
|
||||
description_holders["antag"] = update_antag_info ? A.detailed_examine_antag() : null
|
||||
|
||||
// The examine panel itself
|
||||
/client/Stat()
|
||||
. = ..()
|
||||
if(usr && statpanel("Examine"))
|
||||
stat(null,"[description_holders["icon"]] <font size='5'>[description_holders["name"]]</font>") //The name, written in big letters.
|
||||
stat(null,"[description_holders["desc"]]") //the default examine text.
|
||||
stat(null, "<font size='5'>[description_holders["name"]]</font>") //The name, written in big letters.
|
||||
stat(null, "[description_holders["desc"]]") //the default examine text.
|
||||
if(description_holders["info"])
|
||||
stat(null,"<font color='#084B8A'><b>[description_holders["info"]]</b></font>") //Blue, informative text.
|
||||
stat(null, "<font color='#084B8A'><b>[description_holders["info"]]</b></font>") //Blue, informative text.
|
||||
if(description_holders["fluff"])
|
||||
stat(null,"<font color='#298A08'><b>[description_holders["fluff"]]</b></font>") //Yellow, fluff-related text.
|
||||
stat(null, "<font color='#298A08'><b>[description_holders["fluff"]]</b></font>") //Yellow, fluff-related text.
|
||||
if(description_holders["antag"])
|
||||
stat(null,"<font color='#8A0808'><b>[description_holders["antag"]]</b></font>") //Red, malicious antag-related text
|
||||
stat(null, "<font color='#8A0808'><b>[description_holders["antag"]]</b></font>") //Red, malicious antag-related text
|
||||
|
||||
@@ -293,9 +293,9 @@
|
||||
return 1
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/monkeycube/proc/Expand()
|
||||
if(LAZYLEN(SSmobs.cubemonkeys) >= config.cubemonkeycap)
|
||||
if(LAZYLEN(SSmobs.cubemonkeys) >= GLOB.configuration.general.monkey_cube_cap)
|
||||
if(fingerprintslast)
|
||||
to_chat(get_mob_by_ckey(fingerprintslast), "<span class='warning'>Bluespace harmonics prevent the spawning of more than [config.cubemonkeycap] monkeys on the station at one time!</span>")
|
||||
to_chat(get_mob_by_ckey(fingerprintslast), "<span class='warning'>Bluespace harmonics prevent the spawning of more than [GLOB.configuration.general.monkey_cube_cap] monkeys on the station at one time!</span>")
|
||||
else
|
||||
visible_message("<span class='notice'>[src] fails to expand!</span>")
|
||||
return
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
var/datum/wires/smartfridge/wires
|
||||
/// Typecache of accepted item types, init it in [/obj/machinery/smartfridge/Initialize].
|
||||
var/list/accepted_items_typecache
|
||||
/// Associative list (/obj/item => /number) representing the items the fridge should initially contain.
|
||||
var/list/starting_items
|
||||
/// The type of the circuitboard dropped on deconstruction. This is how to avoid getting subtypes into the board.
|
||||
var/board_type = /obj/machinery/smartfridge
|
||||
|
||||
/obj/machinery/smartfridge/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -44,8 +48,12 @@
|
||||
reagents.set_reacting(FALSE)
|
||||
// Components
|
||||
component_parts = list()
|
||||
|
||||
var/obj/item/circuitboard/smartfridge/board = new(null)
|
||||
board.set_type(null, type)
|
||||
if(board_type)
|
||||
board.set_type(null, board_type)
|
||||
else
|
||||
board.set_type(null, type)
|
||||
component_parts += board
|
||||
component_parts += new /obj/item/stock_parts/matter_bin(null)
|
||||
RefreshParts()
|
||||
@@ -54,6 +62,14 @@
|
||||
wires = new/datum/wires/smartfridge/secure(src)
|
||||
else
|
||||
wires = new/datum/wires/smartfridge(src)
|
||||
//Add starting items
|
||||
if(starting_items)
|
||||
for(var/typekey in starting_items)
|
||||
var/amount = starting_items[typekey] || 1
|
||||
while(amount--)
|
||||
var/obj/item/I = new typekey(src)
|
||||
item_quants[I.name] += 1
|
||||
update_icon()
|
||||
// Accepted items
|
||||
accepted_items_typecache = typecacheof(list(
|
||||
/obj/item/reagent_containers/food/snacks/grown,
|
||||
@@ -371,6 +387,7 @@
|
||||
desc = "When you need seeds fast!"
|
||||
icon = 'icons/obj/vending.dmi'
|
||||
icon_state = "seeds"
|
||||
board_type = /obj/machinery/smartfridge/seeds
|
||||
|
||||
/obj/machinery/smartfridge/seeds/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -378,6 +395,84 @@
|
||||
/obj/item/seeds
|
||||
))
|
||||
|
||||
/**
|
||||
* # Circuit Boards Storage
|
||||
*
|
||||
* Circuit variant of the [Smart Fridge][/obj/machinery/smartfridge].
|
||||
*
|
||||
*/
|
||||
/obj/machinery/smartfridge/secure/circuits
|
||||
name = "\improper Circuit Board Storage"
|
||||
desc = "A storage unit for circuits."
|
||||
icon_state = "circuits"
|
||||
visible_contents = TRUE
|
||||
board_type = /obj/machinery/smartfridge/secure/circuits
|
||||
|
||||
/obj/machinery/smartfridge/secure/circuits/Initialize(mapload)
|
||||
. = ..()
|
||||
accepted_items_typecache = typecacheof(list(
|
||||
/obj/item/aiModule,
|
||||
/obj/item/circuitboard
|
||||
))
|
||||
|
||||
/obj/machinery/smartfridge/secure/circuits/update_icon()
|
||||
var/prefix = initial(icon_state)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
icon_state = "[prefix]-off"
|
||||
else if(visible_contents)
|
||||
switch(length(contents))
|
||||
if(0)
|
||||
icon_state = "[prefix]"
|
||||
if(1 to 2)
|
||||
icon_state = "[prefix]1"
|
||||
if(3 to 5)
|
||||
icon_state = "[prefix]2"
|
||||
if(6 to INFINITY)
|
||||
icon_state = "[prefix]3"
|
||||
else
|
||||
icon_state = "[prefix]"
|
||||
|
||||
/obj/machinery/smartfridge/secure/circuits/aiupload
|
||||
name = "\improper AI Laws Storage"
|
||||
desc = "A storage unit filled with circuits to be uploaded to an Artificial Intelligence."
|
||||
board_type = /obj/machinery/smartfridge/secure/circuits/aiupload
|
||||
|
||||
/obj/machinery/smartfridge/secure/circuits/aiupload/Initialize(mapload)
|
||||
. = ..()
|
||||
req_access_txt = "[ACCESS_AI_UPLOAD]"
|
||||
|
||||
/obj/machinery/smartfridge/secure/circuits/aiupload/experimental
|
||||
name = "\improper Experimental Laws Storage"
|
||||
starting_items = list(
|
||||
/obj/item/aiModule/cctv = 1,
|
||||
/obj/item/aiModule/hippocratic = 1,
|
||||
/obj/item/aiModule/maintain = 1,
|
||||
/obj/item/aiModule/paladin = 1,
|
||||
/obj/item/aiModule/peacekeeper = 1,
|
||||
/obj/item/aiModule/quarantine = 1,
|
||||
/obj/item/aiModule/robocop = 1
|
||||
)
|
||||
|
||||
/obj/machinery/smartfridge/secure/circuits/aiupload/experimental/Initialize(mapload)
|
||||
. = ..()
|
||||
req_access_txt = "[ACCESS_RD]"
|
||||
|
||||
/obj/machinery/smartfridge/secure/circuits/aiupload/highrisk
|
||||
name = "\improper High-Risk Laws Storage"
|
||||
starting_items = list(
|
||||
/obj/item/aiModule/freeform = 1,
|
||||
/obj/item/aiModule/freeformcore = 1,
|
||||
/obj/item/aiModule/nanotrasen_aggressive = 1,
|
||||
/obj/item/aiModule/oneCrewMember = 1,
|
||||
/obj/item/aiModule/protectStation = 1,
|
||||
/obj/item/aiModule/purge = 1,
|
||||
/obj/item/aiModule/tyrant = 1
|
||||
)
|
||||
|
||||
/obj/machinery/smartfridge/secure/circuits/aiupload/highrisk/Initialize(mapload)
|
||||
. = ..()
|
||||
req_access_txt = "[ACCESS_CAPTAIN]"
|
||||
|
||||
/**
|
||||
* # Refrigerated Medicine Storage
|
||||
*
|
||||
@@ -387,6 +482,7 @@
|
||||
name = "\improper Refrigerated Medicine Storage"
|
||||
desc = "A refrigerated storage unit for storing medicine and chemicals."
|
||||
icon_state = "smartfridge" //To fix the icon in the map editor.
|
||||
board_type = /obj/machinery/smartfridge/medbay
|
||||
|
||||
/obj/machinery/smartfridge/medbay/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -406,6 +502,7 @@
|
||||
/obj/machinery/smartfridge/secure/extract
|
||||
name = "\improper Slime Extract Storage"
|
||||
desc = "A refrigerated storage unit for slime extracts"
|
||||
board_type = /obj/machinery/smartfridge/secure/extract
|
||||
|
||||
/obj/machinery/smartfridge/secure/extract/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -424,6 +521,7 @@
|
||||
desc = "A refrigerated storage unit for storing medicine and chemicals."
|
||||
icon_state = "smartfridge" //To fix the icon in the map editor.
|
||||
req_one_access_txt = "5;33"
|
||||
board_type = /obj/machinery/smartfridge/secure/medbay
|
||||
|
||||
/obj/machinery/smartfridge/secure/medbay/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -444,21 +542,11 @@
|
||||
name = "\improper Smart Chemical Storage"
|
||||
desc = "A refrigerated storage unit for medicine and chemical storage."
|
||||
icon_state = "smartfridge" //To fix the icon in the map editor.
|
||||
/// Associative list (/obj/item => /number) representing the items the fridge should initially contain.
|
||||
var/list/spawn_meds
|
||||
board_type = /obj/machinery/smartfridge/secure/chemistry
|
||||
|
||||
/obj/machinery/smartfridge/secure/chemistry/Initialize(mapload)
|
||||
. = ..()
|
||||
req_access_txt = "[ACCESS_CHEMISTRY]"
|
||||
// Spawn initial chemicals
|
||||
if(mapload)
|
||||
LAZYINITLIST(spawn_meds)
|
||||
for(var/typekey in spawn_meds)
|
||||
var/amount = spawn_meds[typekey] || 1
|
||||
while(amount--)
|
||||
var/obj/item/I = new typekey(src)
|
||||
item_quants[I.name] += 1
|
||||
update_icon()
|
||||
// Accepted items
|
||||
accepted_items_typecache = typecacheof(list(
|
||||
/obj/item/storage/pill_bottle,
|
||||
@@ -474,7 +562,7 @@
|
||||
// I exist!
|
||||
|
||||
/obj/machinery/smartfridge/secure/chemistry/preloaded/Initialize(mapload)
|
||||
spawn_meds = list(
|
||||
starting_items = list(
|
||||
/obj/item/reagent_containers/food/pill/epinephrine = 12,
|
||||
/obj/item/reagent_containers/food/pill/charcoal = 5,
|
||||
/obj/item/reagent_containers/glass/bottle/epinephrine = 1,
|
||||
@@ -505,6 +593,7 @@
|
||||
icon_state = "disktoaster"
|
||||
pass_flags = PASSTABLE
|
||||
visible_contents = FALSE
|
||||
board_type = /obj/machinery/smartfridge/disks
|
||||
|
||||
/obj/machinery/smartfridge/disks/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -516,21 +605,14 @@
|
||||
* # Smart Virus Storage
|
||||
*
|
||||
* Secure, Virology variant of the [Smart Chemical Storage][/obj/machinery/smartfridge/secure/chemistry].
|
||||
* Comes with some items.
|
||||
*
|
||||
*/
|
||||
/obj/machinery/smartfridge/secure/chemistry/virology
|
||||
name = "\improper Smart Virus Storage"
|
||||
desc = "A refrigerated storage unit for volatile sample storage."
|
||||
board_type = /obj/machinery/smartfridge/secure/chemistry/virology
|
||||
|
||||
/obj/machinery/smartfridge/secure/chemistry/virology/Initialize(mapload)
|
||||
spawn_meds = list(
|
||||
/obj/item/reagent_containers/syringe/antiviral = 4,
|
||||
/obj/item/reagent_containers/glass/bottle/cold = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/flu_virion = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/mutagen = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/plasma = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/diphenhydramine = 1
|
||||
)
|
||||
. = ..()
|
||||
req_access_txt = "[ACCESS_VIROLOGY]"
|
||||
accepted_items_typecache = typecacheof(list(
|
||||
@@ -548,14 +630,13 @@
|
||||
// I exist!
|
||||
|
||||
/obj/machinery/smartfridge/secure/chemistry/virology/preloaded/Initialize(mapload)
|
||||
spawn_meds = list(
|
||||
starting_items = list(
|
||||
/obj/item/reagent_containers/syringe/antiviral = 4,
|
||||
/obj/item/reagent_containers/glass/bottle/cold = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/flu_virion = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/mutagen = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/plasma = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/reagent/synaptizine = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/reagent/formaldehyde = 1
|
||||
/obj/item/reagent_containers/glass/bottle/diphenhydramine = 1
|
||||
)
|
||||
. = ..()
|
||||
|
||||
@@ -568,6 +649,15 @@
|
||||
req_access_txt = null
|
||||
|
||||
/obj/machinery/smartfridge/secure/chemistry/virology/preloaded/syndicate/Initialize(mapload)
|
||||
starting_items = list(
|
||||
/obj/item/reagent_containers/syringe/antiviral = 4,
|
||||
/obj/item/reagent_containers/glass/bottle/cold = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/flu_virion = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/mutagen = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/plasma = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/reagent/synaptizine = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/reagent/formaldehyde = 1
|
||||
)
|
||||
. = ..()
|
||||
req_access = list(ACCESS_SYNDICATE)
|
||||
|
||||
@@ -579,6 +669,7 @@
|
||||
/obj/machinery/smartfridge/drinks
|
||||
name = "\improper Drink Showcase"
|
||||
desc = "A refrigerated storage unit for tasty tasty alcohol."
|
||||
board_type = /obj/machinery/smartfridge/drinks
|
||||
|
||||
/obj/machinery/smartfridge/drinks/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
var/obj/machinery/hydroponics/parent = loc
|
||||
var/make_podman = 0
|
||||
var/ckey_holder = null
|
||||
if(config.revival_pod_plants)
|
||||
if(GLOB.configuration.general.enable_revival_pod_plants)
|
||||
if(ckey)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(isobserver(M))
|
||||
|
||||
+24
-25
@@ -16,7 +16,7 @@
|
||||
return
|
||||
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("karma")] (spendername, spenderkey, receivername, receiverkey, receiverrole, receiverspecial, spenderip, time)
|
||||
INSERT INTO karma (spendername, spenderkey, receivername, receiverkey, receiverrole, receiverspecial, spenderip, time)
|
||||
VALUES (:sname, :skey, :rname, :rkey, :rrole, :rspecial, :sip, Now())"}, list(
|
||||
"sname" = spender.name,
|
||||
"skey" = spender.ckey,
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
qdel(log_query)
|
||||
|
||||
var/datum/db_query/select_spender = SSdbcore.NewQuery("SELECT id, karma FROM [format_table_name("karmatotals")] WHERE byondkey=:rkey", list(
|
||||
var/datum/db_query/select_spender = SSdbcore.NewQuery("SELECT id, karma FROM karmatotals WHERE byondkey=:rkey", list(
|
||||
"rkey" = receiver.ckey
|
||||
))
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
if(karma == null)
|
||||
karma = 1
|
||||
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO [format_table_name("karmatotals")] (byondkey, karma) VALUES (:rkey, :karma)", list(
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO karmatotals (byondkey, karma) VALUES (:rkey, :karma)", list(
|
||||
"rkey" = receiver.ckey,
|
||||
"karma" = karma
|
||||
))
|
||||
@@ -62,7 +62,7 @@
|
||||
qdel(insert_query)
|
||||
else
|
||||
karma++
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE [format_table_name("karmatotals")] SET karma=:karma WHERE id=:id", list(
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE karmatotals SET karma=:karma WHERE id=:id", list(
|
||||
"karma" = karma,
|
||||
"id" = id
|
||||
))
|
||||
@@ -78,7 +78,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
if(!client)
|
||||
to_chat(src, "<span class='warning'>You can't award karma without being connected.</span>")
|
||||
return FALSE
|
||||
if(config.disable_karma)
|
||||
if(!GLOB.configuration.general.enable_karma)
|
||||
to_chat(src, "<span class='warning'>Karma is disabled.</span>")
|
||||
return FALSE
|
||||
if(!SSticker || !GLOB.player_list.len || (SSticker.current_state == GAME_STATE_PREGAME))
|
||||
@@ -152,7 +152,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
if(!M)
|
||||
to_chat(usr, "Please right click a mob to award karma directly, or use the 'Award Karma' verb to select a player from the player listing.")
|
||||
return
|
||||
if(config.disable_karma) // this is here because someone thought it was a good idea to add an alert box before checking if they can even give a mob karma
|
||||
if(!GLOB.configuration.general.enable_karma) // this is here because someone thought it was a good idea to add an alert box before checking if they can even give a mob karma
|
||||
to_chat(usr, "<span class='warning'>Karma is disabled.</span>")
|
||||
return
|
||||
if(alert("Give [M.name] good karma?", "Karma", "Yes", "No") != "Yes")
|
||||
@@ -160,20 +160,19 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
if(!can_give_karma_to_mob(M))
|
||||
return // Check again, just in case things changed while the alert box was up
|
||||
|
||||
M.client.karma++
|
||||
to_chat(usr, "Good karma spent on [M.name].")
|
||||
client.karma_spent = TRUE
|
||||
GLOB.karma_spenders += ckey
|
||||
|
||||
var/special_role = "None"
|
||||
var/assigned_role = "None"
|
||||
var/karma_diary = file("[GLOB.log_directory]/karma.log")
|
||||
if(M.mind)
|
||||
if(M.mind.special_role)
|
||||
special_role = M.mind.special_role
|
||||
if(M.mind.assigned_role)
|
||||
assigned_role = M.mind.assigned_role
|
||||
karma_diary << "[M.name] ([M.key]) [assigned_role]/[special_role]: [M.client.karma] - [time2text(world.timeofday, "hh:mm:ss")] given by [key]"
|
||||
|
||||
rustg_log_write("[GLOB.log_directory]/karma.log", "Karma awarded to [M.name] ([M.key]) (Role: [assigned_role] | Special: [special_role]) - Awarded by [ckey]")
|
||||
|
||||
sql_report_karma(src, M)
|
||||
|
||||
@@ -182,7 +181,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
set desc = "Reports how much karma you have accrued."
|
||||
set category = "Special Verbs"
|
||||
|
||||
if(config.disable_karma)
|
||||
if(!GLOB.configuration.general.enable_karma)
|
||||
to_chat(src, "<span class='warning'>Karma is disabled.</span>")
|
||||
return
|
||||
|
||||
@@ -196,7 +195,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
to_chat(usr, "<span class='warning'>Unable to connect to karma database. Please try again later.<br></span>")
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT karma, karmaspent FROM [format_table_name("karmatotals")] WHERE byondkey=:ckey", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT karma, karmaspent FROM karmatotals WHERE byondkey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -218,13 +217,13 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
set desc = "Spend your hard-earned karma here"
|
||||
set hidden = TRUE
|
||||
|
||||
if(config.disable_karma)
|
||||
if(!GLOB.configuration.general.enable_karma)
|
||||
to_chat(src, "<span class='warning'>Karma is disabled.</span>")
|
||||
return
|
||||
karmashopmenu()
|
||||
|
||||
/client/proc/karmashopmenu()
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, job, species FROM [format_table_name("whitelist")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, job, species FROM whitelist WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -382,7 +381,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
karmashopmenu()
|
||||
|
||||
/client/proc/DB_job_unlock(job, cost)
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT ckey, job FROM [format_table_name("whitelist")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT ckey, job FROM whitelist WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!select_query.warn_execute())
|
||||
@@ -397,7 +396,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
|
||||
qdel(select_query)
|
||||
if(!dbckey)
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO [format_table_name("whitelist")] (ckey, job) VALUES (:ckey, :job)", list(
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO whitelist (ckey, job) VALUES (:ckey, :job)", list(
|
||||
"ckey" = ckey,
|
||||
"job" = job
|
||||
))
|
||||
@@ -416,7 +415,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
if(!(job in joblist))
|
||||
joblist += job
|
||||
var/newjoblist = jointext(joblist,",")
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE [format_table_name("whitelist")] SET job=:newjoblist WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE whitelist SET job=:newjoblist WHERE ckey=:ckey", list(
|
||||
"newjoblist" = newjoblist,
|
||||
"ckey" = ckey
|
||||
))
|
||||
@@ -433,7 +432,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
return
|
||||
|
||||
/client/proc/DB_species_unlock(species, cost)
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT ckey, species FROM [format_table_name("whitelist")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT ckey, species FROM whitelist WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!select_query.warn_execute())
|
||||
@@ -447,7 +446,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
dbspecies = select_query.item[2]
|
||||
qdel(select_query)
|
||||
if(!dbckey)
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO [format_table_name("whitelist")] (ckey, species) VALUES (:ckey, :species)", list(
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO whitelist (ckey, species) VALUES (:ckey, :species)", list(
|
||||
"ckey" = ckey,
|
||||
"species" = species
|
||||
))
|
||||
@@ -465,7 +464,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
if(!(species in specieslist))
|
||||
specieslist += species
|
||||
var/newspecieslist = jointext(specieslist,",")
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE [format_table_name("whitelist")] SET species=:newspecieslist WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE whitelist SET species=:newspecieslist WHERE ckey=:ckey", list(
|
||||
"newspecieslist" = newspecieslist,
|
||||
"ckey" = ckey
|
||||
))
|
||||
@@ -482,7 +481,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
return
|
||||
|
||||
/client/proc/karmacharge(cost, refund = FALSE)
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT karmaspent FROM [format_table_name("karmatotals")] WHERE byondkey=:ckey", list(
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT karmaspent FROM karmatotals WHERE byondkey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!select_query.warn_execute())
|
||||
@@ -495,7 +494,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
spent -= cost
|
||||
else
|
||||
spent += cost
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE [format_table_name("karmatotals")] SET karmaspent=:spent WHERE byondkey=:ckey", list(
|
||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE karmatotals SET karmaspent=:spent WHERE byondkey=:ckey", list(
|
||||
"spent" = spent,
|
||||
"ckey" = ckey
|
||||
))
|
||||
@@ -521,7 +520,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
to_chat(usr, "<span class='warning'>That job is not refundable.</span>")
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, job, species FROM [format_table_name("whitelist")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, job, species FROM whitelist WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -544,10 +543,10 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
switch(type)
|
||||
if("job")
|
||||
typelist = splittext(dbjob,",")
|
||||
statement = "UPDATE [format_table_name("whitelist")] SET job=:newtypelist WHERE ckey=:ckey"
|
||||
statement = "UPDATE whitelist SET job=:newtypelist WHERE ckey=:ckey"
|
||||
if("species")
|
||||
typelist = splittext(dbspecies,",")
|
||||
statement = "UPDATE [format_table_name("whitelist")] SET species=:newtypelist WHERE ckey=:ckey"
|
||||
statement = "UPDATE whitelist SET species=:newtypelist WHERE ckey=:ckey"
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Type [type] is not a valid column.</span>")
|
||||
|
||||
@@ -573,7 +572,7 @@ GLOBAL_LIST_EMPTY(karma_spenders)
|
||||
to_chat(usr, "<span class='warning'>Your ckey ([dbckey]) was not found.</span>")
|
||||
|
||||
/client/proc/checkpurchased(name = null) // If the first parameter is null, return a full list of purchases
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, job, species FROM [format_table_name("whitelist")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, job, species FROM whitelist WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
if(!isbn)
|
||||
return
|
||||
|
||||
var/datum/db_query/query_delbook = SSdbcore.NewQuery("DELETE FROM [format_table_name("library")] WHERE id=:isbn", list(
|
||||
var/datum/db_query/query_delbook = SSdbcore.NewQuery("DELETE FROM library WHERE id=:isbn", list(
|
||||
"isbn" = text2num(isbn) // just to be sure
|
||||
))
|
||||
if(!query_delbook.warn_execute())
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
var/dat = "<table><tr><th>ISBN</th><th>Title</th><th>Total Flags</th><th>Options</th></tr>"
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, title, flagged FROM [format_table_name("library")] WHERE flagged > 0 ORDER BY flagged DESC")
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, title, flagged FROM library WHERE flagged > 0 ORDER BY flagged DESC")
|
||||
if(!query.warn_execute())
|
||||
qdel(query)
|
||||
return
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
// This one doesnt take player input directly, so it doesnt require params
|
||||
searchquery += " [!where ? "WHERE" : "AND"] flagged < [MAX_BOOK_FLAGS]"
|
||||
// This does though
|
||||
var/sql = "SELECT id, author, title, category, ckey, flagged FROM [format_table_name("library")] [searchquery] LIMIT :lowerlimit, :upperlimit"
|
||||
var/sql = "SELECT id, author, title, category, ckey, flagged FROM library [searchquery] LIMIT :lowerlimit, :upperlimit"
|
||||
sql_params["lowerlimit"] = text2num((page_num - 1) * LIBRARY_BOOKS_PER_PAGE)
|
||||
sql_params["upperlimit"] = LIBRARY_BOOKS_PER_PAGE
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
return results
|
||||
|
||||
/obj/machinery/computer/library/proc/get_num_results()
|
||||
var/sql = "SELECT COUNT(id) FROM [format_table_name("library")]"
|
||||
var/sql = "SELECT COUNT(id) FROM library"
|
||||
|
||||
var/datum/db_query/count_query = SSdbcore.NewQuery(sql)
|
||||
if(!count_query.warn_execute())
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
var/datum/cachedbook/target = getBookByID(href_list["del"]) // Sanitized in getBookByID
|
||||
var/ans = alert(usr, "Are you sure you wish to delete \"[target.title]\", by [target.author]? This cannot be undone.", "Library System", "Yes", "No")
|
||||
if(ans=="Yes")
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM [format_table_name("library")] WHERE id=:id", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM library WHERE id=:id", list(
|
||||
"id" = text2num(target.id)
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -280,7 +280,7 @@
|
||||
var/tckey = ckey(href_list["delbyckey"])
|
||||
var/ans = alert(usr,"Are you sure you wish to delete all books by [tckey]? This cannot be undone.", "Library System", "Yes", "No")
|
||||
if(ans=="Yes")
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM [format_table_name("library")] WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM library WHERE ckey=:ckey", list(
|
||||
"ckey" = tckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -387,7 +387,7 @@
|
||||
alert("Connection to Archive has been severed. Aborting.")
|
||||
else
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("library")] (author, title, content, category, ckey, flagged)
|
||||
INSERT INTO library (author, title, content, category, ckey, flagged)
|
||||
VALUES (:author, :title, :content, :category, :ckey, 0)"}, list(
|
||||
"author" = scanner.cache.author,
|
||||
"title" = scanner.cache.name,
|
||||
|
||||
@@ -78,7 +78,7 @@ GLOBAL_LIST_INIT(library_section_names, list("Any", "Fiction", "Non-Fiction", "A
|
||||
books_flagged_this_round["[id]"] = 1
|
||||
message_admins("[key_name_admin(user)] has flagged book #[id] as inappropriate.")
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("UPDATE [format_table_name("library")] SET flagged = flagged + 1 WHERE id=:id", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("UPDATE library SET flagged = flagged + 1 WHERE id=:id", list(
|
||||
"id" = text2num(id)
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -93,7 +93,7 @@ GLOBAL_LIST_INIT(library_section_names, list("Any", "Fiction", "Non-Fiction", "A
|
||||
to_chat(user, "<span class='danger'>That book cannot be removed from the system, as it does not actually exist in the database.</span>")
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM [format_table_name("library")] WHERE id=:id", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM library WHERE id=:id", list(
|
||||
"id" = text2num(id)
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -105,7 +105,7 @@ GLOBAL_LIST_INIT(library_section_names, list("Any", "Fiction", "Non-Fiction", "A
|
||||
if("[id]" in cached_books)
|
||||
return cached_books["[id]"]
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, author, title, category, content, ckey, flagged FROM [format_table_name("library")] WHERE id=:id", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, author, title, category, content, ckey, flagged FROM library WHERE id=:id", list(
|
||||
"id" = text2num(id)
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user