Merge branch 'master' into upstream-merge-37476

This commit is contained in:
LetterJay
2018-05-20 23:12:07 -05:00
committed by GitHub
172 changed files with 6336 additions and 4958 deletions
+1 -1
View File
@@ -39,7 +39,7 @@
return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.")
if (CONFIG_GET(flag/panic_bunker) && SSdbcore.Connect())
log_access("Failed Login: [key] - Guests not allowed during panic bunker")
return list("reason"="guest", "desc"="\nReason: You must first join the Discord to verify your account before joining this server. Please ping an admin once you've joined and read the rules. https://discord.gg/E6SQuhz")
return list("reason"="guest", "desc"="\nReason: You must first sign into your BYOND account or join the Discord to verify your account before joining this server. Please ping an admin once you've joined and read the rules. https://discord.gg/E6SQuhz")
//Population Cap Checking
var/extreme_popcap = CONFIG_GET(number/extreme_popcap)
+2 -2
View File
@@ -434,7 +434,7 @@
return
var/list/options = list("Regular Restart", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)")
if(SERVER_TOOLS_PRESENT)
if(world.TgsAvailable())
options += "Server Restart (Kill and restart DD)";
var/rebootconfirm
@@ -459,7 +459,7 @@
world.Reboot(fast_track = TRUE)
if("Server Restart (Kill and restart DD)")
to_chat(world, "Server restart - [init_by]")
SERVER_TOOLS_REBOOT_BYOND
world.TgsEndProcess()
/datum/admins/proc/end_round()
set category = "Server"
+1
View File
@@ -93,6 +93,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
/client/proc/forceEvent,
/client/proc/admin_change_sec_level,
/client/proc/toggle_nuke,
/client/proc/run_weather,
/client/proc/mass_zombie_infection,
/client/proc/mass_zombie_cure,
/client/proc/polymorph_all,
+31 -28
View File
@@ -1,12 +1,12 @@
#define IRC_STATUS_THROTTLE 5
/datum/server_tools_command/ircstatus
/datum/tgs_chat_command/ircstatus
name = "status"
help_text = "Gets the admincount, playercount, gamemode, and true game mode of the server"
admin_only = TRUE
var/static/last_irc_status = 0
var/last_irc_status = 0
/datum/server_tools_command/ircstatus/Run(sender, params)
/datum/tgs_chat_command/ircstatus/Run(datum/tgs_chat_user/sender, params)
var/rtod = REALTIMEOFDAY
if(rtod - last_irc_status < IRC_STATUS_THROTTLE)
return
@@ -17,12 +17,12 @@
status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode ? SSticker.mode.name : "Not started"]."
return status
/datum/server_tools_command/irccheck
/datum/tgs_chat_command/irccheck
name = "check"
help_text = "Gets the playercount, gamemode, and address of the server"
var/static/last_irc_check = 0
var/last_irc_check = 0
/datum/server_tools_command/irccheck/Run(sender, params)
/datum/tgs_chat_command/irccheck/Run(datum/tgs_chat_user/sender, params)
var/rtod = REALTIMEOFDAY
if(rtod - last_irc_check < IRC_STATUS_THROTTLE)
return
@@ -30,14 +30,15 @@
var/server = CONFIG_GET(string/server)
return "[GLOB.round_id ? "Round #[GLOB.round_id]: " : ""][GLOB.clients.len] players on [SSmapping.config.map_name]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [server ? server : "[world.internet_address]:[world.port]"]" //CIT CHANGE - obfuscates the current gamemode from players
/datum/server_tools_command/ahelp
/datum/tgs_chat_command/ahelp
name = "ahelp"
help_text = "<ckey|ticket #> <message|ticket <close|resolve|icissue|reject|reopen <ticket #>|list>>"
required_parameters = 2
admin_only = TRUE
/datum/server_tools_command/ahelp/Run(sender, params)
/datum/tgs_chat_command/ahelp/Run(datum/tgs_chat_user/sender, params)
var/list/all_params = splittext(params, " ")
if(all_params.len < 2)
return "Insufficient parameters"
var/target = all_params[1]
all_params.Cut(1, 2)
var/id = text2num(target)
@@ -47,52 +48,54 @@
target = AH.initiator_ckey
else
return "Ticket #[id] not found!"
var/res = IrcPm(target, all_params.Join(" "), sender)
var/res = IrcPm(target, all_params.Join(" "), sender.friendly_name)
if(res != "Message Successful")
return res
/datum/server_tools_command/namecheck
/datum/tgs_chat_command/namecheck
name = "namecheck"
help_text = "Returns info on the specified target"
required_parameters = 1
admin_only = TRUE
/datum/server_tools_command/namecheck/Run(sender, params)
log_admin("Chat Name Check: [sender] on [params]")
message_admins("Name checking [params] from [sender]")
/datum/tgs_chat_command/namecheck/Run(datum/tgs_chat_user/sender, params)
params = trim(params)
if(!params)
return "Insufficient parameters"
log_admin("Chat Name Check: [sender.friendly_name] on [params]")
message_admins("Name checking [params] from [sender.friendly_name]")
return keywords_lookup(params, 1)
/datum/server_tools_command/adminwho
/datum/tgs_chat_command/adminwho
name = "adminwho"
help_text = "Lists administrators currently on the server"
admin_only = TRUE
/datum/server_tools_command/adminwho/Run(sender, params)
/datum/tgs_chat_command/adminwho/Run(datum/tgs_chat_user/sender, params)
return ircadminwho()
GLOBAL_LIST(round_end_notifiees)
/datum/server_tools_command/notify
/datum/tgs_chat_command/notify
name = "notify"
help_text = "Pings the invoker when the round ends"
admin_only = TRUE
/datum/server_tools_command/notify/Run(sender, params)
/datum/tgs_chat_command/notify/Run(datum/tgs_chat_user/sender, params)
if(!SSticker.IsRoundInProgress() && SSticker.HasRoundStarted())
return "[sender], the round has already ended!"
return "[sender.mention], the round has already ended!"
LAZYINITLIST(GLOB.round_end_notifiees)
GLOB.round_end_notifiees[sender] = TRUE
return "I will notify [sender] when the round ends."
return "I will notify [sender.mention] when the round ends."
/datum/server_tools_command/sdql
/datum/tgs_chat_command/sdql
name = "sdql"
help_text = "Runs an SDQL query"
admin_only = TRUE
/datum/server_tools_command/sdql/Run(sender, params)
/datum/tgs_chat_command/sdql/Run(datum/tgs_chat_user/sender, params)
if(GLOB.AdminProcCaller)
return "Unable to run query, another admin proc call is in progress. Try again later."
GLOB.AdminProcCaller = "CHAT_[sender]" //_ won't show up in ckeys so it'll never match with a real admin
GLOB.AdminProcCaller = "CHAT_[sender.friendly_name]" //_ won't show up in ckeys so it'll never match with a real admin
var/list/results = world.SDQL2_query(params, GLOB.AdminProcCaller, GLOB.AdminProcCaller)
GLOB.AdminProcCaller = null
if(!results)
@@ -100,13 +103,13 @@ GLOBAL_LIST(round_end_notifiees)
var/list/text_res = results.Copy(1, 3)
var/list/refs = results.len > 3 ? results.Copy(4) : null
. = "[text_res.Join("\n")][refs ? "\nRefs: [refs.Join(" ")]" : ""]"
/datum/server_tools_command/reload_admins
/datum/tgs_chat_command/reload_admins
name = "reload_admins"
help_text = "Forces the server to reload admins."
admin_only = TRUE
/datum/server_tools_command/reload_admins/Run(sender, params)
/datum/tgs_chat_command/reload_admins/Run(datum/tgs_chat_user/sender, params)
load_admins()
log_admin("[sender] reloaded admins via chat command.")
log_admin("[sender.friendly_name] reloaded admins via chat command.")
return "Admins reloaded."
+11
View File
@@ -22,6 +22,17 @@
H.facial_hair_color = H.hair_color
H.eye_color = random_eye_color()
H.dna.blood_type = random_blood_type()
// Mutant randomizing, doesn't affect the mob appearance unless it's the specific mutant.
H.dna.features["mcolor"] = random_short_color()
H.dna.features["tail_lizard"] = pick(GLOB.tails_list_lizard)
H.dna.features["snout"] = pick(GLOB.snouts_list)
H.dna.features["horns"] = pick(GLOB.horns_list)
H.dna.features["frills"] = pick(GLOB.frills_list)
H.dna.features["spines"] = pick(GLOB.spines_list)
H.dna.features["body_markings"] = pick(GLOB.body_markings_list)
H.dna.features["moth_wings"] = pick(GLOB.moth_wings_list)
H.update_body()
H.update_hair()
H.update_body_parts()
+13
View File
@@ -2448,6 +2448,19 @@
usr.client.cmd_admin_mod_antag_rep(C, href_list["modantagrep"])
show_player_panel(M)
else if(href_list["slowquery"])
if(!check_rights(R_ADMIN))
return
var/answer = href_list["slowquery"]
if(answer == "yes")
log_query_debug("[usr.key] | Reported a server hang")
if(alert(usr, "Had you just press any admin buttons?", "Query server hang report", "Yes", "No") == "Yes")
var/response = input(usr,"What were you just doing?","Query server hang report") as null|text
if(response)
log_query_debug("[usr.key] | [response]")
else if(answer == "no")
log_query_debug("[usr.key] | Reported no server hang")
/datum/admins/proc/HandleCMode()
if(!check_rights(R_ADMIN))
return
+1 -1
View File
@@ -594,7 +594,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
/proc/send2irc(msg,msg2)
msg = replacetext(replacetext(msg, "\proper", ""), "\improper", "")
msg2 = replacetext(replacetext(msg2, "\proper", ""), "\improper", "")
SERVER_TOOLS_RELAY_BROADCAST("[msg] | [msg2]")
world.TgsTargetedChatBroadcast("[msg] | [msg2]", TRUE)
/proc/send2otherserver(source,msg,type = "Ahelp")
var/comms_key = CONFIG_GET(string/comms_key)
+6 -2
View File
@@ -110,10 +110,14 @@ GLOBAL_PROTECT(LastAdminCalledProc)
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
/proc/WrapAdminProcCall(target, procname, list/arguments)
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target && procname == "Del")
to_chat(usr, "Calling Del() is not allowed")
return
if(!target.CanProcCall(procname))
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
return
var/current_caller = GLOB.AdminProcCaller
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
if(!ckey)
@@ -137,7 +141,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
GLOB.AdminProcCaller = null
//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(target, procname, list/arguments)
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
return call(procname)(arglist(arguments))
else if(target != world)
+24
View File
@@ -1043,6 +1043,30 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
for(var/obj/machinery/shuttle_manipulator/M in GLOB.machines)
M.ui_interact(usr)
/client/proc/run_weather()
set category = "Fun"
set name = "Run Weather"
set desc = "Triggers a weather on the z-level you choose."
if(!holder)
return
var/weather_type = input("Choose a weather", "Weather") as null|anything in subtypesof(/datum/weather)
if(!weather_type)
return
var/z_level = input("Z-Level to target? Leave blank to target current Z-Level.", "Z-Level") as num|null
if(!isnum(z_level))
if(!src.mob)
return
z_level = src.mob.z
SSweather.run_weather(weather_type, z_level)
message_admins("[key_name_admin(usr)] started weather of type [weather_type] on the z-level [z_level].")
log_admin("[key_name(usr)] started weather of type [weather_type] on the z-level [z_level].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Run Weather")
/client/proc/mass_zombie_infection()
set category = "Fun"
set name = "Mass Zombie Infection"
@@ -153,7 +153,7 @@
H.confused += 15
H.adjustBrainLoss(10, 160)
if(3)
H.hallucination += 80
H.hallucination += 60
/obj/item/organ/heart/gland/pop
cooldown_low = 900
@@ -272,10 +272,10 @@
/obj/item/organ/heart/gland/electric/Insert(mob/living/carbon/M, special = 0)
..()
owner.add_trait(TRAIT_SHOCKIMMUNE, "abductor_gland")
owner.add_trait(TRAIT_SHOCKIMMUNE, ORGAN_TRAIT)
/obj/item/organ/heart/gland/electric/Remove(mob/living/carbon/M, special = 0)
owner.remove_trait(TRAIT_SHOCKIMMUNE, "abductor_gland")
owner.remove_trait(TRAIT_SHOCKIMMUNE, ORGAN_TRAIT)
..()
/obj/item/organ/heart/gland/electric/activate()
@@ -353,7 +353,10 @@
if(GLOB.changeling_team_objective_type)
var/datum/objective/changeling_team_objective/team_objective = new GLOB.changeling_team_objective_type
team_objective.owner = owner
objectives += team_objective
if(team_objective.prepare())//Setting up succeeded
objectives += team_objective
else
qdel(team_objective)
return
/datum/antagonist/changeling/proc/forge_objectives()
@@ -72,10 +72,10 @@
//used in /mob/Stat()
/obj/effect/proc_holder/changeling/proc/can_be_used_by(mob/user)
if(!user || QDELETED(user))
return 0
if(QDELETED(user))
return FALSE
if(!ishuman(user) && !ismonkey(user))
return 0
return FALSE
if(req_human && !ishuman(user))
return 0
return 1
return FALSE
return TRUE
@@ -29,8 +29,12 @@
return TRUE
/obj/effect/proc_holder/changeling/revive/can_be_used_by(mob/living/user)
. = ..()
if(!.)
return
if(user.has_trait(CHANGELING_DRAIN) || ((user.stat != DEAD) && !(user.has_trait(TRAIT_FAKEDEATH))))
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.purchasedpowers -= src
return 0
. = ..()
return FALSE
@@ -214,19 +214,19 @@
/obj/effect/proc_holder/changeling/sting/LSD
name = "Hallucination Sting"
desc = "Causes terror in the target."
helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect occurs after 30 to 60 seconds."
helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect begins after a few seconds."
sting_icon = "sting_lsd"
chemical_cost = 10
dna_cost = 1
/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/living/carbon/target)
add_logs(user, target, "stung", "LSD sting")
addtimer(CALLBACK(src, .proc/hallucination_time, target), rand(300,600))
addtimer(CALLBACK(src, .proc/hallucination_time, target), rand(100,200))
return TRUE
/obj/effect/proc_holder/changeling/sting/LSD/proc/hallucination_time(mob/living/carbon/target)
if(target)
target.hallucination = max(400, target.hallucination)
target.hallucination = max(90, target.hallucination)
/obj/effect/proc_holder/changeling/sting/cryo
name = "Cryogenic Sting"
@@ -159,7 +159,7 @@
SSticker.mode.servants_of_ratvar -= owner
SSticker.mode.update_servant_icons_removed(owner)
if(!silent)
owner.current.visible_message("<span class='deconversion_message'>[owner] seems to have remembered their true allegiance!</span>", null, null, null, owner.current)
owner.current.visible_message("<span class='deconversion_message'>[owner.current] seems to have remembered [owner.current.p_their()] true allegiance!</span>", null, null, null, owner.current)
to_chat(owner, "<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
owner.current.log_message("<font color=#BE8700>Has renounced the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
owner.special_role = null
+1 -1
View File
@@ -260,7 +260,7 @@
if(!ishuman(target) || iscultist(target))
return
var/mob/living/carbon/human/H = target
H.hallucination = max(H.hallucination, 240)
H.hallucination = max(H.hallucination, 120)
SEND_SOUND(ranged_ability_user, sound('sound/effects/ghost.ogg',0,1,50))
var/image/C = image('icons/effects/cult_effects.dmi',H,"bloodsparkles", ABOVE_MOB_LAYER)
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", C, FALSE)
+1 -1
View File
@@ -128,7 +128,7 @@
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
if(!silent)
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!</span>", null, null, null, owner.current)
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just reverted to [owner.current.p_their()] old faith!</span>", null, null, null, owner.current)
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
+2 -6
View File
@@ -71,8 +71,6 @@
if(!iscultist(user))
if(!is_servant_of_ratvar(user))
to_chat(user, "<span class='cultlarge'>\"I wouldn't advise that.\"</span>")
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
user.Dizzy(120)
else
to_chat(user, "<span class='cultlarge'>\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"</span>")
to_chat(user, "<span class='userdanger'>A horrible force yanks at your arm!</span>")
@@ -136,10 +134,7 @@
if(!iscultist(user))
if(!is_servant_of_ratvar(user))
to_chat(user, "<span class='cultlarge'>\"I wouldn't advise that.\"</span>")
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
user.Dizzy(80)
user.dropItemToGround(src, TRUE)
user.Knockdown(30)
force = 5
return
else
to_chat(user, "<span class='cultlarge'>\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"</span>")
@@ -149,6 +144,7 @@
user.dropItemToGround(src, TRUE)
user.Knockdown(50)
return
force = initial(force)
jaunt.Grant(user, src)
linked_action.Grant(user, src)
user.update_icons()
+2 -1
View File
@@ -144,7 +144,8 @@ This file contains the cult dagger and rune list code
if(locate(/obj/effect/rune) in T)
to_chat(user, "<span class='cult'>There is already a rune here.</span>")
return FALSE
if(!is_station_level(T.z) && !is_mining_level(T.z))
var/area/A = get_area(T)
if((!is_station_level(T.z) && !is_mining_level(T.z)) || (A && !A.blob_allowed))
to_chat(user, "<span class='warning'>The veil is not weak enough here.</span>")
return FALSE
return TRUE
@@ -90,7 +90,7 @@
to_chat(src, "<b>You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.</b>")
to_chat(src, "<b>To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.</b>")
to_chat(src, "<b><i>You do not remember anything of your past lives, nor will you remember anything about this one after your death.</i></b>")
to_chat(src, "<b>Be sure to read the wiki page at https://tgstation13.org/wiki/Revenant to learn more.</b>")
to_chat(src, "<b>Be sure to read <a href=\"https://tgstation13.org/wiki/Revenant\">the wiki page</a> to learn more.</b>")
if(!generated_objectives_and_spells)
generated_objectives_and_spells = TRUE
mind.assigned_role = ROLE_REVENANT
@@ -201,12 +201,13 @@
/datum/antagonist/rev/farewell()
if(ishuman(owner.current))
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like they just remembered their real allegiance!</span>", null, null, null, owner.current)
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just remembered [owner.current.p_their()] real allegiance!</span>", null, null, null, owner.current)
to_chat(owner, "<span class='userdanger'>You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...</span>")
else if(issilicon(owner.current))
owner.current.visible_message("<span class='deconversion_message'>The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.</span>", null, null, null, owner.current)
to_chat(owner, "<span class='userdanger'>The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.</span>")
//blunt trauma deconversions call this through species.dm spec_attacked_by()
/datum/antagonist/rev/proc/remove_revolutionary(borged, deconverter)
log_attack("[owner.current] (Key: [key_name(owner.current)]) has been deconverted from the revolution by [deconverter] (Key: [key_name(deconverter)])!")
if(borged)
@@ -33,7 +33,6 @@
..()
if(!iscultist(user) && !iswizard(user) && !usability)
to_chat(user, "<span class='danger'>An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.</span>")
user.Dizzy(120)
/obj/item/soulstone/examine(mob/user)
..()
@@ -153,6 +153,9 @@
req_access = null
req_one_access = null
/obj/machinery/airalarm/syndicate //general syndicate access
req_access = list(ACCESS_SYNDICATE)
//all air alarms in area are connected via magic
/area
var/list/air_vent_names = list()
+14 -14
View File
@@ -92,7 +92,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if (citadel_client_procs(href_list))
return
// CITADEL End
switch(href_list["_src_"])
if("holder")
hsrc = holder
@@ -115,16 +115,16 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
switch(href_list["action"])
if("openLink")
src << link(href_list["link"])
var/datum/real_src = hsrc
if(QDELETED(real_src))
return
if (hsrc)
var/datum/real_src = hsrc
if(QDELETED(real_src))
return
..() //redirect to hsrc.Topic()
/client/proc/is_content_unlocked()
if(!prefs.unlock_content)
to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Only 10 bucks for 3 months! <a href='http://www.byond.com/membership'>Click Here to find out more</a>.")
to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Only 10 bucks for 3 months! <a href=\"https://secure.byond.com/membership\">Click Here to find out more</a>.")
return 0
return 1
@@ -267,7 +267,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
log_access("Failed login: [key] - blacklisted byond version")
to_chat(src, "<span class='userdanger'>Your version of byond is blacklisted.</span>")
to_chat(src, "<span class='danger'>Byond build [byond_build] ([byond_version].[byond_build]) has been blacklisted for the following reason: [GLOB.blacklisted_builds[num2text(byond_build)]].</span>")
to_chat(src, "<span class='danger'>Please download a new version of byond. if [byond_build] is the latest, you can go to http://www.byond.com/download/build/ to download other versions.</span>")
to_chat(src, "<span class='danger'>Please download a new version of byond. If [byond_build] is the latest, you can go to <a href=\"https://secure.byond.com/download/build\">BYOND's website</a> to download other versions.</span>")
if(connecting_admin)
to_chat(src, "As an admin, you are being allowed to continue using this version, but please consider changing byond versions")
else
@@ -290,11 +290,11 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
var/cev = CONFIG_GET(number/client_error_version)
var/cwv = CONFIG_GET(number/client_warn_version)
if (byond_version < cev) //Out of date client.
to_chat(src, "<span class='danger'><b>Your version of byond is too old:</b></span>")
to_chat(src, "<span class='danger'><b>Your version of BYOND is too old:</b></span>")
to_chat(src, CONFIG_GET(string/client_error_message))
to_chat(src, "Your version: [byond_version]")
to_chat(src, "Required version: [cev] or later")
to_chat(src, "Visit http://www.byond.com/download/ to get the latest version of byond.")
to_chat(src, "Visit <a href=\"https://secure.byond.com/download\">BYOND's website</a> to get the latest version of BYOND.")
if (connecting_admin)
to_chat(src, "Because you are an admin, you are being allowed to walk past this limitation, But it is still STRONGLY suggested you upgrade")
else
@@ -306,14 +306,14 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
msg += CONFIG_GET(string/client_warn_message) + "<br><br>"
msg += "Your version: [byond_version]<br>"
msg += "Required version to remove this message: [cwv] or later<br>"
msg += "Visit http://www.byond.com/download/ to get the latest version of byond.<br>"
msg += "Visit <a href=\"https://secure.byond.com/download\">BYOND's website</a> to get the latest version of BYOND.<br>"
src << browse(msg, "window=warning_popup")
else
to_chat(src, "<span class='danger'><b>Your version of byond may be getting out of date:</b></span>")
to_chat(src, CONFIG_GET(string/client_warn_message))
to_chat(src, "Your version: [byond_version]")
to_chat(src, "Required version to remove this message: [cwv] or later")
to_chat(src, "Visit http://www.byond.com/download/ to get the latest version of byond.")
to_chat(src, "Visit <a href=\"https://secure.byond.com/download\">BYOND's website</a> to get the latest version of BYOND.")
if (connection == "web" && !connecting_admin)
if (!CONFIG_GET(flag/allow_webclient))
@@ -403,9 +403,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
var/datum/verbs/menu/menuitem = GLOB.menulist[thing]
if (menuitem)
menuitem.Load_checked(src)
hook_vr("client_new",list(src)) // CIT CHANGE - hook for client/New() changes
Master.UpdateTickRate()
//////////////
@@ -484,7 +484,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey])
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
message_admins("<span class='adminnotice'>Failed Login: [key] - New account attempting to connect during panic bunker</span>")
to_chat(src, "Sorry but the server is currently not accepting connections from never before seen players.")
to_chat(src, "You must first join the Discord to verify your account before joining this server. Please ping an admin once you've joined and read the rules. https://discord.gg/E6SQuhz") //CIT CHANGE - makes the panic bunker disconnect message point to the discord
var/list/connectiontopic_a = params2list(connectiontopic)
var/list/panic_addr = CONFIG_GET(string/panic_server_address)
if(panic_addr && !connectiontopic_a["redirect"])
+1 -1
View File
@@ -197,7 +197,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(CONFIG_GET(flag/roundstart_traits))
dat += "<center><h2>Quirk Setup</h2>"
dat += "<a href='?_src_=prefs;preference=trait;task=menu'>Configure Quirks</a><br></center>"
dat += "<center><b>Current quirks:</b> [all_quirks.len ? all_quirks.Join(", ") : "None"]</center>"
dat += "<center><b>Current Quirks:</b> [all_quirks.len ? all_quirks.Join(", ") : "None"]</center>"
dat += "<h2>Identity</h2>"
dat += "<table width='100%'><tr><td width='75%' valign='top'>"
if(jobban_isbanned(user, "appearance"))
+11 -6
View File
@@ -11,22 +11,27 @@
/datum/round_event/mass_hallucination/start()
switch(rand(1,4))
if(1) //same sound for everyone
var/sound = pick("explosion","far_explosion","phone","alarm","hallelujah","creepy","ratvar","shuttle_dock",
"wall_decon","door_hack","blob_alert","tesla","malf_ai","meteors")
var/sound = pick("airlock","airlock_pry","console","explosion","far_explosion","mech","glass","alarm","beepsky","mech","wall_decon","door_hack","tesla")
for(var/mob/living/carbon/C in GLOB.alive_mob_list)
new /datum/hallucination/sounds(C, TRUE, sound)
if(2 to 4)
if(2)
var/weirdsound = pick("phone","hallelujah","highlander","hyperspace","game_over","creepy","tesla")
for(var/mob/living/carbon/C in GLOB.alive_mob_list)
new /datum/hallucination/weird_sounds(C, TRUE, weirdsound)
if(3)
var/stationmessage = pick("ratvar","shuttle_dock","blob_alert","malf_ai","meteors","supermatter")
for(var/mob/living/carbon/C in GLOB.alive_mob_list)
new /datum/hallucination/stationmessage(C, TRUE, stationmessage)
if(4 to 6)
var/picked_hallucination = pick( /datum/hallucination/bolts,
/datum/hallucination/whispers,
/datum/hallucination/chat,
/datum/hallucination/message,
/datum/hallucination/bolts,
/datum/hallucination/fake_flood,
/datum/hallucination/battle,
/datum/hallucination/fire,
/datum/hallucination/self_delusion,
/datum/hallucination/fakeattacker,
/datum/hallucination/death,
/datum/hallucination/xeno_attack,
/datum/hallucination/delusion,
/datum/hallucination/oh_yeah)
for(var/mob/living/carbon/C in GLOB.alive_mob_list)
+2 -1
View File
@@ -15,7 +15,8 @@
var/reagentsAmount = 100
var/list/saferChems = list("water","carbon","flour","cleaner","nutriment","condensedcapsaicin","mushroomhallucinogen","lube","pink_glitter",
"plantbgone","blood","charcoal","space_drugs","morphine","holywater","ethanol","hot_coco","sacid","mindbreaker","rotatium","skewium",
"pax","laughter","concentrated_barbers_aid","colorful_reagent","dizzysolution","tiresolution","salt","beer","hair_dye","sugar","white_glitter","growthserum")
"pax","laughter","concentrated_barbers_aid","colorful_reagent","dizzysolution","tiresolution","sodiumchloride","beer","hair_dye","sugar","white_glitter","growthserum")
//needs to be chemid unit checked at some point
/datum/round_event/vent_clog/announce()
priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "Atmospherics alert")
File diff suppressed because it is too large Load Diff
@@ -298,6 +298,29 @@
icon_state = "grappabottle"
list_reagents = list("grappa" = 100)
/obj/item/reagent_containers/food/drinks/bottle/sake
name = "Ryo's traditional sake"
desc = "Sweet as can be, and burns like fire going down."
icon_state = "sakebottle"
list_reagents = list("sake" = 100)
/obj/item/reagent_containers/food/drinks/bottle/sake/Initialize()
. = ..()
if(prob(10))
name = "Fluffy Tail Sake"
desc += " On the bottle is a picture of a kitsune with nine touchable tails."
icon_state = "sakebottle_k"
else if(prob(10))
name = "Inubashiri's Home Brew"
desc += " Awoo."
icon_state = "sakebottle_i"
/obj/item/reagent_containers/food/drinks/bottle/fernet
name = "Fernet Bronca"
desc = "A bottle of pure Fernet Bronca, produced in Cordoba Space Station"
icon_state = "fernetbottle"
list_reagents = list("fernet" = 100)
//////////////////////////JUICES AND STUFF ///////////////////////
/obj/item/reagent_containers/food/drinks/bottle/orangejuice
@@ -662,3 +662,22 @@
id = "mojito"
results = list("mojito" = 5)
required_reagents = list("rum" = 1, "sugar" = 1, "limejuice" = 1, "sodawater" = 1, "menthol" = 1)
/datum/chemical_reaction/fernet_cola
name = "Fernet Cola"
id = "fernet_cola"
results = list("fernet_cola" = 2)
required_reagents = list("fernet" = 1, "cola" = 1)
/datum/chemical_reaction/fanciulli
name = "Fanciulli"
id = "fanciulli"
results = list("fanciulli" = 2)
required_reagents = list("manhattan" = 1, "fernet" = 1)
/datum/chemical_reaction/branca_menta
name = "Branca Menta"
id = "branca_menta"
results = list("branca_menta" = 3)
required_reagents = list("fernet" = 1, "creme_de_menthe" = 1, "ice" = 1)
@@ -17,6 +17,7 @@
var/obj/item/stock_parts/cell/battery // Internal cell which most circuits need to work.
var/cell_type = /obj/item/stock_parts/cell
var/can_charge = TRUE //Can it be charged in a recharger?
var/can_fire_equipped = FALSE //Can it fire/throw weapons when the assembly is being held?
var/charge_sections = 4
var/charge_tick = FALSE
var/charge_delay = 4
@@ -603,7 +604,11 @@
/obj/item/electronic_assembly/medium/gun
name = "type-e electronic mechanism"
icon_state = "setup_medium_gun"
desc = "It's a case, for building medium-sized electronics with. This one resembles a gun, or some type of tool, if you're feeling optimistic."
item_state = "circuitgun"
desc = "It's a case, for building medium-sized electronics with. This one resembles a gun, or some type of tool, if you're feeling optimistic. It can fire guns and throw items while the user is holding it."
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
can_fire_equipped = TRUE
/obj/item/electronic_assembly/medium/radio
name = "type-f electronic mechanism"
@@ -73,7 +73,7 @@
// For really fat machines.
/obj/item/integrated_circuit/passive/power/relay/large
name = "large tesla power relay"
desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them, now in industiral size!"
desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them, now in industrial size!"
w_class = WEIGHT_CLASS_BULKY
extended_desc = "The siphon drains 2 kW of power from an APC in the same room as it as long as it has charge remaining. It will always drain \
from the 'equipment' power channel."
@@ -89,7 +89,7 @@
desc = "Produces electricity from chemicals."
icon_state = "chemical_cell"
extended_desc = "This is effectively an internal beaker. It will consume and produce power from plasma, slime jelly, welding fuel, carbon,\
ethanol, nutriments, and blood in order of decreasing efficiency. It will consume fuel only if the battery can take more energy."
ethanol, nutriment, and blood in order of decreasing efficiency. It will consume fuel only if the battery can take more energy."
container_type = OPENCONTAINER
complexity = 4
inputs = list()
@@ -1,6 +1,6 @@
/obj/item/integrated_circuit/input/card_reader
name = "card reader"
desc = "A circuit that can read registred name, assignment and a PassKey string from an ID card."
desc = "A circuit that can read the registred name, assignment, and PassKey string from an ID card."
icon_state = "card_reader"
complexity = 4
@@ -94,7 +94,7 @@
/obj/item/integrated_circuit/arithmetic/division
name = "division circuit"
desc = "This circuit can divide numbers, just don't think about trying to divide by zero!"
desc = "This circuit can divide numbers. Don't even think about trying to divide by zero!"
extended_desc = "The order that the calculation goes is;<br>\
result = ((((A / B) / C) / D) ... ) and so on, until all pins have been divided. \
Null pins, and pins containing 0, are ignored. Pin A <b>must</b> be a number or the circuit will not function."
@@ -142,8 +142,8 @@
/obj/item/integrated_circuit/arithmetic/sign
name = "sign circuit"
desc = "This will say if a number is positive, negative, or zero."
extended_desc = "Will output 1, -1, or 0, depending on if A is a postive number, a negative number, or zero, respectively."
desc = "This circuit can tell if a number is positive, negative, or zero."
extended_desc = "Will output 1, -1, or 0, depending on if A is a positive number, a negative number, or zero, respectively."
icon_state = "sign"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
@@ -212,8 +212,8 @@
/obj/item/integrated_circuit/arithmetic/average
name = "average circuit"
desc = "This circuit is of average quality, however it will compute the average for numbers you give it."
extended_desc = "Note that null pins are ignored, where as a pin containing 0 is included in the averaging calculation."
desc = "This circuit is of average quality. It will compute the average of the numbers you give it."
extended_desc = "Note that null pins are ignored, whereas a pin containing 0 is included in the averaging calculation."
icon_state = "average"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
@@ -240,7 +240,7 @@
icon_state = "pi"
inputs = list()
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/arithmetic/pi/Initialize()
. = ..()
desc = "Not recommended for cooking. Outputs '[PI]' when it receives a pulse."
@@ -276,7 +276,7 @@
/obj/item/integrated_circuit/arithmetic/square_root
name = "square root circuit"
desc = "This outputs the square root of a number you input."
desc = "This outputs the square root of the number you input."
icon_state = "square_root"
inputs = list("A" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
@@ -69,7 +69,7 @@
/obj/item/integrated_circuit/converter/refcode
name = "reference encoder"
desc = "This circuit can encode a reference into a string, which can then be read by an EPV2 circuit."
desc = "This circuit can encode a reference into a string, which can then be read by a reference decoder circuit."
icon_state = "ref-string"
inputs = list("input" = IC_PINTYPE_REF)
outputs = list("output" = IC_PINTYPE_STRING)
@@ -88,7 +88,7 @@
/obj/item/integrated_circuit/converter/refdecode
name = "reference decoder"
desc = "This circuit can convert an encoded reference to actual reference."
desc = "This circuit can convert an encoded reference to an actual reference."
icon_state = "ref-string"
inputs = list("input" = IC_PINTYPE_STRING)
outputs = list("output" = IC_PINTYPE_REF)
@@ -180,8 +180,8 @@
/obj/item/integrated_circuit/converter/separator
name = "separator"
desc = "This splits as single string into two at the relative split point."
extended_desc = "This circuits splits a given string into two, based on the string, and the index value. \
desc = "This splits a single string into two at the relative split point."
extended_desc = "This circuit splits a given string into two, based on the string and the index value. \
The index splits the string <b>after</b> the given index, including spaces. So 'a person' with an index of '3' \
will split into 'a p' and 'erson'."
icon_state = "split"
@@ -240,9 +240,10 @@
/obj/item/integrated_circuit/converter/findstring
name = "find text"
desc = "This gives position of sample in the string. Or returns 0."
desc = "This outputs the position of the sample in the string, or returns 0."
extended_desc = "The first pin is the string to be examined. The second pin is the sample to be found. \
For example, 'eat this burger' will give you position 4. This circuit isn't case sensitive."
For example, inputting 'my wife has caught on fire' with 'has' as the sample will give you position 9. \
This circuit isn't case sensitive, and it does not ignore spaces."
complexity = 4
inputs = list(
"string" = IC_PINTYPE_STRING,
@@ -413,7 +414,7 @@
/obj/item/integrated_circuit/converter/rgb2hex
name = "rgb to hexadecimal"
desc = "This circuit can convert a RGB (Red, Green, Blue) color to a Hexadecimal RGB color."
extended_desc = "The first pin controls red amount, the second pin controls green amount, and the third controls blue amount. All go from 0-255."
extended_desc = "The first pin controls red amount, the second pin controls green amount, and the third controls blue amount. They all go from 0-255."
icon_state = "rgb-hex"
inputs = list(
"red" = IC_PINTYPE_NUMBER,
@@ -4,7 +4,7 @@
/obj/item/integrated_circuit/transfer/multiplexer
name = "two multiplexer"
desc = "This is what those in the business tend to refer to as a 'mux' or data selector. It moves data from one of the selected inputs to the output."
desc = "This is what those in the business tend to refer to as a 'mux', or data selector. It moves data from one of the selected inputs to the output."
extended_desc = "The first input pin is used to select which of the other input pins which has its data moved to the output. \
If the input selection is outside the valid range then no output is given."
complexity = 2
@@ -147,7 +147,7 @@
/obj/item/integrated_circuit/transfer/wire_node
name = "wire node"
desc = "Just wire node to make wiring more easy.Transfer pulse from in to out."
desc = "Just a wire node to make wiring easier. Transfers the pulse from in to out."
icon_state = "wire_node"
activators = list("pulse in" = IC_PINTYPE_PULSE_IN, "pulse out" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
@@ -150,7 +150,7 @@
/obj/item/integrated_circuit/input/slime_scanner
name = "slime_scanner"
desc = "A very small version of the xenobio analyser. This allows the machine to know every needed properties of slime. Output mutation list is non associative."
desc = "A very small version of the xenobio analyser. This allows the machine to know every needed properties of slime. Output mutation list is non-associative."
icon_state = "medscan_adv"
complexity = 12
inputs = list("target" = IC_PINTYPE_REF)
@@ -193,8 +193,8 @@
/obj/item/integrated_circuit/input/plant_scanner
name = "integrated plant analyzer"
desc = "A very small version of the plant analyser. This allows the machine to know all valuable params of plants in trays. \
It cannot scan seeds nor fruits, only plants."
desc = "A very small version of the plant analyser. This allows the machine to know all valuable parameters of plants in trays. \
It can only scan plants, not seeds or fruits."
icon_state = "medscan_adv"
complexity = 12
inputs = list("target" = IC_PINTYPE_REF)
@@ -259,9 +259,9 @@
/obj/item/integrated_circuit/input/gene_scanner
name = "gene scanner"
desc = "This circuit will scan plant for traits and reagent genes. Output is non-associative."
desc = "This circuit will scan the target plant for traits and reagent genes. Output is non-associative."
extended_desc = "This allows the machine to scan plants in trays for reagent and trait genes. \
It cannot scan seeds nor fruits, only plants."
It can only scan plants, not seeds or fruits."
inputs = list(
"target" = IC_PINTYPE_REF
)
@@ -358,9 +358,9 @@
/obj/item/integrated_circuit/input/turfpoint
name = "Tile pointer"
desc = "This circuit will get tile ref with given absolute coordinates."
desc = "This circuit will get a tile ref with the provided absolute coordinates."
extended_desc = "If the machine cannot see the target, it will not be able to calculate the correct direction.\
This circuit works only inside an assembly."
This circuit only works while inside an assembly."
icon_state = "numberpad"
complexity = 5
inputs = list("X" = IC_PINTYPE_NUMBER,"Y" = IC_PINTYPE_NUMBER)
@@ -461,7 +461,7 @@
/obj/item/integrated_circuit/input/adjacent_locator
name = "adjacent locator"
desc = "This is needed for certain devices that demand a reference for a target to act upon. This type only locates something \
that is standing a meter away from the machine."
that is standing up to a meter away from the machine."
extended_desc = "The first pin requires a ref to the kind of object that you want the locator to acquire. This means that it will \
give refs to nearby objects that are similar. If more than one valid object is found nearby, it will choose one of them at \
random."
@@ -500,9 +500,9 @@
/obj/item/integrated_circuit/input/advanced_locator_list
complexity = 6
name = "list advanced locator"
desc = "This is needed for certain devices that demand list of names for a targets to act upon. This type locates something \
that is standing in given radius up to 8 meters. Output is non-associative. Input will only consider keys if associative."
extended_desc = "The first pin requires a list of kinds of objects that you want the locator to acquire. It will locate nearby objects by name and description, \
desc = "This is needed for certain devices that demand list of names for a target to act upon. This type locates something \
that is standing in given radius of up to 8 meters. Output is non-associative. Input will only consider keys if associative."
extended_desc = "The first pin requires a list of the kinds of objects that you want the locator to acquire. It will locate nearby objects by name and description, \
and will then provide a list of all found objects which are similar. \
The second pin is a radius."
inputs = list("desired type ref" = IC_PINTYPE_LIST, "radius" = IC_PINTYPE_NUMBER)
@@ -564,10 +564,10 @@
complexity = 6
name = "advanced locator"
desc = "This is needed for certain devices that demand a reference for a target to act upon. This type locates something \
that is standing in given radius up to 8 meters"
extended_desc = "The first pin requires a ref to a kind of object that you want the locator to acquire. This means that it will \
give refs to nearby objects which are similar. If this pin is string, this locator will search for an \
item by matching desired text in it's name and description. If more than one valid object is found nearby, it will choose one of them at \
that is standing in given radius of up to 8 meters"
extended_desc = "The first pin requires a ref to the kind of object that you want the locator to acquire. This means that it will \
give refs to nearby objects which are similar. If this pin is a string, the locator will search for an \
item matching the desired text in its name and description. If more than one valid object is found nearby, it will choose one of them at \
random. The second pin is a radius."
inputs = list("desired type" = IC_PINTYPE_ANY, "radius" = IC_PINTYPE_NUMBER)
outputs = list("located ref" = IC_PINTYPE_REF)
@@ -617,7 +617,7 @@
/obj/item/integrated_circuit/input/signaler
name = "integrated signaler"
desc = "Signals from a signaler can be received with this, allowing for remote control. Additionally, it can send signals as well."
desc = "Signals from a signaler can be received with this, allowing for remote control. It can also send signals."
extended_desc = "When a signal is received from another signaler, the 'on signal received' activator pin will be pulsed. \
The two input pins are to configure the integrated signaler's settings. Note that the frequency should not have a decimal in it, \
meaning the default frequency is expressed as 1457, not 145.7. To send a signal, pulse the 'send signal' activator pin."
@@ -699,11 +699,11 @@
/obj/item/integrated_circuit/input/ntnet_packet
name = "NTNet networking circuit"
desc = "Enables the sending and receiving of messages on NTNet via packet data protocol."
extended_desc = "Data can be send or received using the second pin on each side, \
desc = "Enables the sending and receiving of messages over NTNet via packet data protocol."
extended_desc = "Data can be sent or received using the second pin on each side, \
with additonal data reserved for the third pin. When a message is received, the second activation pin \
will pulse whatever's connected to it. Pulsing the first activation pin will send a message. Message \
can be send to multiple recepients. Addresses must be separated with ; symbol."
will pulse whatever is connected to it. Pulsing the first activation pin will send a message. Messages \
can be sent to multiple recepients. Addresses must be separated with a semicolon, like this: Address1;Address2;Etc."
icon_state = "signal"
complexity = 2
cooldown_per_use = 1
@@ -756,11 +756,11 @@
/obj/item/integrated_circuit/input/ntnet_advanced
name = "Low level NTNet transreciever"
desc = "Enables the sending and receiving of messages on NTNet via packet data protocol. Allows advanced control of message contents and signalling. Must use associative lists. Outputs associative list. Has a slower transmission rate than normal NTNet circuits, due to increased data processing complexity.."
extended_desc = "Data can be send or received using the second pin on each side, \
desc = "Enables the sending and receiving of messages over NTNet via packet data protocol. Allows advanced control of message contents and signalling. Must use associative lists. Outputs associative list. Has a slower transmission rate than normal NTNet circuits, due to increased data processing complexity."
extended_desc = "Data can be sent or received using the second pin on each side, \
with additonal data reserved for the third pin. When a message is received, the second activation pin \
will pulse whatever's connected to it. Pulsing the first activation pin will send a message. Message \
can be send to multiple recepients. Addresses must be separated with ; symbol."
will pulse whatever is connected to it. Pulsing the first activation pin will send a message. Messages \
can be sent to multiple recepients. Addresses must be separated with a semicolon, like this: Address1;Address2;Etc."
icon_state = "signal"
complexity = 4
cooldown_per_use = 10
@@ -802,7 +802,7 @@
/obj/item/integrated_circuit/input/gps
name = "global positioning system"
desc = "This allows you to easily know the position of a machine containing this device."
extended_desc = "The GPS's coordinates it gives is absolute, not relative."
extended_desc = "The coordinates that the GPS outputs are absolute, not relative."
icon_state = "gps"
complexity = 4
inputs = list()
@@ -829,7 +829,7 @@
/obj/item/integrated_circuit/input/microphone
name = "microphone"
desc = "Useful for spying on people or for voice activated machines."
desc = "Useful for spying on people, or for voice-activated machines."
extended_desc = "This will automatically translate most languages it hears to Galactic Common. \
The first activation pin is always pulsed when the circuit hears someone talk, while the second one \
is only triggered if it hears someone speaking a language other than Galactic Common."
@@ -921,7 +921,7 @@
/obj/item/integrated_circuit/input/obj_scanner
name = "scanner"
desc = "Scans and obtains a reference for any objects you use on the assembly."
extended_desc = "If the 'put down' pin is set to true, the assembly will take the scanned object from your hands to it's location. \
extended_desc = "If the 'put down' pin is set to true, the assembly will take the scanned object from your hands to its location. \
Useful for interaction with the grabber. The scanner only works using the help intent."
icon_state = "recorder"
complexity = 4
@@ -948,7 +948,7 @@
name = "internal battery monitor"
desc = "This monitors the charge level of an internal battery."
icon_state = "internalbm"
extended_desc = "This circuit will give you values of charge, max charge, and percentage of the internal battery on demand."
extended_desc = "This circuit will give you the values of charge, max charge, and the current percentage of the internal battery on demand."
w_class = WEIGHT_CLASS_TINY
complexity = 1
inputs = list()
@@ -981,9 +981,9 @@
/obj/item/integrated_circuit/input/externalbm
name = "external battery monitor"
desc = "This can help to watch battery state of any device in view"
desc = "This can read the battery state of any device in view."
icon_state = "externalbm"
extended_desc = "This circuit will give you values of charge, max charge, and percentage of any device or battery in view"
extended_desc = "This circuit will give you the charge, max charge, and the current percentage values of any device or battery in view."
w_class = WEIGHT_CLASS_TINY
complexity = 2
inputs = list("target" = IC_PINTYPE_REF)
@@ -1016,7 +1016,7 @@
/obj/item/integrated_circuit/input/ntnetsc
name = "NTNet scanner"
desc = "This can return NTNet IDs of a component inside the given object, if there are any."
desc = "This can return the NTNet IDs of a component inside the given object, if there are any."
icon_state = "signalsc"
w_class = WEIGHT_CLASS_TINY
complexity = 2
@@ -17,8 +17,8 @@
/obj/item/integrated_circuit/lists/pick
name = "pick circuit"
desc = "This circuit will pick a random element from the input list, and output said element."
extended_desc = "Input list is unmodified."
desc = "This circuit will pick a random element from the input list, and output that element."
extended_desc = "The input list is not modified."
icon_state = "addition"
outputs = list(
"result" = IC_PINTYPE_ANY
@@ -70,7 +70,7 @@
/obj/item/integrated_circuit/lists/search
name = "search circuit"
desc = "This circuit will get the index location of the desired element in a list."
extended_desc = "Search will start at 1 position and will return first matching position."
extended_desc = "Search will start at position 1 and will return the first matching position."
inputs = list(
"list" = IC_PINTYPE_LIST,
"item" = IC_PINTYPE_ANY
@@ -104,8 +104,8 @@
/obj/item/integrated_circuit/lists/filter
name = "filter circuit"
desc = "This circuit will search through a list for anything matching the desired element(s) and outputs two lists: \
one containing just matching elements, and one with matching elements filtered out."
extended_desc = "Sample accepts lists. If no match is found, original list is sent to output 1."
one containing only the matching elements, and one with the matching elements filtered out."
extended_desc = "Sample accepts lists. If no match is found, the original list is sent to output 1."
inputs = list(
"input list" = IC_PINTYPE_LIST,
"sample" = IC_PINTYPE_ANY
@@ -168,7 +168,7 @@
/obj/item/integrated_circuit/lists/listset
name = "list set circuit"
desc = "This circuit will remove any duplicate entries from a list."
extended_desc = "If there are no duplicate entries, result list will be unchanged."
extended_desc = "If there are no duplicate entries, the output list will be unchanged."
inputs = list(
"list" = IC_PINTYPE_LIST
)
@@ -189,7 +189,7 @@
/obj/item/integrated_circuit/lists/at
name = "at circuit"
desc = "This circuit will pick an element from a list by the input index."
extended_desc = "If there is no element with such index, result will be null."
extended_desc = "If there is no element at the given index, the result will be null."
inputs = list(
"list" = IC_PINTYPE_LIST,
"index" = IC_PINTYPE_INDEX
@@ -225,7 +225,7 @@
/obj/item/integrated_circuit/lists/delete
name = "delete circuit"
desc = "This circuit will remove an element from a list by the index."
extended_desc = "If there is no element with such index, result list will be unchanged."
extended_desc = "If there is no element at the given index, the result list will be unchanged."
inputs = list(
"list" = IC_PINTYPE_LIST,
"index" = IC_PINTYPE_INDEX
@@ -254,7 +254,7 @@
/obj/item/integrated_circuit/lists/write
name = "write circuit"
desc = "This circuit will write an element to a list at the given index location."
extended_desc = "If there is no element with such index, it will give the same list as before."
extended_desc = "If there is no element at the given index, it will output the same list as before."
inputs = list(
"list" = IC_PINTYPE_LIST,
"index" = IC_PINTYPE_INDEX,
@@ -313,7 +313,7 @@
/obj/item/integrated_circuit/lists/jointext
name = "join text circuit"
desc = "This circuit will combine two lists into one and output it as a string."
desc = "This circuit will combine two lists into one, and output it as a string."
extended_desc = "Default settings will encode the entire list into a string."
icon_state = "join"
inputs = list(
@@ -351,7 +351,7 @@
/obj/item/integrated_circuit/lists/constructor
name = "large list constructor"
desc = "This circuit will build a list out of sixteen input values."
desc = "This circuit will build a list out of up to sixteen input values."
icon_state = "constr8"
inputs = list()
outputs = list(
@@ -383,20 +383,20 @@
/obj/item/integrated_circuit/lists/constructor/small
name = "list constructor"
desc = "This circuit will build a list out of four input values."
desc = "This circuit will build a list out of up to four input values."
icon_state = "constr"
number_of_pins = 4
/obj/item/integrated_circuit/lists/constructor/medium
name = "medium list constructor"
desc = "This circuit will build a list out of eight input values."
desc = "This circuit will build a list out of up to eight input values."
icon_state = "constr8"
number_of_pins = 8
/obj/item/integrated_circuit/lists/deconstructor
name = "large list deconstructor"
desc = "This circuit will write first sixteen entries of input list, starting with index, into the output values."
desc = "This circuit will write the first sixteen entries of its input list, starting with the index, into the output values."
icon_state = "deconstr8"
inputs = list(
"input" = IC_PINTYPE_LIST,
@@ -428,11 +428,11 @@
/obj/item/integrated_circuit/lists/deconstructor/small
name = "list deconstructor"
desc = "This circuit will write first four entries of input list, starting with index, into the output values."
desc = "This circuit will write the first four entries of its input list, starting with the index, into the output values."
icon_state = "deconstr"
number_of_pins = 4
/obj/item/integrated_circuit/lists/deconstructor/medium
name = "medium list deconstructor"
desc = "This circuit will write first eight entries of input list, starting with index, into the output values."
desc = "This circuit will write the first eight entries of its input list, starting with the index, into the output values."
number_of_pins = 8
@@ -89,7 +89,7 @@
/obj/item/integrated_circuit/logic/binary/rslatch
name = "RS latch"
desc = "This gate is a synchronized RS latch. If both R and S are true, state will not change."
desc = "This gate is a synchronized RS latch. If both R and S are true, its state will not change."
icon_state = "sr_nor"
inputs = list("S" = IC_PINTYPE_ANY,"R" = IC_PINTYPE_ANY)
outputs = list("Q" = IC_PINTYPE_BOOLEAN,"!Q" = IC_PINTYPE_BOOLEAN)
@@ -6,8 +6,9 @@
desc = "This somewhat complicated system allows one to slot in a gun, direct it towards a position, and remotely fire it."
extended_desc = "The firing mechanism can slot in any energy weapon. \
The first and second inputs need to be numbers which correspond to coordinates for the gun to fire at relative to the machine itself. \
The 'fire' activator will cause the mechanism to attempt to fire the weapon at the coordinates, if possible. Mode is switch between \
lethal (TRUE) or stun (FALSE) modes. It uses the internal battery of the weapon."
The 'fire' activator will cause the mechanism to attempt to fire the weapon at the coordinates, if possible. Mode will switch between \
lethal (TRUE) or stun (FALSE) modes. It uses the internal battery of the weapon itself, not the assembly. If you wish to fire the gun while the circuit is in \
hand, you will need to use an assembly that is a gun."
complexity = 20
w_class = WEIGHT_CLASS_SMALL
size = 3
@@ -80,7 +81,7 @@
/obj/item/integrated_circuit/manipulation/weapon_firing/do_work()
if(!installed_gun || !installed_gun.handle_pins())
return
if(!isturf(assembly.loc))
if(!isturf(assembly.loc) && !(assembly.can_fire_equipped && ishuman(assembly.loc)))
return
set_pin_data(IC_OUTPUT, 1, WEAKREF(installed_gun))
push_data()
@@ -99,6 +100,7 @@
var/target_x = CLAMP(T.x + xo.data, 0, world.maxx)
var/target_y = CLAMP(T.y + yo.data, 0, world.maxy)
assembly.visible_message("<span class='danger'>[assembly] fires [installed_gun]!</span>")
shootAt(locate(target_x, target_y, T.z))
/obj/item/integrated_circuit/manipulation/weapon_firing/proc/shootAt(turf/target)
@@ -134,8 +136,8 @@
desc = "This allows a machine to move in a given direction."
icon_state = "locomotion"
extended_desc = "The circuit accepts a 'dir' number as a direction to move towards.<br>\
Pulsing the 'step towards dir' activator pin will cause the machine to move a meter in that direction, assuming it is not \
being held, or anchored in some way. It should be noted that the ability to move is dependant on the type of assembly that this circuit inhabits."
Pulsing the 'step towards dir' activator pin will cause the machine to move one step in that direction, assuming it is not \
being held, or anchored in some way. It should be noted that the ability to move is dependant on the type of assembly that this circuit inhabits; only drone assemblies can move."
w_class = WEIGHT_CLASS_SMALL
complexity = 10
cooldown_per_use = 1
@@ -169,9 +171,9 @@
/obj/item/integrated_circuit/manipulation/grenade
name = "grenade primer"
desc = "This circuit comes with the ability to attach most types of grenades and prime them at will."
extended_desc = "Time between priming and detonation is limited to between 1 to 12 seconds but is optional. \
If unset, not a number, or a number less than 1 then the grenade's built-in timing will be used. \
Beware: Once primed there is no aborting the process!"
extended_desc = "The time between priming and detonation is limited to between 1 to 12 seconds, but is optional. \
If the input is not set, not a number, or a number less than 1, the grenade's built-in timing will be used. \
Beware: Once primed, there is no aborting the process!"
icon_state = "grenade"
complexity = 30
cooldown_per_use = 10
@@ -243,9 +245,9 @@
name = "plant manipulation module"
desc = "Used to uproot weeds and harvest/plant trays."
icon_state = "plant_m"
extended_desc = "The circuit accepts a reference to a hydroponic tray or an item in an adjacent tile. \
Mode input(0-harvest, 1-uproot weeds, 2-uproot plant, 3-plant seed) determines action. \
Harvesting returns a list of the harvested plants."
extended_desc = "The circuit accepts a reference to a hydroponic tray or an item on an adjacent tile. \
Mode input (0-harvest, 1-uproot weeds, 2-uproot plant, 3-plant seed) determines action. \
Harvesting outputs a list of the harvested plants."
w_class = WEIGHT_CLASS_TINY
complexity = 10
inputs = list("tray" = IC_PINTYPE_REF,"mode" = IC_PINTYPE_NUMBER,"item" = IC_PINTYPE_REF)
@@ -345,9 +347,9 @@
/obj/item/integrated_circuit/manipulation/grabber
name = "grabber"
desc = "A circuit with it's own inventory for items, used to grab and store things."
desc = "A circuit with its own inventory for items. Used to grab and store things."
icon_state = "grabber"
extended_desc = "The circuit accepts a reference to an object to be grabbed and can store up to 10 objects. Modes: 1 to grab, 0 to eject the first object, and -1 to eject all objects."
extended_desc = "This circuit accepts a reference to an object to be grabbed, and can store up to 10 objects. Modes: 1 to grab, 0 to eject the first object, and -1 to eject all objects. If you throw something from a grabber's inventory with a thrower, the grabber will update its outputs accordingly."
w_class = WEIGHT_CLASS_SMALL
size = 3
cooldown_per_use = 5
@@ -384,6 +386,10 @@
var/obj/item/U
for(U in contents)
U.forceMove(T)
update_outputs()
activate_pin(2)
/obj/item/integrated_circuit/manipulation/grabber/proc/update_outputs()
if(contents.len)
set_pin_data(IC_OUTPUT, 1, WEAKREF(contents[1]))
set_pin_data(IC_OUTPUT, 2, WEAKREF(contents[contents.len]))
@@ -393,7 +399,6 @@
set_pin_data(IC_OUTPUT, 3, contents.len)
set_pin_data(IC_OUTPUT, 4, contents)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/manipulation/grabber/attack_self(var/mob/user)
if(contents.len)
@@ -401,16 +406,14 @@
var/obj/item/U
for(U in contents)
U.forceMove(T)
set_pin_data(IC_OUTPUT, 1, null)
set_pin_data(IC_OUTPUT, 2, null)
set_pin_data(IC_OUTPUT, 3, contents.len)
update_outputs()
push_data()
/obj/item/integrated_circuit/manipulation/claw
name = "pulling claw"
desc = "Circuit which can pull things.."
icon_state = "pull_claw"
extended_desc = "The circuit accepts a reference to thing to be pulled. Modes: 0 for release. 1 for pull."
extended_desc = "This circuit accepts a reference to a thing to be pulled. Modes: 0 for release. 1 for pull."
w_class = WEIGHT_CLASS_SMALL
size = 3
cooldown_per_use = 5
@@ -464,9 +467,10 @@
/obj/item/integrated_circuit/manipulation/thrower
name = "thrower"
desc = "A compact launcher to throw things from inside or nearby tiles."
extended_desc = "The first and second inputs need to be numbers which correspond to coordinates to throw objects at relative to the machine itself. \
extended_desc = "The first and second inputs need to be numbers which correspond to the coordinates to throw objects at relative to the machine itself. \
The 'fire' activator will cause the mechanism to attempt to throw objects at the coordinates, if possible. Note that the \
projectile need to be inside the machine, or to be on an adjacent tile, and must be medium sized or smaller."
projectile needs to be inside the machine, or on an adjacent tile, and must be medium sized or smaller. The assembly \
must also be a gun if you wish to throw something while the assembly is in hand."
complexity = 25
w_class = WEIGHT_CLASS_SMALL
size = 2
@@ -497,6 +501,9 @@
if(max_w_class && (A.w_class > max_w_class))
return
if(!assembly.can_fire_equipped && ishuman(assembly.loc))
return
// Is the target inside the assembly or close to it?
if(!check_target(A, exclude_components = TRUE))
return
@@ -511,13 +518,21 @@
if(!M.temporarilyRemoveItemFromInventory(A))
return
// If the item is in a grabber circuit we'll update the grabber's outputs after we've thrown it.
var/obj/item/integrated_circuit/manipulation/grabber/G = A.loc
var/x_abs = CLAMP(T.x + target_x_rel, 0, world.maxx)
var/y_abs = CLAMP(T.y + target_y_rel, 0, world.maxy)
var/range = round(CLAMP(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1)
assembly.visible_message("<span class='danger'>[assembly] has thrown [A]!</span>")
A.forceMove(drop_location())
A.throw_at(locate(x_abs, y_abs, T.z), range, 3)
// If the item came from a grabber now we can update the outputs since we've thrown it.
if(G)
G.update_outputs()
/obj/item/integrated_circuit/manipulation/matman
name = "material manager"
desc = "This circuit is designed for automatic storage and distribution of materials."
@@ -56,14 +56,14 @@
/obj/item/integrated_circuit/memory/large
name = "large memory circuit"
desc = "This big circuit can hold eight pieces of data."
desc = "This big circuit can store eight pieces of data."
icon_state = "memory8"
power_draw_per_use = 4
number_of_pins = 8
/obj/item/integrated_circuit/memory/huge
name = "large memory stick"
desc = "This stick of memory can hold up up to sixteen pieces of data."
desc = "This stick of memory can store up up to sixteen pieces of data."
icon_state = "memory16"
w_class = WEIGHT_CLASS_SMALL
spawn_flags = IC_SPAWN_RESEARCH
@@ -92,7 +92,7 @@
/obj/item/integrated_circuit/output/light/advanced
name = "advanced light"
desc = "A light that takes a hexadecimal color value and a brightness value, and can be toggled on/off with a pulse."
desc = "A light that takes a hexadecimal color value and a brightness value, and can be toggled on/off by pulsing it."
icon_state = "light_adv"
complexity = 8
inputs = list(
@@ -28,8 +28,8 @@
extended_desc = "This circuit transmits 20 kJ of electricity every time the activator pin is pulsed. The input pin must be \
a reference to a machine to send electricity to. This can be a battery, or anything containing a battery. The machine can exist \
inside the assembly, or adjacent to it. The power is sourced from the assembly's power cell. If the target is outside of the assembly, \
some power is lost due to ineffiency.Warning!Don't stack more than 1 power transmittors.it becomes less efficient for every other \
transmission circuit in its own assembly and other nearby ones. "
some power is lost due to ineffiency. Warning! Don't stack more than 1 power transmitter, as it becomes less efficient for every other \
transmission circuit in its own assembly and other nearby ones."
w_class = WEIGHT_CLASS_BULKY
complexity = 32
power_draw_per_use = 2000
@@ -21,7 +21,7 @@
desc = "Unlike most electronics, creating smoke is completely intentional."
icon_state = "smoke"
extended_desc = "This smoke generator creates clouds of smoke on command. It can also hold liquids inside, which will go \
into the smoke clouds when activated. The reagents are consumed when smoke is made."
into the smoke clouds when activated. The reagents are consumed when the smoke is made."
ext_cooldown = 1
container_type = OPENCONTAINER
volume = 100
@@ -99,10 +99,10 @@
/obj/item/integrated_circuit/reagent/injector
name = "integrated hypo-injector"
desc = "This scary looking thing is able to pump liquids into whatever it's pointed at."
desc = "This scary looking thing is able to pump liquids into, or suck liquids out of, whatever it's pointed at."
icon_state = "injector"
extended_desc = "This autoinjector can push reagents into another container or someone else outside of the machine. The target \
must be adjacent to the machine, and if it is a person, they cannot be wearing thick clothing. Negative given amount makes injector suck out reagents."
extended_desc = "This autoinjector can push up to 30 units of reagents into another container or someone else outside of the machine. The target \
must be adjacent to the machine, and if it is a person, they cannot be wearing thick clothing. Negative given amounts makes the injector suck out reagents instead."
container_type = OPENCONTAINER
volume = 30
@@ -252,7 +252,7 @@
icon_state = "reagent_pump"
extended_desc = "This is a pump which will move liquids from the source ref to the target ref. The third pin determines \
how much liquid is moved per pulse, between 0 and 50. The pump can move reagents to any open container inside the machine, or \
outside the machine if it is next to the machine."
outside the machine if it is adjacent to the machine."
complexity = 8
inputs = list("source" = IC_PINTYPE_REF, "target" = IC_PINTYPE_REF, "injection amount" = IC_PINTYPE_NUMBER)
@@ -346,7 +346,7 @@
/obj/item/integrated_circuit/reagent/storage/cryo
name = "cryo reagent storage"
desc = "Stores liquid inside the device away from electrical components. It can store up to 60u. This will also suppress reactions."
desc = "Stores liquid inside the device away from electrical components. It can store up to 60u. This will also prevent reactions."
icon_state = "reagent_storage_cryo"
extended_desc = "This is effectively an internal cryo beaker."
@@ -359,7 +359,7 @@
/obj/item/integrated_circuit/reagent/storage/grinder
name = "reagent grinder"
desc = "This is reagent grinder. It accepts a ref to something and refines it into reagents. It can store up to 100u."
desc = "This is a reagent grinder. It accepts a ref to something, and refines it into reagents. It can store up to 100u."
icon_state = "blender"
extended_desc = ""
inputs = list(
@@ -406,7 +406,7 @@
obj/item/integrated_circuit/reagent/storage/juicer
name = "reagent juicer"
desc = "This is reagent juicer. It accepts a ref to something and refines it into reagents. It can store up to 100u."
desc = "This is a reagent juicer. It accepts a ref to something and refines it into reagents. It can store up to 100u."
icon_state = "blender"
extended_desc = ""
inputs = list(
@@ -454,7 +454,7 @@ obj/item/integrated_circuit/reagent/storage/juicer
name = "reagent scanner"
desc = "Stores liquid inside the device away from electrical components. It can store up to 60u. On pulse this beaker will send list of contained reagents."
icon_state = "reagent_scan"
extended_desc = "Mostly useful for reagent filter."
extended_desc = "Mostly useful for filtering reagents."
complexity = 8
outputs = list(
@@ -482,12 +482,12 @@ obj/item/integrated_circuit/reagent/storage/juicer
/obj/item/integrated_circuit/reagent/filter
name = "reagent filter"
desc = "Filtering liquids by list of desired or unwanted reagents."
desc = "Filters liquids by list of desired or unwanted reagents."
icon_state = "reagent_filter"
extended_desc = "This is a filter which will move liquids from the source to the target. \
It will move all reagents, except those in the unwanted list, given the fourth pin if amount value is positive, \
or it will move only desired reagents if amount is negative. The third pin determines \
how much reagent is moved per pulse, between 0 and 50. Amount is given for each separate reagent."
extended_desc = "This is a filter which will move liquids from the source to its target. \
If the amount in the fourth pin is positive, it will move all reagents except those in the unwanted list. \
If the amount in the fourth pin is negative, it will only move the reagents in the wanted list. \
The third pin determines how many reagents are moved per pulse, between 0 and 50. Amount is given for each separate reagent."
complexity = 8
inputs = list(
@@ -37,10 +37,11 @@
activate_pin(2)
/obj/item/integrated_circuit/smart/coord_basic_pathfinder
name = "coordinte pathfinder"
name = "coordinate pathfinder"
desc = "This complex circuit is able to determine what direction a given target is."
extended_desc = "This circuit uses absolute coordintes to determine where the target is. If the machine \
cannot see the target, it will not be able to calculate the correct direction.This circuit is working only in assembly."
extended_desc = "This circuit uses absolute coordinates to determine where the target is. If the machine \
cannot see the target, it will not be able to calculate the correct direction. \
This circuit will only work while inside an assembly."
icon_state = "numberpad"
complexity = 5
inputs = list("X" = IC_PINTYPE_NUMBER,"Y" = IC_PINTYPE_NUMBER,"ignore obstacles" = IC_PINTYPE_BOOLEAN)
@@ -74,8 +75,8 @@
/obj/item/integrated_circuit/smart/advanced_pathfinder
name = "advanced pathfinder"
desc = "This circuit uses a complex processor for long-range pathfinding."
extended_desc = "This circuit uses absolute coordinates for target. A path will be generated taking obstacle input into account, \
pathing around any instances of said input. The passkey provided from a card reader is used to create a valid path through doorways."
extended_desc = "This circuit uses absolute coordinates to find its target. A path will be generated to the target, taking obstacles into account, \
and pathing around any instances of said input. The passkey provided from a card reader is used to calculate a valid path through airlocks."
icon_state = "numberpad"
complexity = 40
cooldown_per_use = 50
@@ -117,4 +118,4 @@
set_pin_data(IC_OUTPUT, 1, Xn)
set_pin_data(IC_OUTPUT, 2, Yn)
push_data()
activate_pin(2)
activate_pin(2)
@@ -53,8 +53,10 @@
/obj/item/integrated_circuit/time/delay/custom
name = "custom delay circuit"
desc = "This sends a pulse signal out after a delay, critical for ensuring proper control flow in a complex machine. \
This circuit's delay can be customized, between 1/10th of a second to one hour. The delay is updated upon receiving a pulse."
desc = "This sends a pulse signal out after a delay defined in tenths of a second, critical for ensuring proper control \
flow in a complex machine. This circuit's delay can be customized, between 1/10th of a second to one hour. \
The delay is updated upon receiving a pulse."
extended_desc = "The delay is defined in tenths of a second. For instance, 4 will be a delay of 0.4 seconds, or 15 for 1.5 seconds."
icon_state = "delay"
inputs = list("delay time" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_RESEARCH
@@ -104,7 +106,9 @@
/obj/item/integrated_circuit/time/ticker/custom
name = "custom ticker"
desc = "This advanced circuit sends an automatic pulse every given interval."
desc = "This advanced circuit sends an automatic pulse every given interval, defined in tenths of a second."
extended_desc ="This advanced circuit sends an automatic pulse every given interval, defined in tenths of a second. \
For example, setting the time pin to 4 will send a pulse every 0.4 seconds, or 15 for every 1.5 seconds."
icon_state = "tick-f"
complexity = 8
delay = 2 SECONDS
@@ -115,7 +119,7 @@
/obj/item/integrated_circuit/time/ticker/custom/on_data_written()
var/delay_input = get_pin_data(IC_INPUT, 2)
if(delay_input && isnum(delay_input) )
var/new_delay = CLAMP(delay_input ,1 ,1 HOURS)
var/new_delay = CLAMP(delay_input ,1 ,1 HOURS)
delay = new_delay
..()
+1 -1
View File
@@ -1,7 +1,7 @@
# In-code keypress handling system
This whole system is heavily based off of forum_account's keyboard library.
Thanks to forum_account for saving the day, the library can be found [here](http://www.byond.com/developer/Forum_account/Keyboard)!
Thanks to forum_account for saving the day, the library can be found [here](https://secure.byond.com/developer/Forum_account/Keyboard)!
.dmf macros have some very serious shortcomings. For example, they do not allow reusing parts
of one macro in another, so giving cyborgs their own shortcuts to swap active module couldn't
+27 -4
View File
@@ -7,20 +7,23 @@
desc = "Controls a stacking machine... in theory."
density = FALSE
anchored = TRUE
var/obj/machinery/mineral/stacking_machine/machine = null
circuit = /obj/item/circuitboard/machine/stacking_unit_console
var/obj/machinery/mineral/stacking_machine/machine
var/machinedir = SOUTHEAST
speed_process = TRUE
/obj/machinery/mineral/stacking_unit_console/Initialize()
. = ..()
machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
if (machine)
machine.CONSOLE = src
else
qdel(src)
/obj/machinery/mineral/stacking_unit_console/ui_interact(mob/user)
. = ..()
if(!machine)
to_chat(user, "<span class='notice'>[src] is not linked to a machine!</span>")
return
var/obj/item/stack/sheet/s
var/dat
@@ -35,6 +38,13 @@
user << browse(dat, "window=console_stacking_machine")
/obj/machinery/mineral/stacking_unit_console/multitool_act(mob/living/user, obj/item/I)
if(istype(I, /obj/item/multitool))
var/obj/item/multitool/M = I
M.buffer = src
to_chat(user, "<span class='notice'>You store linkage information in [I]'s buffer.</span>")
return TRUE
/obj/machinery/mineral/stacking_unit_console/Topic(href, href_list)
if(..())
return
@@ -62,6 +72,7 @@
desc = "A machine that automatically stacks acquired materials. Controlled by a nearby console."
density = TRUE
anchored = TRUE
circuit = /obj/item/circuitboard/machine/stacking_machine
var/obj/machinery/mineral/stacking_unit_console/CONSOLE
var/stk_types = list()
var/stk_amt = list()
@@ -78,6 +89,18 @@
if(istype(AM, /obj/item/stack/sheet) && AM.loc == get_step(src, input_dir))
process_sheet(AM)
/obj/machinery/mineral/stacking_machine/multitool_act(mob/living/user, obj/item/I)
if(istype(I, /obj/item/multitool))
var/obj/item/multitool/M = I
if(!istype(M.buffer, /obj/machinery/mineral/stacking_unit_console))
to_chat(user, "<span class='warning'>The [I] has no linkage data in its buffer.</span>")
return FALSE
else
CONSOLE = M.buffer
CONSOLE.machine = src
to_chat(user, "<span class='notice'>You link [src] to the console in [I]'s buffer.</span>")
return TRUE
/obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/inp)
if(!(inp.type in stack_list)) //It's the first of this sheet added
var/obj/item/stack/sheet/s = new inp.type(src, 0)
@@ -1559,9 +1559,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
H.gain_trauma(/datum/brain_trauma/mild/concussion)
else
if(!I.is_sharp())
H.adjustBrainLoss(I.force / 5)
H.adjustBrainLoss(I.force * 0.2)
if(prob(I.force + ((100 - H.health)/2)) && H != user)
if(!I.is_sharp() && prob(I.force + ((100 - H.health) * 0.5)) && H != user) // rev deconversion through blunt trauma.
var/datum/antagonist/rev/rev = H.mind.has_antag_datum(/datum/antagonist/rev)
if(rev)
rev.remove_revolutionary(FALSE, user)
+2 -2
View File
@@ -207,9 +207,9 @@
if(breath_gases[/datum/gas/bz])
var/bz_partialpressure = (breath_gases[/datum/gas/bz][MOLES]/breath.total_moles())*breath_pressure
if(bz_partialpressure > 1)
hallucination += 20
hallucination += 10
else if(bz_partialpressure > 0.01)
hallucination += 5//Removed at 2 per tick so this will slowly build up
hallucination += 5
//TRITIUM
if(breath_gases[/datum/gas/tritium])
var/tritium_partialpressure = (breath_gases[/datum/gas/tritium][MOLES]/breath.total_moles())*breath_pressure
+2 -2
View File
@@ -494,7 +494,7 @@
update_canmove()
GET_COMPONENT(mood, /datum/component/mood)
if (mood)
QDEL_LIST(mood.mood_events)
QDEL_LIST_ASSOC_VAL(mood.mood_events)
mood.sanity = SANITY_GREAT
mood.update_mood()
@@ -941,7 +941,7 @@
/mob/living/rad_act(amount)
. = ..()
if(!amount || amount < RAD_MOB_SKIN_PROTECTION)
if(!amount || (amount < RAD_MOB_SKIN_PROTECTION) || has_trait(TRAIT_RADIMMUNE))
return
amount -= RAD_BACKGROUND_RADIATION // This will always be at least 1 because of how skin protection is calculated
@@ -148,9 +148,14 @@
if(loc == get_turf(target))
if(!(check_bot(target) && prob(50))) //Target is not defined at the parent. 50% chance to still try and clean so we dont get stuck on the last blood drop.
UnarmedAttack(target) //Rather than check at every step of the way, let's check before we do an action, so we can rescan before the other bot.
if(QDELETED(target)) //We done here.
target = null
mode = BOT_IDLE
return
else
shuffle = TRUE //Shuffle the list the next time we scan so we dont both go the same way.
path = list()
if(!path || path.len == 0) //No path, need a new one
//Try to produce a path to the target, and ignore airlocks to which it has access.
path = get_path_to(src, target.loc, /turf/proc/Distance_cardinal, 0, 30, id=access_card)
+19 -2
View File
@@ -204,8 +204,25 @@
/mob/living/proc/has_quirk(quirk)
return roundstart_quirks[quirk]
/mob/living/proc/remove_all_traits()
status_traits = list()
/mob/living/proc/remove_all_traits(remove_species_traits = FALSE, remove_organ_traits = FALSE, remove_quirks = FALSE)
var/list/blacklisted_sources = list()
if(!remove_species_traits)
blacklisted_sources += SPECIES_TRAIT
if(!remove_organ_traits)
blacklisted_sources += ORGAN_TRAIT
if(!remove_quirks)
blacklisted_sources += ROUNDSTART_TRAIT
for(var/kebab in status_traits)
var/skip
for(var/S in blacklisted_sources)
if(S in status_traits[kebab])
skip = TRUE
break
if(!skip)
remove_trait(kebab, null, TRUE)
CHECK_TICK
/////////////////////////////////// TRAIT PROCS ////////////////////////////////////
+1 -1
View File
@@ -289,7 +289,7 @@
/mob/proc/show_inv(mob/user)
return
//mob verbs are faster than object verbs. See http://www.byond.com/forum/?post=1326139&page=2#comment8198716 for why this isn't atom/verb/examine()
//mob verbs are faster than object verbs. See https://secure.byond.com/forum/?post=1326139&page=2#comment8198716 for why this isn't atom/verb/examine()
/mob/verb/examinate(atom/A as mob|obj|turf in view()) //It used to be oview(12), but I can't really say why
set name = "Examine"
set category = "IC"
+3
View File
@@ -105,6 +105,9 @@
/obj/machinery/power/apc/unlocked
locked = FALSE
/obj/machinery/power/apc/syndicate //general syndicate access
req_access = list(ACCESS_SYNDICATE)
/obj/machinery/power/apc/highcap/five_k
cell_type = /obj/item/stock_parts/cell/upgraded/plus
@@ -5,8 +5,9 @@
caliber = "foam_force"
icon = 'icons/obj/guns/toy.dmi'
icon_state = "foamdart"
var/modified = 0
materials = list(MAT_METAL = 11.25)
harmful = FALSE
var/modified = FALSE
/obj/item/ammo_casing/caseless/foam_dart/update_icon()
..()
@@ -25,8 +26,8 @@
/obj/item/ammo_casing/caseless/foam_dart/attackby(obj/item/A, mob/user, params)
var/obj/item/projectile/bullet/reusable/foam_dart/FD = BB
if (istype(A, /obj/item/screwdriver) && !modified)
modified = 1
FD.modified = 1
modified = TRUE
FD.modified = TRUE
FD.damage_type = BRUTE
to_chat(user, "<span class='notice'>You pop the safety cap off [src].</span>")
update_icon()
@@ -38,7 +39,7 @@
return
FD.pen = A
FD.damage = 5
FD.nodamage = 0
FD.nodamage = FALSE
to_chat(user, "<span class='notice'>You insert [A] into [src].</span>")
else
to_chat(user, "<span class='warning'>There's already something in [src].</span>")
@@ -61,4 +62,4 @@
desc = "Whose smart idea was it to use toys as crowd control? Ages 18 and up."
projectile_type = /obj/item/projectile/bullet/reusable/foam_dart/riot
icon_state = "foamdart_riot"
materials = list(MAT_METAL = 1000)
materials = list(MAT_METAL = 1125)
@@ -60,7 +60,9 @@
icon_state = "foambox"
ammo_type = /obj/item/ammo_casing/caseless/foam_dart
max_ammo = 40
materials = list(MAT_METAL = 500)
/obj/item/ammo_box/foambox/riot
icon_state = "foambox_riot"
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot
materials = list(MAT_METAL = 50000)
@@ -3,12 +3,12 @@
desc = "I hope you're wearing eye protection."
damage = 0 // It's a damn toy.
damage_type = OXY
nodamage = 1
nodamage = TRUE
icon = 'icons/obj/guns/toy.dmi'
icon_state = "foamdart_proj"
ammo_type = /obj/item/ammo_casing/caseless/foam_dart
range = 10
var/modified = 0
var/modified = FALSE
var/obj/item/pen/pen = null
/obj/item/projectile/bullet/reusable/foam_dart/handle_drop()
@@ -6,4 +6,4 @@
if(ishuman(target))
var/mob/living/carbon/human/M = target
M.adjustBrainLoss(20)
M.hallucination += 20
M.hallucination += 30
@@ -467,7 +467,8 @@ obj/machinery/chem_dispenser/proc/work_animation()
"creme_de_menthe",
"creme_de_cacao",
"triple_sec",
"sake"
"sake",
"fernet"
)
emagged_reagents = list(
"ethanol",
@@ -1238,7 +1238,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_desc = "Like having your brain smashed out by a slice of lemon wrapped around a large gold brick."
/datum/reagent/consumable/ethanol/gargle_blaster/on_mob_life(mob/living/M)
M.dizziness +=6
M.dizziness +=1.5
switch(current_cycle)
if(15 to 45)
if(!M.slurring)
@@ -1267,7 +1267,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/neurotoxin/on_mob_life(mob/living/carbon/M)
M.Knockdown(60, 1, 0)
M.dizziness +=6
M.dizziness +=2
switch(current_cycle)
if(15 to 45)
if(!M.slurring)
@@ -1613,3 +1613,91 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "mojito"
glass_name = "Mojito"
glass_desc = "A drink that looks as refreshing as it tastes."
/datum/reagent/consumable/ethanol/fernet
name = "Fernet"
id = "fernet"
description = "An incredibly bitter herbal liqueur used as a digestif."
color = "#1B2E24" // rgb: 27, 46, 36
boozepwr = 80
taste_description = "utter bitterness"
glass_name = "glass of fernet"
glass_desc = "A glass of pure Fernet. Only an absolute madman would drink this alone." //Hi Kevum
/datum/reagent/consumable/ethanol/fernet/on_mob_life(mob/living/M)
if(M.nutrition <= NUTRITION_LEVEL_STARVING)
M.adjustToxLoss(1*REM, 0)
M.nutrition = max(M.nutrition - 5, 0)
M.overeatduration = 0
return ..()
/datum/reagent/consumable/ethanol/fernet_cola
name = "Fernet Cola"
id = "fernet_cola"
description = "A very popular and bittersweet digestif, ideal after a heavy meal. Best served on a sawed-off cola bottle as per tradition."
color = "#390600" // rgb: 57, 6, 0
boozepwr = 25
taste_description = "sweet relief"
glass_icon_state = "godlyblend"
glass_name = "glass of fernet cola"
glass_desc = "A sawed-off cola bottle filled with Fernet Cola. Nothing better after eating like a lardass."
/datum/reagent/consumable/ethanol/fernetcola/on_mob_life(mob/living/M)
if(M.nutrition <= NUTRITION_LEVEL_STARVING)
M.adjustToxLoss(0.5*REM, 0)
M.nutrition = max(M.nutrition - 3, 0)
M.overeatduration = 0
return ..()
/datum/reagent/consumable/ethanol/fanciulli
name = "Fanciulli"
id = "fanciulli"
description = "What if the Manhattan coctail ACTUALLY used a bitter herb liquour? Helps you sobers up." //also causes a bit of stamina damage to symbolize the afterdrink lazyness
color = "#CA933F" // rgb: 202, 147, 63
boozepwr = -10
taste_description = "a sweet sobering mix"
glass_icon_state = "fanciulli"
glass_name = "glass of fanciulli"
glass_desc = "A glass of Fanciulli. It's just Manhattan with Fernet."
/datum/reagent/consumable/ethanol/fanciulli/on_mob_life(mob/living/M)
M.nutrition = max(M.nutrition - 5, 0)
M.overeatduration = 0
return ..()
/datum/reagent/consumable/ethanol/fanciulli/on_mob_add(mob/living/M)
if(M.health > 0)
M.adjustStaminaLoss(20)
. = TRUE
..()
/datum/reagent/consumable/ethanol/branca_menta
name = "Branca Menta"
id = "branca_menta"
description = "A refreshing mixture of bitter Fernet with mint creme liquour."
color = "#4B5746" // rgb: 75, 87, 70
boozepwr = 35
taste_description = "a bitter freshness"
glass_icon_state= "minted_fernet"
glass_name = "glass of branca menta"
glass_desc = "A glass of Branca Menta, perfect for those lazy and hot sunday summer afternoons." //Get lazy literally by drinking this
/datum/reagent/consumable/ethanol/branca_menta/on_mob_life(mob/living/M)
M.adjust_bodytemperature(-20 * TEMPERATURE_DAMAGE_COEFFICIENT, T0C)
if(M.nutrition <= NUTRITION_LEVEL_STARVING)
M.adjustToxLoss(1*REM, 0)
M.nutrition = max(M.nutrition - 5, 0)
M.overeatduration = 0
return ..()
/datum/reagent/consumable/ethanol/branca_menta/on_mob_add(mob/living/M)
if(M.health > 0)
M.adjustStaminaLoss(35)
. = TRUE
..()
@@ -407,7 +407,7 @@
/datum/reagent/consumable/nuka_cola/on_mob_life(mob/living/M)
M.Jitter(20)
M.set_drugginess(30)
M.dizziness +=5
M.dizziness +=1.5
M.drowsyness = 0
M.AdjustSleeping(-40, FALSE)
M.adjust_bodytemperature(-5 * TEMPERATURE_DAMAGE_COEFFICIENT, BODYTEMP_NORMAL)
@@ -278,7 +278,7 @@
to_chat(M, "<span class='notice'>[high_message]</span>")
M.adjustStaminaLoss(-5, 0)
M.adjustBrainLoss(4)
M.hallucination += 10
M.hallucination += 5
if(M.canmove && !ismovableatom(M.loc))
step(M, pick(GLOB.cardinals))
step(M, pick(GLOB.cardinals))
@@ -286,7 +286,7 @@
. = 1
/datum/reagent/drug/bath_salts/overdose_process(mob/living/M)
M.hallucination += 10
M.hallucination += 5
if(M.canmove && !ismovableatom(M.loc))
for(var/i in 1 to 8)
step(M, pick(GLOB.cardinals))
@@ -332,7 +332,7 @@
..()
/datum/reagent/drug/bath_salts/addiction_act_stage4(mob/living/carbon/human/M)
M.hallucination += 40
M.hallucination += 30
if(M.canmove && !ismovableatom(M.loc))
for(var/i = 0, i < 16, i++)
step(M, pick(GLOB.cardinals))
@@ -1093,7 +1093,7 @@
. = 1
/datum/reagent/medicine/earthsblood/overdose_process(mob/living/M)
M.hallucination = min(max(0, M.hallucination + 10), 50)
M.hallucination = min(max(0, M.hallucination + 5), 60)
M.adjustToxLoss(5 * REM, 0)
..()
. = 1
@@ -103,7 +103,7 @@
/datum/reagent/blackpowder/on_mob_life(mob/living/M)
..()
if(isplasmaman(M))
M.hallucination += 10
M.hallucination += 5
/datum/reagent/blackpowder/on_ex_act()
var/location = get_turf(holder.my_atom)
@@ -188,7 +188,7 @@
taste_description = "sourness"
/datum/reagent/toxin/mindbreaker/on_mob_life(mob/living/M)
M.hallucination += 10
M.hallucination += 5
return ..()
/datum/reagent/toxin/plantbgone
@@ -626,16 +626,16 @@
/datum/reagent/toxin/lipolicide
name = "Lipolicide"
id = "lipolicide"
description = "A powerful toxin that will destroy fat cells, massively reducing body weight in a short time. More deadly to those without nutriment in their body."
description = "A powerful toxin that will destroy fat cells, massively reducing body weight in a short time. Deadly to those without nutriment in their body."
taste_description = "mothballs"
reagent_state = LIQUID
color = "#F0FFF0"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
toxpwr = 0.5
toxpwr = 0
/datum/reagent/toxin/lipolicide/on_mob_life(mob/living/M)
if(M.nutrition <= NUTRITION_LEVEL_STARVING)
M.adjustToxLoss(0.5*REM, 0)
M.adjustToxLoss(1*REM, 0)
M.nutrition = max(M.nutrition - 3, 0) // making the chef more valuable, one meme trap at a time
M.overeatduration = 0
return ..()
@@ -179,8 +179,7 @@ Borg Shaker
charge_cost = 20 //Lots of reagents all regenerating at once, so the charge cost is lower. They also regenerate faster.
recharge_time = 3
accepts_reagent_upgrades = FALSE
reagent_ids = list("beer", "orangejuice", "limejuice", "tomatojuice", "cola", "tonic", "sodawater", "ice", "cream", "whiskey", "vodka", "rum", "gin", "tequila", "vermouth", "wine", "kahlua", "cognac", "ale")
reagent_ids = list("beer", "orangejuice", "grenadine" ,"limejuice", "tomatojuice", "cola", "tonic", "sodawater", "ice", "cream", "whiskey", "vodka", "rum", "gin", "tequila", "vermouth", "wine", "kahlua", "cognac", "ale", "fernet")
/obj/item/reagent_containers/borghypo/borgshaker/attack(mob/M, mob/user)
return //Can't inject stuff with a shaker, can we? //not with that attitude
@@ -482,3 +482,19 @@
build_path = /obj/item/circuitboard/machine/dish_drive
category = list ("Misc. Machinery")
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/board/stacking_unit_console
name = "Machine Design (Stacking Machine Console)"
desc = "The circuit board for a Stacking Machine Console."
id = "stack_console"
build_path = /obj/item/circuitboard/machine/stacking_unit_console
category = list ("Misc. Machinery")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/board/stacking_machine
name = "Machine Design (Stacking Machine)"
desc = "The circuit board for a Stacking Machine."
id = "stack_machine"
build_path = /obj/item/circuitboard/machine/stacking_machine
category = list ("Misc. Machinery")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_ENGINEERING
+5 -20
View File
@@ -44,24 +44,21 @@
/obj/machinery/rnd/experimentor/proc/SetTypeReactions()
var/probWeight = 0
for(var/I in typesof(/obj/item))
if(istype(I, /obj/item/relic))
item_reactions["[I]"] = SCANTYPE_DISCOVER
else
item_reactions["[I]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE)
if(ispath(I, /obj/item/stock_parts) || ispath(I, /obj/item/grenade/chem_grenade) || ispath(I, /obj/item/kitchen))
var/obj/item/tempCheck = I
if(initial(tempCheck.icon_state) != null) //check it's an actual usable item, in a hacky way
valid_items += 15
valid_items += I
probWeight++
valid_items["[I]"] += 15
if(ispath(I, /obj/item/reagent_containers/food))
var/obj/item/tempCheck = I
if(initial(tempCheck.icon_state) != null) //check it's an actual usable item, in a hacky way
valid_items += rand(1,max(2,35-probWeight))
valid_items += I
valid_items["[I]"] += rand(1,4)
if(ispath(I, /obj/item/construction/rcd) || ispath(I, /obj/item/grenade) || ispath(I, /obj/item/aicard) || ispath(I, /obj/item/storage/backpack/holding) || ispath(I, /obj/item/slime_extract) || ispath(I, /obj/item/onetankbomb) || ispath(I, /obj/item/transfer_valve))
var/obj/item/tempCheck = I
@@ -225,18 +222,6 @@
smoke.set_up(0, where)
smoke.start()
/obj/machinery/rnd/experimentor/proc/pickWeighted(list/from)
var/result = FALSE
var/counter = 1
while(!result)
var/probtocheck = from[counter]
if(prob(probtocheck))
result = TRUE
return from[counter+1]
if(counter + 2 < from.len)
counter = counter + 2
else
counter = 1
/obj/machinery/rnd/experimentor/proc/experiment(exp,obj/item/exp_on)
recentlyExperimented = 1
@@ -283,13 +268,13 @@
visible_message("<span class='warning'>[src] malfunctions, spewing toxic waste!</span>")
for(var/turf/T in oview(1, src))
if(!T.density)
if(prob(EFFECT_PROB_VERYHIGH))
if(prob(EFFECT_PROB_VERYHIGH) && !(locate(/obj/effect/decal/cleanable/greenglow) in T))
var/obj/effect/decal/cleanable/reagentdecal = new/obj/effect/decal/cleanable/greenglow(T)
reagentdecal.reagents.add_reagent("radium", 7)
else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
var/savedName = "[exp_on]"
ejectItem(TRUE)
var/newPath = pickWeighted(valid_items)
var/newPath = text2path(pickweight(valid_items))
loaded_item = new newPath(src)
visible_message("<span class='warning'>[src] malfunctions, transforming [savedName] into [loaded_item]!</span>")
investigate_log("Experimentor has transformed [savedName] into [loaded_item]", INVESTIGATE_EXPERIMENTOR)
@@ -9,5 +9,6 @@
/obj/machinery/rnd/production/circuit_imprinter/department/science
name = "department circuit imprinter (Science)"
circuit = /obj/item/circuitboard/machine/circuit_imprinter/department/science
allowed_department_flags = DEPARTMENTAL_FLAG_ALL|DEPARTMENTAL_FLAG_SCIENCE
department_tag = "Science"
+1
View File
@@ -50,6 +50,7 @@ doesn't have toxins access.
var/research_control = TRUE
/obj/machinery/computer/rdconsole/production
circuit = /obj/item/circuitboard/computer/rdconsole/production
research_control = FALSE
/proc/CallMaterialName(ID)
+2 -1
View File
@@ -93,7 +93,8 @@
description = "A refresher course on modern engineering technology."
prereq_ids = list("base")
design_ids = list("solarcontrol", "recharger", "powermonitor", "rped", "pacman", "adv_capacitor", "adv_scanning", "emitter", "high_cell", "adv_matter_bin",
"atmosalerts", "atmos_control", "recycler", "autolathe", "high_micro_laser", "nano_mani", "mesons", "thermomachine", "rad_collector", "tesla_coil", "grounding_rod", "apc_control", "cell_charger", "power control", "airlock_board", "firelock_board", "airalarm_electronics", "firealarm_electronics")
"atmosalerts", "atmos_control", "recycler", "autolathe", "high_micro_laser", "nano_mani", "mesons", "thermomachine", "rad_collector", "tesla_coil", "grounding_rod",
"apc_control", "cell_charger", "power control", "airlock_board", "firelock_board", "airalarm_electronics", "firealarm_electronics", "cell_charger", "stack_console", "stack_machine")
research_cost = 7500
export_price = 5000
-76
View File
@@ -1,76 +0,0 @@
/datum/server_tools_command
var/name = "" //the string to trigger this command on a chat bot. e.g. TGS3_BOT: do_this_command
var/help_text = "" //help text for this command
var/required_parameters = 0 //number of parameters required for this command
var/admin_only = FALSE //set to TRUE if this command should only be usable by registered chat admins
//override to implement command
//sender is the display name of who sent the command
//params is the trimmed string following the command name
/datum/server_tools_command/proc/Run(sender, params)
CRASH("[type] has no implementation for Run()")
/world/proc/ListServiceCustomCommands(warnings_only)
if(!warnings_only)
. = list()
var/list/command_name_types = list()
var/list/warned_command_names = warnings_only ? list() : null
for(var/I in typesof(/datum/server_tools_command) - /datum/server_tools_command)
var/datum/server_tools_command/stc = I
var/command_name = initial(stc.name)
var/static/list/warned_server_tools_names = list()
if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\""))
if(warnings_only && !warned_command_names[command_name])
SERVER_TOOLS_LOG("WARNING: Custom command [command_name] can't be used as it is empty or contains illegal characters!")
warned_command_names[command_name] = TRUE
continue
if(command_name_types[command_name])
if(warnings_only)
SERVER_TOOLS_LOG("WARNING: Custom commands [command_name_types[command_name]] and [stc] have the same name, only [command_name_types[command_name]] will be available!")
continue
command_name_types[stc] = command_name
if(!warnings_only)
.[command_name] = list(SERVICE_JSON_PARAM_HELPTEXT = initial(stc.help_text), SERVICE_JSON_PARAM_ADMINONLY = initial(stc.admin_only), SERVICE_JSON_PARAM_REQUIREDPARAMETERS = initial(stc.required_parameters))
/world/proc/HandleServiceCustomCommand(command, sender, params)
var/static/list/cached_custom_server_tools_commands
if(!cached_custom_server_tools_commands)
cached_custom_server_tools_commands = list()
for(var/I in typesof(/datum/server_tools_command) - /datum/server_tools_command)
var/datum/server_tools_command/stc = I
cached_custom_server_tools_commands[lowertext(initial(stc.name))] = stc
var/command_type = cached_custom_server_tools_commands[command]
if(!command_type)
return FALSE
var/datum/server_tools_command/stc = new command_type
return stc.Run(sender, params) || TRUE
/*
The MIT License
Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-135
View File
@@ -1,135 +0,0 @@
SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(reboot_mode, REBOOT_MODE_NORMAL)
SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(server_tools_api_compatible, FALSE)
/proc/GetTestMerges()
if(RunningService(TRUE) && fexists(SERVICE_PR_TEST_JSON))
. = json_decode(file2text(SERVICE_PR_TEST_JSON))
if(.)
return
return list()
/world/proc/ServiceInit()
if(!RunningService(TRUE))
return
ListServiceCustomCommands(TRUE)
ExportService("[SERVICE_REQUEST_API_VERSION] [SERVER_TOOLS_API_VERSION]", TRUE)
/proc/RunningService(skip_compat_check = FALSE)
if(!skip_compat_check && !SERVER_TOOLS_READ_GLOBAL(server_tools_api_compatible))
return FALSE
. = world.params[SERVICE_WORLD_PARAM] != null
if(. && world.system_type != MS_WINDOWS)
SERVER_TOOLS_LOG("Warning: Server tools world parameter detected but not running on Windows. Aborting initialization!")
return FALSE
/proc/ServiceVersion()
if(RunningService(TRUE))
return world.params[SERVICE_VERSION_PARAM]
/proc/ServiceAPIVersion()
return SERVICE_API_VERSION_STRING
/world/proc/ExportService(command, skip_compat_check = FALSE)
. = FALSE
if(!RunningService(skip_compat_check))
return
if(skip_compat_check && !fexists(SERVICE_INTERFACE_DLL))
CRASH("Service parameter present but no interface DLL detected. This is symptomatic of running a service less than version 3.1! Please upgrade.")
var/instance = params[SERVICE_INSTANCE_PARAM]
if(!instance)
instance = "TG Station Server" //maybe just upgraded
call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance, command) //trust no retval
return TRUE
/world/proc/ChatBroadcast(message)
ExportService("[SERVICE_REQUEST_IRC_BROADCAST] [message]")
/world/proc/AdminBroadcast(message)
ExportService("[SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE] [message]")
/world/proc/ServiceEndProcess()
SERVER_TOOLS_LOG("Sending shutdown request!");
sleep(world.tick_lag) //flush the buffers
ExportService(SERVICE_REQUEST_KILL_PROCESS)
//called at the exact moment the world is supposed to reboot
/world/proc/ServiceReboot()
switch(SERVER_TOOLS_READ_GLOBAL(reboot_mode))
if(REBOOT_MODE_HARD)
SERVER_TOOLS_WORLD_ANNOUNCE("Hard reboot triggered, you will automatically reconnect...")
ServiceEndProcess()
if(REBOOT_MODE_SHUTDOWN)
SERVER_TOOLS_WORLD_ANNOUNCE("The server is shutting down...")
ServiceEndProcess()
else
ExportService(SERVICE_REQUEST_WORLD_REBOOT) //just let em know
/world/proc/ServiceCommand(list/params)
var/their_sCK = params[SERVICE_CMD_PARAM_KEY]
if(!their_sCK || !RunningService(TRUE))
return FALSE //continue world/Topic
var/sCK = world.params[SERVICE_WORLD_PARAM]
if(their_sCK != sCK)
return "Invalid comms key!";
var/command = params[SERVICE_CMD_PARAM_COMMAND]
if(!command)
return "No command!"
switch(command)
if(SERVICE_CMD_API_COMPATIBLE)
SERVER_TOOLS_WRITE_GLOBAL(server_tools_api_compatible, TRUE)
return SERVICE_RETURN_SUCCESS
if(SERVICE_CMD_HARD_REBOOT)
if(SERVER_TOOLS_READ_GLOBAL(reboot_mode) != REBOOT_MODE_HARD)
SERVER_TOOLS_WRITE_GLOBAL(reboot_mode, REBOOT_MODE_HARD)
SERVER_TOOLS_LOG("Hard reboot requested by service")
SERVER_TOOLS_NOTIFY_ADMINS("The world will hard reboot at the end of the game. Requested by service.")
if(SERVICE_CMD_GRACEFUL_SHUTDOWN)
if(SERVER_TOOLS_READ_GLOBAL(reboot_mode) != REBOOT_MODE_SHUTDOWN)
SERVER_TOOLS_WRITE_GLOBAL(reboot_mode, REBOOT_MODE_SHUTDOWN)
SERVER_TOOLS_LOG("Shutdown requested by service")
message_admins("The world will shutdown at the end of the game. Requested by service.")
if(SERVICE_CMD_WORLD_ANNOUNCE)
var/msg = params["message"]
if(!istext(msg) || !msg)
return "No message set!"
SERVER_TOOLS_WORLD_ANNOUNCE(msg)
return SERVICE_RETURN_SUCCESS
if(SERVICE_CMD_PLAYER_COUNT)
return "[SERVER_TOOLS_CLIENT_COUNT]"
if(SERVICE_CMD_LIST_CUSTOM)
return json_encode(ListServiceCustomCommands(FALSE))
else
var/custom_command_result = HandleServiceCustomCommand(lowertext(command), params[SERVICE_CMD_PARAM_SENDER], params[SERVICE_CMD_PARAM_CUSTOM])
if(custom_command_result)
return istext(custom_command_result) ? custom_command_result : SERVICE_RETURN_SUCCESS
return "Unknown command: [command]"
/*
The MIT License
Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
@@ -19,13 +19,15 @@ Urist: I don't feel like figuring out how you store object spells so I'm leaving
Make sure spells that are removed from spell_list are actually removed and deleted when mind transferring.
Also, you never added distance checking after target is selected. I've went ahead and did that.
*/
/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets, mob/living/user = usr, distanceoverride)
/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets, mob/living/user = usr, distanceoverride, silent = FALSE)
if(!targets.len)
to_chat(user, "<span class='warning'>No mind found!</span>")
if(!silent)
to_chat(user, "<span class='warning'>No mind found!</span>")
return
if(targets.len > 1)
to_chat(user, "<span class='warning'>Too many minds! You're not a hive damnit!</span>")
if(!silent)
to_chat(user, "<span class='warning'>Too many minds! You're not a hive damnit!</span>")
return
var/mob/living/target = targets[1]
@@ -34,28 +36,34 @@ Also, you never added distance checking after target is selected. I've went ahea
var/t_is = target.p_are()
if(!(target in oview(range)) && !distanceoverride)//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it.
to_chat(user, "<span class='warning'>[t_He] [t_is] too far away!</span>")
if(!silent)
to_chat(user, "<span class='warning'>[t_He] [t_is] too far away!</span>")
return
if(ismegafauna(target))
to_chat(user, "<span class='warning'>This creature is too powerful to control!</span>")
if(!silent)
to_chat(user, "<span class='warning'>This creature is too powerful to control!</span>")
return
if(target.stat == DEAD)
to_chat(user, "<span class='warning'>You don't particularly want to be dead!</span>")
if(!silent)
to_chat(user, "<span class='warning'>You don't particularly want to be dead!</span>")
return
if(!target.key || !target.mind)
to_chat(user, "<span class='warning'>[t_He] appear[target.p_s()] to be catatonic! Not even magic can affect [target.p_their()] vacant mind.</span>")
if(!silent)
to_chat(user, "<span class='warning'>[t_He] appear[target.p_s()] to be catatonic! Not even magic can affect [target.p_their()] vacant mind.</span>")
return
if(user.suiciding)
to_chat(user, "<span class='warning'>You're killing yourself! You can't concentrate enough to do this!</span>")
if(!silent)
to_chat(user, "<span class='warning'>You're killing yourself! You can't concentrate enough to do this!</span>")
return
var/datum/mind/TM = target.mind
if((target.anti_magic_check() || TM.has_antag_datum(/datum/antagonist/wizard) || TM.has_antag_datum(/datum/antagonist/cult) || TM.has_antag_datum(/datum/antagonist/clockcult) || TM.has_antag_datum(/datum/antagonist/changeling) || TM.has_antag_datum(/datum/antagonist/rev)) || cmptext(copytext(target.key,1,2),"@"))
to_chat(user, "<span class='warning'>[target.p_their(TRUE)] mind is resisting your spell!</span>")
if(!silent)
to_chat(user, "<span class='warning'>[target.p_their(TRUE)] mind is resisting your spell!</span>")
return
var/mob/living/victim = target//The target of the spell whos body will be transferred to.
@@ -77,3 +85,4 @@ Also, you never added distance checking after target is selected. I've went ahea
victim.Unconscious(unconscious_amount_victim)
SEND_SOUND(caster, sound('sound/magic/mandswap.ogg'))
SEND_SOUND(victim, sound('sound/magic/mandswap.ogg'))// only the caster and victim hear the sounds, that way no one knows for sure if the swap happened
return TRUE
@@ -15,8 +15,9 @@
if(B.mod_type == mod_type)
qdel(src)
return
owner.bioware += src
on_gain()
/datum/bioware/Destroy()
owner = null
if(active)
@@ -31,7 +31,7 @@
/datum/bioware/grounded_nerves
name = "Grounded Nerves"
desc = "Nerves form a safe path for electricity to traverse, protecting the body from electric shocks."
mod_type = "nerves"
mod_type = BIOWARE_NERVES
var/prev_coeff
/datum/bioware/grounded_nerves/on_gain()
@@ -31,7 +31,7 @@
/datum/bioware/spliced_nerves
name = "Spliced Nerves"
desc = "Nerves are connected to each other multiple times, greatly reducing the impact of stunning effects."
mod_type = "nerves"
mod_type = BIOWARE_NERVES
/datum/bioware/spliced_nerves/on_gain()
..()
@@ -31,7 +31,7 @@
/datum/bioware/threaded_veins
name = "Threaded Veins"
desc = "The circulatory system is woven into a mesh, severely reducing the amount of blood lost from wounds."
mod_type = "circulation"
mod_type = BIOWARE_CIRCULATION
/datum/bioware/threaded_veins/on_gain()
..()
+2 -2
View File
@@ -236,13 +236,13 @@
var/bz_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/bz][MOLES])
if(bz_pp > BZ_trip_balls_min)
H.hallucination += 20
H.hallucination += 10
H.reagents.add_reagent("bz_metabolites",5)
if(prob(33))
H.adjustBrainLoss(3, 150)
else if(bz_pp > 0.01)
H.hallucination += 5//Removed at 2 per tick so this will slowly build up
H.hallucination += 5
H.reagents.add_reagent("bz_metabolites",1)
+2
View File
@@ -0,0 +1,2 @@
#define TGS_UNIMPLEMENTED "___unimplemented"
#define TGS_VERSION_PARAMETER "server_service_version"
+144
View File
@@ -0,0 +1,144 @@
/world/TgsNew(datum/tgs_event_handler/event_handler)
var/tgs_version = world.params[TGS_VERSION_PARAMETER]
if(!tgs_version)
return
var/path = SelectTgsApi(tgs_version)
if(!path)
TGS_ERROR_LOG("Found unsupported API version: [tgs_version]. If this is a valid version please report this, backporting is done on demand.")
TGS_INFO_LOG("Activating API for version [tgs_version]")
var/datum/tgs_api/new_api = new path
var/result = new_api.OnWorldNew(event_handler ? event_handler : new /datum/tgs_event_handler/tgs_default)
if(result && result != TGS_UNIMPLEMENTED)
TGS_WRITE_GLOBAL(tgs, new_api)
else
TGS_ERROR_LOG("Failed to activate API!")
/world/proc/SelectTgsApi(tgs_version)
//remove the old 3.0 header
tgs_version = replacetext(tgs_version, "/tg/station 13 Server v", "")
var/list/version_bits = splittext(tgs_version, ".")
var/super = text2num(version_bits[1])
var/major = text2num(version_bits[2])
var/minor = text2num(version_bits[3])
var/patch = text2num(version_bits[4])
switch(super)
if(3)
switch(major)
if(2)
return /datum/tgs_api/v3210
if(super != null && major != null && minor != null && patch != null && tgs_version > TgsMaximumAPIVersion())
TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.")
return /datum/tgs_api/latest
/world/TgsMaximumAPIVersion()
return "4.0.0.0"
/world/TgsMinimumAPIVersion()
return "3.2.0.0"
/world/TgsInitializationComplete()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
api.OnInitializationComplete()
/world/proc/TgsTopic(T)
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
var/result = api.OnTopic(T)
if(result != TGS_UNIMPLEMENTED)
return result
/world/TgsRevision()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
var/result = api.Revision()
if(result != TGS_UNIMPLEMENTED)
return result
/world/TgsReboot()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
api.OnReboot()
/world/TgsAvailable()
return TGS_READ_GLOBAL(tgs) != null
/world/TgsVersion()
return world.params[TGS_VERSION_PARAMETER]
/world/TgsInstanceName()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
var/result = api.InstanceName()
if(result != TGS_UNIMPLEMENTED)
return result
/world/TgsTestMerges()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
var/result = api.TestMerges()
if(result != TGS_UNIMPLEMENTED)
return result
return list()
/world/TgsEndProcess()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
api.EndProcess()
/world/TgsChatChannelInfo()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
var/result = api.ChatChannelInfo()
if(result != TGS_UNIMPLEMENTED)
return result
return list()
/world/TgsChatBroadcast(message, list/channels)
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
api.ChatBroadcast(message, channels)
/world/TgsTargetedChatBroadcast(message, admin_only)
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
api.ChatTargetedBroadcast(message, admin_only)
/world/TgsChatPrivateMessage(message, datum/tgs_chat_user/user)
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
api.ChatPrivateMessage(message, user)
/*
The MIT License
Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+74
View File
@@ -0,0 +1,74 @@
TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
/datum/tgs_api
/datum/tgs_api/latest
parent_type = /datum/tgs_api/v3210
TGS_PROTECT_DATUM(/datum/tgs_api)
/datum/tgs_api/proc/ApiVersion()
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/OnWorldNew(datum/tgs_event_handler/event_handler)
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/OnInitializationComplete()
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/OnTopic(T)
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/OnReboot()
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/InstanceName()
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/TestMerges()
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/EndProcess()
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/Revision()
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/ChatChannelInfo()
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/ChatBroadcast(message, list/channels)
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/ChatTargetedBroadcast(message, admin_only)
return TGS_UNIMPLEMENTED
/datum/tgs_api/proc/ChatPrivateMessage(message, admin_only)
return TGS_UNIMPLEMENTED
/*
The MIT License
Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
@@ -0,0 +1,30 @@
/datum/tgs_event_handler/tgs_default/HandleEvent(event_code)
//TODO
return
/*
The MIT License
Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+6
View File
@@ -0,0 +1,6 @@
#include "core\_definitions.dm"
#include "core\core.dm"
#include "core\datum.dm"
#include "core\default_event_handler.dm"
#include "v3210\api.dm"
#include "v3210\commands.dm"
+248
View File
@@ -0,0 +1,248 @@
#define REBOOT_MODE_NORMAL 0
#define REBOOT_MODE_HARD 1
#define REBOOT_MODE_SHUTDOWN 2
#define SERVICE_WORLD_PARAM "server_service"
#define SERVICE_INSTANCE_PARAM "server_instance"
#define SERVICE_PR_TEST_JSON "prtestjob.json"
#define SERVICE_INTERFACE_DLL "TGDreamDaemonBridge.dll"
#define SERVICE_INTERFACE_FUNCTION "DDEntryPoint"
#define SERVICE_CMD_HARD_REBOOT "hard_reboot"
#define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown"
#define SERVICE_CMD_WORLD_ANNOUNCE "world_announce"
#define SERVICE_CMD_LIST_CUSTOM "list_custom_commands"
#define SERVICE_CMD_API_COMPATIBLE "api_compat"
#define SERVICE_CMD_PLAYER_COUNT "client_count"
#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
#define SERVICE_CMD_PARAM_COMMAND "command"
#define SERVICE_CMD_PARAM_SENDER "sender"
#define SERVICE_CMD_PARAM_CUSTOM "custom"
#define SERVICE_REQUEST_KILL_PROCESS "killme"
#define SERVICE_REQUEST_IRC_BROADCAST "irc"
#define SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE "send2irc"
#define SERVICE_REQUEST_WORLD_REBOOT "worldreboot"
#define SERVICE_REQUEST_API_VERSION "api_ver"
#define SERVICE_RETURN_SUCCESS "SUCCESS"
/datum/tgs_api/v3210
var/reboot_mode = REBOOT_MODE_NORMAL
var/comms_key
var/instance_name
var/originmastercommit
var/commit
var/list/cached_custom_tgs_chat_commands
var/warned_revison = FALSE
var/warned_custom_commands = FALSE
/datum/tgs_api/v3210/ApiVersion()
return "3.2.1.0"
/datum/tgs_api/v3210/proc/trim_left(text)
for (var/i = 1 to length(text))
if (text2ascii(text, i) > 32)
return copytext(text, i)
return ""
/datum/tgs_api/v3210/proc/trim_right(text)
for (var/i = length(text), i > 0, i--)
if (text2ascii(text, i) > 32)
return copytext(text, 1, i + 1)
return ""
/datum/tgs_api/v3210/proc/file2list(filename)
return splittext(trim_left(trim_right(file2text(filename))), "\n")
/datum/tgs_api/v3210/OnWorldNew(datum/tgs_event_handler/event_handler) //don't use event handling in this version
. = FALSE
comms_key = world.params[SERVICE_WORLD_PARAM]
instance_name = world.params[SERVICE_INSTANCE_PARAM]
if(!instance_name)
instance_name = "TG Station Server" //maybe just upgraded
var/list/logs = file2list(".git/logs/HEAD")
if(logs.len)
logs = splittext(logs[logs.len - 1], " ")
commit = logs[2]
logs = file2list(".git/logs/refs/remotes/origin/master")
if(logs.len)
originmastercommit = splittext(logs[logs.len - 1], " ")[2]
if(world.system_type != MS_WINDOWS)
TGS_ERROR_LOG("This API version is only supported on Windows. Not running on Windows. Aborting initialization!")
return
ListServiceCustomCommands(TRUE)
ExportService("[SERVICE_REQUEST_API_VERSION] [ApiVersion()]", TRUE)
return TRUE
//nothing to do for v3
/datum/tgs_api/v3210/OnInitializationComplete()
return
/datum/tgs_api/v3210/InstanceName()
return world.params[SERVICE_INSTANCE_PARAM]
/datum/tgs_api/v3210/proc/ExportService(command, skip_compat_check = FALSE)
. = FALSE
if(skip_compat_check && !fexists(SERVICE_INTERFACE_DLL))
TGS_ERROR_LOG("Service parameter present but no interface DLL detected. This is symptomatic of running a service less than version 3.1! Please upgrade.")
return
call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval
return TRUE
/datum/tgs_api/v3210/OnTopic(T)
var/list/params = params2list(T)
var/their_sCK = params[SERVICE_CMD_PARAM_KEY]
if(!their_sCK)
return FALSE //continue world/Topic
if(their_sCK != comms_key)
return "Invalid comms key!";
var/command = params[SERVICE_CMD_PARAM_COMMAND]
if(!command)
return "No command!"
switch(command)
if(SERVICE_CMD_API_COMPATIBLE)
return SERVICE_RETURN_SUCCESS
if(SERVICE_CMD_HARD_REBOOT)
if(reboot_mode != REBOOT_MODE_HARD)
reboot_mode = REBOOT_MODE_HARD
TGS_INFO_LOG("Hard reboot requested by service")
TGS_NOTIFY_ADMINS("The world will hard reboot at the end of the game. Requested by TGS.")
if(SERVICE_CMD_GRACEFUL_SHUTDOWN)
if(reboot_mode != REBOOT_MODE_SHUTDOWN)
reboot_mode = REBOOT_MODE_SHUTDOWN
TGS_INFO_LOG("Shutdown requested by service")
TGS_NOTIFY_ADMINS("The world will shutdown at the end of the game. Requested by TGS.")
if(SERVICE_CMD_WORLD_ANNOUNCE)
var/msg = params["message"]
if(!istext(msg) || !msg)
return "No message set!"
TGS_WORLD_ANNOUNCE(msg)
return SERVICE_RETURN_SUCCESS
if(SERVICE_CMD_PLAYER_COUNT)
return "[TGS_CLIENT_COUNT]"
if(SERVICE_CMD_LIST_CUSTOM)
return json_encode(ListServiceCustomCommands(FALSE))
else
var/custom_command_result = HandleServiceCustomCommand(lowertext(command), params[SERVICE_CMD_PARAM_SENDER], params[SERVICE_CMD_PARAM_CUSTOM])
if(custom_command_result)
return istext(custom_command_result) ? custom_command_result : SERVICE_RETURN_SUCCESS
return "Unknown command: [command]"
/datum/tgs_api/v3210/OnReboot()
switch(reboot_mode)
if(REBOOT_MODE_HARD)
TGS_WORLD_ANNOUNCE("Hard reboot triggered, you will automatically reconnect...")
EndProcess()
if(REBOOT_MODE_SHUTDOWN)
TGS_WORLD_ANNOUNCE("The server is shutting down...")
EndProcess()
else
ExportService(SERVICE_REQUEST_WORLD_REBOOT) //just let em know
/datum/tgs_api/v3210/TestMerges()
//do the best we can here as the datum can't be completed using the v3 api
. = list()
if(!fexists(SERVICE_PR_TEST_JSON))
return
var/list/json = json_decode(file2text(SERVICE_PR_TEST_JSON))
if(!json)
return
for(var/I in json)
var/datum/tgs_revision_information/test_merge/tm = new
tm.number = text2num(I)
var/list/entry = json[I]
tm.pull_request_commit = entry["commit"]
tm.author = entry["author"]
tm.title = entry["title"]
. += tm
/datum/tgs_api/v3210/Revision()
if(!warned_revison)
TGS_ERROR_LOG("Use of TgsRevision on [ApiVersion()] origin_commit only points to master!")
warned_revison = TRUE
var/datum/tgs_revision_information/ri = new
ri.commit = commit
ri.origin_commit = originmastercommit
/datum/tgs_api/v3210/EndProcess()
sleep(world.tick_lag) //flush the buffers
ExportService(SERVICE_REQUEST_KILL_PROCESS)
/datum/tgs_api/v3210/ChatChannelInfo()
return list()
/datum/tgs_api/v3210/ChatBroadcast(message, list/channels)
if(channels)
return TGS_UNIMPLEMENTED
ChatTargetedBroadcast(message, TRUE)
ChatTargetedBroadcast(message, FALSE)
/datum/tgs_api/v3210/ChatTargetedBroadcast(message, admin_only)
ExportService("[admin_only ? SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE : SERVICE_REQUEST_IRC_BROADCAST] [message]")
/datum/tgs_api/v3210/ChatPrivateMessage(message, admin_only)
return TGS_UNIMPLEMENTED
#undef REBOOT_MODE_NORMAL
#undef REBOOT_MODE_HARD
#undef REBOOT_MODE_SHUTDOWN
#undef SERVICE_WORLD_PARAM
#undef SERVICE_INSTANCE_PARAM
#undef SERVICE_PR_TEST_JSON
#undef SERVICE_INTERFACE_DLL
#undef SERVICE_INTERFACE_FUNCTION
#undef SERVICE_CMD_HARD_REBOOT
#undef SERVICE_CMD_GRACEFUL_SHUTDOWN
#undef SERVICE_CMD_WORLD_ANNOUNCE
#undef SERVICE_CMD_LIST_CUSTOM
#undef SERVICE_CMD_API_COMPATIBLE
#undef SERVICE_CMD_PLAYER_COUNT
#undef SERVICE_CMD_PARAM_KEY
#undef SERVICE_CMD_PARAM_COMMAND
#undef SERVICE_CMD_PARAM_SENDER
#undef SERVICE_CMD_PARAM_CUSTOM
#undef SERVICE_REQUEST_KILL_PROCESS
#undef SERVICE_REQUEST_IRC_BROADCAST
#undef SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE
#undef SERVICE_REQUEST_WORLD_REBOOT
#undef SERVICE_REQUEST_API_VERSION
#undef SERVICE_RETURN_SUCCESS
/*
The MIT License
Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+78
View File
@@ -0,0 +1,78 @@
#define SERVICE_JSON_PARAM_HELPTEXT "help_text"
#define SERVICE_JSON_PARAM_ADMINONLY "admin_only"
#define SERVICE_JSON_PARAM_REQUIREDPARAMETERS "required_parameters"
/datum/tgs_api/v3210/proc/ListServiceCustomCommands(warnings_only)
if(!warnings_only)
. = list()
var/list/command_name_types = list()
var/list/warned_command_names = warnings_only ? list() : null
var/warned_about_the_dangers_of_robutussin = !warnings_only
for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
if(!warned_about_the_dangers_of_robutussin)
TGS_ERROR_LOG("Custom chat commands in [ApiVersion()] lacks the /datum/tgs_chat_user/sender.channel field!")
warned_about_the_dangers_of_robutussin = TRUE
var/datum/tgs_chat_command/stc = I
var/command_name = initial(stc.name)
if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\""))
if(warnings_only && !warned_command_names[command_name])
TGS_ERROR_LOG("Custom command [command_name] can't be used as it is empty or contains illegal characters!")
warned_command_names[command_name] = TRUE
continue
if(command_name_types[command_name])
if(warnings_only)
TGS_ERROR_LOG("Custom commands [command_name_types[command_name]] and [stc] have the same name, only [command_name_types[command_name]] will be available!")
continue
command_name_types[stc] = command_name
if(!warnings_only)
.[command_name] = list(SERVICE_JSON_PARAM_HELPTEXT = initial(stc.help_text), SERVICE_JSON_PARAM_ADMINONLY = initial(stc.admin_only), SERVICE_JSON_PARAM_REQUIREDPARAMETERS = 0)
/datum/tgs_api/v3210/proc/HandleServiceCustomCommand(command, sender, params)
if(!cached_custom_tgs_chat_commands)
cached_custom_tgs_chat_commands = list()
for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
var/datum/tgs_chat_command/stc = I
cached_custom_tgs_chat_commands[lowertext(initial(stc.name))] = stc
var/command_type = cached_custom_tgs_chat_commands[command]
if(!command_type)
return FALSE
var/datum/tgs_chat_command/stc = new command_type
var/datum/tgs_chat_user/user = new
user.friendly_name = sender
user.mention = sender
return stc.Run(user, params) || TRUE
/*
#undef SERVICE_JSON_PARAM_HELPTEXT
#undef SERVICE_JSON_PARAM_ADMINONLY
#undef SERVICE_JSON_PARAM_REQUIREDPARAMETERS
The MIT License
Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+4 -2
View File
@@ -15,6 +15,8 @@
/obj/item/reagent_containers/food/drinks/bottle/hcider = 5,
/obj/item/reagent_containers/food/drinks/bottle/absinthe = 5,
/obj/item/reagent_containers/food/drinks/bottle/grappa = 5,
/obj/item/reagent_containers/food/drinks/bottle/sake = 5,
/obj/item/reagent_containers/food/drinks/bottle/fernet = 5,
/obj/item/reagent_containers/food/drinks/ale = 6,
/obj/item/reagent_containers/food/drinks/bottle/orangejuice = 4,
/obj/item/reagent_containers/food/drinks/bottle/tomatojuice = 4,
@@ -38,5 +40,5 @@
/obj/item/vending_refill/boozeomat
machine_name = "Booze-O-Mat"
icon_state = "refill_booze"
charges = list(59, 4, 0)//of 178 standard, 12 contraband
init_charges = list(59, 4, 0)
charges = list(61, 4, 0)//of 182 standard, 12 contraband
init_charges = list(61, 4, 0)
+1
View File
@@ -6,6 +6,7 @@
product_slogans = "Get your cool toys today!;Trigger a valid hunter today!;Quality toy weapons for cheap prices!;Give them to HoPs for all access!;Give them to HoS to get perma briged!"
product_ads = "Feel robust with your toys!;Express your inner child today!;Toy weapons don't kill people, but valid hunters do!;Who needs responsibilities when you have toy weapons?;Make your next murder FUN!"
vend_reply = "Come back for more!"
circuit = /obj/item/circuitboard/machine/vending/syndicatedonksofttoyvendor
products = list(/obj/item/gun/ballistic/automatic/toy/unrestricted = 10,
/obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = 10,
/obj/item/gun/ballistic/shotgun/toy/unrestricted = 10,
+1
View File
@@ -5,6 +5,7 @@
product_slogans = "Get your cool toys today!;Trigger a valid hunter today!;Quality toy weapons for cheap prices!;Give them to HoPs for all access!;Give them to HoS to get perma briged!"
product_ads = "Feel robust with your toys!;Express your inner child today!;Toy weapons don't kill people, but valid hunters do!;Who needs responsibilities when you have toy weapons?;Make your next murder FUN!"
vend_reply = "Come back for more!"
circuit = /obj/item/circuitboard/machine/vending/donksofttoyvendor
products = list(/obj/item/gun/ballistic/automatic/toy/unrestricted = 10,
/obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = 10,
/obj/item/gun/ballistic/shotgun/toy/unrestricted = 10,