module things, jfc
This commit is contained in:
@@ -95,7 +95,7 @@
|
||||
SStgui.close_user_uis(occupant, src)
|
||||
vr_human.real_mind = human_occupant.mind
|
||||
vr_human.ckey = human_occupant.ckey
|
||||
to_chat(vr_human, "<span class='notice'>Transfer successful! you are now playing as [vr_human] in VR!</span>")
|
||||
to_chat(vr_human, "<span class='notice'>Transfer successful! You are now playing as [vr_human] in VR!</span>")
|
||||
else
|
||||
if(allow_creating_vr_humans)
|
||||
to_chat(occupant, "<span class='warning'>Virtual avatar not found, attempting to create one...</span>")
|
||||
@@ -104,7 +104,7 @@
|
||||
if(T)
|
||||
SStgui.close_user_uis(occupant, src)
|
||||
build_virtual_human(occupant, T, V.vr_outfit)
|
||||
to_chat(vr_human, "<span class='notice'>Transfer successful! you are now playing as [vr_human] in VR!</span>")
|
||||
to_chat(vr_human, "<span class='notice'>Transfer successful! You are now playing as [vr_human] in VR!</span>")
|
||||
else
|
||||
to_chat(occupant, "<span class='warning'>Virtual world misconfigured, aborting transfer</span>")
|
||||
else
|
||||
|
||||
@@ -80,8 +80,8 @@
|
||||
var/client/banned_client = banned_mob?.client
|
||||
var/banned_mob_guest_key = had_banned_mob && IsGuestKey(banned_mob.key)
|
||||
banned_mob = null
|
||||
|
||||
var/datum/DBQuery/query_add_ban_get_ckey = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("player")] WHERE ckey = '[ckey]'")
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
var/datum/DBQuery/query_add_ban_get_ckey = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_add_ban_get_ckey.warn_execute())
|
||||
qdel(query_add_ban_get_ckey)
|
||||
return
|
||||
@@ -123,9 +123,9 @@
|
||||
adminwho += ", [C]"
|
||||
|
||||
reason = sanitizeSQL(reason)
|
||||
|
||||
var/sql_a_ckey = sanitizeSQL(a_ckey)
|
||||
if(maxadminbancheck)
|
||||
var/datum/DBQuery/query_check_adminban_amt = SSdbcore.NewQuery("SELECT count(id) AS num FROM [format_table_name("ban")] WHERE (a_ckey = '[a_ckey]') AND (bantype = 'ADMIN_PERMABAN' OR (bantype = 'ADMIN_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
|
||||
var/datum/DBQuery/query_check_adminban_amt = SSdbcore.NewQuery("SELECT count(id) AS num FROM [format_table_name("ban")] WHERE (a_ckey = '[sql_a_ckey]') AND (bantype = 'ADMIN_PERMABAN' OR (bantype = 'ADMIN_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
|
||||
if(!query_check_adminban_amt.warn_execute())
|
||||
qdel(query_check_adminban_amt)
|
||||
return
|
||||
@@ -143,7 +143,12 @@
|
||||
computerid = "0"
|
||||
if(!ip)
|
||||
ip = "0.0.0.0"
|
||||
var/sql = "INSERT INTO [format_table_name("ban")] (`bantime`,`server_ip`,`server_port`,`round_id`,`bantype`,`reason`,`job`,`duration`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]', '[bantype_str]', '[reason]', '[job]', [(duration)?"[duration]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[ckey]', '[computerid]', INET_ATON('[ip]'), '[a_ckey]', '[a_computerid]', INET_ATON('[a_ip]'), '[who]', '[adminwho]')"
|
||||
var/sql_job = sanitizeSQL(job)
|
||||
var/sql_computerid = sanitizeSQL(computerid)
|
||||
var/sql_ip = sanitizeSQL(ip)
|
||||
var/sql_a_computerid = sanitizeSQL(a_computerid)
|
||||
var/sql_a_ip = sanitizeSQL(a_ip)
|
||||
var/sql = "INSERT INTO [format_table_name("ban")] (`bantime`,`server_ip`,`server_port`,`round_id`,`bantype`,`reason`,`job`,`duration`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]', '[bantype_str]', '[reason]', '[sql_job]', [(duration)?"[duration]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[sql_ckey]', '[sql_computerid]', INET_ATON('[sql_ip]'), '[sql_a_ckey]', '[sql_a_computerid]', INET_ATON('[sql_a_ip]'), '[who]', '[adminwho]')"
|
||||
var/datum/DBQuery/query_add_ban = SSdbcore.NewQuery(sql)
|
||||
if(!query_add_ban.warn_execute())
|
||||
qdel(query_add_ban)
|
||||
@@ -207,10 +212,11 @@
|
||||
bantype_sql = "(bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now() ) )"
|
||||
else
|
||||
bantype_sql = "bantype = '[bantype_str]'"
|
||||
|
||||
var/sql = "SELECT id FROM [format_table_name("ban")] WHERE ckey = '[ckey]' AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
var/sql = "SELECT id FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
|
||||
if(job)
|
||||
sql += " AND job = '[job]'"
|
||||
var/sql_job = sanitizeSQL(job)
|
||||
sql += " AND job = '[sql_job]'"
|
||||
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
@@ -252,7 +258,7 @@
|
||||
to_chat(usr, "Cancelled")
|
||||
return
|
||||
|
||||
var/datum/DBQuery/query_edit_ban_get_details = SSdbcore.NewQuery("SELECT (SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), duration, reason FROM [format_table_name("ban")] WHERE id = [banid]")
|
||||
var/datum/DBQuery/query_edit_ban_get_details = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), duration, reason FROM [format_table_name("ban")] WHERE id = [banid]")
|
||||
if(!query_edit_ban_get_details.warn_execute())
|
||||
qdel(query_edit_ban_get_details)
|
||||
return
|
||||
@@ -319,7 +325,7 @@
|
||||
if(!check_rights(R_BAN))
|
||||
return
|
||||
|
||||
var/sql = "SELECT (SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey) FROM [format_table_name("ban")] WHERE id = [id]"
|
||||
var/sql = "SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey) FROM [format_table_name("ban")] WHERE id = [id]"
|
||||
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
@@ -406,6 +412,12 @@
|
||||
output += "<tr><td><b>IP:</b> <input type='text' name='dbbanaddip'></td>"
|
||||
output += "<td><b>Computer id:</b> <input type='text' name='dbbanaddcid'></td></tr>"
|
||||
output += "<tr><td><b>Duration:</b> <input type='text' name='dbbaddduration'></td>"
|
||||
output += "<tr><td><b>Severity:</b><select name='dbbanaddseverity'>"
|
||||
output += "<option value=''>--</option>"
|
||||
output += "<option value='High'>High Severity</option>"
|
||||
output += "<option value='Medium'>Medium Severity</option>"
|
||||
output += "<option value='Minor'>Minor Severity</option>"
|
||||
output += "<option value='None'>No Severity</option>"
|
||||
output += "<td><b>Job:</b><select name='dbbanaddjob'>"
|
||||
output += "<option value=''>--</option>"
|
||||
for(var/j in get_all_jobs())
|
||||
@@ -477,7 +489,7 @@
|
||||
output += "<th width='15%'><b>OPTIONS</b></th>"
|
||||
output += "</tr>"
|
||||
var/limit = " LIMIT [bansperpage * page], [bansperpage]"
|
||||
var/datum/DBQuery/query_search_bans = SSdbcore.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, (SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), (SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), unbanned, (SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].unbanned_ckey), unbanned_datetime, edits, round_id FROM [format_table_name("ban")] WHERE [search] ORDER BY bantime DESC[limit]")
|
||||
var/datum/DBQuery/query_search_bans = SSdbcore.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey), unbanned, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].unbanned_ckey), unbanned_ckey), unbanned_datetime, edits, round_id FROM [format_table_name("ban")] WHERE [search] ORDER BY bantime DESC[limit]")
|
||||
if(!query_search_bans.warn_execute())
|
||||
qdel(query_search_bans)
|
||||
return
|
||||
|
||||
@@ -75,8 +75,8 @@
|
||||
if(computer_id)
|
||||
cidquery = " OR computerid = '[computer_id]' "
|
||||
|
||||
var/datum/DBQuery/query_ban_check = SSdbcore.NewQuery("SELECT (SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), (SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), reason, expiration_time, duration, bantime, bantype, id, round_id FROM [format_table_name("ban")] WHERE (ckey = '[ckey]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR bantype = 'ADMIN_PERMABAN' OR ((bantype = 'TEMPBAN' OR bantype = 'ADMIN_TEMPBAN') AND expiration_time > Now())) AND isnull(unbanned)")
|
||||
if(!query_ban_check.Execute())
|
||||
var/datum/DBQuery/query_ban_check = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey), reason, expiration_time, duration, bantime, bantype, id, round_id FROM [format_table_name("ban")] WHERE (ckey = '[ckey]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR bantype = 'ADMIN_PERMABAN' OR ((bantype = 'TEMPBAN' OR bantype = 'ADMIN_TEMPBAN') AND expiration_time > Now())) AND isnull(unbanned)")
|
||||
if(!query_ban_check.Execute(async = TRUE))
|
||||
qdel(query_ban_check)
|
||||
return
|
||||
while(query_ban_check.NextRow())
|
||||
|
||||
@@ -123,9 +123,9 @@ GLOBAL_PROTECT(Banlist)
|
||||
if (temp)
|
||||
WRITE_FILE(GLOB.Banlist["minutes"], bantimestamp)
|
||||
if(!temp)
|
||||
create_message("note", key, bannedby, "Permanently banned - [reason]", null, null, 0, 0)
|
||||
create_message("note", key, bannedby, "Permanently banned - [reason]", null, null, 0, 0, null, 0, 0)
|
||||
else
|
||||
create_message("note", key, bannedby, "Banned for [minutes] minutes - [reason]", null, null, 0, 0)
|
||||
create_message("note", key, bannedby, "Banned for [minutes] minutes - [reason]", null, null, 0, 0, null, 0, 0)
|
||||
return 1
|
||||
|
||||
/proc/RemoveBan(foldername)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
body += "<body>Options panel for <b>[M]</b>"
|
||||
if(M.client)
|
||||
body += " played by <b>[M.client]</b> "
|
||||
body += "\[<A href='?_src_=holder;[HrefToken()];editrights=[(GLOB.admin_datums[M.client.ckey] || GLOB.deadmins[M.client.ckey]) ? "rank" : "add"];ckey=[M.key]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
|
||||
body += "\[<A href='?_src_=holder;[HrefToken()];editrights=[(GLOB.admin_datums[M.client.ckey] || GLOB.deadmins[M.client.ckey]) ? "rank" : "add"];key=[M.key]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
|
||||
if(CONFIG_GET(flag/use_exp_tracking))
|
||||
body += "\[<A href='?_src_=holder;[HrefToken()];getplaytimewindow=[REF(M)]'>" + M.client.get_exp_living() + "</a>\]"
|
||||
|
||||
@@ -50,6 +50,10 @@
|
||||
body += "<a href='?_src_=holder;[HrefToken()];modantagrep=subtract;mob=[REF(M)]'>\[decrease\]</a> "
|
||||
body += "<a href='?_src_=holder;[HrefToken()];modantagrep=set;mob=[REF(M)]'>\[set\]</a> "
|
||||
body += "<a href='?_src_=holder;[HrefToken()];modantagrep=zero;mob=[REF(M)]'>\[zero\]</a>"
|
||||
var/full_version = "Unknown"
|
||||
if(M.client.byond_version)
|
||||
full_version = "[M.client.byond_version].[M.client.byond_build ? M.client.byond_build : "xxx"]"
|
||||
body += "<br>\[<b>Byond version:</b> [full_version]\]<br>"
|
||||
|
||||
|
||||
body += "<br><br>\[ "
|
||||
@@ -241,7 +245,7 @@
|
||||
if(CHANNEL.is_admin_channel)
|
||||
dat+="<B><FONT style='BACKGROUND-COLOR: LightGreen'><A href='?src=[REF(src)];ac_show_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A></FONT></B><BR>"
|
||||
else
|
||||
dat+="<B><A href='?src=[REF(src)];[HrefToken()];ac_show_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ()]<BR></B>"
|
||||
dat+="<B><A href='?src=[REF(src)];[HrefToken()];ac_show_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ""]<BR></B>"
|
||||
dat+="<BR><HR><A href='?src=[REF(src)];[HrefToken()];ac_refresh=1'>Refresh</A>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Back</A>"
|
||||
if(2)
|
||||
@@ -313,7 +317,7 @@
|
||||
dat+="<I>No feed channels found active...</I><BR>"
|
||||
else
|
||||
for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels)
|
||||
dat+="<A href='?src=[REF(src)];[HrefToken()];ac_pick_censor_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ()]<BR>"
|
||||
dat+="<A href='?src=[REF(src)];[HrefToken()];ac_pick_censor_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ""]<BR>"
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Cancel</A>"
|
||||
if(11)
|
||||
dat+="<B>Nanotrasen D-Notice Handler</B><HR>"
|
||||
@@ -324,7 +328,7 @@
|
||||
dat+="<I>No feed channels found active...</I><BR>"
|
||||
else
|
||||
for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels)
|
||||
dat+="<A href='?src=[REF(src)];[HrefToken()];ac_pick_d_notice=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ()]<BR>"
|
||||
dat+="<A href='?src=[REF(src)];[HrefToken()];ac_pick_d_notice=[REF(CHANNEL)]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : ""]<BR>"
|
||||
|
||||
dat+="<BR><A href='?src=[REF(src)];[HrefToken()];ac_setScreen=[0]'>Back</A>"
|
||||
if(12)
|
||||
@@ -546,7 +550,7 @@
|
||||
|
||||
/datum/admins/proc/toggleaooc()
|
||||
set category = "Server"
|
||||
set desc="Toggle dis bitch"
|
||||
set desc="Toggle to bitch"
|
||||
set name="Toggle Antag OOC"
|
||||
toggle_aooc()
|
||||
log_admin("[key_name(usr)] toggled Antagonist OOC.")
|
||||
|
||||
@@ -42,9 +42,6 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
. = ..()
|
||||
|
||||
/datum/admin_rank/can_vv_get(var_name)
|
||||
return FALSE
|
||||
|
||||
/datum/admin_rank/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
@@ -74,7 +71,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
if("varedit")
|
||||
flag = R_VAREDIT
|
||||
if("everything","host","all")
|
||||
flag = ALL
|
||||
flag = R_EVERYTHING
|
||||
if("sound","sounds")
|
||||
flag = R_SOUNDS
|
||||
if("spawn","create")
|
||||
@@ -112,6 +109,22 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
if(flag)
|
||||
return ((rank.rights & flag) == flag) //true only if right has everything in flag
|
||||
|
||||
/proc/sync_ranks_with_db()
|
||||
set waitfor = FALSE
|
||||
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>")
|
||||
return
|
||||
|
||||
var/list/sql_ranks = list()
|
||||
for(var/datum/admin_rank/R in GLOB.protected_ranks)
|
||||
var/sql_rank = sanitizeSQL(R.name)
|
||||
var/sql_flags = sanitizeSQL(R.include_rights)
|
||||
var/sql_exclude_flags = sanitizeSQL(R.exclude_rights)
|
||||
var/sql_can_edit_flags = sanitizeSQL(R.can_edit_rights)
|
||||
sql_ranks += list(list("rank" = "'[sql_rank]'", "flags" = "[sql_flags]", "exclude_flags" = "[sql_exclude_flags]", "can_edit_flags" = "[sql_can_edit_flags]"))
|
||||
SSdbcore.MassInsert(format_table_name("admin_ranks"), sql_ranks, duplicate_key = TRUE)
|
||||
|
||||
//load our rank - > rights associations
|
||||
/proc/load_admin_ranks(dbfail, no_update)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
@@ -139,14 +152,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
||||
if(!no_update)
|
||||
var/list/sql_ranks = list()
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
var/sql_rank = sanitizeSQL(R.name)
|
||||
var/sql_flags = sanitizeSQL(R.include_rights)
|
||||
var/sql_exclude_flags = sanitizeSQL(R.exclude_rights)
|
||||
var/sql_can_edit_flags = sanitizeSQL(R.can_edit_rights)
|
||||
sql_ranks += list(list("rank" = "'[sql_rank]'", "flags" = "[sql_flags]", "exclude_flags" = "[sql_exclude_flags]", "can_edit_flags" = "[sql_can_edit_flags]"))
|
||||
SSdbcore.MassInsert(format_table_name("admin_ranks"), sql_ranks, duplicate_key = TRUE, blocking = TRUE)
|
||||
sync_ranks_with_db()
|
||||
else
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
@@ -172,20 +178,23 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
qdel(query_load_admin_ranks)
|
||||
//load ranks from backup file
|
||||
if(dbfail)
|
||||
var/backup_file = file("data/admins_backup.json")
|
||||
if(!fexists(backup_file))
|
||||
var/backup_file = file2text("data/admins_backup.json")
|
||||
if(backup_file == null)
|
||||
log_world("Unable to locate admins backup file.")
|
||||
return
|
||||
var/list/json = json_decode(file2text(backup_file))
|
||||
return FALSE
|
||||
var/list/json = json_decode(backup_file)
|
||||
for(var/J in json["ranks"])
|
||||
var/skip
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == "[J]") //this rank was already loaded from txt override
|
||||
continue
|
||||
skip = TRUE
|
||||
if(skip)
|
||||
continue
|
||||
var/datum/admin_rank/R = new("[J]", json["ranks"]["[J]"]["include rights"], json["ranks"]["[J]"]["exclude rights"], json["ranks"]["[J]"]["can edit rights"])
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
return 1
|
||||
return json
|
||||
#ifdef TESTING
|
||||
var/msg = "Permission Sets Built:\n"
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
@@ -210,7 +219,8 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
GLOB.admins.Cut()
|
||||
GLOB.protected_admins.Cut()
|
||||
GLOB.deadmins.Cut()
|
||||
dbfail = load_admin_ranks(dbfail, no_update)
|
||||
var/list/backup_file_json = load_admin_ranks(dbfail, no_update)
|
||||
dbfail = backup_file_json != null
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
@@ -251,16 +261,23 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
qdel(query_load_admins)
|
||||
//load admins from backup file
|
||||
if(dbfail)
|
||||
var/backup_file = file("data/admins_backup.json")
|
||||
if(!fexists(backup_file))
|
||||
log_world("Unable to locate admins backup file.")
|
||||
return
|
||||
var/list/json = json_decode(file2text(backup_file))
|
||||
for(var/J in json["admins"])
|
||||
if(!backup_file_json)
|
||||
if(backup_file_json != null)
|
||||
//already tried
|
||||
return
|
||||
var/backup_file = file2text("data/admins_backup.json")
|
||||
if(backup_file == null)
|
||||
log_world("Unable to locate admins backup file.")
|
||||
return
|
||||
backup_file_json = json_decode(backup_file)
|
||||
for(var/J in backup_file_json["admins"])
|
||||
var/skip
|
||||
for(var/A in GLOB.admin_datums + GLOB.deadmins)
|
||||
if(A == "[J]") //this admin was already loaded from txt override
|
||||
continue
|
||||
new /datum/admins(rank_names[ckeyEx(json["admins"]["[J]"])], ckey("[J]"))
|
||||
skip = TRUE
|
||||
if(skip)
|
||||
continue
|
||||
new /datum/admins(rank_names[ckeyEx(backup_file_json["admins"]["[J]"])], ckey("[J]"))
|
||||
#ifdef TESTING
|
||||
var/msg = "Admins Built:\n"
|
||||
for(var/ckey in GLOB.admin_datums)
|
||||
|
||||
@@ -72,6 +72,7 @@ GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
|
||||
/client/proc/stop_sounds,
|
||||
/client/proc/hide_verbs, /*hides all our adminverbs*/
|
||||
/client/proc/hide_most_verbs /*hides all our hideable adminverbs*/
|
||||
/datum/admins/proc/open_borgopanel
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_ban)
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/DB_ban_panel, /client/proc/stickybanpanel))
|
||||
@@ -161,6 +162,7 @@ GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug())
|
||||
/client/proc/pump_random_event,
|
||||
/client/proc/cmd_display_init_log,
|
||||
/client/proc/cmd_display_overlay_log,
|
||||
/client/proc/reload_configuration,
|
||||
/datum/admins/proc/create_or_modify_area,
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_possess)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
C.jobbancache = list()
|
||||
var/datum/DBQuery/query_jobban_build_cache = SSdbcore.NewQuery("SELECT job, reason FROM [format_table_name("ban")] WHERE ckey = '[sanitizeSQL(C.ckey)]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
|
||||
if(!query_jobban_build_cache.warn_execute())
|
||||
qdel(query_jobban_build_cache)
|
||||
return
|
||||
while(query_jobban_build_cache.NextRow())
|
||||
C.jobbancache[query_jobban_build_cache.item[1]] = query_jobban_build_cache.item[2]
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
return
|
||||
last_irc_check = rtod
|
||||
var/server = CONFIG_GET(string/server)
|
||||
return "[GLOB.round_id ? "Round #[GLOB.round_id]: " : ""][GLOB.clients.len] players on [SSmapping.config.map_name]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [server ? server : "[world.internet_address]:[world.port]"]" //CIT CHANGE - obfuscates the current gamemode from players
|
||||
return "[GLOB.round_id ? "Round #[GLOB.round_id]: " : ""][GLOB.clients.len] players on [SSmapping.config.map_name], Mode: [GLOB.master_mode]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [server ? server : "[world.internet_address]:[world.port]"]"
|
||||
|
||||
/datum/tgs_chat_command/ahelp
|
||||
name = "ahelp"
|
||||
@@ -84,7 +84,7 @@ GLOBAL_LIST(round_end_notifiees)
|
||||
if(!SSticker.IsRoundInProgress() && SSticker.HasRoundStarted())
|
||||
return "[sender.mention], the round has already ended!"
|
||||
LAZYINITLIST(GLOB.round_end_notifiees)
|
||||
GLOB.round_end_notifiees[sender] = TRUE
|
||||
GLOB.round_end_notifiees[sender.mention] = TRUE
|
||||
return "I will notify [sender.mention] when the round ends."
|
||||
|
||||
/datum/tgs_chat_command/sdql
|
||||
@@ -116,4 +116,4 @@ GLOBAL_LIST(round_end_notifiees)
|
||||
|
||||
/datum/tgs_chat_command/reload_admins/proc/ReloadAsync()
|
||||
set waitfor = FALSE
|
||||
load_admins()
|
||||
load_admins()
|
||||
|
||||
@@ -154,12 +154,12 @@
|
||||
else
|
||||
dat += "ETA: <a href='?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]</a><BR>"
|
||||
dat += "<B>Continuous Round Status</B><BR>"
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];toggle_continuous=1'>[CONFIG_GET(keyed_flag_list/continuous)[SSticker.mode.config_tag] ? "Continue if antagonists die" : "End on antagonist death"]</a>"
|
||||
if(CONFIG_GET(keyed_flag_list/continuous)[SSticker.mode.config_tag])
|
||||
dat += ", <a href='?_src_=holder;[HrefToken()];toggle_midround_antag=1'>[CONFIG_GET(keyed_flag_list/midround_antag)[SSticker.mode.config_tag] ? "creating replacement antagonists" : "not creating new antagonists"]</a><BR>"
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];toggle_continuous=1'>[CONFIG_GET(keyed_list/continuous)[SSticker.mode.config_tag] ? "Continue if antagonists die" : "End on antagonist death"]</a>"
|
||||
if(CONFIG_GET(keyed_list/continuous)[SSticker.mode.config_tag])
|
||||
dat += ", <a href='?_src_=holder;[HrefToken()];toggle_midround_antag=1'>[CONFIG_GET(keyed_list/midround_antag)[SSticker.mode.config_tag] ? "creating replacement antagonists" : "not creating new antagonists"]</a><BR>"
|
||||
else
|
||||
dat += "<BR>"
|
||||
if(CONFIG_GET(keyed_flag_list/midround_antag)[SSticker.mode.config_tag])
|
||||
if(CONFIG_GET(keyed_list/midround_antag)[SSticker.mode.config_tag])
|
||||
dat += "Time limit: <a href='?_src_=holder;[HrefToken()];alter_midround_time_limit=1'>[CONFIG_GET(number/midround_antag_time_check)] minutes into round</a><BR>"
|
||||
dat += "Living crew limit: <a href='?_src_=holder;[HrefToken()];alter_midround_life_limit=1'>[CONFIG_GET(number/midround_antag_life_check) * 100]% of crew alive</a><BR>"
|
||||
dat += "If limits past: <a href='?_src_=holder;[HrefToken()];toggle_noncontinuous_behavior=1'>[SSticker.mode.round_ends_with_antag_death ? "End The Round" : "Continue As Extended"]</a><BR>"
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
var/checktime = text2num(query_validate_time.item[1])
|
||||
if(!checktime)
|
||||
to_chat(src, "Datetime entered is improperly formatted or not later than current server time.")
|
||||
qdel(query_validate_time)
|
||||
return
|
||||
endtime = query_validate_time.item[1]
|
||||
qdel(query_validate_time)
|
||||
|
||||
@@ -102,19 +102,6 @@
|
||||
qdel(src)
|
||||
|
||||
|
||||
//Shuttle Build
|
||||
|
||||
/obj/effect/shuttle_build
|
||||
name = "shuttle_build"
|
||||
desc = "Some assembly required."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "syndballoon"
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/shuttle_build/New()
|
||||
SSshuttle.emergency.initiate_docking(SSshuttle.getDock("emergency_home"))
|
||||
qdel(src)
|
||||
|
||||
//Arena
|
||||
|
||||
/obj/effect/forcefield/arena_shuttle
|
||||
@@ -127,7 +114,7 @@
|
||||
for(var/obj/effect/landmark/shuttle_arena_safe/exit in GLOB.landmarks_list)
|
||||
warp_points += exit
|
||||
|
||||
/obj/effect/forcefield/arena_shuttle/CollidedWith(atom/movable/AM)
|
||||
/obj/effect/forcefield/arena_shuttle/Bumped(atom/movable/AM)
|
||||
if(!isliving(AM))
|
||||
return
|
||||
|
||||
@@ -158,7 +145,7 @@
|
||||
timeleft = 0
|
||||
var/list/warp_points = list()
|
||||
|
||||
/obj/effect/forcefield/arena_shuttle_entrance/CollidedWith(atom/movable/AM)
|
||||
/obj/effect/forcefield/arena_shuttle_entrance/Bumped(atom/movable/AM)
|
||||
if(!isliving(AM))
|
||||
return
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ GLOBAL_PROTECT(href_token)
|
||||
/datum/admins/proc/check_if_greater_rights_than_holder(datum/admins/other)
|
||||
if(!other)
|
||||
return 1 //they have no rights
|
||||
if(rank.rights == 65535)
|
||||
if(rank.rights == R_EVERYTHING)
|
||||
return 1 //we have all the rights
|
||||
if(src == other)
|
||||
return 1 //you always have more rights than yourself
|
||||
@@ -146,9 +146,6 @@ GLOBAL_PROTECT(href_token)
|
||||
return 1 //we have all the rights they have and more
|
||||
return 0
|
||||
|
||||
/datum/admins/can_vv_get(var_name, var_value)
|
||||
return FALSE //nice try trialmin
|
||||
|
||||
/datum/admins/vv_edit_var(var_name, var_value)
|
||||
return FALSE //nice try trialmin
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
pagecount++
|
||||
output += "|"
|
||||
var/limit = " LIMIT [logssperpage * page], [logssperpage]"
|
||||
var/datum/DBQuery/query_search_admin_logs = SSdbcore.NewQuery("SELECT datetime, round_id, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), operation, IF(ckey IS NULL, target, byond_key), log FROM [format_table_name("admin_log")] LEFT JOIN [format_table_name("player")] ON target = ckey[search] ORDER BY datetime DESC[limit]")
|
||||
var/datum/DBQuery/query_search_admin_logs = SSdbcore.NewQuery("SELECT datetime, round_id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), operation, IF(ckey IS NULL, target, byond_key), log FROM [format_table_name("admin_log")] LEFT JOIN [format_table_name("player")] ON target = ckey[search] ORDER BY datetime DESC[limit]")
|
||||
if(!query_search_admin_logs.warn_execute())
|
||||
qdel(query_search_admin_logs)
|
||||
return
|
||||
@@ -59,7 +59,7 @@
|
||||
qdel(query_search_admin_logs)
|
||||
if(action == 2)
|
||||
output += "<h3>Admin ckeys with invalid ranks</h3>"
|
||||
var/datum/DBQuery/query_check_admin_errors = SSdbcore.NewQuery("SELECT (SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("admin")].ckey), [format_table_name("admin")].rank FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].rank = [format_table_name("admin")].rank WHERE [format_table_name("admin_ranks")].rank IS NULL")
|
||||
var/datum/DBQuery/query_check_admin_errors = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("admin")].ckey), ckey), [format_table_name("admin")].rank FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].rank = [format_table_name("admin")].rank WHERE [format_table_name("admin_ranks")].rank IS NULL")
|
||||
if(!query_check_admin_errors.warn_execute())
|
||||
qdel(query_check_admin_errors)
|
||||
return
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
<B>General Secrets</B><BR>
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=admin_log'>Admin Log</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=mentor_log'>Mentor Log</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=show_admins'>Show Admin List</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=mentor_log'>Mentor Log</A><BR>
|
||||
<BR>
|
||||
"}
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=blackout'>Break all lights</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=whiteout'>Fix all lights</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=floorlava'>The floor is lava! (DANGEROUS: extremely lame)</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=customportal'>Spawn a custom portal storm</A><BR>
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=flipmovement'>Flip client movement directions</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=randommovement'>Randomize client movement directions</A><BR>
|
||||
@@ -110,6 +111,7 @@
|
||||
|
||||
if("mentor_log")
|
||||
CitadelMentorLogSecret()
|
||||
|
||||
if("show_admins")
|
||||
var/dat = "<B>Current admins:</B><HR>"
|
||||
if(GLOB.admin_datums)
|
||||
@@ -475,7 +477,7 @@
|
||||
message_admins("[key_name_admin(usr)] activated AK-47s for Everyone!")
|
||||
usr.client.ak47s()
|
||||
sound_to_playing_players('sound/misc/ak47s.ogg')
|
||||
|
||||
|
||||
if("guns")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
@@ -643,6 +645,77 @@
|
||||
message_admins("[key_name_admin(usr)] has reset all movement keys.")
|
||||
log_admin("[key_name(usr)] has reset all movement keys.")
|
||||
|
||||
if("customportal")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/list/settings = list(
|
||||
"mainsettings" = list(
|
||||
"typepath" = list("desc" = "Path to spawn", "type" = "datum", "path" = "/mob/living", "subtypesonly" = TRUE, "value" = /mob/living/simple_animal/hostile/poison/bees),
|
||||
"humanoutfit" = list("desc" = "Outfit if human", "type" = "datum", "path" = "/datum/outfit", "subtypesonly" = TRUE, "value" = /datum/outfit),
|
||||
"amount" = list("desc" = "Number per portal", "type" = "number", "value" = 1),
|
||||
"portalnum" = list("desc" = "Number of total portals", "type" = "number", "value" = 10),
|
||||
"offerghosts" = list("desc" = "Get ghosts to play mobs", "type" = "boolean", "value" = "No"),
|
||||
"minplayers" = list("desc" = "Minimum number of ghosts", "type" = "number", "value" = 1),
|
||||
"playersonly" = list("desc" = "Only spawn ghost-controlled mobs", "type" = "boolean", "value" = "No"),
|
||||
"ghostpoll" = list("desc" = "Ghost poll question", "type" = "string", "value" = "Do you want to play as %TYPE% portal invader?"),
|
||||
"delay" = list("desc" = "Time between portals, in deciseconds", "type" = "number", "value" = 50),
|
||||
"color" = list("desc" = "Portal color", "type" = "color", "value" = "#00FF00"),
|
||||
"playlightning" = list("desc" = "Play lightning sounds on announcement", "type" = "boolean", "value" = "Yes"),
|
||||
"announce_players" = list("desc" = "Make an announcement", "type" = "boolean", "value" = "Yes"),
|
||||
"announcement" = list("desc" = "Announcement", "type" = "string", "value" = "Massive bluespace anomaly detected en route to %STATION%. Brace for impact."),
|
||||
)
|
||||
)
|
||||
|
||||
message_admins("[key_name(usr)] is creating a custom portal storm...")
|
||||
var/list/prefreturn = presentpreflikepicker(usr,"Customize Portal Storm", "Customize Portal Storm", Button1="Ok", width = 600, StealFocus = 1,Timeout = 0, settings=settings)
|
||||
|
||||
if (prefreturn["button"] == 1)
|
||||
var/list/prefs = settings["mainsettings"]
|
||||
|
||||
if (prefs["amount"]["value"] < 1 || prefs["portalnum"]["value"] < 1)
|
||||
to_chat(usr, "Number of portals and mobs to spawn must be at least 1")
|
||||
return
|
||||
|
||||
var/mob/pathToSpawn = prefs["typepath"]["value"]
|
||||
if (!ispath(pathToSpawn))
|
||||
pathToSpawn = text2path(pathToSpawn)
|
||||
|
||||
if (!ispath(pathToSpawn))
|
||||
to_chat(usr, "Invalid path [pathToSpawn]")
|
||||
return
|
||||
|
||||
var/list/candidates = list()
|
||||
|
||||
if (prefs["offerghosts"]["value"] == "Yes")
|
||||
candidates = pollGhostCandidates(replacetext(prefs["ghostpoll"]["value"], "%TYPE%", initial(pathToSpawn.name)), ROLE_TRAITOR)
|
||||
|
||||
if (prefs["playersonly"]["value"] == "Yes" && length(candidates) < prefs["minplayers"]["value"])
|
||||
message_admins("Not enough players signed up to create a portal storm, the minimum was [prefs["minplayers"]["value"]] and the number of signups [length(candidates)]")
|
||||
return
|
||||
|
||||
if (prefs["announce_players"]["value"] == "Yes")
|
||||
portalAnnounce(prefs["announcement"]["value"], (prefs["playlightning"]["value"] == "Yes" ? TRUE : FALSE))
|
||||
|
||||
var/mutable_appearance/storm = mutable_appearance('icons/obj/tesla_engine/energy_ball.dmi', "energy_ball_fast", FLY_LAYER)
|
||||
storm.color = prefs["color"]["value"]
|
||||
|
||||
message_admins("[key_name_admin(usr)] has created a customized portal storm that will spawn [prefs["portalnum"]["value"]] portals, each of them spawning [prefs["amount"]["value"]] of [pathToSpawn]")
|
||||
log_admin("[key_name(usr)] has created a customized portal storm that will spawn [prefs["portalnum"]["value"]] portals, each of them spawning [prefs["amount"]["value"]] of [pathToSpawn]")
|
||||
|
||||
var/outfit = prefs["humanoutfit"]["value"]
|
||||
if (!ispath(outfit))
|
||||
outfit = text2path(outfit)
|
||||
|
||||
for (var/i in 1 to prefs["portalnum"]["value"])
|
||||
if (length(candidates)) // if we're spawning players, gotta be a little tricky and also not spawn players on top of NPCs
|
||||
var/ghostcandidates = list()
|
||||
for (var/j in 1 to min(prefs["amount"]["value"], length(candidates)))
|
||||
ghostcandidates += pick_n_take(candidates)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/doPortalSpawn, get_random_station_turf(), pathToSpawn, length(ghostcandidates), storm, ghostcandidates, outfit), i*prefs["delay"]["value"])
|
||||
else if (prefs["playersonly"]["value"] != "Yes")
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/doPortalSpawn, get_random_station_turf(), pathToSpawn, prefs["amount"]["value"], storm, null, outfit), i*prefs["delay"]["value"])
|
||||
|
||||
if(E)
|
||||
E.processing = FALSE
|
||||
if(E.announceWhen>0)
|
||||
@@ -653,3 +726,29 @@
|
||||
log_admin("[key_name(usr)] used secret [item]")
|
||||
if (ok)
|
||||
to_chat(world, text("<B>A secret has been activated by []!</B>", usr.key))
|
||||
|
||||
/proc/portalAnnounce(announcement, playlightning)
|
||||
set waitfor = 0
|
||||
if (playlightning)
|
||||
sound_to_playing_players('sound/magic/lightning_chargeup.ogg')
|
||||
sleep(80)
|
||||
priority_announce(replacetext(announcement, "%STATION%", station_name()))
|
||||
if (playlightning)
|
||||
sleep(20)
|
||||
sound_to_playing_players('sound/magic/lightningbolt.ogg')
|
||||
|
||||
/proc/doPortalSpawn(turf/loc, mobtype, numtospawn, portal_appearance, players, humanoutfit)
|
||||
for (var/i in 1 to numtospawn)
|
||||
var/mob/spawnedMob = new mobtype(loc)
|
||||
if (length(players))
|
||||
var/mob/chosen = players[1]
|
||||
if (chosen.client)
|
||||
chosen.client.prefs.copy_to(spawnedMob)
|
||||
spawnedMob.key = chosen.key
|
||||
players -= chosen
|
||||
if (ishuman(spawnedMob) && ispath(humanoutfit, /datum/outfit))
|
||||
var/mob/living/carbon/human/H = spawnedMob
|
||||
H.equipOutfit(humanoutfit)
|
||||
var/turf/T = get_step(loc, SOUTHWEST)
|
||||
flick_overlay_static(portal_appearance, T, 15)
|
||||
playsound(T, 'sound/magic/lightningbolt.ogg', rand(80, 100), 1)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/proc/create_message(type, target_key, admin_ckey, text, timestamp, server, secret, logged = 1, browse)
|
||||
/proc/create_message(type, target_key, admin_ckey, text, timestamp, server, secret, logged = 1, browse, expiry, note_severity)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
if(!type)
|
||||
return
|
||||
var/target_ckey
|
||||
var/target_ckey = ckey(target_key)
|
||||
if(!target_key && (type == "note" || type == "message" || type == "watchlist entry"))
|
||||
var/new_key = input(usr,"Who would you like to create a [type] for?","Enter a key or ckey",null) as null|text
|
||||
if(!new_key)
|
||||
@@ -23,13 +23,8 @@
|
||||
target_key = new_key
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
if(!target_ckey)
|
||||
if(target_key)
|
||||
target_ckey = ckey(target_key)
|
||||
else
|
||||
return
|
||||
if(target_ckey)
|
||||
target_ckey = sanitizeSQL(ckey(target_ckey))
|
||||
target_ckey = sanitizeSQL(target_ckey)
|
||||
if(!target_key)
|
||||
target_key = target_ckey
|
||||
if(!admin_ckey)
|
||||
@@ -59,7 +54,30 @@
|
||||
secret = 0
|
||||
else
|
||||
return
|
||||
var/datum/DBQuery/query_create_message = SSdbcore.NewQuery("INSERT INTO [format_table_name("messages")] (type, targetckey, adminckey, text, timestamp, server, server_ip, server_port, round_id, secret) VALUES ('[type]', '[target_ckey]', '[admin_ckey]', '[text]', '[timestamp]', '[server]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]','[secret]')")
|
||||
if(isnull(expiry))
|
||||
if(alert(usr, "Set an expiry time? Expired messages are hidden like deleted ones.", "Expiry time?", "Yes", "No", "Cancel") == "Yes")
|
||||
var/expire_time = input("Set expiry time for [type] as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than current time for obvious reasons.", "Set expiry time", SQLtime()) as null|text
|
||||
if(!expire_time)
|
||||
return
|
||||
expire_time = sanitizeSQL(expire_time)
|
||||
var/datum/DBQuery/query_validate_expire_time = SSdbcore.NewQuery("SELECT IF(STR_TO_DATE('[expire_time]','%Y-%c-%d %T') > NOW(), STR_TO_DATE('[expire_time]','%Y-%c-%d %T'), 0)")
|
||||
if(!query_validate_expire_time.warn_execute())
|
||||
qdel(query_validate_expire_time)
|
||||
return
|
||||
if(query_validate_expire_time.NextRow())
|
||||
var/checktime = text2num(query_validate_expire_time.item[1])
|
||||
if(!checktime)
|
||||
to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.")
|
||||
qdel(query_validate_expire_time)
|
||||
return
|
||||
expiry = query_validate_expire_time.item[1]
|
||||
qdel(query_validate_expire_time)
|
||||
if(type == "note" && isnull(note_severity))
|
||||
note_severity = input("Set the severity of the note.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None")
|
||||
if(!note_severity)
|
||||
return
|
||||
note_severity = sanitizeSQL(note_severity)
|
||||
var/datum/DBQuery/query_create_message = SSdbcore.NewQuery("INSERT INTO [format_table_name("messages")] (type, targetckey, adminckey, text, timestamp, server, server_ip, server_port, round_id, secret, expire_timestamp, severity) VALUES ('[type]', '[target_ckey]', '[admin_ckey]', '[text]', '[timestamp]', '[server]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]','[secret]', [expiry ? "'[expiry]'" : "NULL"], [note_severity ? "'[note_severity]'" : "NULL"])")
|
||||
var/pm = "[key_name(usr)] has created a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""]: [text]"
|
||||
var/header = "[key_name_admin(usr)] has created a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""]"
|
||||
if(!query_create_message.warn_execute())
|
||||
@@ -88,7 +106,7 @@
|
||||
var/text
|
||||
var/user_key_name = key_name(usr)
|
||||
var/user_name_admin = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_del_message = SSdbcore.NewQuery("SELECT type, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
var/datum/DBQuery/query_find_del_message = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_del_message.warn_execute())
|
||||
qdel(query_find_del_message)
|
||||
return
|
||||
@@ -123,7 +141,7 @@
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_edit_message = SSdbcore.NewQuery("SELECT type, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
var/datum/DBQuery/query_find_edit_message = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), targetckey), text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_edit_message.warn_execute())
|
||||
qdel(query_find_edit_message)
|
||||
return
|
||||
@@ -151,6 +169,103 @@
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
qdel(query_find_edit_message)
|
||||
|
||||
/proc/edit_message_expiry(message_id, browse)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_edit_expiry_message = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), expire_timestamp FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_edit_expiry_message.warn_execute())
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
if(query_find_edit_expiry_message.NextRow())
|
||||
var/type = query_find_edit_expiry_message.item[1]
|
||||
var/target_key = query_find_edit_expiry_message.item[2]
|
||||
var/admin_key = query_find_edit_expiry_message.item[3]
|
||||
var/old_expiry = query_find_edit_expiry_message.item[4]
|
||||
var/new_expiry
|
||||
var/expire_time = input("Set expiry time for [type] as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than current time for obvious reasons. Enter -1 to remove expiry time.", "Set expiry time", old_expiry) as null|text
|
||||
if(!expire_time)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
if(expire_time == "-1")
|
||||
new_expiry = "non-expiring"
|
||||
else
|
||||
expire_time = sanitizeSQL(expire_time)
|
||||
var/datum/DBQuery/query_validate_expire_time_edit = SSdbcore.NewQuery("SELECT IF(STR_TO_DATE('[expire_time]','%Y-%c-%d %T') > NOW(), STR_TO_DATE('[expire_time]','%Y-%c-%d %T'), 0)")
|
||||
if(!query_validate_expire_time_edit.warn_execute())
|
||||
qdel(query_validate_expire_time_edit)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
if(query_validate_expire_time_edit.NextRow())
|
||||
var/checktime = text2num(query_validate_expire_time_edit.item[1])
|
||||
if(!checktime)
|
||||
to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.")
|
||||
qdel(query_validate_expire_time_edit)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
new_expiry = query_validate_expire_time_edit.item[1]
|
||||
qdel(query_validate_expire_time_edit)
|
||||
var/edit_text = sanitizeSQL("Expiration time edited by [editor_key] on [SQLtime()] from [old_expiry] to [new_expiry]<hr>")
|
||||
var/datum/DBQuery/query_edit_message_expiry = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET expire_timestamp = [expire_time == "-1" ? "NULL" : "'[new_expiry]'"], lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_edit_message_expiry.warn_execute())
|
||||
qdel(query_edit_message_expiry)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
qdel(query_edit_message_expiry)
|
||||
log_admin_private("[kn] has edited the expiration time of a [type] [(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""] made by [admin_key] from [old_expiry] to [new_expiry]")
|
||||
message_admins("[kna] has edited the expiration time of a [type] [(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""] made by [admin_key] from [old_expiry] to [new_expiry]")
|
||||
if(browse)
|
||||
browse_messages("[type]")
|
||||
else
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
|
||||
/proc/edit_message_severity(message_id)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_edit_note_severity = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), severity FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_edit_note_severity.warn_execute())
|
||||
qdel(query_find_edit_note_severity)
|
||||
return
|
||||
if(query_find_edit_note_severity.NextRow())
|
||||
var/type = query_find_edit_note_severity.item[1]
|
||||
var/target_key = query_find_edit_note_severity.item[2]
|
||||
var/admin_key = query_find_edit_note_severity.item[3]
|
||||
var/old_severity = query_find_edit_note_severity.item[4]
|
||||
if(!old_severity)
|
||||
old_severity = "NA"
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/new_severity = input("Set the severity of the note.", "Severity", null, null) as null|anything in list("high", "medium", "minor", "none") //lowercase for edit log consistency
|
||||
if(!new_severity)
|
||||
qdel(query_find_edit_note_severity)
|
||||
return
|
||||
new_severity = sanitizeSQL(new_severity)
|
||||
var/edit_text = sanitizeSQL("Note severity edited by [editor_key] on [SQLtime()] from [old_severity] to [new_severity]<hr>")
|
||||
var/datum/DBQuery/query_edit_note_severity = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET severity = '[new_severity]', lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_edit_note_severity.warn_execute(async = TRUE))
|
||||
qdel(query_edit_note_severity)
|
||||
qdel(qdel(query_find_edit_note_severity))
|
||||
return
|
||||
qdel(query_edit_note_severity)
|
||||
log_admin_private("[kn] has edited the severity of a [type] for [target_key] made by [admin_key] from [old_severity] to [new_severity]")
|
||||
message_admins("[kna] has edited the severity time of a [type] for [target_key] made by [admin_key] from [old_severity] to [new_severity]")
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
qdel(query_find_edit_note_severity)
|
||||
|
||||
/proc/toggle_message_secrecy(message_id)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
@@ -162,7 +277,7 @@
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_message_secret = SSdbcore.NewQuery("SELECT type, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), secret FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
var/datum/DBQuery/query_find_message_secret = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), targetckey), secret FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
if(!query_find_message_secret.warn_execute())
|
||||
qdel(query_find_message_secret)
|
||||
return
|
||||
@@ -189,10 +304,10 @@
|
||||
return
|
||||
var/list/output = list()
|
||||
var/ruler = "<hr style='background:#000000; border:0; height:3px'>"
|
||||
var/list/navbar = list("<a href='?_src_=holder;[HrefToken()];nonalpha=1'>\[All\]</a>|<a href='?_src_=holder;[HrefToken()];nonalpha=2'>\[#\]</a>")
|
||||
var/list/navbar = list("<a href='?_src_=holder;[HrefToken()];nonalpha=1'>All</a><a href='?_src_=holder;[HrefToken()];nonalpha=2'>#</a>")
|
||||
for(var/letter in GLOB.alphabet)
|
||||
navbar += "|<a href='?_src_=holder;[HrefToken()];showmessages=[letter]'>\[[letter]\]</a>"
|
||||
navbar += "|<a href='?_src_=holder;[HrefToken()];showmemo=1'>\[Memos\]</a>|<a href='?_src_=holder;[HrefToken()];showwatch=1'>\[Watchlist\]</a>"
|
||||
navbar += "<a href='?_src_=holder;[HrefToken()];showmessages=[letter]'>[letter]</a>"
|
||||
navbar += "<a href='?_src_=holder;[HrefToken()];showmemo=1'>Memos</a><a href='?_src_=holder;[HrefToken()];showwatch=1'>Watchlist</a>"
|
||||
navbar += "<br><form method='GET' name='search' action='?'>\
|
||||
<input type='hidden' name='_src_' value='holder'>\
|
||||
[HrefTokenFormField()]\
|
||||
@@ -203,16 +318,16 @@
|
||||
if(type == "memo" || type == "watchlist entry")
|
||||
if(type == "memo")
|
||||
output += "<h2><center>Admin memos</h2>"
|
||||
output += "<a href='?_src_=holder;[HrefToken()];addmemo=1'>\[Add memo\]</a></center>"
|
||||
output += "<a href='?_src_=holder;[HrefToken()];addmemo=1'>Add memo</a></center>"
|
||||
else if(type == "watchlist entry")
|
||||
output += "<h2><center>Watchlist entries</h2>"
|
||||
output += "<a href='?_src_=holder;[HrefToken()];addwatchempty=1'>\[Add watchlist entry\]</a>"
|
||||
output += "<a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a>"
|
||||
if(filter)
|
||||
output += "|<a href='?_src_=holder;[HrefToken()];showwatch=1'>\[Unfilter clients\]</a></center>"
|
||||
output += "<a href='?_src_=holder;[HrefToken()];showwatch=1'>Unfilter clients</a></center>"
|
||||
else
|
||||
output += "|<a href='?_src_=holder;[HrefToken()];showwatchfilter=1'>\[Filter offline clients\]</a></center>"
|
||||
output += "<a href='?_src_=holder;[HrefToken()];showwatchfilter=1'>Filter offline clients</a></center>"
|
||||
output += ruler
|
||||
var/datum/DBQuery/query_get_type_messages = SSdbcore.NewQuery("SELECT id, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), text, timestamp, server, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor) FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0")
|
||||
var/datum/DBQuery/query_get_type_messages = SSdbcore.NewQuery("SELECT id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), targetckey, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), text, timestamp, server, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor), expire_timestamp FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)")
|
||||
if(!query_get_type_messages.warn_execute())
|
||||
qdel(query_get_type_messages)
|
||||
return
|
||||
@@ -229,12 +344,17 @@
|
||||
var/timestamp = query_get_type_messages.item[6]
|
||||
var/server = query_get_type_messages.item[7]
|
||||
var/editor_key = query_get_type_messages.item[8]
|
||||
var/expire_timestamp = query_get_type_messages.item[9]
|
||||
output += "<b>"
|
||||
if(type == "watchlist entry")
|
||||
output += "[t_key] | "
|
||||
output += "[timestamp] | [server] | [admin_key]</b>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];deletemessageempty=[id]'>\[Delete\]</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];editmessageempty=[id]'>\[Edit\]</a>"
|
||||
output += "[timestamp] | [server] | [admin_key]"
|
||||
if(expire_timestamp)
|
||||
output += " | Expires [expire_timestamp]"
|
||||
output += "</b>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];editmessageexpiryempty=[id]'>Change Expiry Time</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];deletemessageempty=[id]'>Delete</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];editmessageempty=[id]'>Edit</a>"
|
||||
if(editor_key)
|
||||
output += " <font size='2'>Last edit by [editor_key] <a href='?_src_=holder;[HrefToken()];messageedits=[id]'>(Click here to see edit log)</a></font>"
|
||||
output += "<br>[text]<hr style='background:#000000; border:0; height:1px'>"
|
||||
@@ -242,7 +362,7 @@
|
||||
if(target_ckey)
|
||||
target_ckey = sanitizeSQL(target_ckey)
|
||||
var/target_key
|
||||
var/datum/DBQuery/query_get_messages = SSdbcore.NewQuery("SELECT type, secret, id, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), text, timestamp, server, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), DATEDIFF(NOW(), timestamp) AS `age`, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey) FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey = '[target_ckey]' AND deleted = 0 ORDER BY timestamp DESC")
|
||||
var/datum/DBQuery/query_get_messages = SSdbcore.NewQuery("SELECT type, secret, id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), text, timestamp, server, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor), DATEDIFF(NOW(), timestamp), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), expire_timestamp, severity FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey = '[target_ckey]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL) ORDER BY timestamp DESC")
|
||||
if(!query_get_messages.warn_execute())
|
||||
qdel(query_get_messages)
|
||||
return
|
||||
@@ -267,6 +387,8 @@
|
||||
var/editor_key = query_get_messages.item[8]
|
||||
var/age = text2num(query_get_messages.item[9])
|
||||
target_key = query_get_messages.item[10]
|
||||
var/expire_timestamp = query_get_messages.item[11]
|
||||
var/severity = query_get_messages.item[12]
|
||||
var/alphatext = ""
|
||||
var/nsd = CONFIG_GET(number/note_stale_days)
|
||||
var/nfd = CONFIG_GET(number/note_fresh_days)
|
||||
@@ -280,21 +402,33 @@
|
||||
alpha = 10
|
||||
skipped = TRUE
|
||||
alphatext = "filter: alpha(opacity=[alpha]); opacity: [alpha/100];"
|
||||
|
||||
var/list/data = list("<p style='margin:0px;[alphatext]'> <b>[timestamp] | [server] | [admin_key]</b>")
|
||||
var/list/data = list("<div style='margin:0px;[alphatext]'><p class='severity'>")
|
||||
if(severity)
|
||||
data += "<img src='[severity]_button.png' height='24' width='24'></img> "
|
||||
data += "<b>[timestamp] | [server] | [admin_key][secret ? " | <i>- Secret</i>" : ""]"
|
||||
if(expire_timestamp)
|
||||
data += " | Expires [expire_timestamp]"
|
||||
data += "</b></p><center>"
|
||||
if(!linkless)
|
||||
data += " <a href='?_src_=holder;[HrefToken()];deletemessage=[id]'>\[Delete\]</a>"
|
||||
if(type == "note")
|
||||
data += " <a href='?_src_=holder;[HrefToken()];secretmessage=[id]'>[secret ? "<b>\[Secret\]</b>" : "\[Not secret\]"]</a>"
|
||||
if(severity)
|
||||
data += "<a href='?_src_=holder;[HrefToken()];editmessageseverity=[id]'>[severity=="none" ? "No" : "[capitalize(severity)]"] Severity</a>"
|
||||
else
|
||||
data += "<a href='?_src_=holder;[HrefToken()];editmessageseverity=[id]'>N/A Severity</a>"
|
||||
data += " <a href='?_src_=holder;[HrefToken()];editmessageexpiry=[id]'>Change Expiry Time</a>"
|
||||
data += " <a href='?_src_=holder;[HrefToken()];deletemessage=[id]'>Delete</a>"
|
||||
if(type == "note")
|
||||
data += " <a href='?_src_=holder;[HrefToken()];secretmessage=[id]'>[secret ? "<b>Secret</b>" : "Not secret"]</a>"
|
||||
if(type == "message sent")
|
||||
data += " <font size='2'>Message has been sent</font>"
|
||||
if(editor_key)
|
||||
data += "|"
|
||||
else
|
||||
data += " <a href='?_src_=holder;[HrefToken()];editmessage=[id]'>\[Edit\]</a>"
|
||||
data += " <a href='?_src_=holder;[HrefToken()];editmessage=[id]'>Edit</a>"
|
||||
if(editor_key)
|
||||
data += " <font size='2'>Last edit by [editor_key] <a href='?_src_=holder;[HrefToken()];messageedits=[id]'>(Click here to see edit log)</a></font>"
|
||||
data += "<br>[text]</p><hr style='background:#000000; border:0; height:1px; [alphatext]'>"
|
||||
data += "</div></center>"
|
||||
data += "<p style='[alphatext]'>[text]</p><hr style='background:#000000; border:0; height:1px; [alphatext]'>"
|
||||
switch(type)
|
||||
if("message")
|
||||
messagedata += data
|
||||
@@ -305,36 +439,43 @@
|
||||
if("note")
|
||||
notedata += data
|
||||
qdel(query_get_messages)
|
||||
if(!target_key)
|
||||
var/datum/DBQuery/query_get_message_key = SSdbcore.NewQuery("SELECT byond_key FROM [format_table_name("player")] WHERE ckey = '[target_ckey]'")
|
||||
if(!query_get_message_key.warn_execute())
|
||||
qdel(query_get_message_key)
|
||||
return
|
||||
if(query_get_message_key.NextRow())
|
||||
target_key = query_get_message_key.item[1]
|
||||
qdel(query_get_message_key)
|
||||
output += "<h2><center>[target_key]</center></h2><center>"
|
||||
if(!linkless)
|
||||
output += "<a href='?_src_=holder;[HrefToken()];addnote=[target_key]'>\[Add note\]</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];addmessage=[target_key]'>\[Add message\]</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];addwatch=[target_key]'>\[Add to watchlist\]</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>\[Refresh page\]</a></center>"
|
||||
output += "<a href='?_src_=holder;[HrefToken()];addnote=[target_key]'>Add note</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];addmessage=[target_key]'>Add message</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];addwatch=[target_key]'>Add to watchlist</a>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>Refresh page</a></center>"
|
||||
else
|
||||
output += " <a href='?_src_=holder;[HrefToken()];showmessageckeylinkless=[target_ckey]'>\[Refresh page\]</a></center>"
|
||||
output += " <a href='?_src_=holder;[HrefToken()];showmessageckeylinkless=[target_ckey]'>Refresh page</a></center>"
|
||||
output += ruler
|
||||
if(messagedata)
|
||||
output += "<h4>Messages</h4>"
|
||||
output += "<h2>Messages</h2>"
|
||||
output += messagedata
|
||||
if(watchdata)
|
||||
output += "<h4>Watchlist</h4>"
|
||||
output += "<h2>Watchlist</h2>"
|
||||
output += watchdata
|
||||
if(notedata)
|
||||
output += "<h4>Notes</h4>"
|
||||
output += "<h2>Notes</h2>"
|
||||
output += notedata
|
||||
if(!linkless)
|
||||
if (agegate)
|
||||
if (skipped) //the first skipped message is still shown so that we can put this link over it.
|
||||
output += " <center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1' style='position: relative; top: -3em;'>\[Show [skipped] hidden messages\]</center>"
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1' style='position: relative; top: -3em;'>Show [skipped] hidden messages</a></center>"
|
||||
else
|
||||
output += " <center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1'>\[Show All\]</center>"
|
||||
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey];showall=1'>Show All</a></center>"
|
||||
else
|
||||
output += " <center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>\[Hide Old\]</center>"
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];showmessageckey=[target_ckey]'>Hide Old</a></center>"
|
||||
if(index)
|
||||
var/search
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];addmessageempty=1'>\[Add message\]</a><a href='?_src_=holder;[HrefToken()];addwatchempty=1'>\[Add watchlist entry\]</a><a href='?_src_=holder;[HrefToken()];addnoteempty=1'>\[Add note\]</a></center>"
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];addmessageempty=1'>Add message</a><a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a><a href='?_src_=holder;[HrefToken()];addnoteempty=1'>Add note</a></center>"
|
||||
output += ruler
|
||||
if(!isnum(index))
|
||||
index = sanitizeSQL(index)
|
||||
@@ -345,7 +486,7 @@
|
||||
search = "^\[^\[:alpha:\]\]"
|
||||
else
|
||||
search = "^[index]"
|
||||
var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey) FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' AND deleted = 0 ORDER BY targetckey")
|
||||
var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey) FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL) ORDER BY targetckey")
|
||||
if(!query_list_messages.warn_execute())
|
||||
qdel(query_list_messages)
|
||||
return
|
||||
@@ -354,12 +495,18 @@
|
||||
return
|
||||
var/index_ckey = query_list_messages.item[1]
|
||||
var/index_key = query_list_messages.item[2]
|
||||
if(!index_key)
|
||||
index_key = index_ckey
|
||||
output += "<a href='?_src_=holder;[HrefToken()];showmessageckey=[index_ckey]'>[index_key]</a><br>"
|
||||
qdel(query_list_messages)
|
||||
else if(!type && !target_ckey && !index)
|
||||
output += "<center></a> <a href='?_src_=holder;[HrefToken()];addmessageempty=1'>\[Add message\]</a><a href='?_src_=holder;[HrefToken()];addwatchempty=1'>\[Add watchlist entry\]</a><a href='?_src_=holder;[HrefToken()];addnoteempty=1'>\[Add note\]</a></center>"
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];addmessageempty=1'>Add message</a><a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a><a href='?_src_=holder;[HrefToken()];addnoteempty=1'>Add note</a></center>"
|
||||
output += ruler
|
||||
usr << browse({"<!DOCTYPE html><html><head><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /></head><body>[jointext(output, "")]</body></html>"}, "window=browse_messages;size=900x500")
|
||||
var/datum/browser/browser = new(usr, "Note panel", "Manage player notes", 1000, 500)
|
||||
var/datum/asset/notes_assets = get_asset_datum(/datum/asset/simple/notes)
|
||||
notes_assets.send(src)
|
||||
browser.set_content(jointext(output, ""))
|
||||
browser.open()
|
||||
|
||||
/proc/get_message_output(type, target_ckey)
|
||||
if(!SSdbcore.Connect())
|
||||
@@ -370,7 +517,7 @@
|
||||
var/output
|
||||
if(target_ckey)
|
||||
target_ckey = sanitizeSQL(target_ckey)
|
||||
var/query = "SELECT id, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), text, timestamp, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor) FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0"
|
||||
var/query = "SELECT id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), text, timestamp, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor) FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)"
|
||||
if(type == "message" || type == "watchlist entry")
|
||||
query += " AND targetckey = '[target_ckey]'"
|
||||
var/datum/DBQuery/query_get_message_output = SSdbcore.NewQuery(query)
|
||||
@@ -432,7 +579,7 @@
|
||||
timestamp = query_convert_time.item[1]
|
||||
qdel(query_convert_time)
|
||||
if(ckey && notetext && timestamp && admin_ckey && server)
|
||||
create_message("note", ckey, admin_ckey, notetext, timestamp, server, 1, 0)
|
||||
create_message("note", ckey, admin_ckey, notetext, timestamp, server, 1, 0, null, 0, 0)
|
||||
notesfile.cd = "/"
|
||||
notesfile.dir.Remove(ckey)
|
||||
|
||||
|
||||
+82
-35
@@ -215,37 +215,38 @@
|
||||
var/banduration = text2num(href_list["dbbaddduration"])
|
||||
var/banjob = href_list["dbbanaddjob"]
|
||||
var/banreason = href_list["dbbanreason"]
|
||||
var/banseverity = href_list["dbbanaddseverity"]
|
||||
|
||||
switch(bantype)
|
||||
if(BANTYPE_PERMA)
|
||||
if(!banckey || !banreason)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey and reason).")
|
||||
if(!banckey || !banreason || !banseverity)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, severity, and reason).")
|
||||
return
|
||||
banduration = null
|
||||
banjob = null
|
||||
if(BANTYPE_TEMP)
|
||||
if(!banckey || !banreason || !banduration)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, reason and duration).")
|
||||
if(!banckey || !banreason || !banduration || !banseverity)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, reason, severity and duration).")
|
||||
return
|
||||
banjob = null
|
||||
if(BANTYPE_JOB_PERMA)
|
||||
if(!banckey || !banreason || !banjob)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, reason and job).")
|
||||
if(!banckey || !banreason || !banjob || !banseverity)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, severity, reason and job).")
|
||||
return
|
||||
banduration = null
|
||||
if(BANTYPE_JOB_TEMP)
|
||||
if(!banckey || !banreason || !banjob || !banduration)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, reason and job).")
|
||||
if(!banckey || !banreason || !banjob || !banduration || !banseverity)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, severity, reason and job).")
|
||||
return
|
||||
if(BANTYPE_ADMIN_PERMA)
|
||||
if(!banckey || !banreason)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey and reason).")
|
||||
if(!banckey || !banreason || !banseverity)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, severity and reason).")
|
||||
return
|
||||
banduration = null
|
||||
banjob = null
|
||||
if(BANTYPE_ADMIN_TEMP)
|
||||
if(!banckey || !banreason || !banduration)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, reason and duration).")
|
||||
if(!banckey || !banreason || !banduration || !banseverity)
|
||||
to_chat(usr, "Not enough parameters (Requires ckey, severity, reason and duration).")
|
||||
return
|
||||
banjob = null
|
||||
|
||||
@@ -270,7 +271,7 @@
|
||||
if(!DB_ban_record(bantype, playermob, banduration, banreason, banjob, bankey, banip, bancid ))
|
||||
to_chat(usr, "<span class='danger'>Failed to apply ban.</span>")
|
||||
return
|
||||
create_message("note", bankey, null, banreason, null, null, 0, 0)
|
||||
create_message("note", bankey, null, banreason, null, null, 0, 0, null, 0, banseverity)
|
||||
|
||||
else if(href_list["editrightsbrowser"])
|
||||
edit_admin_permissions(0)
|
||||
@@ -340,7 +341,7 @@
|
||||
else if(href_list["toggle_continuous"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/list/continuous = CONFIG_GET(keyed_flag_list/continuous)
|
||||
var/list/continuous = CONFIG_GET(keyed_list/continuous)
|
||||
if(!continuous[SSticker.mode.config_tag])
|
||||
continuous[SSticker.mode.config_tag] = TRUE
|
||||
else
|
||||
@@ -353,7 +354,7 @@
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
var/list/midround_antag = CONFIG_GET(keyed_flag_list/midround_antag)
|
||||
var/list/midround_antag = CONFIG_GET(keyed_list/midround_antag)
|
||||
if(!midround_antag[SSticker.mode.config_tag])
|
||||
midround_antag[SSticker.mode.config_tag] = TRUE
|
||||
else
|
||||
@@ -599,6 +600,9 @@
|
||||
var/reason = input(usr,"Please State Reason.","Reason") as message|null
|
||||
if(!reason)
|
||||
return
|
||||
var/severity = input("Set the severity of the note/ban.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None")
|
||||
if(!severity)
|
||||
return
|
||||
if(!DB_ban_record(BANTYPE_JOB_PERMA, M, -1, reason, "appearance"))
|
||||
to_chat(usr, "<span class='danger'>Failed to apply ban.</span>")
|
||||
return
|
||||
@@ -606,7 +610,7 @@
|
||||
jobban_buildcache(M.client)
|
||||
ban_unban_log_save("[key_name(usr)] appearance banned [key_name(M)]. reason: [reason]")
|
||||
log_admin_private("[key_name(usr)] appearance banned [key_name(M)]. \nReason: [reason]")
|
||||
create_message("note", M.key, null, "Appearance banned - [reason]", null, null, 0, 0)
|
||||
create_message("note", M.key, null, "Appearance banned - [reason]", null, null, 0, 0, null, 0, severity)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] appearance banned [key_name_admin(M)].</span>")
|
||||
to_chat(M, "<span class='boldannounce'><BIG>You have been appearance banned by [usr.client.key].</BIG></span>")
|
||||
to_chat(M, "<span class='boldannounce'>The reason is: [reason]</span>")
|
||||
@@ -804,30 +808,35 @@
|
||||
|
||||
|
||||
//Drones
|
||||
if(jobban_isbanned(M, "drone"))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=drone;jobban4=[REF(M)]'><font color=red>Drone</font></a></td>"
|
||||
if(jobban_isbanned(M, ROLE_DRONE))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_DRONE];jobban4=[REF(M)]'><font color=red>Drone</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=drone;jobban4=[REF(M)]'>Drone</a></td>"
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_DRONE];jobban4=[REF(M)]'>Drone</a></td>"
|
||||
|
||||
|
||||
//Positronic Brains
|
||||
if(jobban_isbanned(M, "posibrain"))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=posibrain;jobban4=[REF(M)]'><font color=red>Posibrain</font></a></td>"
|
||||
if(jobban_isbanned(M, ROLE_POSIBRAIN))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_POSIBRAIN];jobban4=[REF(M)]'><font color=red>Posibrain</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=posibrain;jobban4=[REF(M)]'>Posibrain</a></td>"
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_POSIBRAIN];jobban4=[REF(M)]'>Posibrain</a></td>"
|
||||
|
||||
//Sentience Potion Spawn
|
||||
if(jobban_isbanned(M, ROLE_SENTIENCE))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_SENTIENCE];jobban4=[REF(M)]'><font color=red>Sentience Potion Spawn</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_SENTIENCE];jobban4=[REF(M)]'>Sentience Potion Spawn</a></td>"
|
||||
|
||||
//Deathsquad
|
||||
if(jobban_isbanned(M, "deathsquad"))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=deathsquad;jobban4=[REF(M)]'><font color=red>Deathsquad</font></a></td>"
|
||||
if(jobban_isbanned(M, ROLE_DEATHSQUAD))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_DEATHSQUAD];jobban4=[REF(M)]'><font color=red>Deathsquad</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=deathsquad;jobban4=[REF(M)]'>Deathsquad</a></td>"
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_DEATHSQUAD];jobban4=[REF(M)]'>Deathsquad</a></td>"
|
||||
|
||||
//Lavaland roles
|
||||
if(jobban_isbanned(M, "lavaland"))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=lavaland;jobban4=[REF(M)]'><font color=red>Lavaland</font></a></td>"
|
||||
if(jobban_isbanned(M, ROLE_LAVALAND))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_LAVALAND];jobban4=[REF(M)]'><font color=red>Lavaland</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=lavaland;jobban4=[REF(M)]'>Lavaland</a></td>"
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_LAVALAND];jobban4=[REF(M)]'>Lavaland</a></td>"
|
||||
|
||||
dat += "</tr></table>"
|
||||
|
||||
@@ -894,6 +903,16 @@
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=alien;jobban4=[REF(M)]'>Alien</a></td>"
|
||||
|
||||
//Other Roles (black)
|
||||
dat += "<table cellpadding='1' cellspacing='0' width='100%'>"
|
||||
dat += "<tr bgcolor='000000'><th colspan='5'><a href='?src=[REF(src)];[HrefToken()];jobban3=otherroles;jobban4=[REF(M)]' style='color: white;'>Other Roles</a></th></tr><tr align='center'>"
|
||||
|
||||
//Mind Transfer Potion
|
||||
if(jobban_isbanned(M, ROLE_MIND_TRANSFER))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_MIND_TRANSFER];jobban4=[REF(M)]'><font color=red>Mind Transfer Potion</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_MIND_TRANSFER];jobban4=[REF(M)]'>Mind Transfer Potion</a></td>"
|
||||
|
||||
dat += "</tr></table>"
|
||||
usr << browse(dat, "window=jobban2;size=800x450")
|
||||
return
|
||||
@@ -953,11 +972,13 @@
|
||||
continue
|
||||
joblist += jobPos
|
||||
if("ghostroles")
|
||||
joblist += list(ROLE_PAI, "posibrain", "drone", "deathsquad", "lavaland")
|
||||
joblist += list(ROLE_PAI, ROLE_POSIBRAIN, ROLE_DRONE , ROLE_DEATHSQUAD, ROLE_LAVALAND, ROLE_SENTIENCE)
|
||||
if("teamantags")
|
||||
joblist += list(ROLE_OPERATIVE, ROLE_REV, ROLE_CULTIST, ROLE_SERVANT_OF_RATVAR, ROLE_ABDUCTOR, ROLE_ALIEN)
|
||||
if("convertantags")
|
||||
joblist += list(ROLE_REV, ROLE_CULTIST, ROLE_SERVANT_OF_RATVAR, ROLE_ALIEN)
|
||||
if("otherroles")
|
||||
joblist += list(ROLE_MIND_TRANSFER)
|
||||
else
|
||||
joblist += href_list["jobban3"]
|
||||
|
||||
@@ -969,6 +990,7 @@
|
||||
|
||||
//Banning comes first
|
||||
if(notbannedlist.len) //at least 1 unbanned job exists in joblist so we have stuff to ban.
|
||||
var/severity = null
|
||||
switch(alert("Temporary Ban for [M.key]?",,"Yes","No", "Cancel"))
|
||||
if("Yes")
|
||||
var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null
|
||||
@@ -978,7 +1000,9 @@
|
||||
var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null
|
||||
if(!reason)
|
||||
return
|
||||
|
||||
severity = input("Set the severity of the note/ban.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None")
|
||||
if(!severity)
|
||||
return
|
||||
var/msg
|
||||
for(var/job in notbannedlist)
|
||||
if(!DB_ban_record(BANTYPE_JOB_TEMP, M, mins, reason, job))
|
||||
@@ -992,7 +1016,7 @@
|
||||
msg = job
|
||||
else
|
||||
msg += ", [job]"
|
||||
create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0)
|
||||
create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0, null, 0, severity)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes.</span>")
|
||||
to_chat(M, "<span class='boldannounce'><BIG>You have been [(msg == ("ooc" || "appearance")) ? "banned" : "jobbanned"] by [usr.client.key] from: [msg].</BIG></span>")
|
||||
to_chat(M, "<span class='boldannounce'>The reason is: [reason]</span>")
|
||||
@@ -1001,6 +1025,9 @@
|
||||
return 1
|
||||
if("No")
|
||||
var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null
|
||||
severity = input("Set the severity of the note/ban.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None")
|
||||
if(!severity)
|
||||
return
|
||||
if(reason)
|
||||
var/msg
|
||||
for(var/job in notbannedlist)
|
||||
@@ -1015,7 +1042,7 @@
|
||||
msg = job
|
||||
else
|
||||
msg += ", [job]"
|
||||
create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0)
|
||||
create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0, null, 0, severity)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] banned [key_name_admin(M)] from [msg].</span>")
|
||||
to_chat(M, "<span class='boldannounce'><BIG>You have been [(msg == ("ooc" || "appearance")) ? "banned" : "jobbanned"] by [usr.client.key] from: [msg].</BIG></span>")
|
||||
to_chat(M, "<span class='boldannounce'>The reason is: [reason]</span>")
|
||||
@@ -1140,6 +1167,24 @@
|
||||
var/message_id = href_list["editmessageempty"]
|
||||
edit_message(message_id, browse = 1)
|
||||
|
||||
else if(href_list["editmessageexpiry"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/message_id = href_list["editmessageexpiry"]
|
||||
edit_message_expiry(message_id)
|
||||
|
||||
else if(href_list["editmessageexpiryempty"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/message_id = href_list["editmessageexpiryempty"]
|
||||
edit_message_expiry(message_id, browse = 1)
|
||||
|
||||
else if(href_list["editmessageseverity"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/message_id = href_list["editmessageseverity"]
|
||||
edit_message_severity(message_id)
|
||||
|
||||
else if(href_list["secretmessage"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
@@ -1204,7 +1249,9 @@
|
||||
if(query_get_message_edits.NextRow())
|
||||
var/edit_log = query_get_message_edits.item[1]
|
||||
if(!QDELETED(usr))
|
||||
usr << browse(edit_log,"window=noteedits")
|
||||
var/datum/browser/browser = new(usr, "Note edits", "Note edits")
|
||||
browser.set_content(jointext(edit_log, ""))
|
||||
browser.open()
|
||||
qdel(query_get_message_edits)
|
||||
|
||||
else if(href_list["newban"])
|
||||
@@ -1365,10 +1412,10 @@
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "this can only be used on instances of type /mob.")
|
||||
|
||||
var/speech = input("What will [key_name(M)] say?.", "Force speech", "")// Don't need to sanitize, since it does that in say(), we also trust our admins.
|
||||
var/speech = input("What will [key_name(M)] say?", "Force speech", "")// Don't need to sanitize, since it does that in say(), we also trust our admins.
|
||||
if(!speech)
|
||||
return
|
||||
M.say(speech)
|
||||
M.say(speech, forced = "admin speech")
|
||||
speech = sanitize(speech) // Nah, we don't trust them
|
||||
log_admin("[key_name(usr)] forced [key_name(M)] to say: [speech]")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] forced [key_name_admin(M)] to say: [speech]</span>")
|
||||
|
||||
@@ -196,9 +196,10 @@
|
||||
|
||||
|
||||
/proc/SDQL_testout(list/query_tree, indent = 0)
|
||||
var/static/whitespace = " "
|
||||
var/spaces = ""
|
||||
for(var/s = 0, s < indent, s++)
|
||||
spaces += " "
|
||||
spaces += whitespace
|
||||
|
||||
for(var/item in query_tree)
|
||||
if(istype(item, /list))
|
||||
@@ -212,12 +213,12 @@
|
||||
if(!isnum(item) && query_tree[item])
|
||||
|
||||
if(istype(query_tree[item], /list))
|
||||
to_chat(usr, "[spaces] (")
|
||||
to_chat(usr, "[spaces][whitespace](")
|
||||
SDQL_testout(query_tree[item], indent + 2)
|
||||
to_chat(usr, "[spaces] )")
|
||||
to_chat(usr, "[spaces][whitespace])")
|
||||
|
||||
else
|
||||
to_chat(usr, "[spaces] [query_tree[item]]")
|
||||
to_chat(usr, "[spaces][whitespace][query_tree[item]]")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -294,8 +294,8 @@
|
||||
break
|
||||
parse_error("Expected ',' or ']' after array assoc value, but found '[token(i)]'")
|
||||
return i
|
||||
i++
|
||||
continue
|
||||
i++
|
||||
continue
|
||||
temp_expression_list = list()
|
||||
i = expression(i, temp_expression_list)
|
||||
while(token(i) && token(i) != "]")
|
||||
@@ -331,7 +331,7 @@
|
||||
//string: ''' <some text> ''' | '"' <some text > '"'
|
||||
/datum/SDQL_parser/proc/string(i, list/node)
|
||||
if(copytext(token(i), 1, 2) in list("'", "\""))
|
||||
node += copytext(token(i),2,-1)
|
||||
node += token(i)
|
||||
else
|
||||
parse_error("Expected string but found '[token(i)]'")
|
||||
return i + 1
|
||||
|
||||
@@ -372,7 +372,6 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
var/msg = "<font color='red' size='4'><b>- AdminHelp marked as IC issue! -</b></font><br>"
|
||||
msg += "<font color='red'><b>Losing is part of the game!</b></font><br>"
|
||||
msg += "<font color='red'>It is also possible that your ahelp is unable to be answered properly, due to events occurring in the round.</font>"
|
||||
|
||||
if(initiator)
|
||||
to_chat(initiator, msg)
|
||||
|
||||
@@ -607,7 +606,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
message["key"] = comms_key
|
||||
message += type
|
||||
|
||||
var/list/servers = CONFIG_GET(keyed_string_list/cross_server)
|
||||
var/list/servers = CONFIG_GET(keyed_list/cross_server)
|
||||
for(var/I in servers)
|
||||
world.Export("[servers[I]]?[list2params(message)]")
|
||||
|
||||
@@ -686,7 +685,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
var/is_antag = 0
|
||||
if(found.mind && found.mind.special_role)
|
||||
is_antag = 1
|
||||
founds += "Name: [found.name]([found.real_name]) Ckey: [found.key] [is_antag ? "(Antag)" : null] "
|
||||
founds += "Name: [found.name]([found.real_name]) Key: [found.key] Ckey: [found.ckey] [is_antag ? "(Antag)" : null] "
|
||||
msg += "[original_word]<font size='1' color='[is_antag ? "red" : "black"]'>(<A HREF='?_src_=holder;[HrefToken(TRUE)];adminmoreinfo=[REF(found)]'>?</A>|<A HREF='?_src_=holder;[HrefToken(TRUE)];adminplayerobservefollow=[REF(found)]'>F</A>)</font> "
|
||||
continue
|
||||
msg += "[original_word] "
|
||||
|
||||
@@ -66,9 +66,8 @@
|
||||
|
||||
if(src.mob)
|
||||
var/mob/A = src.mob
|
||||
A.x = tx
|
||||
A.y = ty
|
||||
A.z = tz
|
||||
var/turf/T = locate(tx,ty,tz)
|
||||
A.forceMove(T)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Coordiate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
message_admins("[key_name_admin(usr)] jumped to coordinates [tx], [ty], [tz]")
|
||||
|
||||
|
||||
@@ -9,16 +9,11 @@
|
||||
if(!msg)
|
||||
return
|
||||
|
||||
msg = emoji_parse(msg)
|
||||
mob.log_talk(msg, LOG_ASAY)
|
||||
|
||||
log_talk(mob,"[key_name(src)] : [msg]",LOGASAY)
|
||||
msg = keywords_lookup(msg)
|
||||
if(check_rights(R_ADMIN,0))
|
||||
msg = "<span class='admin'><span class='prefix'>ADMIN:</span> <EM>[key_name(usr, 1)]</EM> [ADMIN_FLW(mob)]: <span class='message linkify'>[msg]</span></span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
else
|
||||
msg = "<span class='adminobserver'><span class='prefix'>ADMIN:</span> <EM>[key_name(usr, 1)]</EM> [ADMIN_FLW(mob)]: <span class='message linkify'>[msg]</span></span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
msg = "<span class='adminsay'><span class='prefix'>ADMIN:</span> <EM>[key_name(usr, 1)]</EM> [ADMIN_FLW(mob)]: <span class='message linkify'>[msg]</span></span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Asay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
@@ -21,18 +21,17 @@
|
||||
var/mob/living/silicon/robot/borg
|
||||
var/user
|
||||
|
||||
/datum/borgpanel/New(user, mob/living/silicon/robot/borg)
|
||||
if(!istype(borg))
|
||||
/datum/borgpanel/New(to_user, mob/living/silicon/robot/to_borg)
|
||||
if(!istype(to_borg))
|
||||
CRASH("Borg panel is only available for borgs")
|
||||
qdel(src)
|
||||
if (istype(user, /mob))
|
||||
var/mob/M = user
|
||||
if (!M.client)
|
||||
CRASH("Borg panel attempted to open to a mob without a client")
|
||||
src.user = M.client
|
||||
else
|
||||
src.user = user
|
||||
src.borg = borg
|
||||
|
||||
user = CLIENT_FROM_VAR(to_user)
|
||||
|
||||
if (!user)
|
||||
CRASH("Borg panel attempted to open to a mob without a client")
|
||||
|
||||
borg = to_borg
|
||||
|
||||
/datum/borgpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/client/proc/dsay(msg as text)
|
||||
set category = "Special Verbs"
|
||||
set name = "Dsay" //Gave this shit a shorter name so you only have to time out "dsay" rather than "dead say" to use it --NeoFite
|
||||
set name = "Dsay"
|
||||
set hidden = 1
|
||||
if(!src.holder)
|
||||
to_chat(src, "Only administrators may use this command.")
|
||||
@@ -15,16 +15,13 @@
|
||||
return
|
||||
|
||||
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
log_talk(mob,"[key_name(src)] : [msg]",LOGDSAY)
|
||||
mob.log_talk(msg, LOG_DSAY)
|
||||
|
||||
if (!msg)
|
||||
return
|
||||
|
||||
msg = emoji_parse(msg)
|
||||
|
||||
var/static/nicknames = world.file2list("[global.config.directory]/admin_nicknames.txt")
|
||||
|
||||
var/rendered = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <span class='name'>[uppertext(holder.rank)]([src.holder.fakekey ? pick(nicknames) : src.key])</span> says, <span class='message'>\"[msg]\"</span></span>"
|
||||
var/rendered = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <span class='name'>[uppertext(holder.rank)]([src.holder.fakekey ? pick(nicknames) : src.key])</span> says, <span class='message'>\"[emoji_parse(msg)]\"</span></span>"
|
||||
|
||||
for (var/mob/M in GLOB.player_list)
|
||||
if(isnewplayer(M))
|
||||
|
||||
@@ -959,6 +959,50 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
to_chat(usr, "<span class='name'>[template.name]</span>")
|
||||
to_chat(usr, "<span class='italics'>[template.description]</span>")
|
||||
|
||||
/client/proc/place_ruin()
|
||||
set category = "Debug"
|
||||
set name = "Spawn Ruin"
|
||||
set desc = "Attempt to randomly place a specific ruin."
|
||||
if (!holder)
|
||||
return
|
||||
|
||||
var/list/exists = list()
|
||||
for(var/landmark in GLOB.ruin_landmarks)
|
||||
var/obj/effect/landmark/ruin/L = landmark
|
||||
exists[L.ruin_template] = landmark
|
||||
|
||||
var/list/names = list()
|
||||
names += "---- Space Ruins ----"
|
||||
for(var/name in SSmapping.space_ruins_templates)
|
||||
names[name] = list(SSmapping.space_ruins_templates[name], ZTRAIT_SPACE_RUINS, /area/space)
|
||||
names += "---- Lava Ruins ----"
|
||||
for(var/name in SSmapping.lava_ruins_templates)
|
||||
names[name] = list(SSmapping.lava_ruins_templates[name], ZTRAIT_LAVA_RUINS, /area/lavaland/surface/outdoors/unexplored)
|
||||
|
||||
var/ruinname = input("Select ruin", "Spawn Ruin") as null|anything in names
|
||||
var/data = names[ruinname]
|
||||
if (!data)
|
||||
return
|
||||
var/datum/map_template/ruin/template = data[1]
|
||||
if (exists[template])
|
||||
var/response = alert("There is already a [template] in existence.", "Spawn Ruin", "Jump", "Place Another", "Cancel")
|
||||
if (response == "Jump")
|
||||
usr.forceMove(get_turf(exists[template]))
|
||||
return
|
||||
else if (response == "Cancel")
|
||||
return
|
||||
|
||||
var/len = GLOB.ruin_landmarks.len
|
||||
seedRuins(SSmapping.levels_by_trait(data[2]), max(1, template.cost), data[3], list(ruinname = template))
|
||||
if (GLOB.ruin_landmarks.len > len)
|
||||
var/obj/effect/landmark/ruin/landmark = GLOB.ruin_landmarks[GLOB.ruin_landmarks.len]
|
||||
log_admin("[key_name(src)] randomly spawned ruin [ruinname] at [COORD(landmark)].")
|
||||
usr.forceMove(get_turf(landmark))
|
||||
to_chat(src, "<span class='name'>[template.name]</span>")
|
||||
to_chat(src, "<span class='italics'>[template.description]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='warning'>Failed to place [template.name].</span>")
|
||||
|
||||
/client/proc/clear_dynamic_transit()
|
||||
set category = "Debug"
|
||||
set name = "Clear Dynamic Turf Reservations"
|
||||
@@ -1047,3 +1091,12 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
return
|
||||
sort = sortlist[sort]
|
||||
profile_show(src, sort)
|
||||
|
||||
/client/proc/reload_configuration()
|
||||
set category = "Debug"
|
||||
set name = "Reload Configuration"
|
||||
set desc = "Force config reload to world default"
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
if(alert(usr, "Are you absolutely sure you want to reload the configuration from the default path on the disk, wiping any in-round modificatoins?", "Really reset?", "No", "Yes") == "Yes")
|
||||
config.admin_reload()
|
||||
|
||||
@@ -1,29 +1,45 @@
|
||||
/proc/show_individual_logging_panel(mob/M, source = LOGSRC_CLIENT, type = INDIVIDUAL_ATTACK_LOG)
|
||||
if(!M || !ismob(M))
|
||||
return
|
||||
|
||||
|
||||
var/ntype = text2num(type)
|
||||
|
||||
//Add client links
|
||||
var/dat = ""
|
||||
if(M.client)
|
||||
dat += "<center><p>Client</p></center>"
|
||||
dat += "<center><a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_ATTACK_LOG];log_src=[LOGSRC_CLIENT]'>Attack log</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_SAY_LOG];log_src=[LOGSRC_CLIENT]'>Say log</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_EMOTE_LOG];log_src=[LOGSRC_CLIENT]'>Emote log</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_OOC_LOG];log_src=[LOGSRC_CLIENT]'>OOC log</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_SHOW_ALL_LOG];log_src=[LOGSRC_CLIENT]'>Show all</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[type];log_src=[LOGSRC_CLIENT]'>Refresh</a></center>"
|
||||
if(M.client)
|
||||
dat += "<center><p>Client</p></center>"
|
||||
dat += "<center>"
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_ATTACK_LOG, LOGSRC_CLIENT, "Attack Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_SAY_LOG, LOGSRC_CLIENT, "Say Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_EMOTE_LOG, LOGSRC_CLIENT, "Emote Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_COMMS_LOG, LOGSRC_CLIENT, "Comms Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_OOC_LOG, LOGSRC_CLIENT, "OOC Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_SHOW_ALL_LOG, LOGSRC_CLIENT, "Show All", source, ntype)
|
||||
dat += "</center>"
|
||||
else
|
||||
dat += "<p> No client attached to mob </p>"
|
||||
|
||||
dat += "<hr style='background:#000000; border:0; height:1px'>"
|
||||
dat += "<center><p>Mob</p></center>"
|
||||
dat += "<center><p>Mob</p></center>"
|
||||
//Add the links for the mob specific log
|
||||
dat += "<center><a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_ATTACK_LOG];log_src=[LOGSRC_MOB]'>Attack log</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_SAY_LOG];log_src=[LOGSRC_MOB]'>Say log</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_EMOTE_LOG];log_src=[LOGSRC_MOB]'>Emote log</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_OOC_LOG];log_src=[LOGSRC_MOB]'>OOC log</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[INDIVIDUAL_SHOW_ALL_LOG];log_src=[LOGSRC_MOB]'>Show all</a> | "
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[type];log_src=[LOGSRC_MOB]'>Refresh</a></center>"
|
||||
dat += "<center>"
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_ATTACK_LOG, LOGSRC_MOB, "Attack Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_SAY_LOG, LOGSRC_MOB, "Say Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_EMOTE_LOG, LOGSRC_MOB, "Emote Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_COMMS_LOG, LOGSRC_MOB, "Comms Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_OOC_LOG, LOGSRC_MOB, "OOC Log", source, ntype)
|
||||
dat += " | "
|
||||
dat += individual_logging_panel_link(M, INDIVIDUAL_SHOW_ALL_LOG, LOGSRC_MOB, "Show All", source, ntype)
|
||||
dat += "</center>"
|
||||
|
||||
dat += "<hr style='background:#000000; border:0; height:1px'>"
|
||||
|
||||
@@ -31,22 +47,21 @@
|
||||
if(source == LOGSRC_CLIENT && M.client) //if client doesn't exist just fall back to the mob log
|
||||
log_source = M.client.player_details.logging //should exist, if it doesn't that's a bug, don't check for it not existing
|
||||
|
||||
if(type == INDIVIDUAL_SHOW_ALL_LOG)
|
||||
dat += "<center>Displaying all [source] logs of [key_name(M)]</center><br><hr>"
|
||||
for(var/log_type in log_source)
|
||||
dat += "<center><b>[log_type]</b></center><br>"
|
||||
for(var/log_type in log_source)
|
||||
var/nlog_type = text2num(log_type)
|
||||
if(nlog_type & ntype)
|
||||
var/list/reversed = log_source[log_type]
|
||||
if(islist(reversed))
|
||||
reversed = reverseRange(reversed.Copy())
|
||||
for(var/entry in reversed)
|
||||
dat += "<font size=2px>[entry]: [reversed[entry]]</font><br>"
|
||||
dat += "<font size=2px><b>[entry]</b><br>[reversed[entry]]</font><br>"
|
||||
dat += "<hr>"
|
||||
else
|
||||
dat += "<center>[source] [type] of [key_name(M)]</center><br>"
|
||||
var/list/reversed = log_source[type]
|
||||
if(reversed)
|
||||
reversed = reverseRange(reversed.Copy())
|
||||
for(var/entry in reversed)
|
||||
dat += "<font size=2px>[entry]: [reversed[entry]]</font><hr>"
|
||||
|
||||
usr << browse(dat, "window=invidual_logging_[key_name(M)];size=600x480")
|
||||
|
||||
/proc/individual_logging_panel_link(mob/M, log_type, log_src, label, selected_src, selected_type)
|
||||
var/slabel = label
|
||||
if(selected_type == log_type && selected_src == log_src)
|
||||
slabel = "<b>\[[label]\]</b>"
|
||||
|
||||
return "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[log_type];log_src=[log_src]'>[slabel]</a>"
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
var/datum/map_template/template
|
||||
|
||||
var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in SSmapping.map_templates
|
||||
var/map = input(src, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in SSmapping.map_templates
|
||||
if(!map)
|
||||
return
|
||||
template = SSmapping.map_templates[map]
|
||||
@@ -18,35 +18,50 @@
|
||||
var/image/item = image('icons/turf/overlays.dmi',S,"greenOverlay")
|
||||
item.plane = ABOVE_LIGHTING_PLANE
|
||||
preview += item
|
||||
usr.client.images += preview
|
||||
if(alert(usr,"Confirm location.","Template Confirm","Yes","No") == "Yes")
|
||||
images += preview
|
||||
if(alert(src,"Confirm location.","Template Confirm","Yes","No") == "Yes")
|
||||
if(template.load(T, centered = TRUE))
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has placed a map template ([template.name]) at [ADMIN_COORDJMP(T)]</span>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] has placed a map template ([template.name]) at [ADMIN_COORDJMP(T)]</span>")
|
||||
else
|
||||
to_chat(usr, "Failed to place map")
|
||||
usr.client.images -= preview
|
||||
to_chat(src, "Failed to place map")
|
||||
images -= preview
|
||||
|
||||
/client/proc/map_template_upload()
|
||||
set category = "Debug"
|
||||
set name = "Map Template - Upload"
|
||||
|
||||
var/map = input(usr, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file
|
||||
var/map = input(src, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file
|
||||
if(!map)
|
||||
return
|
||||
if(copytext("[map]",-4) != ".dmm")
|
||||
to_chat(usr, "Bad map file: [map]")
|
||||
to_chat(src, "<span class='warning'>Filename must end in '.dmm': [map]</span>")
|
||||
return
|
||||
var/datum/map_template/M
|
||||
switch(alert(usr, "What kind of map is this?", "Map type", "Normal", "Shuttle", "Cancel"))
|
||||
switch(alert(src, "What kind of map is this?", "Map type", "Normal", "Shuttle", "Cancel"))
|
||||
if("Normal")
|
||||
M = new /datum/map_template(map, "[map]")
|
||||
M = new /datum/map_template(map, "[map]", TRUE)
|
||||
if("Shuttle")
|
||||
M = new /datum/map_template/shuttle(map, "[map]")
|
||||
M = new /datum/map_template/shuttle(map, "[map]", TRUE)
|
||||
else
|
||||
return
|
||||
if(M.preload_size(map))
|
||||
to_chat(usr, "Map template '[map]' ready to place ([M.width]x[M.height])")
|
||||
SSmapping.map_templates[M.name] = M
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has uploaded a map template ([map])</span>")
|
||||
else
|
||||
to_chat(usr, "Map template '[map]' failed to load properly")
|
||||
if(!M.cached_map)
|
||||
to_chat(src, "<span class='warning'>Map template '[map]' failed to parse properly.</span>")
|
||||
return
|
||||
|
||||
var/datum/map_report/report = M.cached_map.check_for_errors()
|
||||
var/report_link
|
||||
if(report)
|
||||
report.show_to(src)
|
||||
report_link = " - <a href='?src=[REF(report)];[HrefToken(TRUE)];show=1'>validation report</a>"
|
||||
to_chat(src, "<span class='warning'>Map template '[map]' <a href='?src=[REF(report)];[HrefToken()];show=1'>failed validation</a>.</span>")
|
||||
if(report.loadable)
|
||||
var/response = alert(src, "The map failed validation, would you like to load it anyways?", "Map Errors", "Cancel", "Upload Anyways")
|
||||
if(response != "Upload Anyways")
|
||||
return
|
||||
else
|
||||
alert(src, "The map failed validation and cannot be loaded.", "Map Errors", "Oh Darn")
|
||||
return
|
||||
|
||||
SSmapping.map_templates[M.name] = M
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] has uploaded a map template '[map]' ([M.width]x[M.height])[report_link].</span>")
|
||||
to_chat(src, "<span class='notice'>Map template '[map]' ready to place ([M.width]x[M.height])</span>")
|
||||
|
||||
@@ -47,7 +47,8 @@ GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list(
|
||||
/client/proc/stop_line_profiling,
|
||||
/client/proc/show_line_profiling,
|
||||
/client/proc/create_mapping_job_icons,
|
||||
/client/proc/debug_z_levels
|
||||
/client/proc/debug_z_levels,
|
||||
/client/proc/place_ruin
|
||||
))
|
||||
|
||||
/obj/effect/debugging/mapfix_marker
|
||||
|
||||
@@ -629,9 +629,11 @@ GLOBAL_PROTECT(VVpixelmovement)
|
||||
if (O.vv_edit_var(variable, var_new) == FALSE)
|
||||
to_chat(src, "Your edit was rejected by the object.")
|
||||
return
|
||||
vv_update_display(O, "varedited", VV_MSG_EDITED)
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_VAR_EDIT, args)
|
||||
log_world("### VarEdit by [key_name(src)]: [O.type] [variable]=[var_value] => [var_new]")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [variable] from [html_encode("[var_value]")] to [html_encode("[var_new]")]")
|
||||
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] from [var_value] to [var_new]"
|
||||
message_admins(msg)
|
||||
admin_ticket_log(O, msg)
|
||||
return TRUE
|
||||
|
||||
@@ -351,7 +351,7 @@
|
||||
"template" = list("desc" = "Template", "callback" = CALLBACK(src, .proc/makeERTTemplateModified), "type" = "datum", "path" = "/datum/ert", "subtypesonly" = TRUE, "value" = ertemplate.type),
|
||||
"teamsize" = list("desc" = "Team Size", "type" = "number", "value" = ertemplate.teamsize),
|
||||
"mission" = list("desc" = "Mission", "type" = "string", "value" = ertemplate.mission),
|
||||
"polldesc" = list("desc" = "Ghost poll description", "string" = "text", "value" = ertemplate.polldesc),
|
||||
"polldesc" = list("desc" = "Ghost poll description", "type" = "string", "value" = ertemplate.polldesc),
|
||||
"enforce_human" = list("desc" = "Enforce human authority", "type" = "boolean", "value" = "[(CONFIG_GET(flag/enforce_human_authority) ? "Yes" : "No")]"),
|
||||
"open_armory" = list("desc" = "Open armory doors", "type" = "boolean", "value" = "[(ertemplate.opendoors ? "Yes" : "No")]"),
|
||||
)
|
||||
|
||||
@@ -31,23 +31,24 @@
|
||||
cross.icon_state = "tome"
|
||||
font_color = "red"
|
||||
prayer_type = "CULTIST PRAYER"
|
||||
deity = "Nar-Sie"
|
||||
deity = "Nar'Sie"
|
||||
else if(isliving(usr))
|
||||
var/mob/living/L = usr
|
||||
if(L.has_trait(TRAIT_SPIRITUAL))
|
||||
cross.icon_state = "holylight"
|
||||
font_color = "blue"
|
||||
prayer_type = "SPIRITUAL PRAYER"
|
||||
|
||||
|
||||
var/msg_tmp = msg
|
||||
msg = "<span class='adminnotice'>[icon2html(cross, GLOB.admins)]<b><font color=[font_color]>[prayer_type][deity ? " (to [deity])" : ""]: </font>[ADMIN_FULLMONTY(src)] [ADMIN_SC(src)]:</b> <span class='linkify'>[msg]</span></span>"
|
||||
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(C.prefs.chat_toggles & CHAT_PRAYER)
|
||||
to_chat(C, msg)
|
||||
if(C.prefs.toggles & SOUND_PRAYERS)
|
||||
if(usr.job == "Chaplain")
|
||||
SEND_SOUND(C, sound('sound/effects/pray.ogg'))
|
||||
to_chat(usr, "Your prayers have been received by the gods.")
|
||||
to_chat(usr, "<span class='info'>You pray to the gods: \"[msg_tmp]\"</span>")
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Prayer") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
//log_admin("HELP: [key_name(src)]: [msg]")
|
||||
|
||||
@@ -48,12 +48,12 @@
|
||||
/client/proc/cmd_admin_headset_message(mob/M in GLOB.mob_list)
|
||||
set category = "Special Verbs"
|
||||
set name = "Headset Message"
|
||||
|
||||
|
||||
admin_headset_message(M)
|
||||
|
||||
/client/proc/admin_headset_message(mob/M in GLOB.mob_list, sender = null)
|
||||
var/mob/living/carbon/human/H = M
|
||||
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
message_admins("[key_name_admin(src)] decided not to answer [key_name_admin(H)]'s [sender] request.")
|
||||
return
|
||||
|
||||
log_admin("[key_name(src)] replied to [key_name(H)]'s [sender] message with the message [input].")
|
||||
log_directed_talk(src, H, input, LOG_ADMIN, "reply")
|
||||
message_admins("[key_name_admin(src)] replied to [key_name_admin(H)]'s [sender] message with: \"[input]\"")
|
||||
to_chat(H, "You hear something crackle in your ears for a moment before a voice speaks. \"Please stand by for a message from [sender == "Syndicate" ? "your benefactor" : "Central Command"]. Message as follows[sender == "Syndicate" ? ", agent." : ":"] <span class='bold'>[input].</span> Message ends.\"")
|
||||
|
||||
@@ -596,16 +596,28 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
|
||||
/client/proc/admin_delete(datum/D)
|
||||
var/atom/A = D
|
||||
var/coords = istype(A) ? " at ([A.x], [A.y], [A.z])" : ""
|
||||
if (alert(src, "Are you sure you want to delete:\n[D]\nat[coords]?", "Confirmation", "Yes", "No") == "Yes")
|
||||
log_admin("[key_name(usr)] deleted [D][coords]")
|
||||
message_admins("[key_name_admin(usr)] deleted [D][coords]")
|
||||
var/coords = ""
|
||||
var/jmp_coords = ""
|
||||
if(istype(A))
|
||||
var/turf/T = get_turf(A)
|
||||
if(T)
|
||||
coords = "at [COORD(T)]"
|
||||
jmp_coords = "at [ADMIN_COORDJMP(T)]"
|
||||
else
|
||||
jmp_coords = coords = "in nullspace"
|
||||
|
||||
if (alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", "Yes", "No") == "Yes")
|
||||
log_admin("[key_name(usr)] deleted [D] [coords]")
|
||||
message_admins("[key_name_admin(usr)] deleted [D] [jmp_coords]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
if(isturf(D))
|
||||
var/turf/T = D
|
||||
T.ScrapeAway()
|
||||
else
|
||||
vv_update_display(D, "deleted", VV_MSG_DELETED)
|
||||
qdel(D)
|
||||
if(!QDELETED(D))
|
||||
vv_update_display(D, "deleted", "")
|
||||
|
||||
/client/proc/cmd_admin_list_open_jobs()
|
||||
set category = "Admin"
|
||||
@@ -1117,7 +1129,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
return
|
||||
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
new /obj/item/organ/zombie_infection(H)
|
||||
new /obj/item/organ/zombie_infection/nodamage(H)
|
||||
|
||||
message_admins("[key_name_admin(usr)] added a latent zombie infection to all humans.")
|
||||
log_admin("[key_name(usr)] added a latent zombie infection to all humans.")
|
||||
@@ -1134,7 +1146,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
if(confirm != "Yes")
|
||||
return
|
||||
|
||||
for(var/obj/item/organ/zombie_infection/I in GLOB.zombie_infection_list)
|
||||
for(var/obj/item/organ/zombie_infection/nodamage/I in GLOB.zombie_infection_list)
|
||||
qdel(I)
|
||||
|
||||
message_admins("[key_name_admin(usr)] cured all zombies.")
|
||||
@@ -1201,82 +1213,6 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
log_admin("[key_name(usr)] sent \"[input]\" as the Tip of the Round.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Tip")
|
||||
|
||||
/proc/mass_purrbation()
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(ishumanbasic(M))
|
||||
purrbation_apply(M)
|
||||
CHECK_TICK
|
||||
|
||||
/proc/mass_remove_purrbation()
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(ishumanbasic(M))
|
||||
purrbation_remove(M)
|
||||
CHECK_TICK
|
||||
|
||||
/proc/purrbation_toggle(mob/living/carbon/human/H, silent = FALSE)
|
||||
if(!ishumanbasic(H))
|
||||
return
|
||||
if(!iscatperson(H))
|
||||
purrbation_apply(H, silent)
|
||||
. = TRUE
|
||||
else
|
||||
purrbation_remove(H, silent)
|
||||
. = FALSE
|
||||
|
||||
/proc/purrbation_apply(mob/living/carbon/human/H, silent = FALSE)
|
||||
if(!ishuman(H))
|
||||
return
|
||||
if(iscatperson(H))
|
||||
return
|
||||
|
||||
var/obj/item/organ/ears/cat/ears = new
|
||||
var/obj/item/organ/tail/cat/tail = new
|
||||
ears.Insert(H, drop_if_replaced=FALSE)
|
||||
tail.Insert(H, drop_if_replaced=FALSE)
|
||||
|
||||
if(!silent)
|
||||
to_chat(H, "Something is nya~t right.")
|
||||
playsound(get_turf(H), 'sound/effects/meow1.ogg', 50, 1, -1)
|
||||
|
||||
/proc/purrbation_remove(mob/living/carbon/human/H, silent = FALSE)
|
||||
if(!ishuman(H))
|
||||
return
|
||||
if(!iscatperson(H))
|
||||
return
|
||||
|
||||
var/obj/item/organ/ears/cat/ears = H.getorgan(/obj/item/organ/ears/cat)
|
||||
var/obj/item/organ/tail/cat/tail = H.getorgan(/obj/item/organ/tail/cat)
|
||||
|
||||
if(ears)
|
||||
var/obj/item/organ/ears/NE
|
||||
if(H.dna.species && H.dna.species.mutantears)
|
||||
// Roundstart cat ears override H.dna.species.mutantears, reset it here.
|
||||
H.dna.species.mutantears = initial(H.dna.species.mutantears)
|
||||
if(H.dna.species.mutantears)
|
||||
NE = new H.dna.species.mutantears()
|
||||
|
||||
if(!NE)
|
||||
// Go with default ears
|
||||
NE = new /obj/item/organ/ears()
|
||||
|
||||
NE.Insert(H, drop_if_replaced = FALSE)
|
||||
|
||||
if(tail)
|
||||
var/obj/item/organ/tail/NT
|
||||
if(H.dna.species && H.dna.species.mutanttail)
|
||||
// Roundstart cat tail overrides H.dna.species.mutanttail, reset it here.
|
||||
H.dna.species.mutanttail = initial(H.dna.species.mutanttail)
|
||||
if(H.dna.species.mutanttail)
|
||||
NT = new H.dna.species.mutanttail()
|
||||
|
||||
if(NT)
|
||||
NT.Insert(H, drop_if_replaced = FALSE)
|
||||
else
|
||||
tail.Remove(H)
|
||||
|
||||
if(!silent)
|
||||
to_chat(H, "You are no longer a cat.")
|
||||
|
||||
/client/proc/modify_goals()
|
||||
set category = "Debug"
|
||||
set name = "Modify goals"
|
||||
@@ -1310,7 +1246,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
/client/proc/smite(mob/living/carbon/human/target as mob)
|
||||
set name = "Smite"
|
||||
set category = "Fun"
|
||||
if(!check_rights(R_ADMIN))
|
||||
if(!check_rights(R_ADMIN) || !check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_ROD, ADMIN_PUNISHMENT_SUPPLYPOD, ADMIN_PUNISHMENT_MAZING)
|
||||
|
||||
@@ -14,7 +14,8 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/list/objectives = list()
|
||||
var/antag_memory = ""//These will be removed with antag datum
|
||||
var/antag_moodlet //typepath of moodlet that the mob will gain with their status
|
||||
|
||||
var/can_hijack = HIJACK_NEUTRAL //If these antags are alone on shuttle hijack happens.
|
||||
|
||||
//Antag panel properties
|
||||
var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
|
||||
var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
//////SYNDICATE BORG
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele
|
||||
name = "syndicate cyborg teleporter"
|
||||
desc = "A single-use teleporter designed to quickly reinforce operatives in the field.."
|
||||
desc = "A single-use teleporter designed to quickly reinforce operatives in the field."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "locator"
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@
|
||||
|
||||
|
||||
/obj/item/abductor/gizmo/afterattack(atom/target, mob/living/user, flag, params)
|
||||
. = ..()
|
||||
if(flag)
|
||||
return
|
||||
if(!ScientistCheck(user))
|
||||
@@ -251,6 +252,7 @@
|
||||
radio_off(M, user)
|
||||
|
||||
/obj/item/abductor/silencer/afterattack(atom/target, mob/living/user, flag, params)
|
||||
. = ..()
|
||||
if(flag)
|
||||
return
|
||||
if(!AbductorCheck(user))
|
||||
@@ -303,6 +305,7 @@
|
||||
to_chat(user, "<span class='notice'>You switch the device to [mode==MIND_DEVICE_MESSAGE? "TRANSMISSION": "COMMAND"] MODE</span>")
|
||||
|
||||
/obj/item/abductor/mind_device/afterattack(atom/target, mob/living/user, flag, params)
|
||||
. = ..()
|
||||
if(!ScientistCheck(user))
|
||||
return
|
||||
|
||||
@@ -359,7 +362,7 @@
|
||||
|
||||
to_chat(L, "<span class='italics'>You hear a voice in your head saying: </span><span class='abductor'>[message]</span>")
|
||||
to_chat(user, "<span class='notice'>You send the message to your target.</span>")
|
||||
log_talk(user,"[key_name(user)] sent an abductor mind message to [key_name(L)]: '[message]'", LOGSAY)
|
||||
log_directed_talk(user, L, message, LOG_SAY, "abductor whisper")
|
||||
|
||||
|
||||
/obj/item/firing_pin/abductor
|
||||
@@ -512,7 +515,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
var/mob/living/carbon/human/H = L
|
||||
H.forcesay(GLOB.hit_appends)
|
||||
|
||||
add_logs(user, L, "stunned")
|
||||
log_combat(user, L, "stunned")
|
||||
|
||||
/obj/item/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user)
|
||||
if(L.incapacitated(TRUE, TRUE))
|
||||
@@ -526,7 +529,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
"<span class='userdanger'>You suddenly feel very drowsy!</span>")
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
|
||||
L.Sleeping(1200)
|
||||
add_logs(user, L, "put to sleep")
|
||||
log_combat(user, L, "put to sleep")
|
||||
else
|
||||
if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
|
||||
to_chat(user, "<span class='warning'>The specimen's protective headgear is completely blocking our sleep inducement methods!</span>")
|
||||
@@ -543,16 +546,16 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
return
|
||||
var/mob/living/carbon/C = L
|
||||
if(!C.handcuffed)
|
||||
if(C.get_num_arms() >= 2 || C.get_arm_ignore())
|
||||
if(C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore())
|
||||
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
|
||||
C.visible_message("<span class='danger'>[user] begins restraining [C] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] begins shaping an energy field around your hands!</span>")
|
||||
if(do_mob(user, C, 30) && (C.get_num_arms() >= 2 || C.get_arm_ignore()))
|
||||
if(do_mob(user, C, 30) && (C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore()))
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/restraints/handcuffs/energy/used(C)
|
||||
C.update_handcuffed()
|
||||
to_chat(user, "<span class='notice'>You restrain [C].</span>")
|
||||
add_logs(user, C, "handcuffed")
|
||||
log_combat(user, C, "handcuffed")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You fail to restrain [C].</span>")
|
||||
else
|
||||
|
||||
@@ -213,6 +213,7 @@
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
hud_type = /datum/hud/blobbernaut
|
||||
var/independent = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/Initialize()
|
||||
|
||||
@@ -21,6 +21,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
faction = list(ROLE_BLOB)
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
call_life = TRUE
|
||||
hud_type = /datum/hud/blob_overmind
|
||||
var/obj/structure/blob/core/blob_core = null // The blob overmind's core
|
||||
var/blob_points = 0
|
||||
var/max_blob_points = 100
|
||||
@@ -184,7 +185,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
blob_points = CLAMP(blob_points + points, 0, max_blob_points)
|
||||
hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_points)]</font></div>"
|
||||
|
||||
/mob/camera/blob/say(message)
|
||||
/mob/camera/blob/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
if (!message)
|
||||
return
|
||||
|
||||
@@ -207,7 +208,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
if (!message)
|
||||
return
|
||||
|
||||
log_talk(src,"[key_name(src)] : [message]",LOGSAY)
|
||||
src.log_talk(message, LOG_SAY)
|
||||
|
||||
var/message_a = say_quote(message, get_spans())
|
||||
var/rendered = "<span class='big'><font color=\"#EE4000\"><b>\[Blob Telepathy\] [name](<font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</font>)</b> [message_a]</font></span>"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
var/special_role = ROLE_BROTHER
|
||||
var/datum/team/brother_team/team
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
|
||||
if(!new_team)
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
to_chat(owner.current, "We have reached our capacity for abilities.")
|
||||
return
|
||||
|
||||
if(owner.current.has_trait(TRAIT_FAKEDEATH))//To avoid potential exploits by buying new powers while in stasis, which clears your verblist.
|
||||
if(owner.current.has_trait(TRAIT_DEATHCOMA))//To avoid potential exploits by buying new powers while in stasis, which clears your verblist.
|
||||
to_chat(owner.current, "We lack the energy to evolve new abilities right now.")
|
||||
return
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
if(req_stat < user.stat)
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
if((user.has_trait(TRAIT_FAKEDEATH)) && (!ignores_fakedeath))
|
||||
if((user.has_trait(TRAIT_DEATHCOMA)) && (!ignores_fakedeath))
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
//Recent as opposed to all because rounds tend to have a LOT of text.
|
||||
var/list/recent_speech = list()
|
||||
|
||||
var/list/say_log = target.logging[INDIVIDUAL_SAY_LOG]
|
||||
var/list/say_log = target.logging[LOG_SAY]
|
||||
|
||||
if(LAZYLEN(say_log) > LING_ABSORB_RECENT_SPEECH)
|
||||
recent_speech = say_log.Copy(say_log.len-LING_ABSORB_RECENT_SPEECH+1,0) //0 so len-LING_ARS+1 to end of list
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
dna_cost = 0
|
||||
req_dna = 1
|
||||
req_stat = DEAD
|
||||
ignores_fakedeath = TRUE
|
||||
|
||||
//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay.
|
||||
/obj/effect/proc_holder/changeling/fakedeath/sting_action(mob/living/user)
|
||||
@@ -27,7 +28,7 @@
|
||||
C.purchasedpowers += new /obj/effect/proc_holder/changeling/revive(null)
|
||||
|
||||
/obj/effect/proc_holder/changeling/fakedeath/can_sting(mob/living/user)
|
||||
if(user.has_trait(TRAIT_FAKEDEATH, "changeling"))
|
||||
if(user.has_trait(TRAIT_DEATHCOMA, "changeling"))
|
||||
to_chat(user, "<span class='warning'>We are already reviving.</span>")
|
||||
return
|
||||
if(!user.stat) //Confirmation for living changelings if they want to fake their death
|
||||
|
||||
@@ -159,6 +159,7 @@
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
sharpness = IS_SHARP
|
||||
var/can_drop = FALSE
|
||||
var/fake = FALSE
|
||||
|
||||
/obj/item/melee/arm_blade/Initialize(mapload,silent,synthetic)
|
||||
. = ..()
|
||||
@@ -169,6 +170,7 @@
|
||||
AddComponent(/datum/component/butchering, 60, 80)
|
||||
|
||||
/obj/item/melee/arm_blade/afterattack(atom/target, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
if(istype(target, /obj/structure/table))
|
||||
@@ -236,6 +238,7 @@
|
||||
fire_sound = 'sound/effects/splat.ogg'
|
||||
force = 0
|
||||
max_charges = 1
|
||||
fire_delay = 1
|
||||
throwforce = 0 //Just to be on the safe side
|
||||
throw_range = 0
|
||||
throw_speed = 0
|
||||
@@ -252,6 +255,11 @@
|
||||
/obj/item/gun/magic/tentacle/shoot_with_empty_chamber(mob/living/user as mob|obj)
|
||||
to_chat(user, "<span class='warning'>The [name] is not ready yet.</span>")
|
||||
|
||||
/obj/item/gun/magic/tentacle/process_chamber()
|
||||
. = ..()
|
||||
if(charges == 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/gun/magic/tentacle/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] coils [src] tightly around [user.p_their()] neck! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (OXYLOSS)
|
||||
@@ -300,8 +308,12 @@
|
||||
|
||||
/obj/item/projectile/tentacle/proc/tentacle_grab(mob/living/carbon/human/H, mob/living/carbon/C)
|
||||
if(H.Adjacent(C))
|
||||
if(H.get_active_held_item() && !H.get_inactive_held_item())
|
||||
H.swap_hand()
|
||||
if(H.get_active_held_item())
|
||||
return
|
||||
C.grabbedby(H)
|
||||
C.grippedby(H) //instant aggro grab
|
||||
C.grippedby(H, instant = TRUE) //instant aggro grab
|
||||
|
||||
/obj/item/projectile/tentacle/proc/tentacle_stab(mob/living/carbon/human/H, mob/living/carbon/C)
|
||||
if(H.Adjacent(C))
|
||||
@@ -316,7 +328,6 @@
|
||||
|
||||
/obj/item/projectile/tentacle/on_hit(atom/target, blocked = FALSE)
|
||||
var/mob/living/carbon/human/H = firer
|
||||
H.dropItemToGround(source.gun, TRUE) //Unequip thus delete the tentacle on hit
|
||||
if(blocked >= 100)
|
||||
return 0
|
||||
if(isitem(target))
|
||||
@@ -332,7 +343,11 @@
|
||||
if(!L.anchored && !L.throwing)//avoid double hits
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
switch(firer.a_intent)
|
||||
var/firer_intent = INTENT_HARM
|
||||
var/mob/M = firer
|
||||
if(istype(M))
|
||||
firer_intent = M.a_intent
|
||||
switch(firer_intent)
|
||||
if(INTENT_HELP)
|
||||
C.visible_message("<span class='danger'>[L] is pulled by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
|
||||
C.throw_at(get_step_towards(H,C), 8, 2)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(user.has_trait(CHANGELING_DRAIN) || ((user.stat != DEAD) && !(user.has_trait(TRAIT_FAKEDEATH))))
|
||||
if(user.has_trait(CHANGELING_DRAIN) || ((user.stat != DEAD) && !(user.has_trait(TRAIT_DEATHCOMA))))
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.purchasedpowers -= src
|
||||
return FALSE
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/sting_action(mob/user, mob/target)
|
||||
add_logs(user, target, "stung", "transformation sting", " new identity is [selected_dna.dna.real_name]")
|
||||
log_combat(user, target, "stung", "transformation sting", " new identity is '[selected_dna.dna.real_name]'")
|
||||
var/datum/dna/NewDNA = selected_dna.dna
|
||||
if(ismonkey(target))
|
||||
to_chat(user, "<span class='notice'>Our genes cry out as we sting [target.name]!</span>")
|
||||
@@ -119,9 +119,7 @@
|
||||
/obj/item/melee/arm_blade/false
|
||||
desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless."
|
||||
force = 5 //Basically as strong as a punch
|
||||
|
||||
/obj/item/melee/arm_blade/false/afterattack(atom/target, mob/user, proximity)
|
||||
return
|
||||
fake = TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/can_sting(mob/user, mob/target)
|
||||
if(!..())
|
||||
@@ -134,7 +132,7 @@
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/sting_action(mob/user, mob/target)
|
||||
add_logs(user, target, "stung", object="false armblade sting")
|
||||
log_combat(user, target, "stung", object="false armblade sting")
|
||||
|
||||
var/obj/item/held = target.get_active_held_item()
|
||||
if(held && !target.dropItemToGround(held))
|
||||
@@ -176,7 +174,7 @@
|
||||
return changeling.can_absorb_dna(target)
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna/sting_action(mob/user, mob/living/carbon/human/target)
|
||||
add_logs(user, target, "stung", "extraction sting")
|
||||
log_combat(user, target, "stung", "extraction sting")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!(changeling.has_dna(target.dna)))
|
||||
changeling.add_new_profile(target)
|
||||
@@ -191,7 +189,7 @@
|
||||
dna_cost = 2
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/mute/sting_action(mob/user, mob/living/carbon/target)
|
||||
add_logs(user, target, "stung", "mute sting")
|
||||
log_combat(user, target, "stung", "mute sting")
|
||||
target.silent += 30
|
||||
return TRUE
|
||||
|
||||
@@ -204,7 +202,7 @@
|
||||
dna_cost = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/blind/sting_action(mob/user, mob/living/carbon/target)
|
||||
add_logs(user, target, "stung", "blind sting")
|
||||
log_combat(user, target, "stung", "blind sting")
|
||||
to_chat(target, "<span class='danger'>Your eyes burn horrifically!</span>")
|
||||
target.become_nearsighted(EYE_DAMAGE)
|
||||
target.blind_eyes(20)
|
||||
@@ -220,7 +218,7 @@
|
||||
dna_cost = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/living/carbon/target)
|
||||
add_logs(user, target, "stung", "LSD sting")
|
||||
log_combat(user, target, "stung", "LSD sting")
|
||||
addtimer(CALLBACK(src, .proc/hallucination_time, target), rand(100,200))
|
||||
return TRUE
|
||||
|
||||
@@ -237,7 +235,7 @@
|
||||
dna_cost = 2
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/cryo/sting_action(mob/user, mob/target)
|
||||
add_logs(user, target, "stung", "cryo sting")
|
||||
log_combat(user, target, "stung", "cryo sting")
|
||||
if(target.reagents)
|
||||
target.reagents.add_reagent("frostoil", 30)
|
||||
return TRUE
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
/obj/effect/clockwork/city_of_cogs_rift/attack_hand(atom/movable/AM)
|
||||
beckon(AM)
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/CollidedWith(atom/movable/AM)
|
||||
/obj/effect/clockwork/city_of_cogs_rift/Bumped(atom/movable/AM)
|
||||
if(!QDELETED(AM))
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
/obj/effect/clockwork/sigil/proc/sigil_effects(mob/living/L)
|
||||
|
||||
|
||||
//Sigil of Transgression: Stuns the first non-servant to walk on it and flashes all nearby non_servants. Nar-Sian cultists are damaged and knocked down for a longer time
|
||||
//Sigil of Transgression: Stuns the first non-servant to walk on it and flashes all nearby non_servants. Nar'Sian cultists are damaged and knocked down for a longer time
|
||||
/obj/effect/clockwork/sigil/transgression
|
||||
name = "dull sigil"
|
||||
desc = "A dull, barely-visible golden sigil. It's as though light was carved into the ground."
|
||||
@@ -143,7 +143,7 @@
|
||||
GLOB.application_scripture_unlocked = TRUE
|
||||
hierophant_message("<span class='large_brass bold'>With the conversion of a new servant the Ark's power grows. Application scriptures are now available.</span>")
|
||||
if(add_servant_of_ratvar(L))
|
||||
L.log_message("<font color=#BE8700>Conversion was done with a [sigil_name].</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
L.log_message("conversion was done with a [sigil_name]", LOG_ATTACK, color="BE8700")
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/M = L
|
||||
M.uncuff()
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
name = "Inath-neq, the Resonant Cogwheel"
|
||||
desc = "A humanoid form blazing with blue fire. It radiates an aura of kindness and caring."
|
||||
clockwork_desc = "One of Ratvar's four generals. Before her current form, Inath-neq was a powerful warrior priestess commanding the Resonant Cogs, a sect of Ratvarian warriors renowned for \
|
||||
their prowess. After a lost battle with Nar-Sian cultists, Inath-neq was struck down and stated in her dying breath, \
|
||||
their prowess. After a lost battle with Nar'Sian cultists, Inath-neq was struck down and stated in her dying breath, \
|
||||
\"The Resonant Cogs shall not fall silent this day, but will come together to form a wheel that shall never stop turning.\" Ratvar, touched by this, granted Inath-neq an eternal body and \
|
||||
merged her soul with those of the Cogs slain with her on the battlefield."
|
||||
icon = 'icons/effects/119x268.dmi'
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
/obj/effect/clockwork/servant_blocker/Destroy(force)
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
var/turf/T = get_turf(src)
|
||||
. = ..()
|
||||
T.air_update_turf(TRUE)
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/CanPass(atom/movable/M, turf/target)
|
||||
var/list/target_contents = M.GetAllContents() + M
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
return
|
||||
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/CollidedWith(atom/movable/AM)
|
||||
/obj/effect/clockwork/spatial_gateway/Bumped(atom/movable/AM)
|
||||
..()
|
||||
if(!QDELETED(AM))
|
||||
pass_through_gateway(AM, FALSE)
|
||||
|
||||
@@ -46,5 +46,5 @@
|
||||
return
|
||||
if(ishuman(owner))
|
||||
clockwork_say(owner, "[text2ratvar("Servants, hear my words: [input]")]", TRUE)
|
||||
log_talk(owner,"CLOCK:[key_name(owner)] : [input]",LOGSAY)
|
||||
owner.log_talk(input, LOG_SAY, tag="clockwork")
|
||||
titled_hierophant_message(owner, input, span_for_name, span_for_message, title)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
The Ratvarian Language
|
||||
In the lore of the Servants of Ratvar, the Ratvarian tongue is a timeless language and full of power. It sounds like gibberish, much like Nar-Sie's language, but is in fact derived from
|
||||
aforementioned language, and may induce miracles when spoken in the correct way with an amplifying tool (similar to runes used by the Nar-Sian cult).
|
||||
In the lore of the Servants of Ratvar, the Ratvarian tongue is a timeless language and full of power. It sounds like gibberish, much like Nar'Sie's language, but is in fact derived from
|
||||
aforementioned language, and may induce miracles when spoken in the correct way with an amplifying tool (similar to runes used by the Nar'Sian cult).
|
||||
|
||||
While the canon states that the language of Ratvar and his servants is incomprehensible to the unenlightened as it is a derivative of the most ancient known language, in reality it is
|
||||
actually very simple. To translate a plain English sentence to Ratvar's tongue, simply move all of the letters thirteen places ahead, starting from "a" if the end of the alphabet is reached.
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
L.handcuffed = new/obj/item/restraints/handcuffs/clockwork(L)
|
||||
L.update_handcuffed()
|
||||
to_chat(ranged_ability_user, "<span class='neovgre_small'>You shackle [L].</span>")
|
||||
add_logs(ranged_ability_user, L, "handcuffed")
|
||||
log_combat(ranged_ability_user, L, "handcuffed")
|
||||
else
|
||||
to_chat(ranged_ability_user, "<span class='warning'>You fail to shackle [L].</span>")
|
||||
|
||||
@@ -117,12 +117,12 @@
|
||||
L.adjustOxyLoss(-oxydamage)
|
||||
L.adjustToxLoss(totaldamage * 0.5, TRUE, TRUE)
|
||||
clockwork_say(ranged_ability_user, text2ratvar("[has_holy_water ? "Heal tainted" : "Mend wounded"] flesh!"))
|
||||
add_logs(ranged_ability_user, L, "healed with Sentinel's Compromise")
|
||||
log_combat(ranged_ability_user, L, "healed with Sentinel's Compromise")
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], [has_holy_water ? "causing [L.p_them()] to briefly glow as it mends" : " mending"] [L.p_their()] bruises and burns!</span>", \
|
||||
"<span class='heavy_brass'>You feel Inath-neq's power healing your wounds[has_holy_water ? " and purging the darkness within you" : ""], but a deep nausea overcomes you!</span>")
|
||||
else
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Purge foul darkness!"))
|
||||
add_logs(ranged_ability_user, L, "purged of holy water with Sentinel's Compromise")
|
||||
log_combat(ranged_ability_user, L, "purged of holy water with Sentinel's Compromise")
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], causing [L.p_them()] to briefly glow!</span>", \
|
||||
"<span class='heavy_brass'>You feel Inath-neq's power purging the darkness within you!</span>")
|
||||
playsound(targetturf, 'sound/magic/staff_healing.ogg', 50, 1)
|
||||
@@ -153,7 +153,7 @@
|
||||
var/turf/U = get_turf(target)
|
||||
to_chat(ranged_ability_user, "<span class='brass'>You release the light of Ratvar!</span>")
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Purge all untruths and honor Engine!"))
|
||||
add_logs(ranged_ability_user, U, "fired at with Kindle")
|
||||
log_combat(ranged_ability_user, U, "fired at with Kindle")
|
||||
playsound(ranged_ability_user, 'sound/magic/blink.ogg', 50, TRUE, frequency = 0.5)
|
||||
var/obj/item/projectile/kindle/A = new(T)
|
||||
A.preparePixelProjectile(target, caller, params)
|
||||
@@ -265,7 +265,7 @@
|
||||
"<span class='heavy_brass'>You direct the judicial force to [target].</span>")
|
||||
var/turf/targetturf = get_turf(target)
|
||||
new/obj/effect/clockwork/judicial_marker(targetturf, ranged_ability_user)
|
||||
add_logs(ranged_ability_user, targetturf, "created a judicial marker")
|
||||
log_combat(ranged_ability_user, targetturf, "created a judicial marker")
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
clockwork_desc = null
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/component_id //What the component is identified as
|
||||
var/cultist_message = "You are not worthy of this meme." //Showed to Nar-Sian cultists if they pick up the component in addition to chaplains
|
||||
var/cultist_message = "You are not worthy of this meme." //Showed to Nar'Sian cultists if they pick up the component in addition to chaplains
|
||||
var/list/servant_of_ratvar_messages = list("ayy" = FALSE, "lmao" = TRUE) //Fluff, shown to servants of Ratvar on a low chance, if associated value is TRUE, will automatically apply ratvarian
|
||||
var/message_span = "heavy_brass"
|
||||
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = list("melee" = 70, "bullet" = 80, "laser" = -15, "energy" = 25, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list("melee" = 60, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
@@ -83,12 +83,12 @@
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = list("melee" = 70, "bullet" = 80, "laser" = -15, "energy" = 25, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list("melee" = 60, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
@@ -149,7 +149,7 @@
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list("melee" = 80, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
|
||||
@@ -313,7 +313,7 @@
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
if("Scripture")
|
||||
dat += "<font color=#BE8700 size=3>The Ancient Scripture</font><br><br>"
|
||||
dat += "If you have experience with the Nar-Sian cult (or the \"blood cult\") then you will know of runes. They are the manifestations of the Geometer's power, and where most \
|
||||
dat += "If you have experience with the Nar'Sian cult (or the \"blood cult\") then you will know of runes. They are the manifestations of the Geometer's power, and where most \
|
||||
of the cult's supernatural ability comes from. The Servant equivalent of runes is called <b>scripture</b>, and unlike runes, scripture is loaded into your clockwork slab.<br><br>"
|
||||
dat += "Each piece of scripture has widely-varying effects. Your most important scripture, <i>Geis</i>, is obvious and suspicious, but charges your slab with energy and allows \
|
||||
you to attack a non-Servant in melee range to restrain them and begin converting them into a Servant. This is just one example; each piece of scripture can be simple or \
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user]'s judicial visor fires a stream of energy at [target], creating a strange mark!</span>", "<span class='heavy_brass'>You direct [visor]'s power to [target]. You must wait for some time before doing this again.</span>")
|
||||
var/turf/targetturf = get_turf(target)
|
||||
new/obj/effect/clockwork/judicial_marker(targetturf, ranged_ability_user)
|
||||
add_logs(ranged_ability_user, targetturf, "created a judicial marker")
|
||||
log_combat(ranged_ability_user, targetturf, "created a judicial marker")
|
||||
ranged_ability_user.update_action_buttons_icon()
|
||||
ranged_ability_user.update_inv_glasses()
|
||||
addtimer(CALLBACK(visor, /obj/item/clothing/glasses/judicial_visor.proc/recharge_visor, ranged_ability_user), GLOB.ratvar_awakens ? visor.recharge_cooldown*0.1 : visor.recharge_cooldown)//Cooldown is reduced by 10x if Ratvar is up
|
||||
@@ -209,7 +209,7 @@
|
||||
targetsjudged++
|
||||
if(!QDELETED(L))
|
||||
L.adjustBruteLoss(20) //does a decent amount of damage
|
||||
add_logs(user, L, "struck with a judicial blast")
|
||||
log_combat(user, L, "struck with a judicial blast")
|
||||
to_chat(user, "<span class='brass'><b>[targetsjudged ? "Successfully judged <span class='neovgre'>[targetsjudged]</span>":"Judged no"] heretic[targetsjudged == 1 ? "":"s"].</b></span>")
|
||||
sleep(3) //so the animation completes properly
|
||||
qdel(src)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Wraith spectacles: Grants X-ray and night vision at the eventual cost of the wearer's sight if worn too long. Nar-Sian cultists are instantly blinded.
|
||||
//Wraith spectacles: Grants X-ray and night vision at the eventual cost of the wearer's sight if worn too long. Nar'Sian cultists are instantly blinded.
|
||||
/obj/item/clothing/glasses/wraith_spectacles
|
||||
name = "antique spectacles"
|
||||
desc = "Unnerving glasses with opaque yellow lenses."
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/proc/blind_cultist(mob/living/victim)
|
||||
if(iscultist(victim))
|
||||
to_chat(victim, "<span class='heavy_brass'>\"It looks like Nar-Sie's dogs really don't value their eyes.\"</span>")
|
||||
to_chat(victim, "<span class='heavy_brass'>\"It looks like Nar'Sie's dogs really don't value their eyes.\"</span>")
|
||||
to_chat(victim, "<span class='userdanger'>Your eyes explode with horrific pain!</span>")
|
||||
victim.emote("scream")
|
||||
victim.become_blind(EYE_DAMAGE)
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
E = new V
|
||||
E.Grant(src)
|
||||
|
||||
/mob/camera/eminence/say(message)
|
||||
/mob/camera/eminence/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
if(client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "You cannot send IC messages (muted).")
|
||||
@@ -86,7 +86,7 @@
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
if(!message)
|
||||
return
|
||||
log_talk(src, "[key_name(src)] : [message]", LOGSAY)
|
||||
src.log_talk(message, LOG_SAY, tag="clockwork eminence")
|
||||
if(GLOB.ratvar_awakens)
|
||||
visible_message("<span class='brass'><b>You feel light slam into your mind and form words:</b> \"[capitalize(message)]\"</span>")
|
||||
playsound(src, 'sound/machines/clockcult/ark_scream.ogg', 50, FALSE)
|
||||
|
||||
+1
-1
@@ -335,7 +335,7 @@
|
||||
sleep(3)
|
||||
GLOB.clockwork_gateway_activated = TRUE
|
||||
var/turf/T = SSmapping.get_station_center()
|
||||
new /obj/structure/destructible/clockwork/massive/ratvar(T, TRUE) //Citadel edit - hugboxes ratvar spawning by admins
|
||||
new /obj/structure/destructible/clockwork/massive/ratvar(T)
|
||||
SSticker.force_ending = TRUE
|
||||
var/x0 = T.x
|
||||
var/y0 = T.y
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot1.ogg',75 * get_efficiency_mod(),1)
|
||||
else
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot2.ogg',75 * get_efficiency_mod(),1)
|
||||
L.adjustFireLoss((!iscultist(L) ? damage_per_tick : damage_per_tick * 2) * get_efficiency_mod()) //Nar-Sian cultists take additional damage
|
||||
L.adjustFireLoss((!iscultist(L) ? damage_per_tick : damage_per_tick * 2) * get_efficiency_mod()) //Nar'Sian cultists take additional damage
|
||||
if(GLOB.ratvar_awakens && L)
|
||||
L.adjust_fire_stacks(damage_per_tick)
|
||||
L.IgniteMob()
|
||||
|
||||
+10
-11
@@ -13,11 +13,11 @@
|
||||
light_range = 15
|
||||
light_color = "#BE8700"
|
||||
var/atom/prey //Whatever Ratvar is chasing
|
||||
var/clashing = FALSE //If Ratvar is fighting with Nar-Sie
|
||||
var/clashing = FALSE //If Ratvar is fighting with Nar'Sie
|
||||
var/convert_range = 10
|
||||
obj_flags = CAN_BE_HIT | DANGEROUS_POSSESSION
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Initialize(mapload, is_from_gateway = FALSE)
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Initialize()
|
||||
. = ..()
|
||||
GLOB.ratvar_awakens++
|
||||
for(var/obj/O in GLOB.all_clockwork_objects)
|
||||
@@ -29,8 +29,7 @@
|
||||
sound_to_playing_players('sound/effects/ratvar_reveal.ogg')
|
||||
var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/clockwork_effects.dmi', "ratvar_alert")
|
||||
notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [get_area_name(src)] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay)
|
||||
if(is_from_gateway) //citadel edit - hugbox
|
||||
INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 10, null, FALSE, 0)
|
||||
INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 10, null, FALSE, 0)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Destroy()
|
||||
GLOB.ratvar_awakens--
|
||||
@@ -48,7 +47,7 @@
|
||||
R.visible_message("<span class='heavy_brass'>[R] forms, and its eyes blink open, glowing bright red!</span>")
|
||||
R.key = O.key
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Collide(atom/A)
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Bump(atom/A)
|
||||
var/turf/T = get_turf(A)
|
||||
if(T == loc)
|
||||
T = get_step(T, dir) //please don't run into a window like a bird, ratvar
|
||||
@@ -72,7 +71,7 @@
|
||||
if(L.z == z && !is_servant_of_ratvar(L) && L.mind)
|
||||
meals += L
|
||||
if(GLOB.cult_narsie && GLOB.cult_narsie.z == z)
|
||||
meals = list(GLOB.cult_narsie) //if you're in the way, handy for him, but ratvar only cares about nar-sie!
|
||||
meals = list(GLOB.cult_narsie) //if you're in the way, handy for him, but ratvar only cares about Nar'Sie!
|
||||
prey = GLOB.cult_narsie
|
||||
if(get_dist(src, prey) <= 10)
|
||||
clash()
|
||||
@@ -94,7 +93,7 @@
|
||||
<span class='userdanger'>You feel tremendous relief as the crushing focus relents...</span>")
|
||||
prey = null
|
||||
else
|
||||
dir_to_step_in = get_dir(src, prey) //Unlike Nar-Sie, Ratvar ruthlessly chases down his target
|
||||
dir_to_step_in = get_dir(src, prey) //Unlike Nar'Sie, Ratvar ruthlessly chases down his target
|
||||
step(src, dir_to_step_in)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/proc/clash()
|
||||
@@ -107,7 +106,7 @@
|
||||
clash_of_the_titans(GLOB.cult_narsie) // >:(
|
||||
return TRUE
|
||||
|
||||
//Put me in Reebe, will you? Ratvar has found and is going to do a hecking murder on Nar-Sie
|
||||
//Put me in Reebe, will you? Ratvar has found and is going to do a hecking murder on Nar'Sie
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/proc/clash_of_the_titans(obj/singularity/narsie/narsie)
|
||||
var/winner = "Undeclared"
|
||||
var/base_victory_chance = 1
|
||||
@@ -133,18 +132,18 @@
|
||||
flash_color(M, flash_color="#C80000", flash_time=1)
|
||||
shake_camera(M, 4, 3)
|
||||
if(narsie_chance > ratvar_chance)
|
||||
winner = "Nar-Sie"
|
||||
winner = "Nar'Sie"
|
||||
break
|
||||
base_victory_chance *= 2 //The clash has a higher chance of resolving each time both gods attack one another
|
||||
switch(winner)
|
||||
if("Ratvar")
|
||||
send_to_playing_players("<span class='heavy_brass'><font size=5>\"[pick("DIE.", "ROT.")]\"</font></span>\n\
|
||||
<span class='cult'><font size=5>\"<b>[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"</b></font></span>") //nar-sie get out
|
||||
<span class='cult'><font size=5>\"<b>[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"</b></font></span>") //Nar'Sie get out
|
||||
sound_to_playing_players('sound/magic/clockwork/anima_fragment_attack.ogg')
|
||||
sound_to_playing_players('sound/magic/demon_dies.ogg', 50)
|
||||
clashing = FALSE
|
||||
qdel(narsie)
|
||||
if("Nar-Sie")
|
||||
if("Nar'Sie")
|
||||
send_to_playing_players("<span class='cult'><font size=5>\"<b>[pick("Ha.", "Ra'sha fonn dest.", "You fool. To come here.")]</b>\"</font></span>") //Broken English
|
||||
sound_to_playing_players('sound/magic/demon_attack1.ogg')
|
||||
sound_to_playing_players('sound/magic/clockwork/anima_fragment_death.ogg', 62)
|
||||
|
||||
@@ -43,11 +43,11 @@
|
||||
affect_mob(AM)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/CollidedWith(atom/movable/AM)
|
||||
/obj/structure/destructible/clockwork/taunting_trail/Bumped(atom/movable/AM)
|
||||
affect_mob(AM)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/Collide(atom/movable/AM)
|
||||
/obj/structure/destructible/clockwork/taunting_trail/Bump(atom/movable/AM)
|
||||
affect_mob(AM)
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
SSticker.mode.servants_of_ratvar += owner
|
||||
SSticker.mode.update_servant_icons_added(owner)
|
||||
owner.special_role = ROLE_SERVANT_OF_RATVAR
|
||||
owner.current.log_message("<font color=#BE8700>Has been converted to the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
owner.current.log_message("has been converted to the cult of Ratvar!", LOG_ATTACK, color="#BE8700")
|
||||
if(issilicon(current))
|
||||
if(iscyborg(current) && !silent)
|
||||
var/mob/living/silicon/robot/R = current
|
||||
@@ -161,7 +161,7 @@
|
||||
if(!silent)
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] seems to have remembered [owner.current.p_their()] true allegiance!</span>", null, null, null, owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
|
||||
owner.current.log_message("<font color=#BE8700>Has renounced the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
owner.current.log_message("has renounced the cult of Ratvar!", LOG_ATTACK, color="#BE8700")
|
||||
owner.special_role = null
|
||||
if(iscyborg(owner.current))
|
||||
to_chat(owner.current, "<span class='warning'>Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.</span>")
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
/datum/action/innate/cult/blood_magic/Grant()
|
||||
..()
|
||||
button.screen_loc = "6:-29,4:-2"
|
||||
button.moved = "6:-29,4:-2"
|
||||
button.screen_loc = DEFAULT_BLOODSPELLS
|
||||
button.moved = DEFAULT_BLOODSPELLS
|
||||
button.ordered = FALSE
|
||||
|
||||
/datum/action/innate/cult/blood_magic/Remove()
|
||||
@@ -84,7 +84,7 @@
|
||||
to_chat(owner, "<span class='warning'>Your wounds glows with power, you have prepared a [new_spell.name] invocation!</span>")
|
||||
channeling = FALSE
|
||||
|
||||
/datum/action/innate/cult/blood_spell //The next generation of talismans
|
||||
/datum/action/innate/cult/blood_spell //The next generation of talismans, handles storage/creation of blood magic
|
||||
name = "Blood Magic"
|
||||
button_icon_state = "telerune"
|
||||
desc = "Fear the Old Blood."
|
||||
@@ -161,7 +161,7 @@
|
||||
/datum/action/innate/cult/blood_spell/emp/Activate()
|
||||
owner.visible_message("<span class='warning'>[owner]'s hand flashes a bright blue!</span>", \
|
||||
"<span class='cultitalic'>You speak the cursed words, emitting an EMP blast from your hand.</span>")
|
||||
empulse(owner, 3, 6)
|
||||
empulse(owner, 2, 5)
|
||||
owner.whisper(invocation, language = /datum/language/common)
|
||||
charges--
|
||||
if(charges<=0)
|
||||
@@ -179,11 +179,11 @@
|
||||
desc = "<u>A sinister spell used to convert:</u><br>Plasteel into runed metal<br>25 metal into a construct shell<br>Cyborgs directly into constructs<br>Cyborg shells into construct shells<br>Airlocks into runed airlocks (harm intent)"
|
||||
button_icon_state = "transmute"
|
||||
magic_path = "/obj/item/melee/blood_magic/construction"
|
||||
health_cost = 10
|
||||
health_cost = 12
|
||||
|
||||
/datum/action/innate/cult/blood_spell/equipment
|
||||
name = "Summon Equipment"
|
||||
desc = "A crucial spell that enables you to summon either a ritual dagger or combat gear including armored robes, the nar'sien bola, and an eldritch longsword."
|
||||
desc = "A crucial spell that enables you to summon either a ritual dagger or combat gear including armored robes, the Nar'Sien bola, and an eldritch longsword."
|
||||
button_icon_state = "equip"
|
||||
magic_path = "/obj/item/melee/blood_magic/armor"
|
||||
|
||||
@@ -378,11 +378,12 @@
|
||||
uses = 0
|
||||
qdel(src)
|
||||
return
|
||||
add_logs(user, M, "used a cult spell on", source.name, "")
|
||||
log_combat(user, M, "used a cult spell on", source.name, "")
|
||||
M.lastattacker = user.real_name
|
||||
M.lastattackerckey = user.ckey
|
||||
|
||||
/obj/item/melee/blood_magic/afterattack(atom/target, mob/living/carbon/user, proximity)
|
||||
. = ..()
|
||||
if(invocation)
|
||||
user.whisper(invocation, language = /datum/language/common)
|
||||
if(health_cost)
|
||||
@@ -400,7 +401,7 @@
|
||||
//Stun
|
||||
/obj/item/melee/blood_magic/stun
|
||||
name = "Stunning Aura "
|
||||
color = "#ff0000" // red
|
||||
color = RUNE_COLOR_RED
|
||||
invocation = "Fuu ma'jin!"
|
||||
|
||||
/obj/item/melee/blood_magic/stun/afterattack(atom/target, mob/living/carbon/user, proximity)
|
||||
@@ -488,7 +489,7 @@
|
||||
/obj/item/melee/blood_magic/shackles/afterattack(atom/target, mob/living/carbon/user, proximity)
|
||||
if(iscultist(user) && iscarbon(target) && proximity)
|
||||
var/mob/living/carbon/C = target
|
||||
if(C.get_num_arms() >= 2 || C.get_arm_ignore())
|
||||
if(C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore())
|
||||
CuffAttack(C, user)
|
||||
else
|
||||
user.visible_message("<span class='cultitalic'>This victim doesn't have enough arms to complete the restraint!</span>")
|
||||
@@ -506,7 +507,7 @@
|
||||
C.update_handcuffed()
|
||||
C.silent += 5
|
||||
to_chat(user, "<span class='notice'>You shackle [C].</span>")
|
||||
add_logs(user, C, "shackled")
|
||||
log_combat(user, C, "shackled")
|
||||
uses--
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[C] is already bound.</span>")
|
||||
@@ -585,10 +586,13 @@
|
||||
new /obj/structure/constructshell(T)
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
else if(istype(target,/obj/machinery/door/airlock))
|
||||
target.narsie_act()
|
||||
uses--
|
||||
user.visible_message("<span class='warning'>Black ribbons suddenly eminate from [user]'s hand and cling to the airlock - twisting and corrupting it!</span>")
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
playsound(T, 'sound/machines/airlockforced.ogg', 50, 1)
|
||||
do_sparks(5, TRUE, target)
|
||||
if(do_after(user, 50, target = user))
|
||||
target.narsie_act()
|
||||
uses--
|
||||
user.visible_message("<span class='warning'>Black ribbons suddenly emanate from [user]'s hand and cling to the airlock - twisting and corrupting it!</span>")
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The spell will not work on [target]!</span>")
|
||||
return
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
job_rank = ROLE_CULTIST
|
||||
var/ignore_implant = FALSE
|
||||
var/give_equipment = FALSE
|
||||
|
||||
var/datum/team/cult/cult_team
|
||||
|
||||
|
||||
/datum/antagonist/cult/get_team()
|
||||
return cult_team
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
equip_cultist(TRUE)
|
||||
SSticker.mode.cult += owner // Only add after they've been given objectives
|
||||
SSticker.mode.update_cult_icons_added(owner)
|
||||
current.log_message("<font color=#960000>Has been converted to the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
current.log_message("has been converted to the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
|
||||
|
||||
if(cult_team.blood_target && cult_team.blood_target_image && current.client)
|
||||
current.client.images += cult_team.blood_target_image
|
||||
@@ -111,7 +111,11 @@
|
||||
if(ishuman(current))
|
||||
magic.Grant(current)
|
||||
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
|
||||
|
||||
if(cult_team.cult_risen)
|
||||
cult_team.rise(current)
|
||||
if(cult_team.cult_ascendent)
|
||||
cult_team.ascend(current)
|
||||
|
||||
/datum/antagonist/cult/remove_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
@@ -123,14 +127,19 @@
|
||||
communion.Remove(current)
|
||||
magic.Remove(current)
|
||||
current.clear_alert("bloodsense")
|
||||
|
||||
if(ishuman(current))
|
||||
var/mob/living/carbon/human/H = current
|
||||
H.eye_color = initial(H.eye_color)
|
||||
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
|
||||
H.remove_trait(CULT_EYES)
|
||||
H.update_body()
|
||||
/datum/antagonist/cult/on_removal()
|
||||
SSticker.mode.cult -= owner
|
||||
SSticker.mode.update_cult_icons_removed(owner)
|
||||
if(!silent)
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just reverted to [owner.current.p_their()] old faith!</span>", null, null, null, owner.current)
|
||||
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
|
||||
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
owner.current.log_message("has renounced the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
|
||||
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
|
||||
owner.current.client.images -= cult_team.blood_target_image
|
||||
. = ..()
|
||||
@@ -193,7 +202,10 @@
|
||||
throwing.Grant(current)
|
||||
current.update_action_buttons_icon()
|
||||
current.apply_status_effect(/datum/status_effect/cult_master)
|
||||
|
||||
if(cult_team.cult_risen)
|
||||
cult_team.rise(current)
|
||||
if(cult_team.cult_ascendent)
|
||||
cult_team.ascend(current)
|
||||
/datum/antagonist/cult/master/remove_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
@@ -204,6 +216,14 @@
|
||||
throwing.Remove(current)
|
||||
current.update_action_buttons_icon()
|
||||
current.remove_status_effect(/datum/status_effect/cult_master)
|
||||
|
||||
if(ishuman(current))
|
||||
var/mob/living/carbon/human/H = current
|
||||
H.eye_color = initial(H.eye_color)
|
||||
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
|
||||
H.remove_trait(CULT_EYES)
|
||||
H.cut_overlays()
|
||||
H.regenerate_icons()
|
||||
|
||||
/datum/team/cult
|
||||
name = "Cult"
|
||||
@@ -215,7 +235,53 @@
|
||||
var/cult_vote_called = FALSE
|
||||
var/mob/living/cult_master
|
||||
var/reckoning_complete = FALSE
|
||||
|
||||
var/cult_risen = FALSE
|
||||
var/cult_ascendent = FALSE
|
||||
|
||||
/datum/team/cult/proc/check_size()
|
||||
if(cult_ascendent)
|
||||
return
|
||||
var/alive = 0
|
||||
var/cultplayers = 0
|
||||
for(var/I in GLOB.player_list)
|
||||
var/mob/M = I
|
||||
if(M.stat != DEAD)
|
||||
if(iscultist(M))
|
||||
++cultplayers
|
||||
else
|
||||
++alive
|
||||
var/ratio = cultplayers/alive
|
||||
if(ratio > CULT_RISEN && !cult_risen)
|
||||
for(var/datum/mind/B in members)
|
||||
if(B.current)
|
||||
SEND_SOUND(B.current, 'sound/hallucinations/i_see_you2.ogg')
|
||||
to_chat(B.current, "<span class='cultlarge'>The veil weakens as your cult grows, your eyes begin to glow...")
|
||||
addtimer(CALLBACK(src, .proc/rise, B.current), 200)
|
||||
cult_risen = TRUE
|
||||
|
||||
if(ratio > CULT_ASCENDENT && !cult_ascendent)
|
||||
for(var/datum/mind/B in members)
|
||||
if(B.current)
|
||||
SEND_SOUND(B.current, 'sound/hallucinations/im_here1.ogg')
|
||||
to_chat(B.current, "<span class='cultlarge'>Your cult is ascendent and the red harvest approaches - you cannot hide your true nature for much longer!!")
|
||||
addtimer(CALLBACK(src, .proc/ascend, B.current), 200)
|
||||
cult_ascendent = TRUE
|
||||
|
||||
|
||||
/datum/team/cult/proc/rise(cultist)
|
||||
if(ishuman(cultist))
|
||||
var/mob/living/carbon/human/H = cultist
|
||||
H.eye_color = "f00"
|
||||
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
|
||||
H.add_trait(CULT_EYES)
|
||||
H.update_body()
|
||||
|
||||
/datum/team/cult/proc/ascend(cultist)
|
||||
if(ishuman(cultist))
|
||||
var/mob/living/carbon/human/H = cultist
|
||||
new /obj/effect/temp_visual/cult/sparks(get_turf(H), H.dir)
|
||||
var/istate = pick("halo1","halo2","halo3","halo4","halo5","halo6")
|
||||
H.add_overlay(mutable_appearance('icons/effects/32x64.dmi', istate, -BODY_FRONT_LAYER))
|
||||
|
||||
/datum/team/cult/proc/setup_objectives()
|
||||
//SAC OBJECTIVE , todo: move this to objective internals
|
||||
@@ -257,6 +323,7 @@
|
||||
summon_objective.team = src
|
||||
objectives += summon_objective
|
||||
|
||||
|
||||
/datum/objective/sacrifice
|
||||
var/sacced = FALSE
|
||||
var/sac_image
|
||||
@@ -285,7 +352,7 @@
|
||||
update_explanation_text()
|
||||
|
||||
/datum/objective/eldergod/update_explanation_text()
|
||||
explanation_text = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'. <b>The summoning can only be accomplished in [english_list(summon_spots)] - where the veil is weak enough for the ritual to begin.</b>"
|
||||
explanation_text = "Summon Nar'Sie by invoking the rune 'Summon Nar'Sie'. <b>The summoning can only be accomplished in [english_list(summon_spots)] - where the veil is weak enough for the ritual to begin.</b>"
|
||||
|
||||
/datum/objective/eldergod/check_completion()
|
||||
return summoned || completed
|
||||
@@ -300,7 +367,7 @@
|
||||
var/list/parts = list()
|
||||
|
||||
if(check_cult_victory())
|
||||
parts += "<span class='greentext big'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>"
|
||||
parts += "<span class='greentext big'>The cult has succeeded! Nar'Sie has snuffed out another torch in the void!</span>"
|
||||
else
|
||||
parts += "<span class='redtext big'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>"
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
var/link = FOLLOW_LINK(M, user)
|
||||
to_chat(M, "[link] [my_message]")
|
||||
|
||||
log_talk(user,"CULT:[key_name(user)] : [message]",LOGSAY)
|
||||
user.log_talk(message, LOG_SAY, tag="cult")
|
||||
|
||||
/datum/action/innate/cult/comm/spirit
|
||||
name = "Spiritual Communion"
|
||||
@@ -79,7 +79,7 @@
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/cult/mastervote/Activate()
|
||||
var/choice = alert(owner, "The mantle of leadership is a heavy. Success in this role requires an expert level of communication and experience. Are you sure?",, "Yes", "No")
|
||||
var/choice = alert(owner, "The mantle of leadership is heavy. Success in this role requires an expert level of communication and experience. Are you sure?",, "Yes", "No")
|
||||
if(choice == "Yes" && IsAvailable())
|
||||
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
pollCultists(owner,C.cult_team)
|
||||
@@ -196,15 +196,15 @@
|
||||
/datum/action/innate/cult/master/finalreck/proc/chant(chant_number)
|
||||
switch(chant_number)
|
||||
if(1)
|
||||
owner.say("C'arta forbici!", language = /datum/language/common)
|
||||
owner.say("C'arta forbici!", language = /datum/language/common, forced = "cult invocation")
|
||||
if(2)
|
||||
owner.say("Pleggh e'ntrath!", language = /datum/language/common)
|
||||
owner.say("Pleggh e'ntrath!", language = /datum/language/common, forced = "cult invocation")
|
||||
playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 50, 1)
|
||||
if(3)
|
||||
owner.say("Barhah hra zar'garis!", language = /datum/language/common)
|
||||
owner.say("Barhah hra zar'garis!", language = /datum/language/common, forced = "cult invocation")
|
||||
playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 75, 1)
|
||||
if(4)
|
||||
owner.say("N'ath reth sh'yro eth d'rekkathnor!!!", language = /datum/language/common)
|
||||
owner.say("N'ath reth sh'yro eth d'rekkathnor!!!", language = /datum/language/common, forced = "cult invocation")
|
||||
playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 100, 1)
|
||||
|
||||
/datum/action/innate/cult/master/cultmark
|
||||
@@ -334,7 +334,7 @@
|
||||
if(cooldown>world.time)
|
||||
reset_blood_target(C.cult_team)
|
||||
to_chat(owner, "<span class='cultbold'>You have cleared the cult's blood target!</span>")
|
||||
qdel(C.cult_team.blood_target_reset_timer)
|
||||
deltimer(C.cult_team.blood_target_reset_timer)
|
||||
return
|
||||
else
|
||||
to_chat(owner, "<span class='cultbold'>The cult has already designated a target!</span>")
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
actions_types = list(/datum/action/item_action/cult_dagger)
|
||||
|
||||
/obj/item/melee/cultblade/dagger/Initialize()
|
||||
..()
|
||||
. = ..()
|
||||
var/image/I = image(icon = 'icons/effects/blood.dmi' , icon_state = null, loc = src)
|
||||
I.override = TRUE
|
||||
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "cult_dagger", I)
|
||||
@@ -81,7 +81,7 @@
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard
|
||||
name = "bloody bastard sword"
|
||||
desc = "An enormous sword used by Nar-Sien cultists to rapidly harvest the souls of non-believers."
|
||||
desc = "An enormous sword used by Nar'Sien cultists to rapidly harvest the souls of non-believers."
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
block_chance = 50
|
||||
throwforce = 20
|
||||
@@ -251,8 +251,8 @@
|
||||
holder.update_action_buttons_icon()
|
||||
|
||||
/obj/item/restraints/legcuffs/bola/cult
|
||||
name = "nar'sien bola"
|
||||
desc = "A strong bola, bound with dark magic that allows it to pass harmlessly through Nar'sien cultists. Throw it to trip and slow your victim."
|
||||
name = "\improper Nar'Sien bola"
|
||||
desc = "A strong bola, bound with dark magic that allows it to pass harmlessly through Nar'Sien cultists. Throw it to trip and slow your victim."
|
||||
icon_state = "bola_cult"
|
||||
breakouttime = 60
|
||||
knockdown = 20
|
||||
@@ -297,7 +297,7 @@
|
||||
|
||||
/obj/item/clothing/head/culthood/alt
|
||||
name = "cultist hood"
|
||||
desc = "An armored hood worn by the followers of Nar-Sie."
|
||||
desc = "An armored hood worn by the followers of Nar'Sie."
|
||||
icon_state = "cult_hoodalt"
|
||||
item_state = "cult_hoodalt"
|
||||
|
||||
@@ -306,7 +306,7 @@
|
||||
|
||||
/obj/item/clothing/suit/cultrobes/alt
|
||||
name = "cultist robes"
|
||||
desc = "An armored set of robes worn by the followers of Nar-Sie."
|
||||
desc = "An armored set of robes worn by the followers of Nar'Sie."
|
||||
icon_state = "cultrobesalt"
|
||||
item_state = "cultrobesalt"
|
||||
|
||||
@@ -318,14 +318,14 @@
|
||||
name = "magus helm"
|
||||
icon_state = "magus"
|
||||
item_state = "magus"
|
||||
desc = "A helm worn by the followers of Nar-Sie."
|
||||
desc = "A helm worn by the followers of Nar'Sie."
|
||||
flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDEEARS|HIDEEYES
|
||||
armor = list("melee" = 30, "bullet" = 30, "laser" = 30,"energy" = 20, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 10, "acid" = 10)
|
||||
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
|
||||
|
||||
/obj/item/clothing/suit/magusred
|
||||
name = "magus robes"
|
||||
desc = "A set of armored robes worn by the followers of Nar-Sie."
|
||||
desc = "A set of armored robes worn by the followers of Nar'Sie."
|
||||
icon_state = "magusred"
|
||||
item_state = "magusred"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
@@ -334,8 +334,8 @@
|
||||
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/cult
|
||||
name = "\improper Nar-Sien hardened helmet"
|
||||
desc = "A heavily-armored helmet worn by warriors of the Nar-Sien cult. It can withstand hard vacuum."
|
||||
name = "\improper Nar'Sien hardened helmet"
|
||||
desc = "A heavily-armored helmet worn by warriors of the Nar'Sien cult. It can withstand hard vacuum."
|
||||
icon_state = "cult_helmet"
|
||||
item_state = "cult_helmet"
|
||||
armor = list("melee" = 60, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 40, "acid" = 75)
|
||||
@@ -343,10 +343,10 @@
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/cult
|
||||
name = "\improper Nar-Sien hardened armor"
|
||||
name = "\improper Nar'Sien hardened armor"
|
||||
icon_state = "cult_armor"
|
||||
item_state = "cult_armor"
|
||||
desc = "A heavily-armored exosuit worn by warriors of the Nar-Sien cult. It can withstand hard vacuum."
|
||||
desc = "A heavily-armored exosuit worn by warriors of the Nar'Sien cult. It can withstand hard vacuum."
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
allowed = list(/obj/item/tome, /obj/item/melee/cultblade, /obj/item/tank/internals/)
|
||||
armor = list("melee" = 70, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 40, "acid" = 75)
|
||||
@@ -456,13 +456,13 @@
|
||||
user.dropItemToGround(src, TRUE)
|
||||
|
||||
/obj/item/clothing/glasses/hud/health/night/cultblind
|
||||
desc = "may Nar-Sie guide you through the darkness and shield you from the light."
|
||||
desc = "may Nar'Sie guide you through the darkness and shield you from the light."
|
||||
name = "zealot's blindfold"
|
||||
icon_state = "blindfold"
|
||||
item_state = "blindfold"
|
||||
flash_protect = 1
|
||||
|
||||
/obj/item/clothing/glasses/night/cultblind/equipped(mob/living/user, slot)
|
||||
/obj/item/clothing/glasses/hud/health/night/cultblind/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='cultlarge'>\"You want to be blind, do you?\"</span>")
|
||||
@@ -496,7 +496,7 @@
|
||||
to_chat(user, "<span class='notice'>We have exhausted our ability to curse the shuttle.</span>")
|
||||
return
|
||||
if(locate(/obj/singularity/narsie) in GLOB.poi_list)
|
||||
to_chat(user, "<span class='warning'>Nar-Sie is already on this plane, there is no delaying the end of all things.</span>")
|
||||
to_chat(user, "<span class='warning'>Nar'Sie is already on this plane, there is no delaying the end of all things.</span>")
|
||||
return
|
||||
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
|
||||
@@ -589,7 +589,7 @@
|
||||
|
||||
/obj/item/flashlight/flare/culttorch
|
||||
name = "void torch"
|
||||
desc = "Used by veteran cultists to instantly transport items to their needful bretheren."
|
||||
desc = "Used by veteran cultists to instantly transport items to their needful brethren."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
brightness_on = 1
|
||||
icon_state = "torch"
|
||||
@@ -770,7 +770,7 @@
|
||||
damage_type = BRUTE
|
||||
impact_effect_type = /obj/effect/temp_visual/dir_setting/bloodsplatter
|
||||
|
||||
/obj/item/projectile/magic/arcane_barrage/blood/Collide(atom/target)
|
||||
/obj/item/projectile/magic/arcane_barrage/blood/Bump(atom/target)
|
||||
var/turf/T = get_turf(target)
|
||||
playsound(T, 'sound/effects/splat.ogg', 50, TRUE)
|
||||
if(iscultist(target))
|
||||
@@ -804,6 +804,7 @@
|
||||
|
||||
|
||||
/obj/item/blood_beam/afterattack(atom/A, mob/living/user, flag, params)
|
||||
. = ..()
|
||||
if(firing || charging)
|
||||
return
|
||||
var/C = user.client
|
||||
@@ -897,7 +898,7 @@
|
||||
|
||||
/obj/item/shield/mirror
|
||||
name = "mirror shield"
|
||||
desc = "An infamous shield used by Nar'sien sects to confuse and disorient their enemies. Its edges are weighted for use as a throwing weapon - capable of disabling multiple foes with preternatural accuracy."
|
||||
desc = "An infamous shield used by Nar'Sien sects to confuse and disorient their enemies. Its edges are weighted for use as a throwing weapon - capable of disabling multiple foes with preternatural accuracy."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "mirror_shield" // eshield1 for expanded
|
||||
lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
|
||||
@@ -905,22 +906,22 @@
|
||||
force = 5
|
||||
throwforce = 15
|
||||
throw_speed = 1
|
||||
throw_range = 6
|
||||
throw_range = 4
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
attack_verb = list("bumped", "prodded")
|
||||
hitsound = 'sound/weapons/smash.ogg'
|
||||
var/illusions = 3
|
||||
var/illusions = 2
|
||||
|
||||
/obj/item/shield/mirror/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
if(iscultist(owner))
|
||||
if(istype(hitby, /obj/item/projectile))
|
||||
var/obj/item/projectile/P = hitby
|
||||
if(P.damage >= 35)
|
||||
if(P.damage >= 30)
|
||||
var/turf/T = get_turf(owner)
|
||||
T.visible_message("<span class='warning'>The sheer force from [P] shatters the mirror shield!</span>")
|
||||
new /obj/effect/temp_visual/cult/sparks(T)
|
||||
playsound(T, 'sound/effects/glassbr3.ogg', 100)
|
||||
owner.Knockdown(20)
|
||||
owner.Knockdown(25)
|
||||
qdel(src)
|
||||
return FALSE
|
||||
if(P.is_reflectable)
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
/obj/structure/destructible/cult/talisman
|
||||
name = "altar"
|
||||
desc = "A bloodstained altar dedicated to Nar-Sie."
|
||||
desc = "A bloodstained altar dedicated to Nar'Sie."
|
||||
icon_state = "talismanaltar"
|
||||
break_message = "<span class='warning'>The altar shatters, leaving only the wailing of the damned!</span>"
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
/obj/structure/destructible/cult/forge
|
||||
name = "daemon forge"
|
||||
desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie."
|
||||
desc = "A forge used in crafting the unholy weapons used by the armies of Nar'Sie."
|
||||
icon_state = "forge"
|
||||
light_range = 2
|
||||
light_color = LIGHT_COLOR_LAVA
|
||||
@@ -131,7 +131,7 @@
|
||||
return
|
||||
var/choice
|
||||
if(user.mind.has_antag_datum(/datum/antagonist/cult/master))
|
||||
choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Bastard Sword")
|
||||
choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Mirror Shield")
|
||||
else
|
||||
choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Mirror Shield")
|
||||
var/list/pickedtype = list()
|
||||
@@ -140,14 +140,6 @@
|
||||
pickedtype += /obj/item/clothing/suit/hooded/cultrobes/cult_shield
|
||||
if("Flagellant's Robe")
|
||||
pickedtype += /obj/item/clothing/suit/hooded/cultrobes/berserker
|
||||
if("Bastard Sword")
|
||||
if((world.time - SSticker.round_start_time) >= 12000)
|
||||
pickedtype += /obj/item/twohanded/required/cult_bastard
|
||||
else
|
||||
cooldowntime = 12000 - (world.time - SSticker.round_start_time)
|
||||
to_chat(user, "<span class='cult italic'>The forge fires are not yet hot enough for this weapon, give it another [DisplayTimeText(cooldowntime)].</span>")
|
||||
cooldowntime = 0
|
||||
return
|
||||
if("Mirror Shield")
|
||||
pickedtype += /obj/item/shield/mirror
|
||||
if(src && !QDELETED(src) && anchored && pickedtype && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time)
|
||||
@@ -221,7 +213,10 @@
|
||||
|
||||
var/turf/T = safepick(validturfs)
|
||||
if(T)
|
||||
T.ChangeTurf(/turf/open/floor/engine/cult)
|
||||
if(istype(T, /turf/open/floor/plating))
|
||||
T.PlaceOnTop(/turf/open/floor/engine/cult)
|
||||
else
|
||||
T.ChangeTurf(/turf/open/floor/engine/cult)
|
||||
else
|
||||
var/turf/open/floor/engine/cult/F = safepick(cultturfs)
|
||||
if(F)
|
||||
|
||||
@@ -17,7 +17,7 @@ This file contains the cult dagger and rune list code
|
||||
/obj/item/melee/cultblade/dagger/examine(mob/user)
|
||||
..()
|
||||
if(iscultist(user) || isobserver(user))
|
||||
to_chat(user, "<span class='cult'>The scriptures of the Geometer. Allows the scribing of runes and access to the knowledge archives of the cult of Nar-Sie.</span>")
|
||||
to_chat(user, "<span class='cult'>The scriptures of the Geometer. Allows the scribing of runes and access to the knowledge archives of the cult of Nar'Sie.</span>")
|
||||
to_chat(user, "<span class='cult'>Striking a cult structure will unanchor or reanchor it.</span>")
|
||||
to_chat(user, "<span class='cult'>Striking another cultist with it will purge holy water from them.</span>")
|
||||
to_chat(user, "<span class='cult'>Striking a noncultist, however, will tear their flesh.</span>")
|
||||
@@ -29,7 +29,7 @@ This file contains the cult dagger and rune list code
|
||||
var/holy2unholy = M.reagents.get_reagent_amount("holywater")
|
||||
M.reagents.del_reagent("holywater")
|
||||
M.reagents.add_reagent("unholywater",holy2unholy)
|
||||
add_logs(user, M, "smacked", src, " removing the holy water from them")
|
||||
log_combat(user, M, "smacked", src, " removing the holy water from them")
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
@@ -78,7 +78,7 @@ This file contains the cult dagger and rune list code
|
||||
return
|
||||
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
|
||||
if(!(A in summon_objective.summon_spots))
|
||||
to_chat(user, "<span class='cultlarge'>The Apocalypse rune will remove a ritual site (where Nar-sie can be summoned), it can only be scribed in [english_list(summon_objective.summon_spots)]!</span>")
|
||||
to_chat(user, "<span class='cultlarge'>The Apocalypse rune will remove a ritual site (where Nar'Sie can be summoned), it can only be scribed in [english_list(summon_objective.summon_spots)]!</span>")
|
||||
return
|
||||
if(summon_objective.summon_spots.len < 2)
|
||||
to_chat(user, "<span class='cultlarge'>Only one ritual site remains - it must be reserved for the final summoning!</span>")
|
||||
@@ -87,7 +87,7 @@ This file contains the cult dagger and rune list code
|
||||
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
|
||||
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
|
||||
if(!summon_objective)
|
||||
to_chat(user, "<span class='warning'>Nar-Sie does not wish to be summoned!</span>")
|
||||
to_chat(user, "<span class='warning'>Nar'Sie does not wish to be summoned!</span>")
|
||||
return
|
||||
if(sac_objective && !sac_objective.check_completion())
|
||||
to_chat(user, "<span class='warning'>The sacrifice is not complete. The portal would lack the power to open if you tried!</span>")
|
||||
@@ -98,7 +98,7 @@ This file contains the cult dagger and rune list code
|
||||
if(!(A in summon_objective.summon_spots))
|
||||
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!</span>")
|
||||
return
|
||||
var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
|
||||
var/confirm_final = alert(user, "This is the FINAL step to summon Nar'Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar'Sie!", "No")
|
||||
if(confirm_final == "No")
|
||||
to_chat(user, "<span class='cult'>You decide to prepare further before scribing the rune.</span>")
|
||||
return
|
||||
|
||||
@@ -62,7 +62,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
|
||||
to_chat(user, "<span class='notice'>You carefully erase the [lowertext(cultist_name)] rune.</span>")
|
||||
qdel(src)
|
||||
else if(istype(I, /obj/item/nullrod))
|
||||
user.say("BEGONE FOUL MAGIKS!!")
|
||||
user.say("BEGONE FOUL MAGIKS!!", forced = "nullrod")
|
||||
to_chat(user, "<span class='danger'>You disrupt the magic of [src] with [I].</span>")
|
||||
qdel(src)
|
||||
|
||||
@@ -136,7 +136,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
if(isliving(M))
|
||||
var/mob/living/L = M
|
||||
if(invocation)
|
||||
L.say(invocation, language = /datum/language/common, ignore_spam = TRUE)
|
||||
L.say(invocation, language = /datum/language/common, ignore_spam = TRUE, forced = "cult invocation")
|
||||
if(invoke_damage)
|
||||
L.apply_damage(invoke_damage, BRUTE)
|
||||
to_chat(L, "<span class='cult italic'>[src] saps your strength!</span>")
|
||||
@@ -179,7 +179,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
//Rite of Offering: Converts or sacrifices a target.
|
||||
/obj/effect/rune/convert
|
||||
cultist_name = "Offer"
|
||||
cultist_desc = "offers a noncultist above it to Nar-Sie, either converting them or sacrificing them."
|
||||
cultist_desc = "offers a noncultist above it to Nar'Sie, either converting them or sacrificing them."
|
||||
req_cultists_text = "2 for conversion, 3 for living sacrifices and sacrifice targets."
|
||||
invocation = "Mah'weyh pleggh at e'ntrath!"
|
||||
icon_state = "3"
|
||||
@@ -211,7 +211,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
|
||||
var/mob/living/F = invokers[1]
|
||||
var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
|
||||
var/datum/team/cult/Cult_team = C.cult_team
|
||||
var/is_convertable = is_convertable_to_cult(L,C.cult_team)
|
||||
if(L.stat != DEAD && (is_clock || is_convertable))
|
||||
invocation = "Mah'weyh pleggh at e'ntrath!"
|
||||
@@ -229,8 +229,8 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
do_sacrifice(L, invokers)
|
||||
animate(src, color = oldcolor, time = 5)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 5)
|
||||
Cult_team.check_size() // Triggers the eye glow or aura effects if the cult has grown large enough relative to the crew
|
||||
rune_in_use = FALSE
|
||||
|
||||
/obj/effect/rune/convert/proc/do_convert(mob/living/convertee, list/invokers)
|
||||
if(invokers.len < 2)
|
||||
for(var/M in invokers)
|
||||
@@ -315,6 +315,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
/obj/effect/rune/empower
|
||||
cultist_name = "Empower"
|
||||
cultist_desc = "allows cultists to prepare greater amounts of blood magic at far less of a cost."
|
||||
@@ -439,9 +440,9 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
light_range = 0
|
||||
update_light()
|
||||
|
||||
//Ritual of Dimensional Rending: Calls forth the avatar of Nar-Sie upon the station.
|
||||
//Ritual of Dimensional Rending: Calls forth the avatar of Nar'Sie upon the station.
|
||||
/obj/effect/rune/narsie
|
||||
cultist_name = "Nar-Sie"
|
||||
cultist_name = "Nar'Sie"
|
||||
cultist_desc = "tears apart dimensional barriers, calling forth the Geometer. Requires 9 invokers."
|
||||
invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!"
|
||||
req_cultists = 9
|
||||
@@ -479,8 +480,8 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
return
|
||||
if(locate(/obj/singularity/narsie) in GLOB.poi_list)
|
||||
for(var/M in invokers)
|
||||
to_chat(M, "<span class='warning'>Nar-Sie is already on this plane!</span>")
|
||||
log_game("Nar-Sie rune failed - already summoned")
|
||||
to_chat(M, "<span class='warning'>Nar'Sie is already on this plane!</span>")
|
||||
log_game("Nar'Sie rune failed - already summoned")
|
||||
return
|
||||
//BEGIN THE SUMMONING
|
||||
used = TRUE
|
||||
@@ -490,7 +491,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
sleep(40)
|
||||
if(src)
|
||||
color = RUNE_COLOR_RED
|
||||
new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn even if the rune has been removed
|
||||
new /obj/singularity/narsie/large/cult(T) //Causes Nar'Sie to spawn even if the rune has been removed
|
||||
|
||||
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
|
||||
if((istype(I, /obj/item/melee/cultblade/dagger) && iscultist(user)))
|
||||
@@ -512,7 +513,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
|
||||
icon_state = "1"
|
||||
color = RUNE_COLOR_MEDIUMRED
|
||||
var/static/revives_used = 0
|
||||
var/static/revives_used = -SOULS_TO_REVIVE // Cultists get one "free" revive
|
||||
|
||||
/obj/effect/rune/raise_dead/examine(mob/user)
|
||||
..()
|
||||
@@ -549,11 +550,12 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
invocation = initial(invocation)
|
||||
..()
|
||||
if(mob_to_revive.stat == DEAD)
|
||||
if(LAZYLEN(GLOB.sacrificed) <= revives_used)
|
||||
to_chat(user, "<span class='warning'>Your cult must carry out another sacrifice before it can revive a cultist!</span>")
|
||||
var/diff = LAZYLEN(GLOB.sacrificed) - revives_used - SOULS_TO_REVIVE
|
||||
if(diff < 0)
|
||||
to_chat(user, "<span class='warning'>Your cult must carry out [abs(diff)] more sacrifice\s before it can revive another cultist!</span>")
|
||||
fail_invoke()
|
||||
return
|
||||
revives_used++
|
||||
revives_used += SOULS_TO_REVIVE
|
||||
mob_to_revive.revive(1, 1) //This does remove traits and such, but the rune might actually see some use because of it!
|
||||
mob_to_revive.grab_ghost()
|
||||
if(!mob_to_revive.client || mob_to_revive.client.is_afk())
|
||||
@@ -618,9 +620,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
to_chat(user, "<span class='cultitalic'>The air above this rune has hardened into a barrier that will last [DisplayTimeText(TMR.timeToRun - world.time)].</span>")
|
||||
|
||||
/obj/effect/rune/wall/Destroy()
|
||||
density = FALSE
|
||||
GLOB.wall_runes -= src
|
||||
air_update_turf(1)
|
||||
return ..()
|
||||
|
||||
/obj/effect/rune/wall/BlockSuperconductivity()
|
||||
@@ -863,7 +863,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
var/obj/structure/emergency_shield/invoker/N = new(T)
|
||||
new_human.key = ghost_to_spawn.key
|
||||
SSticker.mode.add_cultist(new_human.mind, 0)
|
||||
to_chat(new_human, "<span class='cultitalic'><b>You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar-Sie, and you are to serve them at all costs.</b></span>")
|
||||
to_chat(new_human, "<span class='cultitalic'><b>You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar'Sie, and you are to serve them at all costs.</b></span>")
|
||||
|
||||
while(!QDELETED(src) && !QDELETED(user) && !QDELETED(new_human) && (user in T))
|
||||
if(user.stat || new_human.InCritical())
|
||||
@@ -946,7 +946,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
to_chat(user, "<span class='cultlarge'>Only one ritual site remains - it must be reserved for the final summoning!</span>")
|
||||
return
|
||||
if(!(place in summon_objective.summon_spots))
|
||||
to_chat(user, "<span class='cultlarge'>The Apocalypse rune will remove a ritual site, where Nar-sie can be summoned, it can only be scribed in [english_list(summon_objective.summon_spots)]!</span>")
|
||||
to_chat(user, "<span class='cultlarge'>The Apocalypse rune will remove a ritual site, where Nar'Sie can be summoned, it can only be scribed in [english_list(summon_objective.summon_spots)]!</span>")
|
||||
return
|
||||
summon_objective.summon_spots -= place
|
||||
rune_in_use = TRUE
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
held_items = list(null, null)
|
||||
bodyparts = list(/obj/item/bodypart/chest/devil, /obj/item/bodypart/head/devil, /obj/item/bodypart/l_arm/devil,
|
||||
/obj/item/bodypart/r_arm/devil, /obj/item/bodypart/r_leg/devil, /obj/item/bodypart/l_leg/devil)
|
||||
hud_type = /datum/hud/devil
|
||||
var/ascended = FALSE
|
||||
var/mob/living/oldform
|
||||
var/list/devil_overlays[DEVIL_TOTAL_LAYERS]
|
||||
@@ -172,14 +173,14 @@
|
||||
visible_message("<span class='danger'>[M] has punched [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has punched [src]!</span>")
|
||||
adjustBruteLoss(damage)
|
||||
add_logs(M, src, "attacked")
|
||||
log_combat(M, src, "attacked")
|
||||
updatehealth()
|
||||
if ("disarm")
|
||||
if (!lying && !ascended) //No stealing the arch devil's pitchfork.
|
||||
if (prob(5))
|
||||
Unconscious(40)
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
add_logs(M, src, "pushed")
|
||||
log_combat(M, src, "pushed")
|
||||
visible_message("<span class='danger'>[M] has pushed down [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has pushed down [src]!</span>")
|
||||
else
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
|
||||
/datum/disease/advance/sentient_disease/IsSame(datum/disease/D)
|
||||
if(istype(src, D.type))
|
||||
if(istype(D, /datum/disease/advance/sentient_disease))
|
||||
var/datum/disease/advance/sentient_disease/V = D
|
||||
if(V.overmind == overmind)
|
||||
return TRUE
|
||||
|
||||
@@ -107,7 +107,7 @@ the new instance inside the host to be updated to the template's stats.
|
||||
if(istype(B))
|
||||
to_chat(user, "<span class='notice'>[B.name]</span>")
|
||||
|
||||
/mob/camera/disease/say(message)
|
||||
/mob/camera/disease/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
return
|
||||
|
||||
/mob/camera/disease/Move(NewLoc, Dir = 0)
|
||||
@@ -245,7 +245,7 @@ the new instance inside the host to be updated to the template's stats.
|
||||
/mob/camera/disease/proc/set_following(mob/living/L)
|
||||
following_host = L
|
||||
if(!move_listener)
|
||||
move_listener = L.AddComponent(/datum/component/redirect, COMSIG_MOVABLE_MOVED, CALLBACK(src, .proc/follow_mob))
|
||||
move_listener = L.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/follow_mob)))
|
||||
else
|
||||
L.TakeComponent(move_listener)
|
||||
if(QDELING(move_listener))
|
||||
@@ -261,7 +261,7 @@ the new instance inside the host to be updated to the template's stats.
|
||||
index = index == hosts.len ? 1 : index + 1
|
||||
set_following(hosts[index])
|
||||
|
||||
/mob/camera/disease/proc/follow_mob(newloc, dir)
|
||||
/mob/camera/disease/proc/follow_mob(datum/source, newloc, dir)
|
||||
var/turf/T = get_turf(following_host)
|
||||
if(T)
|
||||
forceMove(T)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
var/list/name_source
|
||||
show_in_antagpanel = FALSE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
can_hijack = HIJACK_PREVENT
|
||||
|
||||
/datum/antagonist/ert/on_gain()
|
||||
update_name()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
var/obj/item/claymore/highlander/sword
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/highlander/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/L = owner.current || mob_override
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
var/give_objectives = TRUE
|
||||
var/give_equipment = TRUE
|
||||
|
||||
/datum/antagonist/ninja/New()
|
||||
if(helping_station)
|
||||
can_hijack = HIJACK_PREVENT
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_ninja_icons_added(M)
|
||||
@@ -137,6 +142,8 @@
|
||||
adj = "objectiveless"
|
||||
else
|
||||
return
|
||||
if(helping_station)
|
||||
can_hijack = HIJACK_PREVENT
|
||||
new_owner.assigned_role = ROLE_NINJA
|
||||
new_owner.special_role = ROLE_NINJA
|
||||
new_owner.add_antag_datum(src)
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
var/deconstruction_state = NUKESTATE_INTACT
|
||||
var/lights = ""
|
||||
var/interior = ""
|
||||
var/proper_bomb = TRUE //Please
|
||||
var/obj/effect/countdown/nuclearbomb/countdown
|
||||
var/static/bomb_set
|
||||
|
||||
/obj/machinery/nuclearbomb/Initialize()
|
||||
. = ..()
|
||||
@@ -227,7 +227,6 @@
|
||||
|
||||
/obj/machinery/nuclearbomb/process()
|
||||
if(timing && !exploding)
|
||||
bomb_set = TRUE
|
||||
if(detonation_timer < world.time)
|
||||
explode()
|
||||
else
|
||||
@@ -358,26 +357,23 @@
|
||||
S.switch_mode_to(initial(S.mode))
|
||||
S.alert = FALSE
|
||||
timing = FALSE
|
||||
bomb_set = TRUE
|
||||
detonation_timer = null
|
||||
countdown.stop()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/nuclearbomb/proc/set_active()
|
||||
if(safety && !bomb_set)
|
||||
if(safety)
|
||||
to_chat(usr, "<span class='danger'>The safety is still on.</span>")
|
||||
return
|
||||
timing = !timing
|
||||
if(timing)
|
||||
previous_level = get_security_level()
|
||||
bomb_set = TRUE
|
||||
detonation_timer = world.time + (timer_set * 10)
|
||||
for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
|
||||
S.switch_mode_to(TRACK_INFILTRATOR)
|
||||
countdown.start()
|
||||
set_security_level("delta")
|
||||
else
|
||||
bomb_set = FALSE
|
||||
detonation_timer = null
|
||||
set_security_level(previous_level)
|
||||
for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
|
||||
@@ -460,6 +456,7 @@
|
||||
/obj/machinery/nuclearbomb/beer
|
||||
name = "Nanotrasen-brand nuclear fission explosive"
|
||||
desc = "One of the more successful achievements of the Nanotrasen Corporate Warfare Division, their nuclear fission explosives are renowned for being cheap to produce and devastatingly effective. Signs explain that though this particular device has been decommissioned, every Nanotrasen station is equipped with an equivalent one, just in case. All Captains carefully guard the disk needed to detonate them - at least, the sign says they do. There seems to be a tap on the back."
|
||||
proper_bomb = FALSE
|
||||
var/obj/structure/reagent_dispensers/beerkeg/keg
|
||||
|
||||
/obj/machinery/nuclearbomb/beer/Initialize()
|
||||
@@ -498,7 +495,6 @@
|
||||
addtimer(CALLBACK(src, .proc/fizzbuzz), 110)
|
||||
|
||||
/obj/machinery/nuclearbomb/beer/proc/disarm()
|
||||
bomb_set = FALSE
|
||||
detonation_timer = null
|
||||
exploding = FALSE
|
||||
exploded = TRUE
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
|
||||
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
|
||||
var/nukeop_outfit = /datum/outfit/syndicate
|
||||
can_hijack = HIJACK_HIJACKER //Alternative way to wipe out the station.
|
||||
|
||||
/datum/antagonist/nukeop/proc/update_synd_icons_added(mob/living/M)
|
||||
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
|
||||
@@ -32,14 +33,9 @@
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
|
||||
H.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
|
||||
|
||||
H.equipOutfit(nukeop_outfit)
|
||||
|
||||
if(!isplasmaman(owner.current))
|
||||
return TRUE
|
||||
var/mob/living/carbon/human/plasma = owner.current
|
||||
|
||||
plasma.set_species(/datum/species/human) //Plasmamen burn up otherwise.
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/antagonist/nukeop/greet()
|
||||
@@ -250,8 +246,18 @@
|
||||
|
||||
/datum/team/nuclear/proc/disk_rescued()
|
||||
for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
|
||||
if(!D.onCentCom())
|
||||
return FALSE
|
||||
//If emergency shuttle is in transit disk is only safe on it
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
|
||||
if(!SSshuttle.emergency.is_in_shuttle_bounds(D))
|
||||
return FALSE
|
||||
//If shuttle escaped check if it's on centcom side
|
||||
else if(SSshuttle.emergency.mode == SHUTTLE_ENDGAME)
|
||||
if(!D.onCentCom())
|
||||
return FALSE
|
||||
else //Otherwise disk is safe when on station
|
||||
var/turf/T = get_turf(D)
|
||||
if(!T || !is_station_level(T.z))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/team/nuclear/proc/operatives_dead()
|
||||
@@ -267,7 +273,7 @@
|
||||
return S && (is_centcom_level(S.z) || T)
|
||||
|
||||
/datum/team/nuclear/proc/get_result()
|
||||
var/evacuation = SSshuttle.emergency.mode == SHUTTLE_ENDGAME
|
||||
var/evacuation = EMERGENCY_ESCAPED_OR_ENDGAMED
|
||||
var/disk_rescued = disk_rescued()
|
||||
var/syndies_didnt_escape = !syndies_escaped()
|
||||
var/station_was_nuked = SSticker.mode.station_was_nuked
|
||||
@@ -275,9 +281,9 @@
|
||||
|
||||
if(nuke_off_station == NUKE_SYNDICATE_BASE)
|
||||
return NUKE_RESULT_FLUKE
|
||||
else if(!disk_rescued && station_was_nuked && !syndies_didnt_escape)
|
||||
else if(station_was_nuked && !syndies_didnt_escape)
|
||||
return NUKE_RESULT_NUKE_WIN
|
||||
else if (!disk_rescued && station_was_nuked && syndies_didnt_escape)
|
||||
else if (station_was_nuked && syndies_didnt_escape)
|
||||
return NUKE_RESULT_NOSURVIVORS
|
||||
else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape)
|
||||
return NUKE_RESULT_WRONG_STATION
|
||||
@@ -289,7 +295,7 @@
|
||||
return NUKE_RESULT_CREW_WIN
|
||||
else if (!disk_rescued && operatives_dead())
|
||||
return NUKE_RESULT_DISK_LOST
|
||||
else if (!disk_rescued && evacuation)
|
||||
else if (!disk_rescued && evacuation)
|
||||
return NUKE_RESULT_DISK_STOLEN
|
||||
else
|
||||
return //Undefined result
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
show_in_antagpanel = FALSE
|
||||
var/datum/objective/mission
|
||||
var/datum/team/ert/ert_team
|
||||
can_hijack = HIJACK_PREVENT
|
||||
|
||||
/datum/antagonist/official/greet()
|
||||
to_chat(owner, "<B><font size=3 color=red>You are a CentCom Official.</font></B>")
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
#define INITIAL_CRYSTALS 5 // initial telecrystals in the boss' uplink
|
||||
|
||||
// Syndicate mutineer agents. They're agents selected by the Syndicate to take control of stations when assault teams like nuclear operatives cannot be sent.
|
||||
// They sent teams made of 3 agents, of which only one is woke up at round start. The others are, lore-wise, sleeping agents and must be implanted with the converter to wake up.
|
||||
// Mechanics wise, it's just 1 dude per team and he can convert maximum 2 more people of his choice, based on the implanter use var, Upon converting, the newly made guys are given access
|
||||
// to a storage implant they came with when the Syndicate sent them aboard, with one random low-cost traitor item. The initial agent also has this. The only difference between
|
||||
// initial agents and converted ones is that the initial agent has the items required to convert people and the AI.
|
||||
/datum/antagonist/overthrow
|
||||
name = "Syndicate mutineer"
|
||||
roundend_category = "syndicate mutineers"
|
||||
antagpanel_category = "Syndicate Mutineers"
|
||||
job_rank = ROLE_TRAITOR // simply use the traitor preference & jobban settings
|
||||
var/datum/team/overthrow/team
|
||||
var/static/list/possible_useful_items
|
||||
|
||||
// Overthrow agent. The idea is based on sleeping agents being sent as crewmembers, with one for each team that starts woken up who can also wake up others with their converter implant.
|
||||
// Obviously they can just convert anyone, the idea of sleeping agents is just lore. This also explains why this antag type has no deconversion way: they're traitors. Traitors cannot be
|
||||
// deconverted.
|
||||
// Generates the list of possible items for the storage implant given on_gain
|
||||
/datum/antagonist/overthrow/New()
|
||||
..()
|
||||
if(!possible_useful_items)
|
||||
possible_useful_items = list(/obj/item/gun/ballistic/automatic/pistol, /obj/item/storage/box/syndie_kit/throwing_weapons, /obj/item/pen/edagger, /obj/item/pen/sleepy, \
|
||||
/obj/item/soap/syndie, /obj/item/card/id/syndicate, /obj/item/storage/box/syndie_kit/chameleon)
|
||||
|
||||
// Sets objectives, equips all antags with the storage implant.
|
||||
/datum/antagonist/overthrow/on_gain()
|
||||
objectives += team.objectives
|
||||
owner.objectives += objectives
|
||||
..()
|
||||
owner.announce_objectives()
|
||||
equip_overthrow()
|
||||
owner.special_role = ROLE_OVERTHROW
|
||||
|
||||
/datum/antagonist/overthrow/on_removal()
|
||||
owner.special_role = null
|
||||
owner.objectives -= objectives
|
||||
..()
|
||||
|
||||
// Creates the overthrow team, or sets it. The objectives are static for all the team members.
|
||||
/datum/antagonist/overthrow/create_team(datum/team/overthrowers)
|
||||
if(!overthrowers)
|
||||
team = new()
|
||||
team.add_member(owner)
|
||||
name_team()
|
||||
team.create_objectives()
|
||||
else
|
||||
team = overthrowers
|
||||
team.add_member(owner)
|
||||
|
||||
// Used to name the team at round start. If no name is passed, a syndicate themed one is given randomly.
|
||||
/datum/antagonist/overthrow/proc/name_team()
|
||||
var/team_name = stripped_input(owner.current, "Name your team:", "Team name", , MAX_NAME_LEN)
|
||||
var/already_taken = FALSE
|
||||
for(var/datum/antagonist/overthrow/O in GLOB.antagonists)
|
||||
if(team_name == O.name)
|
||||
already_taken = TRUE
|
||||
break
|
||||
if(!team_name || already_taken) // basic protection against two teams with the same name. This could still happen with extreme unluck due to syndicate_name() but it shouldn't break anything.
|
||||
team.name = syndicate_name()
|
||||
to_chat(owner, "<span class='danger'>Since you gave [already_taken ? "an already used" : "no"] name, your team's name has been randomly generated: [team.name]!</span>")
|
||||
return
|
||||
team.name = team_name
|
||||
|
||||
// CLOWNMUT removal and HUD creation/being given
|
||||
/datum/antagonist/overthrow/apply_innate_effects()
|
||||
..()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
traitor_mob.dna.remove_mutation(CLOWNMUT)
|
||||
update_overthrow_icons_added()
|
||||
|
||||
// The opposite
|
||||
/datum/antagonist/overthrow/remove_innate_effects()
|
||||
update_overthrow_icons_removed()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
traitor_mob.dna.add_mutation(CLOWNMUT)
|
||||
..()
|
||||
|
||||
/datum/antagonist/overthrow/get_admin_commands()
|
||||
. = ..()
|
||||
.["Give storage with random item"] = CALLBACK(src,.proc/equip_overthrow)
|
||||
.["Give overthrow boss equip"] = CALLBACK(src,.proc/equip_initial_overthrow_agent)
|
||||
|
||||
// Dynamically creates the HUD for the team if it doesn't exist already, inserting it into the global huds list, and assigns it to the user. The index is saved into a var owned by the team datum.
|
||||
/datum/antagonist/overthrow/proc/update_overthrow_icons_added(datum/mind/traitor_mind)
|
||||
var/datum/atom_hud/antag/overthrowhud = GLOB.huds[team.hud_entry_num]
|
||||
if(!overthrowhud)
|
||||
overthrowhud = new()
|
||||
team.hud_entry_num = GLOB.huds.len + 1 // the index of the hud inside huds list
|
||||
GLOB.huds += overthrowhud
|
||||
overthrowhud.join_hud(owner.current)
|
||||
set_antag_hud(owner.current, "traitor")
|
||||
// Removes hud. Destroying the hud datum itself in case the team is deleted is done on team Destroy().
|
||||
/datum/antagonist/overthrow/proc/update_overthrow_icons_removed(datum/mind/traitor_mind)
|
||||
var/datum/atom_hud/antag/overthrowhud = GLOB.huds[team.hud_entry_num]
|
||||
if(overthrowhud)
|
||||
overthrowhud.leave_hud(owner.current)
|
||||
set_antag_hud(owner.current, null)
|
||||
|
||||
// Gives the storage implant with a random item. They're sleeping agents, after all.
|
||||
/datum/antagonist/overthrow/proc/equip_overthrow()
|
||||
if(!owner || !owner.current || !ishuman(owner.current)) // only equip existing human overthrow members. This excludes the AI, in particular.
|
||||
return
|
||||
var/obj/item/implant/storage/S = locate(/obj/item/implant/storage) in owner.current
|
||||
if(!S)
|
||||
S = new(owner.current)
|
||||
S.implant(owner.current)
|
||||
var/I = pick(possible_useful_items)
|
||||
if(ispath(I)) // in case some admin decides to fuck the list up for fun
|
||||
I = new I()
|
||||
SEND_SIGNAL(S, COMSIG_TRY_STORAGE_INSERT, I, null, TRUE, TRUE)
|
||||
|
||||
// Equip the initial overthrow agent. Manually called in overthrow gamemode, when the initial agents are chosen. Gives uplink, AI module board and the converter.
|
||||
/datum/antagonist/overthrow/proc/equip_initial_overthrow_agent()
|
||||
if(!owner || !owner.current || !ishuman(owner.current))
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
// Give uplink
|
||||
var/obj/item/uplink_holder = owner.equip_traitor(uplink_owner = src)
|
||||
var/datum/component/uplink/uplink = uplink_holder.GetComponent(/datum/component/uplink)
|
||||
uplink.telecrystals = INITIAL_CRYSTALS
|
||||
// Give AI hacking board
|
||||
var/obj/item/aiModule/core/full/overthrow/O = new(H)
|
||||
var/list/slots = list (
|
||||
"backpack" = SLOT_IN_BACKPACK,
|
||||
"left pocket" = SLOT_L_STORE,
|
||||
"right pocket" = SLOT_R_STORE
|
||||
)
|
||||
var/where = H.equip_in_one_of_slots(O, slots)
|
||||
if (!where)
|
||||
to_chat(H, "The Syndicate were unfortunately unable to get you the AI module.")
|
||||
else
|
||||
to_chat(H, "Use the AI board in your [where] to take control of the AI, as requested by the Syndicate.")
|
||||
// Give the implant converter
|
||||
var/obj/item/overthrow_converter/I = new(H)
|
||||
where = H.equip_in_one_of_slots(I, slots)
|
||||
if (!where)
|
||||
to_chat(H, "The Syndicate were unfortunately unable to get you a converter implant.")
|
||||
else
|
||||
to_chat(H, "Use the implanter in your [where] to wake up sleeping syndicate agents, so that they can aid you.")
|
||||
|
||||
/datum/antagonist/overthrow/get_team()
|
||||
return team
|
||||
|
||||
/datum/antagonist/overthrow/greet()
|
||||
to_chat(owner.current, "<B><font size=3 color=red>You are a syndicate sleeping agent!</font> <font size=2 color=red>Your job is to stage a swift, fairly bloodless coup. Your team has a two-use converter that can be used to convert \
|
||||
anyone you want, although mind shield implants need to be removed firstly for it to work. Your team also has a special version of the Syndicate module to be used to convert the AI, too. You \
|
||||
will be able to use the special storage implant you came aboard with, which contains a random, cheap item from our special selection which will aid in your mission. \
|
||||
Your team objective is to deal with the heads, the AI and a special target who angered us for several reasons which you're not entitled to know. Converting to your team will let us \
|
||||
take control of the station faster, so it should be prioritized, especially over killing, which should be avoided where possible. The other Syndicate teams are NOT friends and should not \
|
||||
be trusted.</font></B>")
|
||||
@@ -0,0 +1,56 @@
|
||||
/obj/item/overthrow_converter // nearly equal to an implanter, as an object
|
||||
name = "agent activation implant"
|
||||
desc = "Wakes up syndicate sleeping agents."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "implanter1"
|
||||
item_state = "syringe_0"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
materials = list(MAT_METAL=600, MAT_GLASS=200)
|
||||
var/uses = 2
|
||||
|
||||
/obj/item/overthrow_converter/proc/convert(mob/living/carbon/human/target, mob/living/carbon/human/user) // Should probably also delete any mindshield implant. Not sure.
|
||||
if(istype(target) && target.mind && user && user.mind)
|
||||
var/datum/mind/target_mind = target.mind
|
||||
var/datum/mind/user_mind = user.mind
|
||||
var/datum/antagonist/overthrow/TO = target_mind.has_antag_datum(/datum/antagonist/overthrow)
|
||||
var/datum/antagonist/overthrow/UO = user_mind.has_antag_datum(/datum/antagonist/overthrow)
|
||||
if(!UO)
|
||||
to_chat(user, "<span class='danger'>You don't know how to use this thing!</span>") // It needs a valid team to work, if you aren't an antag don't use this thing
|
||||
return FALSE
|
||||
if(TO)
|
||||
to_chat(user, "<span class='notice'>[target.name] woke up already, the implant would be ineffective against him!</span>")
|
||||
return FALSE
|
||||
target_mind.add_antag_datum(/datum/antagonist/overthrow, UO.team)
|
||||
log_combat(user, target, "implanted", "\a [name]")
|
||||
return TRUE
|
||||
|
||||
/obj/item/overthrow_converter/attack(mob/living/carbon/human/M, mob/living/carbon/human/user)
|
||||
if(!istype(M) || !istype(user))
|
||||
return
|
||||
if(!uses)
|
||||
to_chat(user,"<span class='warning'>The converter is empty!</span>")
|
||||
return
|
||||
if(M == user)
|
||||
to_chat(user,"<span class='warning'>You cannot convert yourself!</span>")
|
||||
return
|
||||
if(M.has_trait(TRAIT_MINDSHIELD))
|
||||
to_chat(user, "<span class='danger'>This mind is too strong to convert, try to remove whatever is protecting it first!</span>")
|
||||
return
|
||||
M.visible_message("<span class='warning'>[user] is attempting to implant [M].</span>")
|
||||
if(do_mob(user, M, 50))
|
||||
if(convert(M,user))
|
||||
M.visible_message("[user] has implanted [M].", "<span class='notice'>[user] implants you.</span>")
|
||||
uses--
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[user] fails to implant [M].</span>")
|
||||
|
||||
/obj/item/overthrow_converter/update_icon()
|
||||
if(uses)
|
||||
icon_state = "implanter1"
|
||||
else
|
||||
icon_state = "implanter0"
|
||||
@@ -0,0 +1,41 @@
|
||||
/datum/team/overthrow
|
||||
name = "overthrow" // The team name is set on creation by the leader.
|
||||
member_name = "syndicate agent"
|
||||
var/hud_entry_num // A number holding the hud's index inside 'huds' global list. Gets set on hud update, if a hud doesn't exist already. Must be a number, otherwise BYOND shits up with assoc lists and everything goes to hell.
|
||||
|
||||
/datum/team/overthrow/Destroy()
|
||||
var/datum/atom_hud/antag/overthrowhud = GLOB.huds[hud_entry_num]
|
||||
GLOB.huds -= GLOB.huds[hud_entry_num]
|
||||
qdel(overthrowhud)
|
||||
. = ..()
|
||||
|
||||
/datum/team/overthrow/proc/create_objectives()
|
||||
// Heads objective
|
||||
var/datum/objective/overthrow/heads/heads = new()
|
||||
heads.team = src
|
||||
heads.find_target()
|
||||
objectives += heads
|
||||
// AI objective
|
||||
var/datum/objective/overthrow/AI/AI = new()
|
||||
AI.team = src
|
||||
AI.update_explanation_text()
|
||||
objectives += AI
|
||||
// Target objective
|
||||
var/datum/objective/overthrow/target/target = new()
|
||||
target.team = src
|
||||
target.find_target()
|
||||
objectives += target
|
||||
addtimer(CALLBACK(src,.proc/update_objectives),OBJECTIVE_UPDATING_TIME,TIMER_UNIQUE)
|
||||
|
||||
/datum/team/overthrow/proc/update_objectives()
|
||||
var/datum/objective/overthrow/heads/heads_obj = locate() in objectives
|
||||
if(!heads_obj)
|
||||
heads_obj = new()
|
||||
heads_obj.team = src
|
||||
objectives += heads_obj
|
||||
for(var/i in members)
|
||||
var/datum/mind/M = i
|
||||
M.objectives += heads_obj
|
||||
heads_obj.find_targets()
|
||||
|
||||
addtimer(CALLBACK(src,.proc/update_objectives),OBJECTIVE_UPDATING_TIME,TIMER_UNIQUE)
|
||||
@@ -45,65 +45,43 @@
|
||||
/datum/team/pirate/proc/forge_objectives()
|
||||
var/datum/objective/loot/getbooty = new()
|
||||
getbooty.team = src
|
||||
getbooty.storage_area = locate(/area/shuttle/pirate/vault) in GLOB.sortedAreas
|
||||
getbooty.update_initial_value()
|
||||
for(var/obj/machinery/computer/piratepad_control/P in GLOB.machines)
|
||||
var/area/A = get_area(P)
|
||||
if(istype(A,/area/shuttle/pirate))
|
||||
getbooty.cargo_hold = P
|
||||
break
|
||||
getbooty.update_explanation_text()
|
||||
objectives += getbooty
|
||||
for(var/datum/mind/M in members)
|
||||
M.objectives |= objectives
|
||||
|
||||
|
||||
GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
|
||||
/obj/structure/reagent_dispensers/beerkeg,
|
||||
/mob/living/simple_animal/parrot,
|
||||
/obj/item/stack/sheet/mineral/gold,
|
||||
/obj/item/stack/sheet/mineral/diamond,
|
||||
/obj/item/stack/spacecash,
|
||||
/obj/item/melee/sabre,)))
|
||||
|
||||
/datum/objective/loot
|
||||
var/area/storage_area //Place where we we will look for the loot.
|
||||
var/obj/machinery/computer/piratepad_control/cargo_hold
|
||||
explanation_text = "Acquire valuable loot and store it in designated area."
|
||||
var/target_value = 50000
|
||||
var/initial_value = 0 //Things in the vault at spawn time do not count
|
||||
|
||||
|
||||
/datum/objective/loot/update_explanation_text()
|
||||
if(storage_area)
|
||||
explanation_text = "Acquire loot and store [target_value] of credits worth in [storage_area.name]."
|
||||
if(cargo_hold)
|
||||
var/area/storage_area = get_area(cargo_hold)
|
||||
explanation_text = "Acquire loot and store [target_value] of credits worth in [storage_area.name] cargo hold."
|
||||
|
||||
/datum/objective/loot/proc/loot_listing()
|
||||
//Lists notable loot.
|
||||
if(!storage_area)
|
||||
if(!cargo_hold || !cargo_hold.total_report)
|
||||
return "Nothing"
|
||||
var/list/loot_table = list()
|
||||
for(var/atom/movable/AM in storage_area.GetAllContents())
|
||||
if(is_type_in_typecache(AM,GLOB.pirate_loot_cache))
|
||||
var/lootname = AM.name
|
||||
var/count = 1
|
||||
if(istype(AM,/obj/item/stack)) //Ugh.
|
||||
var/obj/item/stack/S = AM
|
||||
lootname = S.singular_name
|
||||
count = S.amount
|
||||
if(!loot_table[lootname])
|
||||
loot_table[lootname] = count
|
||||
else
|
||||
loot_table[lootname] += count
|
||||
cargo_hold.total_report.total_value = sortTim(cargo_hold.total_report.total_value, cmp = /proc/cmp_numeric_dsc, associative = TRUE)
|
||||
var/count = 0
|
||||
var/list/loot_texts = list()
|
||||
for(var/key in loot_table)
|
||||
var/amount = loot_table[key]
|
||||
loot_texts += "[amount] [key][amount > 1 ? "s":""]"
|
||||
for(var/datum/export/E in cargo_hold.total_report.total_value)
|
||||
if(++count > 5)
|
||||
break
|
||||
loot_texts += E.total_printout(cargo_hold.total_report,notes = FALSE)
|
||||
return loot_texts.Join(", ")
|
||||
|
||||
/datum/objective/loot/proc/get_loot_value()
|
||||
if(!storage_area)
|
||||
return 0
|
||||
var/value = 0
|
||||
for(var/turf/T in storage_area.contents)
|
||||
value += export_item_and_contents(T,TRUE, TRUE, dry_run = TRUE)
|
||||
return value - initial_value
|
||||
|
||||
/datum/objective/loot/proc/update_initial_value()
|
||||
initial_value = get_loot_value()
|
||||
return cargo_hold.points
|
||||
|
||||
/datum/objective/loot/check_completion()
|
||||
return ..() || get_loot_value() >= target_value
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
speed = 1
|
||||
unique_name = TRUE
|
||||
hud_possible = list(ANTAG_HUD)
|
||||
hud_type = /datum/hud/revenant
|
||||
|
||||
var/essence = 75 //The resource, and health, of revenants.
|
||||
var/essence_regen_cap = 75 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
|
||||
@@ -143,10 +144,10 @@
|
||||
/mob/living/simple_animal/revenant/med_hud_set_status()
|
||||
return //we use no hud
|
||||
|
||||
/mob/living/simple_animal/revenant/say(message)
|
||||
/mob/living/simple_animal/revenant/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
if(!message)
|
||||
return
|
||||
log_talk(src,"[key_name(src)] : [message]",LOGSAY)
|
||||
src.log_talk(message, LOG_SAY)
|
||||
var/rendered = "<span class='revennotice'><b>[src]</b> says, \"[message]\"</span>"
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
if(isrevenant(M))
|
||||
@@ -199,7 +200,7 @@
|
||||
if(!essence)
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/revenant/dust()
|
||||
/mob/living/simple_animal/revenant/dust(just_ash, drop_items, force)
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/revenant/gib()
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
if(!msg)
|
||||
charge_counter = charge_max
|
||||
return
|
||||
log_talk(user,"RevenantTransmit: [key_name(user)]->[key_name(M)] : [msg]",LOGSAY)
|
||||
log_directed_talk(user, M, msg, LOG_SAY, "revenant whisper")
|
||||
to_chat(user, "<span class='revenboldnotice'>You transmit to [M]:</span> <span class='revennotice'>[msg]</span>")
|
||||
if(!M.anti_magic_check(FALSE, TRUE)) //hear no evil
|
||||
to_chat(M, "<span class='revenboldnotice'>You hear something behind you talking...</span> <span class='revennotice'>[msg]</span>")
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
. = ..()
|
||||
create_objectives()
|
||||
equip_rev()
|
||||
owner.current.log_message("<font color='red'>Has been converted to the revolution!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
owner.current.log_message("has been converted to the revolution!", LOG_ATTACK, color="red")
|
||||
|
||||
/datum/antagonist/rev/on_removal()
|
||||
remove_objectives()
|
||||
@@ -209,7 +209,7 @@
|
||||
|
||||
//blunt trauma deconversions call this through species.dm spec_attacked_by()
|
||||
/datum/antagonist/rev/proc/remove_revolutionary(borged, deconverter)
|
||||
log_attack("[owner.current] (Key: [key_name(owner.current)]) has been deconverted from the revolution by [deconverter] (Key: [key_name(deconverter)])!")
|
||||
log_attack("[key_name(owner.current)] has been deconverted from the revolution by [key_name(deconverter)]!")
|
||||
if(borged)
|
||||
message_admins("[ADMIN_LOOKUPFLW(owner.current)] has been borged while being a [name]")
|
||||
owner.special_role = null
|
||||
@@ -281,7 +281,7 @@
|
||||
var/list/datum/mind/heads = SSjob.get_all_heads()
|
||||
var/list/sec = SSjob.get_all_sec()
|
||||
|
||||
if(head_revolutionaries.len < max_headrevs && head_revolutionaries.len < round(heads.len - ((3 - sec.len) / 3)))
|
||||
if(head_revolutionaries.len < max_headrevs && head_revolutionaries.len < round(heads.len - ((8 - sec.len) / 3)))
|
||||
var/list/datum/mind/non_heads = members - head_revolutionaries
|
||||
var/list/datum/mind/promotable = list()
|
||||
for(var/datum/mind/khrushchev in non_heads)
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
del_on_death = 1
|
||||
deathmessage = "explodes with a sharp pop!"
|
||||
light_color = LIGHT_COLOR_CYAN
|
||||
hud_type = /datum/hud/swarmer
|
||||
var/resources = 0 //Resource points, generated by consuming metal/glass
|
||||
var/max_resources = 100
|
||||
|
||||
@@ -482,7 +483,7 @@
|
||||
if(ishuman(target) && (!H.handcuffed))
|
||||
H.handcuffed = new /obj/item/restraints/handcuffs/energy/used(H)
|
||||
H.update_handcuffed()
|
||||
add_logs(src, H, "handcuffed")
|
||||
log_combat(src, H, "handcuffed")
|
||||
|
||||
var/datum/effect_system/spark_spread/S = new
|
||||
S.set_up(4,0,get_turf(target))
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(owner.current && isAI(owner.current))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "Wishgranter Avatar"
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/wishgranter/proc/forge_objectives()
|
||||
var/datum/objective/hijack/hijack = new
|
||||
|
||||
@@ -110,6 +110,25 @@
|
||||
eat()
|
||||
return
|
||||
|
||||
/obj/singularity/wizard/attack_tk(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
GET_COMPONENT_FROM(insaneinthemembrane, /datum/component/mood, C)
|
||||
if(insaneinthemembrane.sanity < 15)
|
||||
return //they've already seen it and are about to die, or are just too insane to care
|
||||
to_chat(C, "<span class='userdanger'>OH GOD! NONE OF IT IS REAL! NONE OF IT IS REEEEEEEEEEEEEEEEEEEEEEEEAL!</span>")
|
||||
insaneinthemembrane.sanity = 0
|
||||
for(var/lore in typesof(/datum/brain_trauma/severe))
|
||||
C.gain_trauma(lore)
|
||||
addtimer(CALLBACK(src, /obj/singularity/wizard.proc/deranged, C), 100)
|
||||
|
||||
/obj/singularity/wizard/proc/deranged(mob/living/carbon/C)
|
||||
if(!C || C.stat == DEAD)
|
||||
return
|
||||
C.vomit(0, TRUE, TRUE, 3, TRUE)
|
||||
C.spew_organ(3, 2)
|
||||
C.death()
|
||||
|
||||
/obj/singularity/wizard/mapped/admin_investigate_setup()
|
||||
return
|
||||
|
||||
@@ -282,7 +301,7 @@
|
||||
switch(user.zone_selected)
|
||||
if(BODY_ZONE_PRECISE_MOUTH)
|
||||
var/wgw = sanitize(input(user, "What would you like the victim to say", "Voodoo", null) as text)
|
||||
target.say(wgw)
|
||||
target.say(wgw, forced = "voodoo doll")
|
||||
log_game("[key_name(user)] made [key_name(target)] say [wgw] with a voodoo doll.")
|
||||
if(BODY_ZONE_PRECISE_EYES)
|
||||
user.set_machine(src)
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
if(iscultist(user))
|
||||
to_chat(user, "<span class='cultlarge'>\"Come now, do not capture your bretheren's soul.\"</span>")
|
||||
return
|
||||
add_logs(user, M, "captured [M.name]'s soul", src)
|
||||
log_combat(user, M, "captured [M.name]'s soul", src)
|
||||
transfer_soul("VICTIM", M, user)
|
||||
|
||||
///////////////////Options for using captured souls///////////////////////////////////////
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
return 0
|
||||
|
||||
/datum/spellbook_entry/proc/Refund(mob/living/carbon/human/user,obj/item/spellbook/book) //return point value or -1 for failure
|
||||
var/area/wizard_station/A = locate() in GLOB.sortedAreas
|
||||
var/area/wizard_station/A = GLOB.areas_by_type[/area/wizard_station]
|
||||
if(!(user in A.contents))
|
||||
to_chat(user, "<span class='warning'>You can only refund spells at the wizard lair</span>")
|
||||
return -1
|
||||
@@ -316,6 +316,12 @@
|
||||
cost = 1
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/item/lockerstaff
|
||||
name = "Staff of the Locker"
|
||||
desc = "A staff that shoots lockers. It eats anyone it hits on its way, leaving a welded locker with your victims behind."
|
||||
item_path = /obj/item/gun/magic/staff/locker
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/item/scryingorb
|
||||
name = "Scrying Orb"
|
||||
desc = "An incandescent orb of crackling energy, using it will allow you to ghost while alive, allowing you to spy upon the station with ease. In addition, buying it will permanently grant you X-ray vision."
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
var/move_to_lair = TRUE
|
||||
var/outfit_type = /datum/outfit/wizard
|
||||
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/wizard/on_gain()
|
||||
register()
|
||||
equip_wizard()
|
||||
if(give_objectives)
|
||||
create_objectives()
|
||||
equip_wizard()
|
||||
if(move_to_lair)
|
||||
send_to_lair()
|
||||
. = ..()
|
||||
|
||||
@@ -101,6 +101,8 @@
|
||||
..()
|
||||
|
||||
/obj/item/assembly/screwdriver_act(mob/living/user, obj/item/I)
|
||||
if(..())
|
||||
return TRUE
|
||||
if(toggle_secure())
|
||||
to_chat(user, "<span class='notice'>\The [src] is ready!</span>")
|
||||
else
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
if(D.secondsElectrified)
|
||||
D.secondsElectrified = -1
|
||||
LAZYADD(D.shockedby, "\[[time_stamp()]\] [key_name(usr)]")
|
||||
add_logs(usr, D, "electrified")
|
||||
log_combat(usr, D, "electrified")
|
||||
else
|
||||
D.secondsElectrified = 0
|
||||
if(specialfunctions & SAFE)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define CONFUSION_STACK_MAX_MULTIPLIER 2
|
||||
/obj/item/assembly/flash
|
||||
name = "flash"
|
||||
desc = "A powerful and versatile flashbulb device, with applications ranging from disorienting attackers to acting as visual receptors in robot production."
|
||||
@@ -86,7 +87,7 @@
|
||||
if(isturf(target_loc) || (ismob(target_loc) && isturf(target_loc.loc)))
|
||||
return viewers(range, get_turf(target_loc))
|
||||
else
|
||||
return typecache_filter_list(target_loc.GetAllContents(), typecacheof(list(/mob/living)))
|
||||
return typecache_filter_list(target_loc.GetAllContents(), GLOB.typecache_living)
|
||||
|
||||
/obj/item/assembly/flash/proc/try_use_flash(mob/user = null)
|
||||
if(crit_fail || (world.time < last_trigger + cooldown))
|
||||
@@ -103,12 +104,17 @@
|
||||
/obj/item/assembly/flash/proc/flash_carbon(mob/living/carbon/M, mob/user, power = 15, targeted = TRUE, generic_message = FALSE)
|
||||
if(!istype(M))
|
||||
return
|
||||
add_logs(user, M, "[targeted? "flashed(targeted)" : "flashed(AOE)"]", src)
|
||||
if(user)
|
||||
log_combat(user, M, "[targeted? "flashed(targeted)" : "flashed(AOE)"]", src)
|
||||
else //caused by emp/remote signal
|
||||
M.log_message("was [targeted? "flashed(targeted)" : "flashed(AOE)"]",LOG_ATTACK)
|
||||
if(generic_message && M != user)
|
||||
to_chat(M, "<span class='disarm'>[src] emits a blinding light!</span>")
|
||||
if(targeted)
|
||||
if(M.flash_act(1, 1))
|
||||
M.confused = CLAMP(M.confused + power, 0, power * 2)
|
||||
if(M.confused < power)
|
||||
var/diff = power * CONFUSION_STACK_MAX_MULTIPLIER - M.confused
|
||||
M.confused += min(power, diff)
|
||||
if(user)
|
||||
terrible_conversion_proc(M, user)
|
||||
visible_message("<span class='disarm'>[user] blinds [M] with the flash!</span>")
|
||||
@@ -125,7 +131,8 @@
|
||||
to_chat(M, "<span class='danger'>[src] fails to blind you!</span>")
|
||||
else
|
||||
if(M.flash_act())
|
||||
M.confused = CLAMP(M.confused + power, 0, power * 2)
|
||||
var/diff = power * CONFUSION_STACK_MAX_MULTIPLIER - M.confused
|
||||
M.confused += min(power, diff)
|
||||
|
||||
/obj/item/assembly/flash/attack(mob/living/M, mob/user)
|
||||
if(!try_use_flash(user))
|
||||
@@ -135,10 +142,11 @@
|
||||
return TRUE
|
||||
else if(issilicon(M))
|
||||
var/mob/living/silicon/robot/R = M
|
||||
add_logs(user, R, "flashed", src)
|
||||
log_combat(user, R, "flashed", src)
|
||||
update_icon(1)
|
||||
M.Knockdown(rand(80,120))
|
||||
R.confused = CLAMP(R.confused + 5, 0, 10)
|
||||
R.Knockdown(rand(80,120))
|
||||
var/diff = 5 * CONFUSION_STACK_MAX_MULTIPLIER - M.confused
|
||||
R.confused += min(5, diff)
|
||||
R.flash_act(affect_silicon = 1)
|
||||
user.visible_message("<span class='disarm'>[user] overloads [R]'s sensors with the flash!</span>", "<span class='danger'>You overload [R]'s sensors with the flash!</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
var/scanning = FALSE
|
||||
var/health_scan
|
||||
var/alarm_health = 0
|
||||
var/alarm_health = HEALTH_THRESHOLD_CRIT
|
||||
|
||||
/obj/item/assembly/health/examine(mob/user)
|
||||
..()
|
||||
@@ -31,11 +31,11 @@
|
||||
return secured
|
||||
|
||||
/obj/item/assembly/health/multitool_act(mob/living/user, obj/item/I)
|
||||
if(alarm_health == 0)
|
||||
alarm_health = -90
|
||||
if(alarm_health == HEALTH_THRESHOLD_CRIT)
|
||||
alarm_health = HEALTH_THRESHOLD_DEAD
|
||||
to_chat(user, "<span class='notice'>You toggle [src] to \"detect death\" mode.</span>")
|
||||
else
|
||||
alarm_health = 0
|
||||
alarm_health = HEALTH_THRESHOLD_CRIT
|
||||
to_chat(user, "<span class='notice'>You toggle [src] to \"detect critical state\" mode.</span>")
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -97,6 +97,8 @@
|
||||
a_right.attack_hand()
|
||||
|
||||
/obj/item/assembly_holder/screwdriver_act(mob/user, obj/item/tool)
|
||||
if(..())
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You disassemble [src]!</span>")
|
||||
if(a_left)
|
||||
a_left.on_detach()
|
||||
|
||||
@@ -164,9 +164,9 @@
|
||||
|
||||
/obj/item/assembly/infra/proc/switchListener(turf/newloc)
|
||||
QDEL_NULL(listener)
|
||||
listener = newloc.AddComponent(/datum/component/redirect, COMSIG_ATOM_EXITED, CALLBACK(src, .proc/check_exit))
|
||||
listener = newloc.AddComponent(/datum/component/redirect, list(COMSIG_ATOM_EXITED = CALLBACK(src, .proc/check_exit)))
|
||||
|
||||
/obj/item/assembly/infra/proc/check_exit(atom/movable/offender)
|
||||
/obj/item/assembly/infra/proc/check_exit(datum/source, atom/movable/offender)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(offender == src || istype(offender,/obj/effect/beam/i_beam))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user