Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into upstream-merge-26908
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
icon_state = "sleeper"
|
||||
state_open = TRUE
|
||||
anchored = TRUE
|
||||
occupant_typecache = list(/mob/living/carbon/human) // turned into typecache in Initialize
|
||||
var/you_die_in_the_game_you_die_for_real = FALSE
|
||||
var/datum/effect_system/spark_spread/sparks
|
||||
var/mob/living/carbon/human/virtual_reality/vr_human
|
||||
@@ -92,11 +93,12 @@
|
||||
return
|
||||
switch(action)
|
||||
if("vr_connect")
|
||||
if(ishuman(occupant) && occupant.mind)
|
||||
var/mob/living/carbon/human/human_occupant = occupant
|
||||
if(human_occupant && human_occupant.mind)
|
||||
to_chat(occupant, "<span class='warning'>Transfering to virtual reality...</span>")
|
||||
if(vr_human)
|
||||
vr_human.revert_to_reality(FALSE, FALSE)
|
||||
occupant.mind.transfer_to(vr_human)
|
||||
human_occupant.mind.transfer_to(vr_human)
|
||||
vr_human.real_me = occupant
|
||||
to_chat(vr_human, "<span class='notice'>Transfer successful! you are now playing as [vr_human] in VR!</span>")
|
||||
SStgui.close_user_uis(vr_human, src)
|
||||
|
||||
@@ -71,16 +71,13 @@
|
||||
computerid = bancid
|
||||
ip = banip
|
||||
|
||||
var/datum/DBQuery/query_add_ban_get_id = SSdbcore.NewQuery("SELECT id FROM [format_table_name("player")] WHERE ckey = '[ckey]'")
|
||||
if(!query_add_ban_get_id.warn_execute())
|
||||
var/datum/DBQuery/query_add_ban_get_ckey = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ckey = '[ckey]'")
|
||||
if(!query_add_ban_get_ckey.warn_execute())
|
||||
return
|
||||
var/validckey = 0
|
||||
if(query_add_ban_get_id.NextRow())
|
||||
validckey = 1
|
||||
if(!validckey)
|
||||
if(!query_add_ban_get_ckey.NextRow())
|
||||
if(!banned_mob || (banned_mob && !IsGuestKey(banned_mob.key)))
|
||||
message_admins("<font color='red'>[key_name_admin(usr)] attempted to ban [ckey], but [ckey] has not been seen yet. Please only ban actual players.</font>",1)
|
||||
return
|
||||
if(alert(usr, "[ckey] has not been seen before, are you sure you want to create a ban for them?", "Unknown ckey", "Yes", "No", "Cancel") != "Yes")
|
||||
return
|
||||
|
||||
var/a_ckey
|
||||
var/a_computerid
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
if(!SSdbcore.Connect())
|
||||
log_world("Ban database connection failure. Key [ckeytext] not checked")
|
||||
GLOB.diary << "Ban database connection failure. Key [ckeytext] not checked"
|
||||
GLOB.world_game_log << "Ban database connection failure. Key [ckeytext] not checked"
|
||||
return
|
||||
|
||||
var/ipquery = ""
|
||||
|
||||
@@ -37,6 +37,11 @@
|
||||
else
|
||||
body += " \[<A href='?_src_=holder;revive=\ref[M]'>Heal</A>\] "
|
||||
|
||||
if(M.client)
|
||||
body += "<br>\[<b>First Seen:</b> [M.client.player_join_date]\]\[<b>Byond account registered on:</b> [M.client.account_join_date]\]"
|
||||
|
||||
|
||||
|
||||
body += "<br><br>\[ "
|
||||
body += "<a href='?_src_=vars;Vars=\ref[M]'>VV</a> - "
|
||||
body += "<a href='?_src_=holder;traitor=\ref[M]'>TP</a> - "
|
||||
@@ -804,7 +809,7 @@
|
||||
return 1
|
||||
|
||||
/client/proc/adminGreet(logout)
|
||||
if(SSticker.HasRoundStarted())
|
||||
if(SSticker.HasRoundStarted())
|
||||
var/string
|
||||
if(logout && config && config.announce_admin_logout)
|
||||
string = pick(
|
||||
|
||||
@@ -1,50 +1,21 @@
|
||||
//By Carnwennan
|
||||
|
||||
//This system was made as an alternative to all the in-game lists and variables used to log stuff in-game.
|
||||
//lists and variables are great. However, they have several major flaws:
|
||||
//Firstly, they use memory. TGstation has one of the highest memory usage of all the ss13 branches.
|
||||
//Secondly, they are usually stored in an object. This means that they aren't centralised. It also means that
|
||||
//the data is lost when the object is deleted! This is especially annoying for things like the singulo engine!
|
||||
#define INVESTIGATE_DIR "data/investigate/"
|
||||
|
||||
//SYSTEM
|
||||
/proc/investigate_subject2file(subject)
|
||||
return file("[INVESTIGATE_DIR][subject].html")
|
||||
|
||||
/proc/investigate_reset()
|
||||
if(fdel(INVESTIGATE_DIR))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/atom/proc/investigate_log(message, subject)
|
||||
if(!message)
|
||||
return
|
||||
var/F = investigate_subject2file(subject)
|
||||
if(!F)
|
||||
atom/proc/investigate_log(message, subject)
|
||||
if(!message || !subject)
|
||||
return
|
||||
var/F = file("[GLOB.log_directory]/[subject].html")
|
||||
F << "<small>[time_stamp()] \ref[src] ([x],[y],[z])</small> || [src] [message]<br>"
|
||||
|
||||
//ADMINVERBS
|
||||
/client/proc/investigate_show( subject in list("hrefs","notes, memos, watchlist","singulo","wires","telesci", "gravity", "records", "cargo", "supermatter", "atmos", "experimentor", "botany") )
|
||||
|
||||
/client/proc/investigate_show( subject in list("hrefs","notes, memos, watchlist","singulo","wires","telesci", "gravity", "records", "cargo", "supermatter", "atmos", "experimentor", "botany") )
|
||||
set name = "Investigate"
|
||||
set category = "Admin"
|
||||
if(!holder)
|
||||
return
|
||||
switch(subject)
|
||||
if("singulo", "wires", "telesci", "gravity", "records", "cargo", "supermatter", "atmos", "botany") //general one-round-only stuff
|
||||
var/F = investigate_subject2file(subject)
|
||||
if(!F)
|
||||
to_chat(src, "<font color='red'>Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed.</font>")
|
||||
return
|
||||
src << browse(F,"window=investigate[subject];size=800x300")
|
||||
if("hrefs") //persistent logs and stuff
|
||||
if(GLOB.href_logfile)
|
||||
src << browse(GLOB.href_logfile,"window=investigate[subject];size=800x300")
|
||||
else if(!config.log_hrefs)
|
||||
to_chat(src, "<span class='danger'>Href logging is off and no logfile was found.</span>")
|
||||
return
|
||||
else
|
||||
to_chat(src, "<span class='danger'>No href logfile was found.</span>")
|
||||
return
|
||||
if("notes, memos, watchlist")
|
||||
browse_messages()
|
||||
else
|
||||
var/F = file("[GLOB.log_directory]/[subject].html")
|
||||
if(!fexists(F))
|
||||
to_chat(src, "<span class='danger'>No [subject] logfile was found.</span>")
|
||||
return
|
||||
src << browse(F,"window=investigate[subject];size=800x300")
|
||||
@@ -127,7 +127,7 @@ GLOBAL_PROTECT(admin_ranks)
|
||||
else
|
||||
if(!SSdbcore.Connect())
|
||||
log_world("Failed to connect to database in load_admin_ranks(). Reverting to legacy system.")
|
||||
GLOB.diary << "Failed to connect to database in load_admin_ranks(). Reverting to legacy system."
|
||||
GLOB.world_game_log << "Failed to connect to database in load_admin_ranks(). Reverting to legacy system."
|
||||
config.admin_legacy_system = 1
|
||||
load_admin_ranks()
|
||||
return
|
||||
@@ -202,7 +202,7 @@ GLOBAL_PROTECT(admin_ranks)
|
||||
else
|
||||
if(!SSdbcore.Connect())
|
||||
log_world("Failed to connect to database in load_admins(). Reverting to legacy system.")
|
||||
GLOB.diary << "Failed to connect to database in load_admins(). Reverting to legacy system."
|
||||
GLOB.world_game_log << "Failed to connect to database in load_admins(). Reverting to legacy system."
|
||||
config.admin_legacy_system = 1
|
||||
load_admins()
|
||||
return
|
||||
|
||||
@@ -4,18 +4,12 @@ GLOBAL_PROTECT(admin_verbs_default)
|
||||
GLOBAL_LIST_INIT(admin_verbs_default, world.AVerbsDefault())
|
||||
/world/proc/AVerbsDefault()
|
||||
return list(
|
||||
/client/proc/toggleadminhelpsound, /*toggles whether we hear a sound when adminhelps/PMs are used*/
|
||||
/client/proc/toggleannouncelogin, /*toggles if an admin's login is announced during a round*/
|
||||
/client/proc/deadmin, /*destroys our own admin datum so we can play as a regular player*/
|
||||
/client/proc/cmd_admin_say, /*admin-only ooc chat*/
|
||||
/client/proc/hide_verbs, /*hides all our adminverbs*/
|
||||
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
|
||||
/client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/
|
||||
/client/proc/deadchat, /*toggles deadchat on/off*/
|
||||
/client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/
|
||||
/client/proc/toggleprayers, /*toggles prayers on/off*/
|
||||
/client/verb/toggleprayersounds, /*Toggles prayer sounds (HALLELUJAH!)*/
|
||||
/client/proc/toggle_hear_radio, /*toggles whether we hear the radio*/
|
||||
/client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/
|
||||
/client/proc/secrets,
|
||||
/client/proc/restart_controller,
|
||||
@@ -32,7 +26,6 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
|
||||
/world/proc/AVerbsAdmin()
|
||||
return list(
|
||||
/client/proc/player_panel_new, /*shows an interface for all players, with links to various panels*/
|
||||
/client/proc/invisimin, /*allows our mob to go invisible/visible*/
|
||||
// /datum/admins/proc/show_traitor_panel, /*interface which shows a mob's mind*/ -Removed due to rare practical use. Moved to debug verbs ~Errorage
|
||||
/datum/admins/proc/show_player_panel, /*shows an interface for individual players, with various links (links require additional flags*/
|
||||
@@ -46,16 +39,14 @@ GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
|
||||
/datum/admins/proc/set_admin_notice,/*announcement all clients see when joining the server.*/
|
||||
/client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/
|
||||
/client/proc/toggle_view_range, /*changes how far we can see*/
|
||||
/datum/admins/proc/view_txt_log, /*shows the server log (diary) for today*/
|
||||
/datum/admins/proc/view_txt_log, /*shows the server log (world_game_log) for today*/
|
||||
/datum/admins/proc/view_atk_log, /*shows the server combat-log, doesn't do anything presently*/
|
||||
/client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/
|
||||
/client/proc/check_antagonists, /*shows all antags*/
|
||||
/datum/admins/proc/access_news_network, /*allows access of newscasters*/
|
||||
/client/proc/giveruntimelog, /*allows us to give access to runtime logs to somebody*/
|
||||
/client/proc/getruntimelog, /*allows us to access runtime logs to somebody*/
|
||||
/client/proc/getserverlog, /*allows us to fetch server logs (diary) for other days*/
|
||||
/client/proc/getserverlog, /*allows us to fetch server logs (world_game_log) for other days*/
|
||||
/client/proc/jumptocoord, /*we ghost and jump to a coordinate*/
|
||||
/client/proc/Getmob, /*teleports a mob to our location*/
|
||||
/client/proc/Getkey, /*teleports a mob with a certain ckey to our location*/
|
||||
@@ -116,7 +107,6 @@ GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
|
||||
/datum/admins/proc/end_round,
|
||||
/datum/admins/proc/delay,
|
||||
/datum/admins/proc/toggleaban,
|
||||
/client/proc/toggle_log_hrefs,
|
||||
/client/proc/everyone_random,
|
||||
/datum/admins/proc/toggleAI,
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
@@ -182,9 +172,6 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/client/proc/set_ooc,
|
||||
/client/proc/reset_ooc,
|
||||
/client/proc/deadmin,
|
||||
/client/proc/deadchat,
|
||||
/client/proc/toggleprayers,
|
||||
/client/proc/toggle_hear_radio,
|
||||
/datum/admins/proc/show_traitor_panel,
|
||||
/datum/admins/proc/toggleenter,
|
||||
/datum/admins/proc/toggleguests,
|
||||
@@ -223,7 +210,6 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/datum/admins/proc/restart,
|
||||
/datum/admins/proc/delay,
|
||||
/datum/admins/proc/toggleaban,
|
||||
/client/proc/toggle_log_hrefs,
|
||||
/client/proc/everyone_random,
|
||||
/datum/admins/proc/toggleAI,
|
||||
/client/proc/restart_controller,
|
||||
@@ -398,13 +384,6 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
mob.invisibility = INVISIBILITY_OBSERVER
|
||||
to_chat(mob, "<span class='adminnotice'><b>Invisimin on. You are now as invisible as a ghost.</b></span>")
|
||||
|
||||
/client/proc/player_panel_new()
|
||||
set name = "Player Panel"
|
||||
set category = "Admin"
|
||||
if(holder)
|
||||
holder.player_panel_new()
|
||||
SSblackbox.add_details("admin_verb","Player Panel New") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/check_antagonists()
|
||||
set name = "Check Antagonists"
|
||||
set category = "Admin"
|
||||
@@ -638,19 +617,6 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
togglebuildmode(src.mob)
|
||||
SSblackbox.add_details("admin_verb","Toggle Build Mode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/toggle_log_hrefs()
|
||||
set name = "Toggle href logging"
|
||||
set category = "Server"
|
||||
if(!holder)
|
||||
return
|
||||
if(config)
|
||||
if(config.log_hrefs)
|
||||
config.log_hrefs = 0
|
||||
to_chat(src, "<b>Stopped logging hrefs</b>")
|
||||
else
|
||||
config.log_hrefs = 1
|
||||
to_chat(src, "<b>Started logging hrefs</b>")
|
||||
|
||||
/client/proc/check_ai_laws()
|
||||
set name = "Check AI Laws"
|
||||
set category = "Admin"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/datum/menu/Admin/Generate_list(client/C)
|
||||
if (C.holder)
|
||||
. = ..()
|
||||
|
||||
/datum/menu/Admin/verb/playerpanel()
|
||||
set name = "Player Panel"
|
||||
set desc = "Player Panel"
|
||||
set category = "Admin"
|
||||
usr.client.holder.player_panel_new()
|
||||
SSblackbox.add_details("admin_verb","Player Panel New") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
@@ -71,7 +71,7 @@
|
||||
if("select", "delete", "update")
|
||||
select_types = query_tree[query_tree[1]]
|
||||
|
||||
from_objs = SDQL_from_objs(query_tree["from"])
|
||||
from_objs = world.SDQL_from_objs(query_tree["from"])
|
||||
|
||||
var/list/objs = list()
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
if("call")
|
||||
for(var/datum/d in objs)
|
||||
try
|
||||
SDQL_var(d, query_tree["call"][1], source = d)
|
||||
world.SDQL_var(d, query_tree["call"][1], source = d)
|
||||
catch(var/exception/e)
|
||||
runtime_tracker += SDQL_parse_exception(e)
|
||||
runtimes++
|
||||
@@ -177,15 +177,6 @@
|
||||
returning += "Description: [E.desc]<BR>"
|
||||
return returning
|
||||
|
||||
/proc/SDQL_callproc_global(procname,args_list)
|
||||
set waitfor = FALSE
|
||||
WrapAdminProcCall(GLOBAL_PROC, procname, args_list)
|
||||
|
||||
/proc/SDQL_callproc(thing, procname, args_list)
|
||||
set waitfor = FALSE
|
||||
if(hascall(thing, procname))
|
||||
WrapAdminProcCall(thing, procname, args_list)
|
||||
|
||||
/proc/SDQL_parse(list/query_list)
|
||||
var/datum/SDQL_parser/parser = new()
|
||||
var/list/querys = list()
|
||||
@@ -249,15 +240,10 @@
|
||||
|
||||
|
||||
|
||||
/proc/SDQL_from_objs(list/tree)
|
||||
/world/proc/SDQL_from_objs(list/tree)
|
||||
if("world" in tree)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = "WARNING: Attempt to retrieve world reference made by [usr]!"
|
||||
log_admin(msg)
|
||||
message_admins(msg)
|
||||
return
|
||||
return world
|
||||
return SDQL_expression(world, tree)
|
||||
return src
|
||||
return SDQL_expression(src, tree)
|
||||
|
||||
/proc/SDQL_get_all(type, location)
|
||||
var/list/out = list()
|
||||
@@ -417,12 +403,12 @@
|
||||
result = dummy
|
||||
val += result
|
||||
else
|
||||
val = SDQL_var(object, expression, i, object)
|
||||
val = world.SDQL_var(object, expression, i, object)
|
||||
i = expression.len
|
||||
|
||||
return list("val" = val, "i" = i)
|
||||
|
||||
/proc/SDQL_var(datum/object, list/expression, start = 1, source)
|
||||
/world/proc/SDQL_var(datum/object, list/expression, start = 1, source)
|
||||
var/v
|
||||
var/long = start < expression.len
|
||||
if(object == world && long && expression[start + 1] == ".")
|
||||
@@ -456,11 +442,6 @@
|
||||
else
|
||||
return null
|
||||
if("world")
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = "WARNING: Attempt to retrieve world reference made by [usr]!"
|
||||
log_admin(msg)
|
||||
message_admins(msg)
|
||||
return
|
||||
v = world
|
||||
if("global")
|
||||
v = GLOB
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
if(!recipient)
|
||||
if(holder)
|
||||
to_chat(src, "<font color='red'>Error: Admin-PM: Client not found.</font>")
|
||||
to_chat(src, msg)
|
||||
else
|
||||
current_ticket.MessageNoRecipient(msg)
|
||||
return
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
if (!msg)
|
||||
return
|
||||
var/nicknames = world.file2list("config/admin_nicknames.txt")
|
||||
var/static/nicknames = world.file2list("config/admin_nicknames.txt")
|
||||
|
||||
var/rendered = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <span class='name'>ADMIN([src.holder.fakekey ? pick(nicknames) : src.key])</span> says, <span class='message'>\"[msg]\"</span></span>"
|
||||
|
||||
|
||||
@@ -1,62 +1,3 @@
|
||||
/*
|
||||
HOW DO I LOG RUNTIMES?
|
||||
Firstly, start dreamdeamon if it isn't already running. Then select "world>Log Session" (or press the F3 key)
|
||||
navigate the popup window to the data/logs/runtimes/ folder from where your tgstation .dmb is located.
|
||||
(you may have to make this folder yourself)
|
||||
|
||||
OPTIONAL: you can select the little checkbox down the bottom to make dreamdeamon save the log everytime you
|
||||
start a world. Just remember to repeat these steps with a new name when you update to a new revision!
|
||||
|
||||
Save it with the name of the revision your server uses (e.g. r3459.txt).
|
||||
Game Masters will now be able to grant access any runtime logs you have archived this way!
|
||||
This will allow us to gather information on bugs across multiple servers and make maintaining the TG
|
||||
codebase for the entire /TG/station commuity a TONNE easier :3 Thanks for your help!
|
||||
*/
|
||||
|
||||
|
||||
//This proc allows Game Masters to grant a client access to the .getruntimelog verb
|
||||
//Permissions expire at the end of each round.
|
||||
//Runtimes can be used to meta or spot game-crashing exploits so it's advised to only grant coders that
|
||||
//you trust access. Also, it may be wise to ensure that they are not going to play in the current round.
|
||||
/client/proc/giveruntimelog()
|
||||
set name = ".giveruntimelog"
|
||||
set desc = "Give somebody access to any session logfiles saved to the /log/runtime/ folder."
|
||||
set category = null
|
||||
|
||||
if(!src.holder)
|
||||
to_chat(src, "<font color='red'>Only Admins may use this command.</font>")
|
||||
return
|
||||
|
||||
var/client/target = input(src,"Choose somebody to grant access to the server's runtime logs (permissions expire at the end of each round):","Grant Permissions",null) as null|anything in GLOB.clients
|
||||
if(!istype(target,/client))
|
||||
to_chat(src, "<font color='red'>Error: giveruntimelog(): Client not found.</font>")
|
||||
return
|
||||
|
||||
target.verbs |= /client/proc/getruntimelog
|
||||
to_chat(target, "<font color='red'>You have been granted access to runtime logs. Please use them responsibly or risk being banned.</font>")
|
||||
return
|
||||
|
||||
|
||||
//This proc allows download of runtime logs saved within the data/logs/ folder by dreamdeamon.
|
||||
//It works similarly to show-server-log.
|
||||
/client/proc/getruntimelog()
|
||||
set name = ".getruntimelog"
|
||||
set desc = "Retrieve any session logfiles saved by dreamdeamon."
|
||||
set category = null
|
||||
|
||||
var/path = browse_files("data/logs/runtimes/")
|
||||
if(!path)
|
||||
return
|
||||
|
||||
if(file_spam_check())
|
||||
return
|
||||
|
||||
message_admins("[key_name_admin(src)] accessed file: [path]")
|
||||
src << ftp(file(path))
|
||||
to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.")
|
||||
return
|
||||
|
||||
|
||||
//This proc allows download of past server logs saved within the data/logs/ folder.
|
||||
//It works similarly to show-server-log.
|
||||
/client/proc/getserverlog()
|
||||
@@ -83,10 +24,10 @@
|
||||
/datum/admins/proc/view_txt_log()
|
||||
set category = "Admin"
|
||||
set name = "Show Server Log"
|
||||
set desc = "Shows today's server log."
|
||||
set desc = "Shows server log for this round."
|
||||
|
||||
if(fexists("[GLOB.diary]"))
|
||||
src << ftp(GLOB.diary)
|
||||
if(fexists("[GLOB.world_game_log]"))
|
||||
src << ftp(GLOB.world_game_log)
|
||||
else
|
||||
to_chat(src, "<font color='red'>Server log not found, try using .getserverlog.</font>")
|
||||
return
|
||||
@@ -97,10 +38,10 @@
|
||||
/datum/admins/proc/view_atk_log()
|
||||
set category = "Admin"
|
||||
set name = "Show Server Attack Log"
|
||||
set desc = "Shows today's server attack log."
|
||||
set desc = "Shows server attack log for this round."
|
||||
|
||||
if(fexists("[GLOB.diaryofmeanpeople]"))
|
||||
src << ftp(GLOB.diaryofmeanpeople)
|
||||
if(fexists("[GLOB.world_attack_log]"))
|
||||
src << ftp(GLOB.world_attack_log)
|
||||
else
|
||||
to_chat(src, "<font color='red'>Server attack log not found, try using .getserverlog.</font>")
|
||||
return
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell
|
||||
name = "cryo cell"
|
||||
icon = 'icons/obj/cryogenics.dmi'
|
||||
icon_state = "pod0"
|
||||
icon_state = "cell-off"
|
||||
density = 1
|
||||
anchored = 1
|
||||
obj_integrity = 350
|
||||
@@ -12,7 +12,6 @@
|
||||
state_open = FALSE
|
||||
var/autoeject = FALSE
|
||||
var/volume = 100
|
||||
var/running_bob_animation = FALSE
|
||||
|
||||
var/efficiency = 1
|
||||
var/sleep_factor = 750
|
||||
@@ -88,59 +87,17 @@
|
||||
beaker = null
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/update_icon()
|
||||
handle_update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/proc/handle_update_icon() //making another proc to avoid spam in update_icon
|
||||
overlays.Cut() //empty the overlay proc, just in case
|
||||
|
||||
if(panel_open)
|
||||
icon_state = "pod0-o"
|
||||
icon_state = "cell-o"
|
||||
else if(state_open)
|
||||
icon_state = "pod0"
|
||||
icon_state = "cell-open"
|
||||
else if(on && is_operational())
|
||||
if(occupant)
|
||||
var/image/pickle = image(occupant.icon, occupant.icon_state)
|
||||
pickle.overlays = occupant.overlays
|
||||
pickle.pixel_y = 22
|
||||
overlays += pickle
|
||||
icon_state = "pod1"
|
||||
var/up = 0 //used to see if we are going up or down, 1 is down, 2 is up
|
||||
spawn(0) // Without this, the icon update will block. The new thread will die once the occupant leaves.
|
||||
running_bob_animation = TRUE
|
||||
while(occupant)
|
||||
overlays -= "lid1" //have to remove the overlays first, to force an update- remove cloning pod overlay
|
||||
overlays -= pickle //remove mob overlay
|
||||
|
||||
switch(pickle.pixel_y) //this looks messy as fuck but it works, switch won't call itself twice
|
||||
|
||||
if(23) //inbetween state, for smoothness
|
||||
switch(up) //this is set later in the switch, to keep track of where the mob is supposed to go
|
||||
if(2) //2 is up
|
||||
pickle.pixel_y = 24 //set to highest
|
||||
|
||||
if(1) //1 is down
|
||||
pickle.pixel_y = 22 //set to lowest
|
||||
|
||||
if(22) //mob is at it's lowest
|
||||
pickle.pixel_y = 23 //set to inbetween
|
||||
up = 2 //have to go up
|
||||
|
||||
if(24) //mob is at it's highest
|
||||
pickle.pixel_y = 23 //set to inbetween
|
||||
up = 1 //have to go down
|
||||
|
||||
overlays += pickle //re-add the mob to the icon
|
||||
overlays += "lid1" //re-add the overlay of the pod, they are inside it, not floating
|
||||
|
||||
sleep(7) //don't want to jiggle violently, just slowly bob
|
||||
return
|
||||
running_bob_animation = FALSE
|
||||
icon_state = "cell-occupied"
|
||||
else
|
||||
icon_state = "pod1"
|
||||
overlays += "lid0" //have to remove the overlays first, to force an update- remove cloning pod overlay
|
||||
icon_state = "cell-on"
|
||||
else
|
||||
icon_state = "pod0"
|
||||
overlays += "lid0" //if no occupant, just put the lid overlay on, and ignore the rest
|
||||
icon_state = "cell-off"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/process()
|
||||
..()
|
||||
@@ -153,25 +110,26 @@
|
||||
return
|
||||
var/datum/gas_mixture/air1 = AIR1
|
||||
var/turf/T = get_turf(src)
|
||||
if(occupant)
|
||||
if(occupant.health >= 100) // Don't bother with fully healed people.
|
||||
if(isliving(occupant))
|
||||
var/mob/living/mob_occupant
|
||||
if(mob_occupant.health >= 100) // Don't bother with fully healed people.
|
||||
on = FALSE
|
||||
update_icon()
|
||||
playsound(T, 'sound/machines/cryo_warning.ogg', volume, 1) // Bug the doctors.
|
||||
radio.talk_into(src, "Patient fully restored", radio_channel)
|
||||
playsound(T, 'sound/machines/cryo_warning.ogg', volume) // Bug the doctors.
|
||||
radio.talk_into(src, "Patient fully restored", radio_channel, get_spans(), get_default_language())
|
||||
if(autoeject) // Eject if configured.
|
||||
radio.talk_into(src, "Auto ejecting patient now", radio_channel,get_spans(), get_default_language())
|
||||
radio.talk_into(src, "Auto ejecting patient now", radio_channel, get_spans(), get_default_language())
|
||||
open_machine()
|
||||
return
|
||||
else if(occupant.stat == DEAD) // We don't bother with dead people.
|
||||
else if(mob_occupant.stat == DEAD) // We don't bother with dead people.
|
||||
return
|
||||
if(autoeject) // Eject if configured.
|
||||
open_machine()
|
||||
return
|
||||
if(air1.gases.len)
|
||||
if(occupant.bodytemperature < T0C) // Sleepytime. Why? More cryo magic.
|
||||
occupant.Sleeping((occupant.bodytemperature / sleep_factor) * 100)
|
||||
occupant.Paralyse((occupant.bodytemperature / paralyze_factor) * 100)
|
||||
if(mob_occupant.bodytemperature < T0C) // Sleepytime. Why? More cryo magic.
|
||||
mob_occupant.Sleeping((mob_occupant.bodytemperature / sleep_factor) * 100)
|
||||
mob_occupant.Paralyse((mob_occupant.bodytemperature / paralyze_factor) * 100)
|
||||
|
||||
if(beaker)
|
||||
if(reagent_transfer == 0) // Magically transfer reagents. Because cryo magic.
|
||||
@@ -191,20 +149,21 @@
|
||||
on = FALSE
|
||||
update_icon()
|
||||
return
|
||||
if(occupant)
|
||||
if(isliving(occupant))
|
||||
var/mob/living/mob_occupant = occupant
|
||||
var/cold_protection = 0
|
||||
var/mob/living/carbon/human/H = occupant
|
||||
if(istype(H))
|
||||
cold_protection = H.get_cold_protection(air1.temperature)
|
||||
|
||||
var/temperature_delta = air1.temperature - occupant.bodytemperature // The only semi-realistic thing here: share temperature between the cell and the occupant.
|
||||
var/temperature_delta = air1.temperature - mob_occupant.bodytemperature // The only semi-realistic thing here: share temperature between the cell and the occupant.
|
||||
if(abs(temperature_delta) > 1)
|
||||
var/air_heat_capacity = air1.heat_capacity()
|
||||
var/heat = ((1 - cold_protection) / 10 + conduction_coefficient) \
|
||||
* temperature_delta * \
|
||||
(air_heat_capacity * heat_capacity / (air_heat_capacity + heat_capacity))
|
||||
air1.temperature = max(air1.temperature - heat / air_heat_capacity, TCMB)
|
||||
occupant.bodytemperature = max(occupant.bodytemperature + heat / heat_capacity, TCMB)
|
||||
mob_occupant.bodytemperature = max(mob_occupant.bodytemperature + heat / heat_capacity, TCMB)
|
||||
|
||||
air1.gases["o2"][MOLES] -= 0.5 / efficiency // Magically consume gas? Why not, we run on cryo magic.
|
||||
|
||||
@@ -242,7 +201,7 @@
|
||||
..()
|
||||
if(occupant)
|
||||
if(on)
|
||||
to_chat(user, "[occupant] is inside [src]!")
|
||||
to_chat(user, "Someone's inside [src]!")
|
||||
else
|
||||
to_chat(user, "You can barely make out a form floating in [src].")
|
||||
else
|
||||
@@ -265,9 +224,11 @@
|
||||
I.loc = src
|
||||
user.visible_message("[user] places [I] in [src].", \
|
||||
"<span class='notice'>You place [I] in [src].</span>")
|
||||
var/reagentlist = pretty_string_from_reagent_list(I.reagents.reagent_list)
|
||||
log_game("[key_name(user)] added an [I] to cyro containing [reagentlist]")
|
||||
return
|
||||
if(!on && !occupant && !state_open)
|
||||
if(default_deconstruction_screwdriver(user, "pod0-o", "pod0", I))
|
||||
if(default_deconstruction_screwdriver(user, "cell-o", "cell-off", I))
|
||||
return
|
||||
if(exchange_parts(user, I))
|
||||
return
|
||||
@@ -294,17 +255,18 @@
|
||||
data["autoEject"] = autoeject
|
||||
|
||||
var/list/occupantData = list()
|
||||
if(occupant)
|
||||
occupantData["name"] = occupant.name
|
||||
occupantData["stat"] = occupant.stat
|
||||
occupantData["health"] = occupant.health
|
||||
occupantData["maxHealth"] = occupant.maxHealth
|
||||
if(isliving(occupant))
|
||||
var/mob/living/mob_occupant = occupant
|
||||
occupantData["name"] = mob_occupant.name
|
||||
occupantData["stat"] = mob_occupant.stat
|
||||
occupantData["health"] = mob_occupant.health
|
||||
occupantData["maxHealth"] = mob_occupant.maxHealth
|
||||
occupantData["minHealth"] = HEALTH_THRESHOLD_DEAD
|
||||
occupantData["bruteLoss"] = occupant.getBruteLoss()
|
||||
occupantData["oxyLoss"] = occupant.getOxyLoss()
|
||||
occupantData["toxLoss"] = occupant.getToxLoss()
|
||||
occupantData["fireLoss"] = occupant.getFireLoss()
|
||||
occupantData["bodyTemperature"] = occupant.bodytemperature
|
||||
occupantData["bruteLoss"] = mob_occupant.getBruteLoss()
|
||||
occupantData["oxyLoss"] = mob_occupant.getOxyLoss()
|
||||
occupantData["toxLoss"] = mob_occupant.getToxLoss()
|
||||
occupantData["fireLoss"] = mob_occupant.getFireLoss()
|
||||
occupantData["bodyTemperature"] = mob_occupant.bodytemperature
|
||||
data["occupant"] = occupantData
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
diff a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm (rejected hunks)
|
||||
@@ -110,8 +110,8 @@
|
||||
return
|
||||
var/datum/gas_mixture/air1 = AIR1
|
||||
var/turf/T = get_turf(src)
|
||||
- if(isliving(occupant))
|
||||
- var/mob/living/mob_occupant
|
||||
+ if(occupant)
|
||||
+ var/mob/living/mob_occupant = occupant
|
||||
if(mob_occupant.health >= 100) // Don't bother with fully healed people.
|
||||
on = FALSE
|
||||
update_icon()
|
||||
@@ -16,22 +16,17 @@
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 100, bomb = 0, bio = 100, rad = 100, fire = 40, acid = 0)
|
||||
|
||||
|
||||
/obj/machinery/meter/New()
|
||||
..()
|
||||
/obj/machinery/meter/Initialize(mapload)
|
||||
. = ..()
|
||||
SSair.atmos_machinery += src
|
||||
src.target = locate(/obj/machinery/atmospherics/pipe) in loc
|
||||
return 1
|
||||
if (mapload && !target)
|
||||
target = locate(/obj/machinery/atmospherics/pipe) in loc
|
||||
|
||||
/obj/machinery/meter/Destroy()
|
||||
SSair.atmos_machinery -= src
|
||||
src.target = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/meter/Initialize(mapload)
|
||||
..()
|
||||
if (mapload && !target)
|
||||
src.target = locate(/obj/machinery/atmospherics/pipe) in loc
|
||||
|
||||
/obj/machinery/meter/process_atmos()
|
||||
if(!target)
|
||||
icon_state = "meterX"
|
||||
|
||||
@@ -227,7 +227,7 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
|
||||
if(check_exile_implant(C))
|
||||
say("Rejecting [AM]: Exile implant detected in contained lifeform.")
|
||||
return
|
||||
if(AM.buckled_mobs.len)
|
||||
if(AM.has_buckled_mobs())
|
||||
for(var/mob/living/carbon/C in AM.buckled_mobs)
|
||||
if(check_exile_implant(C))
|
||||
say("Rejecting [AM]: Exile implant detected in close proximity lifeform.")
|
||||
|
||||
@@ -64,17 +64,18 @@
|
||||
next_check = world.time + cooldown
|
||||
|
||||
/obj/structure/academy_wizard_spawner/proc/give_control()
|
||||
set waitfor = FALSE
|
||||
|
||||
if(!current_wizard)
|
||||
return
|
||||
spawn(0)
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as Wizard Academy Defender?", "wizard", null, ROLE_WIZARD, current_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
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as Wizard Academy Defender?", "wizard", null, be_special_flag = ROLE_WIZARD, M = current_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
|
||||
|
||||
@@ -50,11 +50,6 @@
|
||||
material_id = MAT_PLASMA
|
||||
message = "cm3 of plasma"
|
||||
|
||||
/datum/export/material/plasma/get_cost(obj/O, contr = 0, emag = 0)
|
||||
. = ..()
|
||||
if(emag) // Syndicate pays you more for the plasma.
|
||||
. = round(. * 1.5)
|
||||
|
||||
// Uranium. Still useful for both power generation and nuclear annihilation.
|
||||
/datum/export/material/uranium
|
||||
cost = 400
|
||||
@@ -98,4 +93,4 @@
|
||||
message = "cm3 of glass"
|
||||
material_id = MAT_GLASS
|
||||
export_types = list(/obj/item/stack/sheet/glass, /obj/item/weapon/ore,
|
||||
/obj/item/weapon/shard)
|
||||
/obj/item/weapon/shard)
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
|
||||
// Wood. Quite expensive in the grim and dark 26 century.
|
||||
/datum/export/stack/wood
|
||||
cost = 25
|
||||
cost = 50
|
||||
unit_name = "wood plank"
|
||||
export_types = list(/obj/item/stack/sheet/mineral/wood)
|
||||
|
||||
|
||||
@@ -182,14 +182,14 @@
|
||||
/datum/supply_pack/emergency/syndicate
|
||||
name = "NULL_ENTRY"
|
||||
hidden = TRUE
|
||||
cost = 14000
|
||||
cost = 20000
|
||||
contains = list()
|
||||
crate_name = "emergency crate"
|
||||
crate_type = /obj/structure/closet/crate/internals
|
||||
dangerous = TRUE
|
||||
|
||||
/datum/supply_pack/emergency/syndicate/fill(obj/structure/closet/crate/C)
|
||||
var/crate_value = 50
|
||||
var/crate_value = 30
|
||||
var/list/uplink_items = get_uplink_items(SSticker.mode)
|
||||
while(crate_value)
|
||||
var/category = pick(uplink_items)
|
||||
@@ -828,6 +828,14 @@
|
||||
/obj/item/weapon/defibrillator/loaded)
|
||||
crate_name = "defibrillator crate"
|
||||
|
||||
/datum/supply_pack/medical/vending
|
||||
name = "Medical Vending Crate"
|
||||
cost = 2000
|
||||
contains = list(/obj/item/weapon/vending_refill/medical,
|
||||
/obj/item/weapon/vending_refill/medical,
|
||||
/obj/item/weapon/vending_refill/medical)
|
||||
crate_name = "medical vending crate"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////// Science /////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1681,8 +1689,8 @@
|
||||
crate_name = "art supply crate"
|
||||
|
||||
/datum/supply_pack/misc/soapstone
|
||||
name = "Librarian Engraving/Scribbling Crate"
|
||||
crate_name = "librarian engraving/scribbling crate"
|
||||
name = "Curator Engraving/Scribbling Crate"
|
||||
crate_name = "curator engraving/scribbling crate"
|
||||
cost = 3000
|
||||
contains = list(/obj/item/soapstone)
|
||||
access = GLOB.access_library
|
||||
|
||||
@@ -39,9 +39,12 @@
|
||||
////////////////////////////////////
|
||||
//things that require the database//
|
||||
////////////////////////////////////
|
||||
var/player_age = "Requires database" //So admins know why it isn't working - Used to determine how old the account is - in days.
|
||||
var/player_age = -1 //Used to determine how old the account is - in days.
|
||||
var/player_join_date = null //Date that this account was first seen in the server
|
||||
var/related_accounts_ip = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this ip
|
||||
var/related_accounts_cid = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this computer id
|
||||
var/account_join_date = null //Date of byond account creation in ISO 8601 format
|
||||
var/account_age = -1 //Age of byond account in days
|
||||
|
||||
preload_rsc = PRELOAD_RSC
|
||||
|
||||
@@ -62,4 +65,4 @@
|
||||
var/connection_timeofday //world.timeofday they connected
|
||||
|
||||
var/inprefs = FALSE
|
||||
var/list/topiclimiter
|
||||
var/list/topiclimiter
|
||||
|
||||
@@ -80,8 +80,7 @@
|
||||
*/
|
||||
|
||||
//Logs all hrefs
|
||||
if(config && config.log_hrefs && GLOB.href_logfile)
|
||||
GLOB.href_logfile << "<small>[time_stamp(show_ds = TRUE)] [src] (usr:[usr])</small> || [hsrc ? "[hsrc] " : ""][href]<br>"
|
||||
GLOB.world_href_log << "<small>[time_stamp(show_ds = TRUE)] [src] (usr:[usr])</small> || [hsrc ? "[hsrc] " : ""][href]<br>"
|
||||
|
||||
// Admin PM
|
||||
if(href_list["priv_msg"])
|
||||
@@ -289,16 +288,11 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
mentor_memo_output("Show") */
|
||||
|
||||
add_verbs_from_config()
|
||||
set_client_age_from_db()
|
||||
set_client_age_from_db(tdata)
|
||||
var/cached_player_age = player_age //we have to cache this because other shit may change it and we need it's current value now down below.
|
||||
if (isnum(cached_player_age) && cached_player_age == -1) //first connection
|
||||
player_age = 0
|
||||
if(!IsGuestKey(key) && SSdbcore.IsConnected())
|
||||
findJoinDate()
|
||||
player_age = 0
|
||||
|
||||
sync_client_with_db(tdata)
|
||||
|
||||
|
||||
if (isnum(cached_player_age) && cached_player_age == -1) //first connection
|
||||
if (config.panic_bunker && !holder && !(ckey in GLOB.deadmins))
|
||||
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
|
||||
@@ -311,20 +305,19 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
qdel(src)
|
||||
return 0
|
||||
|
||||
|
||||
if (config.notify_new_player_age >= 0)
|
||||
message_admins("New user: [key_name_admin(src)] is connecting here for the first time.")
|
||||
if (config.irc_first_connection_alert)
|
||||
send2irc_adminless_only("New-user", "[key_name(src)] is connecting for the first time!")
|
||||
|
||||
player_age = 0 // set it from -1 to 0 so the job selection code doesn't have a panic attack
|
||||
|
||||
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(!IsGuestKey(key) && SSdbcore.IsConnected())
|
||||
findJoinDate()
|
||||
|
||||
sync_client_with_db(tdata)
|
||||
else if (isnum(cached_player_age) && cached_player_age < config.notify_new_player_age)
|
||||
message_admins("New user: [key_name_admin(src)] just connected with an age of [cached_player_age] day[(player_age==1?"":"s")]")
|
||||
if(config.use_account_age_for_jobs && account_age >= 0)
|
||||
player_age = account_age
|
||||
if(account_age >= 0 && account_age < config.notify_new_player_account_age)
|
||||
message_admins("[key_name_admin(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age==1?"":"s")] old, created on [account_join_date].")
|
||||
if (config.irc_first_connection_alert)
|
||||
send2irc_adminless_only("new_byond_user", "[key_name(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age==1?"":"s")] old, created on [account_join_date].")
|
||||
get_message_output("watchlist entry", ckey)
|
||||
check_ip_intel()
|
||||
|
||||
@@ -360,6 +353,27 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
|
||||
hook_vr("client_new",list(src))
|
||||
|
||||
var/list/topmenus = GLOB.menulist[/datum/menu]
|
||||
for (var/thing in topmenus)
|
||||
var/datum/menu/topmenu = thing
|
||||
var/topmenuname = "[topmenu]"
|
||||
if (topmenuname == "[topmenu.type]")
|
||||
var/list/tree = splittext(topmenuname, "/")
|
||||
topmenuname = tree[tree.len]
|
||||
winset(src, "[topmenu.type]", "parent=menu;name=[url_encode(topmenuname)]")
|
||||
var/list/entries = topmenu.Generate_list(src)
|
||||
for (var/child in entries)
|
||||
winset(src, "[url_encode(child)]", "[entries[child]]")
|
||||
if (!ispath(child, /datum/menu))
|
||||
var/atom/verb/verbpath = child
|
||||
if (copytext(verbpath.name,1,2) != "@")
|
||||
new child(src)
|
||||
|
||||
for (var/thing in prefs.menuoptions)
|
||||
var/datum/menu/menuitem = GLOB.menulist[thing]
|
||||
if (menuitem)
|
||||
menuitem.Load_checked(src)
|
||||
|
||||
//////////////
|
||||
//DISCONNECT//
|
||||
//////////////
|
||||
@@ -370,8 +384,8 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
adminGreet(1)
|
||||
holder.owner = null
|
||||
GLOB.admins -= src
|
||||
|
||||
if (!GLOB.admins.len && SSticker.current_state == GAME_STATE_PLAYING) //Only report this stuff if we are currently playing.
|
||||
|
||||
if (!GLOB.admins.len && SSticker.IsRoundInProgress()) //Only report this stuff if we are currently playing.
|
||||
if(!GLOB.admins.len) //Apparently the admin logging out is no longer an admin at this point, so we have to check this towards 0 and not towards 1. Awell.
|
||||
var/cheesy_message = pick(
|
||||
"I have no admins online!",\
|
||||
@@ -396,7 +410,7 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
"Sometimes when I have sex, I think about putting an entire peanut butter and jelly sandwich in the VCR.",\
|
||||
"Forever alone :("\
|
||||
)
|
||||
|
||||
|
||||
send2irc("Server", "[cheesy_message] (No admins online)")
|
||||
|
||||
GLOB.ahelp_tickets.ClientLogout(src)
|
||||
@@ -410,70 +424,86 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
/client/Destroy()
|
||||
return QDEL_HINT_HARDDEL_NOW
|
||||
|
||||
/client/proc/set_client_age_from_db()
|
||||
/client/proc/set_client_age_from_db(connectiontopic)
|
||||
if (IsGuestKey(src.key))
|
||||
return
|
||||
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
|
||||
var/sql_ckey = sanitizeSQL(src.ckey)
|
||||
|
||||
var/datum/DBQuery/query_get_client_age = SSdbcore.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_get_client_age.Execute())
|
||||
return
|
||||
|
||||
while(query_get_client_age.NextRow())
|
||||
player_age = text2num(query_get_client_age.item[2])
|
||||
return
|
||||
|
||||
//no match mark it as a first connection for use in client/New()
|
||||
player_age = -1
|
||||
|
||||
|
||||
/client/proc/sync_client_with_db(connectiontopic)
|
||||
if (IsGuestKey(src.key))
|
||||
return
|
||||
|
||||
if (!SSdbcore.Connect())
|
||||
return
|
||||
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
|
||||
var/datum/DBQuery/query_get_ip = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip = INET_ATON('[address]') AND ckey != '[sql_ckey]'")
|
||||
query_get_ip.Execute()
|
||||
var/datum/DBQuery/query_get_related_ip = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip = INET_ATON('[address]') AND ckey != '[sql_ckey]'")
|
||||
query_get_related_ip.Execute()
|
||||
related_accounts_ip = ""
|
||||
while(query_get_ip.NextRow())
|
||||
related_accounts_ip += "[query_get_ip.item[1]], "
|
||||
|
||||
var/datum/DBQuery/query_get_cid = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE computerid = '[computer_id]' AND ckey != '[sql_ckey]'")
|
||||
if(!query_get_cid.Execute())
|
||||
while(query_get_related_ip.NextRow())
|
||||
related_accounts_ip += "[query_get_related_ip.item[1]], "
|
||||
var/datum/DBQuery/query_get_related_cid = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE computerid = '[computer_id]' AND ckey != '[sql_ckey]'")
|
||||
if(!query_get_related_cid.Execute())
|
||||
return
|
||||
related_accounts_cid = ""
|
||||
while (query_get_cid.NextRow())
|
||||
related_accounts_cid += "[query_get_cid.item[1]], "
|
||||
|
||||
while (query_get_related_cid.NextRow())
|
||||
related_accounts_cid += "[query_get_related_cid.item[1]], "
|
||||
var/admin_rank = "Player"
|
||||
if (src.holder && src.holder.rank)
|
||||
admin_rank = src.holder.rank.name
|
||||
else
|
||||
if (check_randomizer(connectiontopic))
|
||||
return
|
||||
|
||||
var/sql_ip = sanitizeSQL(src.address)
|
||||
var/sql_computerid = sanitizeSQL(src.computer_id)
|
||||
var/sql_ip = sanitizeSQL(address)
|
||||
var/sql_computerid = sanitizeSQL(computer_id)
|
||||
var/sql_admin_rank = sanitizeSQL(admin_rank)
|
||||
|
||||
|
||||
var/datum/DBQuery/query_log_player = SSdbcore.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), INET_ATON('[sql_ip]'), '[sql_computerid]', '[sql_admin_rank]') ON DUPLICATE KEY UPDATE lastseen = VALUES(lastseen), ip = VALUES(ip), computerid = VALUES(computerid), lastadminrank = VALUES(lastadminrank)")
|
||||
if(!query_log_player.Execute())
|
||||
var/new_player
|
||||
var/datum/DBQuery/query_client_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_client_in_db.Execute())
|
||||
return
|
||||
|
||||
//Logging player access
|
||||
|
||||
if(!query_client_in_db.NextRow())
|
||||
new_player = 1
|
||||
account_join_date = sanitizeSQL(findJoinDate())
|
||||
var/datum/DBQuery/query_add_player = SSdbcore.NewQuery("INSERT INTO [format_table_name("player")] (`ckey`, `firstseen`, `lastseen`, `ip`, `computerid`, `lastadminrank`, `accountjoindate`) VALUES ('[sql_ckey]', Now(), Now(), INET_ATON('[sql_ip]'), '[sql_computerid]', '[sql_admin_rank]', [account_join_date ? "'[account_join_date]'" : "NULL"])")
|
||||
if(!query_add_player.Execute())
|
||||
return
|
||||
if(!account_join_date)
|
||||
account_join_date = "Error"
|
||||
account_age = -1
|
||||
var/datum/DBQuery/query_get_client_age = SSdbcore.NewQuery("SELECT firstseen, DATEDIFF(Now(),firstseen), accountjoindate, DATEDIFF(Now(),accountjoindate) FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_get_client_age.Execute())
|
||||
return
|
||||
if(query_get_client_age.NextRow())
|
||||
player_join_date = query_get_client_age.item[1]
|
||||
player_age = text2num(query_get_client_age.item[2])
|
||||
if(!account_join_date)
|
||||
account_join_date = query_get_client_age.item[3]
|
||||
account_age = text2num(query_get_client_age.item[4])
|
||||
if(!account_age)
|
||||
account_join_date = sanitizeSQL(findJoinDate())
|
||||
if(!account_join_date)
|
||||
account_age = -1
|
||||
else
|
||||
var/datum/DBQuery/query_datediff = SSdbcore.NewQuery("SELECT DATEDIFF(Now(),[account_join_date])")
|
||||
if(!query_datediff.Execute())
|
||||
return
|
||||
if(query_datediff.NextRow())
|
||||
account_age = text2num(query_datediff.item[1])
|
||||
if(!new_player)
|
||||
var/datum/DBQuery/query_log_player = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET lastseen = Now(), ip = INET_ATON('[sql_ip]'), computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]', accountjoindate = [account_join_date ? "'[account_join_date]'" : "NULL"] WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_log_player.Execute())
|
||||
return
|
||||
if(!account_join_date)
|
||||
account_join_date = "Error"
|
||||
var/datum/DBQuery/query_log_connection = SSdbcore.NewQuery("INSERT INTO `[format_table_name("connection_log")]` (`id`,`datetime`,`server_ip`,`server_port`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),INET_ATON('[world.internet_address]'),'[world.port]','[sql_ckey]',INET_ATON('[sql_ip]'),'[sql_computerid]')")
|
||||
query_log_connection.Execute()
|
||||
|
||||
/client/proc/findJoinDate()
|
||||
var/list/http = world.Export("http://byond.com/members/[ckey]?format=text")
|
||||
if(!http)
|
||||
log_world("Failed to connect to byond age check for [ckey]")
|
||||
return
|
||||
var/F = file2text(http["CONTENT"])
|
||||
if(F)
|
||||
var/regex/R = regex("joined = \"(\\d{4}-\\d{2}-\\d{2})\"")
|
||||
if(R.Find(F))
|
||||
. = R.group[1]
|
||||
else
|
||||
CRASH("Age check regex failed for [src.ckey]")
|
||||
|
||||
/client/proc/check_randomizer(topic)
|
||||
. = FALSE
|
||||
if (connection != "seeker")
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
diff a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm (rejected hunks)
|
||||
@@ -266,17 +266,11 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
if((global.comms_key == "default_pwd" || length(global.comms_key) <= 6) && global.comms_allowed) //It's the default value or less than 6 characters long, but it somehow didn't disable comms.
|
||||
to_chat(src, "<span class='danger'>The server's API key is either too short or is the default value! Consider changing it immediately!</span>")
|
||||
|
||||
- add_verbs_from_config()
|
||||
+ add_verbs_from_config(tdata)
|
||||
set_client_age_from_db()
|
||||
var/cached_player_age = player_age //we have to cache this because other shit may change it and we need it's current value now down below.
|
||||
if (isnum(cached_player_age) && cached_player_age == -1) //first connection
|
||||
- player_age = 0
|
||||
- if(!IsGuestKey(key) && SSdbcore.IsConnected())
|
||||
- findJoinDate()
|
||||
-
|
||||
- sync_client_with_db(tdata)
|
||||
-
|
||||
-
|
||||
+ player_age = 0
|
||||
if (isnum(cached_player_age) && cached_player_age == -1) //first connection
|
||||
if (config.panic_bunker && !holder && !(ckey in GLOB.deadmins))
|
||||
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
|
||||
@@ -295,7 +289,14 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
send2irc_adminless_only("New-user", "[key_name(src)] is connecting for the first time!")
|
||||
else if (isnum(cached_player_age) && cached_player_age < config.notify_new_player_age)
|
||||
message_admins("New user: [key_name_admin(src)] just connected with an age of [cached_player_age] day[(player_age==1?"":"s")]")
|
||||
-
|
||||
+ if(config.use_account_age_for_jobs && account_age >= 0)
|
||||
+ player_age = account_age
|
||||
+ if(account_age >= 0 && account_age < config.notify_new_player_account_age)
|
||||
+ message_admins("[key_name_admin(src)] (IP: [address], ID: [computer_id]) is a new BYOND account day[(account_age==1?"":"s")] old, created on [account_join_date].")
|
||||
+ if (config.irc_first_connection_alert)
|
||||
+ send2irc_adminless_only("new_byond_user", "[key_name(src)] (IP: [address], ID: [computer_id]) is a new BYOND account day[(account_age==1?"":"s")] old, created on [account_join_date].")
|
||||
+ else //We failed to get an age for this user, let admins know they need to keep an eye on them
|
||||
+ message_admins("Failed to get BYOND account age for [key_name_admin(src)]")
|
||||
get_message_output("watchlist entry", ckey)
|
||||
check_ip_intel()
|
||||
|
||||
@@ -340,7 +341,7 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
adminGreet(1)
|
||||
holder.owner = null
|
||||
GLOB.admins -= src
|
||||
-
|
||||
+
|
||||
GLOB.ahelp_tickets.ClientLogout(src)
|
||||
GLOB.directory -= ckey
|
||||
GLOB.clients -= src
|
||||
@@ -168,6 +168,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
var/uplink_spawn_loc = UPLINK_PDA
|
||||
|
||||
var/list/menuoptions
|
||||
|
||||
//citadel code
|
||||
var/arousable = TRUE //Allows players to disable arousal from the character creation menu
|
||||
var/flavor_text = ""
|
||||
@@ -194,6 +196,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(!loaded_preferences_successfully)
|
||||
save_preferences()
|
||||
save_character() //let's save this new random character so it doesn't keep generating new ones.
|
||||
menuoptions = list()
|
||||
return
|
||||
|
||||
/datum/preferences/proc/ShowChoices(mob/user)
|
||||
@@ -790,7 +793,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(href_list["jobbancheck"])
|
||||
var/job = sanitizeSQL(href_list["jobbancheck"])
|
||||
var/sql_ckey = sanitizeSQL(user.ckey)
|
||||
var/datum/DBQuery/query_get_jobban = SSdbcore.NewQuery("SELECT reason, bantime, duration, expiration_time, a_ckey FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[job]'")
|
||||
var/datum/DBQuery/query_get_jobban = SSdbcore.NewQuery("SELECT reason, bantime, duration, expiration_time, a_ckey FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[job]'")
|
||||
if(!query_get_jobban.warn_execute())
|
||||
return
|
||||
if(query_get_jobban.NextRow())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//This is the lowest supported version, anything below this is completely obsolete and the entire savefile will be wiped.
|
||||
#define SAVEFILE_VERSION_MIN 10
|
||||
#define SAVEFILE_VERSION_MIN 15
|
||||
|
||||
//This is the current version, anything below this will attempt to update (if it's not obsolete)
|
||||
#define SAVEFILE_VERSION_MAX 20
|
||||
@@ -88,15 +88,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
|
||||
/datum/preferences/proc/update_preferences(current_version, savefile/S)
|
||||
if(current_version < 10)
|
||||
toggles |= MEMBER_PUBLIC
|
||||
if(current_version < 11)
|
||||
chat_toggles = TOGGLES_DEFAULT_CHAT
|
||||
toggles = TOGGLES_DEFAULT
|
||||
if(current_version < 12)
|
||||
ignoring = list()
|
||||
if(current_version < 15)
|
||||
toggles |= SOUND_ANNOUNCEMENTS
|
||||
|
||||
|
||||
//should this proc get fairly long (say 3 versions long),
|
||||
@@ -106,16 +97,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
//It's only really meant to avoid annoying frequent players
|
||||
//if your savefile is 3 months out of date, then 'tough shit'.
|
||||
/datum/preferences/proc/update_character(current_version, savefile/S)
|
||||
if(pref_species && !(pref_species.id in GLOB.roundstart_species))
|
||||
var/rando_race = pick(config.roundstart_races)
|
||||
pref_species = new rando_race()
|
||||
|
||||
if(current_version < 13 || !istext(backbag))
|
||||
switch(backbag)
|
||||
if(2)
|
||||
backbag = DSATCHEL
|
||||
else
|
||||
backbag = DBACKPACK
|
||||
if(current_version < 16)
|
||||
var/berandom
|
||||
S["userandomjob"] >> berandom
|
||||
@@ -186,12 +167,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
S["tgui_fancy"] >> tgui_fancy
|
||||
S["tgui_lock"] >> tgui_lock
|
||||
S["windowflash"] >> windowflashing
|
||||
S["be_special"] >> be_special
|
||||
|
||||
if(islist(S["be_special"]))
|
||||
S["be_special"] >> be_special
|
||||
else //force update and store the old bitflag version of be_special
|
||||
needs_update = 12
|
||||
S["be_special"] >> old_be_special
|
||||
|
||||
S["default_slot"] >> default_slot
|
||||
S["chat_toggles"] >> chat_toggles
|
||||
@@ -207,6 +184,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
S["uses_glasses_colour"]>> uses_glasses_colour
|
||||
S["clientfps"] >> clientfps
|
||||
S["parallax"] >> parallax
|
||||
S["menuoptions"] >> menuoptions
|
||||
//citadel code
|
||||
S["arousable"] >> arousable
|
||||
|
||||
@@ -231,6 +209,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
ghost_orbit = sanitize_inlist(ghost_orbit, GLOB.ghost_orbits, initial(ghost_orbit))
|
||||
ghost_accs = sanitize_inlist(ghost_accs, GLOB.ghost_accs_options, GHOST_ACCS_DEFAULT_OPTION)
|
||||
ghost_others = sanitize_inlist(ghost_others, GLOB.ghost_others_options, GHOST_OTHERS_DEFAULT_OPTION)
|
||||
menuoptions = SANITIZE_LIST(menuoptions)
|
||||
be_special = SANITIZE_LIST(be_special)
|
||||
|
||||
|
||||
return 1
|
||||
|
||||
@@ -267,6 +248,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
S["uses_glasses_colour"]<< uses_glasses_colour
|
||||
S["clientfps"] << clientfps
|
||||
S["parallax"] << parallax
|
||||
S["menuoptions"] << menuoptions
|
||||
//citadel code
|
||||
S["arousable"] << arousable
|
||||
|
||||
@@ -299,9 +281,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
if(config.mutant_races && species_id && (species_id in GLOB.roundstart_species))
|
||||
var/newtype = GLOB.roundstart_species[species_id]
|
||||
pref_species = new newtype()
|
||||
else
|
||||
else if (config.roundstart_races.len)
|
||||
var/rando_race = pick(config.roundstart_races)
|
||||
pref_species = new rando_race()
|
||||
if (rando_race)
|
||||
pref_species = new rando_race()
|
||||
|
||||
if(!S["features["mcolor"]"] || S["features["mcolor"]"] == "#000")
|
||||
S["features["mcolor"]"] << "#FFF"
|
||||
@@ -565,7 +548,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
#undef SAVEFILE_VERSION_MAX
|
||||
#undef SAVEFILE_VERSION_MIN
|
||||
/*
|
||||
|
||||
#ifdef TESTING
|
||||
//DEBUG
|
||||
//Some crude tools for testing savefiles
|
||||
//path is the savefile path
|
||||
@@ -576,4 +560,5 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
/client/verb/savefile_import(path as text)
|
||||
var/savefile/S = new /savefile(path)
|
||||
S.ImportText("/",file("[path].txt"))
|
||||
*/
|
||||
|
||||
#endif
|
||||
@@ -1,162 +1,249 @@
|
||||
//toggles
|
||||
/client/verb/toggle_ghost_ears()
|
||||
set name = "Show/Hide GhostEars"
|
||||
set category = "Preferences"
|
||||
set desc = ".Toggle Between seeing all mob speech, and only speech of nearby mobs"
|
||||
prefs.chat_toggles ^= CHAT_GHOSTEARS
|
||||
to_chat(src, "As a ghost, you will now [(prefs.chat_toggles & CHAT_GHOSTEARS) ? "see all speech in the world" : "only see speech from nearby mobs"].")
|
||||
prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost Ears|[prefs.chat_toggles & CHAT_GHOSTEARS]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
//this works as is to create a single checked item, but has no back end code for toggleing the check yet
|
||||
#define TOGGLE_CHECKBOX(PARENT, CHILD) PARENT/CHILD/abstract = TRUE;PARENT/CHILD/checkbox = CHECKBOX_TOGGLE;PARENT/CHILD/verb/CHILD
|
||||
|
||||
/client/verb/toggle_ghost_sight()
|
||||
set name = "Show/Hide GhostSight"
|
||||
set category = "Preferences"
|
||||
set desc = ".Toggle Between seeing all mob emotes, and only emotes of nearby mobs"
|
||||
prefs.chat_toggles ^= CHAT_GHOSTSIGHT
|
||||
to_chat(src, "As a ghost, you will now [(prefs.chat_toggles & CHAT_GHOSTSIGHT) ? "see all emotes in the world" : "only see emotes from nearby mobs"].")
|
||||
prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost Sight|[prefs.chat_toggles & CHAT_GHOSTSIGHT]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
//Example usage TOGGLE_CHECKBOX(datum/menu/Settings/Ghost/chatterbox, toggle_ghost_ears)()
|
||||
|
||||
/client/verb/toggle_ghost_whispers()
|
||||
set name = "Show/Hide GhostWhispers"
|
||||
set category = "Preferences"
|
||||
set desc = ".Toggle between hearing all whispers, and only whispers of nearby mobs"
|
||||
prefs.chat_toggles ^= CHAT_GHOSTWHISPER
|
||||
to_chat(src, "As a ghost, you will now [(prefs.chat_toggles & CHAT_GHOSTWHISPER) ? "see all whispers in the world" : "only see whispers from nearby mobs"].")
|
||||
prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost Whispers|[prefs.chat_toggles & CHAT_GHOSTWHISPER]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
//override because we don't want to save preferences twice.
|
||||
/datum/menu/Settings/Set_checked(client/C, verbpath)
|
||||
if (checkbox == CHECKBOX_GROUP)
|
||||
C.prefs.menuoptions[type] = verbpath
|
||||
else if (checkbox == CHECKBOX_TOGGLE)
|
||||
var/checked = Get_checked(C)
|
||||
C.prefs.menuoptions[type] = !checked
|
||||
winset(C, "[verbpath]", "is-checked = [!checked]")
|
||||
|
||||
/client/verb/toggle_ghost_radio()
|
||||
set name = "Show/Hide GhostRadio"
|
||||
/datum/menu/Settings/verb/setup_character()
|
||||
set name = "Game Preferences"
|
||||
set category = "Preferences"
|
||||
set desc = ".Enable or disable hearing radio chatter as a ghost"
|
||||
prefs.chat_toggles ^= CHAT_GHOSTRADIO
|
||||
to_chat(src, "As a ghost, you will now [(prefs.chat_toggles & CHAT_GHOSTRADIO) ? "see radio chatter" : "not see radio chatter"].")
|
||||
prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost Radio|[prefs.chat_toggles & CHAT_GHOSTRADIO]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! //social experiment, increase the generation whenever you copypaste this shamelessly GENERATION 1
|
||||
set desc = "Open Game Preferences Window"
|
||||
usr.client.prefs.current_tab = 1
|
||||
usr.client.prefs.ShowChoices(usr)
|
||||
|
||||
//toggles
|
||||
/datum/menu/Settings/Ghost/chatterbox
|
||||
name = "Chat Box Spam"
|
||||
|
||||
/client/verb/toggle_ghost_pda()
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_ears)()
|
||||
set name = "Show/Hide GhostEars"
|
||||
set category = "Preferences"
|
||||
set desc = "See All Speech"
|
||||
usr.client.prefs.chat_toggles ^= CHAT_GHOSTEARS
|
||||
to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTEARS) ? "see all speech in the world" : "only see speech from nearby mobs"].")
|
||||
usr.client.prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost Ears|[usr.client.prefs.chat_toggles & CHAT_GHOSTEARS]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_ears/Get_checked(client/C)
|
||||
return C.prefs.chat_toggles & CHAT_GHOSTEARS
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_sight)()
|
||||
set name = "Show/Hide GhostSight"
|
||||
set category = "Preferences"
|
||||
set desc = "See All Emotes"
|
||||
usr.client.prefs.chat_toggles ^= CHAT_GHOSTSIGHT
|
||||
to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTSIGHT) ? "see all emotes in the world" : "only see emotes from nearby mobs"].")
|
||||
usr.client.prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost Sight|[usr.client.prefs.chat_toggles & CHAT_GHOSTSIGHT]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_sight/Get_checked(client/C)
|
||||
return C.prefs.chat_toggles & CHAT_GHOSTSIGHT
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_whispers)()
|
||||
set name = "Show/Hide GhostWhispers"
|
||||
set category = "Preferences"
|
||||
set desc = "See All Whispers"
|
||||
usr.client.prefs.chat_toggles ^= CHAT_GHOSTWHISPER
|
||||
to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTWHISPER) ? "see all whispers in the world" : "only see whispers from nearby mobs"].")
|
||||
usr.client.prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost Whispers|[usr.client.prefs.chat_toggles & CHAT_GHOSTWHISPER]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_whispers/Get_checked(client/C)
|
||||
return C.prefs.chat_toggles & CHAT_GHOSTWHISPER
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_radio)()
|
||||
set name = "Show/Hide GhostRadio"
|
||||
set category = "Preferences"
|
||||
set desc = "See All Radio Chatter"
|
||||
usr.client.prefs.chat_toggles ^= CHAT_GHOSTRADIO
|
||||
to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTRADIO) ? "see radio chatter" : "not see radio chatter"].")
|
||||
usr.client.prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost Radio|[usr.client.prefs.chat_toggles & CHAT_GHOSTRADIO]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! //social experiment, increase the generation whenever you copypaste this shamelessly GENERATION 1
|
||||
/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_radio/Get_checked(client/C)
|
||||
return C.prefs.chat_toggles & CHAT_GHOSTRADIO
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_pda)()
|
||||
set name = "Show/Hide GhostPDA"
|
||||
set category = "Preferences"
|
||||
set desc = ".Toggle Between seeing all mob pda messages, and only pda messages of nearby mobs"
|
||||
prefs.chat_toggles ^= CHAT_GHOSTPDA
|
||||
to_chat(src, "As a ghost, you will now [(prefs.chat_toggles & CHAT_GHOSTPDA) ? "see all pda messages in the world" : "only see pda messages from nearby mobs"].")
|
||||
prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost PDA|[prefs.chat_toggles & CHAT_GHOSTPDA]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
set category = "Preferences"
|
||||
set desc = "See All PDA Messages"
|
||||
usr.client.prefs.chat_toggles ^= CHAT_GHOSTPDA
|
||||
to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTPDA) ? "see all pda messages in the world" : "only see pda messages from nearby mobs"].")
|
||||
usr.client.prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost PDA|[usr.client.prefs.chat_toggles & CHAT_GHOSTPDA]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_pda/Get_checked(client/C)
|
||||
return C.prefs.chat_toggles & CHAT_GHOSTPDA
|
||||
|
||||
/datum/menu/Settings/Ghost/chatterbox/Events
|
||||
name = "Events"
|
||||
|
||||
//please be aware that the following two verbs have inverted stat output, so that "Toggle Deathrattle|1" still means you activated it
|
||||
/client/verb/toggle_deathrattle()
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox/Events, toggle_deathrattle)()
|
||||
set name = "Toggle Deathrattle"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggle recieving a message in deadchat when sentient mobs die."
|
||||
prefs.toggles ^= DISABLE_DEATHRATTLE
|
||||
prefs.save_preferences()
|
||||
to_chat(usr, "You will [(prefs.toggles & DISABLE_DEATHRATTLE) ? "no longer" : "now"] get messages when a sentient mob dies.")
|
||||
SSblackbox.add_details("preferences_verb", "Toggle Deathrattle|[!(prefs.toggles & DISABLE_DEATHRATTLE)]") //If you are copy-pasting this, maybe you should spend some time reading the comments.
|
||||
|
||||
/client/verb/toggle_arrivalrattle()
|
||||
set category = "Preferences"
|
||||
set desc = "Death"
|
||||
usr.client.prefs.toggles ^= DISABLE_DEATHRATTLE
|
||||
usr.client.prefs.save_preferences()
|
||||
to_chat(usr, "You will [(usr.client.prefs.toggles & DISABLE_DEATHRATTLE) ? "no longer" : "now"] get messages when a sentient mob dies.")
|
||||
SSblackbox.add_details("preferences_verb", "Toggle Deathrattle|[!(usr.client.prefs.toggles & DISABLE_DEATHRATTLE)]") //If you are copy-pasting this, maybe you should spend some time reading the comments.
|
||||
/datum/menu/Settings/Ghost/chatterbox/Events/toggle_deathrattle/Get_checked(client/C)
|
||||
return !(C.prefs.toggles & DISABLE_DEATHRATTLE)
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox/Events, toggle_arrivalrattle)()
|
||||
set name = "Toggle Arrivalrattle"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggle recieving a message in deadchat when someone joins the station."
|
||||
prefs.toggles ^= DISABLE_ARRIVALRATTLE
|
||||
to_chat(usr, "You will [(prefs.toggles & DISABLE_ARRIVALRATTLE) ? "no longer" : "now"] get messages when someone joins the station.")
|
||||
prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb", "Toggle Arrivalrattle|[!(prefs.toggles & DISABLE_ARRIVALRATTLE)]") //If you are copy-pasting this, maybe you should rethink where your life went so wrong.
|
||||
|
||||
/client/verb/togglemidroundantag()
|
||||
set category = "Preferences"
|
||||
set desc = "New Player Arrival"
|
||||
usr.client.prefs.toggles ^= DISABLE_ARRIVALRATTLE
|
||||
to_chat(usr, "You will [(usr.client.prefs.toggles & DISABLE_ARRIVALRATTLE) ? "no longer" : "now"] get messages when someone joins the station.")
|
||||
usr.client.prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb", "Toggle Arrivalrattle|[!(usr.client.prefs.toggles & DISABLE_ARRIVALRATTLE)]") //If you are copy-pasting this, maybe you should rethink where your life went so wrong.
|
||||
/datum/menu/Settings/Ghost/chatterbox/Events/toggle_arrivalrattle/Get_checked(client/C)
|
||||
return !(C.prefs.toggles & DISABLE_ARRIVALRATTLE)
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost, togglemidroundantag)()
|
||||
set name = "Toggle Midround Antagonist"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles whether or not you will be considered for antagonist status given during a round."
|
||||
prefs.toggles ^= MIDROUND_ANTAG
|
||||
prefs.save_preferences()
|
||||
to_chat(src, "You will [(prefs.toggles & MIDROUND_ANTAG) ? "now" : "no longer"] be considered for midround antagonist positions.")
|
||||
SSblackbox.add_details("preferences_verb","Toggle Midround Antag|[prefs.toggles & MIDROUND_ANTAG]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/verb/toggletitlemusic()
|
||||
set category = "Preferences"
|
||||
set desc = "Midround Antagonist"
|
||||
usr.client.prefs.toggles ^= MIDROUND_ANTAG
|
||||
usr.client.prefs.save_preferences()
|
||||
to_chat(usr, "You will [(usr.client.prefs.toggles & MIDROUND_ANTAG) ? "now" : "no longer"] be considered for midround antagonist positions.")
|
||||
SSblackbox.add_details("preferences_verb","Toggle Midround Antag|[usr.client.prefs.toggles & MIDROUND_ANTAG]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Ghost/togglemidroundantag/Get_checked(client/C)
|
||||
return C.prefs.toggles & MIDROUND_ANTAG
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggletitlemusic)()
|
||||
set name = "Hear/Silence LobbyMusic"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles hearing the GameLobby music"
|
||||
prefs.toggles ^= SOUND_LOBBY
|
||||
prefs.save_preferences()
|
||||
if(prefs.toggles & SOUND_LOBBY)
|
||||
to_chat(src, "You will now hear music in the game lobby.")
|
||||
if(isnewplayer(mob))
|
||||
playtitlemusic()
|
||||
set desc = "Hear Music In Lobby"
|
||||
usr.client.prefs.toggles ^= SOUND_LOBBY
|
||||
usr.client.prefs.save_preferences()
|
||||
if(usr.client.prefs.toggles & SOUND_LOBBY)
|
||||
to_chat(usr, "You will now hear music in the game lobby.")
|
||||
if(isnewplayer(usr))
|
||||
usr.client.playtitlemusic()
|
||||
else
|
||||
to_chat(src, "You will no longer hear music in the game lobby.")
|
||||
mob.stop_sound_channel(CHANNEL_LOBBYMUSIC)
|
||||
SSblackbox.add_details("preferences_verb","Toggle Lobby Music|[prefs.toggles & SOUND_LOBBY]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
to_chat(usr, "You will no longer hear music in the game lobby.")
|
||||
usr.stop_sound_channel(CHANNEL_LOBBYMUSIC)
|
||||
SSblackbox.add_details("preferences_verb","Toggle Lobby Music|[usr.client.prefs.toggles & SOUND_LOBBY]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Sound/toggletitlemusic/Get_checked(client/C)
|
||||
return C.prefs.toggles & SOUND_LOBBY
|
||||
|
||||
|
||||
/client/verb/togglemidis()
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, togglemidis)()
|
||||
set name = "Hear/Silence Midis"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles hearing sounds uploaded by admins"
|
||||
prefs.toggles ^= SOUND_MIDI
|
||||
prefs.save_preferences()
|
||||
if(prefs.toggles & SOUND_MIDI)
|
||||
to_chat(src, "You will now hear any sounds uploaded by admins.")
|
||||
set desc = "Hear Admin Triggered Sounds (Midis)"
|
||||
usr.client.prefs.toggles ^= SOUND_MIDI
|
||||
usr.client.prefs.save_preferences()
|
||||
if(usr.client.prefs.toggles & SOUND_MIDI)
|
||||
to_chat(usr, "You will now hear any sounds uploaded by admins.")
|
||||
else
|
||||
to_chat(src, "You will no longer hear sounds uploaded by admins")
|
||||
mob.stop_sound_channel(CHANNEL_ADMIN)
|
||||
SSblackbox.add_details("preferences_verb","Toggle Hearing Midis|[prefs.toggles & SOUND_MIDI]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
to_chat(usr, "You will no longer hear sounds uploaded by admins")
|
||||
usr.stop_sound_channel(CHANNEL_ADMIN)
|
||||
SSblackbox.add_details("preferences_verb","Toggle Hearing Midis|[usr.client.prefs.toggles & SOUND_MIDI]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Sound/togglemidis/Get_checked(client/C)
|
||||
return C.prefs.toggles & SOUND_MIDI
|
||||
|
||||
/client/verb/stop_client_sounds()
|
||||
set name = "Stop Sounds"
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggle_instruments)()
|
||||
set name = "Hear/Silence Instruments"
|
||||
set category = "Preferences"
|
||||
set desc = "Kills all currently playing sounds, use if admin taste in midis a shite"
|
||||
src << sound(null)
|
||||
SSblackbox.add_details("preferences_verb","Stop Self Sounds") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
set desc = "Hear In-game Instruments"
|
||||
usr.client.prefs.toggles ^= SOUND_INSTRUMENTS
|
||||
usr.client.prefs.save_preferences()
|
||||
if(usr.client.prefs.toggles & SOUND_INSTRUMENTS)
|
||||
to_chat(usr, "You will now hear people playing musical instruments.")
|
||||
else
|
||||
to_chat(usr, "You will no longer hear musical instruments.")
|
||||
SSblackbox.add_details("preferences_verb","Toggle Instruments|[usr.client.prefs.toggles & SOUND_INSTRUMENTS]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Sound/toggle_instruments/Get_checked(client/C)
|
||||
return C.prefs.toggles & SOUND_INSTRUMENTS
|
||||
|
||||
|
||||
/client/verb/listen_ooc()
|
||||
set name = "Show/Hide OOC"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles seeing OutOfCharacter chat"
|
||||
prefs.chat_toggles ^= CHAT_OOC
|
||||
prefs.save_preferences()
|
||||
to_chat(src, "You will [(prefs.chat_toggles & CHAT_OOC) ? "now" : "no longer"] see messages on the OOC channel.")
|
||||
SSblackbox.add_details("preferences_verb","Toggle Seeing OOC|[prefs.chat_toggles & CHAT_OOC]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/verb/Toggle_Soundscape() //All new ambience should be added here so it works with this verb until someone better at things comes up with a fix that isn't awful
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, Toggle_Soundscape)()
|
||||
set name = "Hear/Silence Ambience"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles hearing ambient sound effects"
|
||||
prefs.toggles ^= SOUND_AMBIENCE
|
||||
prefs.save_preferences()
|
||||
if(prefs.toggles & SOUND_AMBIENCE)
|
||||
to_chat(src, "You will now hear ambient sounds.")
|
||||
set desc = "Hear Ambient Sound Effects"
|
||||
usr.client.prefs.toggles ^= SOUND_AMBIENCE
|
||||
usr.client.prefs.save_preferences()
|
||||
if(usr.client.prefs.toggles & SOUND_AMBIENCE)
|
||||
to_chat(usr, "You will now hear ambient sounds.")
|
||||
else
|
||||
to_chat(src, "You will no longer hear ambient sounds.")
|
||||
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1)
|
||||
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ambience|[prefs.toggles & SOUND_AMBIENCE]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
to_chat(usr, "You will no longer hear ambient sounds.")
|
||||
usr << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1)
|
||||
usr << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ambience|[usr.client.prefs.toggles & SOUND_AMBIENCE]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Sound/Toggle_Soundscape/Get_checked(client/C)
|
||||
return C.prefs.toggles & SOUND_AMBIENCE
|
||||
|
||||
// This needs a toggle because you people are awful and spammed terrible music
|
||||
/client/verb/toggle_instruments()
|
||||
set name = "Hear/Silence Instruments"
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggle_ship_ambience)()
|
||||
set name = "Hear/Silence Ship Ambience"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles hearing musical instruments like the violin and piano"
|
||||
prefs.toggles ^= SOUND_INSTRUMENTS
|
||||
prefs.save_preferences()
|
||||
if(prefs.toggles & SOUND_INSTRUMENTS)
|
||||
to_chat(src, "You will now hear people playing musical instruments.")
|
||||
set desc = "Hear Ship Ambience Roar"
|
||||
usr.client.prefs.toggles ^= SOUND_SHIP_AMBIENCE
|
||||
usr.client.prefs.save_preferences()
|
||||
if(usr.client.prefs.toggles & SOUND_SHIP_AMBIENCE)
|
||||
to_chat(usr, "You will now hear ship ambience.")
|
||||
else
|
||||
to_chat(src, "You will no longer hear musical instruments.")
|
||||
SSblackbox.add_details("preferences_verb","Toggle Instruments|[prefs.toggles & SOUND_INSTRUMENTS]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
to_chat(usr, "You will no longer hear ship ambience.")
|
||||
usr << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)
|
||||
usr.client.ambience_playing = 0
|
||||
SSblackbox.add_details("preferences_verb", "Toggle Ship Ambience|[usr.client.prefs.toggles & SOUND_SHIP_AMBIENCE]") //If you are copy-pasting this, I bet you read this comment expecting to see the same thing :^)
|
||||
/datum/menu/Settings/Sound/toggle_ship_ambience/Get_checked(client/C)
|
||||
return C.prefs.toggles & SOUND_SHIP_AMBIENCE
|
||||
|
||||
//Lots of people get headaches from the normal ship ambience, this is to prevent that
|
||||
/client/verb/toggle_ship_ambience()
|
||||
set name = "Hear/Silence Ship Ambience"
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggle_announcement_sound)()
|
||||
set name = "Hear/Silence Announcements"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles hearing generalized ship ambience, no matter your area."
|
||||
prefs.toggles ^= SOUND_SHIP_AMBIENCE
|
||||
prefs.save_preferences()
|
||||
if(prefs.toggles & SOUND_SHIP_AMBIENCE)
|
||||
to_chat(src, "You will now hear ship ambience.")
|
||||
set desc = "Hear Announcement Sound"
|
||||
usr.client.prefs.toggles ^= SOUND_ANNOUNCEMENTS
|
||||
to_chat(usr, "You will now [(usr.client.prefs.toggles & SOUND_ANNOUNCEMENTS) ? "hear announcement sounds" : "no longer hear announcements"].")
|
||||
usr.client.prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Announcement Sound|[usr.client.prefs.toggles & SOUND_ANNOUNCEMENTS]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/Sound/toggle_announcement_sound/Get_checked(client/C)
|
||||
return C.prefs.toggles & SOUND_ANNOUNCEMENTS
|
||||
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggleprayersounds)()
|
||||
set name = "Hear/Silence Prayer Sounds"
|
||||
set category = "Preferences"
|
||||
set desc = "Hear Prayer Sounds"
|
||||
usr.client.prefs.toggles ^= SOUND_PRAYERS
|
||||
usr.client.prefs.save_preferences()
|
||||
if(usr.client.prefs.toggles & SOUND_PRAYERS)
|
||||
to_chat(usr, "You will now hear prayer sounds.")
|
||||
else
|
||||
to_chat(src, "You will no longer hear ship ambience.")
|
||||
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)
|
||||
src.ambience_playing = 0
|
||||
SSblackbox.add_details("preferences_verb", "Toggle Ship Ambience|[prefs.toggles & SOUND_SHIP_AMBIENCE]") //If you are copy-pasting this, I bet you read this comment expecting to see the same thing :^)
|
||||
to_chat(usr, "You will no longer prayer sounds.")
|
||||
SSblackbox.add_details("admin_toggle", "Toggle Prayer Sounds|[usr.client.prefs.toggles & SOUND_PRAYERS]")
|
||||
/datum/menu/Settings/Sound/toggleprayersounds/Get_checked(client/C)
|
||||
return C.prefs.toggles & SOUND_PRAYERS
|
||||
|
||||
|
||||
/datum/menu/Settings/Sound/verb/stop_client_sounds()
|
||||
set name = "Stop Sounds"
|
||||
set category = "Preferences"
|
||||
set desc = "Stop Current Sounds"
|
||||
usr << sound(null)
|
||||
SSblackbox.add_details("preferences_verb","Stop Self Sounds") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/menu/Settings, listen_ooc)()
|
||||
set name = "Show/Hide OOC"
|
||||
set category = "Preferences"
|
||||
set desc = "Show OOC Chat"
|
||||
usr.client.prefs.chat_toggles ^= CHAT_OOC
|
||||
usr.client.prefs.save_preferences()
|
||||
to_chat(usr, "You will [(usr.client.prefs.chat_toggles & CHAT_OOC) ? "now" : "no longer"] see messages on the OOC channel.")
|
||||
SSblackbox.add_details("preferences_verb","Toggle Seeing OOC|[usr.client.prefs.chat_toggles & CHAT_OOC]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/menu/Settings/listen_ooc/Get_checked(client/C)
|
||||
return C.prefs.chat_toggles & CHAT_OOC
|
||||
|
||||
|
||||
GLOBAL_LIST_INIT(ghost_forms, list("ghost","ghostking","ghostian2","skeleghost","ghost_red","ghost_black", \
|
||||
"ghost_blue","ghost_yellow","ghost_green","ghost_pink", \
|
||||
@@ -246,13 +333,6 @@ GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS
|
||||
prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Intent Selection|[prefs.toggles & INTENT_STYLE]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/verb/setup_character()
|
||||
set name = "Game Preferences"
|
||||
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)
|
||||
|
||||
/client/verb/toggle_ghost_hud_pref()
|
||||
set name = "Toggle Ghost HUD"
|
||||
set category = "Preferences"
|
||||
@@ -278,15 +358,6 @@ GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS
|
||||
to_chat(src, "<span class='notice'>You will no longer examine things you click on.</span>")
|
||||
SSblackbox.add_details("preferences_verb","Toggle Ghost Inquisitiveness|[prefs.inquisitive_ghost]")
|
||||
|
||||
/client/verb/toggle_announcement_sound()
|
||||
set name = "Hear/Silence Announcements"
|
||||
set category = "Preferences"
|
||||
set desc = ".Toggles hearing Central Command, Captain, VOX, and other announcement sounds"
|
||||
prefs.toggles ^= SOUND_ANNOUNCEMENTS
|
||||
to_chat(src, "You will now [(prefs.toggles & SOUND_ANNOUNCEMENTS) ? "hear announcement sounds" : "no longer hear announcements"].")
|
||||
prefs.save_preferences()
|
||||
SSblackbox.add_details("preferences_verb","Toggle Announcement Sound|[prefs.toggles & SOUND_ANNOUNCEMENTS]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
//Admin Preferences
|
||||
/client/proc/toggleadminhelpsound()
|
||||
set name = "Hear/Silence Adminhelps"
|
||||
@@ -338,14 +409,3 @@ GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS
|
||||
to_chat(src, "You will [(prefs.chat_toggles & CHAT_PRAYER) ? "now" : "no longer"] see prayerchat.")
|
||||
SSblackbox.add_details("admin_toggle","Toggle Prayer Visibility|[prefs.chat_toggles & CHAT_PRAYER]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/verb/toggleprayersounds()
|
||||
set name = "Hear/Silence Prayer Sounds"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles hearing pray sounds."
|
||||
prefs.toggles ^= SOUND_PRAYERS
|
||||
prefs.save_preferences()
|
||||
if(prefs.toggles & SOUND_PRAYERS)
|
||||
to_chat(src, "You will now hear prayer sounds.")
|
||||
else
|
||||
to_chat(src, "You will no longer prayer sounds.")
|
||||
SSblackbox.add_details("admin_toggle", "Toggle Prayer Sounds|[prefs.toggles & SOUND_PRAYERS]")
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
return
|
||||
if(confirm == "Yes")
|
||||
suiciding = 1
|
||||
log_game("[key_name(src)] (job: [job ? "[job]" : "None"]) commited suicide at [get_area(src)].")
|
||||
message_admins("[key_name(src)] (job: [job ? "[job]" : "None"]) commited suicide at [get_area(src)].")
|
||||
log_game("[key_name(src)] (job: [job ? "[job]" : "None"]) committed suicide at [get_area(src)].")
|
||||
message_admins("[key_name(src)] (job: [job ? "[job]" : "None"]) committed suicide at [get_area(src)].")
|
||||
var/obj/item/held_item = get_active_held_item()
|
||||
if(held_item)
|
||||
var/damagetype = held_item.suicide_act(src)
|
||||
|
||||
@@ -161,7 +161,9 @@
|
||||
/obj/item/clothing/obj_break(damage_flag)
|
||||
if(!damaged_clothes)
|
||||
update_clothes_damaged_state(TRUE)
|
||||
to_chat(usr, "<span class='notice'>Your [src] starts to fall apart!")
|
||||
if(ismob(loc)) //It's not important enough to warrant a message if nobody's wearing it
|
||||
var/mob/M = loc
|
||||
M.visible_message("<span class='warning'>[M]'s [name] starts to fall apart!", "<span class='warning'>Your [name] starts to fall apart!")
|
||||
|
||||
/obj/item/clothing/proc/update_clothes_damaged_state(damaging = TRUE)
|
||||
var/index = "\ref[initial(icon)]-[initial(icon_state)]"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
vision_flags = 0
|
||||
darkness_view = 2
|
||||
invis_view = SEE_INVISIBLE_LIVING
|
||||
lighting_alpha = null
|
||||
to_chat(user, "<span class='notice'>You toggle the goggles' scanning mode to \[T-Ray].</span>")
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/obj/item/clothing/head/hunter
|
||||
name = "hunter hat"
|
||||
desc = "It's a flimsy looking hat."
|
||||
icon_state = "hunter"
|
||||
icon = 'icons/obj/clothing/cit_hats.dmi'
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
/obj/item/clothing/head/collectable/paper
|
||||
name = "collectable paper hat"
|
||||
desc = "What looks like an ordinary paper hat is actually a rare and valuable collector's edition paper hat. Keep away from water, fire, and Librarians."
|
||||
desc = "What looks like an ordinary paper hat is actually a rare and valuable collector's edition paper hat. Keep away from water, fire, and Curators."
|
||||
icon_state = "paper"
|
||||
|
||||
dog_fashion = /datum/dog_fashion/head
|
||||
|
||||
@@ -158,4 +158,5 @@
|
||||
name = "treasure hunter's fedora"
|
||||
desc = "You got red text today kid, but it doesn't mean you have to like it."
|
||||
icon_state = "curator"
|
||||
armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50)
|
||||
armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50)
|
||||
pockets = /obj/item/weapon/storage/internal/pocket/small
|
||||
@@ -326,9 +326,6 @@
|
||||
disable_flight(1)
|
||||
if(!suit)
|
||||
disable_flight(1)
|
||||
if(!resync)
|
||||
addtimer(CALLBACK(src, .proc/resync), 600)
|
||||
resync = 1
|
||||
if(!wearer) //Oh god our user fell off!
|
||||
disable_flight(1)
|
||||
if(!pressure && brake)
|
||||
@@ -340,12 +337,6 @@
|
||||
stabilizer = FALSE
|
||||
usermessage("Warning: Sensor data is not being recieved from flight shoes. Stabilizers and airbrake modules OFFLINE!", 2)
|
||||
|
||||
//Resync the suit
|
||||
/obj/item/device/flightpack/proc/resync()
|
||||
resync = FALSE
|
||||
suit.resync()
|
||||
|
||||
//How fast should the wearer be?
|
||||
/obj/item/device/flightpack/proc/update_slowdown()
|
||||
if(!flight)
|
||||
suit.slowdown = slowdown_ground
|
||||
@@ -356,20 +347,11 @@
|
||||
/obj/item/device/flightpack/process()
|
||||
if(!suit || (processing_mode == FLIGHTSUIT_PROCESSING_NONE))
|
||||
return FALSE
|
||||
update_slowdown()
|
||||
update_icon()
|
||||
check_conditions()
|
||||
calculate_momentum_speed()
|
||||
momentum_drift()
|
||||
handle_boost()
|
||||
handle_damage()
|
||||
handle_flight()
|
||||
|
||||
/obj/item/device/flightpack/proc/handle_flight()
|
||||
if(!flight)
|
||||
return FALSE
|
||||
if(wearer)
|
||||
wearer.float(TRUE)
|
||||
|
||||
/obj/item/device/flightpack/proc/handle_damage()
|
||||
if(crash_damage)
|
||||
@@ -424,7 +406,6 @@
|
||||
if(boost_charge < boost_maxcharge)
|
||||
boost_charge = Clamp(boost_charge+boost_chargerate, 0, boost_maxcharge)
|
||||
|
||||
|
||||
/obj/item/device/flightpack/proc/cycle_power()
|
||||
if(powersetting < powersetting_high)
|
||||
powersetting++
|
||||
@@ -654,6 +635,8 @@
|
||||
wearer.movement_type |= FLYING
|
||||
wearer.pass_flags |= flight_passflags
|
||||
usermessage("ENGAGING FLIGHT ENGINES.")
|
||||
update_slowdown()
|
||||
wearer.floating = TRUE
|
||||
wearer.visible_message("<font color='blue' size='2'>[wearer]'s flight engines activate as they lift into the air!</font>")
|
||||
//I DONT HAVE SOUND EFFECTS YET playsound(
|
||||
flight = TRUE
|
||||
@@ -670,6 +653,8 @@
|
||||
momentum_x = 0
|
||||
momentum_y = 0
|
||||
usermessage("DISENGAGING FLIGHT ENGINES.")
|
||||
update_slowdown()
|
||||
wearer.floating = FALSE
|
||||
wearer.visible_message("<font color='blue' size='2'>[wearer] drops to the ground as their flight engines cut out!</font>")
|
||||
//NO SOUND YET playsound(
|
||||
ion_trail.stop()
|
||||
@@ -678,6 +663,9 @@
|
||||
flight = FALSE
|
||||
if(suit.shoes)
|
||||
suit.shoes.toggle(FALSE)
|
||||
if(isturf(wearer.loc))
|
||||
var/turf/T = wearer.loc
|
||||
T.Entered(src)
|
||||
else
|
||||
if(override_safe)
|
||||
disable_flight(TRUE)
|
||||
@@ -749,11 +737,13 @@
|
||||
wearer.visible_message("<span class='notice'>[wearer.name]'s flightpack engines flare in intensity as they are rocketed forward by the immense thrust!</span>")
|
||||
boost = TRUE
|
||||
update_slowdown()
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/flightpack/proc/deactivate_booster()
|
||||
usermessage("Boosters disengaged!")
|
||||
boost = FALSE
|
||||
update_slowdown()
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/flightpack/proc/enable_airbrake()
|
||||
if(wearer)
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
item_state = "curator"
|
||||
blood_overlay_type = "coat"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
allowed = list(/obj/item/weapon/tank/internals/emergency_oxygen, /obj/item/weapon/melee/curator_whip)
|
||||
allowed = list(/obj/item/weapon/tank/internals, /obj/item/weapon/melee/curator_whip)
|
||||
armor = list(melee = 25, bullet = 10, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 45)
|
||||
cold_protection = CHEST|ARMS
|
||||
heat_protection = CHEST|ARMS
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
can_adjust = 1
|
||||
alt_covers_chest = 1
|
||||
|
||||
/obj/item/clothing/under/rank/librarian
|
||||
/obj/item/clothing/under/rank/curator
|
||||
name = "sensible suit"
|
||||
desc = "It's very... sensible."
|
||||
icon_state = "red_suit"
|
||||
@@ -145,7 +145,7 @@
|
||||
item_color = "red_suit"
|
||||
can_adjust = 0
|
||||
|
||||
/obj/item/clothing/under/rank/librarian/curator
|
||||
/obj/item/clothing/under/rank/curator/treasure_hunter
|
||||
name = "treasure hunter uniform"
|
||||
desc = "A rugged uniform suitable for treasure hunting."
|
||||
icon_state = "curator"
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
var/scanning = 0
|
||||
var/list/log = list()
|
||||
origin_tech = "engineering=4;biotech=2;programming=5"
|
||||
var/range = 8
|
||||
var/view_check = TRUE
|
||||
|
||||
/obj/item/device/detective_scanner/attack_self(mob/user)
|
||||
if(log.len && !scanning)
|
||||
@@ -43,7 +45,7 @@
|
||||
log = list()
|
||||
scanning = 0
|
||||
|
||||
/obj/item/device/detective_scanner/pre_attackby(atom/A, mob/user, params)
|
||||
/obj/item/device/detective_scanner/afterattack(atom/A, mob/user, params)
|
||||
scan(A, user)
|
||||
return FALSE
|
||||
|
||||
@@ -51,9 +53,7 @@
|
||||
set waitfor = 0
|
||||
if(!scanning)
|
||||
// Can remotely scan objects and mobs.
|
||||
if(!in_range(A, user) && !(A in view(world.view, user)))
|
||||
return
|
||||
if(loc != user)
|
||||
if((get_dist(A, user) > range) || (!(A in view(range, user)) && view_check) || (loc != user))
|
||||
return
|
||||
|
||||
scanning = 1
|
||||
|
||||
@@ -6,7 +6,7 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0)
|
||||
if(!istype(E)) //Something threw an unusual exception
|
||||
log_world("\[[time_stamp()]] Uncaught exception: [E]")
|
||||
return ..()
|
||||
|
||||
|
||||
var/static/list/error_last_seen = list()
|
||||
var/static/list/error_cooldown = list() /* Error_cooldown items will either be positive(cooldown time) or negative(silenced error)
|
||||
If negative, starts at -1, and goes down by 1 each time that error gets skipped*/
|
||||
@@ -107,9 +107,8 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0)
|
||||
if (split[i] != "")
|
||||
split[i] = "\[[time2text(world.timeofday,"hh:mm:ss")]\][split[i]]"
|
||||
E.desc = jointext(split, "\n")
|
||||
if(config && config.log_runtimes)
|
||||
world.log = GLOB.runtime_diary
|
||||
..(E)
|
||||
world.log = GLOB.world_runtime_log
|
||||
..(E)
|
||||
|
||||
world.log = null
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
"sodiumchloride" = list("saltshakersmall", "salt shaker", "Salt. From space oceans, presumably"),
|
||||
"blackpepper" = list("peppermillsmall", "pepper mill", "Often used to flavor food or make people sneeze"),
|
||||
"cornoil" = list("oliveoil", "corn oil bottle", "A delicious oil used in cooking. Made from corn"),
|
||||
"sugar" = list("emptycondiment", "sugar bottle", "Tasty spacey sugar!"))
|
||||
"sugar" = list("emptycondiment", "sugar bottle", "Tasty spacey sugar!"),
|
||||
"mayonnaise" = list("mayonnaise", "mayonnaise jar", "An oily condiment made from egg yolks."))
|
||||
var/originalname = "condiment" //Can't use initial(name) for this. This stores the name set by condimasters.
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/attack(mob/M, mob/user, def_zone)
|
||||
@@ -207,6 +208,13 @@
|
||||
list_reagents = list("soysauce" = 50)
|
||||
possible_states = list()
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/mayonnaise
|
||||
name = "mayonnaise"
|
||||
desc = "An oily condiment made from egg yolks."
|
||||
icon_state = "mayonnaise"
|
||||
list_reagents = list("mayonnaise" = 50)
|
||||
possible_states = list()
|
||||
|
||||
|
||||
|
||||
//Food packs. To easily apply deadly toxi... delicious sauces to your food!
|
||||
|
||||
@@ -468,3 +468,11 @@
|
||||
list_reagents = list("nutriment" = 3, "vitamin" = 2, "sodiumchloride" = 5)
|
||||
bonus_reagents = list("sodiumchloride" = 10)
|
||||
tastes = list("bran" = 4, "raisins" = 3, "salt" = 1)
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/butter
|
||||
name = "stick of butter"
|
||||
desc = "A stick of delicious, golden, fatty goodness."
|
||||
icon_state = "butter"
|
||||
list_reagents = list("nutriment" = 5)
|
||||
filling_color = "#FFD700"
|
||||
tastes = list("butter" = 1)
|
||||
@@ -31,7 +31,7 @@
|
||||
break
|
||||
|
||||
if(!input_plate)
|
||||
GLOB.diary << "a [src] didn't find an input plate."
|
||||
GLOB.world_game_log << "a [src] didn't find an input plate."
|
||||
return
|
||||
|
||||
/obj/machinery/gibber/autogibber/Bumped(atom/A)
|
||||
@@ -168,13 +168,14 @@
|
||||
|
||||
var/offset = prob(50) ? -2 : 2
|
||||
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 200) //start shaking
|
||||
var/sourcename = src.occupant.real_name
|
||||
var/mob/living/mob_occupant = occupant
|
||||
var/sourcename = mob_occupant.real_name
|
||||
var/sourcejob
|
||||
if(ishuman(occupant))
|
||||
var/mob/living/carbon/human/gibee = occupant
|
||||
sourcejob = gibee.job
|
||||
var/sourcenutriment = src.occupant.nutrition / 15
|
||||
var/sourcetotalreagents = src.occupant.reagents.total_volume
|
||||
var/sourcenutriment = mob_occupant.nutrition / 15
|
||||
var/sourcetotalreagents = mob_occupant.reagents.total_volume
|
||||
var/gibtype = /obj/effect/decal/cleanable/blood/gibs
|
||||
var/typeofmeat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human
|
||||
var/typeofskin = /obj/item/stack/sheet/animalhide/human
|
||||
@@ -212,8 +213,8 @@
|
||||
allskin = newskin
|
||||
|
||||
add_logs(user, occupant, "gibbed")
|
||||
src.occupant.death(1)
|
||||
src.occupant.ghostize()
|
||||
mob_occupant.death(1)
|
||||
mob_occupant.ghostize()
|
||||
qdel(src.occupant)
|
||||
spawn(src.gibtime)
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
|
||||
@@ -50,17 +50,22 @@
|
||||
/obj/item/weapon/grown/nettle/pickup(mob/living/user)
|
||||
..()
|
||||
if(!iscarbon(user))
|
||||
return 0
|
||||
return FALSE
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.gloves)
|
||||
return 0
|
||||
return FALSE
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.dna && H.dna.species)
|
||||
if(PIERCEIMMUNE in H.dna.species.species_traits)
|
||||
return FALSE
|
||||
var/hit_zone = (C.held_index_to_dir(C.active_hand_index) == "l" ? "l_":"r_") + "arm"
|
||||
var/obj/item/bodypart/affecting = C.get_bodypart(hit_zone)
|
||||
if(affecting)
|
||||
if(affecting.receive_damage(0, force))
|
||||
C.update_damage_overlays()
|
||||
to_chat(C, "<span class='userdanger'>The nettle burns your bare hand!</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/weapon/grown/nettle/afterattack(atom/A as mob|obj, mob/user,proximity)
|
||||
if(!proximity) return
|
||||
|
||||
@@ -459,7 +459,7 @@ GLOBAL_VAR_CONST(access_away_generic4, 208)
|
||||
|
||||
/proc/get_all_jobs()
|
||||
return list("Assistant", "Captain", "Head of Personnel", "Bartender", "Cook", "Botanist", "Quartermaster", "Cargo Technician",
|
||||
"Shaft Miner", "Clown", "Mime", "Janitor", "Librarian", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer",
|
||||
"Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer",
|
||||
"Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Chemist", "Geneticist", "Virologist",
|
||||
"Research Director", "Scientist", "Roboticist", "Head of Security", "Warden", "Detective", "Security Officer")
|
||||
|
||||
|
||||
@@ -112,11 +112,11 @@ Mime
|
||||
H.mind.miming = 1
|
||||
|
||||
/*
|
||||
Librarian
|
||||
Curator
|
||||
*/
|
||||
/datum/job/librarian
|
||||
title = "Librarian"
|
||||
flag = LIBRARIAN
|
||||
/datum/job/curator
|
||||
title = "Curator"
|
||||
flag = CURATOR
|
||||
department_head = list("Head of Personnel")
|
||||
department_flag = CIVILIAN
|
||||
faction = "Station"
|
||||
@@ -125,33 +125,35 @@ Librarian
|
||||
supervisors = "the head of personnel"
|
||||
selection_color = "#dddddd"
|
||||
|
||||
outfit = /datum/outfit/job/librarian
|
||||
outfit = /datum/outfit/job/curator
|
||||
|
||||
access = list(GLOB.access_library)
|
||||
minimal_access = list(GLOB.access_library)
|
||||
minimal_access = list(GLOB.access_library, GLOB.access_construction,GLOB.access_mining_station)
|
||||
|
||||
/datum/outfit/job/librarian
|
||||
name = "Librarian"
|
||||
jobtype = /datum/job/librarian
|
||||
/datum/outfit/job/curator
|
||||
name = "Curator"
|
||||
jobtype = /datum/job/curator
|
||||
|
||||
belt = /obj/item/device/pda/librarian
|
||||
uniform = /obj/item/clothing/under/rank/librarian
|
||||
belt = /obj/item/device/pda/curator
|
||||
uniform = /obj/item/clothing/under/rank/curator
|
||||
l_hand = /obj/item/weapon/storage/bag/books
|
||||
r_pocket = /obj/item/weapon/barcodescanner
|
||||
r_pocket = /obj/item/key/displaycase
|
||||
l_pocket = /obj/item/device/laser_pointer
|
||||
backpack_contents = list(
|
||||
/obj/item/soapstone = 1
|
||||
/obj/item/weapon/melee/curator_whip = 1,
|
||||
/obj/item/soapstone = 1,
|
||||
/obj/item/weapon/barcodescanner = 1
|
||||
)
|
||||
|
||||
|
||||
/datum/outfit/job/librarian/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
H.grant_all_languages(omnitongue=TRUE)
|
||||
|
||||
|
||||
/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
H.grant_all_languages(omnitongue=TRUE)
|
||||
|
||||
/*
|
||||
Lawyer
|
||||
*/
|
||||
|
||||
@@ -39,7 +39,7 @@ GLOBAL_LIST_INIT(civilian_positions, list(
|
||||
"Botanist",
|
||||
"Cook",
|
||||
"Janitor",
|
||||
"Librarian",
|
||||
"Curator",
|
||||
"Lawyer",
|
||||
"Chaplain",
|
||||
"Clown",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
var/speed = 300
|
||||
var/correctness = 85
|
||||
var/willpower = 98
|
||||
if(U.job in list("Librarian")) // the librarian is both faster, and more accurate than normal crew members at research
|
||||
if(U.job in list("Curator")) // the curator is both faster, and more accurate than normal crew members at research
|
||||
speed = 45
|
||||
correctness = 100
|
||||
willpower = 100
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
------------
|
||||
A place for the crew to go, relax, and enjoy a good book.
|
||||
Aspiring authors can even self publish and, if they're lucky
|
||||
convince the on-staff Librarian to submit it to the Archives
|
||||
convince the on-staff Curator to submit it to the Archives
|
||||
to be chronicled in history forever - some say even persisting
|
||||
through alternate dimensions.
|
||||
|
||||
@@ -49,12 +49,12 @@
|
||||
|
||||
// Ideas for the future
|
||||
// ---------------------
|
||||
// - Visitor's computer should be able to search the current in-round library inventory (that the Librarian has stocked and checked in)
|
||||
// - Visitor's computer should be able to search the current in-round library inventory (that the Curator has stocked and checked in)
|
||||
// -- Give computer other features like an Instant Messenger application, or the ability to edit, save, and print documents.
|
||||
// - Admin interface directly tied to the Archive DB. Right now there's no way to delete uploaded books in-game.
|
||||
// -- If this gets implemented, allow Librarians to "tag" or "suggest" books to be deleted. The DB ID of the tagged books gets saved to a text file (or another table in the DB maybe?).
|
||||
// -- If this gets implemented, allow Curators to "tag" or "suggest" books to be deleted. The DB ID of the tagged books gets saved to a text file (or another table in the DB maybe?).
|
||||
// The admin interface would automatically take these IDs and SELECT them all from the DB to be displayed along with a Delete link to drop the row from the table.
|
||||
// - When the game sets up and the round begins, have it automatically pick random books from the DB to populate the library with. Even if the Librarian is a useless fuck there are at least a few books around.
|
||||
// - When the game sets up and the round begins, have it automatically pick random books from the DB to populate the library with. Even if the Curator is a useless fuck there are at least a few books around.
|
||||
// - Allow books to be "hollowed out" like the Chaplain's Bible, allowing you to store one pocket-sized item inside.
|
||||
// - Make books/book cases burn when exposed to flame.
|
||||
// - Make book binder hackable.
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
as instructions and/or memes for the next generation of spessmen.
|
||||
|
||||
Limited in location to station_z only. Can be smashed out or exploded,
|
||||
but only permamently removed with the librarian's soapstone.
|
||||
but only permamently removed with the curator's soapstone.
|
||||
*/
|
||||
|
||||
/obj/item/soapstone/infinite
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST))
|
||||
|
||||
/datum/lighting_corner
|
||||
var/list/turf/masters = list()
|
||||
var/list/datum/light_source/affecting = list() // Light sources affecting us.
|
||||
var/list/turf/masters
|
||||
var/list/datum/light_source/affecting // Light sources affecting us.
|
||||
var/active = FALSE // TRUE if one of our masters has dynamic lighting.
|
||||
|
||||
var/x = 0
|
||||
@@ -25,11 +25,9 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
|
||||
var/cache_b = LIGHTING_SOFT_THRESHOLD
|
||||
var/cache_mx = 0
|
||||
|
||||
var/update_gen = 0
|
||||
|
||||
/datum/lighting_corner/New(var/turf/new_turf, var/diagonal)
|
||||
. = ..()
|
||||
|
||||
masters = list()
|
||||
masters[new_turf] = turn(diagonal, 180)
|
||||
z = new_turf.z
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ GLOBAL_LIST_EMPTY(all_lighting_objects) // Global list of lighting objects.
|
||||
anchored = TRUE
|
||||
|
||||
icon = LIGHTING_ICON
|
||||
icon_state = "transparent"
|
||||
color = LIGHTING_BASE_MATRIX
|
||||
plane = LIGHTING_PLANE
|
||||
mouse_opacity = 0
|
||||
@@ -16,7 +17,7 @@ GLOBAL_LIST_EMPTY(all_lighting_objects) // Global list of lighting objects.
|
||||
|
||||
var/needs_update = FALSE
|
||||
|
||||
/atom/movable/lighting_object/Initialize(mapload, var/no_update = FALSE)
|
||||
/atom/movable/lighting_object/Initialize(mapload)
|
||||
. = ..()
|
||||
verbs.Cut()
|
||||
GLOB.all_lighting_objects += src
|
||||
@@ -28,10 +29,8 @@ GLOBAL_LIST_EMPTY(all_lighting_objects) // Global list of lighting objects.
|
||||
for(var/turf/open/space/S in RANGE_TURFS(1, src)) //RANGE_TURFS is in code\__HELPERS\game.dm
|
||||
S.update_starlight()
|
||||
|
||||
if (no_update)
|
||||
return
|
||||
|
||||
update()
|
||||
needs_update = TRUE
|
||||
GLOB.lighting_update_objects += src
|
||||
|
||||
/atom/movable/lighting_object/Destroy(var/force)
|
||||
if (force)
|
||||
@@ -69,10 +68,17 @@ GLOBAL_LIST_EMPTY(all_lighting_objects) // Global list of lighting objects.
|
||||
|
||||
// See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are.
|
||||
var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new
|
||||
var/datum/lighting_corner/cr = T.corners[3] || dummy_lighting_corner
|
||||
var/datum/lighting_corner/cg = T.corners[2] || dummy_lighting_corner
|
||||
var/datum/lighting_corner/cb = T.corners[4] || dummy_lighting_corner
|
||||
var/datum/lighting_corner/ca = T.corners[1] || dummy_lighting_corner
|
||||
|
||||
var/list/corners = T.corners
|
||||
var/datum/lighting_corner/cr = dummy_lighting_corner
|
||||
var/datum/lighting_corner/cg = dummy_lighting_corner
|
||||
var/datum/lighting_corner/cb = dummy_lighting_corner
|
||||
var/datum/lighting_corner/ca = dummy_lighting_corner
|
||||
if (corners) //done this way for speed
|
||||
cr = corners[3] || dummy_lighting_corner
|
||||
cg = corners[2] || dummy_lighting_corner
|
||||
cb = corners[4] || dummy_lighting_corner
|
||||
ca = corners[1] || dummy_lighting_corner
|
||||
|
||||
var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx)
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
if(!IS_DYNAMIC_LIGHTING(T))
|
||||
continue
|
||||
|
||||
new/atom/movable/lighting_object(T, TRUE)
|
||||
new/atom/movable/lighting_object(T)
|
||||
CHECK_TICK
|
||||
CHECK_TICK
|
||||
|
||||
@@ -26,22 +26,15 @@
|
||||
|
||||
var/applied = FALSE // Whether we have applied our light yet or not.
|
||||
|
||||
var/vis_update // Whether we should smartly recalculate visibility. and then only update tiles that became (in)visible to us.
|
||||
var/needs_update // Whether we are queued for an update.
|
||||
var/force_update
|
||||
var/needs_update = LIGHTING_NO_UPDATE // Whether we are queued for an update.
|
||||
|
||||
|
||||
/datum/light_source/New(var/atom/owner, var/atom/top)
|
||||
source_atom = owner // Set our new owner.
|
||||
if (!source_atom.light_sources)
|
||||
source_atom.light_sources = list()
|
||||
|
||||
source_atom.light_sources += src // Add us to the lights of our owner.
|
||||
LAZYADD(source_atom.light_sources, src)
|
||||
top_atom = top
|
||||
if (top_atom != source_atom)
|
||||
if (!top.light_sources)
|
||||
top.light_sources = list()
|
||||
|
||||
top_atom.light_sources += src
|
||||
LAZYADD(top_atom.light_sources, src)
|
||||
|
||||
source_turf = top_atom
|
||||
pixel_turf = get_turf_pixel(top_atom) || source_turf
|
||||
@@ -52,20 +45,18 @@
|
||||
|
||||
parse_light_color()
|
||||
|
||||
effect_str = list()
|
||||
affecting_turfs = list()
|
||||
|
||||
update()
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/light_source/Destroy(force)
|
||||
force_update()
|
||||
remove_lum()
|
||||
if (source_atom)
|
||||
source_atom.light_sources -= src
|
||||
LAZYREMOVE(source_atom.light_sources, src)
|
||||
|
||||
if (top_atom)
|
||||
top_atom.light_sources -= src
|
||||
LAZYREMOVE(top_atom.light_sources, src)
|
||||
|
||||
. = ..()
|
||||
if(!force)
|
||||
return QDEL_HINT_IWILLGC
|
||||
@@ -73,79 +64,34 @@
|
||||
// Yes this doesn't align correctly on anything other than 4 width tabs.
|
||||
// If you want it to go switch everybody to elastic tab stops.
|
||||
// Actually that'd be great if you could!
|
||||
#define EFFECT_UPDATE \
|
||||
if (!needs_update) \
|
||||
{ \
|
||||
GLOB.lighting_update_lights += src; \
|
||||
needs_update = TRUE; \
|
||||
}
|
||||
#define EFFECT_UPDATE(level) \
|
||||
if (needs_update == LIGHTING_NO_UPDATE) \
|
||||
GLOB.lighting_update_lights += src; \
|
||||
if (needs_update < level) \
|
||||
needs_update = level; \
|
||||
|
||||
|
||||
// This proc will cause the light source to update the top atom, and add itself to the update queue.
|
||||
/datum/light_source/proc/update(var/atom/new_top_atom)
|
||||
// This top atom is different.
|
||||
if (new_top_atom && new_top_atom != top_atom)
|
||||
if(top_atom != source_atom && top_atom.light_sources) // Remove ourselves from the light sources of that top atom.
|
||||
top_atom.light_sources -= src
|
||||
LAZYREMOVE(top_atom.light_sources, src)
|
||||
|
||||
top_atom = new_top_atom
|
||||
|
||||
if (top_atom != source_atom)
|
||||
LAZYADD(top_atom.light_sources, src) // Add ourselves to the light sources of our new top atom.
|
||||
|
||||
EFFECT_UPDATE
|
||||
EFFECT_UPDATE(LIGHTING_CHECK_UPDATE)
|
||||
|
||||
// Will force an update without checking if it's actually needed.
|
||||
/datum/light_source/proc/force_update()
|
||||
force_update = 1
|
||||
|
||||
EFFECT_UPDATE
|
||||
EFFECT_UPDATE(LIGHTING_FORCE_UPDATE)
|
||||
|
||||
// Will cause the light source to recalculate turfs that were removed or added to visibility only.
|
||||
/datum/light_source/proc/vis_update()
|
||||
vis_update = 1
|
||||
|
||||
EFFECT_UPDATE
|
||||
|
||||
// Will check if we actually need to update, and update any variables that may need to be updated.
|
||||
/datum/light_source/proc/check()
|
||||
if (!source_atom || !light_range || !light_power)
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
if (!top_atom)
|
||||
top_atom = source_atom
|
||||
. = 1
|
||||
|
||||
if (isturf(top_atom))
|
||||
if (source_turf != top_atom)
|
||||
source_turf = top_atom
|
||||
pixel_turf = source_turf
|
||||
. = 1
|
||||
else if (top_atom.loc != source_turf)
|
||||
source_turf = top_atom.loc
|
||||
pixel_turf = get_turf_pixel(top_atom)
|
||||
. = 1
|
||||
else
|
||||
var/P = get_turf_pixel(top_atom)
|
||||
if (P != pixel_turf)
|
||||
. = 1
|
||||
pixel_turf = get_turf_pixel(top_atom)
|
||||
|
||||
if (source_atom.light_power != light_power)
|
||||
light_power = source_atom.light_power
|
||||
. = 1
|
||||
|
||||
if (source_atom.light_range != light_range)
|
||||
light_range = source_atom.light_range
|
||||
. = 1
|
||||
|
||||
if (light_range && light_power && !applied)
|
||||
. = 1
|
||||
|
||||
if (source_atom.light_color != light_color)
|
||||
light_color = source_atom.light_color
|
||||
parse_light_color()
|
||||
. = 1
|
||||
EFFECT_UPDATE(LIGHTING_VIS_UPDATE)
|
||||
|
||||
// Decompile the hexadecimal colour into lumcounts of each perspective.
|
||||
/datum/light_source/proc/parse_light_color()
|
||||
@@ -164,48 +110,47 @@
|
||||
// As such this all gets counted as a single line.
|
||||
// The braces and semicolons are there to be able to do this on a single line.
|
||||
#define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range)))
|
||||
#define APPLY_CORNER(C) \
|
||||
. = LUM_FALLOFF(C, pixel_turf); \
|
||||
\
|
||||
. *= light_power; \
|
||||
\
|
||||
effect_str[C] = .; \
|
||||
\
|
||||
C.update_lumcount \
|
||||
( \
|
||||
. * applied_lum_r, \
|
||||
. * applied_lum_g, \
|
||||
. * applied_lum_b \
|
||||
|
||||
#define APPLY_CORNER(C) \
|
||||
. = LUM_FALLOFF(C, pixel_turf); \
|
||||
. *= light_power; \
|
||||
var/OLD = effect_str[C]; \
|
||||
\
|
||||
effect_str[C] = .; \
|
||||
\
|
||||
C.update_lumcount \
|
||||
( \
|
||||
(. * lum_r) - (OLD * applied_lum_r), \
|
||||
(. * lum_g) - (OLD * applied_lum_g), \
|
||||
(. * lum_b) - (OLD * applied_lum_b) \
|
||||
);
|
||||
|
||||
// I don't need to explain what this does, do I?
|
||||
#define REMOVE_CORNER(C) \
|
||||
. = -effect_str[C]; \
|
||||
C.update_lumcount \
|
||||
( \
|
||||
. * applied_lum_r, \
|
||||
. * applied_lum_g, \
|
||||
. * applied_lum_b \
|
||||
|
||||
#define REMOVE_CORNER(C) \
|
||||
. = -effect_str[C]; \
|
||||
C.update_lumcount \
|
||||
( \
|
||||
. * applied_lum_r, \
|
||||
. * applied_lum_g, \
|
||||
. * applied_lum_b \
|
||||
);
|
||||
|
||||
// This is the define used to calculate falloff.
|
||||
|
||||
|
||||
/*
|
||||
/datum/light_source/proc/apply_lum()
|
||||
var/static/update_gen = 1
|
||||
applied = 1
|
||||
|
||||
// Keep track of the last applied lum values so that the lighting can be reversed
|
||||
applied_lum_r = lum_r
|
||||
applied_lum_g = lum_g
|
||||
applied_lum_b = lum_b
|
||||
var/thing
|
||||
var/datum/lighting_corner/C
|
||||
var/corners = list()
|
||||
LAZYINITLIST(effect_str)
|
||||
FOR_DVIEW(var/turf/T, light_range+1, source_turf, INVISIBILITY_LIGHTING)
|
||||
if (!T.lighting_corners_initialised)
|
||||
T.generate_missing_corners()
|
||||
var/list/turf_corners = T.get_corners()
|
||||
|
||||
for (thing in T.get_corners())
|
||||
for (thing in turf_corners)
|
||||
C = thing
|
||||
if (C.update_gen == update_gen)
|
||||
continue
|
||||
@@ -220,9 +165,13 @@
|
||||
APPLY_CORNER(C)
|
||||
|
||||
LAZYADD(T.affecting_lights, src)
|
||||
affecting_turfs += T
|
||||
LAZYADD(affecting_turfs, T)
|
||||
FOR_DVIEW_END
|
||||
update_gen++
|
||||
applied_lum_r = lum_r
|
||||
applied_lum_g = lum_g
|
||||
applied_lum_b = lum_b
|
||||
*/
|
||||
|
||||
/datum/light_source/proc/remove_lum()
|
||||
applied = FALSE
|
||||
@@ -231,7 +180,7 @@
|
||||
var/turf/T = thing
|
||||
LAZYREMOVE(T.affecting_lights, src)
|
||||
|
||||
affecting_turfs.Cut()
|
||||
affecting_turfs = null
|
||||
|
||||
var/datum/lighting_corner/C
|
||||
for (thing in effect_str)
|
||||
@@ -240,30 +189,93 @@
|
||||
|
||||
LAZYREMOVE(C.affecting, src)
|
||||
|
||||
effect_str.Cut()
|
||||
effect_str = null
|
||||
|
||||
/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C)
|
||||
if (effect_str.Find(C)) // Already have one.
|
||||
LAZYINITLIST(effect_str)
|
||||
if (effect_str[C]) // Already have one.
|
||||
REMOVE_CORNER(C)
|
||||
effect_str[C] = 0
|
||||
|
||||
APPLY_CORNER(C)
|
||||
UNSETEMPTY(effect_str)
|
||||
|
||||
/datum/light_source/proc/update_corners()
|
||||
var/update = FALSE
|
||||
|
||||
if (!source_atom || QDELETED(source_atom))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if (source_atom.light_power != light_power)
|
||||
light_power = source_atom.light_power
|
||||
update = TRUE
|
||||
|
||||
if (source_atom.light_range != light_range)
|
||||
light_range = source_atom.light_range
|
||||
update = TRUE
|
||||
|
||||
if (!top_atom)
|
||||
top_atom = source_atom
|
||||
update = TRUE
|
||||
|
||||
if (!light_range || !light_power)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if (isturf(top_atom))
|
||||
if (source_turf != top_atom)
|
||||
source_turf = top_atom
|
||||
pixel_turf = source_turf
|
||||
update = TRUE
|
||||
else if (top_atom.loc != source_turf)
|
||||
source_turf = top_atom.loc
|
||||
pixel_turf = get_turf_pixel(top_atom)
|
||||
update = TRUE
|
||||
else
|
||||
var/P = get_turf_pixel(top_atom)
|
||||
if (P != pixel_turf)
|
||||
pixel_turf = P
|
||||
update = TRUE
|
||||
|
||||
if (!isturf(source_turf))
|
||||
if (applied)
|
||||
remove_lum()
|
||||
return
|
||||
|
||||
if (light_range && light_power && !applied)
|
||||
update = TRUE
|
||||
|
||||
if (source_atom.light_color != light_color)
|
||||
light_color = source_atom.light_color
|
||||
parse_light_color()
|
||||
update = TRUE
|
||||
|
||||
else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b)
|
||||
update = TRUE
|
||||
|
||||
if (update)
|
||||
needs_update = LIGHTING_CHECK_UPDATE
|
||||
applied = TRUE
|
||||
else if (needs_update == LIGHTING_CHECK_UPDATE)
|
||||
return //nothing's changed
|
||||
|
||||
/datum/light_source/proc/smart_vis_update()
|
||||
var/list/datum/lighting_corner/corners = list()
|
||||
var/list/turf/turfs = list()
|
||||
var/thing
|
||||
var/datum/lighting_corner/C
|
||||
var/turf/T
|
||||
if (source_turf)
|
||||
var/oldlum = source_turf.luminosity
|
||||
source_turf.luminosity = Ceiling(light_range)
|
||||
for(T in view(Ceiling(light_range), source_turf))
|
||||
for (thing in T.get_corners(source_turf))
|
||||
C = thing
|
||||
corners[C] = 0
|
||||
turfs += T
|
||||
source_turf.luminosity = oldlum
|
||||
|
||||
FOR_DVIEW(T, light_range+1, source_turf, 0)
|
||||
if (!T.lighting_corners_initialised)
|
||||
T.generate_missing_corners()
|
||||
for (thing in T.get_corners(source_turf))
|
||||
C = thing
|
||||
corners[C] = 0
|
||||
turfs += T
|
||||
FOR_DVIEW_END
|
||||
|
||||
LAZYINITLIST(affecting_turfs)
|
||||
var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them.
|
||||
affecting_turfs += L
|
||||
for (thing in L)
|
||||
@@ -276,22 +288,45 @@
|
||||
T = thing
|
||||
LAZYREMOVE(T.affecting_lights, src)
|
||||
|
||||
LAZYINITLIST(effect_str)
|
||||
if (needs_update == LIGHTING_VIS_UPDATE)
|
||||
for (thing in corners - effect_str) // New corners
|
||||
C = thing
|
||||
LAZYADD(C.affecting, src)
|
||||
if (!C.active)
|
||||
effect_str[C] = 0
|
||||
continue
|
||||
APPLY_CORNER(C)
|
||||
else
|
||||
L = corners - effect_str
|
||||
for (thing in L) // New corners
|
||||
C = thing
|
||||
LAZYADD(C.affecting, src)
|
||||
if (!C.active)
|
||||
effect_str[C] = 0
|
||||
continue
|
||||
APPLY_CORNER(C)
|
||||
|
||||
for (thing in corners - L) // Existing corners
|
||||
C = thing
|
||||
if (!C.active)
|
||||
effect_str[C] = 0
|
||||
continue
|
||||
APPLY_CORNER(C)
|
||||
|
||||
for (thing in corners - effect_str) // New corners
|
||||
C = thing
|
||||
LAZYADD(C.affecting, src)
|
||||
if (!C.active)
|
||||
effect_str[C] = 0
|
||||
continue
|
||||
|
||||
APPLY_CORNER(C)
|
||||
|
||||
for (thing in effect_str - corners) // Old, now gone, corners.
|
||||
L = effect_str - corners
|
||||
for (thing in L) // Old, now gone, corners.
|
||||
C = thing
|
||||
REMOVE_CORNER(C)
|
||||
LAZYREMOVE(C.affecting, src)
|
||||
effect_str -= C
|
||||
effect_str -= L
|
||||
|
||||
applied_lum_r = lum_r
|
||||
applied_lum_g = lum_g
|
||||
applied_lum_b = lum_b
|
||||
|
||||
UNSETEMPTY(effect_str)
|
||||
UNSETEMPTY(affecting_turfs)
|
||||
|
||||
#undef EFFECT_UPDATE
|
||||
#undef LUM_FALLOFF
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
return
|
||||
|
||||
var/area/A = loc
|
||||
if (!IS_DYNAMIC_LIGHTING(A))
|
||||
if (!IS_DYNAMIC_LIGHTING(A) && !light_sources)
|
||||
return
|
||||
|
||||
if (!lighting_corners_initialised)
|
||||
@@ -113,12 +113,18 @@
|
||||
lighting_clear_overlay()
|
||||
|
||||
/turf/proc/get_corners()
|
||||
if (!IS_DYNAMIC_LIGHTING(src) && !light_sources)
|
||||
return null
|
||||
if (!lighting_corners_initialised)
|
||||
generate_missing_corners()
|
||||
if (has_opaque_atom)
|
||||
return null // Since this proc gets used in a for loop, null won't be looped though.
|
||||
|
||||
return corners
|
||||
|
||||
/turf/proc/generate_missing_corners()
|
||||
if (!IS_DYNAMIC_LIGHTING(src) && !light_sources)
|
||||
return
|
||||
lighting_corners_initialised = TRUE
|
||||
if (!corners)
|
||||
corners = list(null, null, null, null)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
desc = "It's watching you suspiciously."
|
||||
|
||||
/obj/structure/closet/crate/necropolis/tendril/PopulateContents()
|
||||
var/loot = rand(1,25)
|
||||
var/loot = rand(1,26)
|
||||
switch(loot)
|
||||
if(1)
|
||||
new /obj/item/device/shared_storage/red(src)
|
||||
@@ -33,7 +33,7 @@
|
||||
if(9)
|
||||
new /obj/item/organ/brain/alien(src)
|
||||
if(10)
|
||||
new /obj/item/organ/heart/cursed(src)
|
||||
new /obj/item/organ/heart/cursed/wizard(src)
|
||||
if(11)
|
||||
new /obj/item/ship_in_a_bottle(src)
|
||||
if(12)
|
||||
@@ -65,6 +65,8 @@
|
||||
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor(src)
|
||||
if(25)
|
||||
new /obj/item/weapon/spellbook/oneuse/summonitem(src)
|
||||
if(26)
|
||||
new /obj/item/book_of_babel(src)
|
||||
|
||||
|
||||
|
||||
@@ -343,6 +345,24 @@
|
||||
add_fingerprint(usr)
|
||||
|
||||
|
||||
|
||||
|
||||
//Book of Babel
|
||||
|
||||
/obj/item/book_of_babel
|
||||
name = "Book of Babel"
|
||||
desc = "An ancient tome written in countless tongues."
|
||||
icon = 'icons/obj/library.dmi'
|
||||
icon_state = "book1"
|
||||
w_class = 2
|
||||
|
||||
/obj/item/book_of_babel/attack_self(mob/user)
|
||||
to_chat(user, "You flip through the pages of the book, quickly and conveniently learning every language in existence. Somewhat less conveniently, the aging book crumbles to dust in the process. Whoops.")
|
||||
user.grant_all_languages(omnitongue=TRUE)
|
||||
new /obj/effect/decal/cleanable/ash(get_turf(user))
|
||||
qdel(src)
|
||||
|
||||
|
||||
//Boat
|
||||
|
||||
/obj/vehicle/lavaboat
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
if(D.make_reagents.len)
|
||||
return 0
|
||||
|
||||
var/build_amount = 1
|
||||
var/build_amount = 0
|
||||
|
||||
for(var/mat_id in D.materials)
|
||||
var/M = D.materials[mat_id]
|
||||
@@ -93,7 +93,15 @@
|
||||
if(!M || !redemption_mat)
|
||||
return 0
|
||||
|
||||
build_amount = min(build_amount, round(redemption_mat.amount / M))
|
||||
var/smeltable_sheets = round(redemption_mat.amount / M)
|
||||
|
||||
if(!smeltable_sheets)
|
||||
return 0
|
||||
|
||||
if(!build_amount)
|
||||
build_amount = smeltable_sheets
|
||||
|
||||
build_amount = min(build_amount, smeltable_sheets)
|
||||
|
||||
return build_amount
|
||||
|
||||
@@ -152,6 +160,7 @@
|
||||
if(exchange_parts(user, W))
|
||||
return
|
||||
if(default_pry_open(W))
|
||||
materials.retrieve_all()
|
||||
return
|
||||
if(default_unfasten_wrench(user, W))
|
||||
return
|
||||
|
||||
@@ -193,9 +193,7 @@
|
||||
qdel(voucher)
|
||||
|
||||
/obj/machinery/mineral/equipment_vendor/ex_act(severity, target)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
do_sparks(5, TRUE, src)
|
||||
if(prob(50 / severity) && severity < 3)
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
INITIALIZE_IMMEDIATE(/mob/dead)
|
||||
|
||||
/mob/dead/Initialize()
|
||||
. = ..()
|
||||
if(initialized)
|
||||
stack_trace("Warning: [src]([type]) initialized multiple times!")
|
||||
tag = "mob_[next_mob_id++]"
|
||||
GLOB.mob_list += src
|
||||
|
||||
prepare_huds()
|
||||
|
||||
if(config.cross_allowed)
|
||||
verbs += /mob/dead/proc/server_hop
|
||||
return INITIALIZE_HINT_NORMAL
|
||||
|
||||
/mob/dead/dust() //ghosts can't be vaporised.
|
||||
return
|
||||
|
||||
@@ -16,12 +16,6 @@
|
||||
var/mob/living/new_character //for instant transfer once the round is set up
|
||||
|
||||
/mob/dead/new_player/Initialize()
|
||||
if(initialized)
|
||||
stack_trace("Warning: [src]([type]) initialized multiple times!")
|
||||
initialized = TRUE
|
||||
tag = "mob_[next_mob_id++]"
|
||||
GLOB.mob_list += src
|
||||
|
||||
if(client && SSticker.state == GAME_STATE_STARTUP)
|
||||
var/obj/screen/splash/S = new(client, TRUE, TRUE)
|
||||
S.Fade(TRUE)
|
||||
@@ -30,7 +24,10 @@
|
||||
loc = pick(GLOB.newplayer_start)
|
||||
else
|
||||
loc = locate(1,1,1)
|
||||
return INITIALIZE_HINT_NORMAL
|
||||
. = ..()
|
||||
|
||||
/mob/dead/new_player/prepare_huds()
|
||||
return
|
||||
|
||||
/mob/dead/new_player/proc/new_player_panel()
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
var/deadchat_name
|
||||
|
||||
/mob/dead/observer/Initialize()
|
||||
invisibility = GLOB.observer_default_invisibility
|
||||
set_invisibility(GLOB.observer_default_invisibility)
|
||||
|
||||
verbs += /mob/dead/observer/proc/dead_tele
|
||||
|
||||
@@ -118,6 +118,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
animate(src, pixel_y = 2, time = 10, loop = -1)
|
||||
|
||||
grant_all_languages()
|
||||
GLOB.dead_mob_list += src
|
||||
..()
|
||||
|
||||
/mob/dead/observer/narsie_act()
|
||||
@@ -787,13 +788,25 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(!invisibility)
|
||||
to_chat(user, "It seems extremely obvious.")
|
||||
|
||||
/mob/dead/observer/proc/set_invisibility(value)
|
||||
invisibility = value
|
||||
if(!value)
|
||||
set_light(1, 2)
|
||||
else
|
||||
set_light(0, 0)
|
||||
|
||||
// Ghosts have no momentum, being massless ectoplasm
|
||||
/mob/dead/observer/Process_Spacemove(movement_dir)
|
||||
return 1
|
||||
|
||||
/mob/dead/observer/vv_edit_var(var_name, var_value)
|
||||
. = ..()
|
||||
if(var_name == "invisibility")
|
||||
set_invisibility(invisibility) // updates light
|
||||
|
||||
/proc/set_observer_default_invisibility(amount, message=null)
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
G.invisibility = amount
|
||||
G.set_invisibility(amount)
|
||||
if(message)
|
||||
to_chat(G, message)
|
||||
GLOB.observer_default_invisibility = amount
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
to_follow = V.source
|
||||
var/link = FOLLOW_LINK(src, to_follow)
|
||||
// Recompose the message, because it's scrambled by default
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans)
|
||||
to_chat(src, "[link] [message]")
|
||||
|
||||
|
||||
@@ -87,6 +87,8 @@
|
||||
owner.adjustFireLoss(-heal_amt)
|
||||
owner.adjustOxyLoss(-heal_amt)
|
||||
owner.adjustCloneLoss(-heal_amt)
|
||||
else
|
||||
owner.adjustPlasma(plasma_rate * 0.1)
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/Insert(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
|
||||
@@ -484,7 +484,7 @@
|
||||
adjustBruteLoss(3)
|
||||
else
|
||||
if(T)
|
||||
T.add_vomit_floor(src, 0)//toxic barf looks different
|
||||
T.add_vomit_floor(src, toxic)//toxic barf looks different
|
||||
nutrition -= lost_nutrition
|
||||
adjustToxLoss(-3)
|
||||
T = get_step(T, dir)
|
||||
@@ -492,6 +492,16 @@
|
||||
break
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/proc/spew_organ(power = 5)
|
||||
if(!internal_organs.len)
|
||||
return //Guess we're out of organs
|
||||
var/obj/item/organ/guts = pick(internal_organs)
|
||||
var/turf/T = get_turf(src)
|
||||
guts.Remove(src)
|
||||
guts.forceMove(T)
|
||||
var/atom/throw_target = get_edge_target_turf(guts, dir)
|
||||
guts.throw_at(throw_target, power, 4, src)
|
||||
|
||||
|
||||
/mob/living/carbon/fully_replace_character_name(oldname,newname)
|
||||
..()
|
||||
|
||||
@@ -119,9 +119,7 @@
|
||||
visible_message("<span class='danger'>The [M.name] has shocked [src]!</span>", \
|
||||
"<span class='userdanger'>The [M.name] has shocked [src]!</span>")
|
||||
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
do_sparks(5, TRUE, src)
|
||||
var/power = M.powerlevel + rand(0,3)
|
||||
Weaken(power)
|
||||
if(stuttering < power)
|
||||
|
||||
@@ -68,6 +68,17 @@
|
||||
if(!isnum(text2num(params)))
|
||||
return message
|
||||
|
||||
/datum/emote/sound/carbon/snap
|
||||
key = "snap"
|
||||
key_third_person = "snaps"
|
||||
message = "snaps their fingers."
|
||||
muzzle_ignore = TRUE
|
||||
restraint_check = TRUE
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
sound = 'sound/effects/snap01.ogg'
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/)
|
||||
|
||||
|
||||
/datum/emote/living/carbon/sign/signal
|
||||
key = "signal"
|
||||
key_third_person = "signals"
|
||||
|
||||
@@ -171,5 +171,8 @@
|
||||
dna.species.mutant_bodyparts -= "wingsopen"
|
||||
dna.species.mutant_bodyparts |= "wings"
|
||||
update_body()
|
||||
if(isturf(loc))
|
||||
var/turf/T = loc
|
||||
T.Entered(src)
|
||||
|
||||
//Ayy lmao
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
if(stat == DEAD || (status_flags & FAKEDEATH))
|
||||
appears_dead = 1
|
||||
if(suiciding)
|
||||
msg += "<span class='warning'>[t_He] appear[p_s()] to have commited suicide... there is no hope of recovery.</span>\n"
|
||||
msg += "<span class='warning'>[t_He] appear[p_s()] to have committed suicide... there is no hope of recovery.</span>\n"
|
||||
if(hellbound)
|
||||
msg += "<span class='warning'>[t_His] soul seems to have been ripped out of [t_his] body. Revival is impossible.</span>\n"
|
||||
msg += "<span class='deadsay'>[t_He] [t_is] limp and unresponsive; there are no signs of life"
|
||||
|
||||
@@ -142,10 +142,12 @@
|
||||
return not_handled //For future deeper overrides
|
||||
|
||||
/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE)
|
||||
var/index = get_held_index_of_item(I)
|
||||
. = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should.
|
||||
if(!. || !I)
|
||||
return
|
||||
|
||||
if(index && dna.species.mutanthands)
|
||||
put_in_hand(new dna.species.mutanthands(), index)
|
||||
if(I == wear_suit)
|
||||
if(s_store && invdrop)
|
||||
dropItemToGround(s_store, TRUE) //It makes no sense for your suit storage to stay on you if you drop your suit.
|
||||
|
||||
@@ -71,6 +71,9 @@
|
||||
//Ears
|
||||
var/obj/item/organ/ears/mutantears = /obj/item/organ/ears
|
||||
|
||||
//Hands
|
||||
var/obj/item/mutanthands = null
|
||||
|
||||
//Citadel snowflake
|
||||
var/fixed_mut_color2 = ""
|
||||
var/fixed_mut_color3 = ""
|
||||
@@ -119,6 +122,8 @@
|
||||
var/obj/item/thing = C.get_item_by_slot(slot_id)
|
||||
if(thing && (!thing.species_exception || !is_type_in_list(src,thing.species_exception)))
|
||||
C.dropItemToGround(thing)
|
||||
if(C.hud_used)
|
||||
C.hud_used.update_locked_slots()
|
||||
|
||||
// this needs to be FIRST because qdel calls update_body which checks if we have DIGITIGRADE legs or not and if not then removes DIGITIGRADE from species_traits
|
||||
if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs")
|
||||
@@ -143,15 +148,16 @@
|
||||
qdel(lungs)
|
||||
lungs = null
|
||||
|
||||
if(eyes)
|
||||
qdel(eyes)
|
||||
eyes = new mutanteyes
|
||||
eyes.Insert(C)
|
||||
if(C.get_bodypart("head"))
|
||||
if(eyes)
|
||||
qdel(eyes)
|
||||
eyes = new mutanteyes
|
||||
eyes.Insert(C)
|
||||
|
||||
if(ears)
|
||||
qdel(ears)
|
||||
ears = new mutantears
|
||||
ears.Insert(C)
|
||||
if(ears)
|
||||
qdel(ears)
|
||||
ears = new mutantears
|
||||
ears.Insert(C)
|
||||
|
||||
if((!(NOBREATH in species_traits)) && !lungs)
|
||||
if(mutantlungs)
|
||||
@@ -173,6 +179,21 @@
|
||||
if(exotic_bloodtype && C.dna.blood_type != exotic_bloodtype)
|
||||
C.dna.blood_type = exotic_bloodtype
|
||||
|
||||
if(old_species.mutanthands)
|
||||
for(var/obj/item/I in C.held_items)
|
||||
if(istype(I, old_species.mutanthands))
|
||||
qdel(I)
|
||||
|
||||
if(mutanthands)
|
||||
// Drop items in hands
|
||||
// If you're lucky enough to have a NODROP item, then it stays.
|
||||
for(var/V in C.held_items)
|
||||
var/obj/item/I = V
|
||||
if(istype(I))
|
||||
C.dropItemToGround(I)
|
||||
else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand
|
||||
C.put_in_hands(new mutanthands())
|
||||
|
||||
if(NOAROUSAL in species_traits)
|
||||
C.canbearoused = FALSE
|
||||
else
|
||||
@@ -352,7 +373,7 @@
|
||||
var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[H.undershirt]
|
||||
if(undershirt)
|
||||
if(H.dna.species.sexes && H.gender == FEMALE)
|
||||
standing += wear_female_version(undershirt.icon_state, undershirt.icon, -BODY_LAYER)
|
||||
standing += wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER)
|
||||
else
|
||||
standing += mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER)
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
diff a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm (rejected hunks)
|
||||
@@ -173,14 +173,18 @@
|
||||
if(exotic_bloodtype && C.dna.blood_type != exotic_bloodtype)
|
||||
C.dna.blood_type = exotic_bloodtype
|
||||
|
||||
+ if(old_species.mutanthands)
|
||||
+ for(var/obj/item/I in C.held_items)
|
||||
+ if(istype(I, old_species.mutanthands))
|
||||
+ qdel(I)
|
||||
+
|
||||
if(mutanthands)
|
||||
// Drop items in hands
|
||||
// If you're lucky enough to have a NODROP item, then it stays.
|
||||
for(var/V in C.held_items)
|
||||
var/obj/item/I = V
|
||||
if(istype(I))
|
||||
- if(C.dropItemToGround(I))
|
||||
- C.put_in_hands(new mutanthands())
|
||||
+ C.dropItemToGround(I)
|
||||
else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand
|
||||
C.put_in_hands(new mutanthands())
|
||||
|
||||
@@ -189,10 +193,6 @@
|
||||
C.dna.blood_type = random_blood_type()
|
||||
if(DIGITIGRADE in species_traits)
|
||||
C.Digitigrade_Leg_Swap(TRUE)
|
||||
- if(mutanthands)
|
||||
- for(var/obj/item/I in C.held_items)
|
||||
- if(istype(I, mutanthands))
|
||||
- qdel(I)
|
||||
|
||||
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
H.remove_overlay(HAIR_LAYER)
|
||||
@@ -9,7 +9,7 @@
|
||||
punchdamagelow = 5
|
||||
punchdamagehigh = 14
|
||||
punchstunthreshold = 11 //about 40% chance to stun
|
||||
no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_w_uniform)
|
||||
no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_w_uniform, slot_s_store)
|
||||
nojumpsuit = 1
|
||||
sexes = 1
|
||||
damage_overlay_type = ""
|
||||
@@ -20,6 +20,7 @@
|
||||
dangerous_existence = TRUE
|
||||
limbs_id = "golem"
|
||||
fixed_mut_color = "aaa"
|
||||
mutant_organs = list(/obj/item/organ/adamantine_resonator)
|
||||
var/info_text = "As an <span class='danger'>Iron Golem</span>, you don't have any special traits."
|
||||
|
||||
var/prefix = "Iron"
|
||||
@@ -54,8 +55,9 @@
|
||||
name = "Adamantine Golem"
|
||||
id = "adamantine golem"
|
||||
meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/mutant/golem/adamantine
|
||||
mutant_organs = list(/obj/item/organ/adamantine_resonator, /obj/item/organ/vocal_cords/adamantine)
|
||||
fixed_mut_color = "4ed"
|
||||
info_text = "As an <span class='danger'>Adamantine Golem</span>, you don't have any special traits."
|
||||
info_text = "As an <span class='danger'>Adamantine Golem</span>, you possess special vocal cords allowing you to \"resonate\" messages to all golems."
|
||||
prefix = "Adamantine"
|
||||
|
||||
//Explodes on death
|
||||
@@ -71,14 +73,14 @@
|
||||
prefix = "Plasma"
|
||||
special_names = list("Flood","Fire","Bar","Man")
|
||||
|
||||
/datum/species/golem/plasma/spec_life(mob/living/carbon/human/H)
|
||||
if(H.bodytemperature > 900 && H.on_fire)
|
||||
explosion(get_turf(H),1,2,4,flame_range = 5)
|
||||
if(H)
|
||||
H.gib()
|
||||
if(H.fire_stacks < 2) //flammable
|
||||
H.adjust_fire_stacks(1)
|
||||
..()
|
||||
/datum/species/golem/plasma/spec_life(mob/living/carbon/human/H)
|
||||
if(H.bodytemperature > 900 && H.on_fire)
|
||||
explosion(get_turf(H),1,2,4,flame_range = 5)
|
||||
if(H)
|
||||
H.gib()
|
||||
if(H.fire_stacks < 2) //flammable
|
||||
H.adjust_fire_stacks(1)
|
||||
..()
|
||||
|
||||
//Harder to hurt
|
||||
/datum/species/golem/diamond
|
||||
@@ -505,7 +507,7 @@
|
||||
sexes = FALSE
|
||||
info_text = "As a <span class='danger'>Runic Golem</span>, you possess eldritch powers granted by the Elder God Nar'Sie."
|
||||
species_traits = list(NOBREATH,RESISTHOT,RESISTCOLD,RESISTPRESSURE,NOFIRE,NOGUNS,NOBLOOD,RADIMMUNE,VIRUSIMMUNE,PIERCEIMMUNE,NODISMEMBER) //no mutcolors
|
||||
prefix = "Runic"
|
||||
prefix = "Runic"
|
||||
|
||||
var/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/golem/phase_shift
|
||||
var/obj/effect/proc_holder/spell/targeted/abyssal_gaze/abyssal_gaze
|
||||
@@ -643,4 +645,19 @@
|
||||
|
||||
if(P.is_hot())
|
||||
visible_message("<span class='danger'>[src] bursts into flames!</span>")
|
||||
fire_act()
|
||||
|
||||
fire_act()
|
||||
/datum/species/golem/plastic
|
||||
name = "Plastic"
|
||||
id = "plastic golem"
|
||||
prefix = "Plastic"
|
||||
fixed_mut_color = "fff"
|
||||
info_text = "As a <span class='danger'>Plastic Golem</span>, you are capable of ventcrawling, and passing through plastic flaps."
|
||||
|
||||
/datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
C.ventcrawler = VENTCRAWLER_NUDE
|
||||
|
||||
/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.ventcrawler = initial(C.ventcrawler)
|
||||
|
||||
@@ -13,9 +13,11 @@
|
||||
name = "Infectious Zombie"
|
||||
id = "memezombies"
|
||||
limbs_id = "zombie"
|
||||
mutanthands = /obj/item/zombie_hand
|
||||
no_equip = list(slot_wear_mask, slot_head)
|
||||
armor = 20 // 120 damage to KO a zombie, which kills it
|
||||
speedmod = 2
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/zombie
|
||||
|
||||
/datum/species/zombie/infectious/spec_life(mob/living/carbon/C)
|
||||
. = ..()
|
||||
@@ -27,29 +29,15 @@
|
||||
|
||||
/datum/species/zombie/infectious/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
// Drop items in hands
|
||||
// If you're a zombie lucky enough to have a NODROP item, then it stays.
|
||||
for(var/V in C.held_items)
|
||||
var/obj/item/I = V
|
||||
if(istype(I))
|
||||
if(C.dropItemToGround(I))
|
||||
var/obj/item/zombie_hand/zh = new /obj/item/zombie_hand()
|
||||
C.put_in_hands(zh)
|
||||
else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand
|
||||
var/obj/item/zombie_hand/zh = new /obj/item/zombie_hand()
|
||||
C.put_in_hands(zh)
|
||||
|
||||
// Next, deal with the source of this zombie corruption
|
||||
// Deal with the source of this zombie corruption
|
||||
// Infection organ needs to be handled separately from mutant_organs
|
||||
// because it persists through species transitions
|
||||
var/obj/item/organ/zombie_infection/infection
|
||||
infection = C.getorganslot("zombie_infection")
|
||||
if(!infection)
|
||||
infection = new(C)
|
||||
|
||||
/datum/species/zombie/infectious/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
for(var/obj/item/I in C.held_items)
|
||||
if(istype(I, /obj/item/zombie_hand))
|
||||
qdel(I)
|
||||
infection = new()
|
||||
infection.Insert(C)
|
||||
|
||||
|
||||
// Your skin falls off
|
||||
|
||||
@@ -106,4 +106,4 @@
|
||||
|
||||
/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
|
||||
ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans)
|
||||
|
||||
@@ -1143,7 +1143,7 @@
|
||||
M.visible_message("<span class='boldwarning'>Unfortunately, [M] just can't seem to hold onto [src]!</span>")
|
||||
return
|
||||
if(iscarbon(M) && (!riding_datum.equip_buckle_inhands(M, 1)))
|
||||
M.visible_message("<span class='boldwarning'>[M] can't climb onto [src] because his hands are full!</span>")
|
||||
M.visible_message("<span class='boldwarning'>[M] can't climb onto [src] because [M.p_their()] hands are full!</span>")
|
||||
return
|
||||
. = ..(M, force, check_loc)
|
||||
|
||||
|
||||
@@ -287,17 +287,13 @@
|
||||
to_chat(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()
|
||||
do_sparks(5, TRUE, src)
|
||||
..()
|
||||
|
||||
/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()
|
||||
do_sparks(5, TRUE, src)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/emp_act(severity)
|
||||
|
||||
@@ -259,9 +259,7 @@
|
||||
if(prob(50))
|
||||
new /obj/item/bodypart/l_arm/robot(Tsec)
|
||||
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
do_sparks(3, TRUE, src)
|
||||
..()
|
||||
|
||||
/obj/machinery/bot_core/cleanbot
|
||||
|
||||
@@ -390,9 +390,7 @@ Auto Patrol[]"},
|
||||
if(lasercolor == "r")
|
||||
new /obj/item/clothing/suit/redtag(Tsec)
|
||||
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
do_sparks(3, TRUE, src)
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
..()
|
||||
|
||||
@@ -381,9 +381,7 @@
|
||||
var/obj/item/stack/tile/plasteel/T = new (Tsec)
|
||||
T.amount = 1
|
||||
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
do_sparks(3, TRUE, src)
|
||||
..()
|
||||
|
||||
/obj/machinery/bot_core/floorbot
|
||||
|
||||
@@ -530,9 +530,7 @@
|
||||
if(emagged && prob(25))
|
||||
playsound(loc, 'sound/voice/minsult.ogg', 50, 0)
|
||||
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
do_sparks(3, TRUE, src)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/declare(crit_patient)
|
||||
|
||||
@@ -719,9 +719,7 @@
|
||||
cell.update_icon()
|
||||
cell = null
|
||||
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
do_sparks(3, TRUE, src)
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
..()
|
||||
|
||||
@@ -397,9 +397,7 @@ Auto Patrol: []"},
|
||||
if(prob(50))
|
||||
new /obj/item/bodypart/l_arm/robot(Tsec)
|
||||
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
do_sparks(3, TRUE, src)
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
..()
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
var/obj/item/inventory_head
|
||||
var/obj/item/inventory_mask
|
||||
gold_core_spawnable = 2
|
||||
devourable = TRUE
|
||||
|
||||
/mob/living/simple_animal/crab/Life()
|
||||
..()
|
||||
|
||||
@@ -108,7 +108,6 @@
|
||||
speak_emote = list("clanks", "clinks", "clunks", "clangs")
|
||||
verb_ask = "requests"
|
||||
verb_exclaim = "proclaims"
|
||||
verb_whisper = "imparts"
|
||||
verb_yell = "harangues"
|
||||
bubble_icon = "clock"
|
||||
initial_languages = list(/datum/language/common, /datum/language/ratvar)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
speed = 0
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
devourable = TRUE
|
||||
|
||||
harm_intent_damage = 8
|
||||
obj_damage = 50
|
||||
|
||||
@@ -53,7 +53,5 @@
|
||||
ranged = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebot/death(gibbed)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
do_sparks(3, TRUE, src)
|
||||
..(1)
|
||||
@@ -0,0 +1,85 @@
|
||||
/mob/living/simple_animal/hostile/jungle
|
||||
vision_range = 5
|
||||
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)
|
||||
faction = list("jungle")
|
||||
weather_immunities = list("acid")
|
||||
obj_damage = 30
|
||||
environment_smash = 2
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 450
|
||||
response_help = "pokes"
|
||||
response_disarm = "shoves"
|
||||
response_harm = "strikes"
|
||||
status_flags = 0
|
||||
a_intent = INTENT_HARM
|
||||
see_in_dark = 4
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
|
||||
|
||||
|
||||
//Mega arachnid
|
||||
|
||||
/mob/living/simple_animal/hostile/jungle/mega_arachnid
|
||||
name = "mega arachnid"
|
||||
desc = "Though physically imposing, it prefers to ambush its prey, and it will only engage with an already crippled opponent."
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 30
|
||||
maxHealth = 300
|
||||
health = 300
|
||||
speed = 1
|
||||
ranged = 1
|
||||
pixel_x = -16
|
||||
move_to_delay = 10
|
||||
aggro_vision_range = 9
|
||||
speak_emote = list("chitters")
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
ranged_cooldown_time = 60
|
||||
projectiletype = /obj/item/projectile/mega_arachnid
|
||||
projectilesound = 'sound/weapons/pierce.ogg'
|
||||
icon = 'icons/mob/jungle/arachnid.dmi'
|
||||
icon_state = "arachnid"
|
||||
icon_living = "arachnid"
|
||||
icon_dead = "dead_purple"
|
||||
alpha = 50
|
||||
|
||||
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Life()
|
||||
..()
|
||||
if(target && ranged_cooldown > world.time && iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(!C.legcuffed && C.health < 50)
|
||||
retreat_distance = 9
|
||||
minimum_distance = 9
|
||||
alpha = 125
|
||||
return
|
||||
retreat_distance = 0
|
||||
minimum_distance = 0
|
||||
alpha = 255
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Aggro()
|
||||
..()
|
||||
alpha = 255
|
||||
|
||||
/mob/living/simple_animal/hostile/jungle/mega_arachnid/LoseAggro()
|
||||
..()
|
||||
alpha = 50
|
||||
|
||||
/obj/item/projectile/mega_arachnid
|
||||
name = "flesh snare"
|
||||
nodamage = 1
|
||||
damage = 0
|
||||
icon_state = "tentacle_end"
|
||||
|
||||
/obj/item/projectile/mega_arachnid/on_hit(atom/target, blocked = 0)
|
||||
if(iscarbon(target) && blocked < 100)
|
||||
var/obj/item/weapon/restraints/legcuffs/beartrap/mega_arachnid/B = new /obj/item/weapon/restraints/legcuffs/beartrap/mega_arachnid(get_turf(target))
|
||||
B.Crossed(target)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/restraints/legcuffs/beartrap/mega_arachnid
|
||||
name = "fleshy restraints"
|
||||
desc = "Used by mega arachnids to immobilize their prey."
|
||||
flags = DROPDEL
|
||||
icon_state = "tentacle_end"
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
@@ -401,7 +401,7 @@ Difficulty: Very Hard
|
||||
to_chat(user, observer_desc)
|
||||
to_chat(user, "It is activated by [activation_method].")
|
||||
|
||||
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans)
|
||||
..()
|
||||
if(isliving(speaker))
|
||||
ActivationReaction(speaker, ACTIVATE_SPEECH)
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/ghost/Initialize()
|
||||
. = ..()
|
||||
set_light(1, 2)
|
||||
if(!random)
|
||||
give_hair()
|
||||
else
|
||||
@@ -60,4 +61,4 @@
|
||||
ghost_facial_hair = mutable_appearance('icons/mob/human_face.dmi', "facial_[ghost_facial_hair_style]", -HAIR_LAYER)
|
||||
ghost_facial_hair.alpha = 200
|
||||
ghost_facial_hair.color = ghost_facial_hair_color
|
||||
add_overlay(ghost_facial_hair)
|
||||
add_overlay(ghost_facial_hair)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans)
|
||||
if(speaker != src && !radio_freq && !stat)
|
||||
if (speaker in Friends)
|
||||
speech_buffer = list()
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
response_disarm = "shoos"
|
||||
response_harm = "stomps on"
|
||||
emote_see = list("jiggles", "bounces in place")
|
||||
speak_emote = list("telepathically chirps")
|
||||
speak_emote = list("blorbles")
|
||||
bubble_icon = "slime"
|
||||
initial_languages = list(/datum/language/common, /datum/language/slime)
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
|
||||
see_in_dark = 8
|
||||
|
||||
verb_say = "telepathically chirps"
|
||||
verb_ask = "telepathically asks"
|
||||
verb_exclaim = "telepathically cries"
|
||||
verb_yell = "telephatically cries"
|
||||
verb_say = "blorbles"
|
||||
verb_ask = "inquisitively blorbles"
|
||||
verb_exclaim = "loudly blorbles"
|
||||
verb_yell = "loudly blorbles"
|
||||
|
||||
// canstun and canweaken don't affect slimes because they ignore stun and weakened variables
|
||||
// for the sake of cleanliness, though, here they are.
|
||||
|
||||
@@ -351,6 +351,8 @@
|
||||
/mob/proc/spin(spintime, speed)
|
||||
set waitfor = 0
|
||||
var/D = dir
|
||||
if((spintime < 1)||(speed < 1)||!spintime||!speed)
|
||||
return
|
||||
while(spintime >= speed)
|
||||
sleep(speed)
|
||||
switch(D)
|
||||
|
||||
@@ -497,9 +497,7 @@
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/structure/cable/N = T.get_cable_node()
|
||||
if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE))
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
do_sparks(5, TRUE, src)
|
||||
return
|
||||
C.use(10)
|
||||
to_chat(user, "<span class='notice'>You add cables to the APC frame.</span>")
|
||||
@@ -1181,9 +1179,7 @@
|
||||
/obj/machinery/power/apc/proc/shock(mob/user, prb)
|
||||
if(!prob(prb))
|
||||
return 0
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
do_sparks(5, TRUE, src)
|
||||
if(isalien(user))
|
||||
return 0
|
||||
if(electrocute_mob(user, src, src, 1, TRUE))
|
||||
|
||||
@@ -156,9 +156,7 @@ By design, d1 is the smallest direction and d2 is the highest
|
||||
if(!prob(prb))
|
||||
return 0
|
||||
if (electrocute_mob(user, powernet, src, siemens_coeff))
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
do_sparks(5, TRUE, src)
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
light_power = 0.7
|
||||
light_range = 15
|
||||
light_color = rgb(255, 0, 0)
|
||||
gender = FEMALE
|
||||
var/clashing = FALSE //If Nar-Sie is fighting Ratvar
|
||||
|
||||
/obj/singularity/narsie/large
|
||||
|
||||
@@ -59,6 +59,11 @@ GLOBAL_LIST_INIT(blacklisted_tesla_types, typecacheof(list(/obj/machinery/atmosp
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/singularity/energy_ball/admin_investigate_setup()
|
||||
if(istype(loc, /obj/singularity/energy_ball))
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/singularity/energy_ball/process()
|
||||
if(!orbiting)
|
||||
handle_energy()
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
fire_sound = 'sound/magic/lightningbolt.ogg'
|
||||
e_cost = 200
|
||||
select_name = "stun"
|
||||
projectile_type = /obj/item/projectile/energy/tesla_revolver
|
||||
projectile_type = /obj/item/projectile/energy/tesla/revolver
|
||||
|
||||
/obj/item/ammo_casing/energy/gravityrepulse
|
||||
projectile_type = /obj/item/projectile/gravityrepulse
|
||||
|
||||
@@ -179,6 +179,8 @@
|
||||
return
|
||||
if(setAngle)
|
||||
Angle = setAngle
|
||||
var/old_pixel_x = pixel_x
|
||||
var/old_pixel_y = pixel_y
|
||||
if(!legacy) //new projectiles
|
||||
set waitfor = 0
|
||||
var/next_run = world.time
|
||||
@@ -201,29 +203,30 @@
|
||||
|
||||
var/Pixel_x=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
|
||||
var/Pixel_y=round((cos(Angle)+16*cos(Angle)*2), 1)
|
||||
var/pixel_x_offset = pixel_x + Pixel_x
|
||||
var/pixel_y_offset = pixel_y + Pixel_y
|
||||
var/pixel_x_offset = old_pixel_x + Pixel_x
|
||||
var/pixel_y_offset = old_pixel_y + Pixel_y
|
||||
var/new_x = x
|
||||
var/new_y = y
|
||||
|
||||
while(pixel_x_offset > 16)
|
||||
pixel_x_offset -= 32
|
||||
pixel_x -= 32
|
||||
old_pixel_x -= 32
|
||||
new_x++// x++
|
||||
while(pixel_x_offset < -16)
|
||||
pixel_x_offset += 32
|
||||
pixel_x += 32
|
||||
old_pixel_x += 32
|
||||
new_x--
|
||||
|
||||
while(pixel_y_offset > 16)
|
||||
pixel_y_offset -= 32
|
||||
pixel_y -= 32
|
||||
old_pixel_y -= 32
|
||||
new_y++
|
||||
while(pixel_y_offset < -16)
|
||||
pixel_y_offset += 32
|
||||
pixel_y += 32
|
||||
old_pixel_y += 32
|
||||
new_y--
|
||||
|
||||
|
||||
pixel_x = old_pixel_x
|
||||
pixel_y = old_pixel_y
|
||||
step_towards(src, locate(new_x, new_y, z))
|
||||
next_run += max(world.tick_lag, speed)
|
||||
var/delay = next_run - world.time
|
||||
@@ -232,7 +235,9 @@
|
||||
pixel_y = pixel_y_offset
|
||||
else
|
||||
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
|
||||
|
||||
old_pixel_x = pixel_x_offset
|
||||
old_pixel_y = pixel_y_offset
|
||||
|
||||
if(original && (original.layer>=2.75) || ismob(original))
|
||||
if(loc == get_turf(original))
|
||||
if(!(original in permutated))
|
||||
|
||||
@@ -159,44 +159,34 @@
|
||||
/obj/item/projectile/energy/bolt/large
|
||||
damage = 20
|
||||
|
||||
/obj/item/projectile/energy/tesla_revolver
|
||||
/obj/item/projectile/energy/tesla
|
||||
name = "tesla bolt"
|
||||
icon_state = "tesla_projectile"
|
||||
impact_effect_type = /obj/effect/overlay/temp/impact_effect/blue_laser
|
||||
var/chain
|
||||
|
||||
/obj/item/projectile/energy/tesla_revolver/fire(setAngle)
|
||||
/obj/item/projectile/energy/tesla/fire(setAngle)
|
||||
if(firer)
|
||||
chain = firer.Beam(src, icon_state = "lightning[rand(1, 12)]", time = INFINITY, maxdistance = INFINITY)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/energy/tesla_revolver/on_hit(atom/target)
|
||||
. = ..()
|
||||
if(isliving(target))
|
||||
tesla_zap(src, 3, 10000)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/projectile/energy/tesla_revolver/Destroy()
|
||||
/obj/item/projectile/energy/tesla/Destroy()
|
||||
qdel(chain)
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/energy/tesla/revolver
|
||||
name = "energy orb"
|
||||
|
||||
/obj/item/projectile/energy/tesla_cannon
|
||||
name = "tesla bolt"
|
||||
icon_state = "tesla_projectile"
|
||||
impact_effect_type = /obj/effect/overlay/temp/impact_effect/blue_laser
|
||||
var/chain
|
||||
/obj/item/projectile/energy/tesla/revolver/on_hit(atom/target)
|
||||
. = ..()
|
||||
if(isliving(target))
|
||||
tesla_zap(target, 3, 10000)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/projectile/energy/tesla_cannon/fire(setAngle)
|
||||
if(firer)
|
||||
chain = firer.Beam(src, icon_state = "lightning[rand(1, 12)]", time = INFINITY, maxdistance = INFINITY)
|
||||
..()
|
||||
/obj/item/projectile/energy/tesla/cannon
|
||||
name = "tesla orb"
|
||||
|
||||
/obj/item/projectile/energy/tesla_cannon/on_hit(atom/target)
|
||||
/obj/item/projectile/energy/tesla/cannon/on_hit(atom/target)
|
||||
. = ..()
|
||||
tesla_zap(src, 3, 10000, explosive = FALSE, stun_mobs = FALSE)
|
||||
tesla_zap(target, 3, 10000, explosive = FALSE, stun_mobs = FALSE)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/projectile/energy/tesla_cannon/Destroy()
|
||||
qdel(chain)
|
||||
return ..()
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
active_power_usage = 100
|
||||
pass_flags = PASSTABLE
|
||||
resistance_flags = ACID_PROOF
|
||||
var/operating = 0
|
||||
var/operating = FALSE
|
||||
var/obj/item/weapon/reagent_containers/beaker = null
|
||||
var/limit = 10
|
||||
var/list/blend_items = list (
|
||||
@@ -220,9 +220,12 @@
|
||||
[processing_chamber]<br>
|
||||
[beaker_contents]<hr>
|
||||
"}
|
||||
if (is_beaker_ready && !is_chamber_empty && !(stat & (NOPOWER|BROKEN)))
|
||||
dat += "<A href='?src=\ref[src];action=grind'>Grind the reagents</a><BR>"
|
||||
dat += "<A href='?src=\ref[src];action=juice'>Juice the reagents</a><BR><BR>"
|
||||
if (is_beaker_ready)
|
||||
if(!is_chamber_empty && !(stat & (NOPOWER|BROKEN)))
|
||||
dat += "<A href='?src=\ref[src];action=grind'>Grind the reagents</a><BR>"
|
||||
dat += "<A href='?src=\ref[src];action=juice'>Juice the reagents</a><BR><BR>"
|
||||
else if (beaker.reagents.total_volume)
|
||||
dat += "<A href='?src=\ref[src];action=mix'>Mix the reagents</a><BR><BR>"
|
||||
if(holdingitems && holdingitems.len > 0)
|
||||
dat += "<A href='?src=\ref[src];action=eject'>Eject the reagents</a><BR>"
|
||||
if (beaker)
|
||||
@@ -248,6 +251,8 @@
|
||||
grind()
|
||||
if("juice")
|
||||
juice()
|
||||
if("mix")
|
||||
mix()
|
||||
if("eject")
|
||||
eject()
|
||||
if ("detach")
|
||||
@@ -327,11 +332,11 @@
|
||||
playsound(src.loc, 'sound/machines/juicer.ogg', 20, 1)
|
||||
var/offset = prob(50) ? -2 : 2
|
||||
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking
|
||||
operating = 1
|
||||
operating = TRUE
|
||||
updateUsrDialog()
|
||||
spawn(50)
|
||||
pixel_x = initial(pixel_x) //return to its spot after shaking
|
||||
operating = 0
|
||||
operating = FALSE
|
||||
updateUsrDialog()
|
||||
|
||||
//Snacks
|
||||
@@ -365,11 +370,11 @@
|
||||
playsound(src.loc, 'sound/machines/blender.ogg', 50, 1)
|
||||
var/offset = prob(50) ? -2 : 2
|
||||
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking
|
||||
operating = 1
|
||||
operating = TRUE
|
||||
updateUsrDialog()
|
||||
spawn(60)
|
||||
pixel_x = initial(pixel_x) //return to its spot after shaking
|
||||
operating = 0
|
||||
operating = FALSE
|
||||
updateUsrDialog()
|
||||
|
||||
//Snacks and Plants
|
||||
@@ -467,3 +472,33 @@
|
||||
break
|
||||
beaker.reagents.add_reagent(r_id, min(O.reagent_contents[r_id], space))
|
||||
remove_object(O)
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/mix()
|
||||
|
||||
//For butter and other things that would change upon shaking or mixing
|
||||
power_change()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if (!beaker)
|
||||
return
|
||||
playsound(src.loc, 'sound/machines/juicer.ogg', 20, 1)
|
||||
var/offset = prob(50) ? -2 : 2
|
||||
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking
|
||||
operating = TRUE
|
||||
updateUsrDialog()
|
||||
addtimer(CALLBACK(src, /obj/machinery/reagentgrinder/proc/mix_complete), 50)
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/mix_complete()
|
||||
pixel_x = initial(pixel_x) //return to its spot after shaking
|
||||
operating = FALSE
|
||||
updateUsrDialog()
|
||||
if (beaker.reagents.total_volume)
|
||||
//Recipe to make Butter
|
||||
while(beaker.reagents.get_reagent_amount("milk") >= 15)
|
||||
beaker.reagents.remove_reagent("milk", 15)
|
||||
new /obj/item/weapon/reagent_containers/food/snacks/butter(src.loc)
|
||||
//Recipe to make Mayonnaise
|
||||
if (beaker.reagents.has_reagent("eggyolk"))
|
||||
var/amount = beaker.reagents.get_reagent_amount("eggyolk")
|
||||
beaker.reagents.remove_reagent("eggyolk", amount)
|
||||
beaker.reagents.add_reagent("mayonnaise", amount)
|
||||
@@ -966,7 +966,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
glass_desc = "Only for the experienced. You think you see sand floating in the glass."
|
||||
|
||||
/datum/reagent/consumable/ethanol/bananahonk
|
||||
name = "Banana Mama"
|
||||
name = "Banana Honk"
|
||||
id = "bananahonk"
|
||||
description = "A drink from Clown Heaven."
|
||||
nutriment_factor = 1 * REAGENTS_METABOLISM
|
||||
|
||||
@@ -60,7 +60,10 @@
|
||||
// data for nutriment is one or more (flavour -> ratio)
|
||||
// where all the ratio values adds up to 1
|
||||
|
||||
var/list/taste_amounts = data.Copy()
|
||||
var/list/taste_amounts = list()
|
||||
if(data)
|
||||
taste_amounts = data.Copy()
|
||||
|
||||
counterlist_scale(taste_amounts, volume)
|
||||
|
||||
var/list/other_taste_amounts = newdata.Copy()
|
||||
@@ -524,6 +527,12 @@
|
||||
M.heal_bodypart_damage(3,1)
|
||||
..()
|
||||
|
||||
/datum/reagent/consumable/mayonnaise
|
||||
name = "Mayonnaise"
|
||||
id = "mayonnaise"
|
||||
description = "An white and oily mixture of mixed egg yolks."
|
||||
color = "#DFDFDF"
|
||||
taste_description = "mayonnaise"
|
||||
|
||||
////Lavaland Flora Reagents////
|
||||
|
||||
|
||||
@@ -347,10 +347,9 @@
|
||||
/datum/reagent/medicine/mine_salve/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
|
||||
if(iscarbon(M) && M.stat != DEAD)
|
||||
if(method in list(INGEST, VAPOR, INJECT))
|
||||
M.Stun(4)
|
||||
M.Weaken(4)
|
||||
M.nutrition -= 5
|
||||
if(show_message)
|
||||
to_chat(M, "<span class='warning'>Your stomach agonizingly cramps!</span>")
|
||||
to_chat(M, "<span class='warning'>Your stomach feels empty and cramps!</span>")
|
||||
else
|
||||
var/mob/living/carbon/C = M
|
||||
for(var/s in C.surgeries)
|
||||
@@ -962,8 +961,7 @@
|
||||
/datum/reagent/medicine/antitoxin/on_mob_life(mob/living/M)
|
||||
M.adjustToxLoss(-2*REM, 0)
|
||||
for(var/datum/reagent/toxin/R in M.reagents.reagent_list)
|
||||
if(R != src)
|
||||
M.reagents.remove_reagent(R.id,1)
|
||||
M.reagents.remove_reagent(R.id,1)
|
||||
..()
|
||||
. = 1
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user