Merge branch 'master' into fix-stuff

This commit is contained in:
mochi
2020-08-07 10:07:18 +02:00
1233 changed files with 71721 additions and 374898 deletions
+3 -3
View File
@@ -146,7 +146,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
if(kickbannedckey)
if(banned_mob && banned_mob.client && banned_mob.client.ckey == banckey)
del(banned_mob.client)
qdel(banned_mob.client)
if(isjobban)
jobban_client_fullban(ckey, job)
@@ -211,7 +211,7 @@ datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "")
query.Execute()
while(query.NextRow())
ban_id = query.item[1]
ban_number++;
ban_number++
if(ban_number == 0)
to_chat(usr, "<span class='warning'>Database update failed due to no bans fitting the search criteria. If this is not a legacy ban you should contact the database admin.</span>")
@@ -314,7 +314,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
query.Execute()
while(query.NextRow())
pckey = query.item[1]
ban_number++;
ban_number++
if(ban_number == 0)
to_chat(usr, "<span class='warning'>Database update failed due to a ban id not being present in the database.</span>")
-11
View File
@@ -36,17 +36,6 @@ world/IsBanned(key, address, computer_id, type, check_ipintel = TRUE)
// message_admins("<span class='notice'>Failed Login: [key] - Guests not allowed</span>")
return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a BYOND account.")
//check if the IP address is a known Tor node
if(config.ToRban && ToRban_isbanned(address))
log_adminwarn("Failed Login: [key] [computer_id] [address] - Banned: Tor")
message_admins("<span class='adminnotice'>Failed Login: [key] - Banned: Tor</span>")
//ban their computer_id and ckey for posterity
AddBan(ckey(key), computer_id, "Use of Tor", "Automated Ban", 0, 0)
var/mistakemessage = ""
if(config.banappeals)
mistakemessage = "\nIf you believe this is a mistake, please request help at [config.banappeals]."
return list("reason"="using Tor", "desc"="\nReason: The network you are using to connect has been banned.[mistakemessage]")
//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))
log_adminwarn("Failed Login: [key] [computer_id] [address] - Proxy/VPN")
-3
View File
@@ -58,9 +58,6 @@ GLOBAL_PROTECT(banlist_savefile) // Obvious reasons
GLOB.CMinutes = (world.realtime / 10) / 60
return 1
/hook/startup/proc/loadBans()
return LoadBans()
/proc/LoadBans()
GLOB.banlist_savefile = new("data/banlist.bdb")
-89
View File
@@ -1,89 +0,0 @@
//By Carnwennan
//fetches an external list and processes it into a list of ip addresses.
//It then stores the processed list into a savefile for later use
#define TORFILE "data/ToR_ban.bdb"
#define TOR_UPDATE_INTERVAL 216000 //~6 hours
/proc/ToRban_isbanned(var/ip_address)
var/savefile/F = new(TORFILE)
if(F)
if( ip_address in F.dir )
return 1
return 0
/proc/ToRban_autoupdate()
var/savefile/F = new(TORFILE)
if(F)
var/last_update
F["last_update"] >> last_update
if((last_update + TOR_UPDATE_INTERVAL) < world.realtime) //we haven't updated for a while
ToRban_update()
return
/proc/ToRban_update()
spawn(0)
log_world("Downloading updated ToR data...")
var/http[] = world.Export("http://exitlist.torproject.org/exit-addresses")
var/list/rawlist = file2list(http["CONTENT"])
if(rawlist.len)
fdel(TORFILE)
var/savefile/F = new(TORFILE)
for( var/line in rawlist )
if(!line) continue
if( copytext(line,1,12) == "ExitAddress" )
var/cleaned = copytext(line,13,length(line)-19)
if(!cleaned) continue
F[cleaned] << 1
to_chat(F["last_update"], world.realtime)
log_world("ToR data updated!")
if(usr)
to_chat(usr, "ToRban updated.")
return 1
log_world("ToR data update aborted: no data.")
return 0
/client/proc/ToRban(task in list("update","toggle","show","remove","remove all","find"))
set name = "ToRban"
set category = "Server"
if(!holder) return
switch(task)
if("update")
ToRban_update()
if("toggle")
if(config)
if(config.ToRban)
config.ToRban = 0
message_admins("<font color='red'>ToR banning disabled.</font>")
else
config.ToRban = 1
message_admins("<font colot='green'>ToR banning enabled.</font>")
if("show")
var/savefile/F = new(TORFILE)
var/dat
if( length(F.dir) )
for( var/i=1, i<=length(F.dir), i++ )
dat += "<tr><td>#[i]</td><td> [F.dir[i]]</td></tr>"
dat = "<table width='100%'>[dat]</table>"
else
dat = "No addresses in list."
src << browse(dat,"window=ToRban_show")
if("remove")
var/savefile/F = new(TORFILE)
var/choice = input(src,"Please select an IP address to remove from the ToR banlist:","Remove ToR ban",null) as null|anything in F.dir
if(choice)
F.dir.Remove(choice)
to_chat(src, "<b>Address removed</b>")
if("remove all")
to_chat(src, "<b>[TORFILE] was [fdel(TORFILE)?"":"not "]removed.</b>")
if("find")
var/input = input(src,"Please input an IP address to search for:","Find ToR ban",null) as null|text
if(input)
if(ToRban_isbanned(input))
to_chat(src, "<font color='green'><b>Address is a known ToR address</b></font>")
else
to_chat(src, "<font color='red'><b>Address is not a known ToR address</b></font>")
return
#undef TORFILE
#undef TOR_UPDATE_INTERVAL
+4 -4
View File
@@ -72,7 +72,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\] "
body += "\[<A href='?_src_=holder;getplaytimewindow=[M.UID()]'>" + M.client.get_exp_type(EXP_TYPE_CREW) + " as [EXP_TYPE_CREW]</a>\]"
if(istype(M, /mob/new_player))
if(isnewplayer(M))
body += " <B>Hasn't Entered Game</B> "
else
body += " \[<A href='?_src_=holder;revive=[M.UID()]'>Heal</A>\] "
@@ -147,7 +147,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
body += {" | <A href='?_src_=holder;cryossd=[M.UID()]'>Cryo</A> "}
if(M.client)
if(!istype(M, /mob/new_player))
if(!isnewplayer(M))
body += "<br><br>"
body += "<b>Transformation:</b>"
body += "<br>"
@@ -1004,13 +1004,13 @@ GLOBAL_VAR_INIT(gamma_ship_location, 1) // 0 = station , 1 = space
/proc/kick_clients_in_lobby(message, kick_only_afk = 0)
var/list/kicked_client_names = list()
for(var/client/C in GLOB.clients)
if(istype(C.mob, /mob/new_player))
if(isnewplayer(C.mob))
if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk
continue
if(message)
to_chat(C, message)
kicked_client_names.Add("[C.ckey]")
del(C)
qdel(C)
return kicked_client_names
//returns 1 to let the dragdrop code know we are trapping this event
-4
View File
@@ -11,10 +11,6 @@
/proc/investigate_subject2file(var/subject)
return file("[INVESTIGATE_DIR][subject].html")
/hook/startup/proc/resetInvestigate()
investigate_reset()
return 1
/proc/investigate_reset()
if(fdel(INVESTIGATE_DIR)) return 1
return 0
+15 -4
View File
@@ -56,11 +56,12 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
testing(msg)
#endif
/hook/startup/proc/loadAdmins()
load_admins()
return 1
/proc/load_admins()
if(IsAdminAdvancedProcCall())
to_chat(usr, "<span class='boldannounce'>Admin reload blocked: Advanced ProcCall detected.</span>")
message_admins("[key_name(usr)] attempted to reload admins via advanced proc-call")
log_admin("[key_name(usr)] attempted to reload admins via advanced proc-call")
return
//clear the datums references
GLOB.admin_datums.Cut()
for(var/client/C in GLOB.admins)
@@ -68,6 +69,10 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
C.holder = null
GLOB.admins.Cut()
// Remove all profiler access
for(var/A in world.GetConfig("admin"))
world.SetConfig("APP/admin", A, null)
if(config.admin_legacy_system)
load_admin_ranks()
@@ -98,6 +103,9 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
//create the admin datum and store it for later use
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
if(D.rights & R_DEBUG || D.rights & R_VIEWRUNTIMES) // Grants profiler access to anyone with R_DEBUG or R_VIEWRUNTIMES
world.SetConfig("APP/admin", ckey, "role=admin")
//find the client for a ckey if they are connected and associate them with the new admin datum
D.associate(GLOB.directory[ckey])
@@ -122,6 +130,9 @@ GLOBAL_PROTECT(admin_ranks) // this shit is being protected for obvious reasons
if(istext(rights)) rights = text2num(rights)
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
if(D.rights & R_DEBUG || D.rights & R_VIEWRUNTIMES) // Grants profiler access to anyone with R_DEBUG or R_VIEWRUNTIMES
world.SetConfig("APP/admin", ckey, "role=admin")
//find the client for a ckey if they are connected and associate them with the new admin datum
D.associate(GLOB.directory[ckey])
if(!GLOB.admin_datums)
+10 -6
View File
@@ -125,7 +125,6 @@ GLOBAL_LIST_INIT(admin_verbs_spawn, list(
/client/proc/admin_deserialize
))
GLOBAL_LIST_INIT(admin_verbs_server, list(
/client/proc/ToRban,
/client/proc/Set_Holiday,
/datum/admins/proc/startnow,
/datum/admins/proc/restart,
@@ -247,6 +246,8 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
verbs += GLOB.admin_verbs_server
if(holder.rights & R_DEBUG)
verbs += GLOB.admin_verbs_debug
spawn(1)
control_freak = 0 // Setting control_freak to 0 allows you to use the Profiler and other client-side tools
if(holder.rights & R_POSSESS)
verbs += GLOB.admin_verbs_possess
if(holder.rights & R_PERMISSIONS)
@@ -267,6 +268,9 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
verbs += GLOB.admin_verbs_proccall
if(holder.rights & R_VIEWRUNTIMES)
verbs += /client/proc/view_runtimes
spawn(1) // This setting exposes the profiler for people with R_VIEWRUNTIMES. They must still have it set in cfg/admin.txt
control_freak = 0
/client/proc/remove_admin_verbs()
verbs.Remove(
@@ -332,7 +336,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
ghost.reenter_corpse()
log_admin("[key_name(usr)] re-entered their body")
feedback_add_details("admin_verb","P") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
else if(istype(mob,/mob/new_player))
else if(isnewplayer(mob))
to_chat(src, "<font color='red'>Error: Aghost: Can't admin-ghost whilst in the lobby. Join or observe first.</font>")
else
//ghostize
@@ -537,7 +541,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
message_admins("[key_name_admin(src)] has warned [key_name_admin(C)] resulting in a [AUTOBANTIME] minute ban")
log_admin("[key_name(src)] has warned [key_name(C)] resulting in a [AUTOBANTIME] minute ban")
to_chat(C, "<font color='red'><BIG><B>You have been autobanned due to a warning by [ckey].</B></BIG><br>This is a temporary ban, it will be removed in [AUTOBANTIME] minutes.")
del(C)
qdel(C)
else
message_admins("[key_name_admin(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban")
log_admin("[key_name(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban")
@@ -821,7 +825,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
return
if(holder)
admin_log_and_message_admins("is altering the appearance of [H].")
log_and_message_admins("is altering the appearance of [H].")
H.change_appearance(APPEARANCE_ALL, usr, usr, check_species_whitelist = 0)
feedback_add_details("admin_verb","CHAA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -852,10 +856,10 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
switch(alert("Do you wish for [H] to be allowed to select non-whitelisted races?","Alter Mob Appearance","Yes","No","Cancel"))
if("Yes")
admin_log_and_message_admins("has allowed [H] to change [H.p_their()] appearance, without whitelisting of races.")
log_and_message_admins("has allowed [H] to change [H.p_their()] appearance, without whitelisting of races.")
H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 0)
if("No")
admin_log_and_message_admins("has allowed [H] to change [H.p_their()] appearance, with whitelisting of races.")
log_and_message_admins("has allowed [H] to change [H.p_their()] appearance, with whitelisting of races.")
H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1)
feedback_add_details("admin_verb","CMAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-4
View File
@@ -56,10 +56,6 @@ DEBUG
jobban_loadbanfile()
*/
/hook/startup/proc/loadJobBans()
jobban_loadbanfile()
return 1
/proc/jobban_loadbanfile()
if(config.ban_legacy_system)
var/savefile/S=new("data/job_full.ban")
+25
View File
@@ -16,6 +16,11 @@ GLOBAL_PROTECT(admin_datums) // This is protected because we dont want people ma
var/admincaster_signature //What you'll sign the newsfeeds as
/datum/admins/New(initial_rank = "Temporary Admin", initial_rights = 0, ckey)
if(IsAdminAdvancedProcCall())
to_chat(usr, "<span class='boldannounce'>Admin rank creation blocked: Advanced ProcCall detected.</span>")
message_admins("[key_name(usr)] attempted to create a new admin rank via advanced proc-call")
log_admin("[key_name(usr)] attempted to edit feedback a new admin rank via advanced proc-call")
return
if(!ckey)
error("Admin datum created without a ckey argument. Datum has been deleted")
qdel(src)
@@ -26,10 +31,20 @@ GLOBAL_PROTECT(admin_datums) // This is protected because we dont want people ma
GLOB.admin_datums[ckey] = src
/datum/admins/Destroy()
if(IsAdminAdvancedProcCall())
to_chat(usr, "<span class='boldannounce'>Admin rank deletion blocked: Advanced ProcCall detected.</span>")
message_admins("[key_name(usr)] attempted to delete an admin rank via advanced proc-call")
log_admin("[key_name(usr)] attempted to delete an admin rank via advanced proc-call")
return
..()
return QDEL_HINT_HARDDEL_NOW
/datum/admins/proc/associate(client/C)
if(IsAdminAdvancedProcCall())
to_chat(usr, "<span class='boldannounce'>Rank association blocked: Advanced ProcCall detected.</span>")
message_admins("[key_name(usr)] attempted to associate an admin rank to a new client via advanced proc-call")
log_admin("[key_name(usr)] attempted to associate an admin rank to a new client via advanced proc-call")
return
if(istype(C))
owner = C
owner.holder = src
@@ -39,6 +54,11 @@ GLOBAL_PROTECT(admin_datums) // This is protected because we dont want people ma
GLOB.admins |= C
/datum/admins/proc/disassociate()
if(IsAdminAdvancedProcCall())
to_chat(usr, "<span class='boldannounce'>Rank disassociation blocked: Advanced ProcCall detected.</span>")
message_admins("[key_name(usr)] attempted to disassociate an admin rank from a client via advanced proc-call")
log_admin("[key_name(usr)] attempted to disassociate an admin rank from a client via advanced proc-call")
return
if(owner)
GLOB.admins -= owner
owner.remove_admin_verbs()
@@ -88,6 +108,11 @@ you will have to do something like if(client.holder.rights & R_ADMIN) yourself.
return 0
/client/proc/deadmin()
if(IsAdminAdvancedProcCall())
to_chat(usr, "<span class='boldannounce'>Deadmin blocked: Advanced ProcCall detected.</span>")
message_admins("[key_name(usr)] attempted to de-admin a client via advanced proc-call")
log_admin("[key_name(usr)] attempted to de-admin a client via advanced proc-call")
return
GLOB.admin_datums -= ckey
if(holder)
holder.disassociate()
@@ -102,6 +102,11 @@
to_chat(usr, "<span class='notice'>Admin rank changed.</span>")
/datum/admins/proc/log_admin_permission_modification(var/adm_ckey, var/new_permission)
if(IsAdminAdvancedProcCall())
to_chat(usr, "<span class='boldannounce'>Admin edit blocked: Advanced ProcCall detected.</span>")
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)
return
+20 -3
View File
@@ -2,6 +2,10 @@
/datum/admins/proc/player_panel_new()//The new one
if(!usr.client.holder)
return
// This stops the panel from being invoked by mentors who press F7.
if(!check_rights(R_ADMIN))
message_admins("[key_name_admin(usr)] attempted to invoke player panel without admin rights. If this is a mentor, its a chance they accidentally hit F7. If this is NOT a mentor, there is a high chance an exploit is being used")
return
var/dat = "<html><head><title>Admin Player Panel</title></head>"
//javascript, the part that does most of the work~
@@ -264,7 +268,7 @@
else
M_job = "Living"
else if(istype(M,/mob/new_player))
else if(isnewplayer(M))
M_job = "New player"
else if(isobserver(M))
@@ -352,7 +356,7 @@
dat += "<td>[M.real_name]</td>"
else if(istype(M, /mob/living/silicon/pai))
dat += "<td>pAI</td>"
else if(istype(M, /mob/new_player))
else if(isnewplayer(M))
dat += "<td>New Player</td>"
else if(isobserver(M))
dat += "<td>Ghost</td>"
@@ -400,7 +404,8 @@
<td><A href='?src=[usr.UID()];priv_msg=[M.client ? M.client.UID() : null]'>PM</A> [ADMIN_FLW(M, "FLW")] </td>[close ? "</tr>" : ""]"}
/datum/admins/proc/check_antagonists()
if(!check_rights(R_ADMIN)) return
if(!check_rights(R_ADMIN))
return
if(SSticker && SSticker.current_state >= GAME_STATE_PLAYING)
var/dat = "<html><head><title>Round Status</title></head><body><h1><B>Round Status</B></h1>"
dat += "Current Game Mode: <B>[SSticker.mode.name]</B><BR>"
@@ -486,6 +491,9 @@
if(SSticker.mode.wizards.len)
dat += check_role_table("Wizards", SSticker.mode.wizards)
if(SSticker.mode.apprentices.len)
dat += check_role_table("Apprentices", SSticker.mode.apprentices)
if(SSticker.mode.raiders.len)
dat += check_role_table("Raiders", SSticker.mode.raiders)
@@ -563,6 +571,15 @@
if(SSticker.mode.ert.len)
dat += check_role_table("ERT", SSticker.mode.ert)
//list active security force count, so admins know how bad things are
var/list/sec_list = check_active_security_force()
dat += "<br><table cellspacing=5><tr><td><b>Security</b></td><td></td></tr>"
dat += "<tr><td>Total: </td><td>[sec_list[1]]</td>"
dat += "<tr><td>Active: </td><td>[sec_list[2]]</td>"
dat += "<tr><td>Dead: </td><td>[sec_list[3]]</td>"
dat += "<tr><td>Antag: </td><td>[sec_list[4]]</td>"
dat += "</table>"
dat += "</body></html>"
usr << browse(dat, "window=roundstatus;size=400x500")
else
+4
View File
@@ -186,9 +186,13 @@
var/err = query_list_notes.ErrorMsg()
log_game("SQL ERROR obtaining ckey from notes table. Error : \[[err]\]\n")
return
to_chat(usr, "<span class='notice'>Started regex note search for [search]. Please wait for results...</span>")
message_admins("[usr.ckey] has started a note search with the following regex: [search] | CPU usage may be higher.")
while(query_list_notes.NextRow())
index_ckey = query_list_notes.item[1]
output += "<a href='?_src_=holder;shownoteckey=[index_ckey]'>[index_ckey]</a><br>"
CHECK_TICK
message_admins("The note search started by [usr.ckey] has complete. CPU should return to normal.")
else
output += "<center><a href='?_src_=holder;addnoteempty=1'>\[Add Note\]</a></center>"
output += ruler
+19 -15
View File
@@ -909,7 +909,7 @@
log_admin("[key_name(usr)] booted [key_name(M)].")
message_admins("<span class='notice'>[key_name_admin(usr)] booted [key_name_admin(M)].</span>", 1)
//M.client = null
del(M.client)
qdel(M.client)
//Player Notes
else if(href_list["addnote"])
@@ -1011,8 +1011,7 @@
log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.")
message_admins("<span class='notice'>[key_name_admin(usr)] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.</span>")
del(M.client)
//qdel(M) // See no reason why to delete mob. Important stuff can be lost. And ban can be lifted before round ends.
qdel(M.client)
if("No")
var/reason = input(usr,"Please state the reason","Reason") as message|null
if(!reason)
@@ -1032,8 +1031,7 @@
feedback_inc("ban_perma",1)
DB_ban_record(BANTYPE_PERMA, M, -1, reason)
del(M.client)
//qdel(M)
qdel(M.client)
if("Cancel")
return
@@ -1507,7 +1505,7 @@
if(!check_rights(R_SPAWN)) return
var/mob/M = locateUID(href_list["makeanimal"])
if(istype(M, /mob/new_player))
if(isnewplayer(M))
to_chat(usr, "This cannot be used on instances of type /mob/new_player")
return
if(alert(usr, "Confirm make animal?",, "Yes", "No") != "Yes")
@@ -1980,7 +1978,7 @@
to_chat(usr, "<span class='warning'>ERROR: This mob ([H]) has no mind!</span>")
return
var/list/possible_traitors = list()
for(var/mob/living/player in GLOB.living_mob_list)
for(var/mob/living/player in GLOB.alive_mob_list)
if(player.client && player.mind && player.stat != DEAD && player != H)
if(ishuman(player) && !player.mind.special_role)
if(player.client && (ROLE_TRAITOR in player.client.prefs.be_special) && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, "Syndicate"))
@@ -2585,14 +2583,16 @@
if("monkey")
feedback_inc("admin_secrets_fun_used",1)
feedback_add_details("admin_secrets_fun_used","M")
for(var/mob/living/carbon/human/H in GLOB.mob_list)
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
spawn(0)
H.monkeyize()
ok = 1
if("corgi")
feedback_inc("admin_secrets_fun_used",1)
feedback_add_details("admin_secrets_fun_used","M")
for(var/mob/living/carbon/human/H in GLOB.mob_list)
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
spawn(0)
H.corgize()
ok = 1
@@ -2663,7 +2663,8 @@
feedback_inc("admin_secrets_fun_used",1)
feedback_add_details("admin_secrets_fun_used","PW")
message_admins("<span class='notice'>[key_name_admin(usr)] teleported all players to the prison station.</span>", 1)
for(var/mob/living/carbon/human/H in GLOB.mob_list)
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
var/turf/loc = find_loc(H)
var/security = 0
if(!is_station_level(loc.z) || GLOB.prisonwarped.Find(H))
@@ -2996,7 +2997,8 @@
if("manifest")
var/dat = "<B>Showing Crew Manifest.</B><HR>"
dat += "<table cellspacing=5><tr><th>Name</th><th>Position</th></tr>"
for(var/mob/living/carbon/human/H in GLOB.mob_list)
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
if(H.ckey)
dat += text("<tr><td>[]</td><td>[]</td></tr>", H.name, H.get_assignment())
dat += "</table>"
@@ -3006,7 +3008,8 @@
if("DNA")
var/dat = "<B>Showing DNA from blood.</B><HR>"
dat += "<table cellspacing=5><tr><th>Name</th><th>DNA</th><th>Blood Type</th></tr>"
for(var/mob/living/carbon/human/H in GLOB.mob_list)
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
if(H.dna && H.ckey)
dat += "<tr><td>[H]</td><td>[H.dna.unique_enzymes]</td><td>[H.dna.blood_type]</td></tr>"
dat += "</table>"
@@ -3014,7 +3017,8 @@
if("fingerprints")
var/dat = "<B>Showing Fingerprints.</B><HR>"
dat += "<table cellspacing=5><tr><th>Name</th><th>Fingerprints</th></tr>"
for(var/mob/living/carbon/human/H in GLOB.mob_list)
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
if(H.ckey)
if(H.dna && H.dna.uni_identity)
dat += "<tr><td>[H]</td><td>[md5(H.dna.uni_identity)]</td></tr>"
@@ -3477,9 +3481,9 @@
hunter_mind.objectives += protect_objective
SSticker.mode.traitors |= hunter_mob.mind
to_chat(hunter_mob, "<span class='danger'>ATTENTION:</span> You are now on a mission!")
to_chat(hunter_mob, "<B>Goal: <span class='danger'>[killthem ? "MURDER" : "PROTECT"] [H.real_name]</span>, currently in [get_area(H.loc)]. </B>");
to_chat(hunter_mob, "<B>Goal: <span class='danger'>[killthem ? "MURDER" : "PROTECT"] [H.real_name]</span>, currently in [get_area(H.loc)]. </B>")
if(killthem)
to_chat(hunter_mob, "<B>If you kill [H.p_them()], [H.p_they()] cannot be revived.</B>");
to_chat(hunter_mob, "<B>If you kill [H.p_them()], [H.p_they()] cannot be revived.</B>")
hunter_mob.mind.special_role = SPECIAL_ROLE_TRAITOR
var/datum/atom_hud/antag/tatorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
tatorhud.join_hud(hunter_mob)
+3 -3
View File
@@ -430,7 +430,7 @@
else if(expression[start + 1] == "\[" && islist(v))
var/list/L = v
var/index = SDQL_expression(source, expression[start + 2])
if(isnum(index) && (!IsInteger(index) || L.len < index))
if(isnum(index) && (!ISINTEGER(index) || L.len < index))
to_chat(world, "<span class='danger'>Invalid list index: [index]</span>")
return null
return L[index]
@@ -444,9 +444,9 @@
if(object == world) // Global proc.
procname = "/proc/[procname]"
return call(procname)(arglist(new_args))
return (WrapAdminProcCall(GLOBAL_PROC, procname, new_args))
return call(object, procname)(arglist(new_args))
return (WrapAdminProcCall(object, procname, new_args))
/proc/SDQL2_tokenize(query_text)
+1 -1
View File
@@ -165,7 +165,7 @@ GLOBAL_LIST_INIT(adminhelp_ignored_words, list("unknown","the","a","an","of","mo
var/admin_number_ignored = 0 //Holds the number of admins without +BAN (so admins who are not really admins)
var/admin_number_decrease = 0 //Holds the number of admins with are afk, ignored or both
for(var/client/X in GLOB.admins)
admin_number_total++;
admin_number_total++
var/invalid = 0
if(requiredflags != 0 && !check_rights_for(X, requiredflags))
admin_number_ignored++
+2 -2
View File
@@ -19,7 +19,7 @@
var/list/client/targets[0]
for(var/client/T)
if(T.mob)
if(istype(T.mob, /mob/new_player))
if(isnewplayer(T.mob))
targets["(New Player) - [T]"] = T
else if(istype(T.mob, /mob/dead/observer))
targets["[T.mob.name](Ghost) - [T]"] = T
@@ -42,7 +42,7 @@
var/list/client/targets[0]
for(var/client/T)
if(T.mob)
if(istype(T.mob, /mob/new_player))
if(isnewplayer(T.mob))
targets["[T] - (New Player)"] = T
else if(istype(T.mob, /mob/dead/observer))
targets["[T] - [T.mob.name](Ghost)"] = T
+1 -1
View File
@@ -78,5 +78,5 @@
C.verbs -= msay
to_chat(C, "<b>Mentor chat has been disabled.</b>")
admin_log_and_message_admins("toggled mentor chat [enabling ? "on" : "off"].")
log_and_message_admins("toggled mentor chat [enabling ? "on" : "off"].")
feedback_add_details("admin_verb", "TMC")
+4 -4
View File
@@ -1,7 +1,6 @@
/client/proc/atmosscan()
set category = "Mapping"
set name = "Check Piping"
set background = 1
if(!src.holder)
to_chat(src, "Only administrators may use this command.")
return
@@ -12,17 +11,18 @@
to_chat(usr, "Checking for disconnected pipes...")
//all plumbing - yes, some things might get stated twice, doesn't matter.
for(var/obj/machinery/atmospherics/plumbing in world)
for(var/thing in SSair.atmos_machinery)
var/obj/machinery/atmospherics/plumbing = thing
if(plumbing.nodealert)
to_chat(usr, "Unconnected [plumbing.name] located at [plumbing.x],[plumbing.y],[plumbing.z] ([get_area(plumbing.loc)])")
//Manifolds
for(var/obj/machinery/atmospherics/pipe/manifold/pipe in world)
for(var/obj/machinery/atmospherics/pipe/manifold/pipe in SSair.atmos_machinery)
if(!pipe.node1 || !pipe.node2 || !pipe.node3)
to_chat(usr, "Unconnected [pipe.name] located at [pipe.x],[pipe.y],[pipe.z] ([get_area(pipe.loc)])")
//Pipes
for(var/obj/machinery/atmospherics/pipe/simple/pipe in world)
for(var/obj/machinery/atmospherics/pipe/simple/pipe in SSair.atmos_machinery)
if(!pipe.node1 || !pipe.node2)
to_chat(usr, "Unconnected [pipe.name] located at [pipe.x],[pipe.y],[pipe.z] ([get_area(pipe.loc)])")
+89 -38
View File
@@ -85,18 +85,80 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
return
message_admins("[key_name_admin(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
log_admin("[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
returnval = call(target,procname)(arglist(lst)) // Pass the lst as an argument list to the proc
returnval = WrapAdminProcCall(target, procname, lst) // Pass the lst as an argument list to the proc
else
//this currently has no hascall protection. wasn't able to get it working.
message_admins("[key_name_admin(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]")
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]")
returnval = call(procname)(arglist(lst)) // Pass the lst as an argument list to the proc
returnval = WrapAdminProcCall(GLOBAL_PROC, procname, lst) // Pass the lst as an argument list to the proc
to_chat(usr, "<font color='blue'>[procname] returned: [!isnull(returnval) ? returnval : "null"]</font>")
feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
// All these vars are related to proc call protection
// If you add more of these, for the love of fuck, protect them
/// Who is currently calling procs
GLOBAL_VAR(AdminProcCaller)
GLOBAL_PROTECT(AdminProcCaller)
/// How many procs have been called
GLOBAL_VAR_INIT(AdminProcCallCount, 0)
GLOBAL_PROTECT(AdminProcCallCount)
/// UID of the admin who last called
GLOBAL_VAR(LastAdminCalledTargetUID)
GLOBAL_PROTECT(LastAdminCalledTargetUID)
/// Last target to have a proc called on it
GLOBAL_VAR(LastAdminCalledTarget)
GLOBAL_PROTECT(LastAdminCalledTarget)
/// Last proc called
GLOBAL_VAR(LastAdminCalledProc)
GLOBAL_PROTECT(LastAdminCalledProc)
/// List to handle proc call spam prevention
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
// Wrapper for proccalls where the datum is flagged as vareditted
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target && procname == "Del")
to_chat(usr, "Calling Del() is not allowed")
return
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
return
var/current_caller = GLOB.AdminProcCaller
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
if(!ckey)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
if(current_caller && current_caller != ckey)
if(!GLOB.AdminProcCallSpamPrevention[ckey])
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running, your proc will be run after theirs finish.</span>")
GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
UNTIL(!GLOB.AdminProcCaller)
to_chat(usr, "<span class='adminnotice'>Running your proc</span>")
GLOB.AdminProcCallSpamPrevention -= ckey
else
UNTIL(!GLOB.AdminProcCaller)
GLOB.LastAdminCalledProc = procname
if(target != GLOBAL_PROC)
GLOB.LastAdminCalledTargetUID = target.UID()
GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
++GLOB.AdminProcCallCount
. = world.WrapAdminProcCall(target, procname, arguments)
if(--GLOB.AdminProcCallCount == 0)
GLOB.AdminProcCaller = null
//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
return call(procname)(arglist(arguments))
else if(target != world)
return call(target, procname)(arglist(arguments))
else
to_chat(usr, "<span class='boldannounce'>Call to world/proc/[procname] blocked: Advanced ProcCall detected.</span>")
message_admins("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
log_admin("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]l")
/proc/IsAdminAdvancedProcCall()
#ifdef TESTING
@@ -131,7 +193,7 @@ GLOBAL_PROTECT(AdminProcCaller)
log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]")
spawn()
var/returnval = call(A,procname)(arglist(lst)) // Pass the lst as an argument list to the proc
var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
to_chat(src, "<span class='notice'>[procname] returned: [!isnull(returnval) ? returnval : "null"]</span>")
feedback_add_details("admin_verb","DPC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -251,7 +313,7 @@ GLOBAL_PROTECT(AdminProcCaller)
alert("That mob doesn't seem to exist, close the panel and try again.")
return
if(istype(M, /mob/new_player))
if(isnewplayer(M))
alert("The mob must not be a new_player.")
return
@@ -382,7 +444,7 @@ GLOBAL_PROTECT(AdminProcCaller)
if(!check_rights(R_DEBUG))
return
//This gets a confirmation check because it's way easier to accidentally hit this and delete things than it is with del-all
//This gets a confirmation check because it's way easier to accidentally hit this and delete things than it is with qdel-all
var/confirm = alert("This will delete ALL Singularities and Tesla orbs except for any that are on away mission z-levels or the centcomm z-level. Are you sure you want to delete them?", "Confirm Panic Button", "Yes", "No")
if(confirm != "Yes")
return
@@ -428,7 +490,7 @@ GLOBAL_PROTECT(AdminProcCaller)
id.icon_state = "gold"
id:access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access()
else
var/obj/item/card/id/id = new/obj/item/card/id(M);
var/obj/item/card/id/id = new/obj/item/card/id(M)
id.icon_state = "gold"
id:access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access()
id.registered_name = H.real_name
@@ -487,7 +549,8 @@ GLOBAL_PROTECT(AdminProcCaller)
for(var/area/A in world)
areas_all |= A.type
for(var/obj/machinery/power/apc/APC in world)
for(var/thing in GLOB.apcs)
var/obj/machinery/power/apc/APC = thing
var/area/A = get_area(APC)
if(!A)
continue
@@ -496,7 +559,8 @@ GLOBAL_PROTECT(AdminProcCaller)
else
areas_with_multiple_APCs |= A.type
for(var/obj/machinery/alarm/alarm in world)
for(var/thing in GLOB.air_alarms)
var/obj/machinery/alarm/alarm = thing
var/area/A = get_area(alarm)
if(!A)
continue
@@ -505,31 +569,31 @@ GLOBAL_PROTECT(AdminProcCaller)
else
areas_with_multiple_air_alarms |= A.type
for(var/obj/machinery/requests_console/RC in world)
for(var/obj/machinery/requests_console/RC in GLOB.machines)
var/area/A = get_area(RC)
if(!A)
continue
areas_with_RC |= A.type
for(var/obj/machinery/light/L in world)
for(var/obj/machinery/light/L in GLOB.machines)
var/area/A = get_area(L)
if(!A)
continue
areas_with_light |= A.type
for(var/obj/machinery/light_switch/LS in world)
for(var/obj/machinery/light_switch/LS in GLOB.machines)
var/area/A = get_area(LS)
if(!A)
continue
areas_with_LS |= A.type
for(var/obj/item/radio/intercom/I in world)
for(var/obj/item/radio/intercom/I in GLOB.global_radios)
var/area/A = get_area(I)
if(!A)
continue
areas_with_intercom |= A.type
for(var/obj/machinery/camera/C in world)
for(var/obj/machinery/camera/C in GLOB.machines)
var/area/A = get_area(C)
if(!A)
continue
@@ -579,7 +643,7 @@ GLOBAL_PROTECT(AdminProcCaller)
for(var/areatype in areas_without_camera)
to_chat(world, "* [areatype]")
/client/proc/cmd_admin_dress(var/mob/living/carbon/human/M in GLOB.mob_list)
/client/proc/cmd_admin_dress(mob/living/carbon/human/M in GLOB.human_list)
set category = "Event"
set name = "Select equipment"
@@ -716,23 +780,25 @@ GLOBAL_PROTECT(AdminProcCaller)
if(!check_rights(R_DEBUG))
return
switch(input("Which list?") in list("Players","Admins","Mobs","Living Mobs","Dead Mobs","Silicons","Clients","Respawnable Mobs"))
switch(input("Which list?") in list("Players", "Admins", "Mobs", "Living Mobs", "Alive Mobs", "Dead Mobs", "Silicons", "Clients", "Respawnable Mobs"))
if("Players")
to_chat(usr, jointext(GLOB.player_list,","))
to_chat(usr, jointext(GLOB.player_list, ","))
if("Admins")
to_chat(usr, jointext(GLOB.admins,","))
to_chat(usr, jointext(GLOB.admins, ","))
if("Mobs")
to_chat(usr, jointext(GLOB.mob_list,","))
to_chat(usr, jointext(GLOB.mob_list, ","))
if("Living Mobs")
to_chat(usr, jointext(GLOB.living_mob_list,","))
to_chat(usr, jointext(GLOB.mob_living_list, ","))
if("Alive Mobs")
to_chat(usr, jointext(GLOB.alive_mob_list, ","))
if("Dead Mobs")
to_chat(usr, jointext(GLOB.dead_mob_list,","))
to_chat(usr, jointext(GLOB.dead_mob_list, ","))
if("Silicons")
to_chat(usr, jointext(GLOB.silicon_mob_list,","))
to_chat(usr, jointext(GLOB.silicon_mob_list, ","))
if("Clients")
to_chat(usr, jointext(GLOB.clients,","))
to_chat(usr, jointext(GLOB.clients, ","))
if("Respawnable Mobs")
to_chat(usr, jointext(GLOB.respawnable_list,","))
to_chat(usr, jointext(GLOB.respawnable_list, ","))
/client/proc/cmd_display_del_log()
set category = "Debug"
@@ -812,21 +878,6 @@ GLOBAL_PROTECT(AdminProcCaller)
else
alert("Invalid mob")
/client/proc/reload_nanoui_resources()
set category = "Debug"
set name = "Reload NanoUI Resources"
set desc = "Force the client to redownload NanoUI Resources"
// Close open NanoUIs.
SSnanoui.close_user_uis(usr)
// Re-load the assets.
var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui)
assets.register()
// Clear the user's cache so they get resent.
usr.client.cache = list()
/client/proc/view_runtimes()
set category = "Debug"
set name = "View Runtimes"
+1 -3
View File
@@ -15,9 +15,7 @@
if(T.active_hotspot)
burning = 1
to_chat(usr, "<span class='notice'>@[target.x],[target.y]: O:[GM.oxygen] T:[GM.toxins] N:[GM.nitrogen] C:[GM.carbon_dioxide] w [GM.temperature] Kelvin, [GM.return_pressure()] kPa [(burning)?("<span class='warning'>BURNING</span>"):(null)]</span>")
for(var/datum/gas/trace_gas in GM.trace_gases)
to_chat(usr, "[trace_gas.type]: [trace_gas.moles]")
to_chat(usr, "<span class='notice'>@[target.x],[target.y]: O:[GM.oxygen] T:[GM.toxins] N:[GM.nitrogen] C:[GM.carbon_dioxide] N2O: [GM.sleeping_agent] Agent B: [GM.agent_b] w [GM.temperature] Kelvin, [GM.return_pressure()] kPa [(burning)?("<span class='warning'>BURNING</span>"):(null)]</span>")
message_admins("[key_name_admin(usr)] has checked the air status of [target]")
log_admin("[key_name(usr)] has checked the air status of [target]")
+2 -1
View File
@@ -48,7 +48,8 @@ GLOBAL_VAR_INIT(sent_honksquad, 0)
commandos += candidate//Add their ghost to commandos.
//Spawns HONKsquad and equips them.
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(honksquad_number<=0) break
if(L.name == "HONKsquad")
honk_leader_selected = honksquad_number == 1?1:0
@@ -66,7 +66,8 @@ GLOBAL_VAR_INIT(sent_syndicate_infiltration_team, 0)
var/list/sit_spawns = list()
var/list/sit_spawns_leader = list()
var/list/sit_spawns_mgmt = list()
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(L.name == "Syndicate-Infiltrator")
sit_spawns += L
if(L.name == "Syndicate-Infiltrator-Leader")
+1 -1
View File
@@ -118,7 +118,7 @@ GLOBAL_VAR_INIT(intercom_range_display_status, 0)
qdel(M)
if(GLOB.intercom_range_display_status)
for(var/obj/item/radio/intercom/I in world)
for(var/obj/item/radio/intercom/I in GLOB.global_radios)
for(var/turf/T in orange(7,I))
var/obj/effect/debugging/marker/F = new/obj/effect/debugging/marker(T)
if(!(F in view(7,I.loc)))
@@ -627,6 +627,7 @@ GLOBAL_LIST_INIT(VVpixelmovement, list("step_x", "step_y", "step_size", "bound_h
if(!O.vv_edit_var(variable, var_new))
to_chat(src, "Your edit was rejected by the object.")
return
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_VAR_EDIT, args)
log_world("### VarEdit by [src]: [O.type] [variable]=[html_encode("[var_new]")]")
log_admin("[key_name(src)] modified [original_name]'s [variable] to [var_new]")
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] to [var_new]"
+5 -3
View File
@@ -267,7 +267,7 @@ client/proc/one_click_antag()
var/I = image('icons/mob/mob.dmi', loc = synd_mind_1.current, icon_state = "synd")
synd_mind.current.client.images += I
for(var/obj/machinery/nuclearbomb/bomb in world)
for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
bomb.r_code = nuke_code // All the nukes are set to this code.
return 1
@@ -455,7 +455,8 @@ client/proc/one_click_antag()
if(candidates.len)
var/raiders = min(antnum, candidates.len)
//Spawns vox raiders and equips them.
for(var/obj/effect/landmark/L in world)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(L.name == "voxstart")
if(raiders<=0)
break
@@ -583,7 +584,8 @@ client/proc/one_click_antag()
var/teamOneMembers = 5
var/teamTwoMembers = 5
var/datum/preferences/A = new()
for(var/obj/effect/landmark/L in world)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(L.name == "tdome1")
if(teamOneMembers<=0)
break
+1 -1
View File
@@ -84,7 +84,7 @@
var/obj/item/slot_item_hand = H.get_item_by_slot(slot_r_hand)
H.unEquip(slot_item_hand)
var /obj/item/multisword/pure_evil/multi = new(H)
var/obj/item/multisword/pure_evil/multi = new(H)
H.equip_to_slot_or_del(multi, slot_r_hand)
var/obj/item/card/id/W = new(H)
+5 -4
View File
@@ -73,9 +73,11 @@
..()
if((ishuman(hit_atom)))
var/mob/living/carbon/human/H = hit_atom
if(H.r_hand == src) return
if(H.l_hand == src) return
var/mob/A = H.LAssailant
if(H.r_hand == src)
return
if(H.l_hand == src)
return
var/mob/A = thrownby
if((H in GLOB.team_alpha) && (A in GLOB.team_alpha))
to_chat(A, "<span class='warning'>He's on your team!</span>")
return
@@ -89,4 +91,3 @@
playsound(src, 'sound/items/dodgeball.ogg', 50, 1)
visible_message("<span class='danger'>[H] HAS BEEN ELIMINATED!</span>")
H.melt()
return
+2 -2
View File
@@ -53,7 +53,7 @@ GLOBAL_LIST_EMPTY(sounds_cache)
set name = "Play Server Sound"
if(!check_rights(R_SOUNDS)) return
var/list/sounds = file2list("sound/serversound_list.txt");
var/list/sounds = file2list("sound/serversound_list.txt")
sounds += GLOB.sounds_cache
var/melody = input("Select a sound from the server to play", "Server sound list") as null|anything in sounds
@@ -71,7 +71,7 @@ GLOBAL_LIST_EMPTY(sounds_cache)
var/A = alert("This will play a sound at every intercomm, are you sure you want to continue? This works best with short sounds, beware.","Warning","Yep","Nope")
if(A != "Yep") return
var/list/sounds = file2list("sound/serversound_list.txt");
var/list/sounds = file2list("sound/serversound_list.txt")
sounds += GLOB.sounds_cache
var/melody = input("Select a sound from the server to play", "Server sound list") as null|anything in sounds
+9 -4
View File
@@ -627,7 +627,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
print_command_report(input, "[command_name()] Update")
if("No")
//same thing as the blob stuff - it's not public, so it's classified, dammit
GLOB.command_announcer.autosay("A classified message has been printed out at all communication consoles.");
GLOB.command_announcer.autosay("A classified message has been printed out at all communication consoles.")
print_command_report(input, "Classified [command_name()] Update")
else
return
@@ -826,7 +826,10 @@ Traitors and the like can also be revived with the previous role mostly intact.
else
SSshuttle.emergency.canRecall = FALSE
SSshuttle.emergency.request()
if(seclevel2num(get_security_level()) >= SEC_LEVEL_RED)
SSshuttle.emergency.request(coefficient = 0.5, redAlert = TRUE)
else
SSshuttle.emergency.request()
feedback_add_details("admin_verb","CSHUT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
log_admin("[key_name(usr)] admin-called the emergency shuttle.")
@@ -979,7 +982,8 @@ Traitors and the like can also be revived with the previous role mostly intact.
var/role_string
var/obj_count = 0
var/obj_string = ""
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
if(!isLivingSSD(H))
continue
mins_ssd = round((world.time - H.last_logout) / 600)
@@ -1016,7 +1020,8 @@ Traitors and the like can also be revived with the previous role mostly intact.
msg += "AFK Players:<BR><TABLE border='1'>"
msg += "<TR><TD><B>Key</B></TD><TD><B>Real Name</B></TD><TD><B>Job</B></TD><TD><B>Mins AFK</B></TD><TD><B>Special Role</B></TD><TD><B>Area</B></TD><TD><B>PPN</B></TD><TD><B>Cryo</B></TD></TR>"
var/mins_afk
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
if(H.client == null || H.stat == DEAD) // No clientless or dead
continue
mins_afk = round(H.client.inactivity / 600)
+7 -4
View File
@@ -30,7 +30,7 @@ GLOBAL_VAR_INIT(sent_strike_team, 0)
// Find the nuclear auth code
var/nuke_code
var/temp_code
for(var/obj/machinery/nuclearbomb/N in world)
for(var/obj/machinery/nuclearbomb/N in GLOB.machines)
temp_code = text2num(N.r_code)
if(temp_code)//if it's actually a number. It won't convert any non-numericals.
nuke_code = N.r_code
@@ -48,7 +48,8 @@ GLOBAL_VAR_INIT(sent_strike_team, 0)
var/commando_number = COMMANDOS_POSSIBLE //for selecting a leader
var/is_leader = TRUE // set to FALSE after leader is spawned
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(commando_number <= 0)
break
@@ -109,7 +110,8 @@ GLOBAL_VAR_INIT(sent_strike_team, 0)
commando_number--
//Spawns the rest of the commando gear.
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(L.name == "Commando_Manual")
//new /obj/item/gun/energy/pulse_rifle(L.loc)
var/obj/item/paper/P = new(L.loc)
@@ -120,7 +122,8 @@ GLOBAL_VAR_INIT(sent_strike_team, 0)
P.stamp(stamp)
qdel(stamp)
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(L.name == "Commando-Bomb")
new /obj/effect/spawner/newbomb/timer/syndicate(L.loc)
qdel(L)
@@ -38,7 +38,7 @@ GLOBAL_VAR_INIT(sent_syndicate_strike_team, 0)
// Find the nuclear auth code
var/nuke_code
var/temp_code
for(var/obj/machinery/nuclearbomb/N in world)
for(var/obj/machinery/nuclearbomb/N in GLOB.machines)
temp_code = text2num(N.r_code)
if(temp_code)//if it's actually a number. It won't convert any non-numericals.
nuke_code = N.r_code
@@ -53,7 +53,8 @@ GLOBAL_VAR_INIT(sent_syndicate_strike_team, 0)
GLOB.sent_syndicate_strike_team = 1
//Spawns commandos and equips them.
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(syndicate_commando_number <= 0)
break
@@ -17,8 +17,6 @@ GLOBAL_LIST_INIT(admin_verbs_show_debug_verbs, list(
/client/proc/print_jobban_old,
/client/proc/print_jobban_old_filter,
/client/proc/forceEvent,
/client/proc/nanomapgen_DumpImage,
/client/proc/reload_nanoui_resources,
/client/proc/admin_redo_space_transitions,
/client/proc/make_turf_space_map,
/client/proc/vv_by_ref
+1 -1
View File
@@ -50,7 +50,7 @@
sources_assoc[source] = AS
// Currently only non-0 durations can be altered (normal alarms VS EMP blasts)
if(AS.duration)
duration = SecondsToTicks(duration)
duration = duration SECONDS
AS.duration = duration
AS.severity = severity
@@ -194,7 +194,7 @@
to_chat(user, "<span class='notice'>The demons do not respond to your summon. Perhaps you should try again later.</span>")
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, type = "", mob/user)
var /obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
S.vialspawned = TRUE
S.holder = holder
@@ -41,9 +41,8 @@
A.common_radio.channels.Remove("Syndicate") // De-traitored AIs can still state laws over the syndicate channel without this
A.laws.sorted_laws = A.laws.inherent_laws.Copy() // AI's 'notify laws' button will still state a law 0 because sorted_laws contains it
A.show_laws()
A.malf_picker.remove_malf_verbs(A)
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
qdel(A.malf_picker)
A.remove_malf_abilities()
QDEL_NULL(A.malf_picker)
if(owner.som)
var/datum/mindslaves/slaved = owner.som
@@ -400,7 +399,7 @@
var/phrases = jointext(GLOB.syndicate_code_phrase, ", ")
var/responses = jointext(GLOB.syndicate_code_response, ", ")
var message = "<br><b>The code phrases were:</b> <span class='bluetext'>[phrases]</span><br>\
var/message = "<br><b>The code phrases were:</b> <span class='bluetext'>[phrases]</span><br>\
<b>The code responses were:</b> <span class='redtext'>[responses]</span><br>"
return message
@@ -80,7 +80,7 @@
/obj/machinery/computer/mob_battle_terminal/proc/eject_card(override = 0)
if(!override)
if(ready && SSmob_hunt.battle_turn != team)
audible_message("You can't recall on your rival's turn!", null, 2)
atom_say("You can't recall on your rival's turn!")
return
card.mob_data = mob_info
mob_info = null
@@ -202,7 +202,7 @@
start_battle()
else if(option == 2)
ready = 0
audible_message("[team] Player cancels their battle challenge.", null, 5)
atom_say("[team] Player cancels their battle challenge.")
updateUsrDialog()
@@ -246,7 +246,7 @@
var/message = "[mob_info.mob_name] attacks!"
if(mob_info.nickname)
message = "[mob_info.nickname] attacks!"
audible_message(message, null, 5)
atom_say(message)
SSmob_hunt.launch_attack(team, mob_info.get_raw_damage(), mob_info.get_attack_type())
/obj/machinery/computer/mob_battle_terminal/proc/start_battle()
@@ -255,7 +255,7 @@
if(!card) //don't do anything if there isn't a card inserted
return
ready = 1
audible_message("[team] Player is ready for battle! Waiting for rival...", null, 5)
atom_say("[team] Player is ready for battle! Waiting for rival...")
SSmob_hunt.start_check()
/obj/machinery/computer/mob_battle_terminal/proc/receive_attack(raw_damage, datum/mob_type/attack_type)
@@ -268,7 +268,7 @@
SSmob_hunt.end_turn()
/obj/machinery/computer/mob_battle_terminal/proc/surrender()
audible_message("[team] Player surrenders the battle!", null, 5)
atom_say("[team] Player surrenders the battle!")
SSmob_hunt.end_battle(team, 1)
//////////////////////////////
+3 -3
View File
@@ -55,7 +55,7 @@
var/datum/data/pda/app/mob_hunter_game/client = P.current_app
var/total_catch_mod = client.catch_mod + catch_mod //negative values decrease the chance of the mob running, positive values makes it more likely to flee
if(!client.connected) //must be connected to attempt captures
P.audible_message("[bicon(P)] No server connection. Capture aborted.", null, 4)
P.atom_say("No server connection. Capture aborted.")
return
if(mob_info.is_trap) //traps work even if you ran into them before, which is why this is before the clients_encountered check
@@ -79,7 +79,7 @@
return
else //deal with the new hunter by either running away or getting caught
clients_encountered += client
var/message = "[bicon(P)] "
var/message = null
var/effective_run_chance = mob_info.run_chance + total_catch_mod
if((effective_run_chance > 0) && prob(effective_run_chance))
message += "Capture failed! [name] escaped [P.owner ? "from [P.owner]" : "from this hunter"]!"
@@ -91,7 +91,7 @@
else
message += "Capture error! Try again."
clients_encountered -= client //if the capture registration failed somehow, let them have another chance with this mob
P.audible_message(message, null, 4)
P.atom_say(message)
/obj/effect/nanomob/proc/despawn()
if(SSmob_hunt)
+1 -1
View File
@@ -139,7 +139,7 @@
for(var/areapath in typesof(A))
possible_areas[areapath] -= 2
//removes "bad areas" which shouldn't be on-station but are subtypes of station areas. probably should the unused ones and consider repathing the rest
var/list/bad_areas = list(subtypesof(/area/construction), /area/solar/derelict_starboard, /area/solar/derelict_aft, /area/solar/constructionsite)
var/list/bad_areas = list(subtypesof(/area/construction), /area/solar/derelict_starboard, /area/solar/derelict_aft)
for(var/A in bad_areas)
possible_areas -= A
//weight check, remove negative or zero weight areas from the list, then return the list.
+2 -4
View File
@@ -59,8 +59,7 @@
cooldown--
if(cooldown <= 0)
return FALSE
spawn(10)
process_cooldown()
addtimer(CALLBACK(src, .proc/process_cooldown), 10)
return TRUE
/obj/item/assembly/Destroy()
@@ -94,8 +93,7 @@
if(!secured || cooldown > 0)
return FALSE
cooldown = 2
spawn(10)
process_cooldown()
addtimer(CALLBACK(src, .proc/process_cooldown), 10)
return TRUE
/obj/item/assembly/toggle_secure()
+1 -1
View File
@@ -55,7 +55,7 @@
health_scan = M.health
if(health_scan <= alarm_health)
pulse()
audible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
audible_message("[bicon(src)] *beep* *beep*")
toggle_scan()
return
return
+4 -5
View File
@@ -127,13 +127,12 @@
/obj/item/assembly/infra/proc/trigger_beam()
if(!secured || !on || cooldown > 0)
return FALSE
pulse(0)
audible_message("[bicon(src)] *beep* *beep*", null, 3)
cooldown = 2
pulse(FALSE)
audible_message("[bicon(src)] *beep* *beep*", hearing_distance = 3)
if(first)
qdel(first)
cooldown = 2
spawn(10)
process_cooldown()
addtimer(CALLBACK(src, .proc/process_cooldown), 10)
/obj/item/assembly/infra/interact(mob/user)//TODO: change this this to the wire control panel
if(!secured) return
+3 -4
View File
@@ -47,11 +47,10 @@
/obj/item/assembly/prox_sensor/proc/sense()
if(!secured || !scanning || cooldown > 0)
return FALSE
pulse(0)
visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
cooldown = 2
spawn(10)
process_cooldown()
pulse(FALSE)
visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
addtimer(CALLBACK(src, .proc/process_cooldown), 10)
/obj/item/assembly/prox_sensor/process()
if(timing && (time >= 0))
+1 -2
View File
@@ -41,8 +41,7 @@
if(cooldown > 0)
return FALSE
cooldown = 2
spawn(10)
process_cooldown()
addtimer(CALLBACK(src, .proc/process_cooldown), 10)
signal()
return TRUE
+3 -4
View File
@@ -39,12 +39,11 @@
/obj/item/assembly/timer/proc/timer_end()
if(!secured || cooldown > 0)
return FALSE
pulse(0)
cooldown = 2
pulse(FALSE)
if(loc)
loc.visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
cooldown = 2
spawn(10)
process_cooldown()
addtimer(CALLBACK(src, .proc/process_cooldown), 10)
/obj/item/assembly/timer/process()
if(timing && (time > 0))
-454
View File
@@ -1,454 +0,0 @@
/obj/machinery/computer/general_air_control/atmos_automation
icon = 'icons/obj/computer.dmi'
icon_screen = "area_atmos"
icon_keyboard = "atmos_key"
circuit = /obj/item/circuitboard/atmos_automation
req_one_access_txt = "24;10"
Mtoollink = 1
show_sensors = 0
var/on = 0
name = "Atmospherics Automations Console"
var/list/datum/automation/automations = list()
/obj/machinery/computer/general_air_control/atmos_automation/receive_signal(datum/signal/signal)
if(!signal || signal.encryption) return
var/id_tag = signal.data["tag"]
if(!id_tag)
return
sensor_information[id_tag] = signal.data
/obj/machinery/computer/general_air_control/atmos_automation/process()
if(on)
for(var/datum/automation/A in automations)
A.process()
/obj/machinery/computer/general_air_control/atmos_automation/update_icon()
icon_state = initial(icon_state)
// Broken
if(stat & BROKEN)
icon_state += "b"
// Powered
else if(stat & NOPOWER)
icon_state = initial(icon_state)
icon_state += "0"
else if(on)
icon_state += "_active"
/obj/machinery/computer/general_air_control/atmos_automation/proc/request_device_refresh(device)
send_signal(list("tag"=device, "status"))
/obj/machinery/computer/general_air_control/atmos_automation/proc/send_signal(list/data, filter = RADIO_ATMOSIA)//filter's here so the AAC can cross communicate to things like vents, which have a different filter
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data=data
signal.data["sigtype"]="command"
signal.data["advcontrol"]=1//AAC balancing, you need to manually get up to the machine to make it listen to this
radio_connection.post_signal(src, signal, range = 8, filter = filter)
/obj/machinery/computer/general_air_control/atmos_automation/proc/selectValidChildFor(datum/automation/parent, mob/user, list/valid_returntypes)
var/list/choices=list()
for(var/childtype in GLOB.automation_types)
var/datum/automation/A = new childtype(src)
if(A.returntype == null)
continue
if(!(A.returntype in valid_returntypes))
continue
choices[A.name]=A
if(choices.len==0)
testing("Unable to find automations with returntype in [english_list(valid_returntypes)]!")
return 0
var/label=input(user, "Select new automation:", "Automations", "Cancel") as null|anything in choices
if(!label)
return 0
return choices[label]
/obj/machinery/computer/general_air_control/atmos_automation/return_text()
var/out=..()
if(on)
out += "<a href=\"?src=[UID()];on=1\" style=\"font-size:large;font-weight:bold;color:red;\">RUNNING</a>"
else
out += "<a href=\"?src=[UID()];on=1\" style=\"font-size:large;font-weight:bold;color:green;\">STOPPED</a>"
out += {"
<h2>Automations</h2>
<p>\[
<a href="?src=[UID()];add=1">
Add
</a>
|
<a href="?src=[UID()];reset=*">
Reset All
</a>
|
<a href="?src=[UID()];remove=*">
Clear
</a>
\]</p>
<p>\[
<a href="?src=[UID()];dump=1">
Export
</a>
|
<a href="?src=[UID()];read=1">
Import
</a>
\]</p>"}
if(automations.len==0)
out += "<i>No automations present.</i>"
else
for(var/datum/automation/A in automations)
out += {"
<fieldset>
<legend>
<a href="?src=[UID()];label=\ref[A]">[A.label]</a>
(<a href="?src=[UID()];reset=\ref[A]">Reset</a> |
<a href="?src=[UID()];remove=\ref[A]">&times;</a>)
</legend>
[A.GetText()]
</fieldset>
"}
return out
/obj/machinery/computer/general_air_control/atmos_automation/Topic(href,href_list)
if(..())
return 1
if(href_list["on"])
on = !on
updateUsrDialog()
update_icon()
return 1
if(href_list["add"])
var/new_child=selectValidChildFor(null,usr,list(0))
if(!new_child)
return 1
automations += new_child
updateUsrDialog()
return 1
if(href_list["label"])
var/datum/automation/A=locate(href_list["label"])
if(!A) return 1
var/nl=input(usr, "Please enter a label for this automation task.") as text|null
if(!nl) return 1
nl = copytext(sanitize(nl), 1, 50)
A.label=nl
updateUsrDialog()
return 1
if(href_list["reset"])
if(href_list["reset"]=="*")
for(var/datum/automation/A in automations)
if(!A) continue
A.OnReset()
else
var/datum/automation/A=locate(href_list["reset"])
if(!A) return 1
A.OnReset()
updateUsrDialog()
return 1
if(href_list["remove"])
if(href_list["remove"]=="*")
var/confirm=alert("Are you sure you want to remove ALL automations?","Automations","Yes","No")
if(confirm == "No") return 0
for(var/datum/automation/A in automations)
if(!A) continue
A.OnRemove()
automations.Remove(A)
else
var/datum/automation/A=locate(href_list["remove"])
if(!A) return 1
A.OnRemove()
automations.Remove(A)
updateUsrDialog()
return 1
if(href_list["read"])
var/code = input("Input exported AAC code.","Automations","") as message|null
if(!code) return 0
ReadCode(code)
updateUsrDialog()
return 1
if(href_list["dump"])
input("Exported AAC code:","Automations",DumpCode()) as message|null
return 0
/obj/machinery/computer/general_air_control/atmos_automation/proc/MakeCompare(datum/automation/a, datum/automation/b, comparetype)
var/datum/automation/compare/compare=new(src)
compare.comparator = comparetype
compare.children[1] = a
compare.children[2] = b
return compare
/obj/machinery/computer/general_air_control/atmos_automation/proc/MakeNumber(value)
var/datum/automation/static_value/val = new(src)
val.value=value
return val
/obj/machinery/computer/general_air_control/atmos_automation/proc/MakeGetSensorData(sns_tag,field)
var/datum/automation/get_sensor_data/sensor=new(src)
sensor.sensor=sns_tag
sensor.field=field
return sensor
/obj/machinery/computer/general_air_control/atmos_automation/proc/DumpCode()
var/list/json[0]
for(var/datum/automation/A in automations)
json += list(A.Export())
return json_encode(json)
/obj/machinery/computer/general_air_control/atmos_automation/proc/ReadCode(jsonStr)
automations.Cut()
var/list/json = json_decode(jsonStr)
if(json.len>0)
for(var/list/cData in json)
if(isnull(cData) || !("type" in cData))
testing("AAC: Null cData in root JS array.")
continue
var/Atype=text2path(cData["type"])
if(!(Atype in GLOB.automation_types))
testing("AAC: Unrecognized Atype [Atype].")
continue
var/datum/automation/A = new Atype(src)
A.Import(cData)
automations += A
/obj/machinery/computer/general_air_control/atmos_automation/burnchamber
var/injector_tag="inc_in"
var/output_tag="inc_out"
var/sensor_tag="inc_sensor"
frequency=AIRLOCK_FREQ
var/temperature=1000
/obj/machinery/computer/general_air_control/atmos_automation/burnchamber/New()
..()
// On State
// Pretty much this:
/*
if(get_sensor("inc_sensor","temperature") < 200)
set_injector_state("inc_in",1)
set_vent_pump_power("inc_out",0)
else
set_vent_pump_power("inc_out",1
*/
var/datum/automation/get_sensor_data/sensor=new(src)
sensor.sensor=sensor_tag
sensor.field="temperature"
var/datum/automation/static_value/val = new(src)
val.value=temperature - 800
var/datum/automation/compare/compare=new(src)
compare.comparator = "Less Than"
compare.children[1] = sensor
compare.children[2] = val
var/datum/automation/set_injector_power/inj_on=new(src)
inj_on.injector=injector_tag
inj_on.state=1
var/datum/automation/set_vent_pump_power/vp_on=new(src)
vp_on.vent_pump=output_tag
vp_on.state=1
var/datum/automation/set_vent_pump_power/vp_off=new(src)
vp_off.vent_pump=output_tag
vp_off.state=0
var/datum/automation/if_statement/i = new (src)
i.label = "Fuel Injector On"
i.condition = compare
i.children_then.Add(inj_on)
i.children_then.Add(vp_off)
i.children_else.Add(vp_on)
automations += i
// Off state
/*
if(get_sensor("inc_sensor","temperature") > 1000)
set_injector_state("inc_in",0)
*/
sensor=new(src)
sensor.sensor=sensor_tag
sensor.field="temperature"
val = new(src)
val.value=temperature
compare=new(src)
compare.comparator = "Greater Than"
compare.children[1] = sensor
compare.children[2] = val
var/datum/automation/set_injector_power/inj_off=new(src)
inj_off.injector=injector_tag
inj_off.state=0
i = new (src)
i.label = "Fuel Injector Off"
i.condition = compare
i.children_then.Add(inj_off)
automations += i
/obj/machinery/computer/general_air_control/atmos_automation/air_mixing
var/n2_injector_tag="air_n2_in"
var/o2_injector_tag="air_o2_in"
var/output_tag="air_out"
var/sensor_tag="air_sensor"
frequency=ATMOS_DISTRO_FREQ
var/temperature=1000
/obj/machinery/computer/general_air_control/atmos_automation/air_mixing/New()
..()
buildO2()
buildN2()
buildOutletVent()
/obj/machinery/computer/general_air_control/atmos_automation/air_mixing/proc/buildO2()
///////////////////////////////////////////////////////////////
// Oxygen Injection
///////////////////////////////////////////////////////////////
var/datum/automation/set_injector_power/inj_on=new(src)
inj_on.injector=o2_injector_tag
inj_on.state=1
var/datum/automation/set_injector_power/inj_off=new(src)
inj_off.injector=o2_injector_tag
inj_off.state=0
var/datum/automation/if_statement/i = new (src)
i.label = "Oxygen Injection"
i.condition = MakeCompare(
MakeGetSensorData(sensor_tag,"oxygen"),
MakeNumber(20),
"Less Than or Equal to"
)
i.children_then.Add(inj_on)
i.children_else.Add(inj_off)
automations += i
/obj/machinery/computer/general_air_control/atmos_automation/air_mixing/proc/buildN2()
///////////////////////////////////////////////////////////////
// Nitrogen Injection
///////////////////////////////////////////////////////////////
/*
if(get_sensor_data("pressure") < 100)
injector_on()
else
if(get_sensor_data("pressure") > 5000)
injector_off()
*/
var/datum/automation/set_injector_power/inj_on=new(src)
inj_on.injector=n2_injector_tag
inj_on.state=1
var/datum/automation/set_injector_power/inj_off=new(src)
inj_off.injector=n2_injector_tag
inj_off.state=0
var/datum/automation/if_statement/if_on = new (src)
if_on.label = "Nitrogen Injection"
if_on.condition = MakeCompare(
MakeGetSensorData(sensor_tag,"pressure"),
MakeNumber(100),
"Less Than"
)
if_on.children_then.Add(inj_on)
var/datum/automation/if_statement/if_off=new(src)
if_off.condition=MakeCompare(
MakeGetSensorData(sensor_tag,"pressure"),
MakeNumber(5000),
"Greater Than"
)
if_off.children_then.Add(inj_off)
if_on.children_else.Add(if_off)
automations += if_on
/obj/machinery/computer/general_air_control/atmos_automation/air_mixing/proc/buildOutletVent()
///////////////////////////////////////////////////////////////
// Outlet Management
///////////////////////////////////////////////////////////////
/*
if(get_sensor_data("pressure") >= 5000 && get_sensor_data("oxygen") >= 20)
vent_on()
else
if(get_sensor_data("oxygen") < 20 || get_sensor_data("pressure") < 100)
vent_off()
*/
var/datum/automation/set_vent_pump_power/vp_on=new(src)
vp_on.vent_pump=output_tag
vp_on.state=1
var/datum/automation/set_vent_pump_power/vp_off=new(src)
vp_off.vent_pump=output_tag
vp_off.state=0
var/datum/automation/if_statement/if_on=new(src)
if_on.label="Air Output"
var/datum/automation/and/and_on=new(src)
and_on.children.Add(
MakeCompare(
MakeGetSensorData(sensor_tag,"pressure"),
MakeNumber(5000),
"Greater Than or Equal to"
)
)
and_on.children.Add(
MakeCompare(
MakeGetSensorData(sensor_tag,"oxygen"),
MakeNumber(20),
"Greater Than or Equal to"
)
)
if_on.condition=and_on
if_on.children_then.Add(vp_on)
//////////////////////////////
var/datum/automation/if_statement/if_off=new(src)
var/datum/automation/or/or_off=new(src)
or_off.children.Add(
MakeCompare(
MakeGetSensorData(sensor_tag,"pressure"),
MakeNumber(100),
"Less Than"
)
)
or_off.children.Add(
MakeCompare(
MakeGetSensorData(sensor_tag,"oxygen"),
MakeNumber(20),
"Less Than"
)
)
if_off.condition=or_off
if_off.children_then.Add(vp_off)
if_on.children_else.Add(if_off)
automations += if_on
@@ -1,44 +0,0 @@
/datum/automation/set_valve_state
name = "Digital Valve: Set Open/Closed"
var/valve=null
var/state=0
Export()
var/list/json = ..()
json["valve"]=valve
json["state"]=state
return json
Import(var/list/json)
..(json)
valve = json["valve"]
state = text2num(json["state"])
process()
if(valve)
parent.send_signal(list ("tag" = valve, "command"="valve_set","valve_set"=state))
return 0
GetText()
return "Set digital valve <a href=\"?src=[UID()];set_subject=1\">[fmtString(valve)]</a> to <a href=\"?src=[UID()];set_state=1\">[state?"open":"closed"]</a>."
Topic(href,href_list)
if(..())
return 1
if(href_list["set_state"])
state=!state
parent.updateUsrDialog()
return 1
if(href_list["set_subject"])
var/list/valves=list()
for(var/obj/machinery/atmospherics/binary/valve/digital/V in world)
if(!isnull(V.id_tag) && V.frequency == parent.frequency)
valves|=V.id_tag
if(valves.len==0)
to_chat(usr, "<span class='warning'>Unable to find any digital valves on this frequency.</span>")
return
valve = input("Select a valve:", "Sensor Data", valve) as null|anything in valves
parent.updateUsrDialog()
return 1
@@ -1,42 +0,0 @@
/datum/automation/set_emitter_power
name = "Emitter: Set Power"
var/emitter=null
var/on=0
Export()
var/list/json = ..()
json["emitter"]=emitter
json["on"]=on
return json
Import(var/list/json)
..(json)
emitter = json["emitter"]
on = text2num(json["on"])
process()
if(emitter)
parent.send_signal(list("tag" = emitter, "command"="set", "state" = on, "hiddenprints" = parent.fingerprintshidden))
return 0
GetText()
return "Set emitter <a href=\"?src=[UID()];set_subject=1\">[fmtString(emitter)]</a> to <a href=\"?src=[UID()];set_power=1\">[on?"on":"off"]</a>."
Topic(href,href_list)
if(..())
return 1
if(href_list["set_power"])
on=!on
parent.updateUsrDialog()
return 1
if(href_list["set_subject"])
var/list/emitters=list()
for(var/obj/machinery/power/emitter/E in GLOB.machines)
if(!isnull(E.id_tag) && E.frequency == parent.frequency)
emitters|=E.id_tag
if(emitters.len==0)
to_chat(usr, "<span class='warning'>Unable to find any emitters on this frequency.</span>")
return
emitter = input("Select an emitter:", "Emitter", emitter) as null|anything in emitters
parent.updateUsrDialog()
return 1
@@ -1,83 +0,0 @@
////////////////////////////////////////////
// Injector
////////////////////////////////////////////
/datum/automation/set_injector_power
name = "Injector: Power"
var/injector=null
var/state=0
Export()
var/list/json = ..()
json["injector"]=injector
json["state"]=state
return json
Import(var/list/json)
..(json)
injector = json["injector"]
state = text2num(json["state"])
process()
if(injector)
parent.send_signal(list ("tag" = injector, "power"=state))
return 0
GetText()
return "Set injector <a href=\"?src=[UID()];set_injector=1\">[fmtString(injector)]</a> power to <a href=\"?src=[UID()];toggle_state=1\">[state ? "on" : "off"]</a>."
Topic(href,href_list)
if(..())
return 1
if(href_list["toggle_state"])
state = !state
parent.updateUsrDialog()
return 1
if(href_list["set_injector"])
var/list/injector_names=list()
for(var/obj/machinery/atmospherics/unary/outlet_injector/I in GLOB.machines)
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names|=I.id_tag
injector = input("Select an injector:", "Sensor Data", injector) as null|anything in injector_names
parent.updateUsrDialog()
return 1
/datum/automation/set_injector_rate
name = "Injector: Rate"
var/injector = null
var/rate = 0
Export()
var/list/json = ..()
json["injector"] = injector
json["rate"] = rate
return json
Import(var/list/json)
..(json)
injector = json["injector"]
rate = text2num(json["rate"])
process()
if(injector)
parent.send_signal(list ("tag" = injector, "set_volume_rate"=rate))
return 0
GetText()
return "Set injector <a href=\"?src=[UID()];set_injector=1\">[fmtString(injector)]</a> transfer rate to <a href=\"?src=[UID()];set_rate=1\">[rate]</a> L/s."
Topic(href,href_list)
if(..())
return 1
if(href_list["set_rate"])
rate = input("Set rate in L/s.", "Rate", rate) as num
parent.updateUsrDialog()
return 1
if(href_list["set_injector"])
var/list/injector_names=list()
for(var/obj/machinery/atmospherics/unary/outlet_injector/I in GLOB.machines)
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names|=I.id_tag
injector = input("Select an injector:", "Sensor Data", injector) as null|anything in injector_names
parent.updateUsrDialog()
return 1
@@ -1,153 +0,0 @@
/datum/automation/set_scrubber_mode
name="Scrubber: Mode"
var/scrubber=null
var/mode=1
Export()
var/list/json = ..()
json["scrubber"]=scrubber
json["mode"]=mode
return json
Import(var/list/json)
..(json)
scrubber = json["scrubber"]
mode = text2num(json["mode"])
New(var/obj/machinery/computer/general_air_control/atmos_automation/aa)
..(aa)
children=list(null)
process()
if(scrubber)
parent.send_signal(list ("tag" = scrubber, "sigtype"="command", "scrubbing"=mode),filter = RADIO_FROM_AIRALARM)
return 0
GetText()
return "Set Scrubber <a href=\"?src=[UID()];set_scrubber=1\">[fmtString(scrubber)]</a> mode to <a href=\"?src=[UID()];set_mode=1\">[mode?"Scrubbing":"Syphoning"]</a>."
Topic(href,href_list)
if(..()) return
if(href_list["set_mode"])
mode=!mode
parent.updateUsrDialog()
return 1
if(href_list["set_scrubber"])
var/list/injector_names=list()
for(var/obj/machinery/atmospherics/unary/vent_scrubber/S in GLOB.machines)
if(!isnull(S.id_tag) && S.frequency == parent.frequency)
injector_names|=S.id_tag
scrubber = input("Select a scrubber:", "Scrubbers", scrubber) as null|anything in injector_names
parent.updateUsrDialog()
return 1
/datum/automation/set_scrubber_power
name="Scrubber: Power"
var/scrubber=null
var/state=0
Export()
var/list/json = ..()
json["scrubber"]=scrubber
json["state"]=state
return json
Import(var/list/json)
..(json)
scrubber = json["scrubber"]
state = text2num(json["state"])
New(var/obj/machinery/computer/general_air_control/atmos_automation/aa)
..(aa)
process()
if(scrubber)
parent.send_signal(list ("tag" = scrubber, "sigtype"="command", "power"=state),filter = RADIO_FROM_AIRALARM)
GetText()
return "Set Scrubber <a href=\"?src=[UID()];set_scrubber=1\">[fmtString(scrubber)]</a> power to <a href=\"?src=[UID()];set_power=1\">[state ? "on" : "off"]</a>."
Topic(href,href_list)
if(..()) return
if(href_list["set_power"])
state = !state
parent.updateUsrDialog()
return 1
if(href_list["set_scrubber"])
var/list/injector_names=list()
for(var/obj/machinery/atmospherics/unary/vent_scrubber/S in GLOB.machines)
if(!isnull(S.id_tag) && S.frequency == parent.frequency)
injector_names|=S.id_tag
scrubber = input("Select a scrubber:", "Scrubbers", scrubber) as null|anything in injector_names
parent.updateUsrDialog()
return 1
GLOBAL_LIST_INIT(gas_labels, list(
"co2" = "CO<sub>2</sub>",
"tox" = "Plasma",
"n2o" = "N<sub>2</sub>O",
"o2" = "O<sub>2</sub>",
"n2" = "N<sub>2</sub>"
))
/datum/automation/set_scrubber_gasses
name="Scrubber: Gasses"
var/scrubber=null
var/list/gasses=list(
"co2" = 1,
"tox" = 0,
"n2o" = 0,
"o2" = 0,
"n2" = 0
)
Export()
var/list/json = ..()
json["scrubber"]=scrubber
json["gasses"]=gasses
return json
Import(var/list/json)
..(json)
scrubber = json["scrubber"]
var/list/newgasses=json["gasses"]
for(var/key in newgasses)
gasses[key]=newgasses[key]
New(var/obj/machinery/computer/general_air_control/atmos_automation/aa)
..(aa)
process()
if(scrubber)
var/list/data = list ("tag" = scrubber, "sigtype"="command")
for(var/gas in gasses)
data[gas+"_scrub"]=gasses[gas]
parent.send_signal(data,filter = RADIO_FROM_AIRALARM)
GetText()
var/txt = "Set Scrubber <a href=\"?src=[UID()];set_scrubber=1\">[fmtString(scrubber)]</a> to scrub "
for(var/gas in gasses)
txt += " [GLOB.gas_labels[gas]] (<a href=\"?src=[UID()];tog_gas=[gas]\">[gasses[gas] ? "on" : "off"]</a>),"
return txt
Topic(href,href_list)
if(..()) return
if(href_list["tog_gas"])
var/gas = href_list["tog_gas"]
if(!(gas in gasses))
return
gasses[gas] = !gasses[gas]
parent.updateUsrDialog()
return 1
if(href_list["set_scrubber"])
var/list/injector_names=list()
for(var/obj/machinery/atmospherics/unary/vent_scrubber/S in GLOB.machines)
if(!isnull(S.id_tag) && S.frequency == parent.frequency)
injector_names|=S.id_tag
scrubber = input("Select a scrubber:", "Scrubbers", scrubber) as null|anything in injector_names
parent.updateUsrDialog()
return 1
@@ -1,56 +0,0 @@
///////////////////////////////////////////
// sensor data
///////////////////////////////////////////
/datum/automation/get_sensor_data
name = "Sensor: Get Data"
var/field="temperature"
var/sensor=null
returntype=AUTOM_RT_NUM
Export()
var/list/json = ..()
json["sensor"]=sensor
json["field"]=field
return json
Import(var/list/json)
..(json)
sensor = json["sensor"]
field = json["field"]
Evaluate()
if(sensor && field && (sensor in parent.sensor_information))
return parent.sensor_information[sensor][field]
return 0
GetText()
return "<a href=\"?src=[UID()];set_field=1\">[fmtString(field)]</a> from sensor <a href=\"?src=[UID()];set_sensor=1\">[fmtString(sensor)]</a>"
Topic(href,href_list)
if(..())
return 1
if(href_list["set_field"])
field = input("Select a sensor output:", "Sensor Data", field) as null|anything in list(
"temperature",
"pressure",
"oxygen",
"toxins",
"nitrogen",
"carbon_dioxide"
)
parent.updateUsrDialog()
return 1
if(href_list["set_sensor"])
var/list/sensor_list = list()
for(var/obj/machinery/air_sensor/G in GLOB.machines)
if(!isnull(G.id_tag) && G.frequency == parent.frequency)
sensor_list|=G.id_tag
for(var/obj/machinery/meter/M in GLOB.machines)
if(!isnull(M.id_tag) && M.frequency == parent.frequency)
sensor_list|=M.id_tag
sensor = input("Select a sensor:", "Sensor Data", field) as null|anything in sensor_list
parent.updateUsrDialog()
return 1
@@ -1,314 +0,0 @@
/datum/automation/set_vent_pump_mode
name="Vent Pump: Mode"
var/vent_pump = null
var/mode = "stabilize"
var/vent_type = 0//0 for unary vents, 1 for DP vents
var/list/modes = list("stabilize","purge")
Export()
var/list/json = ..()
json["vent_pump"] = vent_pump
json["mode"] = mode
json["vent_type"] = vent_type
return json
Import(var/list/json)
..(json)
vent_pump = json["vent_pump"]
mode = json["mode"]
vent_type = text2num(json["vent_type"])
process()
if(vent_pump)
var/dirvalue = (mode == "stabilize" ? 1 : mode == "purge" ? 0 : 1)
parent.send_signal(list("tag" = vent_pump, "direction" = dirvalue), filter = (vent_type ? RADIO_ATMOSIA : RADIO_FROM_AIRALARM))
return 0
GetText()
return "Set <a href=\"?src=[UID()];toggle_type=1\">[vent_type ? "Dual-Port" : "Unary"]</a> vent pump <a href=\"?src=[UID()];set_vent_pump=1\">[fmtString(vent_pump)]</a> mode to <a href=\"?src=[UID()];set_mode=1\">[mode]</a>."
Topic(href,href_list)
if(..())
return 1
if(href_list["set_mode"])
mode = input("Select a mode to put this pump into.",mode) in modes
parent.updateUsrDialog()
return 1
if(href_list["set_vent_pump"])
var/list/injector_names = list()
if(!vent_type)
for(var/obj/machinery/atmospherics/unary/vent_pump/I in GLOB.machines)
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names |= I.id_tag
else
for(var/obj/machinery/atmospherics/binary/dp_vent_pump/I in world)
// to_chat(world, "test")
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names |= I.id_tag
vent_pump = input("Select a vent:", "Vent Pumps", vent_pump) as null|anything in injector_names
parent.updateUsrDialog()
return 1
if(href_list["toggle_type"])
vent_type = !vent_type
parent.updateUsrDialog()
return 1
/datum/automation/set_vent_pump_power
name="Vent Pump: Power"
var/vent_pump = null
var/state = 0
var/mode = 0//0 for unary vents, 1 for DP vents.
Export()
var/list/json = ..()
json["vent_pump"] = vent_pump
json["state"] = state
json["mode"] = mode
return json
Import(var/list/json)
..(json)
vent_pump = json["vent_pump"]
state = text2num(json["state"])
mode = text2num(json["mode"])
process()
if(vent_pump)
parent.send_signal(list ("tag" = vent_pump, "power" = state), filter = (mode ? RADIO_ATMOSIA : RADIO_FROM_AIRALARM))
GetText()
return "Set <a href=\"?src=[UID()];toggle_mode=1\">[mode ? "Dual-Port" : "Unary"]</a> vent pump <a href=\"?src=[UID()];set_vent_pump=1\">[fmtString(vent_pump)]</a> power to <a href=\"?src=[UID()];set_power=1\">[state ? "on" : "off"]</a>."
Topic(href,href_list)
if(..())
return 1
if(href_list["set_power"])
state = !state
parent.updateUsrDialog()
return 1
if(href_list["set_vent_pump"])
var/list/injector_names=list()
if(!mode)
for(var/obj/machinery/atmospherics/unary/vent_pump/I in GLOB.machines)
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names|=I.id_tag
else
for(var/obj/machinery/atmospherics/binary/dp_vent_pump/I in world)
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names|=I.id_tag
vent_pump = input("Select a vent:", "Vent Pumps", vent_pump) as null|anything in injector_names
parent.updateUsrDialog()
return 1
if(href_list["toggle_mode"])
mode = !mode
parent.updateUsrDialog()
return 1
/datum/automation/set_vent_pump_pressure//controls the internal/external pressure bounds of a vent pump.
name = "Vent Pump: Pressure Settings"
var/vent_pump = null
var/intpressureout = 0//these 2 are for DP vents, if it's a unary vent you're sending to it will take intpressureout as var
var/intpressurein = 0
var/extpressure = 0
var/mode = 0//0 for unary vents, 1 for DP vents.
Export()
var/list/json = ..()
json["vent_pump"] = vent_pump
json["intpressureout"] = intpressureout
json["intpressurein"] = intpressurein
json["extpressure"] = extpressure
json["mode"] = mode
return json
Import(var/list/json)
..(json)
vent_pump = json["vent_pump"]
intpressureout = text2num(json["intpressureout"])
intpressurein = text2num(json["intpressurein"])
extpressure = text2num(json["extpressure"])
mode = text2num(json["mode"])
New(var/obj/machinery/computer/general_air_control/atmos_automation/aa)
..(aa)
process()
if(vent_pump)
var/list/data = list( \
"tag" = vent_pump, \
)
var/filter = RADIO_ATMOSIA
if(mode)//it's a DP vent
if(intpressurein)
data.Add(list("set_input_pressure" = intpressurein))
if(intpressureout)
data.Add(list("set_output_pressure" = intpressureout))
if(extpressure)
data.Add(list("set_external_pressure" = extpressure))
else
if(intpressureout)
data.Add(list("set_internal_pressure" = intpressureout))
if(extpressure)
data.Add(list("set_external_pressure" = extpressure))
filter = RADIO_FROM_AIRALARM
parent.send_signal(data, filter)
GetText()
if(mode)//DP vent
return {"Set <a href=\"?src=[UID()];swap_modes=1\">dual-port</a> vent pump <a href=\"?src=[UID()];set_vent_pump=1\">[fmtString(vent_pump)]</a>
pressure bounds: internal outwards: <a href=\"?src=[UID()];set_intpressure_out=1">[fmtString(intpressureout)]</a>
internal inwards: <a href=\"?src=[UID()];set_intpressure_in=1">[fmtString(intpressurein)]</a>
external: <a href=\"?src=[UID()];set_external=1">[fmtString(extpressure)]</a>
"}//well that was a lot to type
else
return {"Set <a href=\"?src=[UID()];swap_modes=1\">unary</a> vent pump <a href=\"?src=[UID()];set_vent_pump=1\">[fmtString(vent_pump)]</a>
pressure bounds: internal: <a href=\"?src=[UID()];set_intpressure_out=1">[fmtString(intpressureout)]</a>
external: <a href=\"?src=[UID()];set_external=1">[fmtString(extpressure)]</a>
"}//copy paste FTW
Topic(href, href_list)
if(..())
return 1
if(href_list["set_vent_pump"])
var/list/injector_names=list()
if(mode)//DP vent selection
for(var/obj/machinery/atmospherics/binary/dp_vent_pump/I in world)
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names|=I.id_tag
else
for(var/obj/machinery/atmospherics/unary/vent_pump/I in GLOB.machines)
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names|=I.id_tag
vent_pump = input("Select a vent:", "Vent Pumps", vent_pump) as null|anything in injector_names
parent.updateUsrDialog()
return 1
if(href_list["set_intpressure_out"])
var/response = input("Set new pressure, in kPa. \[0-[50*ONE_ATMOSPHERE]\]") as num
intpressureout = text2num(response)
intpressureout = between(0, intpressureout, 50*ONE_ATMOSPHERE)
parent.updateUsrDialog()
return 1
if(href_list["set_intpressure_in"])
var/response = input("Set new pressure, in kPa. \[0-[50*ONE_ATMOSPHERE]\]") as num
intpressurein = text2num(response)
intpressurein = between(0, intpressurein, 50*ONE_ATMOSPHERE)
parent.updateUsrDialog()
return 1
if(href_list["set_external"])
var/response = input(usr,"Set new pressure, in kPa. \[0-[50*ONE_ATMOSPHERE]\]") as num
extpressure = text2num(response)
extpressure = between(0, extpressure, 50*ONE_ATMOSPHERE)
parent.updateUsrDialog()
return 1
if(href_list["swap_modes"])
mode = !mode
vent_pump = null//if we don't clear this is could get glitchy, by which I mean not at all, whatever, stay clean
parent.updateUsrDialog()
return 1
/datum/automation/set_vent_pressure_checks
name = "Vent Pump: Pressure Checks"
var/vent_pump = null
var/checks = 1
var/mode = 0//1 for DP vent, 0 for unary vent
/*
checks bitflags
1 = external
2 = internal in (regular internal for unaries)
4 = internal out (ignored by unaries)
*/
Export()
var/list/json = ..()
json["vent_pump"] = vent_pump
json["checks"] = checks
json["mode"] = mode
return json
Import(var/list/json)
..(json)
vent_pump = json["vent_pump"]
checks = text2num(json["checks"])
mode = text2num(json["mode"])
New(var/obj/machinery/computer/general_air_control/atmos_automation/aa)
..(aa)
process()
if(vent_pump)
parent.send_signal(list("tag" = vent_pump, "checks" = checks), filter = (mode ? RADIO_ATMOSIA : RADIO_FROM_AIRALARM))//not gonna bother with a sanity check here, there *should* not be any problems
GetText()
if(mode)
return {"Set <a href=\"?src=[UID()];swap_modes=1\">dual-port</a> vent pump <a href=\"?src=[UID()];set_vent_pump=1\">[fmtString(vent_pump)]</a> pressure checks to:
external <a href=\"?src=[UID()];togglecheck=1\">[checks&1 ? "Enabled" : "Disabled"]</a>
internal inwards <a href=\"?src=[UID()];togglecheck=2\">[checks&2 ? "Enabled" : "Disabled"]</a>
internal outwards <a href=\"?src=[UID()];togglecheck=4\">[checks&4 ? "Enabled" : "Disabled"]</a>
"}
else
return {"Set <a href=\"?src=[UID()];swap_modes=1\">unary</a> vent pump <a href=\"?src=[UID()];set_vent_pump=1\">[fmtString(vent_pump)]</a> pressure checks to:
external: <a href=\"?src=[UID()];togglecheck=1\">[checks&1 ? "Enabled" : "Disabled"]</a>,
internal: <a href=\"?src=[UID()];togglecheck=2\">[checks&2 ? "Enabled" : "Disabled"]</a>
"}
Topic(href, href_list)
if(..())
return 1
if(href_list["set_vent_pump"])
var/list/injector_names=list()
if(mode)//DP vent selection
for(var/obj/machinery/atmospherics/binary/dp_vent_pump/I in world)
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names|=I.id_tag
else
for(var/obj/machinery/atmospherics/unary/vent_pump/I in GLOB.machines)
if(!isnull(I.id_tag) && I.frequency == parent.frequency)
injector_names|=I.id_tag
vent_pump = input("Select a vent:", "Vent Pumps", vent_pump) as null|anything in injector_names
parent.updateUsrDialog()
return 1
if(href_list["swap_modes"])
mode = !mode
vent_pump = null//if we don't clear this is could get glitchy, by which I mean not at all, whatever, stay clean
if(!mode && checks&4)//disable this bitflag since we're switching to unaries
checks &= ~4
parent.updateUsrDialog()
return 1
if(href_list["togglecheck"])
var/bitflagvalue = text2num(href_list["togglecheck"])
if(mode)
if(!(bitflagvalue in list(1, 2, 4)))
return 0
else if(!(bitflagvalue in list(1, 2)))
return 0
if(checks&bitflagvalue)//the bitflag is on ATM
checks &= ~bitflagvalue
else//can't not be off
checks |= bitflagvalue
parent.updateUsrDialog()
return 1
-457
View File
@@ -1,457 +0,0 @@
GLOBAL_LIST_INIT(automation_types, subtypesof(/datum/automation))
#define AUTOM_RT_NULL 0
#define AUTOM_RT_NUM 1
#define AUTOM_RT_STRING 2
/datum/automation
// Name of the Automation
var/name="Base Automation"
// For labelling what shit does on the AAC.
var/label="Unnamed Script"
var/desc ="No Description."
var/obj/machinery/computer/general_air_control/atmos_automation/parent
var/list/valid_child_returntypes=list()
var/list/datum/automation/children=list()
var/returntype=AUTOM_RT_NULL
/datum/automation/New(var/obj/machinery/computer/general_air_control/atmos_automation/aa)
parent=aa
/datum/automation/proc/GetText()
return "[type] doesn't override GetText()!"
/datum/automation/proc/OnReset()
return
/datum/automation/proc/OnRemove()
return
/datum/automation/process()
return
/datum/automation/proc/Evaluate()
return 0
/datum/automation/proc/Export()
var/list/R = list("type"=type)
if(initial(label)!=label)
R["label"]=label
if(initial(desc)!=desc)
R["desc"]=desc
if(children.len>0)
var/list/C=list()
for(var/datum/automation/A in children)
C += list(A.Export())
R["children"]=C
return R
/datum/automation/proc/unpackChild(var/list/cData)
if(isnull(cData) || !("type" in cData))
return null
var/Atype=text2path(cData["type"])
if(!(Atype in GLOB.automation_types))
return null
var/datum/automation/A = new Atype(parent)
A.Import(cData)
return A
/datum/automation/proc/unpackChildren(var/list/childList)
. = list()
if(childList.len>0)
for(var/list/cData in childList)
if(isnull(cData) || !("type" in cData))
. += null
continue
var/Atype=text2path(cData["type"])
if(!(Atype in GLOB.automation_types))
continue
var/datum/automation/A = new Atype(parent)
A.Import(cData)
. += A
/datum/automation/proc/packChildren(var/list/childList)
. = list()
if(childList.len>0)
for(var/datum/automation/A in childList)
if(isnull(A) || !istype(A))
. += null
continue
. += list(A.Export())
/datum/automation/proc/Import(var/list/json)
if("label" in json)
label = json["label"]
if("desc" in json)
desc = json["desc"]
if("children" in json)
children = unpackChildren(json["children"])
/datum/automation/proc/fmtString(var/str)
if(str==null || str == "")
return "-----"
return str
/datum/automation/Topic(href,href_list)
if(parent.Topic("src=[parent.UID()]", list("src" = parent)))//dumb hack to check sanity, empty topic shouldn't trigger a 1 on anything but sanity checks
return 1
if(href_list["add"])
var/new_child=selectValidChildFor(usr)
if(!new_child) return 1
children += new_child
parent.updateUsrDialog()
return 1
if(href_list["remove"])
if(href_list["remove"]=="*")
var/confirm=alert("Are you sure you want to remove ALL automations?","Automations","Yes","No")
if(confirm == "No") return 0
for(var/datum/automation/A in children)
A.OnRemove()
children.Remove(A)
else
var/datum/automation/A=locate(href_list["remove"])
if(!A) return 1
var/confirm=alert("Are you sure you want to remove this automation?","Automations","Yes","No")
if(confirm == "No") return 0
A.OnRemove()
children.Remove(A)
parent.updateUsrDialog()
return 1
if(href_list["reset"])
if(href_list["reset"]=="*")
for(var/datum/automation/A in children)
A.OnReset()
else
var/datum/automation/A=locate(href_list["reset"])
if(!A) return 1
A.OnReset()
parent.updateUsrDialog()
return 1
return 0 // 1 if handled
/datum/automation/proc/selectValidChildFor(var/mob/user, var/list/returntypes=valid_child_returntypes)
return parent.selectValidChildFor(src, user, returntypes)
///////////////////////////////////////////
// AND
///////////////////////////////////////////
/datum/automation/and
name = "AND statement"
returntype=AUTOM_RT_NUM
valid_child_returntypes=list(AUTOM_RT_NUM)
Evaluate()
if(children.len==0) return 0
for(var/datum/automation/stmt in children)
if(!stmt.Evaluate())
return 0
return 1
GetText()
var/out="AND (<a href=\"?src=[UID()];add=1\">Add</a>)"
if(children.len>0)
out += "<ul>"
for(var/datum/automation/stmt in children)
out += {"<li>
\[<a href="?src=[UID()];reset=\ref[stmt]">Reset</a> |
<a href="?src=[UID()];remove=\ref[stmt]">&times;</a>\]
[stmt.GetText()]
</li>"}
out += "</ul>"
else
out += "<blockquote><i>No statements to evaluate.</i></blockquote>"
return out
///////////////////////////////////////////
// OR
///////////////////////////////////////////
/datum/automation/or
name = "OR statement"
returntype=AUTOM_RT_NUM
valid_child_returntypes=list(AUTOM_RT_NUM)
Evaluate()
if(children.len==0) return 0
for(var/datum/automation/stmt in children)
if(stmt.Evaluate())
return 1
return 0
GetText()
var/out="OR (<a href=\"?src=[UID()];add=1\">Add</a>)"
if(children.len>0)
out += "<ul>"
for(var/datum/automation/stmt in children)
out += {"<li>
\[<a href="?src=[UID()];reset=\ref[stmt]">Reset</a> |
<a href="?src=[UID()];remove=\ref[stmt]">&times;</a>\]
[stmt.GetText()]
</li>"}
out += "</ul>"
else
out += "<blockquote><i>No statements to evaluate.</i></blockquote>"
return out
///////////////////////////////////////////
// if .. then
///////////////////////////////////////////
/datum/automation/if_statement
name = "IF statement"
var/datum/automation/condition=null
valid_child_returntypes=list(AUTOM_RT_NULL)
var/list/valid_conditions=list(AUTOM_RT_NUM)
var/list/children_then=list()
var/list/children_else=list()
Export()
var/list/R = ..()
if(children_then.len>0)
R["then"]=packChildren(children_then)
if(children_else.len>0)
R["else"]=packChildren(children_else)
if(condition)
R["condition"]=condition.Export()
return R
Import(var/list/json)
..(json)
if("then" in json)
children_then = unpackChildren(json["then"])
if("else" in json)
children_else = unpackChildren(json["else"])
if("condition" in json)
condition = unpackChild(json["condition"])
GetText()
var/out="<b>IF</b> (<a href=\"?src=[UID()];set_condition=1\">SET</a>):<blockquote>"
if(condition)
out += condition.GetText()
else
out += "<i>Not set</i>"
out += "</blockquote>"
out += "<b>THEN:</b> (<a href=\"?src=[UID()];add=then\">Add</a>)"
if(children_then.len>0)
out += "<ul>"
for(var/datum/automation/stmt in children_then)
out += {"<li>
\[<a href="?src=[UID()];reset=\ref[stmt];context=then">Reset</a> |
<a href="?src=[UID()];remove=\ref[stmt];context=then">&times;</a>\]
[stmt.GetText()]
</li>"}
out += "</ul>"
else
out += "<blockquote><i>(No statements to run)</i></blockquote>"
out += "<b>ELSE:</b> (<a href=\"?src=[UID()];add=else\">Add</a>)"
if(children_then.len>0)
out += "<ul>"
for(var/datum/automation/stmt in children_else)
out += {"<li>
\[<a href="?src=[UID()];reset=\ref[stmt];context=else">Reset</a> |
<a href="?src=[UID()];remove=\ref[stmt];context=else">&times;</a>\]
[stmt.GetText()]
</li>"}
out += "</ul>"
else
out += "<blockquote><i>(No statements to run)</i></blockquote>"
return out
Topic(href,href_list)
if(href_list["add"])
var/new_child=selectValidChildFor(usr)
if(!new_child) return 1
switch(href_list["add"])
if("then")
children_then += new_child
if("else")
children_else += new_child
else
warning("Unknown add value given to [type]/Topic():[__LINE__]: [href]")
return 1
parent.updateUsrDialog()
return 1
if(href_list["remove"])
if(href_list["remove"]=="*")
var/confirm=input("Are you sure you want to remove ALL automations?","Automations","No") in list("Yes","No")
if(confirm == "No") return 0
for(var/datum/automation/A in children_then)
A.OnRemove()
children_then.Remove(A)
for(var/datum/automation/A in children_else)
A.OnRemove()
children_else.Remove(A)
else
var/datum/automation/A=locate(href_list["remove"])
if(!A) return 1
var/confirm=input("Are you sure you want to remove this automation?","Automations","No") in list("Yes","No")
if(confirm == "No") return 0
A.OnRemove()
switch(href_list["context"])
if("then")
children_then.Remove(A)
if("else")
children_else.Remove(A)
parent.updateUsrDialog()
return 1
if(href_list["reset"])
if(href_list["reset"]=="*")
for(var/datum/automation/A in children_then)
A.OnReset()
for(var/datum/automation/A in children_else)
A.OnReset()
else
var/datum/automation/A=locate(href_list["reset"])
if(!A) return 1
A.OnReset()
parent.updateUsrDialog()
return 1
if(href_list["set_condition"])
var/new_condition = selectValidChildFor(usr,valid_conditions)
testing("Selected condition: [new_condition]")
if(!new_condition)
return 1
condition = new_condition
parent.updateUsrDialog()
return 1
process()
if(condition)
if(condition.Evaluate())
for(var/datum/automation/stmt in children_then)
stmt.process()
else
for(var/datum/automation/stmt in children_else)
stmt.process()
///////////////////////////////////////////
// compare
///////////////////////////////////////////
/datum/automation/compare
name = "comparison"
var/comparator="Greater Than"
returntype=AUTOM_RT_NUM
valid_child_returntypes=list(AUTOM_RT_NUM)
New(var/obj/machinery/computer/general_air_control/atmos_automation/aa)
..(aa)
children=list(null,null)
Export()
var/list/json = ..()
json["cmp"]=comparator
return json
Import(var/list/json)
..(json)
comparator = json["cmp"]
Evaluate()
if(children.len<2)
return 0
var/datum/automation/d_left =children[1]
var/datum/automation/d_right=children[2]
if(!d_left || !d_right)
return 0
var/left=d_left.Evaluate()
var/right=d_right.Evaluate()
switch(comparator)
if("Greater Than")
return left>right
if("Greater Than or Equal to")
return left>=right
if("Less Than")
return left<right
if("Less Than or Equal to")
return left<=right
if("Equal to")
return left==right
if("NOT Equal To")
return left!=right
else
return 0
GetText()
var/datum/automation/left =children[1]
var/datum/automation/right=children[2]
var/out = "<a href=\"?src=[UID()];set_field=1\">(Set Left)</a> ("
if(left==null)
out += "-----"
else
out += left.GetText()
out += ") is <a href=\"?src=[UID()];set_comparator=left\">[comparator]</a>: <a href=\"?src=[UID()];set_field=2\">(Set Right)</a> ("
if(right==null)
out += "-----"
else
out += right.GetText()
out +=")"
return out
Topic(href,href_list)
if(href_list["set_comparator"])
comparator = input("Select a comparison operator:", "Compare", "Greater Than") in list("Greater Than","Greater Than or Equal to","Less Than","Less Than or Equal to","Equal to","NOT Equal To")
parent.updateUsrDialog()
return 1
if(href_list["set_field"])
var/idx = text2num(href_list["set_field"])
var/new_child = selectValidChildFor(usr)
if(!new_child)
return 1
children[idx] = new_child
parent.updateUsrDialog()
return 1
///////////////////////////////////////////
// static value
///////////////////////////////////////////
/datum/automation/static_value
name = "Number"
var/value=0
returntype=AUTOM_RT_NUM
Evaluate()
return value
Export()
var/list/json = ..()
json["value"]=value
return json
Import(var/list/json)
..(json)
value = text2num(json["value"])
GetText()
return "<a href=\"?src=[UID()];set_value=1\">[value]</a>"
Topic(href,href_list)
if(href_list["set_value"])
value = input("Set a value:", "Static Value", value) as num
parent.updateUsrDialog()
return 1
+4 -4
View File
@@ -48,7 +48,7 @@ GLOBAL_DATUM_INIT(the_gateway, /obj/machinery/gateway/centerstation, null)
..()
update_icon()
wait = world.time + config.gateway_delay //+ thirty minutes default
awaygate = locate(/obj/machinery/gateway/centeraway) in world
awaygate = locate(/obj/machinery/gateway/centeraway) in GLOB.machines
/obj/machinery/gateway/centerstation/update_density_from_dir()
return
@@ -103,7 +103,7 @@ GLOBAL_DATUM_INIT(the_gateway, /obj/machinery/gateway/centerstation, null)
if(!powered())
return
if(!awaygate)
awaygate = locate(/obj/machinery/gateway/centeraway) in world
awaygate = locate(/obj/machinery/gateway/centeraway) in GLOB.machines
if(!awaygate)
to_chat(user, "<span class='notice'>Error: No destination found.</span>")
return
@@ -180,7 +180,7 @@ GLOBAL_DATUM_INIT(the_gateway, /obj/machinery/gateway/centerstation, null)
/obj/machinery/gateway/centeraway/Initialize()
..()
update_icon()
stationgate = locate(/obj/machinery/gateway/centerstation) in world
stationgate = locate(/obj/machinery/gateway/centerstation) in GLOB.machines
/obj/machinery/gateway/centeraway/update_density_from_dir()
@@ -219,7 +219,7 @@ GLOBAL_DATUM_INIT(the_gateway, /obj/machinery/gateway/centerstation, null)
if(linked.len != 8)
return
if(!stationgate)
stationgate = locate(/obj/machinery/gateway/centerstation) in world
stationgate = locate(/obj/machinery/gateway/centerstation) in GLOB.machines
if(!stationgate)
to_chat(user, "<span class='notice'>Error: No destination found.</span>")
return
@@ -1,72 +1,82 @@
GLOBAL_DATUM_INIT(maploader, /dmm_suite, new())
dmm_suite{
/*
/*
dmm_suite version 1.0
Released January 30th, 2011.
dmm_suite version 1.0
Released January 30th, 2011.
defines the object /dmm_suite
- Provides the proc load_map()
- Loads the specified map file onto the specified z-level.
- provides the proc write_map()
- Returns a text string of the map in dmm format
ready for output to a file.
- provides the proc save_map()
- Returns a .dmm file if map is saved
- Returns FALSE if map fails to save
defines the object /dmm_suite
- Provides the proc load_map()
- Loads the specified map file onto the specified z-level.
- provides the proc write_map()
- Returns a text string of the map in dmm format
ready for output to a file.
- provides the proc save_map()
- Returns a .dmm file if map is saved
- Returns FALSE if map fails to save
The dmm_suite provides saving and loading of map files in BYOND's native DMM map
format. It approximates the map saving and loading processes of the Dream Maker
and Dream Seeker programs so as to allow editing, saving, and loading of maps at
runtime.
The dmm_suite provides saving and loading of map files in BYOND's native DMM map
format. It approximates the map saving and loading processes of the Dream Maker
and Dream Seeker programs so as to allow editing, saving, and loading of maps at
runtime.
------------------------
------------------------
To save a map at runtime, create an instance of /dmm_suite, and then call
write_map(), which accepts three arguments:
- A turf representing one corner of a three dimensional grid (Required).
- Another turf representing the other corner of the same grid (Required).
- Any, or a combination, of several bit flags (Optional, see documentation).
To save a map at runtime, create an instance of /dmm_suite, and then call
write_map(), which accepts three arguments:
- A turf representing one corner of a three dimensional grid (Required).
- Another turf representing the other corner of the same grid (Required).
- Any, or a combination, of several bit flags (Optional, see documentation).
The order in which the turfs are supplied does not matter, the /dmm_writer will
determine the grid containing both, in much the same way as DM's block() function.
write_map() will then return a string representing the saved map in dmm format;
this string can then be saved to a file, or used for any other purose.
The order in which the turfs are supplied does not matter, the /dmm_writer will
determine the grid containing both, in much the same way as DM's block() function.
write_map() will then return a string representing the saved map in dmm format;
this string can then be saved to a file, or used for any other purose.
------------------------
------------------------
To load a map at runtime, create an instance of /dmm_suite, and then call load_map(),
which accepts two arguments:
- A .dmm file to load (Required).
- A number representing the z-level on which to start loading the map (Optional).
To load a map at runtime, create an instance of /dmm_suite, and then call load_map(),
which accepts two arguments:
- A .dmm file to load (Required).
- A number representing the z-level on which to start loading the map (Optional).
The /dmm_suite will load the map file starting on the specified z-level. If no
z-level was specified, world.maxz will be increased so as to fit the map. Note
that if you wish to load a map onto a z-level that already has objects on it,
you will have to handle the removal of those objects. Otherwise the new map will
simply load the new objects on top of the old ones.
The /dmm_suite will load the map file starting on the specified z-level. If no
z-level was specified, world.maxz will be increased so as to fit the map. Note
that if you wish to load a map onto a z-level that already has objects on it,
you will have to handle the removal of those objects. Otherwise the new map will
simply load the new objects on top of the old ones.
Also note that all type paths specified in the .dmm file must exist in the world's
code, and that the /dmm_reader trusts that files to be loaded are in fact valid
.dmm files. Errors in the .dmm format will cause runtime errors.
Also note that all type paths specified in the .dmm file must exist in the world's
code, and that the /dmm_reader trusts that files to be loaded are in fact valid
.dmm files. Errors in the .dmm format will cause runtime errors.
*/
*/
verb/load_map(var/dmm_file as file, var/x_offset as num, var/y_offset as num, var/z_offset as num, do_sleep as num){
// dmm_file: A .dmm file to load (Required).
// z_offset: A number representing the z-level on which to start loading the map (Optional).
}
verb/write_map(var/turf/t1 as turf, var/turf/t2 as turf, var/flags as num){
// t1: A turf representing one corner of a three dimensional grid (Required).
// t2: Another turf representing the other corner of the same grid (Required).
// flags: Any, or a combination, of several bit flags (Optional, see documentation).
}
GLOBAL_DATUM_INIT(maploader, /datum/dmm_suite, new())
// save_map is included as a legacy proc. Use write_map instead.
verb/save_map(var/turf/t1 as turf, var/turf/t2 as turf, var/map_name as text, var/flags as num){
// t1: A turf representing one corner of a three dimensional grid (Required).
// t2: Another turf representing the other corner of the same grid (Required).
// map_name: A valid name for the map to be saved, such as "castle" (Required).
// flags: Any, or a combination, of several bit flags (Optional, see documentation).
}
}
/datum/dmm_suite
var/static/quote = "\""
// These regexes are global - meaning that starting the maploader again mid-load will
// reset progress - which means we need to track our index per-map, or we'll
// eternally recurse
// /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g
var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g")
// /^[\s\n]+"?|"?[\s\n]+$|^"|"$/g
var/static/regex/trimQuotesRegex = new/regex({"^\[\\s\n]+"?|"?\[\\s\n]+$|^"|"$"}, "g")
// /^[\s\n]+|[\s\n]+$/
var/static/regex/trimRegex = new/regex("^\[\\s\n]+|\[\\s\n]+$", "g")
var/static/list/modelCache = list()
var/static/list/letter_digits = list(
"a", "b", "c", "d", "e",
"f", "g", "h", "i", "j",
"k", "l", "m", "n", "o",
"p", "q", "r", "s", "t",
"u", "v", "w", "x", "y",
"z",
"A", "B", "C", "D", "E",
"F", "G", "H", "I", "J",
"K", "L", "M", "N", "O",
"P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y",
"Z"
)
+107 -120
View File
@@ -1,23 +1,11 @@
///////////////////////////////////////////////////////////////
//SS13 Optimized Map loader
// SS13 Optimized Map loader
//////////////////////////////////////////////////////////////
//As of 3.6.2016
//global datum that will preload variables on atoms instanciation
// As of 3.6.2016
// global datum that will preload variables on atoms instanciation
GLOBAL_VAR_INIT(use_preloader, FALSE)
GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
/dmm_suite
// These regexes are global - meaning that starting the maploader again mid-load will
// reset progress - which means we need to track our index per-map, or we'll
// eternally recurse
// /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g
var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g")
// /^[\s\n]+"?|"?[\s\n]+$|^"|"$/g
var/static/regex/trimQuotesRegex = new/regex({"^\[\\s\n]+"?|"?\[\\s\n]+$|^"|"$"}, "g")
// /^[\s\n]+|[\s\n]+$/
var/static/regex/trimRegex = new/regex("^\[\\s\n]+|\[\\s\n]+$", "g")
var/static/list/modelCache = list()
GLOBAL_DATUM_INIT(_preloader, /datum/dmm_suite/preloader, new())
/**
* Construct the model map and control the loading process
@@ -37,13 +25,18 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
* atmos will attempt to start before it's ready, causing runtimes galore if init is
* allowed to romp unchecked.
*/
/dmm_suite/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num)
var/tfile = dmm_file//the map file we're creating
/datum/dmm_suite/proc/load_map(dmm_file, x_offset = 0, y_offset = 0, z_offset = 0, shouldCropMap = FALSE, measureOnly = FALSE)
var/tfile = dmm_file// the map file we're creating
var/fname = "Lambda"
if(isfile(tfile))
fname = "[tfile]"
// Make sure we dont load a dir up
var/lastchar = copytext(fname, -1)
if(lastchar == "/" || lastchar == "\\")
log_debug("Attempted to load map template without filename (Attempted [tfile])")
return
tfile = file2text(tfile)
if(length(tfile) == 0)
if(!length(tfile))
throw EXCEPTION("Map path '[fname]' does not exist!")
if(!x_offset)
@@ -57,7 +50,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
var/list/grid_models = list()
var/key_len = 0
var/dmm_suite/loaded_map/LM = new
var/datum/dmm_suite/loaded_map/LM = new
// This try-catch is used as a budget "Finally" clause, as the dirt count
// needs to be reset
var/watch = start_watch()
@@ -76,7 +69,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
if(!key_len)
key_len = length(key)
else
throw EXCEPTION("Inconsistant key length in DMM")
throw EXCEPTION("Inconsistent key length in DMM")
if(!measureOnly)
grid_models[key] = dmmRegex.group[2]
@@ -86,17 +79,17 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
throw EXCEPTION("Coords before model definition in DMM")
var/xcrdStart = text2num(dmmRegex.group[3]) + x_offset - 1
//position of the currently processed square
// position of the currently processed square
var/xcrd
var/ycrd = text2num(dmmRegex.group[4]) + y_offset - 1
var/zcrd = text2num(dmmRegex.group[5]) + z_offset - 1
if(!measureOnly)
if(zcrd > world.maxz)
if(cropMap)
if(shouldCropMap)
continue
else
GLOB.space_manager.increase_max_zlevel_to(zcrd) //create a new z_level if needed
GLOB.space_manager.increase_max_zlevel_to(zcrd) // create a new z_level if needed
bounds[MAP_MINX] = min(bounds[MAP_MINX], xcrdStart)
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], zcrd)
@@ -118,7 +111,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
bounds[MAP_MINY] = min(bounds[MAP_MINY], ycrd)
ycrd += gridLines.len - 1 // Start at the top and work down
if(!cropMap && ycrd > world.maxy)
if(!shouldCropMap && ycrd > world.maxy)
if(!measureOnly)
world.maxy = ycrd // Expand Y here. X is expanded in the loop below
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], ycrd)
@@ -133,9 +126,9 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
for(var/line in gridLines)
if(ycrd <= world.maxy && ycrd >= 1)
xcrd = xcrdStart
for(var/tpos = 1 to length(line) - key_len + 1 step key_len)
for(var/tpos = 1 to (length(line) - key_len + 1) step key_len)
if(xcrd > world.maxx)
if(cropMap)
if(shouldCropMap)
break
else
world.maxx = xcrd
@@ -152,7 +145,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
maxx = max(maxx, xcrd)
++xcrd
--ycrd
bounds[MAP_MAXX] = max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx)
bounds[MAP_MAXX] = max(bounds[MAP_MAXX], shouldCropMap ? min(maxx, world.maxx) : maxx)
CHECK_TICK
catch(var/exception/e)
@@ -175,8 +168,8 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
if(!measureOnly)
for(var/t in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
var/turf/T = t
//we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs
T.AfterChange(1, keep_cabling = TRUE)
// we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs
T.AfterChange(TRUE, keep_cabling = TRUE)
return bounds
/**
@@ -196,14 +189,14 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
* 4) Instanciates the atom with its variables
*
*/
/dmm_suite/proc/parse_grid(model as text,xcrd as num,ycrd as num,zcrd as num, dmm_suite/loaded_map/LM)
/datum/dmm_suite/proc/parse_grid(model = "", xcrd = 0, ycrd = 0, zcrd = 0, datum/dmm_suite/loaded_map/LM)
/*Method parse_grid()
- Accepts a text string containing a comma separated list of type paths of the
same construction as those contained in a .dmm file, and instantiates them.
*/
var/list/members //will contain all members (paths) in model (in our example : /turf/unsimulated/wall and /area/mine/dangerous/explored)
var/list/members_attributes //will contain lists filled with corresponding variables, if any (in our example : list(icon_state = "rock") and list())
var/list/members // will contain all members (paths) in model (in our example : /turf/unsimulated/wall and /area/mine/dangerous/explored)
var/list/members_attributes // will contain lists filled with corresponding variables, if any (in our example : list(icon_state = "rock") and list())
var/list/cached = modelCache[model]
var/index
@@ -212,7 +205,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
members_attributes = cached[2]
else
/////////////////////////////////////////////////////////
//Constructing members and corresponding variables lists
// Constructing members and corresponding variables lists
////////////////////////////////////////////////////////
members = list()
@@ -223,13 +216,13 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
var/dpos
do
//finding next member (e.g /turf/unsimulated/wall{icon_state = "rock"} or /area/mine/dangerous/explored)
dpos = find_next_delimiter_position(model, old_position, ",", "{", "}") //find next delimiter (comma here) that's not within {...}
// finding next member (e.g /turf/unsimulated/wall{icon_state = "rock"} or /area/mine/dangerous/explored)
dpos = find_next_delimiter_position(model, old_position, ",", "{", "}") // find next delimiter (comma here) that's not within {...}
var/full_def = trim_text(copytext(model, old_position, dpos)) //full definition, e.g : /obj/foo/bar{variables=derp}
var/full_def = trim_text(copytext(model, old_position, dpos)) // full definition, e.g : /obj/foo/bar{variables=derp}
var/variables_start = findtext(full_def, "{")
var/atom_text = trim_text(copytext(full_def, 1, variables_start))
var/atom_def = text2path(atom_text) //path definition, e.g /obj/foo/bar
var/atom_def = text2path(atom_text) // path definition, e.g /obj/foo/bar
old_position = dpos + 1
if(!atom_def) // Skip the item if the path does not exist. Fix your crap, mappers!
@@ -237,14 +230,14 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
continue
members.Add(atom_def)
//transform the variables in text format into a list (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
// transform the variables in text format into a list (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
var/list/fields = list()
if(variables_start)//if there's any variable
full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}'
if(variables_start) // if there's any variable
full_def = copytext(full_def, variables_start + 1, length(full_def)) // removing the last '}'
fields = readlist(full_def, ";")
//then fill the members_attributes list with the corresponding variables
// then fill the members_attributes list with the corresponding variables
members_attributes.len++
members_attributes[index++] = fields
@@ -255,24 +248,23 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
////////////////
//Instanciation
// Instanciation
////////////////
//The next part of the code assumes there's ALWAYS an /area AND a /turf on a given tile
// The next part of the code assumes there's ALWAYS an /area AND a /turf on a given tile
//first instance the /area and remove it from the members list
// first instance the /area and remove it from the members list
index = members.len
var/turf/crds = locate(xcrd,ycrd,zcrd)
var/turf/crds = locate(xcrd, ycrd, zcrd)
if(members[index] != /area/template_noop)
// We assume `members[index]` is an area path, as above, yes? I will operate
// on that assumption.
if(!ispath(members[index], /area))
throw EXCEPTION("Oh no, I thought this was an area!")
var/atom/instance
GLOB._preloader.setup(members_attributes[index])//preloader for assigning set variables on atom creation
instance = LM.area_path_to_real_area(members[index])
GLOB._preloader.setup(members_attributes[index]) // preloader for assigning set variables on atom creation
var/atom/instance = LM.area_path_to_real_area(members[index])
if(crds)
instance.contents.Add(crds)
@@ -280,45 +272,46 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
if(GLOB.use_preloader && instance)
GLOB._preloader.load(instance)
//then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect
// then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect
var/first_turf_index = 1
while(!ispath(members[first_turf_index],/turf)) //find first /turf object in members
while(!ispath(members[first_turf_index], /turf)) // find first /turf object in members
first_turf_index++
//instanciate the first /turf
// instanciate the first /turf
var/turf/T
if(members[first_turf_index] != /turf/template_noop)
T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],xcrd,ycrd,zcrd)
T = instance_atom(members[first_turf_index], members_attributes[first_turf_index], xcrd, ycrd, zcrd)
if(T)
//if others /turf are presents, simulates the underlays piling effect
// if others /turf are presents, simulates the underlays piling effect
index = first_turf_index + 1
while(index <= members.len - 1) // Last item is an /area
var/mlen = members.len - 1
while(index <= mlen) // Last item is an /area
var/underlay
if(istype(T, /turf)) // I blame this on the stupid clown who coded the BYOND map editor
underlay = T.appearance
T = instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)//instance new turf
if(ispath(members[index],/turf))
T = instance_atom(members[index], members_attributes[index], xcrd, ycrd, zcrd) // instance new turf
if(ispath(members[index], /turf))
T.underlays += underlay
index++
//finally instance all remainings objects/mobs
for(index in 1 to first_turf_index-1)
instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)
// finally instance all remainings objects/mobs
for(index in 1 to first_turf_index - 1)
instance_atom(members[index], members_attributes[index], xcrd, ycrd, zcrd)
CHECK_TICK
////////////////
//Helpers procs
// Helpers procs
////////////////
//Instance an atom at (x,y,z) and gives it the variables in attributes
/dmm_suite/proc/instance_atom(path,list/attributes, x, y, z)
// Instance an atom at (x, y, z) and gives it the variables in attributes
/datum/dmm_suite/proc/instance_atom(path, list/attributes, x, y, z)
var/atom/instance
GLOB._preloader.setup(attributes, path)
var/turf/T = locate(x,y,z)
var/turf/T = locate(x, y, z)
if(T)
if(ispath(path, /turf))
T.ChangeTurf(path, defer_change = TRUE, keep_icon = FALSE)
@@ -326,115 +319,111 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
else if(ispath(path, /area))
else
instance = new path (T)//first preloader pass
instance = new path(T) // first preloader pass
if(GLOB.use_preloader && instance)//second preloader pass, for those atoms that don't ..() in New()
if(GLOB.use_preloader && instance) // second preloader pass, for those atoms that don't ..() in New()
GLOB._preloader.load(instance)
return instance
//text trimming (both directions) helper proc
//optionally removes quotes before and after the text (for variable name)
/dmm_suite/proc/trim_text(what as text,trim_quotes=0)
// text trimming (both directions) helper proc
// optionally removes quotes before and after the text (for variable name)
/datum/dmm_suite/proc/trim_text(what, trim_quotes = FALSE)
if(trim_quotes)
return trimQuotesRegex.Replace(what, "")
else
return trimRegex.Replace(what, "")
//find the position of the next delimiter,skipping whatever is comprised between opening_escape and closing_escape
//returns 0 if reached the last delimiter
/dmm_suite/proc/find_next_delimiter_position(text as text,initial_position as num, delimiter=",",opening_escape=quote,closing_escape=quote)
// find the position of the next delimiter, skipping whatever is comprised between opening_escape and closing_escape
// returns 0 if reached the last delimiter
/datum/dmm_suite/proc/find_next_delimiter_position(text, initial_position = 0, delimiter = ",", opening_escape = quote, closing_escape = quote)
var/position = initial_position
var/next_delimiter = findtext(text,delimiter,position,0)
var/next_opening = findtext(text,opening_escape,position,0)
var/next_delimiter = findtext(text, delimiter, position, 0)
var/next_opening = findtext(text, opening_escape, position, 0)
while((next_opening != 0) && (next_opening < next_delimiter))
position = findtext(text,closing_escape,next_opening + 1,0)+1
next_delimiter = findtext(text,delimiter,position,0)
next_opening = findtext(text,opening_escape,position,0)
position = findtext(text, closing_escape, next_opening + 1, 0) + 1
next_delimiter = findtext(text, delimiter, position, 0)
next_opening = findtext(text, opening_escape, position, 0)
return next_delimiter
//build a list from variables in text form (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
//return the filled list
/dmm_suite/proc/readlist(text as text, delimiter=",")
// build a list from variables in text form (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
// return the filled list
/datum/dmm_suite/proc/readlist(text, delimiter = ",")
var/list/to_return = list()
var/position
var/old_position = 1
do
//find next delimiter that is not within "..."
position = find_next_delimiter_position(text,old_position,delimiter)
// find next delimiter that is not within "..."
position = find_next_delimiter_position(text, old_position, delimiter)
//check if this is a simple variable (as in list(var1, var2)) or an associative one (as in list(var1="foo",var2=7))
var/equal_position = findtext(text,"=",old_position, position)
// check if this is a simple variable (as in list(var1, var2)) or an associative one (as in list(var1="foo", var2=7))
var/equal_position = findtext(text, "=", old_position, position)
var/trim_left = trim_text(copytext(text,old_position,(equal_position ? equal_position : position)),1)//the name of the variable, must trim quotes to build a BYOND compliant associatives list
var/trim_left = trim_text(copytext(text, old_position, (equal_position ? equal_position : position)), 1) // the name of the variable, must trim quotes to build a BYOND compliant associatives list
old_position = position + 1
if(equal_position)//associative var, so do the association
var/trim_right = trim_text(copytext(text,equal_position+1,position))//the content of the variable
if(equal_position) // associative var, so do the association
var/trim_right = trim_text(copytext(text, equal_position + 1, position)) // the content of the variable
//Check for string
// Check for string
// Make it read to the next delimiter, instead of the quote
if(findtext(trim_right,quote,1,2))
var/endquote = findtext(trim_right,quote,-1)
if(findtext(trim_right, quote, 1, 2))
var/endquote = findtext(trim_right, quote, -1)
if(!endquote)
log_runtime(EXCEPTION("Terminating quote not found!"), src)
// Our map writer escapes quotes and curly brackets to avoid
// letting our simple parser choke on meanly-crafted names/etc
// - so we decode it here so it's back to good ol' legibility
trim_right = dmm_decode(copytext(trim_right,2,endquote))
trim_right = dmm_decode(copytext(trim_right, 2, endquote))
//Check for number
// Check for number
else if(isnum(text2num(trim_right)))
trim_right = text2num(trim_right)
//Check for null
// Check for null
else if(trim_right == "null")
trim_right = null
//Check for list
else if(copytext(trim_right,1,5) == "list")
trim_right = readlist(copytext(trim_right,6,length(trim_right)))
// Check for list
else if(copytext(trim_right, 1, 5) == "list")
trim_right = readlist(copytext(trim_right, 6, length(trim_right)))
//Check for file
else if(copytext(trim_right,1,2) == "'")
trim_right = file(copytext(trim_right,2,length(trim_right)))
// Check for file
else if(copytext(trim_right, 1, 2) == "'")
trim_right = file(copytext(trim_right, 2, length(trim_right)))
//Check for path
// Check for path
else if(ispath(text2path(trim_right)))
trim_right = text2path(trim_right)
to_return[trim_left] = trim_right
else//simple var
else// simple var
to_return[trim_left] = null
while(position != 0)
return to_return
/dmm_suite/Destroy()
/datum/dmm_suite/Destroy()
..()
return QDEL_HINT_HARDDEL_NOW
//////////////////
//Preloader datum
// Preloader datum
//////////////////
// This ain't re-entrant, but we had this before the maploader update
/dmm_suite/preloader
parent_type = /datum
/datum/dmm_suite/preloader
var/list/attributes
var/target_path
var/json_ready = 0
/dmm_suite/preloader/proc/setup(list/the_attributes, path)
/datum/dmm_suite/preloader/proc/setup(list/the_attributes, path)
if(the_attributes.len)
json_ready = 0
if("map_json_data" in the_attributes)
@@ -443,25 +432,24 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
attributes = the_attributes
target_path = path
/dmm_suite/preloader/proc/load(atom/what)
/datum/dmm_suite/preloader/proc/load(atom/A)
if(json_ready)
var/json_data = attributes["map_json_data"]
var/json_data = dmm_decode(attributes["map_json_data"])
attributes -= "map_json_data"
json_data = dmm_decode(json_data)
try
what.deserialize(json_decode(json_data))
catch(var/exception/e)
A.deserialize(json_decode(json_data))
catch(var/exception/E)
log_runtime(EXCEPTION("Bad json data: '[json_data]'"), src)
throw e
throw E
for(var/attribute in attributes)
var/value = attributes[attribute]
if(islist(value))
value = deepCopyList(value)
what.vars[attribute] = value
A.vars[attribute] = value
GLOB.use_preloader = FALSE
// If the map loader fails, make this safe
/dmm_suite/preloader/proc/reset()
/datum/dmm_suite/preloader/proc/reset()
GLOB.use_preloader = FALSE
attributes = list()
target_path = null
@@ -470,12 +458,11 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new())
// so that one can have separate "unpowered" areas for ruins or whatever,
// yet have a single area type for use of mapping, instead of creating
// a new area type for each new ruin
/dmm_suite/loaded_map
parent_type = /datum
/datum/dmm_suite/loaded_map
var/list/area_list = list()
var/index = 1 // To store the state of the regex
/dmm_suite/loaded_map/proc/area_path_to_real_area(area/A)
/datum/dmm_suite/loaded_map/proc/area_path_to_real_area(area/A)
if(!ispath(A, /area))
throw EXCEPTION("Wrong argument to `area_path_to_real_area`")
+78 -77
View File
@@ -5,28 +5,12 @@
#define DMM_IGNORE_PLAYERS 16
#define DMM_IGNORE_MOBS 24
#define DMM_USE_JSON 32
/dmm_suite
var/quote = "\""
var/list/letter_digits = list(
"a","b","c","d","e",
"f","g","h","i","j",
"k","l","m","n","o",
"p","q","r","s","t",
"u","v","w","x","y",
"z",
"A","B","C","D","E",
"F","G","H","I","J",
"K","L","M","N","O",
"P","Q","R","S","T",
"U","V","W","X","Y",
"Z"
)
/dmm_suite/save_map(var/turf/t1 as turf, var/turf/t2 as turf, var/map_name as text, var/flags as num)
//Check for illegal characters in file name... in a cheap way.
if(!((ckeyEx(map_name)==map_name) && ckeyEx(map_name)))
/datum/dmm_suite/proc/save_map(turf/t1, turf/t2, map_name = "", flags = 0)
// Check for illegal characters in file name... in a cheap way.
if(!((ckeyEx(map_name) == map_name) && ckeyEx(map_name)))
CRASH("Invalid text supplied to proc save_map, invalid characters or empty string.")
//Check for valid turfs.
// Check for valid turfs.
if(!isturf(t1) || !isturf(t2))
CRASH("Invalid arguments supplied to proc save_map, arguments were not turfs.")
@@ -35,17 +19,17 @@
if(fexists(map_path))
fdel(map_path)
var/saved_map = file(map_path)
var/map_text = write_map(t1,t2,flags,saved_map)
var/map_text = write_map(t1, t2, flags, saved_map)
saved_map << map_text
return saved_map
/dmm_suite/write_map(var/turf/t1 as turf, var/turf/t2 as turf, var/flags as num)
//Check for valid turfs.
/datum/dmm_suite/proc/write_map(turf/t1, turf/t2, flags = 0)
// Check for valid turfs.
if(!isturf(t1) || !isturf(t2))
CRASH("Invalid arguments supplied to proc write_map, arguments were not turfs.")
var/turf/ne = locate(max(t1.x,t2.x),max(t1.y,t2.y),max(t1.z,t2.z)) // Outer corner
var/turf/sw = locate(min(t1.x,t2.x),min(t1.y,t2.y),min(t1.z,t2.z)) // Inner corner
var/turf/ne = locate(max(t1.x, t2.x), max(t1.y, t2.y), max(t1.z, t2.z)) // Outer corner
var/turf/sw = locate(min(t1.x, t2.x), min(t1.y, t2.y), min(t1.z, t2.z)) // Inner corner
var/list/templates[0]
var/list/template_buffer = list()
var/template_buffer_text
@@ -54,37 +38,40 @@
var/total_timer = start_watch()
var/timer = start_watch()
log_debug("Reading turfs...")
// Read the contents of all the turfs we were given
for(var/pos_z in sw.z to ne.z)
for(var/pos_y in ne.y to sw.y step -1) // We're reversing this because the map format is silly
for(var/pos_x in sw.x to ne.x)
var/turf/test_turf = locate(pos_x,pos_y,pos_z)
var/turf/test_turf = locate(pos_x, pos_y, pos_z)
var/test_template = make_template(test_turf, flags)
var/template_number = templates.Find(test_template)
if(!template_number)
templates.Add(test_template)
template_number = templates.len
template_number = length(templates)
template_buffer += "[template_number],"
CHECK_TICK
template_buffer += ";"
template_buffer += "."
template_buffer_text = jointext(template_buffer,"")
template_buffer_text = jointext(template_buffer, "")
log_debug("Reading turfs took [stop_watch(timer)]s.")
if(templates.len == 0)
if(length(templates) == 0)
CRASH("No templates found!")
var/key_length = round/*floor*/(log(letter_digits.len,templates.len-1)+1)
var/list/keys[templates.len]
var/key_length = round(log(length(letter_digits), length(templates) - 1) + 1) // or floor
var/list/keys[length(templates)]
// Write the list of key/model pairs to the file
timer = start_watch()
log_debug("Writing out key/model pairs to file header...")
var/list/key_models = list()
for(var/key_pos in 1 to templates.len)
keys[key_pos] = get_model_key(key_pos,key_length)
for(var/key_pos in 1 to length(templates))
keys[key_pos] = get_model_key(key_pos, key_length)
key_models += "\"[keys[key_pos]]\" = ([templates[key_pos]])\n"
CHECK_TICK
dmm_text += jointext(key_models,"")
log_debug("Writing key/model pairs complete, took [stop_watch(timer)]s.")
@@ -92,58 +79,69 @@
// Loop over all z in our zone
timer = start_watch()
log_debug("Writing out key map...")
var/list/key_map = list()
for(var/z_pos=1;TRUE;z_pos=findtext(template_buffer_text,".",z_pos)+1)
if(z_pos>=length(template_buffer_text)) break
if(z_level) key_map += "\n"
for(var/z_pos = 1; TRUE; z_pos = findtext(template_buffer_text, ".", z_pos) + 1)
if(z_pos >= length(template_buffer_text))
break
if(z_level)
key_map += "\n"
key_map += "\n(1,1,[++z_level]) = {\"\n"
var/z_block = copytext(template_buffer_text,z_pos,findtext(template_buffer_text,".",z_pos))
for(var/y_pos=1;TRUE;y_pos=findtext(z_block,";",y_pos)+1)
if(y_pos>=length(z_block)) break
var/y_block = copytext(z_block,y_pos,findtext(z_block,";",y_pos))
var/z_block = copytext(template_buffer_text, z_pos, findtext(template_buffer_text, ".", z_pos))
for(var/y_pos = 1; TRUE; y_pos = findtext(z_block, ";", y_pos) + 1)
if(y_pos >= length(z_block))
break
var/y_block = copytext(z_block, y_pos, findtext(z_block, ";", y_pos))
// A row of keys
for(var/x_pos=1;TRUE;x_pos=findtext(y_block,",",x_pos)+1)
if(x_pos>=length(y_block)) break
var/x_block = copytext(y_block,x_pos,findtext(y_block,",",x_pos))
for(var/x_pos = 1; TRUE; x_pos = findtext(y_block, ",", x_pos) + 1)
if(x_pos >= length(y_block))
break
var/x_block = copytext(y_block, x_pos, findtext(y_block, ",", x_pos))
var/key_number = text2num(x_block)
var/temp_key = keys[key_number]
key_map += temp_key
CHECK_TICK
key_map += "\n"
key_map += "\"}"
dmm_text += jointext(key_map,"")
dmm_text += jointext(key_map, "")
log_debug("Writing key map complete, took [stop_watch(timer)]s.")
log_debug("TOTAL TIME: [stop_watch(total_timer)]s.")
return dmm_text
/dmm_suite/proc/make_template(var/turf/model as turf, var/flags as num)
var/use_json = 0
if(flags & DMM_USE_JSON)
use_json = 1
/datum/dmm_suite/proc/make_template(turf/model, flags = 0)
var/use_json = (flags & DMM_USE_JSON) ? TRUE : FALSE
var/template = ""
var/turf_template = ""
var/list/obj_template = list()
var/list/mob_template = list()
var/area_template = ""
// Turf
if(!(flags & DMM_IGNORE_TURFS))
turf_template = "[model.type][check_attributes(model,use_json=use_json)],"
else turf_template = "[world.turf],"
else
turf_template = "[world.turf],"
// Objects loop
if(!(flags & DMM_IGNORE_OBJS))
for(var/obj/O in model.contents)
if(O.dont_save || QDELETED(O))
continue
obj_template += "[O.type][check_attributes(O,use_json=use_json)],"
// Mobs Loop
for(var/mob/M in model.contents)
if(M.dont_save || QDELETED(M))
continue
if(M.client)
if(!(flags & DMM_IGNORE_PLAYERS))
mob_template += "[M.type][check_attributes(M,use_json=use_json)],"
@@ -155,65 +153,68 @@
if(!(flags & DMM_IGNORE_AREAS))
var/area/m_area = model.loc
area_template = "[m_area.type][check_attributes(m_area,use_json=use_json)]"
else area_template = "[world.area]"
else
area_template = "[world.area]"
template = "[jointext(obj_template,"")][jointext(mob_template,"")][turf_template][area_template]"
return template
/dmm_suite/proc/check_attributes(var/atom/A,use_json=0)
/datum/dmm_suite/proc/check_attributes(atom/A, use_json = FALSE)
var/attributes_text = "{"
var/list/attributes = list()
if(!use_json)
for(var/V in A.vars)
CHECK_TICK
if((!issaved(A.vars[V])) || (A.vars[V]==initial(A.vars[V]))) continue
if((!issaved(A.vars[V])) || (A.vars[V] == initial(A.vars[V])))
continue
attributes += var_to_dmm(A.vars[V], V)
else
var/list/yeah = A.serialize()
var/list/to_encode = A.serialize()
// We'll want to write out vars that are important to the editor
// So that the map is legible as before
for(var/thing in A.map_important_vars())
for(var/T in A.map_important_vars())
// Save vars that are important for the map editor, so that
// json-encoded maps are legible for standard editors
if(A.vars[thing] != initial(A.vars[thing]))
yeah -= thing
attributes += var_to_dmm(A.vars[thing],thing)
if(A.vars[T] != initial(A.vars[T]))
to_encode -= T
attributes += var_to_dmm(A.vars[T], T)
// Remove useless info
yeah -= "type"
if(yeah.len)
var/json_stuff = json_encode(yeah)
to_encode -= "type"
if(length(to_encode))
var/json_stuff = json_encode(to_encode)
attributes += var_to_dmm(json_stuff, "map_json_data")
if(attributes.len == 0)
if(length(attributes) == 0)
return
// Trim a trailing semicolon - `var_to_dmm` always appends a semicolon,
// so the last one will be trailing.
if(copytext(attributes_text, length(attributes_text)-1, 0) == "; ")
attributes_text = copytext(attributes_text, 1, length(attributes_text)-1)
if(copytext(attributes_text, length(attributes_text) - 1, 0) == "; ")
attributes_text = copytext(attributes_text, 1, length(attributes_text) - 1)
attributes_text = "{[jointext(attributes,"; ")]}"
return attributes_text
/dmm_suite/proc/get_model_key(var/which as num, var/key_length as num)
/datum/dmm_suite/proc/get_model_key(which, key_length)
var/list/key = list()
var/working_digit = which-1
var/working_digit = which - 1
for(var/digit_pos in key_length to 1 step -1)
var/place_value = round/*floor*/(working_digit/(letter_digits.len**(digit_pos-1)))
working_digit-=place_value*(letter_digits.len**(digit_pos-1))
key += letter_digits[place_value+1]
var/place_value = round/*floor*/(working_digit / (length(letter_digits) ** (digit_pos - 1)))
working_digit -= place_value * (length(letter_digits) ** (digit_pos - 1))
key += letter_digits[place_value + 1]
return jointext(key,"")
/dmm_suite/proc/var_to_dmm(attr, name)
/datum/dmm_suite/proc/var_to_dmm(attr, name)
if(istext(attr))
// dmm_encode will strip out characters that would be capable of disrupting
// parsing - namely, quotes and curly braces
return "[name] = \"[dmm_encode(attr)]\""
else if(isnum(attr)||ispath(attr))
else if(isnum(attr) || ispath(attr))
return "[name] = [attr]"
else if(isicon(attr)||isfile(attr))
else if(isicon(attr) || isfile(attr))
if(length("[attr]") == 0)
// The DM map reader is unable to read files that have a '' file/icon entry
return
@@ -191,26 +191,27 @@
origin_tech = null
selfcharge = 1
can_charge = 0
var/inawaymission = 1
// Selfcharge is enabled and disabled, and used as the away mission tracker
selfcharge = TRUE
/obj/item/gun/energy/laser/awaymission_aeg/process()
var/turf/my_loc = get_turf(src)
if(is_away_level(my_loc.z))
if(inawaymission)
return ..()
/obj/item/gun/energy/laser/awaymission_aeg/Initialize(mapload)
. = ..()
// Force update it incase it spawns outside an away mission and shouldnt be charged
onTransitZ(new_z = loc.z)
/obj/item/gun/energy/laser/awaymission_aeg/onTransitZ(old_z, new_z)
if(is_away_level(new_z))
if(ismob(loc))
to_chat(loc, "<span class='notice'>Your [src] activates, starting to draw power from a nearby wireless power source.</span>")
inawaymission = 1
selfcharge = TRUE
else
if(inawaymission)
if(selfcharge)
if(ismob(loc))
to_chat(loc, "<span class='danger'>Your [src] deactivates, as it is out of range from its power source.</span>")
cell.charge = 0
inawaymission = 0
selfcharge = FALSE
update_icon()
/obj/item/reagent_containers/glass/beaker/terror_black_toxin
name = "beaker 'Black Terror Venom'"
@@ -7,32 +7,32 @@
/area/awaymission/centcomAway/general
name = "XCC-P5831"
music = "music/ambigen3.ogg"
ambientsounds = list('sound/ambience/ambigen3.ogg')
/area/awaymission/centcomAway/maint
name = "XCC-P5831 Maintenance"
icon_state = "away1"
music = "music/ambisin1.ogg"
ambientsounds = list('sound/ambience/ambisin1.ogg')
/area/awaymission/centcomAway/thunderdome
name = "XCC-P5831 Thunderdome"
icon_state = "away2"
music = "music/ambisin2.ogg"
ambientsounds = list('sound/ambience/ambisin2.ogg')
/area/awaymission/centcomAway/cafe
name = "XCC-P5831 Kitchen Arena"
icon_state = "away3"
music = "music/ambisin3.ogg"
ambientsounds = list('sound/ambience/ambisin3.ogg')
/area/awaymission/centcomAway/courtroom
name = "XCC-P5831 Courtroom"
icon_state = "away4"
music = "music/ambisin4.ogg"
ambientsounds = list('sound/ambience/ambisin4.ogg')
/area/awaymission/centcomAway/hangar
name = "XCC-P5831 Hangars"
icon_state = "away4"
music = "music/ambigen5.ogg"
ambientsounds = list('sound/ambience/ambigen5.ogg')
//centcomAway items
@@ -105,7 +105,7 @@
/obj/item/paper/fluff/ruins/oldstation/damagereport
name = "Damage Report"
info = "<b>*Damage Report*</b><br><br><b>Alpha Station</b> - Destroyed<br><br><b>Beta Station</b> - Catastrophic Damage. Medical, destroyed. Atmospherics, partially destroyed. Engine Core, destroyed.<br><br><b>Charlie Station</b> - Intact. Loss of oxygen to eastern side of main corridor.<br><br><b>Delta Station</b> - Intact. <b>WARNING</b>: Unknown force occupying Delta Station. Intent unknown. Species unknown. Numbers unknown.<br><br>Recommendation - Reestablish station powernet via solar array. Reestablish station atmospherics system to restore air."
info = "<b>*Damage Report*</b><br><br><b>Alpha Station</b> - Destroyed<br><br><b>Beta Station</b> - Catastrophic Damage. Medical, destroyed. Atmospherics, partially destroyed. Engine Core, destroyed.<br><br><b>Charlie Station</b> - Intact. Loss of oxygen to eastern side of main corridor.<br><br><b>Theta Station</b> - Intact. <b>WARNING</b>: Unknown force occupying Theta Station. Intent unknown. Species unknown. Numbers unknown.<br><br>Recommendation - Reestablish station powernet via solar array. Reestablish station atmospherics system to restore air."
/obj/item/paper/fluff/ruins/oldstation/protosuit
name = "B01-RIG Hardsuit Report"
@@ -145,7 +145,7 @@
info = "Artificial Program's report to surviving crewmembers.<br><br>Crew were placed into cryostasis on March 10th, 2445.<br><br>Crew were awoken from cryostasis around June, 2557.<br><br> \
<b>SIGNIFICANT EVENTS OF NOTE</b><br>1: The primary radiation detectors were taken offline after 112 years due to power failure, secondary radiation detectors showed no residual \
radiation on station. Deduction, primarily detector was malfunctioning and was producing a radiation signal when there was none.<br><br>2: A data burst from a nearby Nanotrasen Space \
Station was received, this data burst contained research data that has been uploaded to our RnD labs.<br><br>3: Unknown invasion force has occupied Delta station."
Station was received, this data burst contained research data that has been uploaded to our RnD labs.<br><br>3: Unknown invasion force has occupied Theta station."
/obj/item/paper/fluff/ruins/oldstation/generator_manual
name = "S.U.P.E.R.P.A.C.M.A.N.-type portable generator manual"
@@ -321,6 +321,7 @@
name = "Beta Station Atmospherics"
icon_state = "red"
has_gravity = FALSE
ambientsounds = ENGINEERING_SOUNDS
/area/ruin/space/ancientstation/betanorth
name = "Beta Station North Corridor"
@@ -333,6 +334,7 @@
/area/ruin/space/ancientstation/engi
name = "Charlie Station Engineering"
icon_state = "engine"
ambientsounds = ENGINEERING_SOUNDS
/area/ruin/space/ancientstation/comm
name = "Charlie Station Command"
@@ -350,16 +352,16 @@
name = "Charlie Station Security"
icon_state = "red"
/area/ruin/space/ancientstation/deltacorridor
name = "Delta Station Main Corridor"
/area/ruin/space/ancientstation/thetacorridor
name = "Theta Station Main Corridor"
icon_state = "green"
/area/ruin/space/ancientstation/proto
name = "Delta Station Prototype Lab"
name = "Theta Station Prototype Lab"
icon_state = "toxlab"
/area/ruin/space/ancientstation/rnd
name = "Delta Station Research and Development"
name = "Theta Station Research and Development"
icon_state = "toxlab"
/area/ruin/space/ancientstation/hivebot
@@ -117,10 +117,8 @@
if("Peace")
to_chat(user, "<B>Whatever alien sentience that the Wish Granter possesses is satisfied with your wish. There is a distant wailing as the last of the Faithless begin to die, then silence.</B>")
to_chat(user, "You feel as if you just narrowly avoided a terrible fate...")
for(var/mob/living/simple_animal/hostile/faithless/F in world)
F.health = -10
F.stat = 2
F.icon_state = "faithless_dead"
for(var/mob/living/simple_animal/hostile/faithless/F in GLOB.mob_living_list)
F.death()
///////////////Meatgrinder//////////////
@@ -173,23 +171,9 @@
to_chat(C, "<span class='notice'>Death is not your end!</span>")
spawn(rand(800,1200))
if(C.stat == DEAD)
GLOB.dead_mob_list -= C
GLOB.living_mob_list += C
C.stat = CONSCIOUS
C.timeofdeath = 0
C.setToxLoss(0)
C.setOxyLoss(0)
C.setCloneLoss(0)
C.SetParalysis(0)
C.SetStunned(0)
C.SetWeakened(0)
C.radiation = 0
C.heal_overall_damage(C.getBruteLoss(), C.getFireLoss())
C.reagents.clear_reagents()
C.revive()
to_chat(C, "<span class='notice'>You have regenerated.</span>")
C.visible_message("<span class='warning'>[usr] appears to wake from the dead, having healed all wounds.</span>")
C.update_canmove()
return 1
/obj/item/wildwest_communicator
@@ -234,7 +218,8 @@
to_chat(user, "<span class='warning'>The communicator buzzes, and you hear the voice again: 'Really? I think not. Get them!'</span>")
if(option_threat)
to_chat(user, "<span class='warning'>The communicator buzzes, and you hear the voice again: 'Oh really now?' You hear a clicking sound. 'Team, get back here. We have trouble'. Then the line goes dead.</span>")
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(L.name == "wildwest_syndipod")
var/obj/spacepod/syndi/P = new /obj/spacepod/syndi(get_turf(L))
P.name = "Syndi Recon Pod"
@@ -247,7 +232,7 @@
used = TRUE
/obj/item/wildwest_communicator/proc/stand_down()
for(var/mob/living/simple_animal/hostile/syndicate/ranged/wildwest/W in GLOB.living_mob_list)
for(var/mob/living/simple_animal/hostile/syndicate/ranged/wildwest/W in GLOB.alive_mob_list)
W.on_alert = FALSE
/mob/living/simple_animal/hostile/syndicate/ranged/wildwest
@@ -262,6 +247,6 @@
// putting this up here so we don't say anything after deathgasp
if(can_die() && !on_alert)
say("How could you betray the Syndicate?")
for(var/mob/living/simple_animal/hostile/syndicate/ranged/wildwest/W in GLOB.living_mob_list)
for(var/mob/living/simple_animal/hostile/syndicate/ranged/wildwest/W in GLOB.alive_mob_list)
W.on_alert = TRUE
return ..(gibbed)
+4 -2
View File
@@ -56,7 +56,8 @@ GLOBAL_LIST_INIT(potentialRandomZlevels, generateMapList(filename = "config/away
GLOB.space_manager.remove_dirt(zlev)
log_world(" Away mission loaded: [map]")
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(L.name != "awaystart")
continue
GLOB.awaydestinations.Add(L)
@@ -89,7 +90,8 @@ GLOBAL_LIST_INIT(potentialRandomZlevels, generateMapList(filename = "config/away
//map_transition_config.Add(AWAY_MISSION_LIST)
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(L.name != "awaystart")
continue
GLOB.awaydestinations.Add(L)
+1 -1
View File
@@ -28,8 +28,8 @@
return "buildmode_[key]"
/datum/buildmode_mode/proc/show_help(mob/user)
CRASH("No help defined, yell at a coder")
to_chat(user, "<span class='warning'>There is no help defined for this mode, this is a bug.</span>")
CRASH("No help defined, yell at a coder")
/datum/buildmode_mode/proc/change_settings(mob/user)
to_chat(user, "<span class='warning'>There is no configuration available for this mode</span>")
+1 -1
View File
@@ -12,7 +12,7 @@
var/matrix/mat = matrix()
mat.Translate(0, 16)
mat.Scale(1, sqrt((x_offset * x_offset) + (y_offset * y_offset)) / 32)
mat.Turn(90 - Atan2(x_offset, y_offset)) // So... You pass coords in order x,y to this version of atan2. It should be called acsc2.
mat.Turn(90 - ATAN2(x_offset, y_offset)) // So... You pass coords in order x,y to this version of atan2. It should be called acsc2.
mat.Translate(atom_a.pixel_x, atom_a.pixel_y)
transform = mat
+6 -6
View File
@@ -9,6 +9,7 @@
var/plasma = 0
var/cdiox = 0
var/nitrox = 0
var/agentbx = 0
/datum/buildmode_mode/atmos/show_help(mob/user)
@@ -29,6 +30,7 @@
plasma = input(user, "Plasma ratio", "Input", 0) as num|null
cdiox = input(user, "CO2 ratio", "Input", 0) as num|null
nitrox = input(user, "N2O ratio", "Input", 0) as num|null
agentbx = input(user, "Agent B ratio", "Input", 0) as num|null
/datum/buildmode_mode/atmos/proc/ppratio_to_moles(ppratio)
// ideal gas equation: Pressure * Volume = Moles * r * Temperature
@@ -52,11 +54,8 @@
S.air.nitrogen = ppratio_to_moles(nitrogen)
S.air.toxins = ppratio_to_moles(plasma)
S.air.carbon_dioxide = ppratio_to_moles(cdiox)
S.air.trace_gases.Cut()
if(nitrox)
var/datum/gas/TG = new /datum/gas/sleeping_agent
TG.moles = ppratio_to_moles(nitrox)
S.air.trace_gases += TG
S.air.sleeping_agent = ppratio_to_moles(nitrox)
S.air.agent_b = ppratio_to_moles(agentbx)
S.update_visuals()
S.air_update_turf()
else if(ctrl_click) // overwrite "default" unsimulated air
@@ -65,7 +64,8 @@
T.nitrogen = ppratio_to_moles(nitrogen)
T.toxins = ppratio_to_moles(plasma)
T.carbon_dioxide = ppratio_to_moles(cdiox)
// no interface for trace gases on unsim turfs
T.sleeping_agent = ppratio_to_moles(nitrox)
T.agent_b = ppratio_to_moles(agentbx)
T.air_update_turf()
// admin log
+1 -1
View File
@@ -22,6 +22,6 @@
if(stored)
DuplicateObject(stored, perfectcopy=1, sameloc=0,newloc=T)
else if(right_click)
if(ismovableatom(object)) // No copying turfs for now.
if(ismovable(object)) // No copying turfs for now.
to_chat(user, "<span class='notice'>[object] set as template.</span>")
stored = object
+18
View File
@@ -177,6 +177,12 @@ GLOBAL_LIST_EMPTY(asset_datums)
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/tgui
assets = list(
"tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js',
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css'
)
/datum/asset/simple/paper
assets = list(
"large_stamp-clown.png" = 'icons/paper_icons/large_stamp-clown.png',
@@ -344,3 +350,15 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/mob_hunt/send(client)
send_asset_list(client, assets, verify)
// Fontawesome
/datum/asset/simple/fontawesome
verify = FALSE
assets = list(
"fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
"fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
"fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
"fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
"font-awesome.css" = 'html/font-awesome/css/all.min.css',
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
)
+3 -8
View File
@@ -20,7 +20,6 @@
var/skip_antag = FALSE //TRUE when a player declines to be included for the selection process of game mode antagonists.
var/move_delay = 1
var/moving = null
var/adminobs = null
var/area = null
var/time_died_as_mouse = null //when the client last died as a mouse
@@ -60,10 +59,6 @@
var/karma = 0
var/karma_spent = 0
var/karma_tab = 0
/////////////////////////////////////////////
// /vg/: MEDIAAAAAAAA
// Set on login.
var/datum/media_manager/media = null
var/topic_debugging = 0 //if set to true, allows client to see nanoUI errors -- yes i realize this is messy but it'll make live testing infinitely easier
@@ -86,10 +81,10 @@
// If set to true, this client can interact with atoms such as buttons and doors on top of regular machinery interaction
var/advanced_admin_interaction = FALSE
// Has the client been varedited by an admin? [Inherits from datum now]
// var/var_edited = FALSE
var/client_keysend_amount = 0
var/next_keysend_reset = 0
var/next_keysend_trip_reset = 0
var/keysend_tripped = FALSE
// Last world.time that the player tried to request their resources.
var/last_ui_resource_send = 0
+41 -2
View File
@@ -432,7 +432,13 @@
//////////////
//DISCONNECT//
//////////////
/client/Del()
if(!gc_destroyed)
Destroy() //Clean up signals and timers.
return ..()
/client/Destroy()
if(holder)
holder.owner = null
GLOB.admins -= src
@@ -442,7 +448,8 @@
movingmob.client_mobs_in_contents -= mob
UNSETEMPTY(movingmob.client_mobs_in_contents)
Master.UpdateTickRate()
return ..()
..() //Even though we're going to be hard deleted there are still some things that want to know the destroy is happening
return QDEL_HINT_HARDDEL_NOW
/client/proc/donator_check()
@@ -556,7 +563,7 @@
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."
del(src)
qdel(src)
return // Dont insert or they can just go in again
var/DBQuery/query_insert = GLOB.dbcon.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')")
@@ -906,3 +913,35 @@
return TRUE
#undef SSD_WARNING_TIMER
/client/verb/resend_ui_resources()
set name = "Reload UI Resources"
set desc = "Reload your UI assets if they are not working"
set category = "Special Verbs"
if(last_ui_resource_send > world.time)
to_chat(usr, "<span class='warning'>You requested your UI resource files too quickly. Please try again in [(last_ui_resource_send - world.time)/10] seconds.</span>")
return
var/choice = alert(usr, "This will reload your NanoUI and TGUI resources. If you have any open UIs this may break them. Are you sure?", "Resource Reloading", "Yes", "No")
if(choice == "Yes")
// 600 deciseconds = 1 minute
last_ui_resource_send = world.time + 60 SECONDS
// Close their open UIs
SSnanoui.close_user_uis(usr)
SStgui.close_user_uis(usr)
// Resend the resources
var/datum/asset/nano_assets = get_asset_datum(/datum/asset/nanoui)
nano_assets.register()
var/datum/asset/tgui_assets = get_asset_datum(/datum/asset/simple/tgui)
tgui_assets.register()
// Clear the user's cache so they get resent.
// This is not fully clearing their BYOND cache, just their assets sent from the server this round
cache = list()
to_chat(usr, "<span class='notice'>UI resource files resent successfully. If you are still having issues, please try manually clearing your BYOND cache. <b>This can be achieved by opening your BYOND launcher, pressing the cog in the top right, selecting preferences, going to the Games tab, and pressing 'Clear Cache'.</b></span>")
@@ -9,39 +9,6 @@ GLOBAL_LIST_EMPTY(gear_datums)
category = cat
..()
/hook/startup/proc/populate_gear_list()
//create a list of gear datums to sort
for(var/geartype in subtypesof(/datum/gear))
var/datum/gear/G = geartype
var/use_name = initial(G.display_name)
var/use_category = initial(G.sort_category)
if(G == initial(G.subtype_path))
continue
if(!use_name)
error("Loadout - Missing display name: [G]")
continue
if(!initial(G.cost))
error("Loadout - Missing cost: [G]")
continue
if(!initial(G.path))
error("Loadout - Missing path definition: [G]")
continue
if(!GLOB.loadout_categories[use_category])
GLOB.loadout_categories[use_category] = new /datum/loadout_category(use_category)
var/datum/loadout_category/LC = GLOB.loadout_categories[use_category]
GLOB.gear_datums[use_name] = new geartype
LC.gear[use_name] = GLOB.gear_datums[use_name]
GLOB.loadout_categories = sortAssoc(GLOB.loadout_categories)
for(var/loadout_category in GLOB.loadout_categories)
var/datum/loadout_category/LC = GLOB.loadout_categories[loadout_category]
LC.gear = sortAssoc(LC.gear)
return 1
/datum/gear
var/display_name //Name/index. Must be unique.
var/description //Description of this gear. If left blank will default to the description of the pathed item.
@@ -163,41 +163,41 @@
display_name = "armband, blue-yellow"
path = /obj/item/clothing/accessory/armband/yb
/datum/gear/accessory/armband_sec
/datum/gear/accessory/armband_job
subtype_path = /datum/gear/accessory/armband_job
subtype_cost_overlap = FALSE
/datum/gear/accessory/armband_job/sec
display_name = " armband, security"
path = /obj/item/clothing/accessory/armband/sec
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Brig Physician", "Security Pod Pilot")
/datum/gear/accessory/armband_cargo
/datum/gear/accessory/armband_job/cargo
display_name = "cargo armband"
path = /obj/item/clothing/accessory/armband/cargo
allowed_roles = list("Quartermaster","Cargo Technician", "Shaft Miner")
/datum/gear/accessory/armband_medical
/datum/gear/accessory/armband_job/medical
display_name = "armband, medical"
path = /obj/item/clothing/accessory/armband/med
allowed_roles = list("Chief Medical Officer", "Medical Doctor", "Coroner", "Paramedic", "Brig Physician")
/datum/gear/accessory/armband_emt
/datum/gear/accessory/armband_job/emt
display_name = "armband, EMT"
path = /obj/item/clothing/accessory/armband/medgreen
allowed_roles = list("Paramedic", "Brig Physician")
/datum/gear/accessory/armband_engineering
/datum/gear/accessory/armband_job/engineering
display_name = "armband, engineering"
path = /obj/item/clothing/accessory/armband/engine
allowed_roles = list("Chief Engineer","Station Engineer", "Life Support Specialist")
/datum/gear/accessory/armband_hydro
/datum/gear/accessory/armband_job/hydro
display_name = "armband, hydroponics"
path = /obj/item/clothing/accessory/armband/hydro
allowed_roles = list("Botanist")
/datum/gear/accessory/armband_sci
/datum/gear/accessory/armband_job/sci
display_name = "armband, science"
path = /obj/item/clothing/accessory/armband/science
allowed_roles = list("Research Director","Scientist", "Roboticist")
@@ -42,11 +42,6 @@
display_name = "fedora, brown"
path = /obj/item/clothing/head/fedora/brownfedora
/datum/gear/hat/beretsec
display_name = "security beret"
path = /obj/item/clothing/head/beret/sec
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot")
/datum/gear/hat/capcsec
display_name = "security corporate cap"
path = /obj/item/clothing/head/soft/sec/corp
@@ -113,32 +108,51 @@
display_name = "cowboy hat, pink"
path = /obj/item/clothing/head/cowboyhat/pink
/datum/gear/hat/pr_beret
/datum/gear/hat/beret_purple
display_name = "beret, purple"
path = /obj/item/clothing/head/beret/purple_normal
/datum/gear/hat/bl_beret
/datum/gear/hat/beret_black
display_name = "beret, black"
path = /obj/item/clothing/head/beret/black
/datum/gear/hat/blu_beret
/datum/gear/hat/beret_blue
display_name = "beret, blue"
path = /obj/item/clothing/head/beret/blue
/datum/gear/hat/red_beret
/datum/gear/hat/beret_red
display_name = "beret, red"
path = /obj/item/clothing/head/beret
/datum/gear/hat/sci_beret
/datum/gear/hat/beret_job
subtype_path = /datum/gear/hat/beret_job
subtype_cost_overlap = FALSE
/datum/gear/hat/beret_job/sec
display_name = "security beret"
path = /obj/item/clothing/head/beret/sec
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot")
/datum/gear/hat/beret_job/sci
display_name = "science beret"
path = /obj/item/clothing/head/beret/sci
allowed_roles = list("Research Director", "Scientist")
/datum/gear/hat/med_beret
/datum/gear/hat/beret_job/med
display_name = "medical beret"
path = /obj/item/clothing/head/beret/med
allowed_roles = list("Chief Medical Officer", "Medical Doctor" , "Virologist", "Brig Physician" , "Coroner")
/datum/gear/hat/beret_job/eng
display_name = "engineering beret"
path = /obj/item/clothing/head/beret/eng
allowed_roles = list("Chief Engineer", "Station Engineer")
/datum/gear/hat/beret_job/atmos
display_name = "atmospherics beret"
path = /obj/item/clothing/head/beret/atmos
allowed_roles = list("Chief Engineer", "Life Support Specialist")
/datum/gear/hat/surgicalcap_purple
display_name = "surgical cap, purple"
path = /obj/item/clothing/head/surgery/purple
@@ -175,32 +175,36 @@
display_name = "regal shawl"
path = /obj/item/clothing/suit/mantle/regal
/datum/gear/suit/captain_cloak
/datum/gear/suit/mantle/job
subtype_path = /datum/gear/suit/mantle/job
subtype_cost_overlap = FALSE
/datum/gear/suit/mantle/job/captain
display_name = "mantle, captain"
path = /obj/item/clothing/suit/mantle/armor/captain
allowed_roles = list("Captain")
/datum/gear/suit/ce_mantle
/datum/gear/suit/mantle/job/ce
display_name = "mantle, chief engineer"
path = /obj/item/clothing/suit/mantle/chief_engineer
allowed_roles = list("Chief Engineer")
/datum/gear/suit/cmo_mantle
/datum/gear/suit/mantle/job/cmo
display_name = "mantle, chief medical officer"
path = /obj/item/clothing/suit/mantle/labcoat/chief_medical_officer
allowed_roles = list("Chief Medical Officer")
/datum/gear/suit/armored_shawl
/datum/gear/suit/mantle/job/hos
display_name = "mantle, head of security"
path = /obj/item/clothing/suit/mantle/armor
allowed_roles = list("Head of Security")
/datum/gear/suit/hop_shawl
/datum/gear/suit/mantle/job/hop
display_name = "mantle, head of personnel"
path = /obj/item/clothing/suit/mantle/armor/head_of_personnel
allowed_roles = list("Head of Personnel")
/datum/gear/suit/rd_mantle
/datum/gear/suit/mantle/job/rd
display_name = "mantle, research director"
path = /obj/item/clothing/suit/mantle/labcoat
allowed_roles = list("Research Director")
+17 -2
View File
@@ -54,7 +54,6 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
return C.player_age
else
return max(0, days - C.player_age)
return 0
#define MAX_SAVE_SLOTS 30 // Save slots for regular players
#define MAX_SAVE_SLOTS_MEMBER 30 // Save slots for BYOND members
@@ -189,6 +188,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
// OOC Metadata:
var/metadata = ""
var/slot_name = ""
var/saved = FALSE // Indicates whether the character comes from the database or not
// Whether or not to use randomized character slots
var/randomslot = 0
@@ -264,10 +264,12 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
dat += "<a href='?_src_=prefs;preference=name'><span class='[be_random_name ? "good" : "bad"]'>(Always Randomize)</span></a><br>"
dat += "</td><td width='405px' height='25px' valign='left'>"
dat += "<center>"
dat += "Slot <b>[slot_name]</b> - "
dat += "Slot <b>[default_slot][saved ? "" : " (empty)"]</b><br>"
dat += "<a href=\"byond://?_src_=prefs;preference=open_load_dialog\">Load slot</a> - "
dat += "<a href=\"byond://?_src_=prefs;preference=save\">Save slot</a> - "
dat += "<a href=\"byond://?_src_=prefs;preference=reload\">Reload slot</a>"
if(saved)
dat += " - <a href=\"byond://?_src_=prefs;preference=clear\"><span class='bad'>Clear slot</span></a>"
dat += "</center>"
dat += "</td></tr></table>"
dat += "<table width='100%'><tr><td width='405px' height='200px' valign='top'>"
@@ -624,6 +626,9 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
if(job.admin_only)
continue
if(job.hidden_from_job_prefs)
continue
index += 1
if((index >= limit) || (job.title in splitJobs))
if((index < limit) && (lastJob != null))
@@ -2001,6 +2006,11 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
windowflashing = !windowflashing
if("afk_watch")
if(!afk_watch)
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>")
else
to_chat(user, "<span class='info'>Automatic cryoing turned off.</span>")
afk_watch = !afk_watch
if("UIcolor")
@@ -2071,6 +2081,11 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
load_preferences(user)
load_character(user)
if("clear")
if(!saved || real_name != input("This will clear the current slot permanently. Please enter the character's full name to confirm."))
return FALSE
clear_character_slot(user)
if("open_load_dialog")
if(!IsGuestKey(user.key))
open_load_dialog(user)
@@ -96,7 +96,7 @@
UI_style_alpha='[UI_style_alpha]',
be_role='[sanitizeSQL(list2params(be_special))]',
default_slot='[default_slot]',
toggles='[num2text(toggles, Ceiling(log(10, (TOGGLES_TOTAL))))]',
toggles='[num2text(toggles, CEILING(log(10, (TOGGLES_TOTAL)), 1))]',
atklog='[atklog]',
sound='[sound]',
randomslot='[randomslot]',
@@ -121,6 +121,7 @@
return 1
/datum/preferences/proc/load_character(client/C,slot)
saved = FALSE
if(!slot) slot = default_slot
slot = sanitize_integer(slot, 1, max_save_slots, initial(default_slot))
@@ -262,6 +263,8 @@
loadout_gear = params2list(query.item[51])
autohiss_mode = text2num(query.item[52])
saved = TRUE
//Sanitize
var/datum/species/SP = GLOB.all_species[species]
metadata = sanitize_text(metadata, initial(metadata))
@@ -320,6 +323,10 @@
if(!rlimb_data) src.rlimb_data = list()
if(!loadout_gear) loadout_gear = list()
// Check if the current body accessory exists
if(!GLOB.body_accessory_by_name[body_accessory])
body_accessory = null
return 1
/datum/preferences/proc/save_character(client/C)
@@ -470,6 +477,8 @@
log_game("SQL ERROR during character slot saving. Error : \[[err]\]\n")
message_admins("SQL ERROR during character slot saving. Error : \[[err]\]\n")
return
saved = TRUE
return 1
/datum/preferences/proc/load_random_character_slot(client/C)
@@ -491,3 +500,20 @@
load_character(C,pick(saves))
return 1
/datum/preferences/proc/clear_character_slot(client/C)
. = FALSE
// Is there a character in that slot?
var/DBQuery/query = GLOB.dbcon.NewQuery("SELECT slot FROM [format_table_name("characters")] WHERE ckey='[C.ckey]' AND slot='[default_slot]'")
query.Execute()
if(!query.RowCount())
return
var/DBQuery/query2 = GLOB.dbcon.NewQuery("DELETE FROM [format_table_name("characters")] WHERE ckey='[C.ckey]' AND slot='[default_slot]'")
if(!query2.Execute())
var/err = query2.ErrorMsg()
log_game("SQL ERROR during character slot clearing. Error : \[[err]\]\n")
message_admins("SQL ERROR during character slot clearing. Error : \[[err]\]\n")
return
saved = FALSE
return TRUE
+94 -41
View File
@@ -9,6 +9,10 @@
..()
initialize_outfits()
/datum/action/chameleon_outfit/Destroy()
STOP_PROCESSING(SSprocessing, src)
return ..()
/datum/action/chameleon_outfit/proc/initialize_outfits()
var/static/list/standard_outfit_options
if(!standard_outfit_options)
@@ -140,29 +144,29 @@
UpdateButtonIcon()
/datum/action/item_action/chameleon/change/proc/update_item(obj/item/picked_item)
// Species-related variables are lists, which can not be retrieved using initial(). As such, we need to instantiate the picked item.
var/obj/item/P = new picked_item(null)
target.name = P.name
target.desc = P.desc
target.icon_state = P.icon_state
target.name = initial(picked_item.name)
target.desc = initial(picked_item.desc)
target.icon_state = initial(picked_item.icon_state)
if(isitem(target))
var/obj/item/I = target
I.item_state = P.item_state
I.item_color = P.item_color
I.item_state = initial(picked_item.item_state)
I.item_color = initial(picked_item.item_color)
I.icon_override = P.icon_override
I.sprite_sheets = P.sprite_sheets
I.icon_override = initial(picked_item.icon_override)
if(initial(picked_item.sprite_sheets))
// Species-related variables are lists, which can not be retrieved using initial(). As such, we need to instantiate the picked item.
var/obj/item/P = new picked_item(null)
I.sprite_sheets = P.sprite_sheets
qdel(P)
if(istype(I, /obj/item/clothing) && istype(P, /obj/item/clothing))
if(istype(I, /obj/item/clothing) && istype(initial(picked_item), /obj/item/clothing))
var/obj/item/clothing/CL = I
var/obj/item/clothing/PCL = P
CL.flags_cover = PCL.flags_cover
var/obj/item/clothing/PCL = picked_item
CL.flags_cover = initial(PCL.flags_cover)
target.icon = P.icon
qdel(P)
target.icon = initial(picked_item.icon)
/datum/action/item_action/chameleon/change/Trigger()
if(!IsAvailable())
@@ -198,7 +202,7 @@
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/under/chameleon/Initialize()
/obj/item/clothing/under/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/under
@@ -206,11 +210,15 @@
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/clothing/under, /obj/item/clothing/under/color, /obj/item/clothing/under/rank), only_root_path = TRUE)
chameleon_action.initialize_disguises()
/obj/item/clothing/under/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/under/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/under/chameleon/broken/Initialize()
/obj/item/clothing/under/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -229,7 +237,7 @@
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/suit/chameleon/Initialize()
/obj/item/clothing/suit/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/suit
@@ -237,11 +245,15 @@
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/clothing/suit/armor/abductor), only_root_path = TRUE)
chameleon_action.initialize_disguises()
/obj/item/clothing/suit/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/suit/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/suit/chameleon/broken/Initialize()
/obj/item/clothing/suit/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -261,7 +273,7 @@
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/glasses/chameleon/Initialize()
/obj/item/clothing/glasses/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/glasses
@@ -269,11 +281,15 @@
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
/obj/item/clothing/glasses/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/glasses/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/glasses/chameleon/broken/Initialize()
/obj/item/clothing/glasses/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -289,7 +305,7 @@
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/glasses/hud/security/chameleon/Initialize()
/obj/item/clothing/glasses/hud/security/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/glasses
@@ -297,11 +313,15 @@
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
/obj/item/clothing/glasses/hud/security/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/glasses/hud/security/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/glasses/hud/security/chameleon/broken/Initialize()
/obj/item/clothing/glasses/hud/security/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -316,7 +336,7 @@
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/gloves/chameleon/Initialize()
/obj/item/clothing/gloves/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/gloves
@@ -324,11 +344,15 @@
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/clothing/gloves, /obj/item/clothing/gloves/color), only_root_path = TRUE)
chameleon_action.initialize_disguises()
/obj/item/clothing/gloves/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/gloves/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/gloves/chameleon/broken/Initialize()
/obj/item/clothing/gloves/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -347,7 +371,7 @@
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/head/chameleon/Initialize()
/obj/item/clothing/head/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/head
@@ -355,11 +379,15 @@
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
/obj/item/clothing/head/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/head/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/head/chameleon/broken/Initialize()
/obj/item/clothing/head/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -389,7 +417,7 @@
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/mask/chameleon/Initialize()
/obj/item/clothing/mask/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
@@ -402,13 +430,14 @@
/obj/item/clothing/mask/chameleon/Destroy()
QDEL_NULL(voice_changer)
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/mask/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/mask/chameleon/broken/Initialize()
/obj/item/clothing/mask/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -423,7 +452,7 @@
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/shoes/chameleon/Initialize()
/obj/item/clothing/shoes/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/shoes
@@ -431,6 +460,10 @@
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
/obj/item/clothing/shoes/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/shoes/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
@@ -442,7 +475,7 @@
desc = "A pair of black shoes."
flags = NOSLIP
/obj/item/clothing/shoes/chameleon/noslip/broken/Initialize()
/obj/item/clothing/shoes/chameleon/noslip/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -455,18 +488,22 @@
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/storage/backpack/chameleon/Initialize()
/obj/item/storage/backpack/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/storage/backpack
chameleon_action.chameleon_name = "Backpack"
chameleon_action.initialize_disguises()
/obj/item/storage/backpack/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/storage/backpack/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/storage/backpack/chameleon/broken/Initialize()
/obj/item/storage/backpack/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -475,7 +512,7 @@
desc = "Holds tools."
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/storage/belt/chameleon/Initialize()
/obj/item/storage/belt/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
@@ -483,11 +520,15 @@
chameleon_action.chameleon_name = "Belt"
chameleon_action.initialize_disguises()
/obj/item/storage/belt/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/storage/belt/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/storage/belt/chameleon/broken/Initialize()
/obj/item/storage/belt/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -495,18 +536,22 @@
name = "radio headset"
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/radio/headset/chameleon/Initialize()
/obj/item/radio/headset/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/radio/headset
chameleon_action.chameleon_name = "Headset"
chameleon_action.initialize_disguises()
/obj/item/radio/headset/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/radio/headset/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/radio/headset/chameleon/broken/Initialize()
/obj/item/radio/headset/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
@@ -514,7 +559,7 @@
name = "PDA"
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/pda/chameleon/Initialize()
/obj/item/pda/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/pda
@@ -522,24 +567,32 @@
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/pda/heads), only_root_path = TRUE)
chameleon_action.initialize_disguises()
/obj/item/pda/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/pda/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/pda/chameleon/broken/Initialize()
/obj/item/pda/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/stamp/chameleon
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/stamp/chameleon/Initialize()
/obj/item/stamp/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/stamp
chameleon_action.chameleon_name = "Stamp"
chameleon_action.initialize_disguises()
/obj/item/stamp/chameleon/broken/Initialize()
/obj/item/stamp/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/stamp/chameleon/broken/Initialize(mapload)
. = ..()
chameleon_action.emp_randomise(INFINITY)
+1 -2
View File
@@ -376,7 +376,6 @@
desc = "Covers the eyes, preventing sight."
icon_state = "blindfold"
item_state = "blindfold"
//vision_flags = BLIND
flash_protect = 2
tint = 3 //to make them blind
prescription_upgradable = 0
@@ -412,7 +411,7 @@
if(M.glasses == src)
M.EyeBlind(3)
M.EyeBlurry(5)
if(!(M.disabilities & NEARSIGHTED))
if(!(NEARSIGHTED in M.mutations))
M.BecomeNearsighted()
spawn(100)
M.CureNearsighted()
+1 -1
View File
@@ -113,7 +113,7 @@
/obj/item/clothing/head/soft/sec/corp
name = "corporate security cap"
desc = "It's baseball hat in corpotate colours."
desc = "It's a baseball hat in corporate colours."
icon_state = "corpsoft"
item_color = "corp"
+20 -16
View File
@@ -86,21 +86,25 @@
name = "orange shoes"
icon_state = "orange"
item_color = "orange"
var/obj/item/restraints/handcuffs/shackles
/obj/item/clothing/shoes/orange/attack_self(mob/user as mob)
if(src.chained)
src.chained = null
src.slowdown = SHOES_SLOWDOWN
new /obj/item/restraints/handcuffs( user.loc )
src.icon_state = "orange"
return
/obj/item/clothing/shoes/orange/Destroy()
QDEL_NULL(shackles)
return ..()
/obj/item/clothing/shoes/orange/attackby(obj/H, loc, params)
..()
if(istype(H, /obj/item/restraints/handcuffs) && !chained && !(H.flags & NODROP))
if(src.icon_state != "orange") return
qdel(H)
src.chained = 1
src.slowdown = 15
src.icon_state = "orange1"
return
/obj/item/clothing/shoes/orange/attack_self(mob/user)
if(shackles)
user.put_in_hands(shackles)
shackles = null
slowdown = SHOES_SLOWDOWN
icon_state = "orange"
/obj/item/clothing/shoes/orange/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/restraints/handcuffs) && !shackles)
if(user.drop_item())
I.forceMove(src)
shackles = I
slowdown = 15
icon_state = "orange1"
return
return ..()
+2 -3
View File
@@ -73,16 +73,15 @@ obj/item/clothing/shoes/magboots/syndie/advance //For the Syndicate Strike Team
shoe_sound = "clownstep"
origin_tech = "magnets=4;syndicate=2"
var/enabled_waddle = TRUE
var/datum/component/waddle
/obj/item/clothing/shoes/magboots/clown/equipped(mob/user, slot)
. = ..()
if(slot == slot_shoes && enabled_waddle)
waddle = user.AddComponent(/datum/component/waddling)
user.AddElement(/datum/element/waddling)
/obj/item/clothing/shoes/magboots/clown/dropped(mob/user)
. = ..()
QDEL_NULL(waddle)
user.RemoveElement(/datum/element/waddling)
/obj/item/clothing/shoes/magboots/clown/CtrlClick(mob/living/user)
if(!isliving(user))
+2 -3
View File
@@ -71,16 +71,15 @@
var/footstep = 1 //used for squeeks whilst walking
shoe_sound = "clownstep"
var/enabled_waddle = TRUE
var/datum/component/waddle
/obj/item/clothing/shoes/clown_shoes/equipped(mob/user, slot)
. = ..()
if(slot == slot_shoes && enabled_waddle)
waddle = user.AddComponent(/datum/component/waddling)
user.AddElement(/datum/element/waddling)
/obj/item/clothing/shoes/clown_shoes/dropped(mob/user)
. = ..()
QDEL_NULL(waddle)
user.RemoveElement(/datum/element/waddling)
/obj/item/clothing/shoes/clown_shoes/CtrlClick(mob/living/user)
if(!isliving(user))
+1 -1
View File
@@ -531,7 +531,7 @@
/obj/item/clothing/suit/space/hardsuit/shielded/process()
if(world.time > recharge_cooldown && current_charges < max_charges)
current_charges = Clamp((current_charges + recharge_rate), 0, max_charges)
current_charges = clamp((current_charges + recharge_rate), 0, max_charges)
playsound(loc, 'sound/magic/charge.ogg', 50, TRUE)
if(current_charges == max_charges)
playsound(loc, 'sound/machines/ding.ogg', 50, TRUE)
+6 -7
View File
@@ -155,9 +155,8 @@
if(piece.siemens_coefficient > siemens_coefficient) //So that insulated gloves keep their insulation.
piece.siemens_coefficient = siemens_coefficient
piece.permeability_coefficient = permeability_coefficient
if(islist(armor))
var/list/L = armor
piece.armor = L.Copy()
if(armor)
piece.armor = armor
update_icon(1)
@@ -286,7 +285,7 @@
if(helmet)
helmet.update_light(wearer)
correct_piece.armor["bio"] = 100
correct_piece.armor = correct_piece.armor.setRating(bio_value = 100)
sealing = FALSE
@@ -389,7 +388,7 @@
if(helmet)
helmet.update_light(wearer)
correct_piece.armor["bio"] = armor["bio"]
correct_piece.armor = correct_piece.armor.setRating(bio_value = armor.getRating("bio"))
sealing = FALSE
@@ -553,7 +552,7 @@
data["charge"] = cell ? round(cell.charge,1) : 0
data["maxcharge"] = cell ? cell.maxcharge : 0
data["chargestatus"] = cell ? Floor((cell.charge/cell.maxcharge)*50) : 0
data["chargestatus"] = cell ? FLOOR((cell.charge/cell.maxcharge)*50, 1) : 0
data["emagged"] = subverted
data["coverlock"] = locked
@@ -798,7 +797,7 @@
to_chat(wearer, "<span class='danger'>You are unable to deploy \the [piece] as \the [check_slot] [check_slot.gender == PLURAL ? "are" : "is"] in the way.</span>")
return
use_obj.forceMove(wearer)
if(!wearer.equip_to_slot_if_possible(use_obj, equip_to, 0, 1))
if(!wearer.equip_to_slot_if_possible(use_obj, equip_to, FALSE, TRUE))
use_obj.forceMove(src)
else
if(wearer)
@@ -9,13 +9,22 @@
multi *= (100 - chest.damage) / 100 //If we have some breaches, lower the armor value.
//TODO check for other armor mods, likely modules, which need to be coded.
if(!armor) //Did we even give them some armor, if this is the case, the list should be initialized from New()
return
var/datum/armor/A = armor
for(var/obj/item/piece in list(gloves, helmet, boots, chest))
if(!istype(piece)) //Do we have the piece
continue
if(islist(armor)) //Did we even give them some armor, if this is the case, the list should be initialized from New()
var/list/L = armor
for(var/armortype in L)
piece.armor[armortype] = L[armortype]*multi
piece.armor = piece.armor.setRating(melee_value = A.getRating("melee") * multi,
bullet_value = A.getRating("bullet") * multi,
laser_value = A.getRating("laser") * multi,
energy_value = A.getRating("energy") * multi,
bomb_value = A.getRating("bomb") * multi,
bio_value = A.getRating("bio") * multi,
rad_value = A.getRating("rad") * multi,
fire_value = A.getRating("fire") * multi,
acid_value = A.getRating("acidd") * multi)
//Perfect place to also add something like shield modules, or any other hit_reaction modules check.
+1 -1
View File
@@ -59,7 +59,7 @@
if(H.head)
to_chat(H,"<span class='warning'>You're already wearing something on your head!</span>")
return
else if(H.equip_to_slot_if_possible(hood, slot_head, 0, 0, 1))
else if(H.equip_to_slot_if_possible(hood, slot_head, FALSE, FALSE))
suit_adjusted = 1
icon_state = "[initial(icon_state)]_hood"
H.update_inv_wear_suit()
+1 -1
View File
@@ -68,7 +68,7 @@
if(H.head)
to_chat(H, "<span class='warning'>You're already wearing something on your head!</span>")
return
else if(H.equip_to_slot_if_possible(helmet, slot_head, 0 ,0, 1))
else if(H.equip_to_slot_if_possible(helmet, slot_head, FALSE, FALSE))
to_chat(H, "<span class='notice'>You engage the helmet on the hardsuit.</span>")
suittoggled = TRUE
H.update_inv_wear_suit()
@@ -37,8 +37,13 @@
var/mob/M = has_suit.loc
A.Grant(M)
for(var/armor_type in armor)
has_suit.armor[armor_type] += armor[armor_type]
if (islist(has_suit.armor) || isnull(has_suit.armor)) // This proc can run before /obj/Initialize has run for U and src,
has_suit.armor = getArmor(arglist(has_suit.armor)) // we have to check that the armor list has been transformed into a datum before we try to call a proc on it
// This is safe to do as /obj/Initialize only handles setting up the datum if actually needed.
if (islist(armor) || isnull(armor))
armor = getArmor(arglist(armor))
has_suit.armor = has_suit.armor.attachArmor(armor)
if(user)
to_chat(user, "<span class='notice'>You attach [src] to [has_suit].</span>")
@@ -56,8 +61,7 @@
var/mob/M = has_suit.loc
A.Remove(M)
for(var/armor_type in armor)
has_suit.armor[armor_type] -= armor[armor_type]
has_suit.armor = has_suit.armor.detachArmor(armor)
has_suit = null
if(user)
@@ -314,6 +318,36 @@
if(isliving(user))
user.visible_message("<span class='warning'>[user] invades [M]'s personal space, thrusting [src] into [M.p_their()] face insistently.</span>","<span class='warning'>You invade [M]'s personal space, thrusting [src] into [M.p_their()] face insistently. You are the law.</span>")
//////////////
//OBJECTION!//
//////////////
/obj/item/clothing/accessory/lawyers_badge
name = "attorney's badge"
desc = "Fills you with the conviction of JUSTICE. Lawyers tend to want to show it to everyone they meet."
icon_state = "lawyerbadge"
item_state = "lawyerbadge"
item_color = "lawyerbadge"
var/cached_bubble_icon = null
/obj/item/clothing/accessory/lawyers_badge/attack_self(mob/user)
if(prob(1))
user.say("The testimony contradicts the evidence!")
user.visible_message("<span class='notice'>[user] shows [user.p_their()] attorney's badge.</span>", "<span class='notice'>You show your attorney's badge.</span>")
/obj/item/clothing/accessory/lawyers_badge/on_attached(obj/item/clothing/under/S, mob/user)
..()
if(has_suit && ismob(has_suit.loc))
var/mob/M = has_suit.loc
cached_bubble_icon = M.bubble_icon
M.bubble_icon = "lawyer"
/obj/item/clothing/accessory/lawyers_badge/on_removed(mob/user)
if(has_suit && ismob(has_suit.loc))
var/mob/M = has_suit.loc
M.bubble_icon = cached_bubble_icon
..()
///////////
//SCARVES//
///////////
+1 -1
View File
@@ -128,7 +128,7 @@
continue main_loop
return FALSE
for(var/obj/item/T in tools_used)
if(!T.tool_start_check(user, 0)) //Check if all our tools are valid for their use
if(!T.tool_start_check(null, user, 0)) //Check if all our tools are valid for their use
return FALSE
return TRUE
+2 -2
View File
@@ -48,7 +48,7 @@
var/mob/living/carbon/human/target = M
if(ismachine(target))
if(ismachineperson(target))
to_chat(user, "<span class= 'notice'>[target] has no skin, how do you expect to tattoo [target.p_them()]?</span>")
return
@@ -349,7 +349,7 @@
to_chat(user, "<span class='notice'>You modify the appearance of [target].</span>")
var/obj/item/clothing/mask/gas/M = target
M.name = "Prescription Gas Mask"
M.desc = "It looks heavily modified, but otherwise functions as a gas mask. The words Property of Yon-Dale can be seen on the inner band."
M.desc = "It looks heavily modified, but otherwise functions as a gas mask. The words \"Property of Yon-Dale\" can be seen on the inner band."
M.icon = 'icons/obj/custom_items.dmi'
M.icon_state = "gas_tariq"
M.sprite_sheets = list(
@@ -18,7 +18,6 @@
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(5)
volume = 5
can_be_placed_into = null
flags = NOBLUDGEON
container_type = OPENCONTAINER
has_lid = FALSE
+1 -1
View File
@@ -159,7 +159,7 @@ GLOBAL_VAR(current_date_string)
var/account_name = href_list["holder_name"]
var/starting_funds = max(text2num(href_list["starting_funds"]), 0)
starting_funds = Clamp(starting_funds, 0, GLOB.station_account.money) // Not authorized to put the station in debt.
starting_funds = clamp(starting_funds, 0, GLOB.station_account.money) // Not authorized to put the station in debt.
starting_funds = min(starting_funds, fund_cap) // Not authorized to give more than the fund cap.
var/datum/money_account/M = create_account(account_name, starting_funds, src)
+1 -1
View File
@@ -5,7 +5,7 @@
////////////////////////
/proc/get_money_account(var/account_number, var/from_z=-1)
for(var/obj/machinery/computer/account_database/DB in world)
for(var/obj/machinery/computer/account_database/DB in GLOB.machines)
if(from_z > -1 && DB.z != from_z) continue
if((DB.stat & NOPOWER) || !DB.activated ) continue
var/datum/money_account/acct = DB.get_account(account_number)
+1 -1
View File
@@ -17,7 +17,7 @@
playercount = length(GLOB.clients)//grab playercount when event starts not when game starts
if(playercount >= highpop_trigger) //spawn with 4 if highpop
spawncount = 4
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world)
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in SSair.atmos_machinery)
if(is_station_level(temp_vent.loc.z) && !temp_vent.welded)
if(temp_vent.parent.other_atmosmch.len > 50) //Stops Aliens getting stuck in small networks. See: Security, Virology
vents += temp_vent
+1 -1
View File
@@ -18,7 +18,7 @@
// Calculate new position (searches through beacons in world)
var/obj/item/radio/beacon/chosen
var/list/possible = list()
for(var/obj/item/radio/beacon/W in world)
for(var/obj/item/radio/beacon/W in GLOB.global_radios)
if(!is_station_level(W.z))
continue
possible += W
+1 -1
View File
@@ -15,7 +15,7 @@
if(!newAnomaly)
kill()
return
if(IsMultiple(activeFor, 5))
if(ISMULTIPLE(activeFor, 5))
newAnomaly.anomalyEffect()
/datum/event/anomaly/anomaly_pyro/end()
+64
View File
@@ -0,0 +1,64 @@
#define APC_BREAK_PROBABILITY 25 // the probability that a given APC will be broken
/datum/event/apc_overload
var/const/announce_after_mc_ticks = 5
var/const/delayed = FALSE
var/const/event_max_duration_mc_ticks = announce_after_mc_ticks * 2
var/const/event_min_duration_mc_ticks = announce_after_mc_ticks
announceWhen = announce_after_mc_ticks
/datum/event/apc_overload/setup()
endWhen = rand(event_min_duration_mc_ticks, event_max_duration_mc_ticks)
/datum/event/apc_overload/start()
apc_overload_failure(announce=delayed)
var/sound/S = sound('sound/effects/powerloss.ogg')
for(var/mob/living/M in GLOB.player_list)
var/turf/T = get_turf(M)
if(!M.client || !is_station_level(T.z))
continue
SEND_SOUND(M, S)
/datum/event/apc_overload/announce()
GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please check all underfloor APC terminals.", "Critical Power Failure", new_sound = 'sound/AI/apc_overload.ogg')
/datum/event/apc_overload/end()
return TRUE
/proc/apc_overload_failure(announce=TRUE)
var/list/skipped_areas_apc = list(
/area/engine/engineering,
/area/turret_protected/ai)
if(announce)
GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please check all underfloor APC terminals.", "Critical Power Failure", new_sound = 'sound/AI/apc_overload.ogg')
// break APC_BREAK_PROBABILITY% of all of the APCs on the station
var/affected_apc_count = 0
for(var/thing in GLOB.apcs)
var/obj/machinery/power/apc/C = thing
// skip any APCs that are too critical to break
var/area/current_area = get_area(C)
if((current_area.type in skipped_areas_apc) || !is_station_level(C.z))
continue
// if we are going to break this one
if(prob(APC_BREAK_PROBABILITY))
// if it has a cell, drain all the charge from the cell
if(C.cell)
C.cell.charge = 0
// if it has a terminal, disconnect and delete the terminal
if(C.terminal)
var/obj/machinery/power/terminal/T = C.terminal
C.terminal.master = null
C.terminal = null
qdel(T)
// if it was operating, toggle off the breaker
if(C.operating)
C.toggle_breaker()
// no matter what, ensure the area knows something happened to the power
current_area.power_change()
affected_apc_count++
log_and_message_admins("APC Overload event deleted [affected_apc_count] underfloor APC terminals.")
#undef APC_BREAK_PROBABILITY
+89
View File
@@ -0,0 +1,89 @@
#define APC_BREAK_PROBABILITY 25 // the probability that a given APC will be disabled
/datum/event/apc_short
var/const/announce_after_mc_ticks = 5
var/const/delayed = FALSE
var/const/event_max_duration_mc_ticks = announce_after_mc_ticks * 2
var/const/event_min_duration_mc_ticks = announce_after_mc_ticks
announceWhen = announce_after_mc_ticks
/datum/event/apc_short/setup()
endWhen = rand(event_min_duration_mc_ticks, event_max_duration_mc_ticks)
/datum/event/apc_short/start()
power_failure(announce=delayed)
var/sound/S = sound('sound/effects/powerloss.ogg')
for(var/mob/living/M in GLOB.player_list)
var/turf/T = get_turf(M)
if(!M.client || !is_station_level(T.z))
continue
SEND_SOUND(M, S)
/datum/event/apc_short/announce()
GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please repair shorted APCs.", "Systems Power Failure", new_sound = 'sound/AI/apc_short.ogg')
/datum/event/apc_short/end()
return TRUE
/proc/power_failure(announce=TRUE)
var/list/skipped_areas_apc = list(
/area/engine/engineering,
/area/turret_protected/ai)
if(announce)
GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please repair shorted APCs.", "Systems Power Failure", new_sound = 'sound/AI/apc_short.ogg')
// break APC_BREAK_PROBABILITY% of all of the APCs on the station
var/affected_apc_count = 0
for(var/thing in GLOB.apcs)
var/obj/machinery/power/apc/C = thing
// skip any APCs that are too critical to disable
var/area/current_area = get_area(C)
if((current_area.type in skipped_areas_apc) || !is_station_level(C.z))
continue
// if we are going to break this one
if(prob(APC_BREAK_PROBABILITY))
// if it has internal wires, cut the power wires
if(C.wires)
if(!C.wires.IsIndexCut(APC_WIRE_MAIN_POWER1))
C.wires.CutWireIndex(APC_WIRE_MAIN_POWER1)
if(!C.wires.IsIndexCut(APC_WIRE_MAIN_POWER2))
C.wires.CutWireIndex(APC_WIRE_MAIN_POWER2)
// if it was operating, toggle off the breaker
if(C.operating)
C.toggle_breaker()
// no matter what, ensure the area knows something happened to the power
current_area.power_change()
affected_apc_count++
log_and_message_admins("APC Short event shorted out [affected_apc_count] APCs.")
/proc/power_restore(announce=TRUE)
if(announce)
GLOB.event_announcement.Announce("Power has been restored to [station_name()]. We apologize for the inconvenience.", "Power Systems Nominal", new_sound = 'sound/AI/poweron.ogg')
// recharge the APCs
for(var/thing in GLOB.apcs)
var/obj/machinery/power/apc/A = thing
if(!is_station_level(A.z))
continue
var/obj/item/stock_parts/cell/C = A.get_cell()
if(C)
C.give(C.maxcharge)
/proc/power_restore_quick(announce=TRUE)
if(announce)
GLOB.event_announcement.Announce("All SMESs on [station_name()] have been recharged. We apologize for the inconvenience.", "Power Systems Nominal", new_sound = 'sound/AI/poweron.ogg')
// fix all of the SMESs
for(var/obj/machinery/power/smes/S in GLOB.machines)
if(!is_station_level(S.z))
continue
S.charge = S.capacity
S.output_level = S.output_level_max
S.output_attempt = 1
S.input_attempt = 1
S.update_icon()
S.power_change()
#undef APC_BREAK_PROBABILITY
+2 -2
View File
@@ -55,12 +55,12 @@
kill()
return
if(IsMultiple(activeFor, 4))
if(ISMULTIPLE(activeFor, 4))
var/obj/machinery/vending/rebel = pick(vendingMachines)
vendingMachines.Remove(rebel)
infectedMachines.Add(rebel)
rebel.shut_up = 0
rebel.shoot_inventory = 1
if(IsMultiple(activeFor, 8))
if(ISMULTIPLE(activeFor, 8))
originMachine.speak(pick(rampant_speeches))
+2 -1
View File
@@ -30,7 +30,8 @@
/datum/event/carp_migration/proc/spawn_fish(num_groups, group_size_min = 3, group_size_max = 5)
var/list/spawn_locations = list()
for(var/obj/effect/landmark/C in GLOB.landmarks_list)
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/C = thing
if(C.name == "carpspawn")
spawn_locations.Add(C.loc)
spawn_locations = shuffle(spawn_locations)
@@ -17,7 +17,7 @@
/datum/event/communications_blackout/start()
// This only affects the cores, relays should be unaffected imo
for(var/obj/machinery/tcomms/core/T in GLOB.tcomms_machines)
T.disable_machine()
T.start_ion()
// Bring it back sometime between 3-5 minutes. This uses deciseconds, so 1800 and 3000 respecticely.
// Note that because this is a strict enable not a toggle, the crew or AI can re-enable the machine themselves
addtimer(CALLBACK(T, /obj/machinery/tcomms.proc/enable_machine), rand(1800, 3000))
// The AI cannot disable this, it must be waited for
addtimer(CALLBACK(T, /obj/machinery/tcomms.proc/end_ion), rand(1800, 3000))

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