mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 12:41:09 +01:00
Merge branch 'master' of https://github.com/tgstation/-tg-station into arguablyallgunsareenergygunsandallbeamsareprojectiles
Conflicts: code/modules/projectiles/guns/energy/laser.dm
This commit is contained in:
@@ -4,6 +4,10 @@
|
||||
if (!key || !address || !computer_id)
|
||||
log_access("Failed Login (invalid data): [key] [address]-[computer_id]")
|
||||
return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided invalid or blank information to the server on connection (byond username, IP, and Computer ID.) Provided information for reference: Username:'[key]' IP:'[address]' Computer ID:'[computer_id]'. (If you continue to get this error, please restart byond or contact byond support.)")
|
||||
|
||||
if (computer_id == 2147483647) //this cid causes stickybans to go haywire
|
||||
log_access("Failed Login (invalid cid): [key] [address]-[computer_id]")
|
||||
return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided an invalid Computer ID.)")
|
||||
var/admin = 0
|
||||
var/ckey = ckey(key)
|
||||
if((ckey in admin_datums) || (ckey in deadmins))
|
||||
|
||||
@@ -201,7 +201,7 @@ var/global/floorIsLava = 0
|
||||
dat+="<BR><A href='?src=\ref[src];ac_menu_wanted=1'>[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue</A>"
|
||||
dat+="<BR><A href='?src=\ref[src];ac_menu_censor_story=1'>Censor Feed Stories</A>"
|
||||
dat+="<BR><A href='?src=\ref[src];ac_menu_censor_channel=1'>Mark Feed Channel with Nanotrasen D-Notice (disables and locks the channel.</A>"
|
||||
dat+="<BR><HR><A href='?src=\ref[src];ac_set_signature=1'>The newscaster recognises you as:<BR> <FONT COLOR='green'>[src.admincaster_signature]</FONT></A>"
|
||||
dat+="<BR><HR><A href='?src=\ref[src];ac_set_signature=1'>The newscaster recognises you as:<BR> <FONT COLOR='green'>[src.admin_signature]</FONT></A>"
|
||||
if(1)
|
||||
dat+= "Station Feed Channels<HR>"
|
||||
if( isemptylist(news_network.network_channels) )
|
||||
@@ -217,13 +217,13 @@ var/global/floorIsLava = 0
|
||||
if(2)
|
||||
dat+="Creating new Feed Channel..."
|
||||
dat+="<HR><B><A href='?src=\ref[src];ac_set_channel_name=1'>Channel Name</A>:</B> [src.admincaster_feed_channel.channel_name]<BR>"
|
||||
dat+="<B><A href='?src=\ref[src];ac_set_signature=1'>Channel Author</A>:</B> <FONT COLOR='green'>[src.admincaster_signature]</FONT><BR>"
|
||||
dat+="<B><A href='?src=\ref[src];ac_set_signature=1'>Channel Author</A>:</B> <FONT COLOR='green'>[src.admin_signature]</FONT><BR>"
|
||||
dat+="<B><A href='?src=\ref[src];ac_set_channel_lock=1'>Will Accept Public Feeds</A>:</B> [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]<BR><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];ac_submit_new_channel=1'>Submit</A><BR><BR><A href='?src=\ref[src];ac_setScreen=[0]'>Cancel</A><BR>"
|
||||
if(3)
|
||||
dat+="Creating new Feed Message..."
|
||||
dat+="<HR><B><A href='?src=\ref[src];ac_set_channel_receiving=1'>Receiving Channel</A>:</B> [src.admincaster_feed_channel.channel_name]<BR>" //MARK
|
||||
dat+="<B>Message Author:</B> <FONT COLOR='green'>[src.admincaster_signature]</FONT><BR>"
|
||||
dat+="<B>Message Author:</B> <FONT COLOR='green'>[src.admin_signature]</FONT><BR>"
|
||||
dat+="<B><A href='?src=\ref[src];ac_set_new_message=1'>Message Body</A>:</B> [src.admincaster_feed_message.returnBody(-1)] <BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];ac_submit_new_message=1'>Submit</A><BR><BR><A href='?src=\ref[src];ac_setScreen=[0]'>Cancel</A><BR>"
|
||||
if(4)
|
||||
@@ -339,7 +339,7 @@ var/global/floorIsLava = 0
|
||||
if(wanted_already)
|
||||
dat+="<B>Wanted Issue created by:</B><FONT COLOR='green'>[news_network.wanted_issue.scannedUser]</FONT><BR>"
|
||||
else
|
||||
dat+="<B>Wanted Issue will be created under prosecutor:</B><FONT COLOR='green'>[src.admincaster_signature]</FONT><BR>"
|
||||
dat+="<B>Wanted Issue will be created under prosecutor:</B><FONT COLOR='green'>[src.admin_signature]</FONT><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];ac_submit_wanted=[end_param]'>[(wanted_already) ? ("Edit Issue") : ("Submit")]</A>"
|
||||
if(wanted_already)
|
||||
dat+="<BR><A href='?src=\ref[src];ac_cancel_wanted=1'>Take down Issue</A>"
|
||||
@@ -380,19 +380,6 @@ var/global/floorIsLava = 0
|
||||
onclose(usr, "admincaster_main")
|
||||
|
||||
|
||||
|
||||
/datum/admins/proc/Jobbans()
|
||||
if(!check_rights(R_BAN)) return
|
||||
|
||||
var/dat = "<B>Job Bans!</B><HR><table>"
|
||||
for(var/t in jobban_keylist)
|
||||
var/r = t
|
||||
if( findtext(r,"##") )
|
||||
r = copytext( r, 1, findtext(r,"##") )//removes the description
|
||||
dat += text("<tr><td>[t] (<A href='?src=\ref[src];removejobban=[r]'>unban</A>)</td></tr>")
|
||||
dat += "</table>"
|
||||
usr << browse(dat, "window=ban;size=400x400")
|
||||
|
||||
/datum/admins/proc/Game()
|
||||
if(!check_rights(0)) return
|
||||
|
||||
@@ -695,14 +682,6 @@ var/global/floorIsLava = 0
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled guests game entering [guests_allowed?"":"dis"]allowed.</span>")
|
||||
feedback_add_details("admin_verb","TGU") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/unjobban_panel()
|
||||
set name = "Unjobban Panel"
|
||||
set category = "Admin"
|
||||
if (src.holder)
|
||||
src.holder.unjobbanpanel()
|
||||
feedback_add_details("admin_verb","UJBP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/datum/admins/proc/output_ai_laws()
|
||||
var/ai_number = 0
|
||||
for(var/mob/living/silicon/S in mob_list)
|
||||
|
||||
@@ -64,8 +64,6 @@ var/list/admin_verbs_admin = list(
|
||||
)
|
||||
var/list/admin_verbs_ban = list(
|
||||
/client/proc/unban_panel,
|
||||
/client/proc/jobbans,
|
||||
/client/proc/unjobban_panel,
|
||||
/client/proc/DB_ban_panel,
|
||||
/client/proc/stickybanpanel
|
||||
)
|
||||
@@ -120,7 +118,6 @@ var/list/admin_verbs_debug = list(
|
||||
/client/proc/cmd_admin_list_open_jobs,
|
||||
/client/proc/Debug2,
|
||||
/client/proc/cmd_debug_make_powernets,
|
||||
/client/proc/debug_controller,
|
||||
/client/proc/cmd_debug_mob_lists,
|
||||
/client/proc/cmd_admin_delete,
|
||||
/client/proc/cmd_debug_del_all,
|
||||
@@ -205,7 +202,6 @@ var/list/admin_verbs_hideable = list(
|
||||
/client/proc/Debug2,
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/cmd_debug_make_powernets,
|
||||
/client/proc/debug_controller,
|
||||
/client/proc/startSinglo,
|
||||
/client/proc/cmd_debug_mob_lists,
|
||||
/client/proc/cmd_debug_del_all,
|
||||
@@ -277,6 +273,7 @@ var/list/admin_verbs_hideable = list(
|
||||
/client/proc/cmd_admin_grantfullaccess,
|
||||
/client/proc/cmd_admin_areatest,
|
||||
/client/proc/readmin,
|
||||
/client/proc/reload_nanoui_resources
|
||||
)
|
||||
if(holder)
|
||||
verbs.Remove(holder.rank.adds)
|
||||
@@ -371,17 +368,6 @@ var/list/admin_verbs_hideable = list(
|
||||
feedback_add_details("admin_verb","CHA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/client/proc/jobbans()
|
||||
set name = "Display Job bans"
|
||||
set category = "Admin"
|
||||
if(holder)
|
||||
if(config.ban_legacy_system)
|
||||
holder.Jobbans()
|
||||
else
|
||||
holder.DB_ban_panel()
|
||||
feedback_add_details("admin_verb","VJB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/client/proc/unban_panel()
|
||||
set name = "Unban Panel"
|
||||
set category = "Admin"
|
||||
@@ -580,7 +566,7 @@ var/list/admin_verbs_hideable = list(
|
||||
var/list/Lines = file2list("config/admins.txt")
|
||||
for(var/line in Lines)
|
||||
var/list/splitline = text2list(line, " = ")
|
||||
if(lowertext(splitline[1]) == ckey)
|
||||
if(ckey(splitline[1]) == ckey)
|
||||
if(splitline.len >= 2)
|
||||
rank = ckeyEx(splitline[2])
|
||||
break
|
||||
|
||||
+27
-100
@@ -1,109 +1,36 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
|
||||
|
||||
var/jobban_runonce // Updates legacy bans with new info
|
||||
var/jobban_keylist[0] //to store the keys & ranks
|
||||
|
||||
/proc/jobban_fullban(mob/M, rank, reason)
|
||||
if (!M || !M.key) return
|
||||
jobban_keylist.Add(text("[M.ckey] - [rank] ## [reason]"))
|
||||
jobban_savebanfile()
|
||||
|
||||
/proc/jobban_client_fullban(ckey, rank)
|
||||
if (!ckey || !rank) return
|
||||
jobban_keylist.Add(text("[ckey] - [rank]"))
|
||||
jobban_savebanfile()
|
||||
|
||||
//returns a reason if M is banned from rank, returns 0 otherwise
|
||||
/proc/jobban_isbanned(mob/M, rank)
|
||||
if(M && rank)
|
||||
for (var/s in jobban_keylist)
|
||||
if( findtext(s,"[M.ckey] - [rank]") == 1 )
|
||||
var/startpos = findtext(s, "## ")+3
|
||||
if(startpos && startpos<length(s))
|
||||
var/text = copytext(s, startpos, 0)
|
||||
if(text)
|
||||
return text
|
||||
return "Reason Unspecified"
|
||||
if(!M || !istype(M) || !M.ckey)
|
||||
return 0
|
||||
|
||||
if(!M.client) //no cache. fallback to a DBQuery
|
||||
var/DBQuery/query = dbcon.NewQuery("SELECT reason FROM [format_table_name("ban")] WHERE ckey = '[sanitizeSQL(M.ckey)]' AND job = '[sanitizeSQL(rank)]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
|
||||
if(!query.Execute())
|
||||
log_game("SQL ERROR obtaining jobbans. Error : \[[query.ErrorMsg()]\]\n")
|
||||
return
|
||||
if(query.NextRow())
|
||||
var/reason = query.item[1]
|
||||
return reason ? reason : 1 //we don't want to return "" if there is no ban reason, as that would evaluate to false
|
||||
else
|
||||
return 0
|
||||
|
||||
if(!M.client.jobbancache)
|
||||
jobban_buildcache(M.client)
|
||||
|
||||
if(rank in M.client.jobbancache)
|
||||
var/reason = M.client.jobbancache[rank]
|
||||
return (reason) ? reason : 1 //see above for why we need to do this
|
||||
return 0
|
||||
|
||||
/*
|
||||
DEBUG
|
||||
/mob/verb/list_all_jobbans()
|
||||
set name = "list all jobbans"
|
||||
|
||||
for(var/s in jobban_keylist)
|
||||
world << s
|
||||
|
||||
/mob/verb/reload_jobbans()
|
||||
set name = "reload jobbans"
|
||||
|
||||
jobban_loadbanfile()
|
||||
*/
|
||||
|
||||
/proc/jobban_loadbanfile()
|
||||
if(config.ban_legacy_system)
|
||||
var/savefile/S=new("data/job_full.ban")
|
||||
S["keys[0]"] >> jobban_keylist
|
||||
log_admin("Loading jobban_rank")
|
||||
S["runonce"] >> jobban_runonce
|
||||
|
||||
if (!length(jobban_keylist))
|
||||
jobban_keylist=list()
|
||||
log_admin("jobban_keylist was empty")
|
||||
else
|
||||
if(!establish_db_connection())
|
||||
world.log << "Database connection failed. Reverting to the legacy ban system."
|
||||
diary << "Database connection failed. Reverting to the legacy ban system."
|
||||
config.ban_legacy_system = 1
|
||||
jobban_loadbanfile()
|
||||
/proc/jobban_buildcache(client/C)
|
||||
if(C && istype(C))
|
||||
C.jobbancache = list()
|
||||
var/DBQuery/query = dbcon.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.Execute())
|
||||
log_game("SQL ERROR obtaining jobbans. Error : \[[query.ErrorMsg()]\]\n")
|
||||
return
|
||||
|
||||
//Job permabans
|
||||
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, job FROM [format_table_name("ban")] WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)")
|
||||
query.Execute()
|
||||
|
||||
while(query.NextRow())
|
||||
var/ckey = query.item[1]
|
||||
var/job = query.item[2]
|
||||
|
||||
jobban_keylist.Add("[ckey] - [job]")
|
||||
|
||||
//Job tempbans
|
||||
var/DBQuery/query1 = dbcon.NewQuery("SELECT ckey, job FROM [format_table_name("ban")] WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()")
|
||||
query1.Execute()
|
||||
|
||||
while(query1.NextRow())
|
||||
var/ckey = query1.item[1]
|
||||
var/job = query1.item[2]
|
||||
|
||||
jobban_keylist.Add("[ckey] - [job]")
|
||||
|
||||
/proc/jobban_savebanfile()
|
||||
var/savefile/S=new("data/job_full.ban")
|
||||
S["keys[0]"] << jobban_keylist
|
||||
|
||||
/proc/jobban_unban(mob/M, rank)
|
||||
jobban_remove("[M.ckey] - [rank]")
|
||||
jobban_savebanfile()
|
||||
|
||||
C.jobbancache[query.item[1]] = query.item[2]
|
||||
|
||||
/proc/ban_unban_log_save(var/formatted_log)
|
||||
text2file(formatted_log,"data/ban_unban_log.txt")
|
||||
|
||||
|
||||
/proc/jobban_updatelegacybans()
|
||||
if(!jobban_runonce)
|
||||
log_admin("Updating jobbanfile!")
|
||||
// Updates bans.. Or fixes them. Either way.
|
||||
for(var/T in jobban_keylist)
|
||||
if(!T) continue
|
||||
jobban_runonce++ //don't run this update again
|
||||
|
||||
|
||||
/proc/jobban_remove(X)
|
||||
for (var/i = 1; i <= length(jobban_keylist); i++)
|
||||
if( findtext(jobban_keylist[i], "[X]") )
|
||||
jobban_keylist.Remove(jobban_keylist[i])
|
||||
jobban_savebanfile()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -12,7 +12,7 @@ var/list/admin_datums = list()
|
||||
var/datum/newscaster/feed_message/admincaster_feed_message = new /datum/newscaster/feed_message
|
||||
var/datum/newscaster/wanted_message/admincaster_wanted_message = new /datum/newscaster/wanted_message
|
||||
var/datum/newscaster/feed_channel/admincaster_feed_channel = new /datum/newscaster/feed_channel
|
||||
var/admincaster_signature
|
||||
var/admin_signature
|
||||
|
||||
/datum/admins/New(datum/admin_rank/R, ckey)
|
||||
if(!ckey)
|
||||
@@ -26,7 +26,7 @@ var/list/admin_datums = list()
|
||||
throw EXCEPTION("Admin datum created without a rank")
|
||||
return
|
||||
rank = R
|
||||
admincaster_signature = "Nanotrasen Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
|
||||
admin_signature = "Nanotrasen Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
|
||||
admin_datums[ckey] = src
|
||||
|
||||
/datum/admins/proc/associate(client/C)
|
||||
|
||||
@@ -1,276 +0,0 @@
|
||||
var/savefile/Banlistjob
|
||||
|
||||
|
||||
/proc/_jobban_isbanned(client/clientvar, rank)
|
||||
if(!clientvar) return 1
|
||||
ClearTempbansjob()
|
||||
var/id = clientvar.computer_id
|
||||
var/key = clientvar.ckey
|
||||
if (guest_jobbans(rank))
|
||||
if(config.guest_jobban && IsGuestKey(key))
|
||||
return 1
|
||||
Banlistjob.cd = "/base"
|
||||
if (Banlistjob.dir.Find("[key][id][rank]"))
|
||||
return 1
|
||||
|
||||
Banlistjob.cd = "/base"
|
||||
for (var/A in Banlistjob.dir)
|
||||
Banlistjob.cd = "/base/[A]"
|
||||
if ((id == Banlistjob["id"] || key == Banlistjob["key"]) && rank == Banlistjob["rank"])
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
///proc/UpdateTime() //No idea why i made this a proc.
|
||||
// CMinutes = (world.realtime / 10) / 60
|
||||
// return 1
|
||||
|
||||
/proc/LoadBansjob()
|
||||
|
||||
Banlistjob = new("data/job_fullnew.bdb")
|
||||
log_admin("Loading Banlistjob")
|
||||
|
||||
if (!length(Banlistjob.dir)) log_admin("Banlistjob is empty.")
|
||||
|
||||
if (!Banlistjob.dir.Find("base"))
|
||||
log_admin("Banlistjob missing base dir.")
|
||||
Banlistjob.dir.Add("base")
|
||||
Banlistjob.cd = "/base"
|
||||
else if (Banlistjob.dir.Find("base"))
|
||||
Banlistjob.cd = "/base"
|
||||
|
||||
ClearTempbansjob()
|
||||
return 1
|
||||
|
||||
/proc/ClearTempbansjob()
|
||||
UpdateTime()
|
||||
|
||||
Banlistjob.cd = "/base"
|
||||
for (var/A in Banlistjob.dir)
|
||||
Banlistjob.cd = "/base/[A]"
|
||||
//if (!Banlistjob["key"] || !Banlistjob["id"])
|
||||
// RemoveBanjob(A, "full")
|
||||
// log_admin("Invalid Ban.")
|
||||
// message_admins("Invalid Ban.")
|
||||
// continue
|
||||
|
||||
if (!Banlistjob["temp"]) continue
|
||||
if (CMinutes >= Banlistjob["minutes"]) RemoveBanjob(A)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
/proc/AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, rank)
|
||||
UpdateTime()
|
||||
var/bantimestamp
|
||||
if (temp)
|
||||
UpdateTime()
|
||||
bantimestamp = CMinutes + minutes
|
||||
if(rank == "Heads")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Head of Personnel")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Captain")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Head of Security")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer")
|
||||
return 1
|
||||
if(rank == "Security")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Head of Security")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Warden")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Detective")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Security Officer")
|
||||
return 1
|
||||
if(rank == "Engineering")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Station Engineer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Atmospheric Technician")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer")
|
||||
return 1
|
||||
if(rank == "Research")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Scientist")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Geneticist")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director")
|
||||
return 1
|
||||
if(rank == "Medical")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Geneticist")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Medical Doctor")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chemist")
|
||||
return 1
|
||||
if(rank == "CE_Station_Engineer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Station Engineer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer")
|
||||
return 1
|
||||
if(rank == "CE_Atmospheric_Tech")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Atmospheric Technician")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer")
|
||||
return 1
|
||||
if(rank == "CE_Shaft_Miner")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Shaft Miner")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Engineer")
|
||||
return 1
|
||||
if(rank == "Chemist_RD_CMO")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chemist")
|
||||
return 1
|
||||
if(rank == "Geneticist_RD_CMO")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Geneticist")
|
||||
return 1
|
||||
if(rank == "MD_CMO")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Medical Doctor")
|
||||
return 1
|
||||
if(rank == "Scientist_RD")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Scientist")
|
||||
return 1
|
||||
if(rank == "AI_Cyborg")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Cyborg")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "AI")
|
||||
return 1
|
||||
if(rank == "Detective_HoS")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Detective")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Head of Security")
|
||||
return 1
|
||||
if(rank == "Virologist_RD_CMO")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Chief Medical Officer")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Research Director")
|
||||
AddBanjob(ckey, computerid, reason, bannedby, temp, minutes, "Virologist")
|
||||
return 1
|
||||
|
||||
Banlistjob.cd = "/base"
|
||||
if ( Banlistjob.dir.Find("[ckey][computerid][rank]") )
|
||||
usr << text("<span class='danger'>Banjob already exists.</span>")
|
||||
return 0
|
||||
else
|
||||
Banlistjob.dir.Add("[ckey][computerid][rank]")
|
||||
Banlistjob.cd = "/base/[ckey][computerid][rank]"
|
||||
Banlistjob["key"] << ckey
|
||||
Banlistjob["id"] << computerid
|
||||
Banlistjob["rank"] << rank
|
||||
Banlistjob["reason"] << reason
|
||||
Banlistjob["bannedby"] << bannedby
|
||||
Banlistjob["temp"] << temp
|
||||
if (temp)
|
||||
Banlistjob["minutes"] << bantimestamp
|
||||
|
||||
return 1
|
||||
|
||||
/proc/RemoveBanjob(foldername)
|
||||
var/key
|
||||
var/id
|
||||
var/rank
|
||||
Banlistjob.cd = "/base/[foldername]"
|
||||
Banlistjob["key"] >> key
|
||||
Banlistjob["id"] >> id
|
||||
Banlistjob["rank"] >> rank
|
||||
Banlistjob.cd = "/base"
|
||||
|
||||
if (!Banlistjob.dir.Remove(foldername)) return 0
|
||||
|
||||
if(!usr)
|
||||
log_admin("Banjob Expired: [key]")
|
||||
message_admins("Banjob Expired: [key]")
|
||||
else
|
||||
log_admin("[key_name(usr)] unjobbanned [key] from [rank]")
|
||||
message_admins("[key_name_admin(usr)] unjobbanned:[key] from [rank]")
|
||||
ban_unban_log_save("[key_name(usr)] unjobbanned [key] from [rank]")
|
||||
feedback_inc("ban_job_unban",1)
|
||||
feedback_add_details("ban_job_unban","- [rank]")
|
||||
|
||||
for (var/A in Banlistjob.dir)
|
||||
Banlistjob.cd = "/base/[A]"
|
||||
if ((key == Banlistjob["key"] || id == Banlistjob["id"]) && (rank == Banlistjob["rank"]))
|
||||
Banlistjob.cd = "/base"
|
||||
Banlistjob.dir.Remove(A)
|
||||
continue
|
||||
|
||||
return 1
|
||||
|
||||
/proc/GetExpjob(minutes as num)
|
||||
UpdateTime()
|
||||
var/exp = minutes - CMinutes
|
||||
if (exp <= 0)
|
||||
return 0
|
||||
else
|
||||
var/timeleftstring
|
||||
if (exp >= 1440) //1440 = 1 day in minutes
|
||||
timeleftstring = "[round(exp / 1440, 0.1)] Days"
|
||||
else if (exp >= 60) //60 = 1 hour in minutes
|
||||
timeleftstring = "[round(exp / 60, 0.1)] Hours"
|
||||
else
|
||||
timeleftstring = "[exp] Minutes"
|
||||
return timeleftstring
|
||||
|
||||
/datum/admins/proc/unjobbanpanel()
|
||||
var/count = 0
|
||||
var/dat
|
||||
//var/dat = "<HR><B>Unban Player:</B> \blue(U) = Unban , (E) = Edit Ban\green (Total<HR><table border=1 rules=all frame=void cellspacing=0 cellpadding=3 >"
|
||||
Banlistjob.cd = "/base"
|
||||
for (var/A in Banlistjob.dir)
|
||||
count++
|
||||
Banlistjob.cd = "/base/[A]"
|
||||
dat += text("<tr><td><A href='?src=\ref[src];unjobbanf=[Banlistjob["key"]][Banlistjob["id"]][Banlistjob["rank"]]'>(U)</A> Key: <B>[Banlistjob["key"]] </B>Rank: <B>[Banlistjob["rank"]]</B></td><td> ([Banlistjob["temp"] ? "[GetExpjob(Banlistjob["minutes"]) ? GetExpjob(Banlistjob["minutes"]) : "Removal pending" ]" : "Permaban"])</td><td>(By: [Banlistjob["bannedby"]])</td><td>(Reason: [Banlistjob["reason"]])</td></tr>")
|
||||
|
||||
dat += "</table>"
|
||||
dat = "<HR><B>Bans:</B> <FONT COLOR=blue>(U) = Unban , </FONT> - <FONT COLOR=green>([count] Bans)</FONT><HR><table border=1 rules=all frame=void cellspacing=0 cellpadding=3 >[dat]"
|
||||
usr << browse(dat, "window=unbanp;size=875x400")
|
||||
|
||||
/*/datum/admins/proc/permjobban(ckey, computerid, reason, bannedby, temp, minutes, rank)
|
||||
if(AddBanjob(ckey, computerid, reason, usr.ckey, 0, 0, job))
|
||||
M << "\red<BIG><B>You have been banned from [job] by [usr.client.ckey].\nReason: [reason]</B></BIG>"
|
||||
M << "\red This is a permanent ban."
|
||||
if(config.banappeals)
|
||||
M << "\red To try to resolve this matter head to [config.banappeals]"
|
||||
else
|
||||
M << "\red No ban appeals URL has been set."
|
||||
log_admin("[usr.client.ckey] has banned from [job] [ckey].\nReason: [reason]\nThis is a permanent ban.")
|
||||
message_admins("\blue[usr.client.ckey] has banned from [job] [ckey].\nReason: [reason]\nThis is a permanent ban.")
|
||||
/datum/admins/proc/timejobban(ckey, computerid, reason, bannedby, temp, minutes, rank)
|
||||
if(AddBanjob(ckey, computerid, reason, usr.ckey, 1, mins, job))
|
||||
M << "\red<BIG><B>You have been jobbanned from [job] by [usr.client.ckey].\nReason: [reason]</B></BIG>"
|
||||
M << "\red This is a temporary ban, it will be removed in [mins] minutes."
|
||||
if(config.banappeals)
|
||||
M << "\red To try to resolve this matter head to [config.banappeals]"
|
||||
else
|
||||
M << "\red No ban appeals URL has been set."
|
||||
log_admin("[usr.client.ckey] has jobbanned from [job] [ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.")
|
||||
message_admins("\blue[usr.client.ckey] has banned from [job] [ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.")*/
|
||||
//////////////////////////////////// DEBUG ////////////////////////////////////
|
||||
|
||||
/proc/CreateBansjob()
|
||||
|
||||
UpdateTime()
|
||||
|
||||
var/i
|
||||
var/last
|
||||
|
||||
for(i=0, i<1001, i++)
|
||||
var/a = pick(1,0)
|
||||
var/b = pick(1,0)
|
||||
if(b)
|
||||
Banlistjob.cd = "/base"
|
||||
Banlistjob.dir.Add("trash[i]trashid[i]")
|
||||
Banlistjob.cd = "/base/trash[i]trashid[i]"
|
||||
Banlistjob["key"] << "trash[i]"
|
||||
else
|
||||
Banlistjob.cd = "/base"
|
||||
Banlistjob.dir.Add("[last]trashid[i]")
|
||||
Banlistjob.cd = "/base/[last]trashid[i]"
|
||||
Banlistjob["key"] << last
|
||||
Banlistjob["id"] << "trashid[i]"
|
||||
Banlistjob["reason"] << "Trashban[i]."
|
||||
Banlistjob["temp"] << a
|
||||
Banlistjob["minutes"] << CMinutes + rand(1,2000)
|
||||
Banlistjob["bannedby"] << "trashmin"
|
||||
last = "trash[i]"
|
||||
|
||||
Banlistjob.cd = "/base"
|
||||
|
||||
/proc/ClearAllBansjob()
|
||||
Banlistjob.cd = "/base"
|
||||
for (var/A in Banlistjob.dir)
|
||||
RemoveBanjob(A, "full")
|
||||
@@ -544,7 +544,7 @@
|
||||
if(istype(ticker.mode, /datum/game_mode/blob))
|
||||
var/datum/game_mode/blob/mode = ticker.mode
|
||||
dat += "<br><table cellspacing=5><tr><td><B>Blob</B></td><td></td><td></td></tr>"
|
||||
dat += "<tr><td><i>Progress: [blobs.len]/[mode.blobwincount]</i></td></tr>"
|
||||
dat += "<tr><td><i>Progress: [blobs_legit.len]/[mode.blobwincount]</i></td></tr>"
|
||||
|
||||
for(var/datum/mind/blob in mode.infected_crew)
|
||||
var/mob/M = blob.current
|
||||
|
||||
@@ -400,9 +400,9 @@
|
||||
if("coffee") M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob )
|
||||
if("parrot") M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob )
|
||||
if("polyparrot") M.change_mob_type( /mob/living/simple_animal/parrot/Poly , null, null, delmob )
|
||||
if("constructarmored") M.change_mob_type( /mob/living/simple_animal/construct/armored , null, null, delmob )
|
||||
if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/construct/builder , null, null, delmob )
|
||||
if("constructwraith") M.change_mob_type( /mob/living/simple_animal/construct/wraith , null, null, delmob )
|
||||
if("constructarmored") M.change_mob_type( /mob/living/simple_animal/hostile/construct/armored , null, null, delmob )
|
||||
if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/hostile/construct/builder , null, null, delmob )
|
||||
if("constructwraith") M.change_mob_type( /mob/living/simple_animal/hostile/construct/wraith , null, null, delmob )
|
||||
if("shade") M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob )
|
||||
|
||||
|
||||
@@ -483,10 +483,6 @@
|
||||
|
||||
var/banreason = appearance_isbanned(M)
|
||||
if(banreason)
|
||||
/* if(!config.ban_legacy_system)
|
||||
usr << "Unfortunately, database based unbanning cannot be done through this panel"
|
||||
DB_ban_panel(M.ckey)
|
||||
return */
|
||||
switch(alert("Reason: '[banreason]' Remove appearance ban?","Please Confirm","Yes","No"))
|
||||
if("Yes")
|
||||
ban_unban_log_save("[key_name(usr)] removed [key_name(M)]'s appearance ban")
|
||||
@@ -895,9 +891,6 @@
|
||||
if(notbannedlist.len) //at least 1 unbanned job exists in joblist so we have stuff to ban.
|
||||
switch(alert("Temporary Ban?",,"Yes","No", "Cancel"))
|
||||
if("Yes")
|
||||
if(config.ban_legacy_system)
|
||||
usr << "<span class='danger'>Your server is using the legacy banning system, which does not support temporary job bans. Consider upgrading. Aborting ban.</span>"
|
||||
return
|
||||
var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null
|
||||
if(!mins)
|
||||
return
|
||||
@@ -912,7 +905,6 @@
|
||||
feedback_inc("ban_job_tmp",1)
|
||||
DB_ban_record(BANTYPE_JOB_TEMP, M, mins, reason, job)
|
||||
feedback_add_details("ban_job_tmp","- [job]")
|
||||
jobban_fullban(M, job, "[reason]; By [usr.ckey] on [time2text(world.realtime)]") //Legacy banning does not support temporary jobbans.
|
||||
if(!msg)
|
||||
msg = job
|
||||
else
|
||||
@@ -934,7 +926,6 @@
|
||||
feedback_inc("ban_job",1)
|
||||
DB_ban_record(BANTYPE_JOB_PERMA, M, -1, reason, job)
|
||||
feedback_add_details("ban_job","- [job]")
|
||||
jobban_fullban(M, job, "[reason]; By [usr.ckey] on [time2text(world.realtime)]")
|
||||
if(!msg) msg = job
|
||||
else msg += ", [job]"
|
||||
add_note(M.ckey, "Banned from [msg] - [reason]", null, usr.ckey, 0)
|
||||
@@ -961,7 +952,6 @@
|
||||
DB_ban_unban(M.ckey, BANTYPE_ANY_JOB, job)
|
||||
feedback_inc("ban_job_unban",1)
|
||||
feedback_add_details("ban_job_unban","- [job]")
|
||||
jobban_unban(M, job)
|
||||
if(!msg) msg = job
|
||||
else msg += ", [job]"
|
||||
else
|
||||
@@ -1029,21 +1019,6 @@
|
||||
var/edit_log = query_noteedits.item[1]
|
||||
usr << browse(edit_log,"window=noteedits")
|
||||
|
||||
else if(href_list["removejobban"])
|
||||
if(!check_rights(R_BAN)) return
|
||||
|
||||
var/t = href_list["removejobban"]
|
||||
if(t)
|
||||
if((alert("Do you want to unjobban [t]?","Unjobban confirmation", "Yes", "No") == "Yes") && t) //No more misclicks! Unless you do it twice.
|
||||
log_admin("[key_name(usr)] removed [t]")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed [t]</span>")
|
||||
jobban_remove(t)
|
||||
href_list["ban"] = 1 // lets it fall through and refresh
|
||||
var/t_split = text2list(t, " - ")
|
||||
var/key = t_split[1]
|
||||
var/job = t_split[2]
|
||||
DB_ban_unban(ckey(key), BANTYPE_JOB_PERMA, job)
|
||||
|
||||
else if(href_list["newban"])
|
||||
if(!check_rights(R_BAN)) return
|
||||
|
||||
@@ -1103,19 +1078,6 @@
|
||||
if("Cancel")
|
||||
return
|
||||
|
||||
else if(href_list["unjobbanf"])
|
||||
if(!check_rights(R_BAN)) return
|
||||
|
||||
var/banfolder = href_list["unjobbanf"]
|
||||
Banlist.cd = "/base/[banfolder]"
|
||||
var/key = Banlist["key"]
|
||||
if(alert(usr, "Are you sure you want to unban [key]?", "Confirmation", "Yes", "No") == "Yes")
|
||||
if (RemoveBanjob(banfolder))
|
||||
unjobbanpanel()
|
||||
else
|
||||
alert(usr,"This ban has already been lifted / does not exist.","Error","Ok")
|
||||
unjobbanpanel()
|
||||
|
||||
//Watchlist
|
||||
else if(href_list["watchadd"])
|
||||
var/target_ckey = locate(href_list["watchadd"])
|
||||
@@ -1898,7 +1860,7 @@
|
||||
else
|
||||
var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel")
|
||||
if(choice=="Confirm")
|
||||
news_network.CreateFeedChannel(src.admincaster_feed_channel.channel_name, src.admincaster_signature, src.admincaster_feed_channel.locked, 1)
|
||||
news_network.CreateFeedChannel(src.admincaster_feed_channel.channel_name, src.admin_signature, src.admincaster_feed_channel.locked, 1)
|
||||
feedback_inc("newscaster_channels",1)
|
||||
log_admin("[key_name(usr)] created command feed channel: [src.admincaster_feed_channel.channel_name]!")
|
||||
src.admincaster_screen=5
|
||||
@@ -1921,7 +1883,7 @@
|
||||
if(src.admincaster_feed_message.returnBody(-1) =="" || src.admincaster_feed_message.returnBody(-1) =="\[REDACTED\]" || src.admincaster_feed_channel.channel_name == "" )
|
||||
src.admincaster_screen = 6
|
||||
else
|
||||
news_network.SubmitArticle(src.admincaster_feed_message.returnBody(-1), src.admincaster_signature, src.admincaster_feed_channel.channel_name, null, 1)
|
||||
news_network.SubmitArticle(src.admincaster_feed_message.returnBody(-1), src.admin_signature, src.admincaster_feed_channel.channel_name, null, 1)
|
||||
feedback_inc("newscaster_stories",1)
|
||||
src.admincaster_screen=4
|
||||
|
||||
@@ -1978,10 +1940,10 @@
|
||||
var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel")
|
||||
if(choice=="Confirm")
|
||||
if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below
|
||||
news_network.submitWanted(admincaster_wanted_message.criminal, admincaster_wanted_message.body, admincaster_signature, null, 1, 1)
|
||||
news_network.submitWanted(admincaster_wanted_message.criminal, admincaster_wanted_message.body, admin_signature, null, 1, 1)
|
||||
src.admincaster_screen = 15
|
||||
else
|
||||
news_network.submitWanted(admincaster_wanted_message.criminal, admincaster_wanted_message.body, admincaster_signature)
|
||||
news_network.submitWanted(admincaster_wanted_message.criminal, admincaster_wanted_message.body, admin_signature)
|
||||
src.admincaster_screen = 19
|
||||
log_admin("[key_name(usr)] issued a Station-wide Wanted Notification for [src.admincaster_wanted_message.criminal]!")
|
||||
src.access_news_network()
|
||||
@@ -2050,7 +2012,7 @@
|
||||
src.access_news_network()
|
||||
|
||||
else if(href_list["ac_set_signature"])
|
||||
src.admincaster_signature = adminscrub(input(usr, "Provide your desired signature", "Network Identity Handler", ""))
|
||||
src.admin_signature = adminscrub(input(usr, "Provide your desired signature", "Network Identity Handler", ""))
|
||||
src.access_news_network()
|
||||
|
||||
else if(href_list["ac_del_comment"])
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
//remove our adminhelp verb temporarily to prevent spamming of admins.
|
||||
src.verbs -= /client/verb/adminhelp
|
||||
adminhelptimerid = addtimer(src,"giveadminhelpverb",1200) //2 minute cooldown of admin helps
|
||||
adminhelptimerid = addtimer(src, "giveadminhelpverb", 1200, FALSE) //2 minute cooldown of admin helps
|
||||
|
||||
msg = keywords_lookup(msg)
|
||||
|
||||
|
||||
@@ -776,3 +776,18 @@ var/global/list/g_fancy_list_of_types = null
|
||||
|
||||
if(!holder) return
|
||||
debug_variables(huds[i])
|
||||
|
||||
/client/proc/reload_nanoui_resources()
|
||||
set category = "Debug"
|
||||
set name = "Reload NanoUI Resources"
|
||||
set desc = "Force the client to redownload NanoUI Resources"
|
||||
|
||||
// Close open NanoUIs.
|
||||
SSnano.close_user_uis(usr)
|
||||
|
||||
// Re-load the assets.
|
||||
var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui)
|
||||
assets.register()
|
||||
|
||||
// Clear the user's cache so they get resent.
|
||||
usr.client.cache = list()
|
||||
|
||||
@@ -64,9 +64,9 @@
|
||||
"_default" = "NO_FILTER"
|
||||
)
|
||||
var/output = "<b>Radio Report</b><hr>"
|
||||
for (var/fq in radio_controller.frequencies)
|
||||
for (var/fq in SSradio.frequencies)
|
||||
output += "<b>Freq: [fq]</b><br>"
|
||||
var/list/datum/radio_frequency/fqs = radio_controller.frequencies[fq]
|
||||
var/list/datum/radio_frequency/fqs = SSradio.frequencies[fq]
|
||||
if (!fqs)
|
||||
output += " <b>ERROR</b><br>"
|
||||
continue
|
||||
@@ -97,26 +97,3 @@
|
||||
message_admins("[key_name_admin(usr)] manually reloaded admins")
|
||||
load_admins()
|
||||
feedback_add_details("admin_verb","RLDA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/print_jobban_old()
|
||||
set name = "Print Jobban Log"
|
||||
set desc = "This spams all the active jobban entries for the current round to standard output."
|
||||
set category = "Debug"
|
||||
|
||||
usr << "<b>Jobbans active in this round.</b>"
|
||||
for(var/t in jobban_keylist)
|
||||
usr << "[t]"
|
||||
|
||||
/client/proc/print_jobban_old_filter()
|
||||
set name = "Search Jobban Log"
|
||||
set desc = "This searches all the active jobban entries for the current round and outputs the results to standard output."
|
||||
set category = "Debug"
|
||||
|
||||
var/filter = input("Contains what?","Filter") as text|null
|
||||
if(!filter)
|
||||
return
|
||||
|
||||
usr << "<b>Jobbans active in this round.</b>"
|
||||
for(var/t in jobban_keylist)
|
||||
if(findtext(t, filter))
|
||||
usr << "[t]"
|
||||
|
||||
@@ -58,7 +58,7 @@ var/intercom_range_display_status = 0
|
||||
set category = "Mapping"
|
||||
set name = "Camera Report"
|
||||
|
||||
if(!master_controller)
|
||||
if(!Master)
|
||||
alert(usr,"Master_controller not found.","Sec Camera Report")
|
||||
return 0
|
||||
|
||||
@@ -153,15 +153,13 @@ var/intercom_range_display_status = 0
|
||||
src.verbs += /client/proc/cmd_admin_areatest
|
||||
src.verbs += /client/proc/cmd_admin_rejuvenate
|
||||
src.verbs += /datum/admins/proc/show_traitor_panel
|
||||
src.verbs += /client/proc/print_jobban_old
|
||||
src.verbs += /client/proc/print_jobban_old_filter
|
||||
src.verbs += /client/proc/disable_communication
|
||||
src.verbs += /client/proc/print_pointers
|
||||
src.verbs += /client/proc/count_movable_instances
|
||||
src.verbs += /client/proc/cmd_show_at_list
|
||||
src.verbs += /client/proc/cmd_show_at_list
|
||||
src.verbs += /client/proc/manipulate_organs
|
||||
//src.verbs += /client/proc/cmd_admin_rejuvenate
|
||||
src.verbs += /client/proc/reload_nanoui_resources
|
||||
|
||||
feedback_add_details("admin_verb","mDV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
@@ -453,6 +453,38 @@
|
||||
if (A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
if(method)
|
||||
if(istype(O,/mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if(istype(M,O.type))
|
||||
M.on_varedit(variable)
|
||||
|
||||
else if(istype(O,/obj))
|
||||
for(var/obj/A in world)
|
||||
if(istype(A,O.type))
|
||||
A.on_varedit(variable)
|
||||
|
||||
else if(istype(O,/turf))
|
||||
for(var/turf/A in block(locate(1,1,1),locate(world.maxx,world.maxy,world.maxz)))
|
||||
if(istype(A,O.type))
|
||||
A.on_varedit(variable)
|
||||
|
||||
else
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.type == O.type)
|
||||
M.on_varedit(variable)
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if(A.type == O.type)
|
||||
A.on_varedit(variable)
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if(A.type == O.type)
|
||||
A.on_varedit(variable)
|
||||
|
||||
world.log << "### MassVarEdit by [src]: [O.type] [variable]=[html_encode("[O.vars[variable]]")]"
|
||||
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]")
|
||||
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]")
|
||||
@@ -143,6 +143,7 @@ var/list/VVckey_edit = list("key", "ckey")
|
||||
switch(alert("Would you like to associate a var with the list entry?",,"Yes","No"))
|
||||
if("Yes")
|
||||
L[var_value] = mod_list_add_ass(O) //haha
|
||||
O.on_varedit(objectvar)
|
||||
world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: ADDED=[var_value]"
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]")
|
||||
@@ -299,6 +300,7 @@ var/list/VVckey_edit = list("key", "ckey")
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: REMOVED=[variable]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: REMOVED=[variable]")
|
||||
L -= variable
|
||||
O.on_varedit(objectvar)
|
||||
return
|
||||
|
||||
if("text")
|
||||
@@ -365,6 +367,7 @@ var/list/VVckey_edit = list("key", "ckey")
|
||||
else
|
||||
L[L.Find(variable)] = new_var
|
||||
|
||||
O.on_varedit(objectvar)
|
||||
world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: [original_var]=[new_var]"
|
||||
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s varlist [objectvar]: [original_var]=[new_var]")
|
||||
@@ -617,6 +620,7 @@ var/list/VVckey_edit = list("key", "ckey")
|
||||
if("marked datum")
|
||||
O.vars[variable] = holder.marked_datum
|
||||
|
||||
O.on_varedit(variable)
|
||||
world.log << "### VarEdit by [src]: [O.type] [variable]=[html_encode("[O.vars[variable]]")]"
|
||||
log_admin("[key_name(src)] modified [original_name]'s [variable] to [O.vars[variable]]")
|
||||
message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [O.vars[variable]]")
|
||||
|
||||
@@ -918,11 +918,11 @@ var/list/datum/outfit/custom_outfits = list() //Admin created outfits
|
||||
|
||||
if(!holder) return
|
||||
|
||||
var/datum/atom_hud/magical = huds[ANTAG_HUD_WIZ]
|
||||
var/adding_hud = (usr in magical.hudusers) ? 0 : 1
|
||||
var/datum/atom_hud/A = huds[DATA_HUD_SECURITY_ADVANCED]
|
||||
var/adding_hud = (usr in A.hudusers) ? 0 : 1
|
||||
|
||||
for(var/datum/atom_hud/H in huds)
|
||||
if(istype(H, /datum/atom_hud/antag))
|
||||
if(istype(H, /datum/atom_hud/antag) || istype(H, /datum/atom_hud/data/human/security/advanced))
|
||||
(adding_hud) ? H.add_hud_to(usr) : H.remove_hud_from(usr)
|
||||
|
||||
usr << "You toggled your admin antag HUD [adding_hud ? "ON" : "OFF"]."
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/signaler/Destroy()
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src,frequency)
|
||||
if(SSradio)
|
||||
SSradio.remove_object(src,frequency)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/assembly/signaler/activate()
|
||||
@@ -135,13 +135,13 @@ Code:
|
||||
|
||||
|
||||
/obj/item/device/assembly/signaler/proc/set_frequency(new_frequency)
|
||||
if(!radio_controller)
|
||||
if(!SSradio)
|
||||
sleep(20)
|
||||
if(!radio_controller)
|
||||
if(!SSradio)
|
||||
return
|
||||
radio_controller.remove_object(src, frequency)
|
||||
SSradio.remove_object(src, frequency)
|
||||
frequency = new_frequency
|
||||
radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT)
|
||||
radio_connection = SSradio.add_object(src, frequency, RADIO_CHAT)
|
||||
return
|
||||
|
||||
// Embedded signaller used in grenade construction.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/obj/effect/landmark/corpse
|
||||
name = "Unknown"
|
||||
var/mobname = "Unknown" //Unused now but it'd fuck up maps to remove it now
|
||||
var/mobname = "default" //Use for the ghost spawner variant, so they don't come out named "sleeper"
|
||||
var/mobgender = MALE //Set to male by default due to the patriarchy. Other options include FEMALE and NEUTER
|
||||
var/mob_species = null //Set to make them a mutant race such as lizard or skeleton
|
||||
var/corpseuniform = null //Set this to an object path to have the slot filled with said object on the corpse.
|
||||
@@ -45,7 +45,10 @@
|
||||
|
||||
/obj/effect/landmark/corpse/proc/createCorpse(death, ckey) //Creates a mob and checks for gear in each slot before attempting to equip it.
|
||||
var/mob/living/carbon/human/M = new /mob/living/carbon/human (src.loc)
|
||||
M.real_name = src.name
|
||||
if(mobname != "default")
|
||||
M.real_name = mobname
|
||||
else
|
||||
M.real_name = src.name
|
||||
M.gender = src.mobgender
|
||||
if(mob_species)
|
||||
M.set_species(mob_species)
|
||||
@@ -257,7 +260,7 @@
|
||||
|
||||
/obj/effect/landmark/corpse/plasmaman
|
||||
mob_species = "plasmaman"
|
||||
corpsehelmet = /obj/item/clothing/head/helmet/plasmaman
|
||||
corpsehelmet = /obj/item/clothing/head/helmet/space/plasmaman
|
||||
corpseuniform = /obj/item/clothing/under/plasmaman
|
||||
corpseback = /obj/item/weapon/tank/internals/plasmaman/full
|
||||
corpsemask = /obj/item/clothing/mask/breath
|
||||
@@ -295,13 +298,45 @@
|
||||
/obj/effect/landmark/corpse/commander/alive
|
||||
death = FALSE
|
||||
roundstart = FALSE
|
||||
mobname = "Nanotrasen Commander"
|
||||
name = "sleeper"
|
||||
icon = 'icons/obj/Cryogenic2.dmi'
|
||||
icon_state = "sleeper"
|
||||
flavour_text = "You are a Nanotrasen Commander!"
|
||||
|
||||
/obj/effect/landmark/corpse/attack_ghost(mob/user)
|
||||
if(ticker.current_state != GAME_STATE_PLAYING)
|
||||
return
|
||||
var/ghost_role = alert("Become [mobname]? (Warning, You can no longer be cloned!)",,"Yes","No")
|
||||
if(ghost_role == "No")
|
||||
return
|
||||
createCorpse(death = src.death, ckey = user.ckey)
|
||||
|
||||
/////////////////Spooky Undead//////////////////////
|
||||
|
||||
/obj/effect/landmark/corpse/skeleton
|
||||
name = "skeletal remains"
|
||||
mobname = "skeleton"
|
||||
mob_species = "skeleton"
|
||||
mobgender = NEUTER
|
||||
|
||||
|
||||
/obj/effect/landmark/corpse/skeleton/alive
|
||||
death = FALSE
|
||||
roundstart = FALSE
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "remains"
|
||||
flavour_text = "By unknown powers, your skeletal remains have been reanimated! Walk this mortal plain and terrorize all living adventurers who dare cross your path."
|
||||
|
||||
|
||||
/obj/effect/landmark/corpse/zombie
|
||||
name = "rotting corpse"
|
||||
mobname = "zombie"
|
||||
mob_species = "zombie"
|
||||
|
||||
/obj/effect/landmark/corpse/zombie/alive
|
||||
death = FALSE
|
||||
roundstart = FALSE
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "remains"
|
||||
flavour_text = "By unknown powers, your rotting remains have been resurrected! Walk this mortal plain and terrorize all living adventurers who dare cross your path."
|
||||
|
||||
@@ -20,6 +20,14 @@
|
||||
name = "\improper Academy Gateway"
|
||||
icon_state = "away4"
|
||||
|
||||
/area/awaymission/academy/academycellar
|
||||
name = "\improper Academy Cellar"
|
||||
icon_state = "away4"
|
||||
|
||||
/area/awaymission/academy/academyengine
|
||||
name = "\improper Academy Engine"
|
||||
icon_state = "away4"
|
||||
|
||||
//Academy Items
|
||||
|
||||
/obj/singularity/academy
|
||||
@@ -40,4 +48,296 @@
|
||||
name = "The Lens of Truesight"
|
||||
desc = "I can see forever!"
|
||||
icon_state = "monocle"
|
||||
item_state = "headset"
|
||||
item_state = "headset"
|
||||
|
||||
|
||||
/obj/structure/academy_wizard_spawner
|
||||
name = "Academy Defensive System"
|
||||
desc = "Made by Abjuration Inc"
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
icon_state = "forge"
|
||||
anchored = 1
|
||||
var/health = 200
|
||||
var/mob/living/current_wizard = null
|
||||
var/next_check = 0
|
||||
var/cooldown = 600
|
||||
var/faction = "wizard"
|
||||
var/broken = 0
|
||||
var/braindead_check = 0
|
||||
|
||||
/obj/structure/academy_wizard_spawner/New()
|
||||
SSobj.processing |= src
|
||||
|
||||
/obj/structure/academy_wizard_spawner/process()
|
||||
if(next_check < world.time)
|
||||
if(!current_wizard)
|
||||
for(var/mob/living/L in player_list)
|
||||
if(L.z == src.z && L.stat != DEAD && !(faction in L.faction))
|
||||
summon_wizard()
|
||||
break
|
||||
else
|
||||
if(current_wizard.stat == DEAD)
|
||||
current_wizard = null
|
||||
summon_wizard()
|
||||
if(!current_wizard.client)
|
||||
if(!braindead_check)
|
||||
braindead_check = 1
|
||||
else
|
||||
braindead_check = 0
|
||||
give_control()
|
||||
next_check = world.time + cooldown
|
||||
|
||||
/obj/structure/academy_wizard_spawner/proc/give_control()
|
||||
if(!current_wizard)
|
||||
return
|
||||
spawn(0)
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as Wizard Academy Defender?", "wizard")
|
||||
var/mob/dead/observer/chosen = null
|
||||
|
||||
if(candidates.len)
|
||||
chosen = pick(candidates)
|
||||
message_admins("[key_name_admin(chosen)] was spawned as Wizard Academy Defender")
|
||||
current_wizard.ghostize() // on the off chance braindead defender gets back in
|
||||
current_wizard.key = chosen.key
|
||||
|
||||
/obj/structure/academy_wizard_spawner/proc/summon_wizard()
|
||||
var/turf/T = src.loc
|
||||
|
||||
var/mob/living/carbon/human/wizbody = new(T)
|
||||
wizbody.equipOutfit(/datum/outfit/wizard/academy)
|
||||
var/obj/item/weapon/implant/exile/Implant = new/obj/item/weapon/implant/exile(wizbody)
|
||||
Implant.implant(wizbody)
|
||||
wizbody.faction |= "wizard"
|
||||
wizbody.real_name = "Academy Teacher"
|
||||
wizbody.name = "Academy Teacher"
|
||||
|
||||
var/datum/mind/wizmind = new /datum/mind()
|
||||
wizmind.name = "Wizard Defender"
|
||||
wizmind.special_role = "Academy Defender"
|
||||
var/datum/objective/O = new("Protect Wizard Academy from the intruders")
|
||||
wizmind.objectives += O
|
||||
wizmind.transfer_to(wizbody)
|
||||
ticker.mode.wizards |= wizmind
|
||||
|
||||
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt)
|
||||
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile)
|
||||
wizmind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball)
|
||||
|
||||
current_wizard = wizbody
|
||||
|
||||
give_control()
|
||||
|
||||
/obj/structure/academy_wizard_spawner/proc/update_status()
|
||||
if(health<0)
|
||||
visible_message("<span class='warning'>[src] breaks down!</span>")
|
||||
icon_state = "forge_off"
|
||||
SSobj.processing.Remove(src)
|
||||
broken = 1
|
||||
|
||||
/obj/structure/academy_wizard_spawner/attackby(obj/item/weapon/W, mob/living/user, params)
|
||||
add_fingerprint(user)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(!broken)
|
||||
health -= W.force
|
||||
update_status()
|
||||
..()
|
||||
|
||||
/obj/structure/academy_wizard_spawner/bullet_act(obj/item/projectile/Proj)
|
||||
if(!broken)
|
||||
if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
|
||||
health -= Proj.damage
|
||||
update_status()
|
||||
..()
|
||||
return
|
||||
|
||||
/datum/outfit/wizard/academy
|
||||
name = "Academy Wizard"
|
||||
r_pocket = null
|
||||
r_hand = null
|
||||
suit = /obj/item/clothing/suit/wizrobe/red
|
||||
head = /obj/item/clothing/head/wizard/red
|
||||
backpack_contents = list(/obj/item/weapon/storage/box/survival = 1)
|
||||
|
||||
/obj/item/weapon/dice/d20/fate
|
||||
name = "Dice of Fate"
|
||||
desc = "A die with twenty sides. You can feel unearthly energies radiating from it. Using this might be VERY risky."
|
||||
icon_state = "d20"
|
||||
sides = 20
|
||||
var/used = 0
|
||||
var/rigged = -1
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/diceroll(mob/user)
|
||||
..()
|
||||
if(!used)
|
||||
if(!ishuman(user) || !user.mind || (user.mind in ticker.mode.wizards))
|
||||
user << "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans!</span>"
|
||||
return
|
||||
if(rigged > 0)
|
||||
effect(user,rigged)
|
||||
else
|
||||
effect(user,result)
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/equipped(mob/user, slot)
|
||||
if(!ishuman(user) || !user.mind || (user.mind in ticker.mode.wizards))
|
||||
user << "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans! You should leave it alone.</span>"
|
||||
user.drop_item()
|
||||
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/proc/effect(var/mob/living/carbon/human/user,roll)
|
||||
used = 1
|
||||
visible_message("<span class='userdanger'>The die flare briefly.</span>")
|
||||
switch(roll)
|
||||
if(1)
|
||||
//Dust
|
||||
user.dust()
|
||||
if(2)
|
||||
//Death
|
||||
user.death()
|
||||
if(3)
|
||||
//Swarm of creatures
|
||||
for(var/direction in alldirs)
|
||||
var/turf/T = get_turf(src)
|
||||
new /mob/living/simple_animal/hostile/creature(get_step(T,direction))
|
||||
if(4)
|
||||
//Destroy Equipment
|
||||
for (var/obj/item/I in user)
|
||||
if (istype(I, /obj/item/weapon/implant))
|
||||
continue
|
||||
qdel(I)
|
||||
if(5)
|
||||
//Monkeying
|
||||
user.monkeyize()
|
||||
if(6)
|
||||
//Cut speed
|
||||
var/datum/species/S = user.dna.species
|
||||
S.speedmod += 1
|
||||
if(7)
|
||||
//Throw
|
||||
user.Stun(3)
|
||||
user.adjustBruteLoss(50)
|
||||
var/throw_dir = pick(cardinal)
|
||||
var/atom/throw_target = get_edge_target_turf(user, throw_dir)
|
||||
user.throw_at(throw_target, 200, 4)
|
||||
if(8)
|
||||
//Fueltank Explosion
|
||||
explosion(src.loc,-1,0,2, flame_range = 2)
|
||||
if(9)
|
||||
//Cold
|
||||
var/datum/disease/D = new /datum/disease/cold
|
||||
user.ForceContractDisease(D)
|
||||
if(10)
|
||||
//Nothing
|
||||
visible_message("<span class='notice'>[src] roll perfectly.</span>")
|
||||
if(11)
|
||||
//Cookie
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/cookie/C = new(get_turf(src))
|
||||
C.name = "Cookie of Fate"
|
||||
if(12)
|
||||
//Healing
|
||||
user.revive()
|
||||
if(13)
|
||||
//Mad Dosh
|
||||
var/turf/Start = get_turf(src)
|
||||
for(var/direction in alldirs)
|
||||
var/turf/T = get_step(Start,direction)
|
||||
if(rand(0,1))
|
||||
new /obj/item/stack/spacecash/c1000(T)
|
||||
else
|
||||
var/obj/item/weapon/moneybag/M = new(T)
|
||||
for(var/i in 1 to rand(5,50))
|
||||
new /obj/item/weapon/coin/gold(M)
|
||||
if(14)
|
||||
//Free Gun
|
||||
new /obj/item/weapon/gun/projectile/revolver/mateba(get_turf(src))
|
||||
if(15)
|
||||
//Random One-use spellbook
|
||||
new /obj/item/weapon/spellbook/oneuse/random(get_turf(src))
|
||||
if(16)
|
||||
//Servant & Servant Summon
|
||||
var/mob/living/carbon/human/H = new(get_turf(src))
|
||||
H.equipOutfit(/datum/outfit/butler)
|
||||
var/datum/mind/servant_mind = new /datum/mind()
|
||||
var/datum/objective/O = new("Serve [user.real_name].")
|
||||
servant_mind.objectives += O
|
||||
servant_mind.transfer_to(H)
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as [user.real_name] Servant?", "wizard")
|
||||
var/mob/dead/observer/chosen = null
|
||||
|
||||
if(candidates.len)
|
||||
chosen = pick(candidates)
|
||||
message_admins("[key_name_admin(chosen)] was spawned as Dice Servant")
|
||||
H.key = chosen.key
|
||||
|
||||
var/obj/effect/proc_holder/spell/targeted/summonmob/S = new
|
||||
S.target_mob = H
|
||||
user.mind.AddSpell(S)
|
||||
|
||||
if(17)
|
||||
//Tator Kit
|
||||
new /obj/item/weapon/storage/box/syndicate/(get_turf(src))
|
||||
if(18)
|
||||
//Captain ID
|
||||
new /obj/item/weapon/card/id/captains_spare(get_turf(src))
|
||||
if(19)
|
||||
//Instrinct Resistance
|
||||
user << "<span class='notice'>You feel robust.</span>"
|
||||
var/datum/species/S = user.dna.species
|
||||
S.brutemod *= 0.5
|
||||
S.burnmod *= 0.5
|
||||
S.coldmod *= 0.5
|
||||
if(20)
|
||||
//Free wizard!
|
||||
user.mind.make_Wizard()
|
||||
|
||||
|
||||
/datum/outfit/butler
|
||||
name = "Butler"
|
||||
uniform = /obj/item/clothing/under/suit_jacket/really_black
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
head = /obj/item/clothing/head/bowler
|
||||
glasses = /obj/item/clothing/glasses/monocle
|
||||
gloves = /obj/item/clothing/gloves/color/white
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/summonmob
|
||||
name = "Summon Servant"
|
||||
desc = "This spell can be used to call your servant, whenever you need it."
|
||||
charge_max = 100
|
||||
clothes_req = 0
|
||||
invocation = "JE VES"
|
||||
invocation_type = "whisper"
|
||||
range = -1
|
||||
level_max = 0 //cannot be improved
|
||||
cooldown_min = 100
|
||||
include_user = 1
|
||||
|
||||
var/mob/living/target_mob
|
||||
|
||||
action_icon_state = "summons"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/summonmob/cast(list/targets,mob/user = usr)
|
||||
if(!target_mob)
|
||||
return
|
||||
var/turf/Start = get_turf(user)
|
||||
for(var/direction in alldirs)
|
||||
var/turf/T = get_step(Start,direction)
|
||||
if(!T.density)
|
||||
target_mob.Move(T)
|
||||
|
||||
/obj/structure/ladder/unbreakable/rune
|
||||
name = "Teleportation Rune"
|
||||
desc = "Could lead anywhere."
|
||||
icon = 'icons/obj/rune.dmi'
|
||||
icon_state = "1"
|
||||
color = rgb(0,0,255)
|
||||
|
||||
/obj/structure/ladder/unbreakable/rune/update_icon()
|
||||
return
|
||||
|
||||
/obj/structure/ladder/unbreakable/rune/show_fluff_message(up,mob/user)
|
||||
user.visible_message("[user] activates \the [src].","<span class='notice'>You activate \the [src].</span>")
|
||||
|
||||
/obj/structure/ladder/can_use(mob/user)
|
||||
if(user.mind in ticker.mode.wizards)
|
||||
return 0
|
||||
return 1
|
||||
@@ -163,7 +163,7 @@ var/sc_safecode5 = "[rand(0,9)]"
|
||||
desc = "Your body becomes weak and your feel your mind slipping away as you try to comprehend what you know can't be possible."
|
||||
move_self = 0 //Contianed narsie does not move!
|
||||
grav_pull = 0 //Contained narsie does not pull stuff in!
|
||||
var/uneatable = list(/turf/space, /obj/effect/overlay, /mob/living/simple_animal/construct)
|
||||
var/uneatable = list(/turf/space, /obj/effect/overlay, /mob/living/simple_animal/hostile/construct)
|
||||
//Override this to prevent no adminlog runtimes and admin warnings about a singularity without containment
|
||||
/obj/singularity/narsie/sc_Narsie/admin_investigate_setup()
|
||||
return
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
if("Peace")
|
||||
user << "<B>Whatever alien sentience that the Wish Granter possesses is satisfied with your wish. There is a distant wailing as the last of the Faithless begin to die, then silence.</B>"
|
||||
user << "You feel as if you just narrowly avoided a terrible fate..."
|
||||
for(var/mob/living/simple_animal/hostile/faithless/F in world)
|
||||
for(var/mob/living/simple_animal/hostile/faithless/F in mob_list)
|
||||
F.health = -10
|
||||
F.stat = 2
|
||||
F.icon_state = "faithless_dead"
|
||||
@@ -135,19 +135,19 @@
|
||||
|
||||
/obj/effect/meatgrinder/Bumped(mob/M as mob|obj)
|
||||
|
||||
if(triggered) return
|
||||
if(triggered)
|
||||
return
|
||||
|
||||
if(istype(M, /mob/living/carbon/human) || istype(M, /mob/living/carbon/monkey))
|
||||
if(istype(M, /mob/living/carbon/human) && M.stat != DEAD && M.ckey)
|
||||
for(var/mob/O in viewers(world.view, src.loc))
|
||||
O << "<font color='red'>[M] triggered the \icon[src] [src]</font>"
|
||||
visible_message("<span class='warning'>[M] triggered the [src]!</span>")
|
||||
triggered = 1
|
||||
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
for(var/mob/O in viewers(world.view, src.loc))
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
explosion(M, 1, 0, 0, 0)
|
||||
qdel(src)
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
explosion(M, 1, 0, 0, 0)
|
||||
qdel(src)
|
||||
|
||||
/////For the Wishgranter///////////
|
||||
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
Asset cache quick users guide:
|
||||
|
||||
Make a datum at the bottom of this file with your assets for your thing.
|
||||
The simple subsystem will most like be of use for most cases.
|
||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||
Then call .send(client) on that stored return value.
|
||||
|
||||
You can set verify to TRUE if you want send() to sleep until the client has the assets.
|
||||
*/
|
||||
|
||||
|
||||
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
|
||||
// This is doubled for the first asset, then added per asset after
|
||||
#define ASSET_CACHE_SEND_TIMEOUT 7
|
||||
|
||||
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
/client
|
||||
var/list/cache = list() // List of all assets sent to this client by the asset cache.
|
||||
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
|
||||
var/list/sending = list()
|
||||
var/last_asset_job = 0 // Last job done.
|
||||
|
||||
//This proc sends the asset to the client, but only if it needs it.
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
|
||||
return 0
|
||||
|
||||
client << browse_rsc(SSasset.cache[asset_name], asset_name)
|
||||
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
|
||||
if (client)
|
||||
client.cache += asset_name
|
||||
return 1
|
||||
if (!client)
|
||||
return 0
|
||||
|
||||
client.sending |= asset_name
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
sleep(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= asset_name
|
||||
client.cache |= asset_name
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
var/list/unreceived = asset_list - (client.cache + client.sending)
|
||||
if(!unreceived || !unreceived.len)
|
||||
return 0
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
client << "Sending Resources..."
|
||||
for(var/asset in unreceived)
|
||||
if (asset in SSasset.cache)
|
||||
client << browse_rsc(SSasset.cache[asset], asset)
|
||||
|
||||
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
|
||||
if (client)
|
||||
client.cache += unreceived
|
||||
return 1
|
||||
if (!client)
|
||||
return 0
|
||||
client.sending |= unreceived
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
sleep(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= unreceived
|
||||
client.cache |= unreceived
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
//The proc calls procs that sleep for long times.
|
||||
/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
|
||||
for(var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (register_asset)
|
||||
register_asset(file,files[file])
|
||||
send_asset(client,file)
|
||||
sleep(-1) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
//if it's an icon or something be careful, you'll have to copy it before further use.
|
||||
/proc/register_asset(var/asset_name, var/asset)
|
||||
SSasset.cache[asset_name] = asset
|
||||
|
||||
//These datums are used to populate the asset cache, the proc "register()" does this.
|
||||
|
||||
//all of our asset datums, used for referring to these later
|
||||
/var/global/list/asset_datums = list()
|
||||
|
||||
//get a assetdatum or make a new one
|
||||
/proc/get_asset_datum(var/type)
|
||||
if (!(type in asset_datums))
|
||||
return new type()
|
||||
return asset_datums[type]
|
||||
|
||||
/datum/asset/New()
|
||||
asset_datums[type] = src
|
||||
|
||||
/datum/asset/proc/register()
|
||||
return
|
||||
|
||||
/datum/asset/proc/send(client)
|
||||
return
|
||||
|
||||
//If you don't need anything complicated.
|
||||
/datum/asset/simple
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
/datum/asset/simple/send(client)
|
||||
send_asset_list(client,assets,verify)
|
||||
|
||||
|
||||
//DEFINITIONS FOR ASSET DATUMS START HERE.
|
||||
|
||||
|
||||
/datum/asset/simple/pda
|
||||
assets = list(
|
||||
"pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
|
||||
"pda_back.png" = 'icons/pda_icons/pda_back.png',
|
||||
"pda_bell.png" = 'icons/pda_icons/pda_bell.png',
|
||||
"pda_blank.png" = 'icons/pda_icons/pda_blank.png',
|
||||
"pda_boom.png" = 'icons/pda_icons/pda_boom.png',
|
||||
"pda_bucket.png" = 'icons/pda_icons/pda_bucket.png',
|
||||
"pda_medbot.png" = 'icons/pda_icons/pda_medbot.png',
|
||||
"pda_floorbot.png" = 'icons/pda_icons/pda_floorbot.png',
|
||||
"pda_cleanbot.png" = 'icons/pda_icons/pda_cleanbot.png',
|
||||
"pda_crate.png" = 'icons/pda_icons/pda_crate.png',
|
||||
"pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png',
|
||||
"pda_eject.png" = 'icons/pda_icons/pda_eject.png',
|
||||
"pda_exit.png" = 'icons/pda_icons/pda_exit.png',
|
||||
"pda_flashlight.png" = 'icons/pda_icons/pda_flashlight.png',
|
||||
"pda_honk.png" = 'icons/pda_icons/pda_honk.png',
|
||||
"pda_mail.png" = 'icons/pda_icons/pda_mail.png',
|
||||
"pda_medical.png" = 'icons/pda_icons/pda_medical.png',
|
||||
"pda_menu.png" = 'icons/pda_icons/pda_menu.png',
|
||||
"pda_mule.png" = 'icons/pda_icons/pda_mule.png',
|
||||
"pda_notes.png" = 'icons/pda_icons/pda_notes.png',
|
||||
"pda_power.png" = 'icons/pda_icons/pda_power.png',
|
||||
"pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png',
|
||||
"pda_reagent.png" = 'icons/pda_icons/pda_reagent.png',
|
||||
"pda_refresh.png" = 'icons/pda_icons/pda_refresh.png',
|
||||
"pda_scanner.png" = 'icons/pda_icons/pda_scanner.png',
|
||||
"pda_signaler.png" = 'icons/pda_icons/pda_signaler.png',
|
||||
"pda_status.png" = 'icons/pda_icons/pda_status.png'
|
||||
)
|
||||
|
||||
/datum/asset/simple/paper
|
||||
assets = list(
|
||||
"large_stamp-clown.png" = 'icons/stamp_icons/large_stamp-clown.png',
|
||||
"large_stamp-deny.png" = 'icons/stamp_icons/large_stamp-deny.png',
|
||||
"large_stamp-ok.png" = 'icons/stamp_icons/large_stamp-ok.png',
|
||||
"large_stamp-hop.png" = 'icons/stamp_icons/large_stamp-hop.png',
|
||||
"large_stamp-cmo.png" = 'icons/stamp_icons/large_stamp-cmo.png',
|
||||
"large_stamp-ce.png" = 'icons/stamp_icons/large_stamp-ce.png',
|
||||
"large_stamp-hos.png" = 'icons/stamp_icons/large_stamp-hos.png',
|
||||
"large_stamp-rd.png" = 'icons/stamp_icons/large_stamp-rd.png',
|
||||
"large_stamp-cap.png" = 'icons/stamp_icons/large_stamp-cap.png',
|
||||
"large_stamp-qm.png" = 'icons/stamp_icons/large_stamp-qm.png',
|
||||
"large_stamp-law.png" = 'icons/stamp_icons/large_stamp-law.png'
|
||||
)
|
||||
|
||||
//Registers HTML Interface assets.
|
||||
/datum/asset/HTML_interface/register()
|
||||
for(var/path in typesof(/datum/html_interface))
|
||||
var/datum/html_interface/hi = new path()
|
||||
hi.registerResources()
|
||||
|
||||
/datum/asset/nanoui
|
||||
var/list/common = list()
|
||||
|
||||
var/list/common_dirs = list(
|
||||
"nano/styles/",
|
||||
"nano/scripts/",
|
||||
"nano/images/",
|
||||
"nano/layouts/"
|
||||
)
|
||||
var/list/uncommon_dirs = list(
|
||||
"nano/interfaces/"
|
||||
)
|
||||
|
||||
/datum/asset/nanoui/register()
|
||||
// Crawl the directories to find files.
|
||||
for (var/path in common_dirs)
|
||||
var/list/filenames = flist(path)
|
||||
for(var/filename in filenames)
|
||||
if(copytext(filename, length(filename)) != "/") // Ignore directories.
|
||||
if(fexists(path + filename))
|
||||
common[filename] = fcopy_rsc(path + filename)
|
||||
register_asset(filename, common[filename])
|
||||
for (var/path in uncommon_dirs)
|
||||
var/list/filenames = flist(path)
|
||||
for(var/filename in filenames)
|
||||
if(copytext(filename, length(filename)) != "/") // Ignore directories.
|
||||
if(fexists(path + filename))
|
||||
register_asset(filename, fcopy_rsc(path + filename))
|
||||
|
||||
/datum/asset/nanoui/send(client, uncommon)
|
||||
if(!islist(uncommon))
|
||||
uncommon = list(uncommon)
|
||||
|
||||
send_asset_list(client, uncommon)
|
||||
send_asset_list(client, common)
|
||||
@@ -6,6 +6,7 @@
|
||||
var/datum/admins/holder = null
|
||||
var/buildmode = 0
|
||||
|
||||
var/jobbancache = null //Used to cache this client's jobbans to save on DB queries
|
||||
var/last_message = "" //Contains the last message sent by this client - used to protect against copy-paste spamming.
|
||||
var/last_message_count = 0 //contins a number of how many times a message identical to last_message was sent.
|
||||
|
||||
|
||||
@@ -22,7 +22,11 @@
|
||||
/client/Topic(href, href_list, hsrc)
|
||||
if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null
|
||||
return
|
||||
|
||||
if(href_list["asset_cache_confirm_arrival"])
|
||||
//src << "ASSET JOB [href_list["asset_cache_confirm_arrival"]] ARRIVED."
|
||||
var/job = text2num(href_list["asset_cache_confirm_arrival"])
|
||||
completed_asset_jobs += job
|
||||
return
|
||||
//Admin PM
|
||||
if(href_list["priv_msg"])
|
||||
if (href_list["ahelp_reply"])
|
||||
@@ -176,13 +180,7 @@ var/next_external_rsc = 0
|
||||
else if (isnum(player_age) && player_age < config.notify_new_player_age)
|
||||
message_admins("New user: [key_name_admin(src)] just connected with an age of [player_age] day[(player_age==1?"":"s")]")
|
||||
|
||||
|
||||
if (!ticker || ticker.current_state == GAME_STATE_PREGAME)
|
||||
spawn (rand(10,150))
|
||||
if (src)
|
||||
sync_client_with_db()
|
||||
else
|
||||
sync_client_with_db()
|
||||
sync_client_with_db()
|
||||
|
||||
send_resources()
|
||||
|
||||
@@ -206,6 +204,9 @@ var/next_external_rsc = 0
|
||||
if (config && config.autoconvert_notes)
|
||||
convert_notes_sql(ckey)
|
||||
|
||||
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
|
||||
src << "<span class='warning'>Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.</span>"
|
||||
|
||||
|
||||
//This is down here because of the browse() calls in tooltip/New()
|
||||
if(!tooltips)
|
||||
@@ -317,63 +318,14 @@ var/next_external_rsc = 0
|
||||
|
||||
//send resources to the client. It's here in its own proc so we can move it around easiliy if need be
|
||||
/client/proc/send_resources()
|
||||
|
||||
spawn
|
||||
// Preload the HTML interface. This needs to be done due to BYOND bug http://www.byond.com/forum/?post=1487244
|
||||
var/datum/html_interface/hi
|
||||
for (var/type in typesof(/datum/html_interface))
|
||||
hi = new type(null)
|
||||
hi.sendResources(src)
|
||||
|
||||
// Preload the crew monitor. This needs to be done due to BYOND bug http://www.byond.com/forum/?post=1487244
|
||||
spawn
|
||||
if (crewmonitor && crewmonitor.initialized)
|
||||
crewmonitor.sendResources(src)
|
||||
|
||||
//Send nanoui files to client
|
||||
SSnano.send_resources(src)
|
||||
//get the common files
|
||||
getFiles(
|
||||
'html/search.js',
|
||||
'html/panels.css',
|
||||
'html/browser/common.css',
|
||||
'html/browser/scannernew.css',
|
||||
'html/browser/playeroptions.css',
|
||||
'icons/pda_icons/pda_atmos.png',
|
||||
'icons/pda_icons/pda_back.png',
|
||||
'icons/pda_icons/pda_bell.png',
|
||||
'icons/pda_icons/pda_blank.png',
|
||||
'icons/pda_icons/pda_boom.png',
|
||||
'icons/pda_icons/pda_bucket.png',
|
||||
'icons/pda_icons/pda_medbot.png',
|
||||
'icons/pda_icons/pda_floorbot.png',
|
||||
'icons/pda_icons/pda_cleanbot.png',
|
||||
'icons/pda_icons/pda_crate.png',
|
||||
'icons/pda_icons/pda_cuffs.png',
|
||||
'icons/pda_icons/pda_eject.png',
|
||||
'icons/pda_icons/pda_exit.png',
|
||||
'icons/pda_icons/pda_flashlight.png',
|
||||
'icons/pda_icons/pda_honk.png',
|
||||
'icons/pda_icons/pda_mail.png',
|
||||
'icons/pda_icons/pda_medical.png',
|
||||
'icons/pda_icons/pda_menu.png',
|
||||
'icons/pda_icons/pda_mule.png',
|
||||
'icons/pda_icons/pda_notes.png',
|
||||
'icons/pda_icons/pda_power.png',
|
||||
'icons/pda_icons/pda_rdoor.png',
|
||||
'icons/pda_icons/pda_reagent.png',
|
||||
'icons/pda_icons/pda_refresh.png',
|
||||
'icons/pda_icons/pda_scanner.png',
|
||||
'icons/pda_icons/pda_signaler.png',
|
||||
'icons/pda_icons/pda_status.png',
|
||||
'icons/stamp_icons/large_stamp-clown.png',
|
||||
'icons/stamp_icons/large_stamp-deny.png',
|
||||
'icons/stamp_icons/large_stamp-ok.png',
|
||||
'icons/stamp_icons/large_stamp-hop.png',
|
||||
'icons/stamp_icons/large_stamp-cmo.png',
|
||||
'icons/stamp_icons/large_stamp-ce.png',
|
||||
'icons/stamp_icons/large_stamp-hos.png',
|
||||
'icons/stamp_icons/large_stamp-rd.png',
|
||||
'icons/stamp_icons/large_stamp-cap.png',
|
||||
'icons/stamp_icons/large_stamp-qm.png',
|
||||
'icons/stamp_icons/large_stamp-law.png'
|
||||
)
|
||||
spawn (10)
|
||||
//Precache the client with all other assets slowly, so as to not block other browse() calls
|
||||
getFilesSlow(src, SSasset.cache, register_asset = FALSE)
|
||||
|
||||
@@ -56,8 +56,7 @@ var/list/preferences_datums = list()
|
||||
var/list/custom_names = list("clown", "mime", "ai", "cyborg", "religion", "deity")
|
||||
|
||||
//Mob preview
|
||||
var/icon/preview_icon_front = null
|
||||
var/icon/preview_icon_side = null
|
||||
var/icon/preview_icon = null
|
||||
|
||||
//Jobs, uses bitflags
|
||||
var/job_civilian_high = 0
|
||||
@@ -113,8 +112,7 @@ var/list/preferences_datums = list()
|
||||
/datum/preferences/proc/ShowChoices(mob/user)
|
||||
if(!user || !user.client) return
|
||||
update_preview_icon()
|
||||
user << browse_rsc(preview_icon_front, "previewicon.png")
|
||||
user << browse_rsc(preview_icon_side, "previewicon2.png")
|
||||
user << browse_rsc(preview_icon, "previewicon.png")
|
||||
var/dat = "<center>"
|
||||
|
||||
dat += "<a href='?_src_=prefs;preference=tab;tab=0' [current_tab == 0 ? "class='linkOn'" : ""]>Character Settings</a> "
|
||||
@@ -168,7 +166,7 @@ var/list/preferences_datums = list()
|
||||
|
||||
dat += "<td valign='center'>"
|
||||
|
||||
dat += "<div class='statusDisplay'><center><img src=previewicon.png height=64 width=64><img src=previewicon2.png height=64 width=64></center></div>"
|
||||
dat += "<div class='statusDisplay'><center><img src=previewicon.png width=[preview_icon.Width()] height=[preview_icon.Height()]></center></div>"
|
||||
|
||||
dat += "</td></tr></table>"
|
||||
|
||||
|
||||
@@ -236,4 +236,4 @@ var/list/ghost_forms = list("ghost","ghostking","ghostian2","skeleghost","ghost_
|
||||
set category = "Preferences"
|
||||
set desc = "Allows you to access the Setup Character screen. Changes to your character won't take effect until next round, but other changes will."
|
||||
prefs.current_tab = 1
|
||||
prefs.ShowChoices(usr)
|
||||
prefs.ShowChoices(usr)
|
||||
|
||||
@@ -220,8 +220,6 @@ BLIND // can't see anything
|
||||
if(blood_DNA)
|
||||
. += image("icon"='icons/effects/blood.dmi', "icon_state"="[blood_overlay_type]blood")
|
||||
|
||||
|
||||
|
||||
//Spacesuit
|
||||
//Note: Everything in modules/clothing/spacesuits should have the entire suit grouped together.
|
||||
// Meaning the the suit is defined directly after the corrisponding helmet. Just like below!
|
||||
|
||||
@@ -11,30 +11,35 @@
|
||||
action_button_name = "Toggle Helmet Light"
|
||||
burn_state = -1 //Won't burn in fires
|
||||
|
||||
attack_self(mob/user)
|
||||
if(!isturf(user.loc))
|
||||
user << "<span class='warning'>You cannot turn the light on while in this [user.loc]!</span>" //To prevent some lighting anomalities.
|
||||
return
|
||||
on = !on
|
||||
icon_state = "hardhat[on]_[item_color]"
|
||||
item_state = "hardhat[on]_[item_color]"
|
||||
user.update_inv_head() //so our mob-overlays update
|
||||
/obj/item/clothing/head/hardhat/attack_self(mob/user)
|
||||
if(!isturf(user.loc))
|
||||
user << "<span class='warning'>You cannot turn the light on while in this [user.loc]!</span>" //To prevent some lighting anomalities.
|
||||
return
|
||||
on = !on
|
||||
icon_state = "hardhat[on]_[item_color]"
|
||||
item_state = "hardhat[on]_[item_color]"
|
||||
user.update_inv_head() //so our mob-overlays update
|
||||
|
||||
if(on) user.AddLuminosity(brightness_on)
|
||||
else user.AddLuminosity(-brightness_on)
|
||||
if(on)
|
||||
turn_on(user)
|
||||
else
|
||||
turn_off(user)
|
||||
|
||||
pickup(mob/user)
|
||||
if(on)
|
||||
user.AddLuminosity(brightness_on)
|
||||
// user.UpdateLuminosity() //TODO: Carn
|
||||
SetLuminosity(0)
|
||||
/obj/item/clothing/head/hardhat/pickup(mob/user)
|
||||
if(on)
|
||||
user.AddLuminosity(brightness_on)
|
||||
SetLuminosity(0)
|
||||
|
||||
dropped(mob/user)
|
||||
if(on)
|
||||
user.AddLuminosity(-brightness_on)
|
||||
// user.UpdateLuminosity()
|
||||
SetLuminosity(brightness_on)
|
||||
/obj/item/clothing/head/hardhat/dropped(mob/user)
|
||||
if(on)
|
||||
user.AddLuminosity(-brightness_on)
|
||||
SetLuminosity(brightness_on)
|
||||
|
||||
/obj/item/clothing/head/hardhat/proc/turn_on(mob/user)
|
||||
user.AddLuminosity(brightness_on)
|
||||
|
||||
/obj/item/clothing/head/hardhat/proc/turn_off(mob/user)
|
||||
user.AddLuminosity(-brightness_on)
|
||||
|
||||
/obj/item/clothing/head/hardhat/orange
|
||||
icon_state = "hardhat0_orange"
|
||||
|
||||
@@ -167,6 +167,35 @@
|
||||
// Offer about the same protection as a hardhat.
|
||||
flags_inv = HIDEEARS|HIDEEYES
|
||||
|
||||
/obj/item/clothing/head/helmet/knight
|
||||
name = "medieval helmet"
|
||||
desc = "A classic metal helmet."
|
||||
icon_state = "knight_green"
|
||||
item_state = "knight_green"
|
||||
armor = list(melee = 41, bullet = 15, laser = 5,energy = 5, bomb = 5, bio = 2, rad = 0)
|
||||
flags = BLOCKHAIR
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
|
||||
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
|
||||
strip_delay = 80
|
||||
|
||||
/obj/item/clothing/head/helmet/knight/blue
|
||||
icon_state = "knight_blue"
|
||||
item_state = "knight_blue"
|
||||
|
||||
/obj/item/clothing/head/helmet/knight/yellow
|
||||
icon_state = "knight_yellow"
|
||||
item_state = "knight_yellow"
|
||||
|
||||
/obj/item/clothing/head/helmet/knight/red
|
||||
icon_state = "knight_red"
|
||||
item_state = "knight_red"
|
||||
|
||||
/obj/item/clothing/head/helmet/knight/templar
|
||||
name = "crusader helmet"
|
||||
desc = "Deus Vult."
|
||||
icon_state = "knight_templar"
|
||||
item_state = "knight_templar"
|
||||
|
||||
//LightToggle
|
||||
|
||||
/obj/item/clothing/head/helmet/update_icon()
|
||||
|
||||
@@ -71,6 +71,14 @@
|
||||
flags_cover = HEADCOVERSEYES
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
|
||||
|
||||
/obj/item/clothing/head/snowman
|
||||
name = "Snowman Head"
|
||||
desc = "A ball of white styrofoam. So festive."
|
||||
icon_state = "snowman_h"
|
||||
item_state = "snowman_h"
|
||||
flags_cover = HEADCOVERSEYES
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
|
||||
|
||||
/obj/item/clothing/head/justice
|
||||
name = "justice hat"
|
||||
desc = "Fight for what's righteous!"
|
||||
|
||||
@@ -42,22 +42,21 @@
|
||||
/*
|
||||
* Cakehat
|
||||
*/
|
||||
/obj/item/clothing/head/cakehat
|
||||
name = "cake-hat"
|
||||
desc = "It's tasty looking!"
|
||||
icon_state = "cake0"
|
||||
/obj/item/clothing/head/hardhat/cakehat
|
||||
name = "cakehat"
|
||||
desc = "You put the cake on your head. Brilliant."
|
||||
icon_state = "hardhat0_cakehat"
|
||||
item_state = "hardhat0_cakehat"
|
||||
item_color = "cakehat"
|
||||
flags = BLOCKHAIR
|
||||
flags_inv = HIDEEARS
|
||||
action_button_name = "Toggle Candle"
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
|
||||
brightness_on = 2 //luminosity when on
|
||||
flags_cover = HEADCOVERSEYES
|
||||
var/onfire = 0
|
||||
var/brightness_on = 1 // luminosity when lit
|
||||
var/status = 0
|
||||
var/fire_resist = T0C+1300 //this is the max temp it can stand before you start to cook. although it might not burn away, you take damage
|
||||
var/processing = 0 //I dont think this is used anywhere.
|
||||
|
||||
/obj/item/clothing/head/cakehat/process()
|
||||
if(!onfire)
|
||||
SSobj.processing.Remove(src)
|
||||
return
|
||||
heat = 1000
|
||||
|
||||
/obj/item/clothing/head/hardhat/cakehat/process()
|
||||
var/turf/location = src.loc
|
||||
if(istype(location, /mob/))
|
||||
var/mob/living/carbon/human/M = location
|
||||
@@ -67,23 +66,20 @@
|
||||
if (istype(location, /turf))
|
||||
location.hotspot_expose(700, 1)
|
||||
|
||||
/obj/item/clothing/head/cakehat/attack_self(mob/user)
|
||||
if(status > 1) return
|
||||
src.onfire = !( src.onfire )
|
||||
if (src.onfire)
|
||||
src.force = 15
|
||||
src.AddLuminosity(brightness_on)
|
||||
src.damtype = "fire"
|
||||
src.icon_state = "cake1"
|
||||
SSobj.processing |= src
|
||||
else
|
||||
src.force = null
|
||||
src.AddLuminosity(-brightness_on)
|
||||
src.damtype = "brute"
|
||||
src.icon_state = "cake0"
|
||||
return
|
||||
/obj/item/clothing/head/hardhat/cakehat/turn_on()
|
||||
..()
|
||||
force = 15
|
||||
damtype = BURN
|
||||
SSobj.processing |= src
|
||||
|
||||
/obj/item/clothing/head/hardhat/cakehat/turn_off()
|
||||
..()
|
||||
force = 0
|
||||
damtype = BRUTE
|
||||
SSobj.processing -= src
|
||||
|
||||
/obj/item/clothing/head/hardhat/cakehat/is_hot()
|
||||
return on * heat
|
||||
/*
|
||||
* Ushanka
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
ears = /obj/item/device/radio/headset/headset_cent/alt
|
||||
|
||||
/datum/outfit/ert/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/ert/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(H)
|
||||
L.imp_in = H
|
||||
L.implanted = 1
|
||||
@@ -34,8 +37,12 @@
|
||||
/obj/item/weapon/gun/energy/gun=1)
|
||||
l_pocket = /obj/item/weapon/switchblade
|
||||
|
||||
/datum/outfit/ert/commander/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/ert/commander/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/device/radio/R = H.ears
|
||||
R.keyslot = new /obj/item/device/encryptionkey/heads/captain
|
||||
R.recalculateChannels()
|
||||
@@ -64,8 +71,12 @@
|
||||
/obj/item/weapon/melee/baton/loaded=1,\
|
||||
/obj/item/weapon/gun/energy/gun/advtaser=1)
|
||||
|
||||
/datum/outfit/ert/security/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/ert/security/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/device/radio/R = H.ears
|
||||
R.keyslot = new /obj/item/device/encryptionkey/heads/hos
|
||||
R.recalculateChannels()
|
||||
@@ -95,8 +106,12 @@
|
||||
/obj/item/weapon/gun/energy/gun=1,\
|
||||
/obj/item/weapon/reagent_containers/hypospray/combat=1)
|
||||
|
||||
/datum/outfit/ert/medic/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/ert/medic/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/device/radio/R = H.ears
|
||||
R.keyslot = new /obj/item/device/encryptionkey/heads/cmo
|
||||
R.recalculateChannels()
|
||||
@@ -126,8 +141,12 @@
|
||||
/obj/item/weapon/gun/energy/gun=1,\
|
||||
/obj/item/weapon/rcd/loaded=1)
|
||||
|
||||
/datum/outfit/ert/engineer/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/ert/engineer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/device/radio/R = H.ears
|
||||
R.keyslot = new /obj/item/device/encryptionkey/heads/ce
|
||||
R.recalculateChannels()
|
||||
@@ -157,7 +176,10 @@
|
||||
l_hand = /obj/item/weapon/clipboard
|
||||
id = /obj/item/weapon/card/id
|
||||
|
||||
/datum/outfit/centcom_official/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/centcom_official/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/device/pda/heads/pda = H.r_store
|
||||
pda.owner = H.real_name
|
||||
pda.ownjob = "Centcom Official"
|
||||
|
||||
@@ -56,7 +56,10 @@
|
||||
l_pocket = /obj/item/weapon/grenade/chem_grenade/cleaner
|
||||
backpack_contents = list(/obj/item/stack/tile/plasteel=6)
|
||||
|
||||
/datum/outfit/tournament/janitor/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/tournament/janitor/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/weapon/reagent_containers/glass/bucket/bucket = H.l_hand
|
||||
bucket.reagents.add_reagent("water",70)
|
||||
|
||||
@@ -112,7 +115,10 @@
|
||||
id = /obj/item/weapon/card/id
|
||||
r_hand = /obj/item/weapon/twohanded/fireaxe
|
||||
|
||||
/datum/outfit/tunnel_clown/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/tunnel_clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/weapon/card/id/W = H.wear_id
|
||||
W.access = get_all_accesses()
|
||||
W.assignment = "Tunnel Clown!"
|
||||
@@ -153,10 +159,13 @@
|
||||
id = /obj/item/weapon/card/id/syndicate
|
||||
belt = /obj/item/device/pda/heads
|
||||
|
||||
/datum/outfit/assassin/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/assassin/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
var/obj/item/clothing/under/U = H.w_uniform
|
||||
U.attachTie(new /obj/item/clothing/tie/waistcoat(H))
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
//Could use a type
|
||||
var/obj/item/weapon/storage/secure/briefcase/sec_briefcase = H.l_hand
|
||||
for(var/obj/item/briefcase_item in sec_briefcase)
|
||||
@@ -196,7 +205,10 @@
|
||||
back = /obj/item/weapon/storage/backpack/satchel
|
||||
id = /obj/item/weapon/card/id
|
||||
|
||||
/datum/outfit/centcom_commander/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/centcom_commander/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/weapon/card/id/W = H.wear_id
|
||||
W.icon_state = "centcom"
|
||||
W.access = get_all_accesses()
|
||||
@@ -221,7 +233,10 @@
|
||||
back = /obj/item/weapon/storage/backpack/satchel
|
||||
id = /obj/item/weapon/card/id
|
||||
|
||||
/datum/outfit/spec_ops/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/spec_ops/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/weapon/card/id/W = H.wear_id
|
||||
W.icon_state = "centcom"
|
||||
W.access = get_all_accesses()
|
||||
@@ -276,7 +291,10 @@
|
||||
|
||||
id = /obj/item/weapon/card/id
|
||||
|
||||
/datum/outfit/soviet/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/soviet/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/weapon/card/id/W = H.wear_id
|
||||
W.icon_state = "centcom"
|
||||
W.access = get_all_accesses()
|
||||
@@ -297,7 +315,10 @@
|
||||
r_hand = /obj/item/weapon/gun/projectile/automatic/tommygun
|
||||
id = /obj/item/weapon/card/id
|
||||
|
||||
/datum/outfit/mobster/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/mobster/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/weapon/card/id/W = H.wear_id
|
||||
W.assignment = "Assistant"
|
||||
W.registered_name = H.real_name
|
||||
@@ -306,9 +327,9 @@
|
||||
/datum/outfit/plasmaman
|
||||
name = "Plasmaman"
|
||||
|
||||
head = /obj/item/clothing/head/helmet/plasmaman
|
||||
head = /obj/item/clothing/head/helmet/space/plasmaman
|
||||
uniform = /obj/item/clothing/under/plasmaman
|
||||
belt = /obj/item/weapon/tank/internals/plasmaman/belt/full
|
||||
r_hand= /obj/item/weapon/tank/internals/plasmaman/belt/full
|
||||
mask = /obj/item/clothing/mask/breath
|
||||
|
||||
/datum/outfit/death_commando
|
||||
@@ -336,7 +357,10 @@
|
||||
/obj/item/device/flashlight=1,\
|
||||
/obj/item/weapon/c4=1)
|
||||
|
||||
/datum/outfit/death_commando/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/death_commando/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/obj/item/device/radio/R = H.ears
|
||||
R.set_frequency(CENTCOM_FREQ)
|
||||
R.freqlock = 1
|
||||
|
||||
@@ -254,6 +254,31 @@
|
||||
jetpack = new /obj/item/weapon/tank/jetpack/suit(src)
|
||||
..()
|
||||
|
||||
|
||||
//Elite Syndie suit
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/syndi/elite
|
||||
name = "elite syndicate hardsuit helmet"
|
||||
desc = "An elite version of the syndicate helmet, with improved armour and fire shielding. It is in travel mode. Property of Gorlex Marauders."
|
||||
alt_desc = "An elite version of the syndicate helmet, with improved armour and fire shielding. It is in combat mode. Property of Gorlex Marauders."
|
||||
icon_state = "hardsuit0-syndielite"
|
||||
item_color = "syndielite"
|
||||
armor = list(melee = 60, bullet = 60, laser = 50, energy = 25, bomb = 55, bio = 100, rad = 70)
|
||||
heat_protection = HEAD
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/syndi/elite
|
||||
name = "elite syndicate hardsuit"
|
||||
desc = "An elite version of the syndicate hardsuit, with improved armour and fire shielding. It is in travel mode."
|
||||
alt_desc = "An elite version of the syndicate hardsuit, with improved armour and fire shielding. It is in combat mode."
|
||||
icon_state = "hardsuit0-syndielite"
|
||||
item_color = "syndielite"
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi/elite
|
||||
armor = list(melee = 60, bullet = 60, laser = 50, energy = 25, bomb = 55, bio = 100, rad = 70)
|
||||
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
|
||||
|
||||
//The Owl Hardsuit
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/syndi/owl
|
||||
name = "owl hardsuit helmet"
|
||||
|
||||
@@ -56,7 +56,7 @@ Contains:
|
||||
allowed = list(/obj/item/weapon/gun,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/weapon/tank/internals)
|
||||
armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100)
|
||||
strip_delay = 130
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
unacidable = 1
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/deathsquad
|
||||
|
||||
@@ -267,3 +267,25 @@ Contains:
|
||||
armor = list(melee = -20, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 100, rad = 75) //As whimpy whimpy whoo
|
||||
allowed = list(/obj/item/weapon/tank/internals, /obj/item/weapon/gun/projectile/automatic/speargun) //I'm giving you a hint here
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/carp
|
||||
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal
|
||||
name = "paranormal response unit helmet"
|
||||
desc = "A helmet worn by those who deal with paranormal threats for a living."
|
||||
icon_state = "hardsuit0-prt"
|
||||
item_state = "hardsuit0-prt"
|
||||
item_color = "knight_grey"
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/ert/paranormal
|
||||
name = "paranormal response team suit"
|
||||
desc = "Powerful wards are built into this hardsuit, protecting the user from all manner of paranormal threats."
|
||||
icon_state = "knight_grey"
|
||||
item_state = "knight_grey"
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/New()
|
||||
..()
|
||||
new /obj/item/weapon/nullrod(src)
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
|
||||
//I just want the light feature of the hardsuit helmet
|
||||
/obj/item/clothing/head/helmet/plasmaman
|
||||
/obj/item/clothing/head/helmet/space/plasmaman
|
||||
name = "plasmaman helmet"
|
||||
desc = "A special containment helmet designed to protect a plasmaman's volatile body from outside exposure and quickly extinguish it in emergencies."
|
||||
icon_state = "plasmaman-helm"
|
||||
|
||||
@@ -134,11 +134,8 @@
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
|
||||
action_button_name = "Toggle Armor"
|
||||
unacidable = 1
|
||||
hit_reaction_chance = 50
|
||||
|
||||
/obj/item/clothing/suit/armor/reactive/IsShield()
|
||||
if(active)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/suit/armor/reactive/attack_self(mob/user)
|
||||
src.active = !( src.active )
|
||||
@@ -159,6 +156,46 @@
|
||||
src.item_state = "reactiveoff"
|
||||
..()
|
||||
|
||||
/obj/item/clothing/suit/armor/reactive/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
|
||||
if(!active)
|
||||
return 0
|
||||
if(prob(hit_reaction_chance))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
owner.visible_message("<span class='danger'>The reactive teleport system flings [H] clear of [attack_text]!</span>")
|
||||
var/list/turfs = new/list()
|
||||
for(var/turf/T in orange(6, H))
|
||||
if(T.density)
|
||||
continue
|
||||
if(T.x>world.maxx-6 || T.x<6)
|
||||
continue
|
||||
if(T.y>world.maxy-6 || T.y<6)
|
||||
continue
|
||||
turfs += T
|
||||
if(!turfs.len)
|
||||
turfs += pick(/turf in orange(6, src))
|
||||
var/turf/picked = pick(turfs)
|
||||
if(!isturf(picked))
|
||||
return
|
||||
if(H.buckled)
|
||||
H.buckled.unbuckle_mob()
|
||||
H.forceMove(picked)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/suit/armor/reactive/fire
|
||||
name = "reactive incendiary armor"
|
||||
|
||||
|
||||
/obj/item/clothing/suit/armor/reactive/fire/hit_reaction(mob/living/carbon/human/owner, attack_text)
|
||||
if(prob(hit_reaction_chance))
|
||||
owner.visible_message("<span class='danger'>The [src] blocks the [attack_text], sending out jets of flame!</span>")
|
||||
for(var/mob/living/carbon/C in range(6, owner))
|
||||
if(C != owner)
|
||||
C.fire_stacks += 8
|
||||
C.IgniteMob()
|
||||
owner.fire_stacks = -20
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//All of the armor below is mostly unused
|
||||
|
||||
@@ -208,3 +245,28 @@
|
||||
desc = "Pukish armor." //classy.
|
||||
icon_state = "tdgreen"
|
||||
item_state = "tdgreen"
|
||||
|
||||
|
||||
/obj/item/clothing/suit/armor/riot/knight
|
||||
name = "plate armour"
|
||||
desc = "A classic suit of plate armour, highly effective at stopping melee attacks."
|
||||
icon_state = "knight_green"
|
||||
item_state = "knight_green"
|
||||
|
||||
/obj/item/clothing/suit/armor/riot/knight/yellow
|
||||
icon_state = "knight_yellow"
|
||||
item_state = "knight_yellow"
|
||||
|
||||
/obj/item/clothing/suit/armor/riot/knight/blue
|
||||
icon_state = "knight_blue"
|
||||
item_state = "knight_blue"
|
||||
|
||||
/obj/item/clothing/suit/armor/riot/knight/red
|
||||
icon_state = "knight_red"
|
||||
item_state = "knight_red"
|
||||
|
||||
/obj/item/clothing/suit/armor/riot/knight/templar
|
||||
name = "crusader armour"
|
||||
desc = "God wills it!"
|
||||
icon_state = "knight_templar"
|
||||
item_state = "knight_templar"
|
||||
@@ -1,12 +1,11 @@
|
||||
//Cloaks. No, not THAT kind of cloak.
|
||||
|
||||
/obj/item/clothing/cloak
|
||||
/obj/item/clothing/suit/cloak
|
||||
name = "brown cloak"
|
||||
desc = "It's a cape that can be worn on your back."
|
||||
icon = 'icons/obj/clothing/cloaks.dmi'
|
||||
icon_state = "qmcloak"
|
||||
w_class = 2
|
||||
slot_flags = SLOT_BACK
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
|
||||
|
||||
@@ -14,39 +13,39 @@
|
||||
user.visible_message("<span class='suicide'>[user] is strangling themself with [src]! It looks like they're trying to commit suicide.</span>")
|
||||
return(OXYLOSS)
|
||||
|
||||
/obj/item/clothing/cloak/hos
|
||||
/obj/item/clothing/suit/cloak/hos
|
||||
name = "head of security's cloak"
|
||||
desc = "Worn by Securistan, ruling the station with an iron fist. It's slightly armored."
|
||||
icon_state = "hoscloak"
|
||||
armor = list(melee = 10, bullet = 10, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
|
||||
armor = list(melee = 30, bullet = 30, laser = 10, energy = 10, bomb = 25, bio = 0, rad = 0)
|
||||
|
||||
/obj/item/clothing/cloak/qm
|
||||
/obj/item/clothing/suit/cloak/qm
|
||||
name = "quartermaster's cloak"
|
||||
desc = "Worn by Cargonia, supplying the station with the necessary tools for survival."
|
||||
|
||||
/obj/item/clothing/cloak/cmo
|
||||
/obj/item/clothing/suit/cloak/cmo
|
||||
name = "chief medical officer's cloak"
|
||||
desc = "Worn by Meditopia, the valiant men and women keeping pestilence at bay. It's slightly shielded from contaminants."
|
||||
icon_state = "cmocloak"
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 25, rad = 0)
|
||||
|
||||
/obj/item/clothing/cloak/ce
|
||||
/obj/item/clothing/suit/cloak/ce
|
||||
name = "chief engineer's cloak"
|
||||
desc = "Worn by Engitopia, wielders of an unlimited power. It's slightly shielded against radiation."
|
||||
icon_state = "cecloak"
|
||||
armor = list(melee = 10, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 10)
|
||||
|
||||
/obj/item/clothing/cloak/rd
|
||||
/obj/item/clothing/suit/cloak/rd
|
||||
name = "research director's cloak."
|
||||
desc = "Worn by Sciencia, thaumaturges and researchers of the universe. It's slightly shielded from contaminants."
|
||||
icon_state = "rdcloak"
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 10, bio = 10, rad = 0)
|
||||
|
||||
/obj/item/clothing/cloak/cap
|
||||
/obj/item/clothing/suit/cloak/cap
|
||||
name = "captain's cloak"
|
||||
desc = "Worm by the commander of Space Station 13."
|
||||
desc = "Worn by the commander of Space Station 13."
|
||||
icon_state = "capcloak"
|
||||
armor = list(melee = 10, bullet = 10, laser = 10, energy = 10, bomb = 10, bio = 10, rad = 10)
|
||||
armor = list(melee = 30, bullet = 30, laser = 30, energy = 10, bomb = 25, bio = 10, rad = 10)
|
||||
|
||||
/* //wip
|
||||
/obj/item/clothing/cloak/wizard //Not actually obtainable until proper balancing can be done
|
||||
@@ -165,6 +165,14 @@
|
||||
body_parts_covered = CHEST|GROIN
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
|
||||
/obj/item/clothing/suit/snowman
|
||||
name = "snowman outfit"
|
||||
desc = "Two white spheres covered in white glitter. 'Tis the season."
|
||||
icon_state = "snowman"
|
||||
item_state = "snowman"
|
||||
body_parts_covered = CHEST|GROIN
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
|
||||
/obj/item/clothing/suit/poncho
|
||||
name = "poncho"
|
||||
desc = "Your classic, non-racist poncho."
|
||||
|
||||
@@ -59,6 +59,9 @@
|
||||
fitted = FEMALE_UNIFORM_TOP
|
||||
can_adjust = 0
|
||||
|
||||
/obj/item/clothing/under/rank/clown/hit_reaction()
|
||||
playsound(loc, 'sound/items/bikehorn.ogg', 50, 1, -1)
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/under/rank/head_of_personnel
|
||||
desc = "It's a jumpsuit worn by someone who works in the position of \"Head of Personnel\"."
|
||||
|
||||
@@ -507,11 +507,10 @@
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 100, rad = 0)
|
||||
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
can_adjust = 0
|
||||
slowdown = 1
|
||||
strip_delay = 80
|
||||
var/next_extinguish = 0
|
||||
var/extinguish_cooldown = 100
|
||||
var/extinguishes_left = 10
|
||||
var/extinguishes_left = 5
|
||||
|
||||
|
||||
/obj/item/clothing/under/plasmaman/examine(mob/user)
|
||||
@@ -536,11 +535,11 @@
|
||||
|
||||
/obj/item/clothing/under/plasmaman/attackby(obj/item/E, mob/user, params)
|
||||
if (istype(E, /obj/item/device/extinguisher_refill))
|
||||
if (extinguishes_left == 10)
|
||||
if (extinguishes_left == 5)
|
||||
user << "<span class='notice'>The inbuilt extinguisher is full.</span>"
|
||||
return
|
||||
else
|
||||
extinguishes_left = 10
|
||||
extinguishes_left = 5
|
||||
user << "<span class='notice'>You refill the suits inbuilt extinguisher, using up the refill pack.</span>"
|
||||
qdel(E)
|
||||
return
|
||||
@@ -550,5 +549,5 @@
|
||||
/obj/item/device/extinguisher_refill
|
||||
name = "Plasma-man jumpsuit refill pack"
|
||||
desc = "A compressed water pack used to refill plasma-man jumpsuit auto-extinguishers."
|
||||
icon_state = "multitool"
|
||||
icon_state = "plasmarefill"
|
||||
|
||||
|
||||
@@ -69,9 +69,21 @@
|
||||
parts = list(/obj/item/weapon/stock_parts/cell = 1)
|
||||
category = CAT_WEAPON
|
||||
|
||||
/datum/table_recipe/teleprod
|
||||
name = "Teleprod"
|
||||
result = /obj/item/weapon/melee/baton/cattleprod/teleprod
|
||||
reqs = list(/obj/item/weapon/restraints/handcuffs/cable = 1,
|
||||
/obj/item/stack/rods = 1,
|
||||
/obj/item/weapon/wirecutters = 1,
|
||||
/obj/item/weapon/stock_parts/cell = 1,
|
||||
/obj/item/weapon/ore/bluespace_crystal = 1)
|
||||
time = 80
|
||||
parts = list(/obj/item/weapon/stock_parts/cell = 1)
|
||||
category = CAT_WEAPON
|
||||
|
||||
/datum/table_recipe/ed209
|
||||
name = "ED209"
|
||||
result = /obj/machinery/bot/ed209
|
||||
result = /mob/living/simple_animal/bot/ed209
|
||||
reqs = list(/obj/item/robot_parts/robot_suit = 1,
|
||||
/obj/item/clothing/head/helmet = 1,
|
||||
/obj/item/clothing/suit/armor/vest = 1,
|
||||
@@ -89,7 +101,7 @@
|
||||
|
||||
/datum/table_recipe/secbot
|
||||
name = "Secbot"
|
||||
result = /obj/machinery/bot/secbot
|
||||
result = /mob/living/simple_animal/bot/secbot
|
||||
reqs = list(/obj/item/device/assembly/signaler = 1,
|
||||
/obj/item/clothing/head/helmet/sec = 1,
|
||||
/obj/item/weapon/melee/baton = 1,
|
||||
@@ -101,7 +113,7 @@
|
||||
|
||||
/datum/table_recipe/cleanbot
|
||||
name = "Cleanbot"
|
||||
result = /obj/machinery/bot/cleanbot
|
||||
result = /mob/living/simple_animal/bot/cleanbot
|
||||
reqs = list(/obj/item/weapon/reagent_containers/glass/bucket = 1,
|
||||
/obj/item/device/assembly/prox_sensor = 1,
|
||||
/obj/item/robot_parts/r_arm = 1)
|
||||
@@ -110,7 +122,7 @@
|
||||
|
||||
/datum/table_recipe/floorbot
|
||||
name = "Floorbot"
|
||||
result = /obj/machinery/bot/floorbot
|
||||
result = /mob/living/simple_animal/bot/floorbot
|
||||
reqs = list(/obj/item/weapon/storage/toolbox/mechanical = 1,
|
||||
/obj/item/stack/tile/plasteel = 1,
|
||||
/obj/item/device/assembly/prox_sensor = 1,
|
||||
@@ -120,7 +132,7 @@
|
||||
|
||||
/datum/table_recipe/medbot
|
||||
name = "Medbot"
|
||||
result = /obj/machinery/bot/medbot
|
||||
result = /mob/living/simple_animal/bot/medbot
|
||||
reqs = list(/obj/item/device/healthanalyzer = 1,
|
||||
/obj/item/weapon/storage/firstaid = 1,
|
||||
/obj/item/device/assembly/prox_sensor = 1,
|
||||
|
||||
@@ -68,4 +68,4 @@
|
||||
message_admins("Situation has been resolved")
|
||||
return 0
|
||||
message_admins("Unfortunately, no candidates were available for becoming an alien. Shutting down.")
|
||||
return kill()
|
||||
return kill()
|
||||
|
||||
@@ -11,11 +11,18 @@
|
||||
/datum/round_event/falsealarm/announce()
|
||||
var/list/events_list = list()
|
||||
for(var/datum/round_event_control/E in SSevent.control)
|
||||
if(!E.wizardevent && !E.holidayID) //No holiday cheer allowed during non-holidays. Not even fake holiday cheer.
|
||||
events_list += E //No holiday cheer allowed during non-holidays. Not even fake holiday cheer.
|
||||
if(E.holidayID || E.wizardevent)
|
||||
continue
|
||||
var/datum/round_event/event = E.typepath
|
||||
if(initial(event.announceWhen) <= 0)
|
||||
continue
|
||||
events_list += E
|
||||
|
||||
var/datum/round_event_control/event_control = pick(events_list)
|
||||
if(event_control)
|
||||
var/datum/round_event/Event = new event_control.typepath()
|
||||
message_admins("False Alarm: [Event]")
|
||||
Event.kill() //do not process this event - no starts, no ticks, no ends
|
||||
Event.announce() //just announce it like it's happening
|
||||
Event.announce() //just announce it like it's happening
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
M << "<br>"
|
||||
|
||||
if(botEmagChance)
|
||||
for(var/obj/machinery/bot/bot in machines)
|
||||
for(var/mob/living/simple_animal/bot/bot in living_mob_list)
|
||||
if(prob(botEmagChance))
|
||||
bot.Emag()
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
/datum/spacevine_mutation/proc/on_buckle(obj/effect/spacevine/holder, mob/living/buckled)
|
||||
return
|
||||
|
||||
/datum/spacevine_mutation/proc/on_explosion(severity, target, obj/effect/spacevine/holder)
|
||||
return
|
||||
|
||||
|
||||
/datum/spacevine_mutation/space_covering
|
||||
name = "space protective"
|
||||
@@ -137,10 +140,11 @@
|
||||
name = "light"
|
||||
hue = "#ffff00"
|
||||
quality = POSITIVE
|
||||
severity = 4
|
||||
|
||||
/datum/spacevine_mutation/light/on_grow(obj/effect/spacevine/holder)
|
||||
if(prob(10*severity))
|
||||
holder.SetLuminosity(4)
|
||||
if(holder.energy)
|
||||
holder.SetLuminosity(severity, 3)
|
||||
|
||||
/datum/spacevine_mutation/toxicity
|
||||
name = "toxic"
|
||||
@@ -162,12 +166,18 @@
|
||||
name = "explosive"
|
||||
hue = "#ff0000"
|
||||
quality = NEGATIVE
|
||||
severity = 2
|
||||
|
||||
/datum/spacevine_mutation/explosive/on_explosion(explosion_severity, target, obj/effect/spacevine/holder)
|
||||
if(explosion_severity < 3)
|
||||
qdel(src)
|
||||
else
|
||||
. = 1
|
||||
spawn(5)
|
||||
qdel(src)
|
||||
|
||||
/datum/spacevine_mutation/explosive/on_death(obj/effect/spacevine/holder, mob/hitter, obj/item/I)
|
||||
var/turf/T = holder.loc
|
||||
src = T
|
||||
spawn(10)
|
||||
explosion(T, 0, 0, 2, 0, 0)
|
||||
explosion(holder.loc, 0, 0, severity, 0, 0)
|
||||
|
||||
/datum/spacevine_mutation/fire_proof
|
||||
name = "fire proof"
|
||||
@@ -194,9 +204,7 @@
|
||||
quality = NEGATIVE
|
||||
|
||||
/datum/spacevine_mutation/aggressive_spread/on_spread(obj/effect/spacevine/holder, turf/target)
|
||||
for(var/atom/A in target)
|
||||
if(!istype(A, /obj/effect))
|
||||
A.ex_act(severity) //To not be the same as self-eating vine
|
||||
target.ex_act(severity, src)
|
||||
|
||||
/datum/spacevine_mutation/aggressive_spread/on_buckle(obj/effect/spacevine/holder, mob/living/buckled)
|
||||
buckled.ex_act(severity)
|
||||
@@ -297,6 +305,24 @@
|
||||
return 1
|
||||
|
||||
|
||||
/datum/spacevine_mutation/flowering
|
||||
name = "flowering"
|
||||
hue = "#0A480D"
|
||||
quality = NEGATIVE
|
||||
severity = 10
|
||||
|
||||
|
||||
/datum/spacevine_mutation/flowering/on_grow(obj/effect/spacevine/holder)
|
||||
if(holder.energy == 2 && prob(severity) && !locate(/obj/structure/alien/resin/flower_bud_enemy) in range(5,holder))
|
||||
var/obj/structure/alien/resin/flower_bud_enemy/FBE = new /obj/structure/alien/resin/flower_bud_enemy (get_turf(holder))
|
||||
FBE.layer = holder.layer+0.1
|
||||
|
||||
|
||||
/datum/spacevine_mutation/flowering/on_cross(obj/effect/spacevine/holder, mob/living/crosser)
|
||||
holder.entangle(crosser)
|
||||
|
||||
|
||||
|
||||
// SPACE VINES (Note that this code is very similar to Biomass code)
|
||||
/obj/effect/spacevine
|
||||
name = "space vines"
|
||||
@@ -485,8 +511,6 @@
|
||||
break
|
||||
|
||||
growth_queue = growth_queue + queue_end
|
||||
//sleep(5)
|
||||
//src.process()
|
||||
|
||||
/obj/effect/spacevine/proc/grow()
|
||||
if(!energy)
|
||||
@@ -503,14 +527,21 @@
|
||||
|
||||
/obj/effect/spacevine/proc/entangle_mob()
|
||||
if(!buckled_mob && prob(25))
|
||||
for(var/mob/living/carbon/V in src.loc)
|
||||
for(var/datum/spacevine_mutation/SM in mutations)
|
||||
SM.on_buckle(src, V)
|
||||
if((V.stat != DEAD) && (V.buckled != src)) //not dead or captured
|
||||
V << "<span class='danger'>The vines [pick("wind", "tangle", "tighten")] around you!</span>"
|
||||
buckle_mob(V)
|
||||
for(var/mob/living/V in src.loc)
|
||||
entangle(V)
|
||||
if(buckled_mob)
|
||||
break //only capture one mob at a time
|
||||
|
||||
|
||||
/obj/effect/spacevine/proc/entangle(mob/living/V)
|
||||
if(!V)
|
||||
return
|
||||
for(var/datum/spacevine_mutation/SM in mutations)
|
||||
SM.on_buckle(src, V)
|
||||
if((V.stat != DEAD) && (V.buckled != src)) //not dead or captured
|
||||
V << "<span class='danger'>The vines [pick("wind", "tangle", "tighten")] around you!</span>"
|
||||
buckle_mob(V)
|
||||
|
||||
/obj/effect/spacevine/proc/spread()
|
||||
var/direction = pick(cardinal)
|
||||
var/turf/stepturf = get_step(src,direction)
|
||||
@@ -522,54 +553,14 @@
|
||||
if(master)
|
||||
master.spawn_spacevine_piece(stepturf, src)
|
||||
|
||||
/*
|
||||
/obj/effect/spacevine/proc/Life()
|
||||
if (!src) return
|
||||
var/Vspread
|
||||
if (prob(50)) Vspread = locate(src.x + rand(-1,1),src.y,src.z)
|
||||
else Vspread = locate(src.x,src.y + rand(-1, 1),src.z)
|
||||
var/dogrowth = 1
|
||||
if (!istype(Vspread, /turf/simulated)) dogrowth = 0
|
||||
for(var/obj/O in Vspread)
|
||||
if (istype(O, /obj/structure/window) || istype(O, /obj/effect/forcefield) || istype(O, /obj/effect/blob) || istype(O, /obj/effect/alien/weeds) || istype(O, /obj/effect/spacevine)) dogrowth = 0
|
||||
if (istype(O, /obj/machinery/door/))
|
||||
if(O:p_open == 0 && prob(50)) O:open()
|
||||
else dogrowth = 0
|
||||
if (dogrowth == 1)
|
||||
var/obj/effect/spacevine/B = new /obj/effect/spacevine(Vspread)
|
||||
B.icon_state = pick("vine-light1", "vine-light2", "vine-light3")
|
||||
spawn(20)
|
||||
if(B)
|
||||
B.Life()
|
||||
src.growth += 1
|
||||
if (src.growth == 10)
|
||||
src.name = "Thick Space Kudzu"
|
||||
src.icon_state = pick("vine-med1", "vine-med2", "vine-med3")
|
||||
src.opacity = 1
|
||||
src.waittime = 80
|
||||
if (src.growth == 20)
|
||||
src.name = "Dense Space Kudzu"
|
||||
src.icon_state = pick("vine-hvy1", "vine-hvy2", "vine-hvy3")
|
||||
src.density = 1
|
||||
spawn(src.waittime)
|
||||
if (src.growth < 20) src.Life()
|
||||
|
||||
*/
|
||||
|
||||
/obj/effect/spacevine/ex_act(severity, target)
|
||||
switch(severity)
|
||||
if(1)
|
||||
qdel(src)
|
||||
return
|
||||
if(2)
|
||||
if (prob(90))
|
||||
qdel(src)
|
||||
return
|
||||
if(3)
|
||||
if (prob(50))
|
||||
qdel(src)
|
||||
return
|
||||
return
|
||||
if(istype(target, type)) //if its agressive spread vine dont do anything
|
||||
return
|
||||
var/i
|
||||
for(var/datum/spacevine_mutation/SM in mutations)
|
||||
i += SM.on_explosion(severity, target, src)
|
||||
if(!i && prob(100/severity))
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/spacevine/temperature_expose(null, temp, volume)
|
||||
var/override = 0
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
var/list/mobs = list()
|
||||
|
||||
for(var/mob/living/carbon/human/H in living_mob_list)
|
||||
if(!H.mind || H.mind in ticker.mode.wizards) continue //the wizard(s) are spared on this one
|
||||
if(!H.stat || !H.mind || H.mind in ticker.mode.wizards) continue //the wizard(s) are spared on this one
|
||||
mobs += H
|
||||
|
||||
if(!mobs) return
|
||||
|
||||
@@ -172,6 +172,15 @@
|
||||
list_reagents = list("nutriment" = 3, "cocoa" = 1)
|
||||
filling_color = "#A0522D"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/fudgedice
|
||||
name = "fudge dice"
|
||||
desc = "A little cube of chocolate that tends to have a less intense taste if you eat too many at once."
|
||||
icon_state = "chocodice"
|
||||
bonus_reagents = list("nutriment" = 1, "sugar" = 1)
|
||||
list_reagents = list("nutriment" = 3, "cocoa" = 1)
|
||||
filling_color = "#A0522D"
|
||||
trash = /obj/item/weapon/dice/fudge
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/chocoorange
|
||||
name = "chocolate orange"
|
||||
desc = "A festive chocolate orange"
|
||||
|
||||
@@ -118,6 +118,7 @@
|
||||
desc = "A box suited for pizzas."
|
||||
icon = 'icons/obj/food/containers.dmi'
|
||||
icon_state = "pizzabox1"
|
||||
item_state = "pizzabox"
|
||||
var/open = 0 // Is the box open?
|
||||
var/ismessy = 0 // Fancy mess on the lid
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/pizza/pizza // Content pizza
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
var/list/nearby_turfs = orange(3, get_turf(src))
|
||||
var/obj/item/meatslab = allmeat[i]
|
||||
meatslab.loc = src.loc
|
||||
meatslab.throw_at(pick(nearby_turfs),i,3)
|
||||
meatslab.throw_at_fast(pick(nearby_turfs),i,3)
|
||||
for (var/turfs=1 to meat_produced*3)
|
||||
var/turf/gibturf = pick(nearby_turfs)
|
||||
if (!gibturf.density && src in viewers(gibturf))
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"[user] starts to fix part of the microwave.", \
|
||||
"<span class='notice'>You start to fix part of the microwave...</span>" \
|
||||
)
|
||||
if (do_after(user,20, target = src))
|
||||
if (do_after(user,20/O.toolspeed, target = src))
|
||||
user.visible_message( \
|
||||
"[user] fixes part of the microwave.", \
|
||||
"<span class='notice'>You fix part of the microwave.</span>" \
|
||||
@@ -77,7 +77,7 @@
|
||||
"[user] starts to fix part of the microwave.", \
|
||||
"<span class='notice'>You start to fix part of the microwave...</span>" \
|
||||
)
|
||||
if (do_after(user,20, target = src))
|
||||
if (do_after(user,20/O.toolspeed, target = src))
|
||||
user.visible_message( \
|
||||
"[user] fixes the microwave.", \
|
||||
"<span class='notice'>You fix the microwave.</span>" \
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
/datum/table_recipe/birthdaycake
|
||||
name = "Birthday cake"
|
||||
reqs = list(
|
||||
/obj/item/clothing/head/cakehat = 1,
|
||||
/obj/item/clothing/head/hardhat/cakehat = 1,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/store/cake/plain = 1
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/store/cake/birthday
|
||||
|
||||
@@ -21,6 +21,15 @@
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/chococoin
|
||||
category = CAT_FOOD
|
||||
|
||||
/datum/table_recipe/fudgedice
|
||||
name = "Fudge dice"
|
||||
reqs = list(
|
||||
/obj/item/weapon/dice = 1,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/chocolatebar = 1,
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/chococoin
|
||||
category = CAT_FOOD
|
||||
|
||||
/datum/table_recipe/chocoorange
|
||||
name = "Choco orange"
|
||||
reqs = list(
|
||||
|
||||
@@ -91,11 +91,12 @@
|
||||
for(var/obj/O in T)
|
||||
var/obj/O2 = DuplicateObject(O , 1, newloc = X, nerf=nerf_weapons)
|
||||
if(!O2) continue
|
||||
copiedobjs += O2.contents + O2
|
||||
copiedobjs += O2.GetAllContents() + O2
|
||||
|
||||
for(var/mob/M in T)
|
||||
if(istype(M, /mob/camera)) continue // If we need to check for more mobs, I'll add a variable
|
||||
copiedobjs += DuplicateObject(M , 1, newloc = X)
|
||||
var/mob/SM = DuplicateObject(M , 1, newloc = X)
|
||||
copiedobjs += SM.GetAllContents() + SM
|
||||
|
||||
var/global/list/forbidden_vars = list("type","stat","loc","locs","vars", "parent", "parent_type","verbs","ckey","key","x","y","z","contents", "luminosity")
|
||||
for(var/V in T.vars - forbidden_vars)
|
||||
|
||||
@@ -70,15 +70,25 @@
|
||||
// should also remove/limit/filter reagents?
|
||||
// this is an exercise left to others I'm afraid. -Sayu
|
||||
spawned = A.copy_contents_to(linked, 1, nerf_weapons = !emagged)
|
||||
for(var/obj/machinery/M in spawned)
|
||||
M.flags |= NODECONSTRUCT
|
||||
for(var/obj/structure/S in spawned)
|
||||
S.flags |= NODECONSTRUCT
|
||||
effects = list()
|
||||
|
||||
spawn(30)
|
||||
var/list/added = list()
|
||||
for(var/obj/effect/holodeck_effect/HE in spawned)
|
||||
effects += HE
|
||||
spawned -= HE
|
||||
var/atom/x = HE.activate(src)
|
||||
if(istype(x) || islist(x))
|
||||
spawned += x // holocarp are not forever
|
||||
added += x
|
||||
for(var/obj/machinery/M in added)
|
||||
M.flags |= NODECONSTRUCT
|
||||
for(var/obj/structure/S in added)
|
||||
S.flags |= NODECONSTRUCT
|
||||
|
||||
/obj/machinery/computer/holodeck/proc/derez(var/obj/obj, var/silent = 1, var/forced = 0)
|
||||
// Emagging a machine creates an anomaly in the derez systems.
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
New()
|
||||
item_color = "red"
|
||||
|
||||
/obj/item/weapon/holo/esword/IsShield()
|
||||
/obj/item/weapon/holo/esword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
|
||||
if(active)
|
||||
return 1
|
||||
return ..()
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/holo/esword/attack(target as mob, mob/user as mob)
|
||||
@@ -213,8 +213,9 @@
|
||||
|
||||
eventstarted = 1
|
||||
|
||||
for(var/obj/structure/window/holo/W in currentarea)
|
||||
qdel(W)
|
||||
for(var/obj/structure/window/W in currentarea)
|
||||
if(W.flags&NODECONSTRUCT) // Just in case: only holo-windows
|
||||
qdel(W)
|
||||
|
||||
for(var/mob/M in currentarea)
|
||||
M << "FIGHT!"
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/obj/structure/table/holo
|
||||
name = "table"
|
||||
frame = null
|
||||
buildstackamount = 0
|
||||
framestackamount = 0
|
||||
canSmoothWith = null
|
||||
|
||||
/obj/structure/table/holo/glass
|
||||
name = "glass table"
|
||||
icon = 'icons/obj/smooth_structures/glass_table.dmi'
|
||||
icon_state = "glass_table"
|
||||
|
||||
/obj/structure/table/holo/wood
|
||||
name = "wood table"
|
||||
icon = 'icons/obj/smooth_structures/wood_table.dmi'
|
||||
icon_state = "wood_table"
|
||||
canSmoothWith = list(/obj/structure/table/holo/wood, /obj/structure/table/holo/poker)
|
||||
|
||||
/obj/structure/table/holo/poker
|
||||
name = "poker table"
|
||||
icon = 'icons/obj/smooth_structures/poker_table.dmi'
|
||||
icon_state = "poker_table"
|
||||
canSmoothWith = list(/obj/structure/table/holo/wood, /obj/structure/table/holo/poker)
|
||||
|
||||
/obj/structure/table/holo/attack_paw(mob/user as mob)
|
||||
return
|
||||
|
||||
/obj/structure/table/holo/attack_alien(mob/user as mob)
|
||||
return
|
||||
|
||||
/obj/structure/table/holo/attack_animal(mob/living/simple_animal/user as mob)
|
||||
return
|
||||
|
||||
/obj/structure/table/holo/attack_hand(mob/user as mob)
|
||||
return
|
||||
/obj/structure/table/holo/attack_hulk()
|
||||
return
|
||||
|
||||
/obj/structure/table/holo/attackby(obj/item/I, mob/user, params)
|
||||
if (istype(I, /obj/item/weapon/grab))
|
||||
tablepush(I, user)
|
||||
return
|
||||
if (istype(I, /obj/item/weapon/storage/bag/tray))
|
||||
var/obj/item/weapon/storage/bag/tray/T = I
|
||||
if(T.contents.len > 0) // If the tray isn't empty
|
||||
var/list/obj/item/oldContents = T.contents.Copy()
|
||||
T.quick_empty()
|
||||
|
||||
for(var/obj/item/C in oldContents)
|
||||
C.loc = src.loc
|
||||
|
||||
user.visible_message("[user] empties [I] on [src].")
|
||||
return
|
||||
// If the tray IS empty, continue on (tray will be placed on the table like other items)
|
||||
|
||||
if(isrobot(user))
|
||||
return
|
||||
|
||||
if(!(I.flags & ABSTRACT)) //rip more parems rip in peace ;_;
|
||||
if(user.drop_item())
|
||||
I.Move(loc)
|
||||
var/list/click_params = params2list(params)
|
||||
//Center the icon where the user clicked.
|
||||
if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
|
||||
return
|
||||
//Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the table turf)
|
||||
I.pixel_x = Clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
|
||||
I.pixel_y = Clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
|
||||
@@ -1,8 +1,8 @@
|
||||
/turf/simulated/floor/holofloor
|
||||
icon_state = "floor"
|
||||
thermal_conductivity = 0
|
||||
broken_states = list()
|
||||
burnt_states = list()
|
||||
broken_states = list("engine")
|
||||
burnt_states = list("engine")
|
||||
|
||||
/turf/simulated/floor/holofloor/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
return // HOLOFLOOR DOES NOT GIVE A FUCK
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/obj/structure/window/holo
|
||||
name = "reinforced window"
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "rwindow"
|
||||
desc = "A window. It has an electric hum to it."
|
||||
density = 1
|
||||
layer = 3.2//Just above doors
|
||||
pressure_resistance = 4*ONE_ATMOSPHERE
|
||||
anchored = 1.0
|
||||
flags = ON_BORDER
|
||||
maxhealth = 100
|
||||
disassembled = 1 // prevents noise on destruction
|
||||
|
||||
/obj/structure/window/holo/New()
|
||||
..()
|
||||
for(var/O in contents)
|
||||
qdel(O) // standard window code generates stuff no matter what we want
|
||||
|
||||
/obj/structure/window/holo/spawnfragments()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/structure/window/holo/attackby(var/obj/item/I, var/mob/user)
|
||||
if(istype(I,/obj/item/weapon/screwdriver))
|
||||
user << "You see no screws to unfasten!"
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/structure/window/holo/hit(var/damage, var/sound_effect = 1)
|
||||
. = ..()
|
||||
spawn(50) // self-healing
|
||||
health += damage
|
||||
|
||||
/obj/structure/window/holo/opaque
|
||||
name = "tinted window"
|
||||
opacity = 1
|
||||
|
||||
/obj/structure/window/holo/fulltile
|
||||
dir = 5
|
||||
maxhealth = 250
|
||||
|
||||
/obj/structure/window/holo/opaque/fulltile
|
||||
dir = 5
|
||||
maxhealth = 250
|
||||
@@ -7,8 +7,7 @@
|
||||
src.head = src.head + "<link rel=\"stylesheet\" type=\"text/css\" href=\"cards.css\" />"
|
||||
src.updateLayout("<div id=\"headbar\"></div><div class=\"wrapper\"><table><tr><td style=\"vertical-align: middle;\"><div id=\"hand\"></div></td></tr></table></div>")
|
||||
|
||||
/datum/html_interface/cards/sendResources(client/client)
|
||||
. = ..() // we need the default resources
|
||||
|
||||
client << browse_rsc('cards.css')
|
||||
client << browse_rsc('cards.png')
|
||||
/datum/html_interface/cards/registerResources(var/list/resources = list())
|
||||
resources["cards.css"] = 'cards.css'
|
||||
resources["cards.png"] = 'cards.png'
|
||||
..(resources)
|
||||
@@ -63,6 +63,8 @@ Closes the interface on all clients.
|
||||
When working with byond:// links make sure to reference the HTML interface object and NOT the original object. Topic() will still be called on
|
||||
your object, but it will pass through the HTML interface first allowing interception at a higher level.
|
||||
|
||||
If you want to use custom resources(images/css/js) with an existing interface:
|
||||
You have to use modules/client/asset_cache to ensure they get sent BEFORE the interface opens
|
||||
|
||||
** Sample code **
|
||||
|
||||
@@ -105,6 +107,10 @@ mob/verb/test()
|
||||
// The initial height of the browser control, used when the window is first shown to a client.
|
||||
var/height
|
||||
|
||||
// A type associated list of assets the interface needs.
|
||||
//Sent to the client when the interface opens on the client for the first time.
|
||||
var/static/list/asset_list
|
||||
|
||||
/datum/html_interface/New(atom/ref, title, width = 700, height = 480, head = "")
|
||||
html_interfaces.Add(src)
|
||||
|
||||
@@ -126,12 +132,20 @@ mob/verb/test()
|
||||
/* * Hooks */
|
||||
/datum/html_interface/proc/specificRenderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE)
|
||||
|
||||
/datum/html_interface/proc/sendResources(client/client)
|
||||
client << browse_rsc('js/jquery.min.js', "jquery.min.js")
|
||||
client << browse_rsc('js/bootstrap.min.js', "bootstrap.min.js")
|
||||
client << browse_rsc('css/bootstrap.min.css', "bootstrap.min.css")
|
||||
client << browse_rsc('css/html_interface.css', "html_interface.css")
|
||||
client << browse_rsc('js/html_interface.js', "html_interface.js")
|
||||
//if you need to override this, either call ..() or add your resources to asset_list
|
||||
/datum/html_interface/proc/registerResources(var/list/resources = list())
|
||||
resources["jquery.min.js"] = 'js/jquery.min.js'
|
||||
resources["bootstrap.min.js"] = 'js/bootstrap.min.js'
|
||||
resources["bootstrap.min.css"] = 'css/bootstrap.min.css'
|
||||
resources["html_interface.css"] = 'css/html_interface.css'
|
||||
resources["html_interface.js"] = 'js/html_interface.js'
|
||||
var/assetlist = list()
|
||||
for (var/R in resources)
|
||||
register_asset(R,resources[R])
|
||||
assetlist += R
|
||||
if (!asset_list)
|
||||
asset_list = list()
|
||||
asset_list[type] = assetlist
|
||||
|
||||
/datum/html_interface/proc/createWindow(datum/html_interface_client/hclient)
|
||||
winclone(hclient.client, "window", "browser_\ref[src]")
|
||||
@@ -207,10 +221,8 @@ mob/verb/test()
|
||||
hclient = getClient(hclient, TRUE)
|
||||
|
||||
if (istype(hclient))
|
||||
// This needs to be commented out due to BYOND bug http://www.byond.com/forum/?post=1487244
|
||||
// /client/proc/send_resources() executes this per client to avoid the bug, but by using it here files may be deleted just as the HTML is loaded,
|
||||
// causing file not found errors.
|
||||
// src.sendResources(hclient.client)
|
||||
if (type in asset_list && islist(asset_list[type]))
|
||||
send_asset_list(hclient.client, asset_list[type], TRUE)
|
||||
|
||||
if (!winexists(hclient.client, "browser_\ref[src]"))
|
||||
src.createWindow(hclient)
|
||||
|
||||
@@ -29,12 +29,11 @@ The client is optional and may be a /mob, /client or /html_interface_client obje
|
||||
// Update the title in our custom header (in addition to default functionality)
|
||||
winset(hclient.client, "browser_\ref[src].uiTitle", list2params(list("text" = "[src.title]")))
|
||||
|
||||
/datum/html_interface/nanotrasen/sendResources(client/client)
|
||||
. = ..() // we need the default resources
|
||||
|
||||
client << browse_rsc('uiBg.png')
|
||||
client << browse_rsc('uiBgcenter.png')
|
||||
client << browse_rsc('nanotrasen.css')
|
||||
/datum/html_interface/nanotrasen/registerResources(var/list/resources = list())
|
||||
resources["uiBg.png"] = 'uiBg.png'
|
||||
resources["uiBgcenter.png"] = 'uiBgcenter.png'
|
||||
resources["nanotrasen.css"] = 'nanotrasen.css'
|
||||
..(resources)
|
||||
|
||||
/datum/html_interface/nanotrasen/createWindow(datum/html_interface_client/hclient)
|
||||
. = ..() // we want the default window
|
||||
|
||||
@@ -1202,8 +1202,8 @@ obj/item/weapon/reagent_containers/food/snacks/grown/shell/eggy/add_juice()
|
||||
planted.endurance = endurance
|
||||
planted.yield = yield
|
||||
planted.potency = potency
|
||||
user << "<span class='notice'>You plant [src].</span>"
|
||||
qdel(src)
|
||||
user << "<span class='notice'>You plant the glowshroom.</span>"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/glowshroom/Destroy()
|
||||
if(istype(loc,/mob))
|
||||
@@ -1218,6 +1218,27 @@ obj/item/weapon/reagent_containers/food/snacks/grown/shell/eggy/add_juice()
|
||||
user.AddLuminosity(round(-potency / 10,1))
|
||||
SetLuminosity(round(potency / 10,1))
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/glowshroom/glowcap
|
||||
seed = /obj/item/seeds/glowcap
|
||||
name = "glowcap cluster"
|
||||
desc = "<I>Mycena Ruthenia</I>: This species of mushroom glows in the dark, but aren't bioluminescent. They're warm to the touch..."
|
||||
icon_state = "glowcap"
|
||||
filling_color = "#00FA9A"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/glowshroom/glowcap/On_Consume()
|
||||
if(!reagents.total_volume)
|
||||
var/batteries_recharged = 0
|
||||
for(var/obj/item/weapon/stock_parts/cell/C in usr.GetAllContents())
|
||||
var/newcharge = (potency*0.01)*C.maxcharge
|
||||
if(C.charge < newcharge)
|
||||
C.charge = newcharge
|
||||
if(isobj(C.loc))
|
||||
var/obj/O = C.loc
|
||||
O.update_icon() //update power meters and such
|
||||
batteries_recharged = 1
|
||||
if(batteries_recharged)
|
||||
usr << "<span class='notice'>Battery has recovered.</span>"
|
||||
..()
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/shell/moneyfruit
|
||||
seed = /obj/item/seeds/cashseed
|
||||
|
||||
@@ -768,7 +768,7 @@
|
||||
user.visible_message("[user] begins to wrench [src] into place.", \
|
||||
"<span class='notice'>You begin to wrench [src] in place...</span>")
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
if (do_after(user, 20, target = src))
|
||||
if (do_after(user, 20/O.toolspeed, target = src))
|
||||
if(anchored)
|
||||
return
|
||||
anchored = 1
|
||||
@@ -778,7 +778,7 @@
|
||||
user.visible_message("[user] begins to unwrench [src].", \
|
||||
"<span class='notice'>You begin to unwrench [src]...</span>")
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
if (do_after(user, 20, target = src))
|
||||
if (do_after(user, 20/O.toolspeed, target = src))
|
||||
if(!anchored)
|
||||
return
|
||||
anchored = 0
|
||||
|
||||
@@ -757,6 +757,25 @@
|
||||
growthstages = 4
|
||||
plant_type = 2
|
||||
rarity = 20
|
||||
mutatelist = list(/obj/item/seeds/glowcap)
|
||||
|
||||
/obj/item/seeds/glowcap
|
||||
name = "pack of glowcap mycelium"
|
||||
desc = "This mycelium -powers- into mushrooms!"
|
||||
icon_state = "mycelium-glowcap"
|
||||
species = "glowcap"
|
||||
plantname = "Glowcaps"
|
||||
product = /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/glowshroom/glowcap
|
||||
lifespan = 120 //ten times that is the delay
|
||||
endurance = 30
|
||||
maturation = 15
|
||||
production = 1
|
||||
yield = 3 //-> spread
|
||||
potency = 30 //-> brightness
|
||||
oneharvest = 1
|
||||
growthstages = 4
|
||||
plant_type = 2
|
||||
rarity = 20
|
||||
|
||||
/obj/item/seeds/plumpmycelium
|
||||
name = "pack of plump-helmet mycelium"
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
proc/json2list(json)
|
||||
var/static/json_reader/_jsonr = new()
|
||||
return _jsonr.ReadObject(_jsonr.ScanJson(json))
|
||||
|
||||
proc/list2json(list/L)
|
||||
var/static/json_writer/_jsonw = new()
|
||||
return _jsonw.write(L)
|
||||
|
||||
proc/list2json_usecache(list/L)
|
||||
var/static/json_writer/_jsonw = new()
|
||||
_jsonw.use_cache = 1
|
||||
return _jsonw.write(L)
|
||||
@@ -1,204 +1,187 @@
|
||||
/json_token
|
||||
var
|
||||
value
|
||||
New(v)
|
||||
src.value = v
|
||||
text
|
||||
number
|
||||
word
|
||||
symbol
|
||||
eof
|
||||
|
||||
/json_reader
|
||||
var
|
||||
list
|
||||
string = list("'", "\"")
|
||||
symbols = list("{", "}", "\[", "]", ":", "\"", "'", ",")
|
||||
sequences = list("b" = 8, "t" = 9, "n" = 10, "f" = 12, "r" = 13)
|
||||
tokens
|
||||
json
|
||||
i = 1
|
||||
|
||||
|
||||
/json_reader/proc/ScanJson(json)
|
||||
// scanner
|
||||
src.json = json
|
||||
. = new/list()
|
||||
src.i = 1
|
||||
while(src.i <= lentext(json))
|
||||
var/char = get_char()
|
||||
if(is_whitespace(char))
|
||||
i++
|
||||
continue
|
||||
if(string.Find(char))
|
||||
. += read_string(char)
|
||||
else if(symbols.Find(char))
|
||||
. += new/json_token/symbol(char)
|
||||
else if(is_digit(char))
|
||||
. += read_number()
|
||||
else
|
||||
. += read_word()
|
||||
i++
|
||||
. += new/json_token/eof()
|
||||
|
||||
/json_reader/proc/read_word()
|
||||
var/val = ""
|
||||
while(i <= lentext(json))
|
||||
var/char = get_char()
|
||||
if(is_whitespace(char) || symbols.Find(char))
|
||||
i-- // let scanner handle this character
|
||||
return new/json_token/word(val)
|
||||
val += char
|
||||
i++
|
||||
|
||||
/json_reader/proc/read_string(delim)
|
||||
var
|
||||
escape = FALSE
|
||||
val = ""
|
||||
while(++i <= lentext(json))
|
||||
var/char = get_char()
|
||||
if(escape)
|
||||
switch(char)
|
||||
if("\\", "'", "\"", "/", "u")
|
||||
val += char
|
||||
else
|
||||
// TODO: support octal, hex, unicode sequences
|
||||
ASSERT(sequences.Find(char))
|
||||
val += ascii2text(sequences[char])
|
||||
else
|
||||
if(char == delim)
|
||||
return new/json_token/text(val)
|
||||
else if(char == "\\")
|
||||
escape = TRUE
|
||||
else
|
||||
val += char
|
||||
CRASH("Unterminated string.")
|
||||
|
||||
/json_reader/proc/read_number()
|
||||
var/val = ""
|
||||
var/char = get_char()
|
||||
while(is_digit(char) || char == "." || lowertext(char) == "e")
|
||||
val += char
|
||||
i++
|
||||
char = get_char()
|
||||
i-- // allow scanner to read the first non-number character
|
||||
return new/json_token/number(text2num(val))
|
||||
|
||||
/json_reader/proc/check_char()
|
||||
ASSERT(args.Find(get_char()))
|
||||
|
||||
/json_reader/proc/get_char()
|
||||
return copytext(json, i, i+1)
|
||||
|
||||
/json_reader/proc/is_whitespace(char)
|
||||
return char == " " || char == "\t" || char == "\n" || text2ascii(char) == 13
|
||||
|
||||
/json_reader/proc/is_digit(char)
|
||||
var/c = text2ascii(char)
|
||||
return 48 <= c && c <= 57 || char == "+" || char == "-"
|
||||
|
||||
|
||||
// parser
|
||||
/json_reader/proc/ReadObject(list/tokens)
|
||||
src.tokens = tokens
|
||||
. = new/list()
|
||||
i = 1
|
||||
read_token("{", /json_token/symbol)
|
||||
while(i <= tokens.len)
|
||||
var/json_token/K = get_token()
|
||||
check_type(/json_token/word, /json_token/text)
|
||||
next_token()
|
||||
read_token(":", /json_token/symbol)
|
||||
|
||||
.[K.value] = read_value()
|
||||
|
||||
var/json_token/S = get_token()
|
||||
check_type(/json_token/symbol)
|
||||
switch(S.value)
|
||||
if(",")
|
||||
next_token()
|
||||
continue
|
||||
if("}")
|
||||
next_token()
|
||||
return
|
||||
else
|
||||
die()
|
||||
|
||||
/json_reader/proc/get_token()
|
||||
return tokens[i]
|
||||
|
||||
/json_reader/proc/next_token()
|
||||
return tokens[++i]
|
||||
|
||||
/json_reader/proc/read_token(val, type)
|
||||
var/json_token/T = get_token()
|
||||
if(!(T.value == val && istype(T, type)))
|
||||
CRASH("Expected '[val]', found '[T.value]'.")
|
||||
next_token()
|
||||
return T
|
||||
|
||||
/json_reader/proc/check_type(...)
|
||||
var/json_token/T = get_token()
|
||||
for(var/type in args)
|
||||
if(istype(T, type))
|
||||
return
|
||||
CRASH("Bad token type: [T.type].")
|
||||
|
||||
/json_reader/proc/check_value(...)
|
||||
var/json_token/T = get_token()
|
||||
ASSERT(args.Find(T.value))
|
||||
|
||||
/json_reader/proc/read_key()
|
||||
var/char = get_char()
|
||||
if(char == "\"" || char == "'")
|
||||
return read_string(char)
|
||||
|
||||
/json_reader/proc/read_value()
|
||||
var/json_token/T = get_token()
|
||||
switch(T.type)
|
||||
if(/json_token/text, /json_token/number)
|
||||
next_token()
|
||||
return T.value
|
||||
if(/json_token/word)
|
||||
next_token()
|
||||
switch(T.value)
|
||||
if("true")
|
||||
return TRUE
|
||||
if("false")
|
||||
return FALSE
|
||||
if("null")
|
||||
return null
|
||||
if(/json_token/symbol)
|
||||
switch(T.value)
|
||||
if("\[")
|
||||
return read_array()
|
||||
if("{")
|
||||
return ReadObject(tokens.Copy(i))
|
||||
die()
|
||||
|
||||
/json_reader/proc/read_array()
|
||||
read_token("\[", /json_token/symbol)
|
||||
. = new/list()
|
||||
var/list/L = .
|
||||
while(i <= tokens.len)
|
||||
// Avoid using Add() or += in case a list is returned.
|
||||
L.len++
|
||||
L[L.len] = read_value()
|
||||
var/json_token/T = get_token()
|
||||
check_type(/json_token/symbol)
|
||||
switch(T.value)
|
||||
if(",")
|
||||
next_token()
|
||||
continue
|
||||
if("]")
|
||||
next_token()
|
||||
return
|
||||
else
|
||||
die()
|
||||
next_token()
|
||||
CRASH("Unterminated array.")
|
||||
|
||||
|
||||
/json_reader/proc/die(json_token/T)
|
||||
if(!T) T = get_token()
|
||||
json_reader/var/list/string = list("'", "\"")
|
||||
json_reader/var/list/symbols = list("{", "}", "\[", "]", ":", "\"", "'", ",")
|
||||
json_reader/var/list/sequences = list("b" = 8, "t" = 9, "n" = 10, "f" = 12, "r" = 13)
|
||||
json_reader/var/list/tokens
|
||||
json_reader/var/json
|
||||
json_reader/var/i = 1
|
||||
|
||||
|
||||
json_reader/proc/ScanJson(json)
|
||||
src.json = json
|
||||
. = new/list()
|
||||
src.i = 1
|
||||
while(src.i <= lentext(json))
|
||||
var/char = get_char()
|
||||
if(is_whitespace(char))
|
||||
i++
|
||||
continue
|
||||
if(string.Find(char))
|
||||
. += read_string(char)
|
||||
else if(symbols.Find(char))
|
||||
. += new/json_token/symbol(char)
|
||||
else if(is_digit(char))
|
||||
. += read_number()
|
||||
else
|
||||
. += read_word()
|
||||
i++
|
||||
. += new/json_token/eof()
|
||||
|
||||
json_reader/proc/read_word()
|
||||
var/val = ""
|
||||
while(i <= lentext(json))
|
||||
var/char = get_char()
|
||||
if(is_whitespace(char) || symbols.Find(char))
|
||||
i-- // let scanner handle this character
|
||||
return new/json_token/word(val)
|
||||
val += char
|
||||
i++
|
||||
|
||||
json_reader/proc/read_string(delim)
|
||||
var/escape = FALSE
|
||||
var/val = ""
|
||||
while(++i <= lentext(json))
|
||||
var/char = get_char()
|
||||
if(escape)
|
||||
switch(char)
|
||||
if("\\", "'", "\"", "/", "u")
|
||||
val += char
|
||||
else
|
||||
// TODO: support octal, hex, unicode sequences
|
||||
ASSERT(sequences.Find(char))
|
||||
val += ascii2text(sequences[char])
|
||||
else
|
||||
if(char == delim)
|
||||
return new/json_token/text(val)
|
||||
else if(char == "\\")
|
||||
escape = TRUE
|
||||
else
|
||||
val += char
|
||||
CRASH("Unterminated string.")
|
||||
|
||||
json_reader/proc/read_number()
|
||||
var/val = ""
|
||||
var/char = get_char()
|
||||
while(is_digit(char) || char == "." || lowertext(char) == "e")
|
||||
val += char
|
||||
i++
|
||||
char = get_char()
|
||||
i-- // allow scanner to read the first non-number character
|
||||
return new/json_token/number(text2num(val))
|
||||
|
||||
json_reader/proc/check_char()
|
||||
ASSERT(args.Find(get_char()))
|
||||
|
||||
json_reader/proc/get_char()
|
||||
return copytext(json, i, i+1)
|
||||
|
||||
json_reader/proc/is_whitespace(char)
|
||||
return char == " " || char == "\t" || char == "\n" || text2ascii(char) == 13
|
||||
|
||||
json_reader/proc/is_digit(char)
|
||||
var/c = text2ascii(char)
|
||||
return 48 <= c && c <= 57 || char == "+" || char == "-"
|
||||
|
||||
|
||||
json_reader/proc/ReadObject(list/tokens)
|
||||
src.tokens = tokens
|
||||
. = new/list()
|
||||
i = 1
|
||||
read_token("{", /json_token/symbol)
|
||||
while(i <= tokens.len)
|
||||
var/json_token/K = get_token()
|
||||
check_type(/json_token/word, /json_token/text)
|
||||
next_token()
|
||||
read_token(":", /json_token/symbol)
|
||||
|
||||
.[K.value] = read_value()
|
||||
|
||||
var/json_token/S = get_token()
|
||||
check_type(/json_token/symbol)
|
||||
switch(S.value)
|
||||
if(",")
|
||||
next_token()
|
||||
continue
|
||||
if("}")
|
||||
next_token()
|
||||
return
|
||||
else
|
||||
die()
|
||||
|
||||
json_reader/proc/get_token()
|
||||
return tokens[i]
|
||||
|
||||
json_reader/proc/next_token()
|
||||
return tokens[++i]
|
||||
|
||||
json_reader/proc/read_token(val, type)
|
||||
var/json_token/T = get_token()
|
||||
if(!(T.value == val && istype(T, type)))
|
||||
CRASH("Expected '[val]', found '[T.value]'.")
|
||||
next_token()
|
||||
return T
|
||||
|
||||
json_reader/proc/check_type(...)
|
||||
var/json_token/T = get_token()
|
||||
for(var/type in args)
|
||||
if(istype(T, type))
|
||||
return
|
||||
CRASH("Bad token type: [T.type].")
|
||||
|
||||
json_reader/proc/check_value(...)
|
||||
var/json_token/T = get_token()
|
||||
ASSERT(args.Find(T.value))
|
||||
|
||||
json_reader/proc/read_key()
|
||||
var/char = get_char()
|
||||
if(char == "\"" || char == "'")
|
||||
return read_string(char)
|
||||
|
||||
json_reader/proc/read_value()
|
||||
var/json_token/T = get_token()
|
||||
switch(T.type)
|
||||
if(/json_token/text, /json_token/number)
|
||||
next_token()
|
||||
return T.value
|
||||
if(/json_token/word)
|
||||
next_token()
|
||||
switch(T.value)
|
||||
if("true")
|
||||
return TRUE
|
||||
if("false")
|
||||
return FALSE
|
||||
if("null")
|
||||
return null
|
||||
if(/json_token/symbol)
|
||||
switch(T.value)
|
||||
if("\[")
|
||||
return read_array()
|
||||
if("{")
|
||||
return ReadObject(tokens.Copy(i))
|
||||
die()
|
||||
|
||||
json_reader/proc/read_array()
|
||||
read_token("\[", /json_token/symbol)
|
||||
. = new/list()
|
||||
var/list/L = .
|
||||
while(i <= tokens.len)
|
||||
// Avoid using Add() or += in case a list is returned.
|
||||
L.len++
|
||||
L[L.len] = read_value()
|
||||
var/json_token/T = get_token()
|
||||
check_type(/json_token/symbol)
|
||||
switch(T.value)
|
||||
if(",")
|
||||
next_token()
|
||||
continue
|
||||
if("]")
|
||||
next_token()
|
||||
return
|
||||
else
|
||||
die()
|
||||
next_token()
|
||||
CRASH("Unterminated array.")
|
||||
|
||||
|
||||
json_reader/proc/die(json_token/T)
|
||||
if(!T) T = get_token()
|
||||
CRASH("Unexpected token: [T.value].")
|
||||
@@ -0,0 +1,9 @@
|
||||
json_token/var/value
|
||||
json_token/New(v)
|
||||
src.value = v
|
||||
|
||||
json_token/text
|
||||
json_token/number
|
||||
json_token/word
|
||||
json_token/symbol
|
||||
json_token/eof
|
||||
@@ -0,0 +1,67 @@
|
||||
#define LIST_FLAT 0
|
||||
#define LIST_NESTED 1
|
||||
#define LIST_OBJECT 2 // Object in this case means json object, ortherwise known as an associative list or array.
|
||||
|
||||
json_writer/var/use_cache = 0
|
||||
|
||||
json_writer/proc/write(val)
|
||||
if(isnum(val))
|
||||
. = num2text(val)
|
||||
else if(isnull(val))
|
||||
. = "null"
|
||||
else if(istype(val, /list))
|
||||
switch (listtype(val))
|
||||
if (LIST_FLAT)
|
||||
. = write_array(val)
|
||||
if (LIST_NESTED)
|
||||
. = write_array(val)
|
||||
if (LIST_OBJECT)
|
||||
. = write_object(val)
|
||||
else
|
||||
. = write_string("[val]")
|
||||
|
||||
json_writer/proc/write_object(list/L)
|
||||
if(use_cache && L["__json_cache"])
|
||||
return L["__json_cache"]
|
||||
. = list()
|
||||
for(var/k in L)
|
||||
. += "\"[k]\":[write(L[k])]"
|
||||
|
||||
. = "{[list2text(., ",")]}"
|
||||
|
||||
json_writer/proc/write_flat_array(list/L)
|
||||
. = "\[[list2text(L, ",")]]"
|
||||
|
||||
json_writer/proc/write_array(list/L)
|
||||
. = list()
|
||||
for(var/item in L)
|
||||
. += write(item)
|
||||
. = "\[[list2text(., ",")]]"
|
||||
|
||||
json_writer/proc/write_string(txt)
|
||||
var/static/list/json_escape = list("\\" = "\\\\", "\"" = "\\\"", "\n" = "\\n")
|
||||
for(var/targ in json_escape)
|
||||
var/start = 1
|
||||
while(start <= lentext(txt))
|
||||
var/i = findtext(txt, targ, start)
|
||||
if(!i)
|
||||
break
|
||||
var/lrep = length(json_escape[targ])
|
||||
txt = "[copytext(txt, 1, i)][json_escape[targ]][copytext(txt, i + length(targ))]"
|
||||
start = i + lrep
|
||||
|
||||
return {""[txt]""}
|
||||
|
||||
json_writer/proc/listtype(list/L)
|
||||
. = LIST_FLAT
|
||||
for(var/key in L)
|
||||
if (. == LIST_FLAT && istype(key, /list))
|
||||
. = LIST_NESTED
|
||||
if (!isnum(key) && !istype(key, /list))
|
||||
. = LIST_OBJECT
|
||||
break // If it's an object, we can just stop now.
|
||||
|
||||
|
||||
#undef LIST_FLAT
|
||||
#undef LIST_NESTED
|
||||
#undef LIST_OBJECT
|
||||
@@ -38,13 +38,13 @@
|
||||
if(0)
|
||||
if(istype(I, /obj/item/weapon/wrench))
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 100, 1)
|
||||
if(do_after(user, 20, target = src))
|
||||
if(do_after(user, 20/I.toolspeed, target = src))
|
||||
user << "<span class='notice'>You wrench the frame into place.</span>"
|
||||
anchored = 1
|
||||
state = 1
|
||||
if(istype(I, /obj/item/weapon/crowbar))
|
||||
playsound(loc, 'sound/items/Crowbar.ogg', 100, 1)
|
||||
if(do_after(user, 20, target = src))
|
||||
if(do_after(user, 20/I.toolspeed, target = src))
|
||||
user << "<span class='notice'>You pry the frame apart.</span>"
|
||||
new /obj/item/stack/sheet/mineral/wood(loc, 4)
|
||||
qdel(src)
|
||||
|
||||
@@ -173,7 +173,7 @@ var/global/list/datum/cachedbook/cachedbooks // List of our cached book datums
|
||||
var/list/inventory = list()
|
||||
var/checkoutperiod = 5 // In minutes
|
||||
var/obj/machinery/libraryscanner/scanner // Book scanner that will be used when uploading books to the Archive
|
||||
var/list/libcomp_menu = list("")
|
||||
var/list/libcomp_menu
|
||||
var/page = 1 //current page of the external archives
|
||||
var/bibledelay = 0 // LOL NO SPAM (1 minute delay) -- Doohl
|
||||
|
||||
@@ -265,7 +265,7 @@ var/global/list/datum/cachedbook/cachedbooks // List of our cached book datums
|
||||
dat += "<table>"
|
||||
dat += "<tr><td>AUTHOR</td><td>TITLE</td><td>CATEGORY</td><td></td></tr>"
|
||||
dat += libcomp_menu[Clamp(page,1,libcomp_menu.len)]
|
||||
dat += "<tr><td><A href='?src=\ref[src];page=[(max(1,page-1))]'><<<<</A></td> <td></td> <td></td> <td><span style='text-align:right'><A href='?src=\ref[src];page=[(min(1,page+1))]'>>>>></A></span></td></tr>"
|
||||
dat += "<tr><td><A href='?src=\ref[src];page=[(max(1,page-1))]'><<<<</A></td> <td></td> <td></td> <td><span style='text-align:right'><A href='?src=\ref[src];page=[(min(libcomp_menu.len,page+1))]'>>>>></A></span></td></tr>"
|
||||
dat += "</table>"
|
||||
dat += "<BR><A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
|
||||
if(5)
|
||||
@@ -316,7 +316,7 @@ var/global/list/datum/cachedbook/cachedbooks // List of our cached book datums
|
||||
usr << browse(null, "window=library")
|
||||
onclose(usr, "library")
|
||||
return
|
||||
if(href_list["page"] && screenstate == 4 && isnum(href_list["page"]))
|
||||
if(href_list["page"] && screenstate == 4)
|
||||
page = text2num(href_list["page"])
|
||||
if(href_list["switchscreen"])
|
||||
switch(href_list["switchscreen"])
|
||||
|
||||
@@ -26,20 +26,23 @@
|
||||
Colored lights
|
||||
*/
|
||||
|
||||
#define LIGHTING_CIRCULAR 1 //comment this out to use old square lighting effects.
|
||||
#define LIGHTING_CIRCULAR 1 //Comment this out to use old square lighting effects.
|
||||
#define LIGHTING_LAYER 15 //Drawing layer for lighting
|
||||
#define LIGHTING_CAP 10 //The lumcount level at which alpha is 0 and we're fully lit.
|
||||
#define LIGHTING_CAP_FRAC (255/LIGHTING_CAP) //A precal'd variable we'll use in turf/redraw_lighting()
|
||||
#define LIGHTING_ICON 'icons/effects/alphacolors.dmi'
|
||||
#define LIGHTING_ICON_STATE "white"
|
||||
#define LIGHTING_TIME 1.2 //Time to do any lighting change. Actual number pulled out of my ass
|
||||
#define LIGHTING_DARKEST_VISIBLE_ALPHA 230 //Anything darker than this is so dark, we'll just consider the whole tile unlit
|
||||
#define LIGHTING_TIME 2 //Time to do any lighting change. Actual number pulled out of my ass
|
||||
#define LIGHTING_DARKEST_VISIBLE_ALPHA 250 //Anything darker than this is so dark, we'll just consider the whole tile unlit
|
||||
#define LIGHTING_LUM_FOR_FULL_BRIGHT 6 //Anything who's lum is lower then this starts off less bright.
|
||||
#define LIGHTING_MIN_RADIUS 4 //Lowest radius a light source can effect.
|
||||
|
||||
/datum/light_source
|
||||
var/atom/owner
|
||||
var/radius = 0
|
||||
var/luminosity = 0
|
||||
var/cap = 0
|
||||
var/changed = 1
|
||||
var/changed = 0
|
||||
var/list/effect = list()
|
||||
var/__x = 0 //x coordinate at last update
|
||||
var/__y = 0 //y coordinate at last update
|
||||
@@ -49,20 +52,33 @@
|
||||
CRASH("The first argument to the light object's constructor must be the atom that is the light source. Expected atom, received '[A]' instead.")
|
||||
..()
|
||||
owner = A
|
||||
radius = A.luminosity
|
||||
__x = owner.x
|
||||
__y = owner.y
|
||||
SSlighting.changed_lights |= src
|
||||
UpdateLuminosity(A.luminosity)
|
||||
|
||||
/datum/light_source/Destroy()
|
||||
if(owner && owner.light == src)
|
||||
remove_effect()
|
||||
owner.light = null
|
||||
owner.luminosity = 0
|
||||
owner = null
|
||||
if(changed)
|
||||
SSlighting.changed_lights -= src
|
||||
return ..()
|
||||
|
||||
/datum/light_source/proc/UpdateLuminosity(new_luminosity, new_cap)
|
||||
if(new_luminosity < 0)
|
||||
new_luminosity = 0
|
||||
|
||||
if(luminosity == new_luminosity && (new_cap == null || cap == new_cap))
|
||||
return
|
||||
|
||||
radius = max(LIGHTING_MIN_RADIUS, new_luminosity)
|
||||
luminosity = new_luminosity
|
||||
if (new_cap != null)
|
||||
cap = new_cap
|
||||
|
||||
changed()
|
||||
|
||||
|
||||
//Check a light to see if its effect needs reprocessing. If it does, remove any old effect and create a new one
|
||||
/datum/light_source/proc/check()
|
||||
if(!owner)
|
||||
@@ -95,46 +111,56 @@
|
||||
|
||||
effect.Cut()
|
||||
|
||||
//Apply a new effect
|
||||
//Apply a new effect.
|
||||
/datum/light_source/proc/add_effect()
|
||||
// only do this if the light is turned on and is on the map
|
||||
if(owner && owner.loc && radius > 0)
|
||||
effect = list()
|
||||
var/turf/To = get_turf(owner)
|
||||
var/range = owner.get_light_range(radius)
|
||||
for(var/atom/movable/AM in To)
|
||||
if(AM == owner)
|
||||
continue
|
||||
if(AM.opacity)
|
||||
range = 0
|
||||
break
|
||||
|
||||
for(var/turf/T in view(range, To))
|
||||
var/delta_lumcount = T.lumen(src)
|
||||
if(delta_lumcount > 0)
|
||||
effect[T] = delta_lumcount
|
||||
T.update_lumcount(delta_lumcount)
|
||||
|
||||
if(!T.affecting_lights)
|
||||
T.affecting_lights = list()
|
||||
T.affecting_lights |= src
|
||||
|
||||
return 1
|
||||
else
|
||||
if(!owner || !owner.loc)
|
||||
return 0
|
||||
var/range = owner.get_light_range(radius)
|
||||
if(range <= 0 || luminosity <= 0)
|
||||
owner.luminosity = 0
|
||||
return 0
|
||||
|
||||
//How much light light_source L should apply to src
|
||||
/turf/proc/lumen(datum/light_source/L)
|
||||
var/distance = 0
|
||||
#ifdef LIGHTING_CIRCULAR
|
||||
distance = cheap_hypotenuse(x, y, L.__x, L.__y)
|
||||
#else
|
||||
distance = max(abs(x - L.__x), abs(y - L.__y))
|
||||
#endif
|
||||
return ( L.cap ? L.cap : LIGHTING_CAP ) * (L.radius - distance) / L.radius
|
||||
//LIGHTING_CAP == strength for now
|
||||
effect = list()
|
||||
var/turf/To = get_turf(owner)
|
||||
|
||||
|
||||
for(var/atom/movable/AM in To)
|
||||
if(AM == owner)
|
||||
continue
|
||||
if(AM.opacity)
|
||||
range = 0
|
||||
break
|
||||
|
||||
owner.luminosity = range
|
||||
if (!range)
|
||||
return 0
|
||||
var/center_strength = 0
|
||||
if (cap <= 0)
|
||||
center_strength = LIGHTING_CAP/LIGHTING_LUM_FOR_FULL_BRIGHT*(luminosity)
|
||||
else
|
||||
center_strength = cap
|
||||
|
||||
for(var/turf/T in view(range+1, To))
|
||||
|
||||
#ifdef LIGHTING_CIRCULAR
|
||||
var/distance = cheap_hypotenuse(T.x, T.y, __x, __y)
|
||||
#else
|
||||
var/distance = max(abs(T,x - __x), abs(T.y - __y))
|
||||
#endif
|
||||
|
||||
var/delta_lumcount = Clamp(center_strength * (range - distance) / range, 0, LIGHTING_CAP)
|
||||
|
||||
if(delta_lumcount > 0)
|
||||
effect[T] = delta_lumcount
|
||||
T.update_lumcount(delta_lumcount)
|
||||
|
||||
if(!T.affecting_lights)
|
||||
T.affecting_lights = list()
|
||||
T.affecting_lights |= src
|
||||
|
||||
return 1
|
||||
|
||||
/atom
|
||||
var/datum/light_source/light
|
||||
|
||||
@@ -145,7 +171,6 @@
|
||||
..()
|
||||
if(luminosity)
|
||||
light = new(src)
|
||||
// luminosity = 0
|
||||
|
||||
//Movable atoms with opacity when they are constructed will trigger nearby lights to update
|
||||
//Movable atoms with luminosity when they are constructed will create a light_source automatically
|
||||
@@ -155,7 +180,6 @@
|
||||
UpdateAffectingLights()
|
||||
if(luminosity)
|
||||
light = new(src)
|
||||
// luminosity = 0
|
||||
|
||||
//Objects with opacity will trigger nearby lights to update at next SSlighting fire
|
||||
/atom/movable/Destroy()
|
||||
@@ -179,27 +203,19 @@
|
||||
//If we are setting luminosity to 0 the light will be cleaned up by the controller and garbage collected once all its
|
||||
//queues are complete.
|
||||
//if we have a light already it is merely updated, rather than making a new one.
|
||||
//The second arg allows you to scale the light cap for calculating falloff. (0 for default, null for no change)
|
||||
/atom/proc/SetLuminosity(new_luminosity, new_cap)
|
||||
if(new_luminosity < 0)
|
||||
new_luminosity = 0
|
||||
//The second arg allows you to scale the light cap for calculating falloff.
|
||||
|
||||
if(!light)
|
||||
if(!new_luminosity)
|
||||
/atom/proc/SetLuminosity(new_luminosity, new_cap)
|
||||
if (!light)
|
||||
if (new_luminosity <= 0)
|
||||
return
|
||||
light = new(src)
|
||||
else
|
||||
if(light.radius == new_luminosity && (new_cap == null || light.cap == new_cap))
|
||||
return
|
||||
light.radius = new_luminosity
|
||||
luminosity = new_luminosity
|
||||
if (new_cap != null)
|
||||
light.cap = new_cap
|
||||
light.changed()
|
||||
|
||||
light.UpdateLuminosity(new_luminosity, new_cap)
|
||||
|
||||
/atom/proc/AddLuminosity(delta_luminosity)
|
||||
if(light)
|
||||
SetLuminosity(light.radius + delta_luminosity)
|
||||
SetLuminosity(light.luminosity + delta_luminosity)
|
||||
else
|
||||
SetLuminosity(delta_luminosity)
|
||||
|
||||
@@ -312,14 +328,16 @@
|
||||
newalpha = 255-num
|
||||
else //if(lighting_lumcount >= LIGHTING_CAP)
|
||||
newalpha = 0
|
||||
|
||||
if(newalpha >= LIGHTING_DARKEST_VISIBLE_ALPHA)
|
||||
newalpha = 255
|
||||
if(lighting_object.alpha != newalpha)
|
||||
if(instantly)
|
||||
lighting_object.alpha = newalpha
|
||||
else
|
||||
animate(lighting_object, alpha = newalpha, time = LIGHTING_TIME)
|
||||
if(newalpha >= LIGHTING_DARKEST_VISIBLE_ALPHA) //Doesn't actually make it darker or anything, just tells byond you can't see the tile
|
||||
if(newalpha >= LIGHTING_DARKEST_VISIBLE_ALPHA)
|
||||
luminosity = 0
|
||||
lighting_object.luminosity = 0
|
||||
|
||||
lighting_changed = 0
|
||||
|
||||
@@ -360,6 +378,8 @@
|
||||
#undef LIGHTING_CAP
|
||||
#undef LIGHTING_CAP_FRAC
|
||||
#undef LIGHTING_DARKEST_VISIBLE_ALPHA
|
||||
#undef LIGHTING_LUM_FOR_FULL_BRIGHT
|
||||
#undef LIGHTING_MIN_RADIUS
|
||||
|
||||
|
||||
//set the changed status of all lights which could have possibly lit this atom.
|
||||
@@ -378,8 +398,8 @@
|
||||
|
||||
|
||||
#define LIGHTING_MAX_LUMINOSITY_STATIC 8 //Maximum luminosity to reduce lag.
|
||||
#define LIGHTING_MAX_LUMINOSITY_MOBILE 5 //Moving objects have a lower max luminosity since these update more often. (lag reduction)
|
||||
#define LIGHTING_MAX_LUMINOSITY_MOB 5
|
||||
#define LIGHTING_MAX_LUMINOSITY_MOBILE 7 //Moving objects have a lower max luminosity since these update more often. (lag reduction)
|
||||
#define LIGHTING_MAX_LUMINOSITY_MOB 6
|
||||
#define LIGHTING_MAX_LUMINOSITY_TURF 8 //turfs are static too, why was this 1?!
|
||||
|
||||
//caps luminosity effects max-range based on what type the light's owner is.
|
||||
|
||||
@@ -68,13 +68,13 @@
|
||||
if(57 to 58)
|
||||
new /obj/item/toy/syndicateballoon(src)
|
||||
if(59 to 60)
|
||||
new /obj/item/weapon/pickaxe/drill(src)
|
||||
new /obj/item/device/taperecorder(src)
|
||||
new /obj/item/weapon/gun/energy/kinetic_accelerator/hyper(src)
|
||||
new /obj/item/clothing/suit/space(src)
|
||||
new /obj/item/clothing/head/helmet/space(src)
|
||||
if(61 to 62)
|
||||
for(var/i = 0, i < 12, ++i)
|
||||
for(var/i = 0, i < 5, ++i)
|
||||
new /obj/item/clothing/head/kitty(src)
|
||||
new /obj/item/clothing/tie/petcollar(src)
|
||||
if(63 to 64)
|
||||
var/t = rand(4,7)
|
||||
for(var/i = 0, i < t, ++i)
|
||||
@@ -82,6 +82,7 @@
|
||||
new newcoin(src)
|
||||
if(65 to 66)
|
||||
new /obj/item/clothing/suit/ianshirt(src)
|
||||
new /obj/item/clothing/suit/hooded/ian_costume(src)
|
||||
if(67 to 68)
|
||||
var/t = rand(4,7)
|
||||
for(var/i = 0, i < t, ++i)
|
||||
@@ -89,7 +90,7 @@
|
||||
new newitem(src)
|
||||
if(69 to 70)
|
||||
for(var/i = 0, i < 5, ++i)
|
||||
new /obj/item/bluespace_crystal(src)
|
||||
new /obj/item/weapon/ore/bluespace_crystal(src)
|
||||
if(71 to 72)
|
||||
new /obj/item/weapon/pickaxe/drill(src)
|
||||
if(73 to 74)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
var/ore_pickup_rate = 15
|
||||
var/sheet_per_ore = 1
|
||||
var/point_upgrade = 1
|
||||
var/list/ore_values = list(("sand" = 1), ("iron" = 1), ("gold" = 20), ("silver" = 20), ("uranium" = 20), ("bananium" = 30), ("diamond" = 40), ("plasma" = 40))
|
||||
var/list/ore_values = list(("sand" = 1), ("iron" = 1), ("plasma" = 15), ("silver" = 16), ("gold" = 18), ("uranium" = 30), ("diamond" = 50), ("bananium" = 60))
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/New()
|
||||
..()
|
||||
@@ -64,14 +64,14 @@
|
||||
qdel(O) //... garbage collect
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/process()
|
||||
if(!panel_open) //If the machine is partially dissassembled, it should not process minerals
|
||||
if(!panel_open && powered()) //If the machine is partially disassembled and/or depowered, it should not process minerals
|
||||
var/turf/T = get_turf(get_step(src, input_dir))
|
||||
var/i
|
||||
if(T)
|
||||
if(locate(/obj/item/weapon/ore) in T)
|
||||
for (i = 0; i < ore_pickup_rate; i++)
|
||||
var/obj/item/weapon/ore/O = locate() in T
|
||||
if(O)
|
||||
if(O && O.refined_type)
|
||||
process_sheet(O)
|
||||
else
|
||||
break
|
||||
@@ -86,6 +86,8 @@
|
||||
break
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if (!powered())
|
||||
return
|
||||
if(istype(W,/obj/item/weapon/card/id))
|
||||
var/obj/item/weapon/card/id/I = usr.get_active_hand()
|
||||
if(istype(I) && !istype(inserted_id))
|
||||
@@ -248,6 +250,17 @@
|
||||
s.loc = loc
|
||||
s.layer = initial(s.layer)
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/update_icon()
|
||||
if(powered())
|
||||
icon_state = initial(icon_state)
|
||||
else
|
||||
icon_state = "[initial(icon_state)]-off"
|
||||
return
|
||||
|
||||
|
||||
/**********************Mining Equipment Vendor**************************/
|
||||
|
||||
@@ -265,18 +278,23 @@
|
||||
new /datum/data/mining_equipment("Whiskey", /obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey, 100),
|
||||
new /datum/data/mining_equipment("Cigar", /obj/item/clothing/mask/cigarette/cigar/havana, 150),
|
||||
new /datum/data/mining_equipment("Soap", /obj/item/weapon/soap/nanotrasen, 200),
|
||||
new /datum/data/mining_equipment("Jaunter", /obj/item/device/wormhole_jaunter, 250),
|
||||
new /datum/data/mining_equipment("Laser Pointer", /obj/item/device/laser_pointer, 300),
|
||||
new /datum/data/mining_equipment("Alien Toy", /obj/item/clothing/mask/facehugger/toy, 300),
|
||||
new /datum/data/mining_equipment("Advanced Scanner", /obj/item/device/t_scanner/adv_mining_scanner, 400),
|
||||
new /datum/data/mining_equipment("Hivelord Stabilizer", /obj/item/weapon/hivelordstabilizer , 400),
|
||||
new /datum/data/mining_equipment("Mining Drone", /mob/living/simple_animal/hostile/mining_drone, 500),
|
||||
new /datum/data/mining_equipment("GAR mesons", /obj/item/clothing/glasses/meson/gar, 500),
|
||||
new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/weapon/storage/firstaid/brute, 600),
|
||||
new /datum/data/mining_equipment("Jaunter", /obj/item/device/wormhole_jaunter, 600),
|
||||
new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/weapon/gun/energy/kinetic_accelerator, 750),
|
||||
new /datum/data/mining_equipment("Resonator", /obj/item/weapon/resonator, 800),
|
||||
new /datum/data/mining_equipment("Lazarus Injector", /obj/item/weapon/lazarus_injector, 1000),
|
||||
new /datum/data/mining_equipment("Diamond Pickaxe", /obj/item/weapon/pickaxe/diamond, 1200),
|
||||
new /datum/data/mining_equipment("Jetpack", /obj/item/weapon/tank/jetpack/carbondioxide/mining, 1500),
|
||||
new /datum/data/mining_equipment("Silver Pickaxe", /obj/item/weapon/pickaxe/silver, 1200),
|
||||
new /datum/data/mining_equipment("Jetpack", /obj/item/weapon/tank/jetpack/carbondioxide/mining, 2000),
|
||||
new /datum/data/mining_equipment("Space Cash", /obj/item/stack/spacecash/c1000, 2000),
|
||||
new /datum/data/mining_equipment("Super Resonator", /obj/item/weapon/resonator/upgraded, 2400),
|
||||
new /datum/data/mining_equipment("Diamond Pickaxe", /obj/item/weapon/pickaxe/diamond, 2500),
|
||||
new /datum/data/mining_equipment("Super Accelerator", /obj/item/weapon/gun/energy/kinetic_accelerator/super, 3000),
|
||||
new /datum/data/mining_equipment("Point Transfer Card", /obj/item/weapon/card/mining_point_card, 500),
|
||||
)
|
||||
|
||||
@@ -300,6 +318,17 @@
|
||||
component_parts += new /obj/item/weapon/stock_parts/console_screen(null)
|
||||
RefreshParts()
|
||||
|
||||
/obj/machinery/mineral/equipment_vendor/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/mineral/equipment_vendor/update_icon()
|
||||
if(powered())
|
||||
icon_state = initial(icon_state)
|
||||
else
|
||||
icon_state = "[initial(icon_state)]-off"
|
||||
return
|
||||
|
||||
/obj/machinery/mineral/equipment_vendor/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
@@ -504,6 +533,14 @@
|
||||
var/fieldlimit = 3
|
||||
origin_tech = "magnets=2;combat=2"
|
||||
|
||||
/obj/item/weapon/resonator/upgraded
|
||||
name = "upgraded resonator"
|
||||
desc = "An upgraded version of the resonator that can produce more fields at once."
|
||||
icon_state = "resonator_u"
|
||||
item_state = "resonator_u"
|
||||
origin_tech = "magnets=3;combat=3"
|
||||
fieldlimit = 5
|
||||
|
||||
/obj/item/weapon/resonator/proc/CreateResonance(target, creator)
|
||||
var/turf/T = get_turf(target)
|
||||
if(locate(/obj/effect/resonance) in T)
|
||||
@@ -852,4 +889,23 @@
|
||||
desc = "A tank of compressed carbon dioxide for miners to use as propulsion in local space. The compact size allows for easy storage at the cost of capacity."
|
||||
volume = 40
|
||||
throw_range = 7
|
||||
w_class = 3 //same as syndie harness
|
||||
w_class = 3 //same as syndie harness
|
||||
|
||||
/*********************Hivelord stabilizer****************/
|
||||
|
||||
/obj/item/weapon/hivelordstabilizer
|
||||
name = "hivelord stabilizer"
|
||||
icon_state = "hivestabilizer"
|
||||
item_state = "hivestabilizer"
|
||||
desc = "Inject a hivelord core with this stabilizer to preserve its healing powers indefinitely."
|
||||
w_class = 1
|
||||
origin_tech = "biotech=1"
|
||||
|
||||
/obj/item/weapon/hivelordstabilizer/attack(obj/item/organ/internal/M, mob/user)
|
||||
var/obj/item/organ/internal/hivelord_core/C = M
|
||||
if(!istype(C, /obj/item/organ/internal/hivelord_core))
|
||||
user << "<span class='warning'>The stabilizer only works on hivelord cores.</span>"
|
||||
return ..()
|
||||
C.preserved = 1
|
||||
user << "<span class='notice'>You inject the hivelord core with the stabilizer. It will no longer go inert.</span>"
|
||||
qdel(src)
|
||||
@@ -74,11 +74,19 @@
|
||||
/obj/item/weapon/pickaxe/proc/playDigSound()
|
||||
playsound(src, pick(digsound),50,1)
|
||||
|
||||
/obj/item/weapon/pickaxe/silver
|
||||
name = "silver-plated pickaxe"
|
||||
icon_state = "spickaxe"
|
||||
item_state = "spickaxe"
|
||||
digspeed = 30 //mines faster than a normal pickaxe, bought from mining vendor
|
||||
origin_tech = "materials=3;engineering=2"
|
||||
desc = "A silver-plated pickaxe that mines slightly faster than standard-issue."
|
||||
|
||||
/obj/item/weapon/pickaxe/diamond
|
||||
name = "diamond-tipped pickaxe"
|
||||
icon_state = "dpickaxe"
|
||||
item_state = "dpickaxe"
|
||||
digspeed = 20 //mines twice as fast as a normal pickaxe, bought from mining vendor
|
||||
digspeed = 20
|
||||
origin_tech = "materials=4;engineering=3"
|
||||
desc = "A pickaxe with a diamond pick head. Extremely robust at cracking rock walls and digging up dirt."
|
||||
|
||||
|
||||
@@ -10,13 +10,15 @@ var/global/list/rockTurfEdgeCache
|
||||
name = "rock"
|
||||
icon = 'icons/turf/mining.dmi'
|
||||
icon_state = "rock_nochance"
|
||||
baseturf = /turf/simulated/floor/plating/asteroid
|
||||
baseturf = /turf/simulated/floor/plating/asteroid/airless
|
||||
oxygen = 0
|
||||
nitrogen = 0
|
||||
opacity = 1
|
||||
density = 1
|
||||
blocks_air = 1
|
||||
temperature = TCMB
|
||||
var/environment_type = "asteroid"
|
||||
var/turf/simulated/floor/plating/asteroid/turf_type = /turf/simulated/floor/plating/asteroid //For basalt vs normal asteroid
|
||||
var/mineralType = null
|
||||
var/mineralAmt = 3
|
||||
var/spread = 0 //will the seam spread?
|
||||
@@ -25,6 +27,11 @@ var/global/list/rockTurfEdgeCache
|
||||
var/scan_state = null //Holder for the image we display when we're pinged by a mining scanner
|
||||
var/hidden = 1
|
||||
|
||||
/turf/simulated/mineral/volcanic
|
||||
environment_type = "basalt"
|
||||
turf_type = /turf/simulated/floor/plating/asteroid/basalt
|
||||
baseturf = /turf/simulated/floor/plating/asteroid/basalt
|
||||
|
||||
/turf/simulated/mineral/ex_act(severity, target)
|
||||
..()
|
||||
switch(severity)
|
||||
@@ -78,6 +85,7 @@ var/global/list/rockTurfEdgeCache
|
||||
|
||||
/turf/simulated/mineral/proc/HideRock()
|
||||
if(hidden)
|
||||
name = "rock"
|
||||
icon_state = "rock"
|
||||
return
|
||||
|
||||
@@ -126,6 +134,10 @@ var/global/list/rockTurfEdgeCache
|
||||
/*if("Adamantine")
|
||||
M = new/turf/simulated/mineral/adamantine(src)*/
|
||||
if(M)
|
||||
M.mineralAmt = rand(1, 5)
|
||||
M.environment_type = src.environment_type
|
||||
M.turf_type = src.turf_type
|
||||
M.baseturf = src.baseturf
|
||||
src = M
|
||||
M.levelupdate()
|
||||
return
|
||||
@@ -215,7 +227,7 @@ var/global/list/rockTurfEdgeCache
|
||||
/turf/simulated/mineral/bscrystal
|
||||
name = "bluespace crystal deposit"
|
||||
icon_state = "rock_BScrystal"
|
||||
mineralType = /obj/item/bluespace_crystal
|
||||
mineralType = /obj/item/weapon/ore/bluespace_crystal
|
||||
mineralAmt = 1
|
||||
spreadChance = 0
|
||||
spread = 0
|
||||
@@ -309,19 +321,16 @@ var/global/list/rockTurfEdgeCache
|
||||
if(det_time >= 1 && det_time <= 2)
|
||||
G.quality = 2
|
||||
G.icon_state = "Gibtonite ore 2"
|
||||
var/turf/simulated/floor/plating/asteroid/airless/gibtonite_remains/G = ChangeTurf(/turf/simulated/floor/plating/asteroid/airless/gibtonite_remains)
|
||||
var/turf/simulated/floor/plating/asteroid/G = ChangeTurf(turf_type)
|
||||
G.fullUpdateMineralOverlays()
|
||||
|
||||
/turf/simulated/floor/plating/asteroid/airless/gibtonite_remains
|
||||
var/det_time = 0
|
||||
var/stage = 0
|
||||
|
||||
////////////////////////////////End Gibtonite
|
||||
|
||||
/turf/simulated/floor/plating/asteroid/airless/cave
|
||||
var/length = 100
|
||||
var/mob_spawn_list = list("Goldgrub" = 1, "Goliath" = 5, "Basilisk" = 4, "Hivelord" = 3)
|
||||
var/sanity = 1
|
||||
turf_type = /turf/simulated/floor/plating/asteroid/airless
|
||||
|
||||
/turf/simulated/floor/plating/asteroid/airless/cave/New(loc, var/length, var/go_backwards = 1, var/exclude_dir = -1)
|
||||
|
||||
@@ -391,7 +400,7 @@ var/global/list/rockTurfEdgeCache
|
||||
return
|
||||
|
||||
SpawnMonster(T)
|
||||
var/turf/simulated/floor/t = new /turf/simulated/floor/plating/asteroid/airless(T)
|
||||
var/turf/simulated/floor/t = new turf_type(T)
|
||||
spawn(2)
|
||||
t.fullUpdateMineralOverlays()
|
||||
|
||||
@@ -446,7 +455,7 @@ var/global/list/rockTurfEdgeCache
|
||||
for (i=0;i<mineralAmt;i++)
|
||||
new mineralType(src)
|
||||
feedback_add_details("ore_mined","[mineralType]|[mineralAmt]")
|
||||
var/turf/simulated/floor/plating/asteroid/airless/N = ChangeTurf(/turf/simulated/floor/plating/asteroid/airless)
|
||||
var/turf/simulated/floor/plating/asteroid/N = ChangeTurf(turf_type)
|
||||
playsound(src, 'sound/effects/break_stone.ogg', 50, 1) //beautiful destruction
|
||||
N.fullUpdateMineralOverlays()
|
||||
return
|
||||
@@ -463,20 +472,6 @@ var/global/list/rockTurfEdgeCache
|
||||
M << "<span class='notice'>You tunnel into the rock.</span>"
|
||||
gets_drilled(M)
|
||||
|
||||
/*
|
||||
/turf/simulated/mineral/proc/setRandomMinerals()
|
||||
var/s = pickweight(list("uranium" = 5, "iron" = 50, "gold" = 5, "silver" = 5, "plasma" = 50, "diamond" = 1))
|
||||
if (s)
|
||||
mineralName = s
|
||||
|
||||
var/N = text2path("/turf/simulated/mineral/[s]")
|
||||
if (N)
|
||||
var/turf/simulated/mineral/M = new N
|
||||
src = M
|
||||
if (src.mineralName)
|
||||
mineralAmt = 5
|
||||
return*/
|
||||
|
||||
/turf/simulated/mineral/Bumped(AM as mob|obj)
|
||||
..()
|
||||
if(istype(AM,/mob/living/carbon/human))
|
||||
@@ -508,9 +503,28 @@ var/global/list/rockTurfEdgeCache
|
||||
icon = 'icons/turf/floors.dmi'
|
||||
icon_state = "asteroid"
|
||||
icon_plating = "asteroid"
|
||||
var/environment_type = "asteroid"
|
||||
var/turf_type = /turf/simulated/floor/plating/asteroid //Because caves do whacky shit to revert to normal
|
||||
var/dug = 0 //0 = has not yet been dug, 1 = has already been dug
|
||||
|
||||
/turf/simulated/floor/plating/asteroid/airless
|
||||
oxygen = 0.01
|
||||
nitrogen = 0.01
|
||||
turf_type = /turf/simulated/floor/plating/asteroid/airless
|
||||
temperature = TCMB
|
||||
|
||||
/turf/simulated/floor/plating/asteroid/basalt
|
||||
name = "volcanic floor"
|
||||
baseturf = /turf/simulated/floor/plating/asteroid/basalt
|
||||
icon = 'icons/turf/floors.dmi'
|
||||
icon_state = "basalt"
|
||||
icon_plating = "basalt"
|
||||
environment_type = "basalt"
|
||||
|
||||
/turf/simulated/floor/plating/asteroid/basalt/lava //lava underneath
|
||||
baseturf = /turf/simulated/floor/plating/lava/smooth
|
||||
|
||||
/turf/simulated/floor/plating/asteroid/basalt/airless
|
||||
oxygen = 0.01
|
||||
nitrogen = 0.01
|
||||
temperature = TCMB
|
||||
@@ -519,13 +533,8 @@ var/global/list/rockTurfEdgeCache
|
||||
var/proper_name = name
|
||||
..()
|
||||
name = proper_name
|
||||
//if (prob(50))
|
||||
// seedName = pick(list("1","2","3","4"))
|
||||
// seedAmt = rand(1,4)
|
||||
if(prob(20))
|
||||
icon_state = "asteroid[rand(0,12)]"
|
||||
// spawn(2)
|
||||
//O updateMineralOverlays()
|
||||
icon_state = "[environment_type][rand(0,12)]"
|
||||
|
||||
/turf/simulated/floor/plating/asteroid/burn_tile()
|
||||
return
|
||||
@@ -598,8 +607,8 @@ var/global/list/rockTurfEdgeCache
|
||||
new/obj/item/weapon/ore/glass(src)
|
||||
new/obj/item/weapon/ore/glass(src)
|
||||
dug = 1
|
||||
icon_plating = "asteroid_dug"
|
||||
icon_state = "asteroid_dug"
|
||||
icon_plating = "[environment_type]_dug"
|
||||
icon_state = "[environment_type]_dug"
|
||||
return
|
||||
|
||||
/turf/simulated/floor/plating/asteroid/singularity_act()
|
||||
@@ -631,6 +640,50 @@ var/global/list/rockTurfEdgeCache
|
||||
t.updateMineralOverlays()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////CHASM//////////////////
|
||||
|
||||
/turf/simulated/chasm
|
||||
name = "chasm"
|
||||
desc = "Watch your step."
|
||||
baseturf = /turf/simulated/chasm
|
||||
smooth = SMOOTH_TRUE
|
||||
icon = 'icons/turf/floors/Chasms.dmi'
|
||||
icon_state = "smooth"
|
||||
var/drop_x = 1
|
||||
var/drop_y = 1
|
||||
var/drop_z = 1
|
||||
|
||||
|
||||
/turf/simulated/chasm/Entered(atom/movable/AM)
|
||||
if(istype(AM, /obj/singularity) || istype(AM, /obj/item/projectile))
|
||||
return
|
||||
drop(AM)
|
||||
|
||||
|
||||
/turf/simulated/chasm/proc/drop(atom/movable/AM)
|
||||
visible_message("[AM] falls into [src]!")
|
||||
AM.Move(locate(drop_x, drop_y, drop_z))
|
||||
AM.visible_message("[AM] falls from above!")
|
||||
if(istype(AM, /mob/living))
|
||||
var/mob/living/L = AM
|
||||
L.adjustBruteLoss(30)
|
||||
|
||||
|
||||
|
||||
/turf/simulated/chasm/straight_down/New()
|
||||
..()
|
||||
drop_x = x
|
||||
drop_y = y
|
||||
if(z+1 <= world.maxz)
|
||||
drop_z = z+1
|
||||
|
||||
|
||||
#undef NORTH_EDGING
|
||||
#undef SOUTH_EDGING
|
||||
#undef EAST_EDGING
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/obj/item/weapon/ore/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/W = I
|
||||
if(W.remove_fuel(15))
|
||||
if(W.remove_fuel(15) && refined_type)
|
||||
new refined_type(get_turf(src.loc))
|
||||
qdel(src)
|
||||
else if(W.isOn())
|
||||
@@ -21,7 +21,7 @@
|
||||
name = "uranium ore"
|
||||
icon_state = "Uranium ore"
|
||||
origin_tech = "materials=5"
|
||||
points = 18
|
||||
points = 30
|
||||
materials = list(MAT_URANIUM=MINERAL_MATERIAL_AMOUNT)
|
||||
refined_type = /obj/item/stack/sheet/mineral/uranium
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
name = "plasma ore"
|
||||
icon_state = "Plasma ore"
|
||||
origin_tech = "plasmatech=2;materials=2"
|
||||
points = 36
|
||||
points = 15
|
||||
materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT)
|
||||
refined_type = /obj/item/stack/sheet/mineral/plasma
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
name = "silver ore"
|
||||
icon_state = "Silver ore"
|
||||
origin_tech = "materials=3"
|
||||
points = 18
|
||||
points = 16
|
||||
materials = list(MAT_SILVER=MINERAL_MATERIAL_AMOUNT)
|
||||
refined_type = /obj/item/stack/sheet/mineral/silver
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
name = "diamond ore"
|
||||
icon_state = "Diamond ore"
|
||||
origin_tech = "materials=6"
|
||||
points = 36
|
||||
points = 50
|
||||
materials = list(MAT_DIAMOND=MINERAL_MATERIAL_AMOUNT)
|
||||
refined_type = /obj/item/stack/sheet/mineral/diamond
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
name = "bananium ore"
|
||||
icon_state = "Clown ore"
|
||||
origin_tech = "materials=4"
|
||||
points = 27
|
||||
points = 60
|
||||
materials = list(MAT_BANANIUM=MINERAL_MATERIAL_AMOUNT)
|
||||
refined_type = /obj/item/stack/sheet/mineral/bananium
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
var/amt_plasma = 0
|
||||
var/amt_uranium = 0
|
||||
var/amt_clown = 0
|
||||
var/amt_bluespace = 0
|
||||
|
||||
for (var/obj/item/weapon/ore/C in contents)
|
||||
if (istype(C,/obj/item/weapon/ore/diamond))
|
||||
@@ -49,6 +50,8 @@
|
||||
amt_uranium++;
|
||||
if (istype(C,/obj/item/weapon/ore/bananium))
|
||||
amt_clown++;
|
||||
if (istype(C,/obj/item/weapon/ore/bluespace_crystal))
|
||||
amt_bluespace++
|
||||
|
||||
var/dat = text("<b>The contents of the ore box reveal...</b><br>")
|
||||
if (amt_gold)
|
||||
@@ -67,6 +70,8 @@
|
||||
dat += text("Uranium ore: [amt_uranium]<br>")
|
||||
if (amt_clown)
|
||||
dat += text("Bananium ore: [amt_clown]<br>")
|
||||
if (amt_bluespace)
|
||||
dat += text("Bluespace crystals: [amt_bluespace]<br>")
|
||||
|
||||
dat += text("<br><br><A href='?src=\ref[src];removeall=1'>Empty box</A>")
|
||||
user << browse("[dat]", "window=orebox")
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
/mob/dead/observer/Login()
|
||||
..()
|
||||
|
||||
if(check_rights(R_ADMIN, 0))
|
||||
has_unlimited_silicon_privilege = 1
|
||||
|
||||
if(client.prefs.unlock_content)
|
||||
icon_state = client.prefs.ghost_form
|
||||
if (ghostimage)
|
||||
|
||||
@@ -402,9 +402,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
H.add_hud_to(src)
|
||||
data_hud_seen = hud_index
|
||||
|
||||
/mob/dead/observer/verb/toggle_ghost_med_sec_hud()
|
||||
set name = "Toggle Sec/Med HUD"
|
||||
set desc = "Toggles whether you see medical/security HUDs"
|
||||
/mob/dead/observer/verb/toggle_ghost_med_sec_diag_hud()
|
||||
set name = "Toggle Sec/Med/Diag HUD"
|
||||
set desc = "Toggles whether you see medical/security/diagnostic HUDs"
|
||||
set category = "Ghost"
|
||||
|
||||
if(data_hud_seen) //remove old huds
|
||||
@@ -414,11 +414,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
switch(data_hud_seen) //give new huds
|
||||
if(0)
|
||||
show_me_the_hud(DATA_HUD_SECURITY_BASIC)
|
||||
src << "<span class='notice'>Security HUD set.</span>"
|
||||
if(DATA_HUD_SECURITY_BASIC)
|
||||
show_me_the_hud(DATA_HUD_MEDICAL_ADVANCED)
|
||||
src << "<span class='notice'>Medical HUD set.</span>"
|
||||
if(DATA_HUD_MEDICAL_ADVANCED)
|
||||
show_me_the_hud(DATA_HUD_DIAGNOSTIC)
|
||||
src << "<span class='notice'>Diagnostic HUD set.</span>"
|
||||
if(DATA_HUD_DIAGNOSTIC)
|
||||
data_hud_seen = 0
|
||||
src << "<span class='notice'>HUDs disabled.</span>"
|
||||
|
||||
/mob/dead/observer/canUseTopic()
|
||||
if(check_rights(R_ADMIN, 0))
|
||||
return
|
||||
return 1
|
||||
return
|
||||
@@ -182,7 +182,7 @@
|
||||
if(TRAITS & TRAIT_THIEVING)
|
||||
slyness = 75
|
||||
|
||||
SSbp.insertBot(src)
|
||||
SSnpc.insertBot(src)
|
||||
|
||||
|
||||
/mob/living/carbon/human/interactive/attack_hand(mob/living/carbon/human/M)
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
var/alt_inhands_file = 'icons/mob/alienqueen.dmi'
|
||||
|
||||
/mob/living/carbon/alien/humanoid/royal/can_inject()
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/alien/humanoid/royal/queen
|
||||
name = "alien queen"
|
||||
caste = "q"
|
||||
|
||||
@@ -84,7 +84,7 @@ var/const/MAX_ACTIVE_TIME = 400
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj)
|
||||
if(CanHug(AM))
|
||||
if(CanHug(AM) && Adjacent(AM))
|
||||
return Attach(AM)
|
||||
return 0
|
||||
|
||||
@@ -230,7 +230,7 @@ var/const/MAX_ACTIVE_TIME = 400
|
||||
return 1
|
||||
|
||||
var/mob/living/carbon/C = M
|
||||
if(ishuman(C))
|
||||
if(ishuman(C) && !(slot_wear_mask in C.dna.species.no_equip))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.is_mouth_covered(head_only = 1))
|
||||
return 0
|
||||
|
||||
@@ -346,6 +346,7 @@ var/const/NO_SLIP_WHEN_WALKING = 1
|
||||
var/const/SLIDE = 2
|
||||
var/const/GALOSHES_DONT_HELP = 4
|
||||
/mob/living/carbon/slip(s_amount, w_amount, obj/O, lube)
|
||||
add_logs(src,, "slipped",, "on [O ? O.name : "floor"]")
|
||||
return loc.handle_slip(src, s_amount, w_amount, O, lube)
|
||||
|
||||
/mob/living/carbon/fall(forced)
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
// called when something steps onto a human
|
||||
// this could be made more general, but for now just handle mulebot
|
||||
/mob/living/carbon/human/Crossed(atom/movable/AM)
|
||||
var/obj/machinery/bot/mulebot/MB = AM
|
||||
var/mob/living/simple_animal/bot/mulebot/MB = AM
|
||||
if(istype(MB))
|
||||
MB.RunOver(src)
|
||||
|
||||
@@ -281,9 +281,14 @@
|
||||
//Added a safety check in case you want to shock a human mob directly through electrocute_act.
|
||||
/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0)
|
||||
if(!safety)
|
||||
var/gloves_siemens_coeff = 1
|
||||
var/species_siemens_coeff = 1
|
||||
if(gloves)
|
||||
var/obj/item/clothing/gloves/G = gloves
|
||||
siemens_coeff = G.siemens_coefficient
|
||||
gloves_siemens_coeff = G.siemens_coefficient
|
||||
if(dna && dna.species)
|
||||
species_siemens_coeff = dna.species.siemens_coeff
|
||||
siemens_coeff = gloves_siemens_coeff * species_siemens_coeff
|
||||
if(heart_attack)
|
||||
if(shock_damage * siemens_coeff >= 1 && prob(25))
|
||||
heart_attack = 0
|
||||
@@ -591,7 +596,7 @@
|
||||
else
|
||||
return null
|
||||
|
||||
/mob/living/carbon/human/assess_threat(obj/machinery/bot/secbot/judgebot, lasercolor)
|
||||
/mob/living/carbon/human/assess_threat(mob/living/simple_animal/bot/secbot/judgebot, lasercolor)
|
||||
if(judgebot.emagged == 2)
|
||||
return 10 //Everyone is a criminal!
|
||||
|
||||
@@ -853,4 +858,4 @@
|
||||
return
|
||||
if(!isturf(M.loc) && M.loc != src)
|
||||
return
|
||||
return 1
|
||||
return 1
|
||||
|
||||
@@ -82,41 +82,25 @@ emp_act
|
||||
//End Here
|
||||
|
||||
/mob/living/carbon/human/proc/check_shields(damage = 0, attack_text = "the attack", atom/movable/AM, thrown_proj = 0, armour_penetration = 0)
|
||||
var/block_chance = 50 + 30*thrown_proj - round(damage / 3) //thrown things are easier to block
|
||||
var/block_chance_modifier = 30*thrown_proj - round(damage / 3) //thrown things are easier to block
|
||||
if(AM)
|
||||
if(AM.flags & NOSHIELD) //weapon ignores shields altogether
|
||||
return 0
|
||||
var/blocker
|
||||
if(l_hand)
|
||||
if(l_hand.IsShield())
|
||||
block_chance -= Clamp((armour_penetration-l_hand.armour_penetration)/2,0,100) //So armour piercing blades can still be parried by other blades, for example
|
||||
if(prob(block_chance))
|
||||
blocker = l_hand
|
||||
if(r_hand)
|
||||
if(r_hand.IsShield())
|
||||
block_chance -= Clamp((armour_penetration-r_hand.armour_penetration)/2,0,100)
|
||||
if(prob(block_chance))
|
||||
blocker = r_hand
|
||||
if(blocker)
|
||||
visible_message("<span class='danger'>[src] blocks [attack_text] with [blocker]!</span>", \
|
||||
"<span class='userdanger'>[src] blocks [attack_text] with [blocker]!</span>")
|
||||
return 1
|
||||
if(l_hand && !istype(l_hand, /obj/item/clothing))
|
||||
var/final_block_chance = l_hand.block_chance - (Clamp((armour_penetration-l_hand.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
|
||||
if(l_hand.hit_reaction(src, attack_text, final_block_chance))
|
||||
return 1
|
||||
if(r_hand && !istype(r_hand, /obj/item/clothing))
|
||||
var/final_block_chance = r_hand.block_chance - (Clamp((armour_penetration-r_hand.armour_penetration)/2,0,100)) + block_chance_modifier //Need to reset the var so it doesn't carry over modifications between attempts
|
||||
if(r_hand.hit_reaction(src, attack_text, final_block_chance))
|
||||
return 1
|
||||
if(wear_suit)
|
||||
if(wear_suit.IsShield() && (prob(50)))
|
||||
visible_message("<span class='danger'>The reactive teleport system flings [src] clear of [attack_text]!</span>", \
|
||||
"<span class='userdanger'>The reactive teleport system flings [src] clear of [attack_text]!</span>")
|
||||
var/list/turfs = new/list()
|
||||
for(var/turf/T in orange(6, src))
|
||||
if(T.density) continue
|
||||
if(T.x>world.maxx-6 || T.x<6) continue
|
||||
if(T.y>world.maxy-6 || T.y<6) continue
|
||||
turfs += T
|
||||
if(!turfs.len) turfs += pick(/turf in orange(6, src))
|
||||
var/turf/picked = pick(turfs)
|
||||
if(!isturf(picked)) return
|
||||
if(buckled)
|
||||
buckled.unbuckle_mob()
|
||||
forceMove(picked)
|
||||
var/final_block_chance = wear_suit.block_chance - (Clamp((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
|
||||
if(wear_suit.hit_reaction(src, attack_text, final_block_chance))
|
||||
return 1
|
||||
if(w_uniform)
|
||||
var/final_block_chance = w_uniform.block_chance - (Clamp((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
|
||||
if(w_uniform.hit_reaction(src, attack_text, final_block_chance))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@
|
||||
|
||||
return shredded
|
||||
|
||||
/mob/living/carbon/human/proc/equipOutfit(outfit)
|
||||
/mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE)
|
||||
var/datum/outfit/O = null
|
||||
|
||||
if(ispath(outfit))
|
||||
@@ -301,4 +301,4 @@
|
||||
if(!O)
|
||||
return 0
|
||||
|
||||
return O.equip(src)
|
||||
return O.equip(src, visualsOnly)
|
||||
@@ -84,7 +84,7 @@
|
||||
if(4)
|
||||
emote("drool")
|
||||
if(5)
|
||||
say(pick("REMOVE SINGULARITY", "INSTLL TEG", "TURBIN IS BEST ENGIENE", "SOLIRS CAN POWER THE HOLE STATION ANEWAY", "parasteng was best"))
|
||||
say(pick("REMOVE SINGULARITY", "INSTLL TEG", "TURBIN IS BEST ENGIENE", "SOLIRS CAN POWER THE HOLE STATION ANEWAY", "parasteng was best", "Tajaran has warrrres, if you have coin"))
|
||||
|
||||
|
||||
/mob/living/carbon/human/handle_mutations_and_radiation()
|
||||
|
||||
@@ -81,11 +81,6 @@
|
||||
ears.talk_into(src, message, , spans)
|
||||
return ITALICS | REDUCE_RANGE
|
||||
|
||||
if(MODE_SECURE_HEADSET)
|
||||
if (ears)
|
||||
ears.talk_into(src, message, 1, spans)
|
||||
return ITALICS | REDUCE_RANGE
|
||||
|
||||
if(MODE_DEPARTMENT)
|
||||
if (ears)
|
||||
ears.talk_into(src, message, message_mode, spans)
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
var/coldmod = 1 // multiplier for cold damage
|
||||
var/heatmod = 1 // multiplier for heat damage
|
||||
var/punchmod = 0 // adds to the punch damage
|
||||
var/siemens_coeff = 1 //base electrocution coefficient
|
||||
|
||||
var/invis_sight = SEE_INVISIBLE_LIVING
|
||||
var/darksight = 2
|
||||
@@ -85,6 +86,14 @@
|
||||
// PROCS //
|
||||
///////////
|
||||
|
||||
|
||||
|
||||
//Called when admins use the Set Species verb, let's species
|
||||
//do some init stuff on the mob that got SS'd if necessary
|
||||
/datum/species/proc/admin_set_species(mob/living/carbon/human/H, datum/species/old_species)
|
||||
return
|
||||
|
||||
|
||||
/datum/species/proc/random_name(gender,unique,lastname)
|
||||
if(unique)
|
||||
return random_unique_name(gender)
|
||||
@@ -883,7 +892,7 @@
|
||||
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H)
|
||||
if(!istype(M)) //sanity check for drones.
|
||||
return
|
||||
if((M != H) && H.check_shields(0, M.name))
|
||||
if((M != H) && M.a_intent != "help" && H.check_shields(0, M.name))
|
||||
add_logs(M, H, "attempted to touch")
|
||||
H.visible_message("<span class='warning'>[M] attempted to touch [H]!</span>")
|
||||
return 0
|
||||
@@ -1004,8 +1013,8 @@
|
||||
// Allows you to put in item-specific reactions based on species
|
||||
if(user != H)
|
||||
user.do_attack_animation(H)
|
||||
if(H.check_shields(I.force, "the [I.name]", I, 0, I.armour_penetration))
|
||||
return 0
|
||||
if(H.check_shields(I.force, "the [I.name]", I, 0, I.armour_penetration))
|
||||
return 0
|
||||
|
||||
if(I.attack_verb && I.attack_verb.len)
|
||||
H.visible_message("<span class='danger'>[user] has [pick(I.attack_verb)] [H] in the [hit_area] with [I]!</span>", \
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None")
|
||||
use_skintones = 1
|
||||
|
||||
|
||||
/datum/species/human/qualifies_for_rank(rank, list/features)
|
||||
if((!features["tail_human"] || features["tail_human"] == "None") && (!features["ears"] || features["ears"] == "None"))
|
||||
return 1 //Pure humans are always allowed in all roles.
|
||||
@@ -336,6 +337,7 @@ datum/species/human/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
specflags = list(NOBREATH,HEATRES,COLDRES,NOGUNS,NOBLOOD,RADIMMUNE,VIRUSIMMUNE,PIERCEIMMUNE)
|
||||
speedmod = 3
|
||||
armor = 55
|
||||
siemens_coeff = 0
|
||||
punchmod = 5
|
||||
no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_w_uniform)
|
||||
nojumpsuit = 1
|
||||
@@ -474,22 +476,28 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_
|
||||
safe_toxins_max = 0
|
||||
dangerous_existence = 1 //So so much
|
||||
need_nutrition = 0 //Hard to eat through a helmet
|
||||
burnmod = 2
|
||||
heatmod = 2
|
||||
speedmod = 1
|
||||
var/skin = 0
|
||||
|
||||
/datum/species/plasmaman/skin
|
||||
name = "Skinbone"
|
||||
skin = 1
|
||||
roundstart = 0
|
||||
|
||||
/datum/species/plasmaman/update_base_icon_state(mob/living/carbon/human/H)
|
||||
var/base = ..()
|
||||
if(base == id)
|
||||
base = "[base][skin]"
|
||||
if(base == id && !skin)
|
||||
base = "[base]_m"
|
||||
else
|
||||
base = "skinbone_m"
|
||||
return base
|
||||
|
||||
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H)
|
||||
var/datum/gas_mixture/environment = H.loc.return_air()
|
||||
|
||||
if(!istype(H.w_uniform, /obj/item/clothing/under/plasmaman) || !istype(H.head, /obj/item/clothing/head/helmet/plasmaman))
|
||||
if(!istype(H.w_uniform, /obj/item/clothing/under/plasmaman) || !istype(H.head, /obj/item/clothing/head/helmet/space/plasmaman))
|
||||
if(environment)
|
||||
var/total_moles = environment.total_moles()
|
||||
if(total_moles)
|
||||
@@ -505,9 +513,9 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_
|
||||
P.Extinguish(H)
|
||||
H.update_fire()
|
||||
|
||||
/datum/species/plasmaman/before_equip_job(datum/job/J, mob/living/carbon/human/H)
|
||||
/datum/species/plasmaman/before_equip_job(datum/job/J, mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
var/datum/outfit/plasmaman/O = new /datum/outfit/plasmaman
|
||||
H.equipOutfit(O)
|
||||
H.equipOutfit(O, visualsOnly)
|
||||
return 0
|
||||
|
||||
/datum/species/plasmaman/qualifies_for_rank(rank, list/features)
|
||||
@@ -519,3 +527,191 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
|
||||
var/global/list/synth_flesh_disguises = list()
|
||||
|
||||
/datum/species/synth
|
||||
name = "Synth" //inherited from the real species, for health scanners and things
|
||||
id = "synth"
|
||||
say_mod = "beep boops" //inherited from a user's real species
|
||||
sexes = 0
|
||||
specflags = list(NOTRANSSTING,NOBREATH,VIRUSIMMUNE) //all of these + whatever we inherit from the real species
|
||||
safe_oxygen_min = 0
|
||||
safe_toxins_min = 0
|
||||
safe_toxins_max = 0
|
||||
safe_co2_max = 0
|
||||
SA_para_min = 0
|
||||
SA_sleep_min = 0
|
||||
dangerous_existence = 1
|
||||
need_nutrition = 0 //beep boop robots do not need sustinance
|
||||
meat = null
|
||||
var/list/initial_specflags = list(NOTRANSSTING,NOBREATH,VIRUSIMMUNE) //for getting these values back for assume_disguise()
|
||||
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
|
||||
var/image/damaged_synth_flesh = null //an image to display when we're below disguise_fail_health
|
||||
var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
|
||||
|
||||
|
||||
/datum/species/synth/military
|
||||
name = "Military Synth"
|
||||
id = "military_synth"
|
||||
armor = 25
|
||||
punchmod = 10
|
||||
disguise_fail_health = 50
|
||||
|
||||
|
||||
/datum/species/synth/admin_set_species(mob/living/carbon/human/H, old_species)
|
||||
assume_disguise(old_species,H)
|
||||
|
||||
|
||||
/datum/species/synth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.id == "synthflesh")
|
||||
chem.reaction_mob(H, TOUCH, 2 ,0) //heal a little
|
||||
handle_disguise(H) //and update flesh disguise
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
|
||||
|
||||
/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
|
||||
if(S && !istype(S, type))
|
||||
name = S.name
|
||||
say_mod = S.say_mod
|
||||
specflags = initial_specflags.Copy()
|
||||
specflags.Add(S.specflags)
|
||||
attack_verb = S.attack_verb
|
||||
attack_sound = S.attack_sound
|
||||
miss_sound = S.miss_sound
|
||||
meat = S.meat
|
||||
mutant_bodyparts = S.mutant_bodyparts.Copy()
|
||||
default_features = S.default_features.Copy()
|
||||
nojumpsuit = S.nojumpsuit
|
||||
no_equip = S.no_equip.Copy()
|
||||
fake_species = new S.type
|
||||
else
|
||||
name = initial(name)
|
||||
say_mod = initial(say_mod)
|
||||
specflags = initial_specflags.Copy()
|
||||
attack_verb = initial(attack_verb)
|
||||
attack_sound = initial(attack_sound)
|
||||
miss_sound = initial(miss_sound)
|
||||
mutant_bodyparts = list()
|
||||
default_features = list()
|
||||
nojumpsuit = initial(nojumpsuit)
|
||||
no_equip = list()
|
||||
qdel(fake_species)
|
||||
fake_species = null
|
||||
meat = initial(meat)
|
||||
|
||||
build_disguise(H)
|
||||
handle_disguise(H)
|
||||
|
||||
|
||||
/datum/species/synth/proc/build_disguise(mob/living/carbon/human/H)
|
||||
var/base = ""
|
||||
if(fake_species)
|
||||
base = fake_species.update_base_icon_state(H)
|
||||
if(synth_flesh_disguises[base])
|
||||
damaged_synth_flesh = synth_flesh_disguises[base]
|
||||
else
|
||||
var/icon/base_flesh = icon(H.icon,"[base]_s")
|
||||
var/icon/damage = icon(H.icon,"synthflesh_damage")
|
||||
base_flesh.Blend(damage,ICON_MULTIPLY) //damage the skin
|
||||
damaged_synth_flesh = image(icon = base_flesh, layer= -SPECIES_LAYER)
|
||||
synth_flesh_disguises[base] = damaged_synth_flesh
|
||||
else
|
||||
damaged_synth_flesh = null
|
||||
|
||||
|
||||
/datum/species/synth/proc/handle_disguise(mob/living/carbon/human/H)
|
||||
if(H)
|
||||
H.updatehealth()
|
||||
var/add_overlay = FALSE
|
||||
if(H.health < disguise_fail_health)
|
||||
//clear these out, they look weird
|
||||
H.underwear = ""
|
||||
H.undershirt = ""
|
||||
H.socks = ""
|
||||
add_overlay = TRUE
|
||||
else
|
||||
H.overlays -= damaged_synth_flesh
|
||||
if(H.overlays_standing[SPECIES_LAYER] == damaged_synth_flesh)
|
||||
H.overlays_standing[SPECIES_LAYER] = null
|
||||
|
||||
H.regenerate_icons()
|
||||
if(add_overlay)
|
||||
H.remove_overlay(SPECIES_LAYER)
|
||||
|
||||
//Copy and colour the image for coloured species
|
||||
var/image/I = image(layer = -SPECIES_LAYER)
|
||||
I.appearance = damaged_synth_flesh.appearance
|
||||
if(MUTCOLORS in specflags)
|
||||
I.color = "#[H.dna.features["mcolor"]]"
|
||||
damaged_synth_flesh = I
|
||||
|
||||
H.overlays_standing[SPECIES_LAYER] = damaged_synth_flesh
|
||||
H.apply_overlay(SPECIES_LAYER)
|
||||
|
||||
|
||||
|
||||
/datum/species/synth/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
handle_disguise(H)
|
||||
|
||||
|
||||
//Proc redirects:
|
||||
//Passing procs onto the fake_species, to ensure we look as much like them as possible
|
||||
|
||||
/datum/species/synth/update_base_icon_state(mob/living/carbon/human/H)
|
||||
H.updatehealth()
|
||||
if(H.health > disguise_fail_health)
|
||||
if(fake_species)
|
||||
return fake_species.update_base_icon_state(H)
|
||||
else
|
||||
return ..()
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/datum/species/synth/update_color(mob/living/carbon/human/H, forced_colour)
|
||||
H.updatehealth()
|
||||
if(H.health > disguise_fail_health)
|
||||
if(fake_species)
|
||||
fake_species.update_color(H, forced_colour)
|
||||
|
||||
|
||||
/datum/species/synth/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
H.updatehealth()
|
||||
if(H.health > disguise_fail_health)
|
||||
if(fake_species)
|
||||
fake_species.handle_hair(H, forced_colour)
|
||||
|
||||
|
||||
/datum/species/synth/handle_body(mob/living/carbon/human/H)
|
||||
H.updatehealth()
|
||||
if(H.health > disguise_fail_health)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H)
|
||||
|
||||
|
||||
/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
|
||||
H.updatehealth()
|
||||
if(H.health > disguise_fail_health)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H,forced_colour)
|
||||
|
||||
|
||||
/datum/species/synth/get_spans()
|
||||
if(fake_species)
|
||||
return fake_species.get_spans()
|
||||
return list()
|
||||
|
||||
|
||||
/datum/species/synth/handle_speech(message, mob/living/carbon/human/H)
|
||||
H.updatehealth()
|
||||
if(H.health > disguise_fail_health)
|
||||
if(fake_species)
|
||||
return fake_species.handle_speech(message,H)
|
||||
else
|
||||
return ..()
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/mob/living/carbon/human/whisper(message as text)
|
||||
if(!IsVocal())
|
||||
return
|
||||
if(!message)
|
||||
return
|
||||
if(!message)
|
||||
return
|
||||
|
||||
if(say_disabled) //This is here to try to identify lag problems
|
||||
usr << "<span class='danger'>Speech is currently admin-disabled.</span>"
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
breath_moles = environment.total_moles()*BREATH_PERCENTAGE
|
||||
|
||||
breath = loc.remove_air(breath_moles)
|
||||
|
||||
else //Breathe from loc as obj again
|
||||
if(istype(loc, /obj/))
|
||||
var/obj/loc_as_obj = loc
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
/mob/living/carbon/monkey/canBeHandcuffed()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/monkey/assess_threat(obj/machinery/bot/secbot/judgebot, lasercolor)
|
||||
/mob/living/carbon/monkey/assess_threat(mob/living/simple_animal/bot/secbot/judgebot, lasercolor)
|
||||
if(judgebot.emagged == 2)
|
||||
return 10 //Everyone is a criminal!
|
||||
var/threatcount = 0
|
||||
|
||||
@@ -160,9 +160,10 @@ Sorry Giacom. Please don't be mad :(
|
||||
set name = "Pull"
|
||||
set category = "Object"
|
||||
|
||||
if(AM.Adjacent(src))
|
||||
if(pulling == AM)
|
||||
stop_pulling()
|
||||
else if(AM.Adjacent(src))
|
||||
src.start_pulling(AM)
|
||||
return
|
||||
|
||||
//same as above
|
||||
/mob/living/pointed(atom/A as mob|obj|turf in view())
|
||||
@@ -765,7 +766,7 @@ Sorry Giacom. Please don't be mad :(
|
||||
|
||||
/mob/living/narsie_act()
|
||||
if(client)
|
||||
makeNewConstruct(/mob/living/simple_animal/construct/harvester, src, null, 0)
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, null, 0)
|
||||
spawn_dust()
|
||||
gib()
|
||||
return
|
||||
@@ -777,28 +778,17 @@ Sorry Giacom. Please don't be mad :(
|
||||
var/final_pixel_y = initial(pixel_y)
|
||||
if(end_pixel_y)
|
||||
final_pixel_y = end_pixel_y
|
||||
|
||||
var/direction = get_dir(src, A)
|
||||
switch(direction)
|
||||
if(NORTH)
|
||||
pixel_y_diff = 8
|
||||
if(SOUTH)
|
||||
pixel_y_diff = -8
|
||||
if(EAST)
|
||||
pixel_x_diff = 8
|
||||
if(WEST)
|
||||
pixel_x_diff = -8
|
||||
if(NORTHEAST)
|
||||
pixel_x_diff = 8
|
||||
pixel_y_diff = 8
|
||||
if(NORTHWEST)
|
||||
pixel_x_diff = -8
|
||||
pixel_y_diff = 8
|
||||
if(SOUTHEAST)
|
||||
pixel_x_diff = 8
|
||||
pixel_y_diff = -8
|
||||
if(SOUTHWEST)
|
||||
pixel_x_diff = -8
|
||||
pixel_y_diff = -8
|
||||
if(direction & NORTH)
|
||||
pixel_y_diff = 8
|
||||
else if(direction & SOUTH)
|
||||
pixel_y_diff = -8
|
||||
|
||||
if(direction & EAST)
|
||||
pixel_x_diff = 8
|
||||
else if(direction & WEST)
|
||||
pixel_x_diff = -8
|
||||
|
||||
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2)
|
||||
animate(pixel_x = initial(pixel_x), pixel_y = final_pixel_y, time = 2)
|
||||
@@ -807,24 +797,44 @@ Sorry Giacom. Please don't be mad :(
|
||||
/mob/living/do_attack_animation(atom/A)
|
||||
var/final_pixel_y = get_standard_pixel_y_offset(lying)
|
||||
..(A, final_pixel_y)
|
||||
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure to restart it in next life().
|
||||
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
|
||||
|
||||
//Show an image of the wielded weapon over the person who got dunked.
|
||||
// What icon do we use for the attack?
|
||||
var/image/I
|
||||
if(hand)
|
||||
if(l_hand)
|
||||
I = image(l_hand.icon,A,l_hand.icon_state,A.layer+1)
|
||||
else
|
||||
if(r_hand)
|
||||
I = image(r_hand.icon,A,r_hand.icon_state,A.layer+1)
|
||||
if(I)
|
||||
var/list/viewing = list()
|
||||
for(var/mob/M in viewers(A))
|
||||
if(M.client)
|
||||
viewing |= M.client
|
||||
flick_overlay(I,viewing,5)
|
||||
I.pixel_z = 16 //lift it up...
|
||||
animate(I, pixel_z = 0, alpha = 125, time = 3) //smash it down into them!
|
||||
if(hand && l_hand) // Attacked with item in left hand.
|
||||
I = image(l_hand.icon, A, l_hand.icon_state, A.layer + 1)
|
||||
else if (!hand && r_hand) // Attacked with item in right hand.
|
||||
I = image(r_hand.icon, A, r_hand.icon_state, A.layer + 1)
|
||||
else // Attacked with a fist?
|
||||
return
|
||||
|
||||
// Who can see the attack?
|
||||
var/list/viewing = list()
|
||||
for (var/mob/M in viewers(A))
|
||||
if (M.client)
|
||||
viewing |= M.client
|
||||
flick_overlay(I, viewing, 5) // 5 ticks/half a second
|
||||
|
||||
// Scale the icon.
|
||||
I.transform *= 0.75
|
||||
|
||||
// Set the direction of the icon animation.
|
||||
var/direction = get_dir(src, A)
|
||||
if(direction & NORTH)
|
||||
I.pixel_y = -16
|
||||
else if(direction & SOUTH)
|
||||
I.pixel_y = 16
|
||||
|
||||
if(direction & EAST)
|
||||
I.pixel_x = -16
|
||||
else if(direction & WEST)
|
||||
I.pixel_x = 16
|
||||
|
||||
if(!direction) // Attacked self?!
|
||||
I.pixel_z = 16
|
||||
|
||||
// And animate the attack!
|
||||
animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3)
|
||||
|
||||
/mob/living/proc/do_jitter_animation(jitteriness)
|
||||
var/amplitude = min(4, (jitteriness/100) + 1)
|
||||
|
||||
@@ -35,7 +35,7 @@ var/list/ai_list = list()
|
||||
radiomod = ";" //AIs will, by default, state their laws on the internal radio.
|
||||
var/obj/item/device/pda/ai/aiPDA = null
|
||||
var/obj/item/device/multitool/aiMulti = null
|
||||
var/obj/machinery/bot/Bot
|
||||
var/mob/living/simple_animal/bot/Bot
|
||||
var/tracking = 0 //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed.
|
||||
var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N
|
||||
|
||||
@@ -257,11 +257,6 @@ var/list/ai_list = list()
|
||||
else
|
||||
stat(null, text("Systems nonfunctional"))
|
||||
|
||||
/mob/living/silicon/ai/canUseTopic()
|
||||
if(stat)
|
||||
return
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_alerts()
|
||||
var/dat = "<HEAD><TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n"
|
||||
dat += "<A HREF='?src=\ref[src];mach_close=aialerts'>Close</A><BR><BR>"
|
||||
@@ -446,14 +441,14 @@ var/list/ai_list = list()
|
||||
src << "Target is not on or near any active cameras on the station."
|
||||
return
|
||||
if(href_list["callbot"]) //Command a bot to move to a selected location.
|
||||
Bot = locate(href_list["callbot"]) in SSbot.processing
|
||||
Bot = locate(href_list["callbot"]) in living_mob_list
|
||||
if(!Bot || Bot.remote_disabled || src.control_disabled)
|
||||
return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
|
||||
waypoint_mode = 1
|
||||
src << "<span class='notice'>Set your waypoint by clicking on a valid location free of obstructions.</span>"
|
||||
return
|
||||
if(href_list["interface"]) //Remotely connect to a bot!
|
||||
Bot = locate(href_list["interface"]) in SSbot.processing
|
||||
Bot = locate(href_list["interface"]) in living_mob_list
|
||||
if(!Bot || Bot.remote_disabled || src.control_disabled)
|
||||
return
|
||||
Bot.attack_ai(src)
|
||||
@@ -522,15 +517,16 @@ var/list/ai_list = list()
|
||||
var/ai_Zlevel = ai_current_turf.z
|
||||
var/d
|
||||
var/area/bot_area
|
||||
d += "<A HREF=?src=\ref[src];botrefresh=\ref[Bot]>Query network status</A><br>"
|
||||
d += "<A HREF=?src=\ref[src];botrefresh=1>Query network status</A><br>"
|
||||
d += "<table width='100%'><tr><td width='40%'><h3>Name</h3></td><td width='30%'><h3>Status</h3></td><td width='30%'><h3>Location</h3></td><td width='10%'><h3>Control</h3></td></tr>"
|
||||
|
||||
for (Bot in SSbot.processing)
|
||||
for (Bot in living_mob_list)
|
||||
if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
|
||||
bot_area = get_area(Bot)
|
||||
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!)</span>" : ""] [Bot.name] ([Bot.model])</td>"
|
||||
var/bot_mode = Bot.get_mode()
|
||||
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!)</span>" : ""] [Bot.name]</A> ([Bot.model])</td>"
|
||||
//If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all.
|
||||
d += "<td width='30%'>[Bot.on ? "[Bot.mode ? "<span class='average'>[ Bot.get_mode() ]</span>": "<span class='good'>Idle</span>"]" : "<span class='bad'>Inactive</span>"]</td>"
|
||||
d += "<td width='30%'>[bot_mode]</td>"
|
||||
d += "<td width='30%'>[bot_area.name]</td>"
|
||||
d += "<td width='10%'><A HREF=?src=\ref[src];interface=\ref[Bot]>Interface</A></td>"
|
||||
d += "<td width='10%'><A HREF=?src=\ref[src];callbot=\ref[Bot]>Call</A></td>"
|
||||
@@ -795,6 +791,7 @@ var/list/ai_list = list()
|
||||
|
||||
if(stat == 2)
|
||||
return //won't work if dead
|
||||
|
||||
src << "Accessing Subspace Transceiver control..."
|
||||
if (radio)
|
||||
radio.interact(src)
|
||||
@@ -852,6 +849,6 @@ var/list/ai_list = list()
|
||||
//stop AIs from leaving windows open and using then after they lose vision
|
||||
//apc_override is needed here because AIs use their own APC when powerless
|
||||
//get_turf_pixel() is because APCs in maint aren't actually in view of the inner camera
|
||||
if(cameranet && !cameranet.checkTurfVis(get_turf_pixel(M)) && !apc_override)
|
||||
if(M && cameranet && !cameranet.checkTurfVis(get_turf_pixel(M)) && !apc_override)
|
||||
return
|
||||
return 1
|
||||
@@ -7,12 +7,17 @@ var/const/CHUNK_SIZE = 16 // Only chunk sizes that are to the power of 2. E.g: 2
|
||||
var/datum/cameranet/cameranet = new()
|
||||
|
||||
/datum/cameranet
|
||||
var/name = "Camera Net" // Name to show for VV and stat()
|
||||
|
||||
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Del().
|
||||
var/list/cameras = list()
|
||||
// The chunks of the map, mapping the areas that the cameras can see.
|
||||
var/list/chunks = list()
|
||||
var/ready = 0
|
||||
|
||||
// The object used for the clickable stat() button.
|
||||
var/obj/effect/statclick/statclick
|
||||
|
||||
// Checks if a chunk has been Generated in x, y, z.
|
||||
/datum/cameranet/proc/chunkGenerated(x, y, z)
|
||||
x &= ~(CHUNK_SIZE - 1)
|
||||
@@ -142,6 +147,11 @@ var/datum/cameranet/cameranet = new()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/cameranet/proc/stat_entry()
|
||||
if(!statclick)
|
||||
statclick = new/obj/effect/statclick/debug("Initializing...", src)
|
||||
|
||||
stat(name, statclick.update("Cameras: [cameranet.cameras.len] | Chunks: [cameranet.chunks.len]"))
|
||||
|
||||
// Debug verb for VVing the chunk that the turf is in.
|
||||
/*
|
||||
@@ -151,4 +161,4 @@ var/datum/cameranet/cameranet = new()
|
||||
if(cameranet.chunkGenerated(x, y, z))
|
||||
var/datum/camerachunk/chunk = cameranet.getCameraChunk(x, y, z)
|
||||
usr.client.debug_variables(chunk)
|
||||
*/
|
||||
*/
|
||||
@@ -49,7 +49,7 @@
|
||||
loc = T.loc
|
||||
if (istype(loc, /area))
|
||||
//stage = 4
|
||||
if (!loc.master.power_equip && !is_type_in_list(src.loc,list(/obj/item, /obj/mecha)))
|
||||
if (lacks_power())
|
||||
//stage = 5
|
||||
blindness = 1
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
src.see_in_dark = 0
|
||||
src.see_invisible = SEE_INVISIBLE_LIVING
|
||||
|
||||
if (((!loc.master.power_equip) || istype(T, /turf/space)) && !is_type_in_list(src.loc,list(/obj/item, /obj/mecha)))
|
||||
if (lacks_power())
|
||||
if (src:aiRestorePowerRoutine==0)
|
||||
src:aiRestorePowerRoutine = 1
|
||||
|
||||
@@ -169,6 +169,11 @@
|
||||
sleep(50)
|
||||
theAPC = null
|
||||
|
||||
/mob/living/silicon/ai/proc/lacks_power()
|
||||
var/turf/T = get_turf(src)
|
||||
var/area/A = get_area(src)
|
||||
return ((!A.power_equip) || istype(T, /turf/space)) && !is_type_in_list(src.loc, list(/obj/item, /obj/mecha))
|
||||
|
||||
/mob/living/silicon/ai/updatehealth()
|
||||
if(status_flags & GODMODE)
|
||||
health = maxHealth
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
|
||||
playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
|
||||
aicamera = new/obj/item/device/camera/siliconcam/robot_camera(src)
|
||||
toner = 40
|
||||
toner = tonermax
|
||||
diag_hud_set_borgcell()
|
||||
|
||||
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
|
||||
@@ -429,7 +429,7 @@
|
||||
if (WT.remove_fuel(0, user)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away.
|
||||
if(src == user)
|
||||
user << "<span class='notice'>You start fixing youself...</span>"
|
||||
if(!do_after(user, 50, target = src))
|
||||
if(!do_after(user, 50/W.toolspeed, target = src))
|
||||
return
|
||||
|
||||
adjustBruteLoss(-30)
|
||||
@@ -510,7 +510,7 @@
|
||||
else
|
||||
playsound(src, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You start to unfasten [src]'s securing bolts...</span>"
|
||||
if(do_after(user, 50, target = src) && !cell)
|
||||
if(do_after(user, 50/W.toolspeed, target = src) && !cell)
|
||||
user.visible_message("[user] deconstructs [src]!", "<span class='notice'>You unfasten the securing bolts, and [src] falls to pieces!</span>")
|
||||
deconstruct()
|
||||
|
||||
@@ -573,7 +573,7 @@
|
||||
else
|
||||
if(!user.drop_item())
|
||||
return
|
||||
toner = 40
|
||||
toner = tonermax
|
||||
qdel(W)
|
||||
user << "<span class='notice'>You fill the toner level of [src] to its max capacity.</span>"
|
||||
|
||||
|
||||
@@ -99,6 +99,9 @@
|
||||
var/obj/item/weapon/melee/baton/B = I
|
||||
if(B.bcell)
|
||||
B.bcell.charge = B.bcell.maxcharge
|
||||
|
||||
R.toner = R.tonermax
|
||||
|
||||
return
|
||||
|
||||
/obj/item/weapon/robot_module/proc/rebuild()//Rebuilds the list so it's possible to add/remove items from the module
|
||||
|
||||
@@ -0,0 +1,784 @@
|
||||
//Defines for bots are now found in code\__DEFINES\bots.dm
|
||||
|
||||
// AI (i.e. game AI, not the AI player) controlled bots
|
||||
/mob/living/simple_animal/bot
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
layer = MOB_LAYER
|
||||
luminosity = 3
|
||||
stop_automated_movement = 1
|
||||
wander = 0
|
||||
healable = 0
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
has_unlimited_silicon_privilege = 1
|
||||
sentience_type = SENTIENCE_ARTIFICIAL
|
||||
status_flags = NONE //no default canpush
|
||||
|
||||
var/obj/machinery/bot_core/bot_core = null
|
||||
var/bot_core_type = /obj/machinery/bot_core
|
||||
var/list/users = list() //for dialog updates
|
||||
var/window_id = "bot_control"
|
||||
var/window_name = "Protobot 1.0" //Popup title
|
||||
var/window_width = 0 //0 for default size
|
||||
var/window_height = 0
|
||||
|
||||
var/list/player_access = list() //Additonal access the bots gets when player controlled
|
||||
var/emagged = 0
|
||||
var/list/prev_access = list()
|
||||
var/on = 1
|
||||
var/open = 0//Maint panel
|
||||
var/locked = 1
|
||||
var/hacked = 0 //Used to differentiate between being hacked by silicons and emagged by humans.
|
||||
var/text_hack = "" //Custom text returned to a silicon upon hacking a bot.
|
||||
var/text_dehack = "" //Text shown when resetting a bots hacked status to normal.
|
||||
var/text_dehack_fail = "" //Shown when a silicon tries to reset a bot emagged with the emag item, which cannot be reset.
|
||||
var/declare_message = "" //What the bot will display to the HUD user.
|
||||
var/frustration = 0 //Used by some bots for tracking failures to reach their target.
|
||||
var/base_speed = 2 //The speed at which the bot moves, or the number of times it moves per process() tick.
|
||||
var/turf/ai_waypoint //The end point of a bot's path, or the target location.
|
||||
var/list/path = list() //List of turfs through which a bot 'steps' to reach the waypoint.
|
||||
var/pathset = 0
|
||||
var/list/ignore_list = list() //List of unreachable targets for an ignore-list enabled bot to ignore.
|
||||
var/mode = BOT_IDLE //Standardizes the vars that indicate the bot is busy with its function.
|
||||
var/tries = 0 //Number of times the bot tried and failed to move.
|
||||
var/remote_disabled = 0 //If enabled, the AI cannot *Remotely* control a bot. It can still control it through cameras.
|
||||
var/mob/living/silicon/ai/calling_ai //Links a bot to the AI calling it.
|
||||
var/obj/item/device/radio/Radio //The bot's radio, for speaking to people.
|
||||
var/radio_key = null //which channels can the bot listen to
|
||||
var/radio_channel = "Common" //The bot's default radio channel
|
||||
var/auto_patrol = 0// set to make bot automatically patrol
|
||||
var/turf/patrol_target // this is turf to navigate to (location of beacon)
|
||||
var/turf/summon_target // The turf of a user summoning a bot.
|
||||
var/new_destination // pending new destination (waiting for beacon response)
|
||||
var/destination // destination description tag
|
||||
var/next_destination // the next destination in the patrol route
|
||||
|
||||
var/blockcount = 0 //number of times retried a blocked path
|
||||
var/awaiting_beacon = 0 // count of pticks awaiting a beacon response
|
||||
|
||||
var/nearest_beacon // the nearest beacon's tag
|
||||
var/turf/nearest_beacon_loc // the nearest beacon's location
|
||||
|
||||
var/beacon_freq = 1445 // navigation beacon frequency
|
||||
var/model = "" //The type of bot it is.
|
||||
var/bot_type = 0 //The type of bot it is, for radio control.
|
||||
var/list/mode_name = list("In Pursuit","Preparing to Arrest", "Arresting", \
|
||||
"Beginning Patrol", "Patrolling", "Summoned by PDA", \
|
||||
"Cleaning", "Repairing", "Proceeding to work site", "Healing", \
|
||||
"Proceeding to AI waypoint", "Navigating to Delivery Location", "Navigating to Home", \
|
||||
"Waiting for clear path", "Calculating navigation path", "Pinging beacon network", "Unable to reach destination")
|
||||
//This holds text for what the bot is mode doing, reported on the remote bot control interface.
|
||||
|
||||
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD) //Diagnostic HUD views
|
||||
|
||||
/mob/living/simple_animal/bot/proc/get_mode()
|
||||
if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player.
|
||||
return "<b>Sentient</b>"
|
||||
else if(!on)
|
||||
return "<span class='bad'>Inactive</span>"
|
||||
else if(!mode)
|
||||
return "<span class='good'>Idle</span>"
|
||||
else
|
||||
return "<span class='average'>[mode_name[mode]]</span>"
|
||||
|
||||
/mob/living/simple_animal/bot/proc/turn_on()
|
||||
if(stat) return 0
|
||||
on = 1
|
||||
SetLuminosity(initial(luminosity))
|
||||
update_icon()
|
||||
diag_hud_set_botstat()
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/bot/proc/turn_off()
|
||||
on = 0
|
||||
SetLuminosity(0)
|
||||
bot_reset() //Resets an AI's call, should it exist.
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/New()
|
||||
..()
|
||||
access_card = new /obj/item/weapon/card/id(src)
|
||||
//This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first.
|
||||
access_card.access += access_robotics
|
||||
set_custom_texts()
|
||||
Radio = new/obj/item/device/radio(src)
|
||||
if(radio_key)
|
||||
Radio.keyslot = new radio_key
|
||||
Radio.canhear_range = 1 // 0 ?
|
||||
Radio.recalculateChannels()
|
||||
|
||||
bot_core = new bot_core_type(src)
|
||||
|
||||
prepare_huds()
|
||||
var/datum/atom_hud/data/diagnostic/diag_hud = huds[DATA_HUD_DIAGNOSTIC]
|
||||
diag_hud.add_to_hud(src)
|
||||
diag_hud_set_bothealth()
|
||||
diag_hud_set_botstat()
|
||||
diag_hud_set_botmode()
|
||||
|
||||
/mob/living/simple_animal/bot/update_canmove()
|
||||
. = ..()
|
||||
if(!on)
|
||||
. = 0
|
||||
canmove = .
|
||||
|
||||
/mob/living/simple_animal/bot/Destroy()
|
||||
qdel(Radio)
|
||||
qdel(access_card)
|
||||
qdel(bot_core)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/death(gibbed)
|
||||
explode()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/proc/explode()
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/bot/proc/Emag(mob/user) //Master Emag proc. Ensure this is called in your bot before setting unique functions.
|
||||
if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again.
|
||||
locked = 0
|
||||
emagged = 1
|
||||
user << "<span class='notice'>You bypass [src]'s controls.</span>"
|
||||
return
|
||||
if(!locked && open) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging.
|
||||
emagged = 2
|
||||
remote_disabled = 1 //Manually emagging the bot locks out the AI built in panel.
|
||||
locked = 1 //Access denied forever!
|
||||
bot_reset()
|
||||
turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP.
|
||||
src << "<span class='userdanger'>(#$*#$^^( OVERRIDE DETECTED</span>"
|
||||
return
|
||||
else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet.
|
||||
user << "<span class='warning'>You need to open maintenance panel first!</span>"
|
||||
|
||||
/mob/living/simple_animal/bot/examine(mob/user)
|
||||
..()
|
||||
if (health < maxHealth)
|
||||
if (health > maxHealth/3)
|
||||
user << "[src]'s parts look loose."
|
||||
else
|
||||
user << "[src]'s parts look very loose!"
|
||||
else
|
||||
user << "[src] is in pristine condition."
|
||||
|
||||
/mob/living/simple_animal/bot/adjustBruteLoss(amount)
|
||||
if(amount>0 && prob(10))
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
return ..(amount)
|
||||
|
||||
/mob/living/simple_animal/bot/adjustFireLoss(amount)
|
||||
if(amount>0 && prob(10))
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
return ..(amount)
|
||||
|
||||
/mob/living/simple_animal/bot/updatehealth()
|
||||
..()
|
||||
diag_hud_set_bothealth()
|
||||
|
||||
/mob/living/simple_animal/bot/handle_automated_action() //Master process which handles code common across most bots.
|
||||
set background = BACKGROUND_ENABLED
|
||||
diag_hud_set_botmode()
|
||||
|
||||
if(!on || client)
|
||||
return
|
||||
|
||||
switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command.
|
||||
if(BOT_RESPONDING) //Called by the AI.
|
||||
call_mode()
|
||||
return
|
||||
if(BOT_SUMMON) //Called by PDA
|
||||
bot_summon()
|
||||
return
|
||||
return 1 //Successful completion. Used to prevent child process() continuing if this one is ended early.
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/attack_hand(mob/living/carbon/human/M)
|
||||
if(M.a_intent == "help")
|
||||
show_controls(M)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
if(!locked)
|
||||
open = !open
|
||||
user << "<span class='notice'>Maintenance panel is now [open ? "opened" : "closed"].</span>"
|
||||
else
|
||||
user << "<span class='warning'>Maintenance panel is locked.</span>"
|
||||
else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
|
||||
if(bot_core.allowed(user) && !open && !emagged)
|
||||
locked = !locked
|
||||
user << "Controls are now [locked ? "locked." : "unlocked."]"
|
||||
else
|
||||
if(emagged)
|
||||
user << "<span class='warning'>ERROR</span>"
|
||||
if(open)
|
||||
user << "<span class='danger'>Please close the access panel before locking it.</span>"
|
||||
else
|
||||
user << "<span class='danger'>Access denied.</span>"
|
||||
else
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm")
|
||||
if(health >= maxHealth)
|
||||
user << "<span class='warning'>[src] does not need a repair!</span>"
|
||||
return
|
||||
if(!open)
|
||||
user << "<span class='warning'>Unable to repair with the maintenance panel closed!</span>"
|
||||
return
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(WT.remove_fuel(0, user))
|
||||
health = min(maxHealth, health+10)
|
||||
user.visible_message("[user] repairs [src]!","<span class='notice'>You repair [src].</span>")
|
||||
else
|
||||
user << "<span class='warning'>The welder must be on for this task!</span>"
|
||||
else
|
||||
if(W.force) //if force is non-zero
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/emag_act(mob/user)
|
||||
if(emagged < 2)
|
||||
Emag(user)
|
||||
|
||||
/mob/living/simple_animal/bot/bullet_act(obj/item/projectile/Proj)
|
||||
if(Proj && (Proj.damage_type == BRUTE || Proj.damage_type == BURN))
|
||||
if(prob(75) && Proj.damage > 0)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/emp_act(severity)
|
||||
var/was_on = on
|
||||
stat |= EMPED
|
||||
var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( loc )
|
||||
pulse2.icon = 'icons/effects/effects.dmi'
|
||||
pulse2.icon_state = "empdisable"
|
||||
pulse2.name = "emp sparks"
|
||||
pulse2.anchored = 1
|
||||
pulse2.dir = pick(cardinal)
|
||||
|
||||
spawn(10)
|
||||
qdel(pulse2)
|
||||
if (on)
|
||||
turn_off()
|
||||
spawn(severity*300)
|
||||
stat &= ~EMPED
|
||||
if (was_on)
|
||||
turn_on()
|
||||
|
||||
/mob/living/simple_animal/bot/proc/set_custom_texts() //Superclass for setting hack texts. Appears only if a set is not given to a bot locally.
|
||||
text_hack = "You hack [name]."
|
||||
text_dehack = "You reset [name]."
|
||||
text_dehack_fail = "You fail to reset [name]."
|
||||
|
||||
/mob/living/simple_animal/bot/attack_ai(mob/user as mob)
|
||||
show_controls(user)
|
||||
|
||||
/mob/living/simple_animal/bot/proc/speak(message,channel) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio.
|
||||
if((!on) || (!message))
|
||||
return
|
||||
if(channel)
|
||||
if(!Radio.channels[channel]) //Ignore lack of keys
|
||||
Radio.channels[channel] = 1
|
||||
Radio.talk_into(src, message, channel)
|
||||
Radio.channels[channel] = 0
|
||||
else
|
||||
Radio.talk_into(src, message, channel)
|
||||
else
|
||||
say(message)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/say(message)
|
||||
return ..(message, "R")
|
||||
|
||||
/mob/living/simple_animal/bot/get_spans()
|
||||
return ..() | SPAN_ROBOT
|
||||
|
||||
/mob/living/simple_animal/bot/radio(message, message_mode, list/spans)
|
||||
. = ..()
|
||||
if(. != 0)
|
||||
return .
|
||||
|
||||
switch(message_mode)
|
||||
if(MODE_HEADSET)
|
||||
Radio.talk_into(src, message, , spans)
|
||||
return REDUCE_RANGE
|
||||
|
||||
if(MODE_DEPARTMENT)
|
||||
Radio.talk_into(src, message, message_mode, spans)
|
||||
return REDUCE_RANGE
|
||||
|
||||
if(message_mode in radiochannels)
|
||||
Radio.talk_into(src, message, message_mode, spans)
|
||||
return REDUCE_RANGE
|
||||
return 0
|
||||
|
||||
//Generalized behavior code, override where needed!
|
||||
|
||||
/*
|
||||
scan() will search for a given type (such as turfs, human mobs, or objects) in the bot's view range, and return a single result.
|
||||
Arguments: The object type to be searched (such as "/mob/living/carbon/human"), the old scan result to be ignored, if one exists,
|
||||
and the view range, which defaults to 7 (full screen) if an override is not passed.
|
||||
If the bot maintains an ignore list, it is also checked here.
|
||||
|
||||
Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1)
|
||||
The proc would return a human next to the bot to be set to the patient var.
|
||||
Pass the desired type path itself, declaring a temporary var beforehand is not required.
|
||||
*/
|
||||
/mob/living/simple_animal/bot/proc/scan(scan_type, old_target, scan_range = DEFAULT_SCAN_RANGE)
|
||||
var/final_result
|
||||
for (var/scan in view (scan_range, src) ) //Search for something in range!
|
||||
if(!istype(scan, scan_type)) //Check that the thing we found is the type we want!
|
||||
continue //If not, keep searching!
|
||||
if( (scan in ignore_list) || (scan == old_target) ) //Filter for blacklisted elements, usually unreachable or previously processed oness
|
||||
continue
|
||||
var/scan_result = process_scan(scan) //Some bots may require additional processing when a result is selected.
|
||||
if( scan_result )
|
||||
final_result = scan_result
|
||||
else
|
||||
continue //The current element failed assessment, move on to the next.
|
||||
return final_result
|
||||
|
||||
//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default.
|
||||
/mob/living/simple_animal/bot/proc/process_scan(scan_target)
|
||||
return scan_target
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/proc/add_to_ignore(subject)
|
||||
if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot.
|
||||
ignore_list |= subject
|
||||
else if (ignore_list.len >= subject) //If the list is full, insert newest, delete oldest.
|
||||
ignore_list -= ignore_list[1]
|
||||
ignore_list |= subject
|
||||
|
||||
/*
|
||||
Movement proc for stepping a bot through a path generated through A-star.
|
||||
Pass a positive integer as an argument to override a bot's default speed.
|
||||
*/
|
||||
/mob/living/simple_animal/bot/proc/bot_move(dest, move_speed)
|
||||
|
||||
if(!dest || !path || path.len == 0) //A-star failed or a path/destination was not set.
|
||||
path = list()
|
||||
return 0
|
||||
dest = get_turf(dest) //We must always compare turfs, so get the turf of the dest var if dest was originally something else.
|
||||
var/turf/last_node = get_turf(path[path.len]) //This is the turf at the end of the path, it should be equal to dest.
|
||||
if(get_turf(src) == dest) //We have arrived, no need to move again.
|
||||
return 1
|
||||
else if (dest != last_node) //The path should lead us to our given destination. If this is not true, we must stop.
|
||||
path = list()
|
||||
return 0
|
||||
var/step_count = move_speed ? move_speed : base_speed //If a value is passed into move_speed, use that instead of the default speed var.
|
||||
|
||||
if(step_count >= 1 && tries < 4)
|
||||
for(var/step_number = 0, step_number < step_count,step_number++)
|
||||
spawn(BOT_STEP_DELAY*step_number)
|
||||
bot_step(dest)
|
||||
else
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/proc/bot_step(dest) //Step,increase tries if failed
|
||||
if(!path)
|
||||
return 0
|
||||
if(path.len > 1)
|
||||
step_towards(src, path[1])
|
||||
if(get_turf(src) == path[1]) //Successful move
|
||||
path -= path[1]
|
||||
else
|
||||
tries++
|
||||
return 0
|
||||
else if(path.len == 1)
|
||||
step_to(src, dest)
|
||||
path = list()
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/proc/check_bot_access()
|
||||
if(mode != BOT_SUMMON && mode != BOT_RESPONDING)
|
||||
access_card.access = prev_access
|
||||
|
||||
/mob/living/simple_animal/bot/proc/call_bot(caller, turf/waypoint, message=TRUE)
|
||||
bot_reset() //Reset a bot before setting it to call mode.
|
||||
var/area/end_area = get_area(waypoint)
|
||||
|
||||
//For giving the bot temporary all-access.
|
||||
var/obj/item/weapon/card/id/all_access = new /obj/item/weapon/card/id
|
||||
var/datum/job/captain/All = new/datum/job/captain
|
||||
all_access.access = All.get_access()
|
||||
|
||||
path = get_path_to(src, waypoint, src, /turf/proc/Distance_cardinal, 0, 200, id=all_access)
|
||||
calling_ai = caller //Link the AI to the bot!
|
||||
ai_waypoint = waypoint
|
||||
|
||||
if(path && path.len) //Ensures that a valid path is calculated!
|
||||
if(!on)
|
||||
turn_on() //Saves the AI the hassle of having to activate a bot manually.
|
||||
access_card = all_access //Give the bot all-access while under the AI's command.
|
||||
if(message)
|
||||
calling_ai << "<span class='notice'>\icon[src] [name] called to [end_area.name]. [path.len-1] meters to destination.</span>"
|
||||
pathset = 1
|
||||
mode = BOT_RESPONDING
|
||||
tries = 0
|
||||
else
|
||||
if(message)
|
||||
calling_ai << "<span class='danger'>Failed to calculate a valid route. Ensure destination is clear of obstructions and within range.</span>"
|
||||
calling_ai = null
|
||||
path = list()
|
||||
|
||||
/mob/living/simple_animal/bot/proc/call_mode() //Handles preparing a bot for a call, as well as calling the move proc.
|
||||
//Handles the bot's movement during a call.
|
||||
var/success = bot_move(ai_waypoint, 3)
|
||||
if (!success)
|
||||
if(calling_ai)
|
||||
calling_ai << "\icon[src] [get_turf(src) == ai_waypoint ? "<span class='notice'>[src] successfully arrived to waypoint.</span>" : "<span class='danger'>[src] failed to reach waypoint.</span>"]"
|
||||
calling_ai = null
|
||||
bot_reset()
|
||||
|
||||
/mob/living/simple_animal/bot/proc/bot_reset()
|
||||
if(calling_ai) //Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot.
|
||||
calling_ai << "<span class='danger'>Call command to a bot has been reset.</span>"
|
||||
calling_ai = null
|
||||
path = list()
|
||||
summon_target = null
|
||||
pathset = 0
|
||||
access_card.access = prev_access
|
||||
tries = 0
|
||||
mode = BOT_IDLE
|
||||
diag_hud_set_botstat()
|
||||
diag_hud_set_botmode()
|
||||
|
||||
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//Patrol and summon code!
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
/mob/living/simple_animal/bot/proc/bot_patrol()
|
||||
patrol_step()
|
||||
spawn(5)
|
||||
if(mode == BOT_PATROL)
|
||||
patrol_step()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/proc/start_patrol()
|
||||
|
||||
if(tries >= 4) //Bot is trapped, so stop trying to patrol.
|
||||
auto_patrol = 0
|
||||
tries = 0
|
||||
speak("Unable to start patrol.")
|
||||
|
||||
return
|
||||
|
||||
if(!auto_patrol) //A bot not set to patrol should not be patrolling.
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
|
||||
if(patrol_target) // has patrol target
|
||||
spawn(0)
|
||||
calc_path() // Find a route to it
|
||||
if(path.len == 0)
|
||||
patrol_target = null
|
||||
return
|
||||
mode = BOT_PATROL
|
||||
else // no patrol target, so need a new one
|
||||
speak("Engaging patrol mode.")
|
||||
find_patrol_target()
|
||||
tries++
|
||||
return
|
||||
|
||||
// perform a single patrol step
|
||||
|
||||
/mob/living/simple_animal/bot/proc/patrol_step()
|
||||
|
||||
if(loc == patrol_target) // reached target
|
||||
//Find the next beacon matching the target.
|
||||
if(!get_next_patrol_target())
|
||||
find_patrol_target() //If it fails, look for the nearest one instead.
|
||||
return
|
||||
|
||||
else if(path.len > 0 && patrol_target) // valid path
|
||||
var/turf/next = path[1]
|
||||
if(next == loc)
|
||||
path -= next
|
||||
return
|
||||
|
||||
|
||||
var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move
|
||||
if(moved) // successful move
|
||||
blockcount = 0
|
||||
|
||||
else // failed to move
|
||||
blockcount++
|
||||
|
||||
if(blockcount > 5) // attempt 5 times before recomputing
|
||||
// find new path excluding blocked turf
|
||||
|
||||
spawn(2)
|
||||
calc_path(next)
|
||||
if(path.len == 0)
|
||||
find_patrol_target() //Start looking for the next nearest beacon
|
||||
tries++
|
||||
else
|
||||
blockcount = 0
|
||||
tries = 0
|
||||
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
else // no path, so calculate new one
|
||||
mode = BOT_START_PATROL
|
||||
|
||||
return
|
||||
|
||||
// finds the nearest beacon to self
|
||||
/mob/living/simple_animal/bot/proc/find_patrol_target()
|
||||
nearest_beacon = null
|
||||
new_destination = null
|
||||
find_nearest_beacon()
|
||||
if(nearest_beacon)
|
||||
patrol_target = nearest_beacon_loc
|
||||
destination = next_destination
|
||||
else
|
||||
auto_patrol = 0
|
||||
mode = BOT_IDLE
|
||||
speak("Disengaging patrol mode.")
|
||||
|
||||
/mob/living/simple_animal/bot/proc/get_next_patrol_target()
|
||||
// search the beacon list for the next target in the list.
|
||||
for(var/obj/machinery/navbeacon/NB in navbeacons)
|
||||
if(NB.location == next_destination) //Does the Beacon location text match the destination?
|
||||
destination = new_destination //We now know the name of where we want to go.
|
||||
patrol_target = NB.loc //Get its location and set it as the target.
|
||||
next_destination = NB.codes["next_patrol"] //Also get the name of the next beacon in line.
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/bot/proc/find_nearest_beacon()
|
||||
for(var/obj/machinery/navbeacon/NB in navbeacons)
|
||||
var/dist = get_dist(src, NB)
|
||||
if(nearest_beacon) //Loop though the beacon net to find the true closest beacon.
|
||||
//Ignore the beacon if were are located on it.
|
||||
if(dist>1 && dist<get_dist(src,nearest_beacon_loc))
|
||||
nearest_beacon = NB.location
|
||||
nearest_beacon_loc = NB.loc
|
||||
next_destination = NB.codes["next_patrol"]
|
||||
else
|
||||
continue
|
||||
else if(dist > 1) //Begin the search, save this one for comparison on the next loop.
|
||||
nearest_beacon = NB.location
|
||||
nearest_beacon_loc = NB.loc
|
||||
patrol_target = nearest_beacon_loc
|
||||
destination = nearest_beacon
|
||||
|
||||
//PDA control. Some bots, especially MULEs, may have more parameters.
|
||||
/mob/living/simple_animal/bot/proc/bot_control(command, mob/user, turf/user_turf, list/user_access = list())
|
||||
if(!on || emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands.
|
||||
return 1 //ACCESS DENIED
|
||||
if(client)
|
||||
bot_control_message(command,user,user_turf,user_access)
|
||||
// process control input
|
||||
switch(command)
|
||||
if("patroloff")
|
||||
bot_reset() //HOLD IT!!
|
||||
auto_patrol = 0
|
||||
return
|
||||
|
||||
if("patrolon")
|
||||
auto_patrol = 1
|
||||
return
|
||||
|
||||
if("summon")
|
||||
bot_reset()
|
||||
summon_target = user_turf
|
||||
if(user_access.len != 0)
|
||||
access_card.access = user_access + prev_access //Adds the user's access, if any.
|
||||
mode = BOT_SUMMON
|
||||
speak("Responding.", radio_channel)
|
||||
calc_summon_path()
|
||||
return
|
||||
return
|
||||
|
||||
//
|
||||
/mob/living/simple_animal/bot/proc/bot_control_message(command,user,user_turf,user_access)
|
||||
switch(command)
|
||||
if("patroloff")
|
||||
src << "<span class='warning big'>STOP PATROL</span>"
|
||||
if("patrolon")
|
||||
src << "<span class='warning big'>START PATROL</span>"
|
||||
if("summon")
|
||||
var/area/a = get_area(user_turf)
|
||||
src << "<span class='warning big'>PRIORITY ALERT:[user] in [a.name]!</span>"
|
||||
if("stop")
|
||||
src << "<span class='warning big'>STOP!</span>"
|
||||
|
||||
if("go")
|
||||
src << "<span class='warning big'>GO!</span>"
|
||||
|
||||
if("home")
|
||||
src << "<span class='warning big'>RETURN HOME!</span>"
|
||||
else
|
||||
src << "<span class='warning'>Unidentified control sequence recieved:[command]</span>"
|
||||
|
||||
/mob/living/simple_animal/bot/proc/bot_summon()
|
||||
// summoned to PDA
|
||||
summon_step()
|
||||
return
|
||||
|
||||
// calculates a path to the current destination
|
||||
// given an optional turf to avoid
|
||||
/mob/living/simple_animal/bot/proc/calc_path(turf/avoid)
|
||||
check_bot_access()
|
||||
path = get_path_to(loc, patrol_target, src, /turf/proc/Distance_cardinal, 0, 120, id=access_card, exclude=avoid)
|
||||
|
||||
/mob/living/simple_animal/bot/proc/calc_summon_path(turf/avoid)
|
||||
check_bot_access()
|
||||
spawn()
|
||||
path = get_path_to(loc, summon_target, src, /turf/proc/Distance_cardinal, 0, 150, id=access_card, exclude=avoid)
|
||||
if(!path.len || tries >= 5) //Cannot reach target. Give up and announce the issue.
|
||||
speak("Summon command failed, destination unreachable.",radio_channel)
|
||||
bot_reset()
|
||||
|
||||
/mob/living/simple_animal/bot/proc/summon_step()
|
||||
|
||||
if(loc == summon_target) // Arrived to summon location.
|
||||
bot_reset()
|
||||
return
|
||||
|
||||
else if(path.len > 0 && summon_target) //Proper path acquired!
|
||||
var/turf/next = path[1]
|
||||
if(next == loc)
|
||||
path -= next
|
||||
return
|
||||
|
||||
var/moved = bot_move(summon_target, 3) // Move attempt
|
||||
if(moved)
|
||||
blockcount = 0
|
||||
|
||||
else // failed to move
|
||||
blockcount++
|
||||
|
||||
if(blockcount > 5) // attempt 5 times before recomputing
|
||||
// find new path excluding blocked turf
|
||||
spawn(2)
|
||||
calc_summon_path(next)
|
||||
tries++
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
else // no path, so calculate new one
|
||||
calc_summon_path()
|
||||
|
||||
return
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/Bump(M as mob|obj) //Leave no door unopened!
|
||||
. = ..()
|
||||
if((istype(M, /obj/machinery/door/airlock) || istype(M, /obj/machinery/door/window)) && (!isnull(access_card)))
|
||||
var/obj/machinery/door/D = M
|
||||
if(D.check_access(access_card))
|
||||
D.open()
|
||||
frustration = 0
|
||||
|
||||
/mob/living/simple_animal/bot/proc/show_controls(mob/M)
|
||||
users |= M
|
||||
var/dat = ""
|
||||
dat = get_controls(M)
|
||||
var/datum/browser/popup = new(M,window_id,window_name,350,600)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
onclose(M,window_id,ref=src)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/proc/update_controls()
|
||||
for(var/mob/M in users)
|
||||
show_controls(M)
|
||||
|
||||
/mob/living/simple_animal/bot/proc/get_controls(mob/M)
|
||||
return "PROTOBOT - NOT FOR USE"
|
||||
|
||||
/mob/living/simple_animal/bot/Topic(href, href_list)
|
||||
//No ..() to prevent strip panel showing up - Todo: make that saner
|
||||
if(topic_denied(usr))
|
||||
usr << "<span class='warning'>[src]'s interface is not responding!</span>"
|
||||
return 1
|
||||
add_fingerprint(usr)
|
||||
if(href_list["close"])// HUE HUE
|
||||
if(usr in users)
|
||||
users.Remove(usr)
|
||||
return 1
|
||||
if((href_list["power"]) && (bot_core.allowed(usr) || !locked))
|
||||
if (on)
|
||||
turn_off()
|
||||
else
|
||||
turn_on()
|
||||
|
||||
switch(href_list["operation"])
|
||||
if("patrol")
|
||||
auto_patrol = !auto_patrol
|
||||
bot_reset()
|
||||
if("remote")
|
||||
remote_disabled = !remote_disabled
|
||||
if("hack")
|
||||
if(emagged != 2)
|
||||
emagged = 2
|
||||
hacked = 1
|
||||
locked = 1
|
||||
usr << "<span class='warning'>[text_hack]</span>"
|
||||
bot_reset()
|
||||
else if(!hacked)
|
||||
usr << "<span class='boldannounce'>[text_dehack_fail]</span>"
|
||||
else
|
||||
emagged = 0
|
||||
hacked = 0
|
||||
usr << "<span class='notice'>[text_dehack]</span>"
|
||||
bot_reset()
|
||||
update_controls()
|
||||
|
||||
/mob/living/simple_animal/bot/proc/update_icon()
|
||||
icon_state = "[initial(icon_state)][on]"
|
||||
|
||||
// Machinery to simplify topic and access calls
|
||||
/obj/machinery/bot_core
|
||||
use_power = 0
|
||||
var/mob/living/simple_animal/bot/owner = null
|
||||
|
||||
/obj/machinery/bot_core/New(loc)
|
||||
..()
|
||||
owner = loc
|
||||
if(!istype(owner))
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired.
|
||||
// 0 for access, 1 for denied.
|
||||
if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it.
|
||||
if(!hacked) //Manually emagged by a human - access denied to all.
|
||||
return 1
|
||||
else if(!issilicon(user) || IsAdminGhost(user)) //Bot is hacked, so only silicons and admins are allowed access.
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/bot/proc/hack(mob/user)
|
||||
var/hack
|
||||
if(issilicon(user) || IsAdminGhost(user)) //Allows silicons or admins to toggle the emag status of a bot.
|
||||
hack += "[emagged == 2 ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]<BR>"
|
||||
hack += "Harm Prevention Safety System: <A href='?src=\ref[src];operation=hack'>[emagged ? "<span class='bad'>DANGER</span>" : "Engaged"]</A><BR>"
|
||||
else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control.
|
||||
hack += "Remote network control radio: <A href='?src=\ref[src];operation=remote'>[remote_disabled ? "Disconnected" : "Connected"]</A><BR><BR>"
|
||||
return hack
|
||||
|
||||
/mob/living/simple_animal/bot/Login()
|
||||
. = ..()
|
||||
access_card.access += player_access
|
||||
diag_hud_set_botmode()
|
||||
|
||||
/mob/living/simple_animal/bot/Logout()
|
||||
. = ..()
|
||||
bot_reset()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user