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:
Jordie0608
2015-12-11 15:59:46 +11:00
675 changed files with 55776 additions and 34740 deletions
+4
View File
@@ -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))
+4 -25
View File
@@ -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)
+2 -16
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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)
-276
View File
@@ -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")
+1 -1
View File
@@ -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
+8 -46
View File
@@ -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"])
+1 -1
View File
@@ -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)
+15
View File
@@ -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()
+2 -25
View File
@@ -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 += "&nbsp;&nbsp;<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]"
+2 -4
View File
@@ -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!
+32
View File
@@ -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]]")
+3 -3
View File
@@ -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"]."
+6 -6
View File
@@ -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.
+38 -3
View File
@@ -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///////////
+262
View File
@@ -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)
+1
View File
@@ -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.
+13 -61
View File
@@ -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)
+3 -5
View File
@@ -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>"
+1 -1
View File
@@ -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)
-2
View File
@@ -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!
+25 -20
View File
@@ -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"
+29
View File
@@ -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()
+8
View File
@@ -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!"
+25 -29
View File
@@ -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
*/
+28 -6
View File
@@ -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"
+34 -10
View File
@@ -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"
+66 -4
View File
@@ -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\"."
+4 -5
View File
@@ -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"
+17 -5
View File
@@ -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,
+1 -1
View File
@@ -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()
+10 -3
View File
@@ -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
+1 -1
View File
@@ -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()
+55 -64
View File
@@ -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
+1 -1
View File
@@ -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(
+3 -2
View File
@@ -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)
+10
View File
@@ -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.
+5 -4
View File
@@ -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!"
-68
View File
@@ -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)
+2 -2
View File
@@ -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
-44
View File
@@ -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
+4 -5
View File
@@ -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)
+22 -10
View File
@@ -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
+22 -1
View File
@@ -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
+2 -2
View File
@@ -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
+19
View File
@@ -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"
+12
View File
@@ -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].")
+9
View File
@@ -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
+67
View File
@@ -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
+2 -2
View File
@@ -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)
+3 -3
View File
@@ -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))]'>&lt;&lt;&lt;&lt;</A></td> <td></td> <td></td> <td><span style='text-align:right'><A href='?src=\ref[src];page=[(min(1,page+1))]'>&gt;&gt;&gt;&gt;</A></span></td></tr>"
dat += "<tr><td><A href='?src=\ref[src];page=[(max(1,page-1))]'>&lt;&lt;&lt;&lt;</A></td> <td></td> <td></td> <td><span style='text-align:right'><A href='?src=\ref[src];page=[(min(libcomp_menu.len,page+1))]'>&gt;&gt;&gt;&gt;</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"])
+83 -63
View File
@@ -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.
+5 -4
View File
@@ -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)
+63 -7
View File
@@ -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)
+9 -1
View File
@@ -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."
+84 -31
View File
@@ -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
+6 -6
View File
@@ -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
+5
View File
@@ -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")
+4
View File
@@ -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)
+11 -4
View File
@@ -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
+1 -1
View File
@@ -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
+1
View File
@@ -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)
+1 -1
View File
@@ -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>"
-1
View File
@@ -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
+50 -40
View File
@@ -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)
+10 -13
View File
@@ -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)
*/
*/
+7 -2
View File
@@ -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