"
if (pai)
if(pai.loc != src)
pai = null
@@ -289,23 +289,23 @@ GLOBAL_LIST_EMPTY(PDAs)
dat += "
"
if (1)
- dat += "
Notekeeper V2.2
"
+ dat += "
[PDAIMG(notes)] Notekeeper V2.2
"
dat += "Edit "
if(notescanned)
dat += "(This is a scanned image, editing it may cause some text formatting to change.) "
dat += "[(!notehtml ? note : notehtml)]"
if (2)
- dat += "
"
var/turf/T = user.loc
if (isnull(T))
@@ -617,7 +617,8 @@ GLOBAL_LIST_EMPTY(PDAs)
return
if((last_text && world.time < last_text + 10) || (everyone && last_everyone && world.time < last_everyone + PDA_SPAM_DELAY))
return
-
+ if(prob(1))
+ message += "\nSent from my PDA"
// Send the signal
var/list/string_targets = list()
for (var/obj/item/pda/P in targets)
@@ -742,7 +743,7 @@ GLOBAL_LIST_EMPTY(PDAs)
var/mob/M = loc
M.put_in_hands(inserted_item)
else
- inserted_item.forceMove(get_turf(src))
+ inserted_item.forceMove(drop_location())
to_chat(usr, "You remove \the [inserted_item] from \the [src].")
inserted_item = null
update_icon()
@@ -1017,4 +1018,4 @@ GLOBAL_LIST_EMPTY(PDAs)
#undef PDA_SCANNER_REAGENT
#undef PDA_SCANNER_HALOGEN
#undef PDA_SCANNER_GAS
-#undef PDA_SPAM_DELAY
\ No newline at end of file
+#undef PDA_SPAM_DELAY
diff --git a/code/game/objects/items/devices/PDA/PDA_types.dm b/code/game/objects/items/devices/PDA/PDA_types.dm
index c1cc5d69a3..089286efda 100644
--- a/code/game/objects/items/devices/PDA/PDA_types.dm
+++ b/code/game/objects/items/devices/PDA/PDA_types.dm
@@ -21,7 +21,7 @@
// Special AI/pAI PDAs that cannot explode.
/obj/item/pda/ai
- icon_state = "NONE"
+ icon = null
ttone = "data"
fon = FALSE
detonatable = FALSE
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index 2737f24cbe..e92eb6e617 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -207,13 +207,12 @@
frequency.post_signal(src, status_signal)
-
/obj/item/cartridge/proc/generate_menu(mob/user)
if(!host_pda)
return
switch(host_pda.mode)
if(40) //signaller
- menu = "
Remote Signaling System
"
+ menu = "
[PDAIMG(signaler)] Remote Signaling System
"
menu += {"
Send Signal
@@ -232,7 +231,7 @@ Code:
+ "}
if (41) //crew manifest
- menu = "
Crew Manifest
"
+ menu = "
[PDAIMG(notes)] Crew Manifest
"
menu += "Entries cannot be modified from this terminal.
"
if(GLOB.data_core.general)
for (var/datum/data/record/t in sortRecord(GLOB.data_core.general))
@@ -241,7 +240,7 @@ Code:
if (42) //status displays
- menu = "
Station Status Display Interlink
"
+ menu = "
[PDAIMG(status)] Station Status Display Interlink
"
menu += "\[ Clear \] "
menu += "\[ Shuttle ETA \] "
@@ -254,7 +253,7 @@ Code:
menu += " Biohazard \] "
if (43)
- menu = "
Power Monitors - Please select one
"
+ menu = "
[PDAIMG(power)] Power Monitors - Please select one
"
powmonitor = null
powermonitors = list()
var/powercount = 0
@@ -280,7 +279,7 @@ Code:
menu += ""
if (433)
- menu = "
Power Monitor
"
+ menu = "
[PDAIMG(power)] Power Monitor
"
if(!powmonitor)
menu += "No connection "
else
@@ -307,13 +306,13 @@ Code:
menu += ""
if (44) //medical records //This thing only displays a single screen so it's hard to really get the sub-menu stuff working.
- menu = "
"
menu += " Current Newsfeed: [current_channel ? current_channel : "None"] "
var/datum/newscaster/feed_channel/current
for(var/datum/newscaster/feed_channel/chan in GLOB.news_network.network_channels)
@@ -533,7 +532,7 @@ Code:
menu += " Post Message"
if (54) // Beepsky, Medibot, Floorbot, and Cleanbot access
- menu = "
Bots Interlink
"
+ menu = "
[PDAIMG(medbot)] Bots Interlink
"
bot_control()
if (99) //Newscaster message permission error
menu = "
ERROR : NOT AUTHORIZED [host_pda.id ? "" : "- ID SLOT EMPTY"]
"
@@ -652,7 +651,7 @@ Code:
var/mob/living/simple_animal/bot/Bot
if(active_bot)
- menu += "[active_bot] Status: (refresh) "
+ menu += "[active_bot] Status: ([PDAIMG(refresh)]refresh) "
menu += "Model: [active_bot.model] "
menu += "Location: [get_area(active_bot)] "
menu += "Mode: [active_bot.get_mode()]"
@@ -688,9 +687,9 @@ Code:
menu += "\[Summon Bot\] " //summon
menu += "Keep an ID inserted to upload access codes upon summoning."
- menu += "Return to bot list"
+ menu += "[PDAIMG(back)]Return to bot list"
else
- menu += " Scan for active bots
"
+ usr << browse("[jointext(output, "")]","window=editrights;size=1000x650")
/datum/admins/proc/edit_rights_topic(list/href_list)
if(!check_rights(R_PERMISSIONS))
@@ -142,10 +192,17 @@
return FALSE
if(use_db)
. = sanitizeSQL(.)
+ //if an admin exists without a datum they won't be caught by the above
+ var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin_ranks")] WHERE ckey = '[.]'")
+ if(!query_admin_in_db.warn_execute())
+ return FALSE
+ if(query_admin_in_db.NextRow())
+ to_chat(usr, "[.] already listed in admin database. Check the Management tab if they don't appear in the list of admins.")
+ return FALSE
var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin")] (ckey, rank) VALUES ('[.]', 'NEW ADMIN')")
if(!query_add_admin.warn_execute())
return FALSE
- var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add admin', 'New admin added: [.]')")
+ var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add admin', '[.]', 'New admin added: [.]')")
if(!query_add_admin_log.warn_execute())
return FALSE
@@ -153,12 +210,13 @@
if(alert("Are you sure you want to remove [admin_ckey]?","Confirm Removal","Do it","Cancel") == "Do it")
GLOB.admin_datums -= admin_ckey
GLOB.deadmins -= admin_ckey
- D.disassociate()
+ if(D)
+ D.disassociate()
if(use_db)
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
if(!query_add_rank.warn_execute())
return
- var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove admin', 'Admin removed: [admin_ckey]')")
+ var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove admin', '[admin_ckey]', 'Admin removed: [admin_ckey]')")
if(!query_add_rank_log.warn_execute())
return
message_admins("[key_name_admin(usr)] removed [admin_ckey] from the admins list [use_db ? "permanently" : "temporarily"]")
@@ -216,13 +274,13 @@
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_ranks")] (rank, flags, exclude_flags, can_edit_flags) VALUES ('[new_rank]', '0', '0', '0')")
if(!query_add_rank.warn_execute())
return
- var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add rank', 'New rank added: [admin_ckey]')")
+ var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add rank', '[new_rank]', 'New rank added: [new_rank]')")
if(!query_add_rank_log.warn_execute())
return
var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET rank = '[new_rank]' WHERE ckey = '[admin_ckey]'")
if(!query_change_rank.warn_execute())
return
- var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change admin rank', 'Rank of [admin_ckey] changed from [old_rank] to [new_rank]')")
+ var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change admin rank', '[admin_ckey]', 'Rank of [admin_ckey] changed from [old_rank] to [new_rank]')")
if(!query_change_rank_log.warn_execute())
return
if(D) //they were previously an admin
@@ -259,7 +317,7 @@
var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery("UPDATE [format_table_name("admin_ranks")] SET flags = '[new_flags]', exclude_flags = '[new_exclude_flags]', can_edit_flags = '[new_can_edit_flags]' WHERE rank = '[D.rank.name]'")
if(!query_change_rank_flags.warn_execute())
return
- var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change rank flags', 'Permissions of [admin_ckey] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]')")
+ var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change rank flags', '[D.rank.name]', 'Permissions of [D.rank.name] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]')")
if(!query_change_rank_flags_log.warn_execute())
return
for(var/datum/admin_rank/R in GLOB.admin_ranks)
@@ -294,6 +352,36 @@
message_admins("[key_name_admin(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_ckey] temporarily"]")
log_admin("[key_name(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_ckey] temporarily"]")
+/datum/admins/proc/remove_rank(admin_rank)
+ if(!admin_rank)
+ return
+ for(var/datum/admin_rank/R in GLOB.admin_ranks)
+ if(R.name == admin_rank && (!(R.rights & usr.client.holder.rank.can_edit_rights) == R.rights))
+ to_chat(usr, "You don't have edit rights to all the rights this rank has, rank deletion not permitted.")
+ return
+ if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && (admin_rank in GLOB.protected_ranks))
+ to_chat(usr, "Deletion of protected ranks is not permitted, it must be removed from admin_ranks.txt.")
+ return
+ if(CONFIG_GET(flag/load_legacy_ranks_only))
+ to_chat(usr, "Rank deletion not permitted while database rank loading is disabled.")
+ return
+ admin_rank = sanitizeSQL(admin_rank)
+ var/datum/DBQuery/query_admins_with_rank = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin")] WHERE rank = '[admin_rank]'")
+ if(!query_admins_with_rank.warn_execute())
+ return
+ if(query_admins_with_rank.NextRow())
+ to_chat(usr, "Error: Rank deletion attempted while rank still used; Tell a coder, this shouldn't happen.")
+ return
+ if(alert("Are you sure you want to remove [admin_rank]?","Confirm Removal","Do it","Cancel") == "Do it")
+ var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin_ranks")] WHERE rank = '[admin_rank]'")
+ if(!query_add_rank.warn_execute())
+ return
+ var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove rank', '[admin_rank]', 'Rank removed: [admin_rank]')")
+ if(!query_add_rank_log.warn_execute())
+ return
+ message_admins("[key_name_admin(usr)] removed rank [admin_rank] permanently")
+ log_admin("[key_name(usr)] removed rank [admin_rank] permanently")
+
/datum/admins/proc/sync_lastadminrank(admin_ckey, datum/admins/D)
var/sqlrank = sanitizeSQL(D.rank.name)
admin_ckey = sanitizeSQL(admin_ckey)
diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm
index a8e92db53a..5138089a6c 100644
--- a/code/modules/admin/secrets.dm
+++ b/code/modules/admin/secrets.dm
@@ -430,7 +430,7 @@
var/obj/item/clothing/under/schoolgirl/I = new seifuku
var/olduniform = H.w_uniform
H.temporarilyRemoveItemFromInventory(H.w_uniform, TRUE, FALSE)
- H.equip_to_slot_or_del(I, slot_w_uniform)
+ H.equip_to_slot_or_del(I, SLOT_W_UNIFORM)
qdel(olduniform)
if(droptype == "Yes")
I.flags_1 |= NODROP_1
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 95dae05c09..bff420320c 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -273,6 +273,21 @@
return
create_message("note", banckey, null, banreason, null, null, 0, 0)
+ else if(href_list["editrightsbrowser"])
+ edit_admin_permissions(0)
+
+ else if(href_list["editrightsbrowserlog"])
+ edit_admin_permissions(1, href_list["editrightstarget"], href_list["editrightsoperation"], href_list["editrightspage"])
+
+ if(href_list["editrightsbrowsermanage"])
+ if(href_list["editrightschange"])
+ change_admin_rank(href_list["editrightschange"], TRUE)
+ else if(href_list["editrightsremove"])
+ remove_admin(href_list["editrightsremove"], TRUE)
+ else if(href_list["editrightsremoverank"])
+ remove_rank(href_list["editrightsremoverank"])
+ edit_admin_permissions(2)
+
else if(href_list["editrights"])
edit_rights_topic(href_list)
@@ -1493,8 +1508,8 @@
if(ishuman(L))
var/mob/living/carbon/human/observer = L
- observer.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket(observer), slot_w_uniform)
- observer.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(observer), slot_shoes)
+ observer.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket(observer), SLOT_W_UNIFORM)
+ observer.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(observer), SLOT_SHOES)
L.Unconscious(100)
sleep(5)
L.forceMove(pick(GLOB.tdomeobserve))
@@ -2448,6 +2463,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
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 2a6b4448d2..f385cdc1bd 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -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)
diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm
index 1e96cc507e..0136efc3b3 100644
--- a/code/modules/admin/verbs/adminjump.dm
+++ b/code/modules/admin/verbs/adminjump.dm
@@ -95,7 +95,7 @@
SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Key") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-/client/proc/Getmob(mob/M in GLOB.mob_list)
+/client/proc/Getmob(mob/M in GLOB.mob_list - GLOB.dummy_mob_list)
set category = "Admin"
set name = "Get Mob"
set desc = "Mob to teleport"
diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm
index 54614cf8ef..2fc616d588 100644
--- a/code/modules/admin/verbs/deadsay.dm
+++ b/code/modules/admin/verbs/deadsay.dm
@@ -27,7 +27,7 @@
if(isnewplayer(M))
continue
if (M.stat == DEAD || (M.client && M.client.holder && (M.client.prefs.chat_toggles & CHAT_DEAD))) //admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above
- M.show_message(rendered, 2)
+ to_chat(M, rendered)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Dsay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 7d4d5fa05e..2fd212b4dc 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -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 != GLOBAL_PROC && !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)
@@ -476,7 +480,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
id.forceMove(W)
W.update_icon()
else
- H.equip_to_slot(id,slot_wear_id)
+ H.equip_to_slot(id,SLOT_WEAR_ID)
else
alert("Invalid mob")
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 83d4f64748..be0b9d04bb 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -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"
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index d14c749992..c282e48b39 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -53,7 +53,7 @@
A.UpdateButtonIcon()
/obj/item/clothing/suit/armor/abductor/vest/item_action_slot_check(slot, mob/user)
- if(slot == slot_wear_suit) //we only give the mob the ability to activate the vest if he's actually wearing it.
+ if(slot == SLOT_WEAR_SUIT) //we only give the mob the ability to activate the vest if he's actually wearing it.
return 1
/obj/item/clothing/suit/armor/abductor/vest/proc/SetDisguise(datum/icon_snapshot/entry)
@@ -338,7 +338,7 @@
if(QDELETED(G))
return
- if(istype(C.get_item_by_slot(slot_head), /obj/item/clothing/head/foilhat))
+ if(istype(C.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
to_chat(user, "Your target seems to have some sort of protective headgear on, blocking the message from being sent!")
return
@@ -425,7 +425,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
item_state = "wonderprod"
lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
force = 7
w_class = WEIGHT_CLASS_NORMAL
actions_types = list(/datum/action/item_action/toggle_mode)
@@ -515,7 +515,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
/obj/item/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user)
if(L.incapacitated(TRUE, TRUE))
- if(istype(L.get_item_by_slot(slot_head), /obj/item/clothing/head/foilhat))
+ if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
to_chat(user, "The specimen's protective headgear is interfering with the sleep inducement!")
L.visible_message("[user] tried to induced sleep in [L] with [src], but their headgear protected them!", \
"You feel a strange wave of heavy drowsiness wash over you, but your headgear deflects most of it!")
@@ -527,7 +527,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
L.Sleeping(1200)
add_logs(user, L, "put to sleep")
else
- if(istype(L.get_item_by_slot(slot_head), /obj/item/clothing/head/foilhat))
+ if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
to_chat(user, "The specimen's protective headgear is completely blocking our sleep inducement methods!")
L.visible_message("[user] tried to induce sleep in [L] with [src], but their headgear completely protected them!", \
"Any sense of drowsiness is quickly diminished as your headgear deflects the effects!")
@@ -620,12 +620,15 @@ Congratulations! You are now trained for invasive xenobiology research!"}
icon_state = "abductor_headset"
item_state = "abductor_headset"
keyslot2 = new /obj/item/encryptionkey/heads/captain
- flags_2 = BANG_PROTECT_2
/obj/item/radio/headset/abductor/Initialize(mapload)
. = ..()
make_syndie()
+/obj/item/radio/headset/abductor/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/wearertargeting/earprotection, list(SLOT_EARS))
+
/obj/item/radio/headset/abductor/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/screwdriver))
return // Stops humans from disassembling abductor headsets.
diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm
index c551509cc7..1e53f778d6 100644
--- a/code/modules/antagonists/abductor/equipment/gland.dm
+++ b/code/modules/antagonists/abductor/equipment/gland.dm
@@ -122,7 +122,7 @@
owner.grant_language(/datum/language/slime)
/obj/item/organ/heart/gland/slime/activate()
- to_chat(owner, "You feel nauseous!")
+ to_chat(owner, "You feel nauseated!")
owner.vomit(20)
var/mob/living/simple_animal/slime/Slime = new(get_turf(owner), "grey")
@@ -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()
diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm
index 08776318c8..e629a0b47d 100644
--- a/code/modules/antagonists/abductor/machinery/console.dm
+++ b/code/modules/antagonists/abductor/machinery/console.dm
@@ -167,7 +167,7 @@
c.console = src
/obj/machinery/abductor/console/proc/AddSnapshot(mob/living/carbon/human/target)
- if(istype(target.get_item_by_slot(slot_head), /obj/item/clothing/head/foilhat))
+ if(istype(target.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
say("Subject wearing specialized protective headgear, unable to get a proper scan!")
return
var/datum/icon_snapshot/entry = new
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index 8c6d7f52bd..a42ae6ef4f 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -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()
diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm
index 92c8a3c069..6ae73336d4 100644
--- a/code/modules/antagonists/changeling/changeling_power.dm
+++ b/code/modules/antagonists/changeling/changeling_power.dm
@@ -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
diff --git a/code/modules/antagonists/changeling/powers/biodegrade.dm b/code/modules/antagonists/changeling/powers/biodegrade.dm
index dbb0e3a88a..1e8eaed383 100644
--- a/code/modules/antagonists/changeling/powers/biodegrade.dm
+++ b/code/modules/antagonists/changeling/powers/biodegrade.dm
@@ -13,7 +13,7 @@
return 0
if(user.handcuffed)
- var/obj/O = user.get_item_by_slot(slot_handcuffed)
+ var/obj/O = user.get_item_by_slot(SLOT_HANDCUFFED)
if(!istype(O))
return 0
user.visible_message("[user] vomits a glob of acid on [user.p_their()] [O]!", \
@@ -23,7 +23,7 @@
used = TRUE
if(user.wear_suit && user.wear_suit.breakouttime && !used)
- var/obj/item/clothing/suit/S = user.get_item_by_slot(slot_wear_suit)
+ var/obj/item/clothing/suit/S = user.get_item_by_slot(SLOT_WEAR_SUIT)
if(!istype(S))
return 0
user.visible_message("[user] vomits a glob of acid across the front of [user.p_their()] [S]!", \
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index fc98d3182d..72826d086f 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -119,8 +119,8 @@
user.dropItemToGround(user.head)
user.dropItemToGround(user.wear_suit)
- user.equip_to_slot_if_possible(new suit_type(user), slot_wear_suit, 1, 1, 1)
- user.equip_to_slot_if_possible(new helmet_type(user), slot_head, 1, 1, 1)
+ user.equip_to_slot_if_possible(new suit_type(user), SLOT_WEAR_SUIT, 1, 1, 1)
+ user.equip_to_slot_if_possible(new helmet_type(user), SLOT_HEAD, 1, 1, 1)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chem_recharge_slowdown += recharge_slowdown
@@ -445,7 +445,8 @@
name = "flesh mass"
icon_state = "lingspacesuit"
desc = "A huge, bulky mass of pressure and temperature-resistant organic tissue, evolved to facilitate space travel."
- flags_1 = STOPSPRESSUREDMAGE_1 | NODROP_1 | DROPDEL_1 //Not THICKMATERIAL_1 because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff)
+ flags_1 = NODROP_1 | DROPDEL_1
+ clothing_flags = STOPSPRESSUREDAMAGE //Not THICKMATERIAL because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/oxygen)
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90) //No armor at all.
@@ -464,7 +465,8 @@
name = "flesh mass"
icon_state = "lingspacehelmet"
desc = "A covering of pressure and temperature-resistant organic tissue with a glass-like chitin front."
- flags_1 = STOPSPRESSUREDMAGE_1 | NODROP_1 | DROPDEL_1 //Again, no THICKMATERIAL_1.
+ flags_1 = NODROP_1 | DROPDEL_1
+ clothing_flags = STOPSPRESSUREDAMAGE
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
diff --git a/code/modules/antagonists/changeling/powers/revive.dm b/code/modules/antagonists/changeling/powers/revive.dm
index 4fb28b4904..d9c1ca7221 100644
--- a/code/modules/antagonists/changeling/powers/revive.dm
+++ b/code/modules/antagonists/changeling/powers/revive.dm
@@ -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
+
diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm
index 10b86ac1ad..6e15334305 100644
--- a/code/modules/antagonists/changeling/powers/tiny_prick.dm
+++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm
@@ -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"
diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm
index 77bfbf4f3b..63de6b8f72 100644
--- a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm
+++ b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm
@@ -21,23 +21,23 @@
/obj/item/clothing/head/helmet/clockwork/ratvar_act()
if(GLOB.ratvar_awakens)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
- flags_1 |= STOPSPRESSUREDMAGE_1
+ clothing_flags |= STOPSPRESSUREDAMAGE
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else if(GLOB.ratvar_approaches)
armor = list("melee" = 70, "bullet" = 80, "laser" = -15, "energy" = 25, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
- flags_1 |= STOPSPRESSUREDMAGE_1
+ clothing_flags |= STOPSPRESSUREDAMAGE
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else
armor = list("melee" = 60, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
- flags_1 &= ~STOPSPRESSUREDMAGE_1
+ clothing_flags &= ~STOPSPRESSUREDAMAGE
max_heat_protection_temperature = initial(max_heat_protection_temperature)
min_cold_protection_temperature = initial(min_cold_protection_temperature)
/obj/item/clothing/head/helmet/clockwork/equipped(mob/living/user, slot)
..()
- if(slot == slot_head && !is_servant_of_ratvar(user))
+ if(slot == SLOT_HEAD && !is_servant_of_ratvar(user))
if(!iscultist(user))
to_chat(user, "\"Now now, this is for my servants, not you.\"")
user.visible_message("As [user] puts [src] on, it flickers off their head!", "The helmet flickers off your head, leaving only nausea!")
@@ -82,17 +82,17 @@
/obj/item/clothing/suit/armor/clockwork/ratvar_act()
if(GLOB.ratvar_awakens)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
- flags_1 |= STOPSPRESSUREDMAGE_1
+ clothing_flags |= STOPSPRESSUREDAMAGE
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else if(GLOB.ratvar_approaches)
armor = list("melee" = 70, "bullet" = 80, "laser" = -15, "energy" = 25, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
- flags_1 |= STOPSPRESSUREDMAGE_1
+ clothing_flags |= STOPSPRESSUREDAMAGE
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else
armor = list("melee" = 60, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
- flags_1 &= ~STOPSPRESSUREDMAGE_1
+ clothing_flags &= ~STOPSPRESSUREDAMAGE
max_heat_protection_temperature = initial(max_heat_protection_temperature)
min_cold_protection_temperature = initial(min_cold_protection_temperature)
@@ -103,7 +103,7 @@
/obj/item/clothing/suit/armor/clockwork/equipped(mob/living/user, slot)
..()
- if(slot == slot_wear_suit && !is_servant_of_ratvar(user))
+ if(slot == SLOT_WEAR_SUIT && !is_servant_of_ratvar(user))
if(!iscultist(user))
to_chat(user, "\"Now now, this is for my servants, not you.\"")
user.visible_message("As [user] puts [src] on, it flickers off their body!", "The curiass flickers off your body, leaving only nausea!")
@@ -148,12 +148,12 @@
/obj/item/clothing/gloves/clockwork/ratvar_act()
if(GLOB.ratvar_awakens)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
- flags_1 |= STOPSPRESSUREDMAGE_1
+ clothing_flags |= STOPSPRESSUREDAMAGE
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else
armor = list("melee" = 80, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
- flags_1 &= ~STOPSPRESSUREDMAGE_1
+ clothing_flags &= ~STOPSPRESSUREDAMAGE
max_heat_protection_temperature = initial(max_heat_protection_temperature)
min_cold_protection_temperature = initial(min_cold_protection_temperature)
@@ -164,7 +164,7 @@
/obj/item/clothing/gloves/clockwork/equipped(mob/living/user, slot)
..()
- if(slot == slot_gloves && !is_servant_of_ratvar(user))
+ if(slot == SLOT_GLOVES && !is_servant_of_ratvar(user))
if(!iscultist(user))
to_chat(user, "\"Now now, this is for my servants, not you.\"")
user.visible_message("As [user] puts [src] on, it flickers off their arms!", "The gauntlets flicker off your arms, leaving only nausea!")
@@ -203,9 +203,9 @@
/obj/item/clothing/shoes/clockwork/ratvar_act()
if(GLOB.ratvar_awakens)
- flags_1 |= NOSLIP_1
+ clothing_flags |= NOSLIP
else
- flags_1 &= ~NOSLIP_1
+ clothing_flags &= ~NOSLIP
/obj/item/clothing/shoes/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
if(equipper && !is_servant_of_ratvar(equipper))
@@ -214,7 +214,7 @@
/obj/item/clothing/shoes/clockwork/equipped(mob/living/user, slot)
..()
- if(slot == slot_shoes && !is_servant_of_ratvar(user))
+ if(slot == SLOT_SHOES && !is_servant_of_ratvar(user))
if(!iscultist(user))
to_chat(user, "\"Now now, this is for my servants, not you.\"")
user.visible_message("As [user] puts [src] on, it flickers off their feet!", "The treads flicker off your feet, leaving only nausea!")
diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
index 5f5bc1b58a..c464656150 100644
--- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
+++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
@@ -9,7 +9,7 @@
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
var/inhand_overlay //If applicable, this overlay will be applied to the slab's inhand
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
var/busy //If the slab is currently being used by something
diff --git a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm
index ca5fe74f2e..3f3bb58598 100644
--- a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm
+++ b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm
@@ -115,4 +115,4 @@
S.no_cost = TRUE
if(seasonal_hat && seasonal_hat != "none")
var/obj/item/hat = new seasonal_hat(construct)
- construct.equip_to_slot_or_del(hat, slot_head)
+ construct.equip_to_slot_or_del(hat, SLOT_HEAD)
diff --git a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm
index a16a52d7aa..f54d88fc49 100644
--- a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm
+++ b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm
@@ -28,13 +28,13 @@
return ..()
/obj/item/clothing/glasses/judicial_visor/item_action_slot_check(slot, mob/user)
- if(slot != slot_glasses)
+ if(slot != SLOT_GLASSES)
return 0
return ..()
/obj/item/clothing/glasses/judicial_visor/equipped(mob/living/user, slot)
..()
- if(slot != slot_glasses)
+ if(slot != SLOT_GLASSES)
update_status(FALSE)
if(blaster.ranged_ability_user)
blaster.remove_ranged_ability()
@@ -55,13 +55,13 @@
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
/obj/item/clothing/glasses/judicial_visor/proc/check_on_mob(mob/user)
- if(user && src != user.get_item_by_slot(slot_glasses)) //if we happen to check and we AREN'T in the slot, we need to remove our shit from whoever we got dropped from
+ if(user && src != user.get_item_by_slot(SLOT_GLASSES)) //if we happen to check and we AREN'T in the slot, we need to remove our shit from whoever we got dropped from
update_status(FALSE)
if(blaster.ranged_ability_user)
blaster.remove_ranged_ability()
/obj/item/clothing/glasses/judicial_visor/attack_self(mob/user)
- if(is_servant_of_ratvar(user) && src == user.get_item_by_slot(slot_glasses))
+ if(is_servant_of_ratvar(user) && src == user.get_item_by_slot(SLOT_GLASSES))
blaster.toggle(user)
/obj/item/clothing/glasses/judicial_visor/proc/update_status(change_to)
@@ -89,7 +89,7 @@
if(!src)
return 0
recharging = FALSE
- if(user && src == user.get_item_by_slot(slot_glasses))
+ if(user && src == user.get_item_by_slot(SLOT_GLASSES))
to_chat(user, "Your [name] hums. It is ready.")
else
active = FALSE
@@ -115,7 +115,7 @@
/obj/effect/proc_holder/judicial_visor/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return
- if(ranged_ability_user.incapacitated() || !visor || visor != ranged_ability_user.get_item_by_slot(slot_glasses))
+ if(ranged_ability_user.incapacitated() || !visor || visor != ranged_ability_user.get_item_by_slot(SLOT_GLASSES))
remove_ranged_ability()
return
@@ -151,6 +151,7 @@
desc = "You get the feeling that you shouldn't be standing here."
clockwork_desc = "A sigil that will soon erupt and smite any unenlightened nearby."
icon = 'icons/effects/96x96.dmi'
+ icon_state = ""
pixel_x = -32
pixel_y = -32
layer = BELOW_MOB_LAYER
diff --git a/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm b/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm
index c1bf94842d..dab12dc304 100644
--- a/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm
+++ b/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm
@@ -74,7 +74,7 @@
/obj/item/clothing/glasses/wraith_spectacles/equipped(mob/living/user, slot)
..()
- if(slot != slot_glasses || up)
+ if(slot != SLOT_GLASSES || up)
return
if(user.has_trait(TRAIT_BLIND))
to_chat(user, "\"You're blind, idiot. Stop embarrassing yourself.\"" )
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
index 9a78c64942..4e1a5b42cb 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
@@ -160,18 +160,18 @@
/datum/action/innate/clockwork_armaments/Activate()
var/do_message = 0
- var/obj/item/I = owner.get_item_by_slot(slot_wear_suit)
+ var/obj/item/I = owner.get_item_by_slot(SLOT_WEAR_SUIT)
if(remove_item_if_better(I, owner))
- do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), slot_wear_suit)
- I = owner.get_item_by_slot(slot_head)
+ do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), SLOT_WEAR_SUIT)
+ I = owner.get_item_by_slot(SLOT_HEAD)
if(remove_item_if_better(I, owner))
- do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), slot_head)
- I = owner.get_item_by_slot(slot_gloves)
+ do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), SLOT_HEAD)
+ I = owner.get_item_by_slot(SLOT_GLOVES)
if(remove_item_if_better(I, owner))
- do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), slot_gloves)
- I = owner.get_item_by_slot(slot_shoes)
+ do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), SLOT_GLOVES)
+ I = owner.get_item_by_slot(SLOT_SHOES)
if(remove_item_if_better(I, owner))
- do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), slot_shoes)
+ do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), SLOT_SHOES)
if(do_message)
owner.visible_message("Strange armor appears on [owner]!", "A bright shimmer runs down your body, equipping you with Ratvarian armor.")
playsound(owner, 'sound/magic/clockwork/fellowship_armory.ogg', 15 * do_message, TRUE) //get sound loudness based on how much we equipped
diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm
index f921b6b527..f2c0518cc2 100644
--- a/code/modules/antagonists/clockcult/clockcult.dm
+++ b/code/modules/antagonists/clockcult/clockcult.dm
@@ -159,7 +159,7 @@
SSticker.mode.servants_of_ratvar -= owner
SSticker.mode.update_servant_icons_removed(owner)
if(!silent)
- owner.current.visible_message("[owner] seems to have remembered their true allegiance!", null, null, null, owner.current)
+ owner.current.visible_message("[owner.current] seems to have remembered [owner.current.p_their()] true allegiance!", null, null, null, owner.current)
to_chat(owner, "A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.")
owner.current.log_message("Has renounced the cult of Ratvar!", INDIVIDUAL_ATTACK_LOG)
owner.special_role = null
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index bb2ce1db2a..f12beef82f 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -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)
@@ -605,11 +605,11 @@
uses--
var/mob/living/carbon/C = target
C.visible_message("Otherworldly armor suddenly appears on [C]!")
- C.equip_to_slot_or_del(new /obj/item/clothing/under/color/black,slot_w_uniform)
- C.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), slot_head)
- C.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), slot_wear_suit)
- C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), slot_shoes)
- C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), slot_back)
+ C.equip_to_slot_or_del(new /obj/item/clothing/under/color/black,SLOT_W_UNIFORM)
+ C.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), SLOT_HEAD)
+ C.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), SLOT_WEAR_SUIT)
+ C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), SLOT_SHOES)
+ C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), SLOT_BACK)
if(C == user)
qdel(src) //Clears the hands
C.put_in_hands(new /obj/item/melee/cultblade(user))
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index b7f0b002ec..99941501e3 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -81,9 +81,9 @@
/datum/antagonist/cult/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
var/list/slots = list(
- "backpack" = slot_in_backpack,
- "left pocket" = slot_l_store,
- "right pocket" = slot_r_store
+ "backpack" = SLOT_IN_BACKPACK,
+ "left pocket" = SLOT_L_STORE,
+ "right pocket" = SLOT_R_STORE
)
var/T = new item_path(mob)
@@ -128,7 +128,7 @@
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
if(!silent)
- owner.current.visible_message("[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!", null, null, null, owner.current)
+ owner.current.visible_message("[owner.current] looks like [owner.current.p_theyve()] just reverted to [owner.current.p_their()] old faith!", null, null, null, owner.current)
to_chat(owner.current, "An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.")
owner.current.log_message("Has renounced the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index a1c16aa078..5f56e1b91b 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -33,10 +33,8 @@
desc = "A sword humming with unholy energy. It glows with a dim red light."
icon_state = "cultblade"
item_state = "cultblade"
- lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
- inhand_x_dimension = 64
- inhand_y_dimension = 64
+ lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
flags_1 = CONDUCT_1
sharpness = IS_SHARP
w_class = WEIGHT_CLASS_BULKY
@@ -73,8 +71,6 @@
if(!iscultist(user))
if(!is_servant_of_ratvar(user))
to_chat(user, "\"I wouldn't advise that.\"")
- to_chat(user, "An overwhelming sense of nausea overpowers you!")
- user.Dizzy(120)
else
to_chat(user, "\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"")
to_chat(user, "A horrible force yanks at your arm!")
@@ -103,7 +99,7 @@
inhand_x_dimension = 64
inhand_y_dimension = 64
actions_types = list()
- flags_2 = SLOWS_WHILE_IN_HAND_2
+ item_flags = SLOWS_WHILE_IN_HAND
var/datum/action/innate/dash/cult/jaunt
var/datum/action/innate/cult/spin2win/linked_action
var/spinning = FALSE
@@ -138,10 +134,7 @@
if(!iscultist(user))
if(!is_servant_of_ratvar(user))
to_chat(user, "\"I wouldn't advise that.\"")
- to_chat(user, "An overwhelming sense of nausea overpowers you!")
- user.Dizzy(80)
- user.dropItemToGround(src, TRUE)
- user.Knockdown(30)
+ force = 5
return
else
to_chat(user, "\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"")
@@ -151,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()
diff --git a/code/modules/antagonists/cult/ritual.dm b/code/modules/antagonists/cult/ritual.dm
index dd129708a8..ba2ea53ef2 100644
--- a/code/modules/antagonists/cult/ritual.dm
+++ b/code/modules/antagonists/cult/ritual.dm
@@ -144,7 +144,8 @@ This file contains the cult dagger and rune list code
if(locate(/obj/effect/rune) in T)
to_chat(user, "There is already a rune here.")
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, "The veil is not weak enough here.")
return FALSE
return TRUE
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 4307f65a28..a1241d5998 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -708,6 +708,11 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
log_game("Summon Cultist rune failed - target died")
return
+ if(cultist_to_summon.pulledby || cultist_to_summon.buckled)
+ to_chat(user, "[cultist_to_summon] is being held in place!")
+ fail_invoke()
+ log_game("Summon Cultist rune failed - target restrained")
+ return
if(!iscultist(cultist_to_summon))
to_chat(user, "[cultist_to_summon] is not a follower of the Geometer!")
fail_invoke()
@@ -1056,7 +1061,7 @@ structure_check() searches for nearby cultist structures required for the invoca
/proc/hudFix(mob/living/carbon/human/target)
if(!target || !target.client)
return
- var/obj/O = target.get_item_by_slot(slot_glasses)
+ var/obj/O = target.get_item_by_slot(SLOT_GLASSES)
if(istype(O, /obj/item/clothing/glasses/hud/security))
var/datum/atom_hud/AH = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
AH.add_hud_to(target)
diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm
index 55a33820f0..3852eb6de1 100644
--- a/code/modules/antagonists/devil/devil.dm
+++ b/code/modules/antagonists/devil/devil.dm
@@ -456,10 +456,10 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
return -1
currentMob.change_mob_type( /mob/living/carbon/human, targetturf, null, 1)
var/mob/living/carbon/human/H = owner.current
- H.equip_to_slot_or_del(new /obj/item/clothing/under/lawyer/black(H), slot_w_uniform)
- H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes)
- H.equip_to_slot_or_del(new /obj/item/storage/briefcase(H), slot_hands)
- H.equip_to_slot_or_del(new /obj/item/pen(H), slot_l_store)
+ H.equip_to_slot_or_del(new /obj/item/clothing/under/lawyer/black(H), SLOT_W_UNIFORM)
+ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), SLOT_SHOES)
+ H.equip_to_slot_or_del(new /obj/item/storage/briefcase(H), SLOT_HANDS)
+ H.equip_to_slot_or_del(new /obj/item/pen(H), SLOT_L_STORE)
if(SOULVALUE >= BLOOD_THRESHOLD)
H.set_species(/datum/species/lizard, 1)
H.underwear = "Nude"
diff --git a/code/modules/antagonists/highlander/highlander.dm b/code/modules/antagonists/highlander/highlander.dm
index 84faf34387..c55f177b7a 100644
--- a/code/modules/antagonists/highlander/highlander.dm
+++ b/code/modules/antagonists/highlander/highlander.dm
@@ -46,11 +46,11 @@
qdel(I)
for(var/obj/item/I in H.held_items)
qdel(I)
- H.equip_to_slot_or_del(new /obj/item/clothing/under/kilt/highlander(H), slot_w_uniform)
- H.equip_to_slot_or_del(new /obj/item/radio/headset/heads/captain(H), slot_ears)
- H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), slot_head)
- H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), slot_shoes)
- H.equip_to_slot_or_del(new /obj/item/pinpointer/nuke(H), slot_l_store)
+ H.equip_to_slot_or_del(new /obj/item/clothing/under/kilt/highlander(H), SLOT_W_UNIFORM)
+ H.equip_to_slot_or_del(new /obj/item/radio/headset/heads/captain(H), SLOT_EARS)
+ H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), SLOT_HEAD)
+ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), SLOT_SHOES)
+ H.equip_to_slot_or_del(new /obj/item/pinpointer/nuke(H), SLOT_L_STORE)
for(var/obj/item/pinpointer/nuke/P in H)
P.attack_self(H)
var/obj/item/card/id/W = new(H)
@@ -61,7 +61,7 @@
W.registered_name = H.real_name
W.flags_1 |= NODROP_1
W.update_label(H.real_name)
- H.equip_to_slot_or_del(W, slot_wear_id)
+ H.equip_to_slot_or_del(W, SLOT_WEAR_ID)
sword = new(H)
if(!GLOB.highlander)
diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm
index 8146ab7fbe..6572584eab 100644
--- a/code/modules/antagonists/morph/morph.dm
+++ b/code/modules/antagonists/morph/morph.dm
@@ -27,12 +27,14 @@
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
vision_range = 1 // Only attack when target is close
- wander = 0
+ wander = FALSE
attacktext = "glomps"
attack_sound = 'sound/effects/blobattack.ogg'
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2)
var/morphed = FALSE
+ var/melee_damage_disguised = 0
+ var/eat_while_disguised = FALSE
var/atom/movable/form = null
var/morph_time = 0
var/static/list/blacklist_typecache = typecacheof(list(
@@ -75,11 +77,14 @@
return !is_type_in_typecache(A, blacklist_typecache) && (isobj(A) || ismob(A))
/mob/living/simple_animal/hostile/morph/proc/eat(atom/movable/A)
+ if(morphed && !eat_while_disguised)
+ to_chat(src, "You can not eat anything while you are disguised!")
+ return FALSE
if(A && A.loc != src)
visible_message("[src] swallows [A] whole!")
A.forceMove(src)
- return 1
- return 0
+ return TRUE
+ return FALSE
/mob/living/simple_animal/hostile/morph/ShiftClickOn(atom/movable/A)
if(morph_time <= world.time && !stat)
@@ -109,8 +114,8 @@
pixel_x = initial(pixel_x)
//Morphed is weaker
- melee_damage_lower = 5
- melee_damage_upper = 5
+ melee_damage_lower = melee_damage_disguised
+ melee_damage_upper = melee_damage_disguised
speed = 0
morph_time = world.time + MORPH_COOLDOWN
@@ -181,10 +186,13 @@
/mob/living/simple_animal/hostile/morph/can_track(mob/living/user)
if(morphed)
- return 0
+ return FALSE
return ..()
/mob/living/simple_animal/hostile/morph/AttackingTarget()
+ if(morphed && !melee_damage_disguised)
+ to_chat(src, "You can not attack while disguised!")
+ return
if(isliving(target)) //Eat Corpses to regen health
var/mob/living/L = target
if(L.stat == DEAD)
diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
index 0e588c4380..a9c6a112bd 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
@@ -501,16 +501,37 @@ This is here to make the tiles around the station mininuke change when it's arme
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/fake = FALSE
+ var/turf/lastlocation
+ var/last_disk_move
/obj/item/disk/nuclear/Initialize()
. = ..()
if(!fake)
GLOB.poi_list |= src
+ last_disk_move = world.time
+ START_PROCESSING(SSobj, src)
/obj/item/disk/nuclear/ComponentInitialize()
. = ..()
AddComponent(/datum/component/stationloving, !fake)
+/obj/item/disk/nuclear/process()
+ if(fake)
+ STOP_PROCESSING(SSobj, src)
+ CRASH("A fake nuke disk tried to call process(). Who the fuck and how the fuck")
+ var/turf/newturf = get_turf(src)
+ if(newturf && lastlocation == newturf)
+ if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.00001))
+ var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
+ if(istype(loneop))
+ loneop.weight += 1
+ else
+ lastlocation = newturf
+ last_disk_move = world.time
+ var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
+ if(istype(loneop) && prob(loneop.weight))
+ loneop.weight = max(loneop.weight - 1, 0)
+
/obj/item/disk/nuclear/examine(mob/user)
. = ..()
if(!fake)
diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm
index 648f62c4a5..df7d21e46b 100644
--- a/code/modules/antagonists/nukeop/nukeop.dm
+++ b/code/modules/antagonists/nukeop/nukeop.dm
@@ -218,7 +218,7 @@
else //Already set by admins/something else?
nuke_team.memorized_code = nuke.r_code
else
- stack_trace("Station self destruct ot found during lone op team creation.")
+ stack_trace("Station self destruct not found during lone op team creation.")
nuke_team.memorized_code = null
/datum/antagonist/nukeop/reinforcement
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index 34d30603d6..03150c0254 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -90,7 +90,7 @@
to_chat(src, "You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.")
to_chat(src, "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.")
to_chat(src, "You do not remember anything of your past lives, nor will you remember anything about this one after your death.")
- to_chat(src, "Be sure to read the wiki page at https://tgstation13.org/wiki/Revenant to learn more.")
+ to_chat(src, "Be sure to read the wiki page to learn more.")
if(!generated_objectives_and_spells)
generated_objectives_and_spells = TRUE
mind.assigned_role = ROLE_REVENANT
diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm
index e3a068eed4..95ea189dde 100644
--- a/code/modules/antagonists/revenant/revenant_abilities.dm
+++ b/code/modules/antagonists/revenant/revenant_abilities.dm
@@ -290,7 +290,7 @@
unlock_amount = 200
action_icon_state = "malfunction"
-//A note to future coders: do not replace this with an EMP because it will wreck malf AIs and gang dominators and everyone will hate you.
+//A note to future coders: do not replace this with an EMP because it will wreck malf AIs and everyone will hate you.
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
for(var/turf/T in targets)
@@ -312,7 +312,7 @@
new /obj/effect/temp_visual/revenant(human.loc)
human.emp_act(EMP_HEAVY)
for(var/obj/thing in T)
- if(istype(thing, /obj/machinery/dominator) || istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
+ if(istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on SMES and APCs, to prevent kekkery
continue
if(prob(20))
if(prob(50))
diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm
index 1f77866d76..51acdae894 100644
--- a/code/modules/antagonists/revolution/revolution.dm
+++ b/code/modules/antagonists/revolution/revolution.dm
@@ -201,12 +201,13 @@
/datum/antagonist/rev/farewell()
if(ishuman(owner.current))
- owner.current.visible_message("[owner.current] looks like they just remembered their real allegiance!", null, null, null, owner.current)
+ owner.current.visible_message("[owner.current] looks like [owner.current.p_theyve()] just remembered [owner.current.p_their()] real allegiance!", null, null, null, owner.current)
to_chat(owner, "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...")
else if(issilicon(owner.current))
owner.current.visible_message("The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.", null, null, null, owner.current)
to_chat(owner, "The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.")
+//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)
@@ -234,9 +235,9 @@
if(give_flash)
var/obj/item/assembly/flash/T = new(H)
var/list/slots = list (
- "backpack" = slot_in_backpack,
- "left pocket" = slot_l_store,
- "right pocket" = slot_r_store
+ "backpack" = SLOT_IN_BACKPACK,
+ "left pocket" = SLOT_L_STORE,
+ "right pocket" = SLOT_R_STORE
)
var/where = H.equip_in_one_of_slots(T, slots)
if (!where)
diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm
index 9457e3a8c8..aea9a1862a 100644
--- a/code/modules/antagonists/slaughter/slaughter.dm
+++ b/code/modules/antagonists/slaughter/slaughter.dm
@@ -66,7 +66,7 @@
name = "pile of viscera"
desc = "A repulsive pile of guts and gore."
gender = NEUTER
- random_icon_states = list("innards")
+ icon_state = "innards"
/mob/living/simple_animal/slaughter/phasein()
. = ..()
diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm
index 8a87191c0d..3ea2e1d739 100644
--- a/code/modules/antagonists/swarmer/swarmer.dm
+++ b/code/modules/antagonists/swarmer/swarmer.dm
@@ -302,10 +302,6 @@
to_chat(S, "This device's destruction would result in the extermination of everything in the area. Aborting.")
return FALSE
-/obj/machinery/dominator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
- to_chat(S, "This device is attempting to corrupt our entire network; attempting to interact with it is too risky. Aborting.")
- return FALSE
-
/obj/effect/rune/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "Searching... sensor malfunction! Target lost. Aborting.")
return FALSE
@@ -497,10 +493,10 @@
D.pixel_z = target.pixel_z
if(do_mob(src, target, 100))
to_chat(src, "Dismantling complete.")
- var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal(target.loc)
- M.amount = 5
+ var/atom/Tsec = target.drop_location()
+ new /obj/item/stack/sheet/metal(Tsec, 5)
for(var/obj/item/I in target.component_parts)
- I.forceMove(M.drop_location())
+ I.forceMove(Tsec)
var/obj/effect/temp_visual/swarmer/disintegration/N = new /obj/effect/temp_visual/swarmer/disintegration(get_turf(target))
N.pixel_x = target.pixel_x
N.pixel_y = target.pixel_y
@@ -509,7 +505,7 @@
if(istype(target, /obj/machinery/computer))
var/obj/machinery/computer/C = target
if(C.circuit)
- C.circuit.forceMove(M.drop_location())
+ C.circuit.forceMove(Tsec)
qdel(target)
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index e09b92a083..f3ea4ef2ea 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -296,9 +296,9 @@
folder = new/obj/item/folder/syndicate/blue(mob.loc)
var/list/slots = list (
- "backpack" = slot_in_backpack,
- "left pocket" = slot_l_store,
- "right pocket" = slot_r_store
+ "backpack" = SLOT_IN_BACKPACK,
+ "left pocket" = SLOT_L_STORE,
+ "right pocket" = SLOT_R_STORE
)
var/where = "At your feet"
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index e0db2e5905..fc933a44cf 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -204,12 +204,12 @@
H.dropItemToGround(I)
var/hat = pick(/obj/item/clothing/head/helmet/roman, /obj/item/clothing/head/helmet/roman/legionaire)
- H.equip_to_slot_or_del(new hat(H), slot_head)
- H.equip_to_slot_or_del(new /obj/item/clothing/under/roman(H), slot_w_uniform)
- H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), slot_shoes)
+ H.equip_to_slot_or_del(new hat(H), SLOT_HEAD)
+ H.equip_to_slot_or_del(new /obj/item/clothing/under/roman(H), SLOT_W_UNIFORM)
+ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), SLOT_SHOES)
H.put_in_hands(new /obj/item/shield/riot/roman(H), TRUE)
H.put_in_hands(new /obj/item/claymore(H), TRUE)
- H.equip_to_slot_or_del(new /obj/item/twohanded/spear(H), slot_back)
+ H.equip_to_slot_or_del(new /obj/item/twohanded/spear(H), SLOT_BACK)
/obj/item/voodoo
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index c0a328b3ae..1c63f4a570 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -8,7 +8,7 @@
layer = HIGH_OBJ_LAYER
desc = "A fragment of the legendary treasure known simply as the 'Soul Stone'. The shard still flickers with a fraction of the full artefact's power."
w_class = WEIGHT_CLASS_TINY
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
var/usability = 0
var/old_shard = FALSE
@@ -33,7 +33,6 @@
..()
if(!iscultist(user) && !iswizard(user) && !usability)
to_chat(user, "An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.")
- user.Dizzy(120)
/obj/item/soulstone/examine(mob/user)
..()
@@ -223,7 +222,7 @@
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker && SSticker.mode)
SSticker.mode.add_cultist(newstruct.mind, 0)
if(iscultist(stoner) || cultoverride)
- to_chat(newstruct, "You are still bound to serve the cult[stoner ? " and [stoner]":""], follow their orders and help them complete their goals at all costs.")
+ to_chat(newstruct, "You are still bound to serve the cult[stoner ? " and [stoner]":""], follow [stoner ? stoner.p_their() : "their"] orders and help [stoner ? stoner.p_them() : "them"] complete [stoner ? stoner.p_their() : "their"] goals at all costs.")
else if(stoner)
to_chat(newstruct, "You are still bound to serve your creator, [stoner], follow their orders and help them complete their goals at all costs.")
newstruct.clear_alert("bloodsense")
diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm
index a042b3d08c..3f94c65437 100644
--- a/code/modules/antagonists/wizard/equipment/spellbook.dm
+++ b/code/modules/antagonists/wizard/equipment/spellbook.dm
@@ -1,716 +1,716 @@
-/datum/spellbook_entry
- var/name = "Entry Name"
-
- var/spell_type = null
- var/desc = ""
- var/category = "Offensive"
- var/cost = 2
- var/refundable = 1
- var/surplus = -1 // -1 for infinite, not used by anything atm
- var/obj/effect/proc_holder/spell/S = null //Since spellbooks can be used by only one person anyway we can track the actual spell
- var/buy_word = "Learn"
- var/limit //used to prevent a spellbook_entry from being bought more than X times with one wizard spellbook
- var/list/no_coexistance_typecache //Used so you can't have specific spells together
-
-/datum/spellbook_entry/New()
- ..()
- no_coexistance_typecache = typecacheof(no_coexistance_typecache)
-
-/datum/spellbook_entry/proc/IsAvailible() // For config prefs / gamemode restrictions - these are round applied
- return 1
-
-/datum/spellbook_entry/proc/CanBuy(mob/living/carbon/human/user,obj/item/spellbook/book) // Specific circumstances
- if(book.uses= aspell.level_max)
- to_chat(user, "This spell cannot be improved further.")
- return 0
- else
- aspell.name = initial(aspell.name)
- aspell.spell_level++
- aspell.charge_max = round(initial(aspell.charge_max) - aspell.spell_level * (initial(aspell.charge_max) - aspell.cooldown_min)/ aspell.level_max)
- if(aspell.charge_max < aspell.charge_counter)
- aspell.charge_counter = aspell.charge_max
- switch(aspell.spell_level)
- if(1)
- to_chat(user, "You have improved [aspell.name] into Efficient [aspell.name].")
- aspell.name = "Efficient [aspell.name]"
- if(2)
- to_chat(user, "You have further improved [aspell.name] into Quickened [aspell.name].")
- aspell.name = "Quickened [aspell.name]"
- if(3)
- to_chat(user, "You have further improved [aspell.name] into Free [aspell.name].")
- aspell.name = "Free [aspell.name]"
- if(4)
- to_chat(user, "You have further improved [aspell.name] into Instant [aspell.name].")
- aspell.name = "Instant [aspell.name]"
- if(aspell.spell_level >= aspell.level_max)
- to_chat(user, "This spell cannot be strengthened any further.")
- SSblackbox.record_feedback("nested tally", "wizard_spell_improved", 1, list("[name]", "[aspell.spell_level]"))
- return 1
- //No same spell found - just learn it
- SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
- user.mind.AddSpell(S)
- to_chat(user, "You have learned [S.name].")
- return 1
-
-/datum/spellbook_entry/proc/CanRefund(mob/living/carbon/human/user,obj/item/spellbook/book)
- if(!refundable)
- return 0
- if(!S)
- S = new spell_type()
- for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list)
- if(initial(S.name) == initial(aspell.name))
- return 1
- return 0
-
-/datum/spellbook_entry/proc/Refund(mob/living/carbon/human/user,obj/item/spellbook/book) //return point value or -1 for failure
- var/area/wizard_station/A = locate() in GLOB.sortedAreas
- if(!(user in A.contents))
- to_chat(user, "You can only refund spells at the wizard lair")
- return -1
- if(!S)
- S = new spell_type()
- var/spell_levels = 0
- for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list)
- if(initial(S.name) == initial(aspell.name))
- spell_levels = aspell.spell_level
- user.mind.spell_list.Remove(aspell)
- qdel(S)
- return cost * (spell_levels+1)
- return -1
-/datum/spellbook_entry/proc/GetInfo()
- if(!S)
- S = new spell_type()
- var/dat =""
- dat += "[initial(S.name)]"
- if(S.charge_type == "recharge")
- dat += " Cooldown:[S.charge_max/10]"
- dat += " Cost:[cost] "
- dat += "[S.desc][desc] "
- dat += "[S.clothes_req?"Needs wizard garb":"Can be cast without wizard garb"] "
- return dat
-
-/datum/spellbook_entry/fireball
- name = "Fireball"
- spell_type = /obj/effect/proc_holder/spell/aimed/fireball
-
-/datum/spellbook_entry/spell_cards
- name = "Spell Cards"
- spell_type = /obj/effect/proc_holder/spell/aimed/spell_cards
-
-/datum/spellbook_entry/rod_form
- name = "Rod Form"
- spell_type = /obj/effect/proc_holder/spell/targeted/rod_form
-
-/datum/spellbook_entry/magicm
- name = "Magic Missile"
- spell_type = /obj/effect/proc_holder/spell/targeted/projectile/magic_missile
- category = "Defensive"
-
-/datum/spellbook_entry/disintegrate
- name = "Disintegrate"
- spell_type = /obj/effect/proc_holder/spell/targeted/touch/disintegrate
-
-/datum/spellbook_entry/disabletech
- name = "Disable Tech"
- spell_type = /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
- category = "Defensive"
- cost = 1
-
-/datum/spellbook_entry/repulse
- name = "Repulse"
- spell_type = /obj/effect/proc_holder/spell/aoe_turf/repulse
- category = "Defensive"
-
-/datum/spellbook_entry/lightningPacket
- name = "Lightning bolt! Lightning bolt!"
- spell_type = /obj/effect/proc_holder/spell/targeted/conjure_item/spellpacket
- category = "Defensive"
-
-/datum/spellbook_entry/timestop
- name = "Time Stop"
- spell_type = /obj/effect/proc_holder/spell/aoe_turf/conjure/timestop
- category = "Defensive"
-
-/datum/spellbook_entry/smoke
- name = "Smoke"
- spell_type = /obj/effect/proc_holder/spell/targeted/smoke
- category = "Defensive"
- cost = 1
-
-/datum/spellbook_entry/blind
- name = "Blind"
- spell_type = /obj/effect/proc_holder/spell/targeted/trigger/blind
- cost = 1
-
-/datum/spellbook_entry/mindswap
- name = "Mindswap"
- spell_type = /obj/effect/proc_holder/spell/targeted/mind_transfer
- category = "Mobility"
-
-/datum/spellbook_entry/forcewall
- name = "Force Wall"
- spell_type = /obj/effect/proc_holder/spell/targeted/forcewall
- category = "Defensive"
- cost = 1
-
-/datum/spellbook_entry/blink
- name = "Blink"
- spell_type = /obj/effect/proc_holder/spell/targeted/turf_teleport/blink
- category = "Mobility"
-
-/datum/spellbook_entry/teleport
- name = "Teleport"
- spell_type = /obj/effect/proc_holder/spell/targeted/area_teleport/teleport
- category = "Mobility"
-
-/datum/spellbook_entry/mutate
- name = "Mutate"
- spell_type = /obj/effect/proc_holder/spell/targeted/genetic/mutate
-
-/datum/spellbook_entry/jaunt
- name = "Ethereal Jaunt"
- spell_type = /obj/effect/proc_holder/spell/targeted/ethereal_jaunt
- category = "Mobility"
-
-/datum/spellbook_entry/knock
- name = "Knock"
- spell_type = /obj/effect/proc_holder/spell/aoe_turf/knock
- category = "Mobility"
- cost = 1
-
-/datum/spellbook_entry/fleshtostone
- name = "Flesh to Stone"
- spell_type = /obj/effect/proc_holder/spell/targeted/touch/flesh_to_stone
-
-/datum/spellbook_entry/summonitem
- name = "Summon Item"
- spell_type = /obj/effect/proc_holder/spell/targeted/summonitem
- category = "Assistance"
- cost = 1
-
-/datum/spellbook_entry/lichdom
- name = "Bind Soul"
- spell_type = /obj/effect/proc_holder/spell/targeted/lichdom
- category = "Defensive"
-
-/datum/spellbook_entry/teslablast
- name = "Tesla Blast"
- spell_type = /obj/effect/proc_holder/spell/targeted/tesla
-
-/datum/spellbook_entry/lightningbolt
- name = "Lightning Bolt"
- spell_type = /obj/effect/proc_holder/spell/aimed/lightningbolt
- cost = 3
-
-/datum/spellbook_entry/lightningbolt/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) //return 1 on success
- . = ..()
- user.flags_2 |= TESLA_IGNORE_2
-
-/datum/spellbook_entry/infinite_guns
- name = "Lesser Summon Guns"
- spell_type = /obj/effect/proc_holder/spell/targeted/infinite_guns/gun
- cost = 3
- no_coexistance_typecache = /obj/effect/proc_holder/spell/targeted/infinite_guns/arcane_barrage
-
-/datum/spellbook_entry/arcane_barrage
- name = "Arcane Barrage"
- spell_type = /obj/effect/proc_holder/spell/targeted/infinite_guns/arcane_barrage
- cost = 3
- no_coexistance_typecache = /obj/effect/proc_holder/spell/targeted/infinite_guns/gun
-
-/datum/spellbook_entry/barnyard
- name = "Barnyard Curse"
- spell_type = /obj/effect/proc_holder/spell/targeted/barnyardcurse
-
-/datum/spellbook_entry/charge
- name = "Charge"
- spell_type = /obj/effect/proc_holder/spell/targeted/charge
- category = "Assistance"
- cost = 1
-
-/datum/spellbook_entry/shapeshift
- name = "Wild Shapeshift"
- spell_type = /obj/effect/proc_holder/spell/targeted/shapeshift
- category = "Assistance"
- cost = 1
-
-/datum/spellbook_entry/spacetime_dist
- name = "Spacetime Distortion"
- spell_type = /obj/effect/proc_holder/spell/spacetime_dist
- category = "Defensive"
- cost = 1
-
-/datum/spellbook_entry/the_traps
- name = "The Traps!"
- spell_type = /obj/effect/proc_holder/spell/aoe_turf/conjure/the_traps
- category = "Defensive"
- cost = 1
-
-
-/datum/spellbook_entry/item
- name = "Buy Item"
- refundable = 0
- buy_word = "Summon"
- var/item_path= null
-
-
-/datum/spellbook_entry/item/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
- new item_path(get_turf(user))
- SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
- return 1
-
-/datum/spellbook_entry/item/GetInfo()
- var/dat =""
- dat += "[name]"
- dat += " Cost:[cost] "
- dat += "[desc] "
- if(surplus>=0)
- dat += "[surplus] left. "
- return dat
-
-/datum/spellbook_entry/item/staffchange
- name = "Staff of Change"
- desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself."
- item_path = /obj/item/gun/magic/staff/change
-
-/datum/spellbook_entry/item/staffanimation
- name = "Staff of Animation"
- desc = "An arcane staff capable of shooting bolts of eldritch energy which cause inanimate objects to come to life. This magic doesn't affect machines."
- item_path = /obj/item/gun/magic/staff/animate
- category = "Assistance"
-
-/datum/spellbook_entry/item/staffchaos
- name = "Staff of Chaos"
- desc = "A caprious tool that can fire all sorts of magic without any rhyme or reason. Using it on people you care about is not recommended."
- item_path = /obj/item/gun/magic/staff/chaos
-
-/datum/spellbook_entry/item/spellblade
- name = "Spellblade"
- desc = "A sword capable of firing blasts of energy which rip targets limb from limb."
- item_path = /obj/item/gun/magic/staff/spellblade
-
-/datum/spellbook_entry/item/staffdoor
- name = "Staff of Door Creation"
- desc = "A particular staff that can mold solid metal into ornate doors. Useful for getting around in the absence of other transportation. Does not work on glass."
- item_path = /obj/item/gun/magic/staff/door
- cost = 1
- category = "Mobility"
-
-/datum/spellbook_entry/item/staffhealing
- name = "Staff of Healing"
- desc = "An altruistic staff that can heal the lame and raise the dead."
- item_path = /obj/item/gun/magic/staff/healing
- cost = 1
- category = "Defensive"
-
-/datum/spellbook_entry/item/scryingorb
- name = "Scrying Orb"
- desc = "An incandescent orb of crackling energy, using it will allow you to ghost while alive, allowing you to spy upon the station with ease. In addition, buying it will permanently grant you x-ray vision."
- item_path = /obj/item/scrying
- category = "Defensive"
-
-/datum/spellbook_entry/item/soulstones
- name = "Six Soul Stone Shards and the spell Artificer"
- desc = "Soul Stone Shards are ancient tools capable of capturing and harnessing the spirits of the dead and dying. The spell Artificer allows you to create arcane machines for the captured souls to pilot."
- item_path = /obj/item/storage/belt/soulstone/full
- category = "Assistance"
-
-/datum/spellbook_entry/item/soulstones/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
- . =..()
- if(.)
- user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/construct(null))
- return .
-
-/datum/spellbook_entry/item/necrostone
- name = "A Necromantic Stone"
- desc = "A Necromantic stone is able to resurrect three dead individuals as skeletal thralls for you to command."
- item_path = /obj/item/necromantic_stone
- category = "Assistance"
-
-/datum/spellbook_entry/item/wands
- name = "Wand Assortment"
- desc = "A collection of wands that allow for a wide variety of utility. Wands have a limited number of charges, so be conservative in use. Comes in a handy belt."
- item_path = /obj/item/storage/belt/wands/full
- category = "Defensive"
-
-/datum/spellbook_entry/item/armor
- name = "Mastercrafted Armor Set"
- desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space."
- item_path = /obj/item/clothing/suit/space/hardsuit/wizard
- category = "Defensive"
-
-/datum/spellbook_entry/item/armor/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
- . = ..()
- if(.)
- new /obj/item/clothing/shoes/sandal/magic(get_turf(user)) //In case they've lost them.
- new /obj/item/clothing/gloves/color/purple(get_turf(user))//To complete the outfit
-
-/datum/spellbook_entry/item/contract
- name = "Contract of Apprenticeship"
- desc = "A magical contract binding an apprentice wizard to your service, using it will summon them to your side."
- item_path = /obj/item/antag_spawner/contract
- category = "Assistance"
-
-/datum/spellbook_entry/item/guardian
- name = "Guardian Deck"
- desc = "A deck of guardian tarot cards, capable of binding a personal guardian to your body. There are multiple types of guardian available, but all of them will transfer some amount of damage to you. \
- It would be wise to avoid buying these with anything capable of causing you to swap bodies with others."
- item_path = /obj/item/guardiancreator/choose/wizard
- category = "Assistance"
-
-/datum/spellbook_entry/item/guardian/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
- . = ..()
- if(.)
- new /obj/item/paper/guides/antag/guardian/wizard(get_turf(user))
-
-/datum/spellbook_entry/item/bloodbottle
- name = "Bottle of Blood"
- desc = "A bottle of magically infused blood, the smell of which will attract extradimensional beings when broken. Be careful though, the kinds of creatures summoned by blood magic are indiscriminate in their killing, and you yourself may become a victim."
- item_path = /obj/item/antag_spawner/slaughter_demon
- limit = 3
- category = "Assistance"
-
-/datum/spellbook_entry/item/hugbottle
- name = "Bottle of Tickles"
- desc = "A bottle of magically infused fun, the smell of which will \
- attract adorable extradimensional beings when broken. These beings \
- are similar to slaughter demons, but they do not permamently kill \
- their victims, instead putting them in an extradimensional hugspace, \
- to be released on the demon's death. Chaotic, but not ultimately \
- damaging. The crew's reaction to the other hand could be very \
- destructive."
- item_path = /obj/item/antag_spawner/slaughter_demon/laughter
- cost = 1 //non-destructive; it's just a jape, sibling!
- limit = 3
- category = "Assistance"
-
-/datum/spellbook_entry/item/mjolnir
- name = "Mjolnir"
- desc = "A mighty hammer on loan from Thor, God of Thunder. It crackles with barely contained power."
- item_path = /obj/item/twohanded/mjollnir
-
-/datum/spellbook_entry/item/singularity_hammer
- name = "Singularity Hammer"
- desc = "A hammer that creates an intensely powerful field of gravity where it strikes, pulling everything nearby to the point of impact."
- item_path = /obj/item/twohanded/singularityhammer
-
-/datum/spellbook_entry/item/battlemage
- name = "Battlemage Armour"
- desc = "An ensorcelled suit of armour, protected by a powerful shield. The shield can completly negate sixteen attacks before being permanently depleted."
- item_path = /obj/item/clothing/suit/space/hardsuit/shielded/wizard
- limit = 1
- category = "Defensive"
-
-/datum/spellbook_entry/item/battlemage_charge
- name = "Battlemage Armour Charges"
- desc = "A powerful defensive rune, it will grant eight additional charges to a suit of battlemage armour."
- item_path = /obj/item/wizard_armour_charge
- category = "Defensive"
- cost = 1
-
-/datum/spellbook_entry/item/warpwhistle
- name = "Warp Whistle"
- desc = "A strange whistle that will transport you to a distant safe place on the station. There is a window of vulnerability at the beginning of every use."
- item_path = /obj/item/warpwhistle
- category = "Mobility"
- cost = 1
-
-/datum/spellbook_entry/summon
- name = "Summon Stuff"
- category = "Rituals"
- refundable = 0
- buy_word = "Cast"
- var/active = 0
-
-/datum/spellbook_entry/summon/CanBuy(mob/living/carbon/human/user,obj/item/spellbook/book)
- return ..() && !active
-
-/datum/spellbook_entry/summon/GetInfo()
- var/dat =""
- dat += "[name]"
- if(cost>0)
- dat += " Cost:[cost] "
- else
- dat += " No Cost "
- dat += "[desc] "
- if(active)
- dat += "Already cast! "
- return dat
-
-/datum/spellbook_entry/summon/ghosts
- name = "Summon Ghosts"
- desc = "Spook the crew out by making them see dead people. Be warned, ghosts are capricious and occasionally vindicative, and some will use their incredibly minor abilties to frustrate you."
- cost = 0
-
-/datum/spellbook_entry/summon/ghosts/IsAvailible()
- if(!SSticker.mode)
- return FALSE
- else
- return TRUE
-
-/datum/spellbook_entry/summon/ghosts/Buy(mob/living/carbon/human/user, obj/item/spellbook/book)
- SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
- new /datum/round_event/wizard/ghost()
- active = TRUE
- to_chat(user, "You have cast summon ghosts!")
- playsound(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
- return TRUE
-
-/datum/spellbook_entry/summon/guns
- name = "Summon Guns"
- desc = "Nothing could possibly go wrong with arming a crew of lunatics just itching for an excuse to kill you. Just be careful not to stand still too long!"
-
-/datum/spellbook_entry/summon/guns/IsAvailible()
- if(!SSticker.mode) // In case spellbook is placed on map
- return 0
- return !CONFIG_GET(flag/no_summon_guns)
-
-/datum/spellbook_entry/summon/guns/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
- SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
- rightandwrong(SUMMON_GUNS, user, 25)
- active = 1
- playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1)
- to_chat(user, "You have cast summon guns!")
- return 1
-
-/datum/spellbook_entry/summon/magic
- name = "Summon Magic"
- desc = "Share the wonders of magic with the crew and show them why they aren't to be trusted with it at the same time."
-
-/datum/spellbook_entry/summon/magic/IsAvailible()
- if(!SSticker.mode) // In case spellbook is placed on map
- return 0
- return !CONFIG_GET(flag/no_summon_magic)
-
-/datum/spellbook_entry/summon/magic/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
- SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
- rightandwrong(SUMMON_MAGIC, user, 25)
- active = 1
- playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1)
- to_chat(user, "You have cast summon magic!")
- return 1
-
-/datum/spellbook_entry/summon/events
- name = "Summon Events"
- desc = "Give Murphy's law a little push and replace all events with special wizard ones that will confound and confuse everyone. Multiple castings increase the rate of these events."
- var/times = 0
-
-/datum/spellbook_entry/summon/events/IsAvailible()
- if(!SSticker.mode) // In case spellbook is placed on map
- return 0
- return !CONFIG_GET(flag/no_summon_events)
-
-/datum/spellbook_entry/summon/events/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
- SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
- summonevents()
- times++
- playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1)
- to_chat(user, "You have cast summon events.")
- return 1
-
-/datum/spellbook_entry/summon/events/GetInfo()
- . = ..()
- if(times>0)
- . += "You cast it [times] times. "
- return .
-
-/obj/item/spellbook
- name = "spell book"
- desc = "An unearthly tome that glows with power."
- icon = 'icons/obj/library.dmi'
- icon_state ="book"
- throw_speed = 2
- throw_range = 5
- w_class = WEIGHT_CLASS_TINY
- var/uses = 10
- var/temp = null
- var/tab = null
- var/mob/living/carbon/human/owner
- var/list/datum/spellbook_entry/entries = list()
- var/list/categories = list()
-
-/obj/item/spellbook/examine(mob/user)
- ..()
- if(owner)
- to_chat(user, "There is a small signature on the front cover: \"[owner]\".")
- else
- to_chat(user, "It appears to have no author.")
-
-/obj/item/spellbook/Initialize()
- . = ..()
- prepare_spells()
-
-/obj/item/spellbook/proc/prepare_spells()
- var/entry_types = subtypesof(/datum/spellbook_entry) - /datum/spellbook_entry/item - /datum/spellbook_entry/summon
- for(var/T in entry_types)
- var/datum/spellbook_entry/E = new T
- if(E.IsAvailible())
- entries |= E
- categories |= E.category
- else
- qdel(E)
- tab = categories[1]
-
-/obj/item/spellbook/attackby(obj/item/O, mob/user, params)
- if(istype(O, /obj/item/antag_spawner/contract))
- var/obj/item/antag_spawner/contract/contract = O
- if(contract.used)
- to_chat(user, "The contract has been used, you can't get your points back now!")
- else
- to_chat(user, "You feed the contract back into the spellbook, refunding your points.")
- uses++
- for(var/datum/spellbook_entry/item/contract/CT in entries)
- if(!isnull(CT.limit))
- CT.limit++
- qdel(O)
- else if(istype(O, /obj/item/antag_spawner/slaughter_demon))
- to_chat(user, "On second thought, maybe summoning a demon is a bad idea. You refund your points.")
- uses++
- for(var/datum/spellbook_entry/item/bloodbottle/BB in entries)
- if(!isnull(BB.limit))
- BB.limit++
- qdel(O)
-
-/obj/item/spellbook/proc/GetCategoryHeader(category)
- var/dat = ""
- switch(category)
- if("Offensive")
- dat += "Spells and items geared towards debilitating and destroying.
"
- dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased. "
- dat += "For spells: the number after the spell name is the cooldown time. "
- dat += "You can reduce this number by spending more points on the spell. "
- if("Defensive")
- dat += "Spells and items geared towards improving your survivabilty or reducing foes' ability to attack.
"
- dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased. "
- dat += "For spells: the number after the spell name is the cooldown time. "
- dat += "You can reduce this number by spending more points on the spell. "
- if("Mobility")
- dat += "Spells and items geared towards improving your ability to move. It is a good idea to take at least one.
"
- dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased. "
- dat += "For spells: the number after the spell name is the cooldown time. "
- dat += "You can reduce this number by spending more points on the spell. "
- if("Assistance")
- dat += "Spells and items geared towards bringing in outside forces to aid you or improving upon your other items and abilties.
"
- dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased. "
- dat += "For spells: the number after the spell name is the cooldown time. "
- dat += "You can reduce this number by spending more points on the spell. "
- if("Challenges")
- dat += "The Wizard Federation typically has hard limits on the potency and number of spells brought to the station based on risk. "
- dat += "Arming the station against you will increases the risk, but will grant you one more charge for your spellbook. "
- if("Rituals")
- dat += "These powerful spells change the very fabric of reality. Not always in your favour. "
- return dat
-
-/obj/item/spellbook/proc/wrap(content)
- var/dat = ""
- dat +="Spellbook"
- dat += {"
-
-
-
- "}
- dat += {"[content]"}
- return dat
-
-/obj/item/spellbook/attack_self(mob/user)
- if(!owner)
- to_chat(user, "You bind the spellbook to yourself.")
- owner = user
- return
- if(user != owner)
- to_chat(user, "The [name] does not recognize you as its owner and refuses to open!")
- return
- user.set_machine(src)
- var/dat = ""
-
- dat += "
"
- var/list/cat_dat = list()
- for(var/category in categories)
- cat_dat[category] = ""
- dat += "
"
- dat += GetCategoryHeader(category)
- dat += cat_dat[category]
- dat += "
"
-
- user << browse(wrap(dat), "window=spellbook;size=700x500")
- onclose(user, "spellbook")
- return
-
-/obj/item/spellbook/Topic(href, href_list)
- ..()
- var/mob/living/carbon/human/H = usr
-
- if(H.stat || H.restrained())
- return
- if(!ishuman(H))
- return 1
-
- if(H.mind.special_role == "apprentice")
- temp = "If you got caught sneaking a peek from your teacher's spellbook, you'd likely be expelled from the Wizard Academy. Better not."
- return
-
- var/datum/spellbook_entry/E = null
- if(loc == H || (in_range(src, H) && isturf(loc)))
- H.set_machine(src)
- if(href_list["buy"])
- E = entries[text2num(href_list["buy"])]
- if(E && E.CanBuy(H,src))
- if(E.Buy(H,src))
- if(E.limit)
- E.limit--
- uses -= E.cost
- else if(href_list["refund"])
- E = entries[text2num(href_list["refund"])]
- if(E && E.refundable)
- var/result = E.Refund(H,src)
- if(result > 0)
- if(!isnull(E.limit))
- E.limit += result
- uses += result
- else if(href_list["page"])
- tab = sanitize(href_list["page"])
- attack_self(H)
- return
+/datum/spellbook_entry
+ var/name = "Entry Name"
+
+ var/spell_type = null
+ var/desc = ""
+ var/category = "Offensive"
+ var/cost = 2
+ var/refundable = 1
+ var/surplus = -1 // -1 for infinite, not used by anything atm
+ var/obj/effect/proc_holder/spell/S = null //Since spellbooks can be used by only one person anyway we can track the actual spell
+ var/buy_word = "Learn"
+ var/limit //used to prevent a spellbook_entry from being bought more than X times with one wizard spellbook
+ var/list/no_coexistance_typecache //Used so you can't have specific spells together
+
+/datum/spellbook_entry/New()
+ ..()
+ no_coexistance_typecache = typecacheof(no_coexistance_typecache)
+
+/datum/spellbook_entry/proc/IsAvailible() // For config prefs / gamemode restrictions - these are round applied
+ return 1
+
+/datum/spellbook_entry/proc/CanBuy(mob/living/carbon/human/user,obj/item/spellbook/book) // Specific circumstances
+ if(book.uses= aspell.level_max)
+ to_chat(user, "This spell cannot be improved further.")
+ return 0
+ else
+ aspell.name = initial(aspell.name)
+ aspell.spell_level++
+ aspell.charge_max = round(initial(aspell.charge_max) - aspell.spell_level * (initial(aspell.charge_max) - aspell.cooldown_min)/ aspell.level_max)
+ if(aspell.charge_max < aspell.charge_counter)
+ aspell.charge_counter = aspell.charge_max
+ switch(aspell.spell_level)
+ if(1)
+ to_chat(user, "You have improved [aspell.name] into Efficient [aspell.name].")
+ aspell.name = "Efficient [aspell.name]"
+ if(2)
+ to_chat(user, "You have further improved [aspell.name] into Quickened [aspell.name].")
+ aspell.name = "Quickened [aspell.name]"
+ if(3)
+ to_chat(user, "You have further improved [aspell.name] into Free [aspell.name].")
+ aspell.name = "Free [aspell.name]"
+ if(4)
+ to_chat(user, "You have further improved [aspell.name] into Instant [aspell.name].")
+ aspell.name = "Instant [aspell.name]"
+ if(aspell.spell_level >= aspell.level_max)
+ to_chat(user, "This spell cannot be strengthened any further.")
+ SSblackbox.record_feedback("nested tally", "wizard_spell_improved", 1, list("[name]", "[aspell.spell_level]"))
+ return 1
+ //No same spell found - just learn it
+ SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
+ user.mind.AddSpell(S)
+ to_chat(user, "You have learned [S.name].")
+ return 1
+
+/datum/spellbook_entry/proc/CanRefund(mob/living/carbon/human/user,obj/item/spellbook/book)
+ if(!refundable)
+ return 0
+ if(!S)
+ S = new spell_type()
+ for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list)
+ if(initial(S.name) == initial(aspell.name))
+ return 1
+ return 0
+
+/datum/spellbook_entry/proc/Refund(mob/living/carbon/human/user,obj/item/spellbook/book) //return point value or -1 for failure
+ var/area/wizard_station/A = locate() in GLOB.sortedAreas
+ if(!(user in A.contents))
+ to_chat(user, "You can only refund spells at the wizard lair")
+ return -1
+ if(!S)
+ S = new spell_type()
+ var/spell_levels = 0
+ for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list)
+ if(initial(S.name) == initial(aspell.name))
+ spell_levels = aspell.spell_level
+ user.mind.spell_list.Remove(aspell)
+ qdel(S)
+ return cost * (spell_levels+1)
+ return -1
+/datum/spellbook_entry/proc/GetInfo()
+ if(!S)
+ S = new spell_type()
+ var/dat =""
+ dat += "[initial(S.name)]"
+ if(S.charge_type == "recharge")
+ dat += " Cooldown:[S.charge_max/10]"
+ dat += " Cost:[cost] "
+ dat += "[S.desc][desc] "
+ dat += "[S.clothes_req?"Needs wizard garb":"Can be cast without wizard garb"] "
+ return dat
+
+/datum/spellbook_entry/fireball
+ name = "Fireball"
+ spell_type = /obj/effect/proc_holder/spell/aimed/fireball
+
+/datum/spellbook_entry/spell_cards
+ name = "Spell Cards"
+ spell_type = /obj/effect/proc_holder/spell/aimed/spell_cards
+
+/datum/spellbook_entry/rod_form
+ name = "Rod Form"
+ spell_type = /obj/effect/proc_holder/spell/targeted/rod_form
+
+/datum/spellbook_entry/magicm
+ name = "Magic Missile"
+ spell_type = /obj/effect/proc_holder/spell/targeted/projectile/magic_missile
+ category = "Defensive"
+
+/datum/spellbook_entry/disintegrate
+ name = "Disintegrate"
+ spell_type = /obj/effect/proc_holder/spell/targeted/touch/disintegrate
+
+/datum/spellbook_entry/disabletech
+ name = "Disable Tech"
+ spell_type = /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
+ category = "Defensive"
+ cost = 1
+
+/datum/spellbook_entry/repulse
+ name = "Repulse"
+ spell_type = /obj/effect/proc_holder/spell/aoe_turf/repulse
+ category = "Defensive"
+
+/datum/spellbook_entry/lightningPacket
+ name = "Lightning bolt! Lightning bolt!"
+ spell_type = /obj/effect/proc_holder/spell/targeted/conjure_item/spellpacket
+ category = "Defensive"
+
+/datum/spellbook_entry/timestop
+ name = "Time Stop"
+ spell_type = /obj/effect/proc_holder/spell/aoe_turf/conjure/timestop
+ category = "Defensive"
+
+/datum/spellbook_entry/smoke
+ name = "Smoke"
+ spell_type = /obj/effect/proc_holder/spell/targeted/smoke
+ category = "Defensive"
+ cost = 1
+
+/datum/spellbook_entry/blind
+ name = "Blind"
+ spell_type = /obj/effect/proc_holder/spell/targeted/trigger/blind
+ cost = 1
+
+/datum/spellbook_entry/mindswap
+ name = "Mindswap"
+ spell_type = /obj/effect/proc_holder/spell/targeted/mind_transfer
+ category = "Mobility"
+
+/datum/spellbook_entry/forcewall
+ name = "Force Wall"
+ spell_type = /obj/effect/proc_holder/spell/targeted/forcewall
+ category = "Defensive"
+ cost = 1
+
+/datum/spellbook_entry/blink
+ name = "Blink"
+ spell_type = /obj/effect/proc_holder/spell/targeted/turf_teleport/blink
+ category = "Mobility"
+
+/datum/spellbook_entry/teleport
+ name = "Teleport"
+ spell_type = /obj/effect/proc_holder/spell/targeted/area_teleport/teleport
+ category = "Mobility"
+
+/datum/spellbook_entry/mutate
+ name = "Mutate"
+ spell_type = /obj/effect/proc_holder/spell/targeted/genetic/mutate
+
+/datum/spellbook_entry/jaunt
+ name = "Ethereal Jaunt"
+ spell_type = /obj/effect/proc_holder/spell/targeted/ethereal_jaunt
+ category = "Mobility"
+
+/datum/spellbook_entry/knock
+ name = "Knock"
+ spell_type = /obj/effect/proc_holder/spell/aoe_turf/knock
+ category = "Mobility"
+ cost = 1
+
+/datum/spellbook_entry/fleshtostone
+ name = "Flesh to Stone"
+ spell_type = /obj/effect/proc_holder/spell/targeted/touch/flesh_to_stone
+
+/datum/spellbook_entry/summonitem
+ name = "Summon Item"
+ spell_type = /obj/effect/proc_holder/spell/targeted/summonitem
+ category = "Assistance"
+ cost = 1
+
+/datum/spellbook_entry/lichdom
+ name = "Bind Soul"
+ spell_type = /obj/effect/proc_holder/spell/targeted/lichdom
+ category = "Defensive"
+
+/datum/spellbook_entry/teslablast
+ name = "Tesla Blast"
+ spell_type = /obj/effect/proc_holder/spell/targeted/tesla
+
+/datum/spellbook_entry/lightningbolt
+ name = "Lightning Bolt"
+ spell_type = /obj/effect/proc_holder/spell/aimed/lightningbolt
+ cost = 3
+
+/datum/spellbook_entry/lightningbolt/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) //return 1 on success
+ . = ..()
+ user.flags_1 |= TESLA_IGNORE_1
+
+/datum/spellbook_entry/infinite_guns
+ name = "Lesser Summon Guns"
+ spell_type = /obj/effect/proc_holder/spell/targeted/infinite_guns/gun
+ cost = 3
+ no_coexistance_typecache = /obj/effect/proc_holder/spell/targeted/infinite_guns/arcane_barrage
+
+/datum/spellbook_entry/arcane_barrage
+ name = "Arcane Barrage"
+ spell_type = /obj/effect/proc_holder/spell/targeted/infinite_guns/arcane_barrage
+ cost = 3
+ no_coexistance_typecache = /obj/effect/proc_holder/spell/targeted/infinite_guns/gun
+
+/datum/spellbook_entry/barnyard
+ name = "Barnyard Curse"
+ spell_type = /obj/effect/proc_holder/spell/targeted/barnyardcurse
+
+/datum/spellbook_entry/charge
+ name = "Charge"
+ spell_type = /obj/effect/proc_holder/spell/targeted/charge
+ category = "Assistance"
+ cost = 1
+
+/datum/spellbook_entry/shapeshift
+ name = "Wild Shapeshift"
+ spell_type = /obj/effect/proc_holder/spell/targeted/shapeshift
+ category = "Assistance"
+ cost = 1
+
+/datum/spellbook_entry/spacetime_dist
+ name = "Spacetime Distortion"
+ spell_type = /obj/effect/proc_holder/spell/spacetime_dist
+ category = "Defensive"
+ cost = 1
+
+/datum/spellbook_entry/the_traps
+ name = "The Traps!"
+ spell_type = /obj/effect/proc_holder/spell/aoe_turf/conjure/the_traps
+ category = "Defensive"
+ cost = 1
+
+
+/datum/spellbook_entry/item
+ name = "Buy Item"
+ refundable = 0
+ buy_word = "Summon"
+ var/item_path= null
+
+
+/datum/spellbook_entry/item/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
+ new item_path(get_turf(user))
+ SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
+ return 1
+
+/datum/spellbook_entry/item/GetInfo()
+ var/dat =""
+ dat += "[name]"
+ dat += " Cost:[cost] "
+ dat += "[desc] "
+ if(surplus>=0)
+ dat += "[surplus] left. "
+ return dat
+
+/datum/spellbook_entry/item/staffchange
+ name = "Staff of Change"
+ desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself."
+ item_path = /obj/item/gun/magic/staff/change
+
+/datum/spellbook_entry/item/staffanimation
+ name = "Staff of Animation"
+ desc = "An arcane staff capable of shooting bolts of eldritch energy which cause inanimate objects to come to life. This magic doesn't affect machines."
+ item_path = /obj/item/gun/magic/staff/animate
+ category = "Assistance"
+
+/datum/spellbook_entry/item/staffchaos
+ name = "Staff of Chaos"
+ desc = "A caprious tool that can fire all sorts of magic without any rhyme or reason. Using it on people you care about is not recommended."
+ item_path = /obj/item/gun/magic/staff/chaos
+
+/datum/spellbook_entry/item/spellblade
+ name = "Spellblade"
+ desc = "A sword capable of firing blasts of energy which rip targets limb from limb."
+ item_path = /obj/item/gun/magic/staff/spellblade
+
+/datum/spellbook_entry/item/staffdoor
+ name = "Staff of Door Creation"
+ desc = "A particular staff that can mold solid metal into ornate doors. Useful for getting around in the absence of other transportation. Does not work on glass."
+ item_path = /obj/item/gun/magic/staff/door
+ cost = 1
+ category = "Mobility"
+
+/datum/spellbook_entry/item/staffhealing
+ name = "Staff of Healing"
+ desc = "An altruistic staff that can heal the lame and raise the dead."
+ item_path = /obj/item/gun/magic/staff/healing
+ cost = 1
+ category = "Defensive"
+
+/datum/spellbook_entry/item/scryingorb
+ name = "Scrying Orb"
+ desc = "An incandescent orb of crackling energy, using it will allow you to ghost while alive, allowing you to spy upon the station with ease. In addition, buying it will permanently grant you x-ray vision."
+ item_path = /obj/item/scrying
+ category = "Defensive"
+
+/datum/spellbook_entry/item/soulstones
+ name = "Six Soul Stone Shards and the spell Artificer"
+ desc = "Soul Stone Shards are ancient tools capable of capturing and harnessing the spirits of the dead and dying. The spell Artificer allows you to create arcane machines for the captured souls to pilot."
+ item_path = /obj/item/storage/belt/soulstone/full
+ category = "Assistance"
+
+/datum/spellbook_entry/item/soulstones/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
+ . =..()
+ if(.)
+ user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/construct(null))
+ return .
+
+/datum/spellbook_entry/item/necrostone
+ name = "A Necromantic Stone"
+ desc = "A Necromantic stone is able to resurrect three dead individuals as skeletal thralls for you to command."
+ item_path = /obj/item/necromantic_stone
+ category = "Assistance"
+
+/datum/spellbook_entry/item/wands
+ name = "Wand Assortment"
+ desc = "A collection of wands that allow for a wide variety of utility. Wands have a limited number of charges, so be conservative in use. Comes in a handy belt."
+ item_path = /obj/item/storage/belt/wands/full
+ category = "Defensive"
+
+/datum/spellbook_entry/item/armor
+ name = "Mastercrafted Armor Set"
+ desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space."
+ item_path = /obj/item/clothing/suit/space/hardsuit/wizard
+ category = "Defensive"
+
+/datum/spellbook_entry/item/armor/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
+ . = ..()
+ if(.)
+ new /obj/item/clothing/shoes/sandal/magic(get_turf(user)) //In case they've lost them.
+ new /obj/item/clothing/gloves/color/purple(get_turf(user))//To complete the outfit
+
+/datum/spellbook_entry/item/contract
+ name = "Contract of Apprenticeship"
+ desc = "A magical contract binding an apprentice wizard to your service, using it will summon them to your side."
+ item_path = /obj/item/antag_spawner/contract
+ category = "Assistance"
+
+/datum/spellbook_entry/item/guardian
+ name = "Guardian Deck"
+ desc = "A deck of guardian tarot cards, capable of binding a personal guardian to your body. There are multiple types of guardian available, but all of them will transfer some amount of damage to you. \
+ It would be wise to avoid buying these with anything capable of causing you to swap bodies with others."
+ item_path = /obj/item/guardiancreator/choose/wizard
+ category = "Assistance"
+
+/datum/spellbook_entry/item/guardian/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
+ . = ..()
+ if(.)
+ new /obj/item/paper/guides/antag/guardian/wizard(get_turf(user))
+
+/datum/spellbook_entry/item/bloodbottle
+ name = "Bottle of Blood"
+ desc = "A bottle of magically infused blood, the smell of which will attract extradimensional beings when broken. Be careful though, the kinds of creatures summoned by blood magic are indiscriminate in their killing, and you yourself may become a victim."
+ item_path = /obj/item/antag_spawner/slaughter_demon
+ limit = 3
+ category = "Assistance"
+
+/datum/spellbook_entry/item/hugbottle
+ name = "Bottle of Tickles"
+ desc = "A bottle of magically infused fun, the smell of which will \
+ attract adorable extradimensional beings when broken. These beings \
+ are similar to slaughter demons, but they do not permamently kill \
+ their victims, instead putting them in an extradimensional hugspace, \
+ to be released on the demon's death. Chaotic, but not ultimately \
+ damaging. The crew's reaction to the other hand could be very \
+ destructive."
+ item_path = /obj/item/antag_spawner/slaughter_demon/laughter
+ cost = 1 //non-destructive; it's just a jape, sibling!
+ limit = 3
+ category = "Assistance"
+
+/datum/spellbook_entry/item/mjolnir
+ name = "Mjolnir"
+ desc = "A mighty hammer on loan from Thor, God of Thunder. It crackles with barely contained power."
+ item_path = /obj/item/twohanded/mjollnir
+
+/datum/spellbook_entry/item/singularity_hammer
+ name = "Singularity Hammer"
+ desc = "A hammer that creates an intensely powerful field of gravity where it strikes, pulling everything nearby to the point of impact."
+ item_path = /obj/item/twohanded/singularityhammer
+
+/datum/spellbook_entry/item/battlemage
+ name = "Battlemage Armour"
+ desc = "An ensorcelled suit of armour, protected by a powerful shield. The shield can completly negate sixteen attacks before being permanently depleted."
+ item_path = /obj/item/clothing/suit/space/hardsuit/shielded/wizard
+ limit = 1
+ category = "Defensive"
+
+/datum/spellbook_entry/item/battlemage_charge
+ name = "Battlemage Armour Charges"
+ desc = "A powerful defensive rune, it will grant eight additional charges to a suit of battlemage armour."
+ item_path = /obj/item/wizard_armour_charge
+ category = "Defensive"
+ cost = 1
+
+/datum/spellbook_entry/item/warpwhistle
+ name = "Warp Whistle"
+ desc = "A strange whistle that will transport you to a distant safe place on the station. There is a window of vulnerability at the beginning of every use."
+ item_path = /obj/item/warpwhistle
+ category = "Mobility"
+ cost = 1
+
+/datum/spellbook_entry/summon
+ name = "Summon Stuff"
+ category = "Rituals"
+ refundable = 0
+ buy_word = "Cast"
+ var/active = 0
+
+/datum/spellbook_entry/summon/CanBuy(mob/living/carbon/human/user,obj/item/spellbook/book)
+ return ..() && !active
+
+/datum/spellbook_entry/summon/GetInfo()
+ var/dat =""
+ dat += "[name]"
+ if(cost>0)
+ dat += " Cost:[cost] "
+ else
+ dat += " No Cost "
+ dat += "[desc] "
+ if(active)
+ dat += "Already cast! "
+ return dat
+
+/datum/spellbook_entry/summon/ghosts
+ name = "Summon Ghosts"
+ desc = "Spook the crew out by making them see dead people. Be warned, ghosts are capricious and occasionally vindicative, and some will use their incredibly minor abilties to frustrate you."
+ cost = 0
+
+/datum/spellbook_entry/summon/ghosts/IsAvailible()
+ if(!SSticker.mode)
+ return FALSE
+ else
+ return TRUE
+
+/datum/spellbook_entry/summon/ghosts/Buy(mob/living/carbon/human/user, obj/item/spellbook/book)
+ SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
+ new /datum/round_event/wizard/ghost()
+ active = TRUE
+ to_chat(user, "You have cast summon ghosts!")
+ playsound(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
+ return TRUE
+
+/datum/spellbook_entry/summon/guns
+ name = "Summon Guns"
+ desc = "Nothing could possibly go wrong with arming a crew of lunatics just itching for an excuse to kill you. Just be careful not to stand still too long!"
+
+/datum/spellbook_entry/summon/guns/IsAvailible()
+ if(!SSticker.mode) // In case spellbook is placed on map
+ return 0
+ return !CONFIG_GET(flag/no_summon_guns)
+
+/datum/spellbook_entry/summon/guns/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
+ SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
+ rightandwrong(SUMMON_GUNS, user, 25)
+ active = 1
+ playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1)
+ to_chat(user, "You have cast summon guns!")
+ return 1
+
+/datum/spellbook_entry/summon/magic
+ name = "Summon Magic"
+ desc = "Share the wonders of magic with the crew and show them why they aren't to be trusted with it at the same time."
+
+/datum/spellbook_entry/summon/magic/IsAvailible()
+ if(!SSticker.mode) // In case spellbook is placed on map
+ return 0
+ return !CONFIG_GET(flag/no_summon_magic)
+
+/datum/spellbook_entry/summon/magic/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
+ SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
+ rightandwrong(SUMMON_MAGIC, user, 25)
+ active = 1
+ playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1)
+ to_chat(user, "You have cast summon magic!")
+ return 1
+
+/datum/spellbook_entry/summon/events
+ name = "Summon Events"
+ desc = "Give Murphy's law a little push and replace all events with special wizard ones that will confound and confuse everyone. Multiple castings increase the rate of these events."
+ var/times = 0
+
+/datum/spellbook_entry/summon/events/IsAvailible()
+ if(!SSticker.mode) // In case spellbook is placed on map
+ return 0
+ return !CONFIG_GET(flag/no_summon_events)
+
+/datum/spellbook_entry/summon/events/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
+ SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
+ summonevents()
+ times++
+ playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1)
+ to_chat(user, "You have cast summon events.")
+ return 1
+
+/datum/spellbook_entry/summon/events/GetInfo()
+ . = ..()
+ if(times>0)
+ . += "You cast it [times] times. "
+ return .
+
+/obj/item/spellbook
+ name = "spell book"
+ desc = "An unearthly tome that glows with power."
+ icon = 'icons/obj/library.dmi'
+ icon_state ="book"
+ throw_speed = 2
+ throw_range = 5
+ w_class = WEIGHT_CLASS_TINY
+ var/uses = 10
+ var/temp = null
+ var/tab = null
+ var/mob/living/carbon/human/owner
+ var/list/datum/spellbook_entry/entries = list()
+ var/list/categories = list()
+
+/obj/item/spellbook/examine(mob/user)
+ ..()
+ if(owner)
+ to_chat(user, "There is a small signature on the front cover: \"[owner]\".")
+ else
+ to_chat(user, "It appears to have no author.")
+
+/obj/item/spellbook/Initialize()
+ . = ..()
+ prepare_spells()
+
+/obj/item/spellbook/proc/prepare_spells()
+ var/entry_types = subtypesof(/datum/spellbook_entry) - /datum/spellbook_entry/item - /datum/spellbook_entry/summon
+ for(var/T in entry_types)
+ var/datum/spellbook_entry/E = new T
+ if(E.IsAvailible())
+ entries |= E
+ categories |= E.category
+ else
+ qdel(E)
+ tab = categories[1]
+
+/obj/item/spellbook/attackby(obj/item/O, mob/user, params)
+ if(istype(O, /obj/item/antag_spawner/contract))
+ var/obj/item/antag_spawner/contract/contract = O
+ if(contract.used)
+ to_chat(user, "The contract has been used, you can't get your points back now!")
+ else
+ to_chat(user, "You feed the contract back into the spellbook, refunding your points.")
+ uses++
+ for(var/datum/spellbook_entry/item/contract/CT in entries)
+ if(!isnull(CT.limit))
+ CT.limit++
+ qdel(O)
+ else if(istype(O, /obj/item/antag_spawner/slaughter_demon))
+ to_chat(user, "On second thought, maybe summoning a demon is a bad idea. You refund your points.")
+ uses++
+ for(var/datum/spellbook_entry/item/bloodbottle/BB in entries)
+ if(!isnull(BB.limit))
+ BB.limit++
+ qdel(O)
+
+/obj/item/spellbook/proc/GetCategoryHeader(category)
+ var/dat = ""
+ switch(category)
+ if("Offensive")
+ dat += "Spells and items geared towards debilitating and destroying.
"
+ dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased. "
+ dat += "For spells: the number after the spell name is the cooldown time. "
+ dat += "You can reduce this number by spending more points on the spell. "
+ if("Defensive")
+ dat += "Spells and items geared towards improving your survivabilty or reducing foes' ability to attack.
"
+ dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased. "
+ dat += "For spells: the number after the spell name is the cooldown time. "
+ dat += "You can reduce this number by spending more points on the spell. "
+ if("Mobility")
+ dat += "Spells and items geared towards improving your ability to move. It is a good idea to take at least one.
"
+ dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased. "
+ dat += "For spells: the number after the spell name is the cooldown time. "
+ dat += "You can reduce this number by spending more points on the spell. "
+ if("Assistance")
+ dat += "Spells and items geared towards bringing in outside forces to aid you or improving upon your other items and abilties.
"
+ dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased. "
+ dat += "For spells: the number after the spell name is the cooldown time. "
+ dat += "You can reduce this number by spending more points on the spell. "
+ if("Challenges")
+ dat += "The Wizard Federation typically has hard limits on the potency and number of spells brought to the station based on risk. "
+ dat += "Arming the station against you will increases the risk, but will grant you one more charge for your spellbook. "
+ if("Rituals")
+ dat += "These powerful spells change the very fabric of reality. Not always in your favour. "
+ return dat
+
+/obj/item/spellbook/proc/wrap(content)
+ var/dat = ""
+ dat +="Spellbook"
+ dat += {"
+
+
+
+ "}
+ dat += {"[content]"}
+ return dat
+
+/obj/item/spellbook/attack_self(mob/user)
+ if(!owner)
+ to_chat(user, "You bind the spellbook to yourself.")
+ owner = user
+ return
+ if(user != owner)
+ to_chat(user, "The [name] does not recognize you as its owner and refuses to open!")
+ return
+ user.set_machine(src)
+ var/dat = ""
+
+ dat += "
"
+ var/list/cat_dat = list()
+ for(var/category in categories)
+ cat_dat[category] = ""
+ dat += "
Close"
@@ -95,7 +105,7 @@
/obj/item/assembly/timer/Topic(href, href_list)
..()
- if(usr.incapacitated() || !in_range(loc, usr))
+ if(!usr.canUseTopic(src, BE_CLOSE))
usr << browse(null, "window=timer")
onclose(usr, "timer")
return
diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm
index 71f51aaaf9..ca97752d90 100644
--- a/code/modules/assembly/voice.dm
+++ b/code/modules/assembly/voice.dm
@@ -1,14 +1,19 @@
+#define INCLUSIVE_MODE 1
+#define EXCLUSIVE_MODE 2
+#define RECOGNIZER_MODE 3
+#define VOICE_SENSOR_MODE 4
+
/obj/item/assembly/voice
name = "voice analyzer"
desc = "A small electronic device able to record a voice sample, and send a signal when that sample is repeated."
icon_state = "voice"
materials = list(MAT_METAL=500, MAT_GLASS=50)
flags_1 = HEAR_1
- attachable = 1
+ attachable = TRUE
verb_say = "beeps"
verb_ask = "beeps"
verb_exclaim = "beeps"
- var/listening = 0
+ var/listening = FALSE
var/recorded = "" //the activation message
var/mode = 1
var/static/list/modes = list("inclusive",
@@ -32,60 +37,64 @@
/obj/item/assembly/voice/proc/record_speech(atom/movable/speaker, raw_message, datum/language/message_language)
switch(mode)
- if(1)
+ if(INCLUSIVE_MODE)
recorded = raw_message
- listening = 0
+ listening = FALSE
say("Activation message is '[recorded]'.", message_language)
- if(2)
+ if(EXCLUSIVE_MODE)
recorded = raw_message
- listening = 0
+ listening = FALSE
say("Activation message is '[recorded]'.", message_language)
- if(3)
+ if(RECOGNIZER_MODE)
recorded = speaker.GetVoice()
- listening = 0
+ listening = FALSE
say("Your voice pattern is saved.", message_language)
- if(4)
+ if(VOICE_SENSOR_MODE)
if(length(raw_message))
addtimer(CALLBACK(src, .proc/pulse, 0), 10)
/obj/item/assembly/voice/proc/check_activation(atom/movable/speaker, raw_message)
- . = 0
+ . = FALSE
switch(mode)
- if(1)
+ if(INCLUSIVE_MODE)
if(findtext(raw_message, recorded))
- . = 1
- if(2)
+ . = TRUE
+ if(EXCLUSIVE_MODE)
if(raw_message == recorded)
- . = 1
- if(3)
+ . = TRUE
+ if(RECOGNIZER_MODE)
if(speaker.GetVoice() == recorded)
- . = 1
- if(4)
+ . = TRUE
+ if(VOICE_SENSOR_MODE)
if(length(raw_message))
- . = 1
+ . = TRUE
-/obj/item/assembly/voice/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/multitool))
- mode %= modes.len
- mode++
- to_chat(user, "You set [src] into a [modes[mode]] mode.")
- listening = 0
- recorded = ""
- else
- return ..()
+/obj/item/assembly/voice/multitool_act(mob/living/user, obj/item/I)
+ mode %= modes.len
+ mode++
+ to_chat(user, "You set [src] into [modes[mode]] mode.")
+ listening = FALSE
+ recorded = ""
+ return TRUE
/obj/item/assembly/voice/activate()
- if(secured)
- if(!holder)
- listening = !listening
- say("[listening ? "Now" : "No longer"] recording input.")
+ if(!secured || holder)
+ return FALSE
+ listening = !listening
+ say("[listening ? "Now" : "No longer"] recording input.")
+ return TRUE
/obj/item/assembly/voice/attack_self(mob/user)
if(!user)
- return 0
+ return FALSE
activate()
- return 1
+ return TRUE
/obj/item/assembly/voice/toggle_secure()
. = ..()
- listening = 0
+ listening = FALSE
+
+#undef INCLUSIVE_MODE
+#undef EXCLUSIVE_MODE
+#undef RECOGNIZER_MODE
+#undef VOICE_SENSOR_MODE
diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm
index c58d14f4d4..a3c9c68d55 100644
--- a/code/modules/atmospherics/environmental/LINDA_fire.dm
+++ b/code/modules/atmospherics/environmental/LINDA_fire.dm
@@ -94,7 +94,7 @@
for(var/A in location)
var/atom/AT = A
- if(AT && AT != src) // It's possible that the item is deleted in temperature_expose
+ if(!QDELETED(AT) && AT != src) // It's possible that the item is deleted in temperature_expose
AT.fire_act(temperature, volume)
return
diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
index 75b744e597..6e78256c87 100644
--- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
@@ -4,11 +4,11 @@ What are the archived variables for?
This prevents race conditions that arise based on the order of tile processing.
*/
#define MINIMUM_HEAT_CAPACITY 0.0003
+#define MINIMUM_MOLE_COUNT 0.01
#define QUANTIZE(variable) (round(variable,0.0000001))/*I feel the need to document what happens here. Basically this is used to catch most rounding errors, however it's previous value made it so that
once gases got hot enough, most procedures wouldnt occur due to the fact that the mole counts would get rounded away. Thus, we lowered it a few orders of magnititude */
GLOBAL_LIST_INIT(meta_gas_info, meta_gas_list()) //see ATMOSPHERICS/gas_types.dm
GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
-GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide))) // These gasses cannot react amongst themselves
/proc/init_gaslist_cache()
. = list()
diff --git a/code/modules/atmospherics/gasmixtures/gas_types.dm b/code/modules/atmospherics/gasmixtures/gas_types.dm
index 0f1a21e1ce..12ad70a9e3 100644
--- a/code/modules/atmospherics/gasmixtures/gas_types.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_types.dm
@@ -1,4 +1,5 @@
GLOBAL_LIST_INIT(hardcoded_gases, list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, /datum/gas/plasma)) //the main four gases, which were at one time hardcoded
+GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, /datum/gas/pluoxium, /datum/gas/stimulum, /datum/gas/nitryl))) //unable to react amongst themselves
/proc/meta_gas_list()
. = subtypesof(/datum/gas)
@@ -124,6 +125,7 @@ GLOBAL_LIST_INIT(hardcoded_gases, list(/datum/gas/oxygen, /datum/gas/nitrogen, /
specific_heat = 80
name = "Pluoxium"
fusion_power = 10
+
/obj/effect/overlay/gas
icon = 'icons/effects/tile_effects.dmi'
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index 689abbc388..dd953dcb11 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -1,10 +1,8 @@
//Plasma fire properties
#define OXYGEN_BURN_RATE_BASE 1.4
#define PLASMA_BURN_RATE_DELTA 9
-#define PLASMA_UPPER_TEMPERATURE (1370+T0C)
#define PLASMA_MINIMUM_OXYGEN_NEEDED 2
#define PLASMA_MINIMUM_OXYGEN_PLASMA_RATIO 30
-#define PLASMA_OXYGEN_FULLBURN 10
#define FIRE_CARBON_ENERGY_RELEASED 100000 //Amount of heat released per mole of burnt carbon into the tile
#define FIRE_HYDROGEN_ENERGY_RELEASED 280000 // Amount of heat released per mole of burnt hydrogen and/or tritium(hydrogen isotope)
#define FIRE_PLASMA_ENERGY_RELEASED 3000000 //Amount of heat released per mole of burnt plasma into the tile
@@ -30,7 +28,6 @@
#define FUSION_PURITY_THRESHOLD 0.95
#define FUSION_HEAT_DROPOFF (20000+T0C)
#define NOBLIUM_FORMATION_ENERGY 2e9 //1 Mole of Noblium takes the planck energy to condense.
-/datum/controller/subsystem/air/var/list/gas_reactions //this is our singleton of all reactions
/proc/init_gas_reactions()
var/list/reaction_types = list()
@@ -49,7 +46,7 @@
/datum/gas_reaction
//regarding the requirements lists: the minimum or maximum requirements must be non-zero.
- //when in doubt, use MINIMUM_HEAT_CAPACITY.
+ //when in doubt, use MINIMUM_MOLE_COUNT.
var/list/min_requirements
var/list/max_requirements
var/exclude = FALSE //do it this way to allow for addition/removal of reactions midmatch in the future
@@ -61,6 +58,7 @@
init_reqs()
/datum/gas_reaction/proc/init_reqs()
+
/datum/gas_reaction/proc/react(datum/gas_mixture/air, atom/location)
return NO_REACTION
@@ -94,16 +92,20 @@
air.gases[/datum/gas/water_vapor][MOLES] -= MOLES_GAS_VISIBLE
. = REACTING
-//fire: combustion of plasma and volatile fuel (treated as hydrocarbons). creates hotspots. exothermic
-/datum/gas_reaction/fire
- priority = -1 //fire should ALWAYS be last
- name = "Hydrocarbon Combustion"
- id = "fire"
+//tritium combustion: combustion of oxygen and tritium (treated as hydrocarbons). creates hotspots. exothermic
+/datum/gas_reaction/tritfire
+ priority = -1 //fire should ALWAYS be last, but tritium fires happen before plasma fires
+ name = "Tritium Combustion"
+ id = "tritfire"
-/datum/gas_reaction/fire/init_reqs()
- min_requirements = list("TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST) //doesn't include plasma reqs b/c of other, rarer, burning gases.
+/datum/gas_reaction/tritfire/init_reqs()
+ min_requirements = list(
+ "TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST,
+ /datum/gas/tritium = MINIMUM_MOLE_COUNT,
+ /datum/gas/oxygen = MINIMUM_MOLE_COUNT
+ )
-/datum/gas_reaction/fire/react(datum/gas_mixture/air, datum/holder)
+/datum/gas_reaction/tritfire/react(datum/gas_mixture/air, datum/holder)
var/energy_released = 0
var/old_heat_capacity = air.heat_capacity()
var/list/cached_gases = air.gases //this speeds things up because accessing datum vars is slow
@@ -112,65 +114,99 @@
cached_results[id] = 0
var/turf/open/location = isturf(holder) ? holder : null
- //General volatile gas burn
- if(cached_gases[/datum/gas/tritium] && cached_gases[/datum/gas/tritium][MOLES])
- var/burned_fuel
- if(!cached_gases[/datum/gas/oxygen])
- burned_fuel = 0
- else if(cached_gases[/datum/gas/oxygen][MOLES] < cached_gases[/datum/gas/tritium][MOLES])
- burned_fuel = cached_gases[/datum/gas/oxygen][MOLES]/TRITIUM_BURN_OXY_FACTOR
- cached_gases[/datum/gas/tritium][MOLES] -= burned_fuel
- else
- burned_fuel = cached_gases[/datum/gas/tritium][MOLES]*TRITIUM_BURN_TRIT_FACTOR
- cached_gases[/datum/gas/tritium][MOLES] -= cached_gases[/datum/gas/tritium][MOLES]/TRITIUM_BURN_TRIT_FACTOR
- cached_gases[/datum/gas/oxygen][MOLES] -= cached_gases[/datum/gas/tritium][MOLES]
+ var/burned_fuel = 0
+ if(cached_gases[/datum/gas/oxygen][MOLES] < cached_gases[/datum/gas/tritium][MOLES])
+ burned_fuel = cached_gases[/datum/gas/oxygen][MOLES]/TRITIUM_BURN_OXY_FACTOR
+ cached_gases[/datum/gas/tritium][MOLES] -= burned_fuel
+ else
+ burned_fuel = cached_gases[/datum/gas/tritium][MOLES]*TRITIUM_BURN_TRIT_FACTOR
+ cached_gases[/datum/gas/tritium][MOLES] -= cached_gases[/datum/gas/tritium][MOLES]/TRITIUM_BURN_TRIT_FACTOR
+ cached_gases[/datum/gas/oxygen][MOLES] -= cached_gases[/datum/gas/tritium][MOLES]
- if(burned_fuel)
- energy_released += FIRE_HYDROGEN_ENERGY_RELEASED * burned_fuel
- if(location && prob(10) && burned_fuel > TRITIUM_MINIMUM_RADIATION_ENERGY) //woah there let's not crash the server
- radiation_pulse(location, energy_released/TRITIUM_BURN_RADIOACTIVITY_FACTOR)
+ if(burned_fuel)
+ energy_released += FIRE_HYDROGEN_ENERGY_RELEASED * burned_fuel
+ if(location && prob(10) && burned_fuel > TRITIUM_MINIMUM_RADIATION_ENERGY) //woah there let's not crash the server
+ radiation_pulse(location, energy_released/TRITIUM_BURN_RADIOACTIVITY_FACTOR)
- ASSERT_GAS(/datum/gas/water_vapor, air) //oxygen+more-or-less hydrogen=H2O
- cached_gases[/datum/gas/water_vapor][MOLES] += burned_fuel/TRITIUM_BURN_OXY_FACTOR
+ ASSERT_GAS(/datum/gas/water_vapor, air) //oxygen+more-or-less hydrogen=H2O
+ cached_gases[/datum/gas/water_vapor][MOLES] += burned_fuel/TRITIUM_BURN_OXY_FACTOR
- cached_results[id] += burned_fuel
+ cached_results[id] += burned_fuel
+
+ if(energy_released > 0)
+ var/new_heat_capacity = air.heat_capacity()
+ if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
+ air.temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity
+
+ //let the floor know a fire is happening
+ if(istype(location))
+ temperature = air.temperature
+ if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
+ location.hotspot_expose(temperature, CELL_VOLUME)
+ for(var/I in location)
+ var/atom/movable/item = I
+ item.temperature_expose(air, temperature, CELL_VOLUME)
+ location.temperature_expose(air, temperature, CELL_VOLUME)
+
+ return cached_results[id] ? REACTING : NO_REACTION
+
+//plasma combustion: combustion of oxygen and plasma (treated as hydrocarbons). creates hotspots. exothermic
+/datum/gas_reaction/plasmafire
+ priority = -2 //fire should ALWAYS be last, but plasma fires happen after tritium fires
+ name = "Plasma Combustion"
+ id = "plasmafire"
+
+/datum/gas_reaction/plasmafire/init_reqs()
+ min_requirements = list(
+ "TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST,
+ /datum/gas/plasma = MINIMUM_MOLE_COUNT,
+ /datum/gas/oxygen = MINIMUM_MOLE_COUNT
+ )
+
+/datum/gas_reaction/plasmafire/react(datum/gas_mixture/air, datum/holder)
+ var/energy_released = 0
+ var/old_heat_capacity = air.heat_capacity()
+ var/list/cached_gases = air.gases //this speeds things up because accessing datum vars is slow
+ var/temperature = air.temperature
+ var/list/cached_results = air.reaction_results
+ cached_results[id] = 0
+ var/turf/open/location = isturf(holder) ? holder : null
//Handle plasma burning
- if(cached_gases[/datum/gas/plasma] && cached_gases[/datum/gas/plasma][MOLES] > MINIMUM_HEAT_CAPACITY)
- var/plasma_burn_rate = 0
- var/oxygen_burn_rate = 0
- //more plasma released at higher temperatures
- var/temperature_scale
- var/super_saturation
- if(temperature > PLASMA_UPPER_TEMPERATURE)
- temperature_scale = 1
+ var/plasma_burn_rate = 0
+ var/oxygen_burn_rate = 0
+ //more plasma released at higher temperatures
+ var/temperature_scale = 0
+ //to make tritium
+ var/super_saturation = FALSE
+
+ if(temperature > PLASMA_UPPER_TEMPERATURE)
+ temperature_scale = 1
+ else
+ temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
+ if(temperature_scale > 0)
+ oxygen_burn_rate = OXYGEN_BURN_RATE_BASE - temperature_scale
+ if(cached_gases[/datum/gas/oxygen][MOLES] / cached_gases[/datum/gas/plasma][MOLES] > SUPER_SATURATION_THRESHOLD) //supersaturation. Form Tritium.
+ super_saturation = TRUE
+ if(cached_gases[/datum/gas/oxygen][MOLES] > cached_gases[/datum/gas/plasma][MOLES]*PLASMA_OXYGEN_FULLBURN)
+ plasma_burn_rate = (cached_gases[/datum/gas/plasma][MOLES]*temperature_scale)/PLASMA_BURN_RATE_DELTA
else
- temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
- if(temperature_scale > 0)
- var/o2 = cached_gases[/datum/gas/oxygen] ? cached_gases[/datum/gas/oxygen][MOLES] : 0
- oxygen_burn_rate = OXYGEN_BURN_RATE_BASE - temperature_scale
- if(o2 / cached_gases[/datum/gas/plasma][MOLES] > SUPER_SATURATION_THRESHOLD) //supersaturation. Form Tritium.
- super_saturation = TRUE
- if(o2 > cached_gases[/datum/gas/plasma][MOLES]*PLASMA_OXYGEN_FULLBURN)
- plasma_burn_rate = (cached_gases[/datum/gas/plasma][MOLES]*temperature_scale)/PLASMA_BURN_RATE_DELTA
+ plasma_burn_rate = (temperature_scale*(cached_gases[/datum/gas/oxygen][MOLES]/PLASMA_OXYGEN_FULLBURN))/PLASMA_BURN_RATE_DELTA
+
+ if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
+ plasma_burn_rate = min(plasma_burn_rate,cached_gases[/datum/gas/plasma][MOLES],cached_gases[/datum/gas/oxygen][MOLES]/oxygen_burn_rate) //Ensures matter is conserved properly
+ cached_gases[/datum/gas/plasma][MOLES] = QUANTIZE(cached_gases[/datum/gas/plasma][MOLES] - plasma_burn_rate)
+ cached_gases[/datum/gas/oxygen][MOLES] = QUANTIZE(cached_gases[/datum/gas/oxygen][MOLES] - (plasma_burn_rate * oxygen_burn_rate))
+ if (super_saturation)
+ ASSERT_GAS(/datum/gas/tritium,air)
+ cached_gases[/datum/gas/tritium][MOLES] += plasma_burn_rate
else
- plasma_burn_rate = (temperature_scale*(o2/PLASMA_OXYGEN_FULLBURN))/PLASMA_BURN_RATE_DELTA
+ ASSERT_GAS(/datum/gas/carbon_dioxide,air)
+ cached_gases[/datum/gas/carbon_dioxide][MOLES] += plasma_burn_rate
- if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
- ASSERT_GAS(/datum/gas/carbon_dioxide, air) //don't need to assert o2, since if it isn't present we'll never reach this point anyway
- plasma_burn_rate = min(plasma_burn_rate,cached_gases[/datum/gas/plasma][MOLES],cached_gases[/datum/gas/oxygen][MOLES]/oxygen_burn_rate) //Ensures matter is conserved properly
- cached_gases[/datum/gas/plasma][MOLES] = QUANTIZE(cached_gases[/datum/gas/plasma][MOLES] - plasma_burn_rate)
- cached_gases[/datum/gas/oxygen][MOLES] = QUANTIZE(cached_gases[/datum/gas/oxygen][MOLES] - (plasma_burn_rate * oxygen_burn_rate))
- if (super_saturation)
- ASSERT_GAS(/datum/gas/tritium,air)
- cached_gases[/datum/gas/tritium][MOLES] += plasma_burn_rate
- else
- ASSERT_GAS(/datum/gas/carbon_dioxide,air)
- cached_gases[/datum/gas/carbon_dioxide][MOLES] += plasma_burn_rate
+ energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
- energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
-
- cached_results[id] += (plasma_burn_rate)*(1+oxygen_burn_rate)
+ cached_results[id] += (plasma_burn_rate)*(1+oxygen_burn_rate)
if(energy_released > 0)
var/new_heat_capacity = air.heat_capacity()
@@ -191,12 +227,11 @@
//fusion: a terrible idea that was fun but broken. Now reworked to be less broken and more interesting. Again.
/datum/gas_reaction/fusion
- exclude = FALSE
+ exclude = TRUE
priority = 2
name = "Plasmic Fusion"
id = "fusion"
-
/datum/gas_reaction/fusion/init_reqs()
min_requirements = list(
"ENER" = PLASMA_BINDING_ENERGY * 1000,
@@ -361,7 +396,7 @@
air.temperature = max(((air.temperature*old_heat_capacity + stim_energy_change)/new_heat_capacity),TCMB)
return REACTING
-/datum/gas_reaction/nobliumformation //Hyper-Nobelium formation is extrememly endothermic, but requires high temperatures to start. Due to its high mass, hyper-nobelium uses large amounts of nitrogen and tritium. BZ can be used as a catalyst to make it less endothermic.
+/datum/gas_reaction/nobliumformation //Hyper-Noblium formation is extrememly endothermic, but requires high temperatures to start. Due to its high mass, hyper-nobelium uses large amounts of nitrogen and tritium. BZ can be used as a catalyst to make it less endothermic.
priority = 6
name = "Hyper-Noblium condensation"
id = "nobformation"
@@ -380,8 +415,8 @@
var/energy_taken = nob_formed*(NOBLIUM_FORMATION_ENERGY/(max(cached_gases[/datum/gas/bz][MOLES],1)))
if ((cached_gases[/datum/gas/tritium][MOLES] - 10*nob_formed < 0) || (cached_gases[/datum/gas/nitrogen][MOLES] - 20*nob_formed < 0))
return NO_REACTION
- cached_gases[/datum/gas/tritium][MOLES] = max(cached_gases[/datum/gas/tritium][MOLES]- 10*nob_formed,0)
- cached_gases[/datum/gas/nitrogen][MOLES] = max(cached_gases[/datum/gas/nitrogen][MOLES]- 20*nob_formed,0)
+ cached_gases[/datum/gas/tritium][MOLES] -= 10*nob_formed
+ cached_gases[/datum/gas/nitrogen][MOLES] -= 20*nob_formed
cached_gases[/datum/gas/hypernoblium][MOLES]+= nob_formed
@@ -392,10 +427,8 @@
#undef OXYGEN_BURN_RATE_BASE
#undef PLASMA_BURN_RATE_DELTA
-#undef PLASMA_UPPER_TEMPERATURE
#undef PLASMA_MINIMUM_OXYGEN_NEEDED
#undef PLASMA_MINIMUM_OXYGEN_PLASMA_RATIO
-#undef PLASMA_OXYGEN_FULLBURN
#undef FIRE_CARBON_ENERGY_RELEASED
#undef FIRE_PLASMA_ENERGY_RELEASED
#undef WATER_VAPOR_FREEZE
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index 381eccb3d8..7bfacbee26 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -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()
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm
index fd3d435c28..50f34e097f 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm
@@ -8,6 +8,7 @@ It's like a regular ol' straight pipe, but you can turn it on and off.
desc = "A pipe with a valve that can be used to disable flow of gas through it."
can_unwrench = TRUE
+ interaction_flags_machine = INTERACT_MACHINE_OFFLINE | INTERACT_MACHINE_OPEN //Intentionally no allow_silicon flag
var/frequency = 0
var/id = null
@@ -68,13 +69,7 @@ It's like a regular ol' straight pipe, but you can turn it on and off.
else if(dir==WEST)
setDir(EAST)
-/obj/machinery/atmospherics/components/binary/valve/attack_ai(mob/user)
- return
-
-/obj/machinery/atmospherics/components/binary/valve/attack_hand(mob/user)
- . = ..()
- if(.)
- return
+/obj/machinery/atmospherics/components/binary/valve/interact(mob/user)
add_fingerprint(usr)
update_icon_nopipes(1)
if(switching)
@@ -97,6 +92,7 @@ It's like a regular ol' straight pipe, but you can turn it on and off.
icon_state = "dvalve_map"
valve_type = "d"
pipe_state = "dvalve"
+ interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OFFLINE | INTERACT_MACHINE_OPEN | INTERACT_MACHINE_OPEN_SILICON
/obj/machinery/atmospherics/components/binary/valve/digital/layer1
piping_layer = PIPING_LAYER_MIN
@@ -108,9 +104,6 @@ It's like a regular ol' straight pipe, but you can turn it on and off.
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-/obj/machinery/atmospherics/components/binary/valve/digital/attack_ai(mob/user)
- return attack_hand(user)
-
/obj/machinery/atmospherics/components/binary/valve/digital/update_icon_nopipes(animation)
if(!is_operational())
normalize_dir()
diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm
index 28148c0364..5dcf95f3cf 100644
--- a/code/modules/atmospherics/machinery/components/components_base.dm
+++ b/code/modules/atmospherics/machinery/components/components_base.dm
@@ -34,8 +34,10 @@ Iconnery
var/turf/T = loc
if(level == 2 || !T.intact)
showpipe = TRUE
+ plane = GAME_PLANE
else
showpipe = FALSE
+ plane = FLOOR_PLANE
if(!showpipe)
return //no need to update the pipes if they aren't showing
diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm
index 8e602577ac..09504c60b7 100644
--- a/code/modules/awaymissions/capture_the_flag.dm
+++ b/code/modules/awaymissions/capture_the_flag.dm
@@ -24,7 +24,7 @@
armour_penetration = 1000
resistance_flags = INDESTRUCTIBLE
anchored = TRUE
- flags_2 = SLOWS_WHILE_IN_HAND_2
+ item_flags = SLOWS_WHILE_IN_HAND
var/team = WHITE_TEAM
var/reset_cooldown = 0
var/anyonecanpickup = TRUE
@@ -496,10 +496,10 @@
W.update_label(W.registered_name, W.assignment)
// The shielded hardsuit is already NODROP_1
- no_drops += H.get_item_by_slot(slot_gloves)
- no_drops += H.get_item_by_slot(slot_shoes)
- no_drops += H.get_item_by_slot(slot_w_uniform)
- no_drops += H.get_item_by_slot(slot_ears)
+ no_drops += H.get_item_by_slot(SLOT_GLOVES)
+ no_drops += H.get_item_by_slot(SLOT_SHOES)
+ no_drops += H.get_item_by_slot(SLOT_W_UNIFORM)
+ no_drops += H.get_item_by_slot(SLOT_EARS)
for(var/i in no_drops)
var/obj/item/I = i
I.flags_1 |= NODROP_1
diff --git a/code/modules/cargo/exports.dm b/code/modules/cargo/exports.dm
index b4c0aa350d..702abf2a12 100644
--- a/code/modules/cargo/exports.dm
+++ b/code/modules/cargo/exports.dm
@@ -115,7 +115,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they
return FALSE
if(!get_cost(O, contr, emag))
return FALSE
- if(O.flags_2 & HOLOGRAM_2)
+ if(O.flags_1 & HOLOGRAM_1)
return FALSE
return TRUE
diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm
index 37afb31a6b..9eec36f53a 100644
--- a/code/modules/cargo/exports/large_objects.dm
+++ b/code/modules/cargo/exports/large_objects.dm
@@ -101,7 +101,7 @@
export_types = list(/obj/machinery/iv_drip)
/datum/export/large/barrier
- cost = 325
+ cost = 100
unit_name = "security barrier"
export_types = list(/obj/item/grenade/barrier, /obj/structure/barricade/security)
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index a961e87c48..2d3ed07505 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -1649,8 +1649,9 @@
. = ..()
if(prob(50))
var/mob/living/simple_animal/pet/dog/corgi/D = locate() in .
- qdel(D)
- new /mob/living/simple_animal/pet/dog/corgi/Lisa(.)
+ if(D.gender == FEMALE)
+ qdel(D)
+ new /mob/living/simple_animal/pet/dog/corgi/Lisa(.)
/datum/supply_pack/critter/cow
name = "Cow Crate"
diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm
index c821204993..28a3ec23b9 100644
--- a/code/modules/client/asset_cache.dm
+++ b/code/modules/client/asset_cache.dm
@@ -157,12 +157,14 @@ GLOBAL_LIST_EMPTY(asset_datums)
//get an assetdatum or make a new one
/proc/get_asset_datum(var/type)
- if (!(type in GLOB.asset_datums))
- return new type()
- return GLOB.asset_datums[type]
+ return GLOB.asset_datums[type] || new type()
+
+/datum/asset
+ var/_abstract = /datum/asset
/datum/asset/New()
GLOB.asset_datums[type] = src
+ register()
/datum/asset/proc/register()
return
@@ -170,20 +172,173 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/proc/send(client)
return
+
//If you don't need anything complicated.
/datum/asset/simple
+ _abstract = /datum/asset/simple
var/assets = list()
var/verify = FALSE
/datum/asset/simple/register()
for(var/asset_name in assets)
register_asset(asset_name, assets[asset_name])
+
/datum/asset/simple/send(client)
send_asset_list(client,assets,verify)
+// For registering or sending multiple others at once
+/datum/asset/group
+ _abstract = /datum/asset/group
+ var/list/children
+
+/datum/asset/group/register()
+ for(var/type in children)
+ get_asset_datum(type)
+
+/datum/asset/group/send(client/C)
+ for(var/type in children)
+ var/datum/asset/A = get_asset_datum(type)
+ A.send(C)
+
+
+// spritesheet implementation - coalesces various icons into a single .png file
+// and uses CSS to select icons out of that file - saves on transferring some
+// 1400-odd individual PNG files
+#define SPR_SIZE 1
+#define SPR_IDX 2
+#define SPRSZ_COUNT 1
+#define SPRSZ_ICON 2
+#define SPRSZ_STRIPPED 3
+
+/datum/asset/spritesheet
+ _abstract = /datum/asset/spritesheet
+ var/name
+ var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
+ var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
+ var/verify = FALSE
+
+/datum/asset/spritesheet/register()
+ if (!name)
+ CRASH("spritesheet [type] cannot register without a name")
+ ensure_stripped()
+
+ var/res_name = "spritesheet_[name].css"
+ var/fname = "data/spritesheets/[res_name]"
+ call("rust_g", "file_write")(generate_css(), fname)
+ register_asset(res_name, file(fname))
+
+ for(var/size_id in sizes)
+ var/size = sizes[size_id]
+ register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
+
+/datum/asset/spritesheet/send(client/C)
+ if (!name)
+ return
+ var/all = list("spritesheet_[name].css")
+ for(var/size_id in sizes)
+ all += "[name]_[size_id].png"
+ send_asset_list(C, all, verify)
+
+/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
+ for(var/size_id in sizes_to_strip)
+ var/size = sizes[size_id]
+ if (size[SPRSZ_STRIPPED])
+ continue
+
+ // save flattened version
+ var/fname = "data/spritesheets/[name]_[size_id].png"
+ fcopy(size[SPRSZ_ICON], fname)
+ var/error = call("rust_g", "dmi_strip_metadata")(fname)
+ if(length(error))
+ stack_trace("Failed to strip [name]_[size_id].png: [error]")
+ size[SPRSZ_STRIPPED] = icon(fname)
+
+/datum/asset/spritesheet/proc/generate_css()
+ var/list/out = list()
+
+ for (var/size_id in sizes)
+ var/size = sizes[size_id]
+ var/icon/tiny = size[SPRSZ_ICON]
+ out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}"
+
+ for (var/sprite_id in sprites)
+ var/sprite = sprites[sprite_id]
+ var/size_id = sprite[SPR_SIZE]
+ var/idx = sprite[SPR_IDX]
+ var/size = sizes[size_id]
+
+ var/icon/tiny = size[SPRSZ_ICON]
+ var/icon/big = size[SPRSZ_STRIPPED]
+ var/per_line = big.Width() / tiny.Width()
+ var/x = (idx % per_line) * tiny.Width()
+ var/y = round(idx / per_line) * tiny.Height()
+
+ out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
+
+ return out.Join("\n")
+
+/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
+ I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
+ if (!I || !length(icon_states(I))) // that direction or state doesn't exist
+ return
+ var/size_id = "[I.Width()]x[I.Height()]"
+ var/size = sizes[size_id]
+
+ if (sprites[sprite_name])
+ CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
+
+ if (size)
+ var/position = size[SPRSZ_COUNT]++
+ var/icon/sheet = size[SPRSZ_ICON]
+ size[SPRSZ_STRIPPED] = null
+ sheet.Insert(I, icon_state=sprite_name)
+ sprites[sprite_name] = list(size_id, position)
+ else
+ sizes[size_id] = size = list(1, I, null)
+ sprites[sprite_name] = list(size_id, 0)
+
+/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
+ if (length(prefix))
+ prefix = "[prefix]-"
+
+ if (!directions)
+ directions = list(SOUTH)
+
+ for (var/icon_state_name in icon_states(I))
+ for (var/direction in directions)
+ var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
+ Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
+
+/datum/asset/spritesheet/proc/css_tag()
+ return {""}
+
+/datum/asset/spritesheet/proc/icon_tag(sprite_name)
+ var/sprite = sprites[sprite_name]
+ if (!sprite)
+ return null
+ var/size_id = sprite[SPR_SIZE]
+ return {""}
+
+#undef SPR_SIZE
+#undef SPR_IDX
+#undef SPRSZ_COUNT
+#undef SPRSZ_ICON
+#undef SPRSZ_STRIPPED
+
+
+/datum/asset/spritesheet/simple
+ _abstract = /datum/asset/spritesheet/simple
+ var/list/assets
+
+/datum/asset/spritesheet/simple/register()
+ for (var/key in assets)
+ Insert(key, assets[key])
+ ..()
+
//Generates assets based on iconstates of a single icon
/datum/asset/simple/icon_states
+ _abstract = /datum/asset/simple/icon_states
var/icon
var/list/directions = list(SOUTH)
var/frame = 1
@@ -209,6 +364,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
register_asset(asset_name, asset)
/datum/asset/simple/icon_states/multiple_icons
+ _abstract = /datum/asset/simple/icon_states/multiple_icons
var/list/icons
/datum/asset/simple/icon_states/multiple_icons/register()
@@ -260,56 +416,63 @@ GLOBAL_LIST_EMPTY(asset_datums)
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif'
)
-/datum/asset/simple/pda
+/datum/asset/spritesheet/simple/pda
+ name = "pda"
assets = list(
- "pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
- "pda_back.png" = 'icons/pda_icons/pda_back.png',
- "pda_bell.png" = 'icons/pda_icons/pda_bell.png',
- "pda_blank.png" = 'icons/pda_icons/pda_blank.png',
- "pda_boom.png" = 'icons/pda_icons/pda_boom.png',
- "pda_bucket.png" = 'icons/pda_icons/pda_bucket.png',
- "pda_medbot.png" = 'icons/pda_icons/pda_medbot.png',
- "pda_floorbot.png" = 'icons/pda_icons/pda_floorbot.png',
- "pda_cleanbot.png" = 'icons/pda_icons/pda_cleanbot.png',
- "pda_crate.png" = 'icons/pda_icons/pda_crate.png',
- "pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png',
- "pda_eject.png" = 'icons/pda_icons/pda_eject.png',
- "pda_flashlight.png" = 'icons/pda_icons/pda_flashlight.png',
- "pda_honk.png" = 'icons/pda_icons/pda_honk.png',
- "pda_mail.png" = 'icons/pda_icons/pda_mail.png',
- "pda_medical.png" = 'icons/pda_icons/pda_medical.png',
- "pda_menu.png" = 'icons/pda_icons/pda_menu.png',
- "pda_mule.png" = 'icons/pda_icons/pda_mule.png',
- "pda_notes.png" = 'icons/pda_icons/pda_notes.png',
- "pda_power.png" = 'icons/pda_icons/pda_power.png',
- "pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png',
- "pda_reagent.png" = 'icons/pda_icons/pda_reagent.png',
- "pda_refresh.png" = 'icons/pda_icons/pda_refresh.png',
- "pda_scanner.png" = 'icons/pda_icons/pda_scanner.png',
- "pda_signaler.png" = 'icons/pda_icons/pda_signaler.png',
- "pda_status.png" = 'icons/pda_icons/pda_status.png',
- "pda_dronephone.png" = 'icons/pda_icons/pda_dronephone.png'
+ "atmos" = 'icons/pda_icons/pda_atmos.png',
+ "back" = 'icons/pda_icons/pda_back.png',
+ "bell" = 'icons/pda_icons/pda_bell.png',
+ "blank" = 'icons/pda_icons/pda_blank.png',
+ "boom" = 'icons/pda_icons/pda_boom.png',
+ "bucket" = 'icons/pda_icons/pda_bucket.png',
+ "medbot" = 'icons/pda_icons/pda_medbot.png',
+ "floorbot" = 'icons/pda_icons/pda_floorbot.png',
+ "cleanbot" = 'icons/pda_icons/pda_cleanbot.png',
+ "crate" = 'icons/pda_icons/pda_crate.png',
+ "cuffs" = 'icons/pda_icons/pda_cuffs.png',
+ "eject" = 'icons/pda_icons/pda_eject.png',
+ "flashlight" = 'icons/pda_icons/pda_flashlight.png',
+ "honk" = 'icons/pda_icons/pda_honk.png',
+ "mail" = 'icons/pda_icons/pda_mail.png',
+ "medical" = 'icons/pda_icons/pda_medical.png',
+ "menu" = 'icons/pda_icons/pda_menu.png',
+ "mule" = 'icons/pda_icons/pda_mule.png',
+ "notes" = 'icons/pda_icons/pda_notes.png',
+ "power" = 'icons/pda_icons/pda_power.png',
+ "rdoor" = 'icons/pda_icons/pda_rdoor.png',
+ "reagent" = 'icons/pda_icons/pda_reagent.png',
+ "refresh" = 'icons/pda_icons/pda_refresh.png',
+ "scanner" = 'icons/pda_icons/pda_scanner.png',
+ "signaler" = 'icons/pda_icons/pda_signaler.png',
+ "status" = 'icons/pda_icons/pda_status.png',
+ "dronephone" = 'icons/pda_icons/pda_dronephone.png'
)
-/datum/asset/simple/paper
+/datum/asset/spritesheet/simple/paper
+ name = "paper"
assets = list(
- "large_stamp-clown.png" = 'icons/stamp_icons/large_stamp-clown.png',
- "large_stamp-deny.png" = 'icons/stamp_icons/large_stamp-deny.png',
- "large_stamp-ok.png" = 'icons/stamp_icons/large_stamp-ok.png',
- "large_stamp-hop.png" = 'icons/stamp_icons/large_stamp-hop.png',
- "large_stamp-cmo.png" = 'icons/stamp_icons/large_stamp-cmo.png',
- "large_stamp-ce.png" = 'icons/stamp_icons/large_stamp-ce.png',
- "large_stamp-hos.png" = 'icons/stamp_icons/large_stamp-hos.png',
- "large_stamp-rd.png" = 'icons/stamp_icons/large_stamp-rd.png',
- "large_stamp-cap.png" = 'icons/stamp_icons/large_stamp-cap.png',
- "large_stamp-qm.png" = 'icons/stamp_icons/large_stamp-qm.png',
- "large_stamp-law.png" = 'icons/stamp_icons/large_stamp-law.png'
+ "stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png',
+ "stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png',
+ "stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png',
+ "stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png',
+ "stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png',
+ "stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png',
+ "stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png',
+ "stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png',
+ "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
+ "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
+ "stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
)
/datum/asset/simple/IRV
assets = list(
"jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
- "jquery-1.10.2.min.js" = 'html/IRV/jquery-1.10.2.min.js'
+ )
+
+/datum/asset/group/IRV
+ children = list(
+ /datum/asset/simple/jquery,
+ /datum/asset/simple/IRV
)
/datum/asset/simple/changelog
@@ -335,10 +498,22 @@ GLOBAL_LIST_EMPTY(asset_datums)
"changelog.css" = 'html/changelog.css'
)
-/datum/asset/simple/goonchat
+/datum/asset/group/goonchat
+ children = list(
+ /datum/asset/simple/jquery,
+ /datum/asset/simple/goonchat,
+ /datum/asset/spritesheet/goonchat
+ )
+
+/datum/asset/simple/jquery
verify = FALSE
assets = list(
"jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
+ )
+
+/datum/asset/simple/goonchat
+ verify = FALSE
+ assets = list(
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
"errorHandler.js" = 'code/modules/goonchat/browserassets/js/errorHandler.js',
"browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
@@ -350,6 +525,24 @@ GLOBAL_LIST_EMPTY(asset_datums)
"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
)
+/datum/asset/spritesheet/goonchat
+ name = "chat"
+
+/datum/asset/spritesheet/goonchat/register()
+ InsertAll("emoji", 'icons/emoji.dmi')
+
+ // pre-loading all lanugage icons also helps to avoid meta
+ InsertAll("language", 'icons/misc/language.dmi')
+ // catch languages which are pulling icons from another file
+ for(var/path in typesof(/datum/language))
+ var/datum/language/L = path
+ var/icon = initial(L.icon)
+ if (icon != 'icons/misc/language.dmi')
+ var/icon_state = initial(L.icon_state)
+ Insert("language-[icon_state]", icon, icon_state=icon_state)
+
+ ..()
+
/datum/asset/simple/permissions
assets = list(
"padlock.png" = 'html/padlock.png'
@@ -362,26 +555,19 @@ GLOBAL_LIST_EMPTY(asset_datums)
var/datum/language/L = new path ()
L.get_icon()
-/datum/asset/simple/icon_states/emojis
- icon = 'icons/emoji.dmi'
- generic_icon_names = TRUE
+/datum/asset/spritesheet/pipes
+ name = "pipes"
-/datum/asset/simple/icon_states/multiple_icons/pipes
- icons = list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi')
- prefix = "pipe"
-
-/datum/asset/simple/icon_states/multiple_icons/pipes/New()
- directions = GLOB.alldirs
+/datum/asset/spritesheet/pipes/register()
+ for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi'))
+ InsertAll("", each, GLOB.alldirs)
..()
-/datum/asset/simple/icon_states/multiple_icons/pipes/register()
- ..()
- var/meter = icon('icons/obj/atmospherics/pipes/simple.dmi', "meterX", SOUTH, frame, movement_states)
- if(meter)
- register_asset(sanitize_filename("[prefix].south.meterX.png"), fcopy_rsc(meter))
-
// Representative icons for each research design
-/datum/asset/simple/research_designs/register()
+/datum/asset/spritesheet/research_designs
+ name = "design"
+
+/datum/asset/spritesheet/research_designs/register()
for (var/path in subtypesof(/datum/design))
var/datum/design/D = path
@@ -401,7 +587,6 @@ GLOBAL_LIST_EMPTY(asset_datums)
if (machine)
item = machine
var/icon_file = initial(item.icon)
- var/all_states = icon_states(icon_file)
var/icon/I = icon(icon_file, initial(item.icon_state), SOUTH)
// computers (and snowflakes) get their screen and keyboard sprites
@@ -409,10 +594,11 @@ GLOBAL_LIST_EMPTY(asset_datums)
var/obj/machinery/computer/C = item
var/screen = initial(C.icon_screen)
var/keyboard = initial(C.icon_keyboard)
+ var/all_states = icon_states(icon_file)
if (screen && (screen in all_states))
I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
if (keyboard && (keyboard in all_states))
I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
- assets["design_[initial(D.id)].png"] = I
+ Insert(initial(D.id), I)
return ..()
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 49d6c4b04a..dfecc6f633 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -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! Click Here to find out more.")
+ 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! Click Here to find out more.")
return 0
return 1
@@ -165,6 +165,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
return var_name != NAMEOF(src, holder) && ..()
/client/New(TopicData)
+ world.SetConfig("APP/admin", ckey, "role=admin") //CITADEL EDIT - Allows admins to reboot in OOM situations
var/tdata = TopicData //save this for later use
chatOutput = new /datum/chatOutput(src)
TopicData = null //Prevent calls to client.Topic from connect
@@ -179,10 +180,15 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins.
//Admin Authorisation
holder = GLOB.admin_datums[ckey]
+ var/debug_tools_allowed = FALSE //CITADEL EDIT
if(holder)
GLOB.admins |= src
holder.owner = src
connecting_admin = TRUE
+ //CITADEL EDIT
+ if(check_rights_for(src, R_DEBUG))
+ debug_tools_allowed = TRUE
+ //END CITADEL EDIT
else if(GLOB.deadmins[ckey])
verbs += /client/proc/readmin
connecting_admin = TRUE
@@ -197,6 +203,12 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
to_chat(world, "Autoadmin rank not found")
else
new /datum/admins(autorank, ckey)
+ //CITADEL EDIT
+ if(check_rights_for(src, R_DEBUG)) //check if autoadmin gave us it
+ debug_tools_allowed = TRUE
+ if(!debug_tools_allowed)
+ world.SetConfig("APP/admin", ckey, null)
+ //END CITADEL EDIT
if(CONFIG_GET(flag/enable_localhost_rank) && !connecting_admin)
var/localhost_addresses = list("127.0.0.1", "::1")
if(isnull(address) || (address in localhost_addresses))
@@ -211,6 +223,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
prefs.last_id = computer_id //these are gonna be used for banning
fps = prefs.clientfps
+ if(fexists(roundend_report_file()))
+ verbs += /client/proc/show_previous_roundend_report
+
log_access("Login: [key_name(src)] from [address ? address : "localhost"]-[computer_id] || BYOND v[byond_version]")
var/alert_mob_dupe_login = FALSE
if(CONFIG_GET(flag/log_access))
@@ -255,7 +270,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
log_access("Failed login: [key] - blacklisted byond version")
to_chat(src, "Your version of byond is blacklisted.")
to_chat(src, "Byond build [byond_build] ([byond_version].[byond_build]) has been blacklisted for the following reason: [GLOB.blacklisted_builds[num2text(byond_build)]].")
- to_chat(src, "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.")
+ to_chat(src, "Please download a new version of byond. If [byond_build] is the latest, you can go to BYOND's website to download other versions.")
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
@@ -278,11 +293,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, "Your version of byond is too old:")
+ to_chat(src, "Your version of BYOND is too old:")
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 BYOND's website 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
@@ -294,14 +309,14 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
msg += CONFIG_GET(string/client_warn_message) + "
"
msg += "Your version: [byond_version] "
msg += "Required version to remove this message: [cwv] or later "
- msg += "Visit http://www.byond.com/download/ to get the latest version of byond. "
+ msg += "Visit BYOND's website to get the latest version of BYOND. "
src << browse(msg, "window=warning_popup")
else
to_chat(src, "Your version of byond may be getting out of date:")
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 BYOND's website to get the latest version of BYOND.")
if (connection == "web" && !connecting_admin)
if (!CONFIG_GET(flag/allow_webclient))
@@ -381,7 +396,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
winset(src, "[topmenu.type]", "parent=menu;name=[url_encode(topmenuname)]")
var/list/entries = topmenu.Generate_list(src)
for (var/child in entries)
- winset(src, "[url_encode(child)]", "[entries[child]]")
+ winset(src, "[child]", "[entries[child]]")
if (!ispath(child, /datum/verbs/menu))
var/atom/verb/verbpath = child
if (copytext(verbpath.name,1,2) != "@")
@@ -391,9 +406,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()
//////////////
@@ -472,7 +487,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("Failed Login: [key] - New account attempting to connect during panic bunker")
- 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"])
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 7558380a36..7eb1c25455 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -83,12 +83,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
//Mob preview
var/icon/preview_icon = null
- //Trait list
- var/list/positive_traits = list()
- var/list/negative_traits = list()
- var/list/neutral_traits = list()
- var/list/all_traits = list()
- var/list/character_traits = list()
+ //Quirk list
+ var/list/positive_quirks = list()
+ var/list/negative_quirks = list()
+ var/list/neutral_quirks = list()
+ var/list/all_quirks = list()
+ var/list/character_quirks = list()
//Jobs, uses bitflags
var/job_civilian_high = 0
@@ -120,6 +120,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/parallax
+ var/ambientocclusion = TRUE
+
var/uplink_spawn_loc = UPLINK_PDA
var/list/exp = list()
@@ -193,9 +195,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "
Current Quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]
"
dat += "
Identity
"
dat += "
"
if(jobban_isbanned(user, "appearance"))
@@ -490,6 +492,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "High"
dat += " "
+ dat += "Ambient Occlusion:[ambientocclusion ? "Enabled" : "Disabled"] "
+
dat += "
"
dat += "
Special Role Settings
"
@@ -855,72 +859,72 @@ GLOBAL_LIST_EMPTY(preferences_datums)
return job_engsec_low
return 0
-/datum/preferences/proc/SetTraits(mob/user)
- if(!SStraits)
- to_chat(user, "The trait subsystem is still initializing! Try again in a minute.")
+/datum/preferences/proc/SetQuirks(mob/user)
+ if(!SSquirks)
+ to_chat(user, "The quirk subsystem is still initializing! Try again in a minute.")
return
var/list/dat = list()
- if(!SStraits.traits.len)
- dat += "The trait subsystem hasn't finished initializing, please hold..."
+ if(!SSquirks.quirks.len)
+ dat += "The quirk subsystem hasn't finished initializing, please hold..."
dat += "
Left-click to add or remove traits. You need one negative trait for every positive trait. \
- Traits are applied at roundstart and cannot normally be removed.
"
+ dat += "
Choose quirk setup
"
+ dat += "
Left-click to add or remove quirks. You need negative quirks to have positive ones. \
+ Quirks are applied at roundstart and cannot normally be removed.
Meteors have been detected on collision course with the station.
")
- target.playsound_local(null, 'sound/ai/meteors.ogg', 100, 0)
- qdel(src)
+ SEND_SOUND(target, 'sound/ai/meteors.ogg')
+ if("supermatter")
+ SEND_SOUND(target, 'sound/magic/charge.ogg')
+ to_chat(target, "You feel reality distort for a moment...")
/datum/hallucination/hudscrew
- cost = 10
-/datum/hallucination/hudscrew/New(mob/living/carbon/T, forced = TRUE)
+/datum/hallucination/hudscrew/New(mob/living/carbon/C, forced = TRUE)
set waitfor = FALSE
..()
//Screwy HUD
@@ -933,9 +911,8 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
qdel(src)
/datum/hallucination/fake_alert
- cost = 15
-/datum/hallucination/fake_alert/New(mob/living/carbon/T, forced = TRUE, specific, duration = 150)
+/datum/hallucination/fake_alert/New(mob/living/carbon/C, forced = TRUE, specific, duration = 150)
set waitfor = FALSE
..()
var/alert_type = pick("not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","weightless","fire","locked","hacked","temphot","tempcold","pressure")
@@ -983,15 +960,14 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
if("hacked")
target.throw_alert(alert_type, /obj/screen/alert/hacked, override = TRUE)
if("charge")
- target.throw_alert(alert_type,/obj/screen/alert/emptycell, override = TRUE)
+ target.throw_alert(alert_type, /obj/screen/alert/emptycell, override = TRUE)
sleep(duration)
target.clear_alert(alert_type, clear_override = TRUE)
qdel(src)
/datum/hallucination/items
- cost = 15
-/datum/hallucination/items/New(mob/living/carbon/T, forced = TRUE)
+/datum/hallucination/items/New(mob/living/carbon/C, forced = TRUE)
set waitfor = FALSE
..()
//Strange items
@@ -1052,9 +1028,8 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
qdel(src)
/datum/hallucination/dangerflash
- cost = 15
-/datum/hallucination/dangerflash/New(mob/living/carbon/T, forced = TRUE)
+/datum/hallucination/dangerflash/New(mob/living/carbon/C, forced = TRUE, danger_type)
set waitfor = FALSE
..()
//Flashes of danger
@@ -1064,32 +1039,92 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
possible_points += F
if(possible_points.len)
var/turf/open/floor/danger_point = pick(possible_points)
-
- switch(rand(1,5))
- if(1)
- target.halimage = image('icons/turf/space.dmi',danger_point,"[rand(1,25)]",TURF_LAYER)
- if(2)
- target.halimage = image('icons/turf/floors/lava.dmi',danger_point,"smooth",TURF_LAYER)
- if(3)
- target.halimage = image('icons/turf/floors/Chasms.dmi',danger_point,"smooth",TURF_LAYER)
- if(4)
- target.halimage = image('icons/effects/effects.dmi',danger_point,"anom",OBJ_LAYER+0.01)
- if(5)
- target.halimage = image('icons/effects/effects.dmi',danger_point,"electricity2",OBJ_LAYER+0.01)
-
-
- if(target.client)
- target.client.images += target.halimage
- sleep(rand(200,450))
- if(target.client)
- target.client.images -= target.halimage
- QDEL_NULL(target.halimage)
+ if(!danger_type)
+ danger_type = pick("lava","chasm","anomaly")
+ switch(danger_type)
+ if("lava")
+ new /obj/effect/hallucination/danger/lava(danger_point, target)
+ if("chasm")
+ new /obj/effect/hallucination/danger/chasm(danger_point, target)
+ if("anomaly")
+ new /obj/effect/hallucination/danger/anomaly(danger_point, target)
qdel(src)
-/datum/hallucination/death
- cost = 40
+/obj/effect/hallucination/danger
+ var/image/image
-/datum/hallucination/death/New(mob/living/carbon/T, forced = TRUE)
+/obj/effect/hallucination/danger/proc/show_icon()
+ return
+
+/obj/effect/hallucination/danger/proc/clear_icon()
+ if(image && target.client)
+ target.client.images -= image
+
+/obj/effect/hallucination/danger/Initialize(mapload, _target)
+ . = ..()
+ target = _target
+ show_icon()
+ QDEL_IN(src, rand(200, 450))
+
+/obj/effect/hallucination/danger/Destroy()
+ clear_icon()
+ . = ..()
+
+/obj/effect/hallucination/danger/lava
+ name = "lava"
+
+/obj/effect/hallucination/danger/lava/show_icon()
+ image = image('icons/turf/floors/lava.dmi',src,"smooth",TURF_LAYER)
+ if(target.client)
+ target.client.images += image
+
+/obj/effect/hallucination/danger/lava/Crossed(atom/movable/AM)
+ if(AM == target)
+ target.adjustStaminaLoss(20)
+ new /datum/hallucination/fire(target)
+
+/obj/effect/hallucination/danger/chasm
+ name = "chasm"
+
+/obj/effect/hallucination/danger/chasm/show_icon()
+ image = image('icons/turf/floors/Chasms.dmi',src,"smooth",TURF_LAYER)
+ if(target.client)
+ target.client.images += image
+
+/obj/effect/hallucination/danger/chasm/Crossed(atom/movable/AM)
+ if(AM == target)
+ to_chat(target, "You fall into the chasm!")
+ target.Knockdown(40)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, target, "It's surprisingly shallow."), 15)
+ QDEL_IN(src, 30)
+
+/obj/effect/hallucination/danger/anomaly
+ name = "flux wave anomaly"
+
+/obj/effect/hallucination/danger/anomaly/Initialize()
+ . = ..()
+ START_PROCESSING(SSobj, src)
+
+/obj/effect/hallucination/danger/anomaly/process()
+ if(prob(70))
+ step(src,pick(GLOB.alldirs))
+
+/obj/effect/hallucination/danger/anomaly/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/effect/hallucination/danger/anomaly/show_icon()
+ image = image('icons/effects/effects.dmi',src,"electricity2",OBJ_LAYER+0.01)
+ if(target.client)
+ target.client.images += image
+
+/obj/effect/hallucination/danger/anomaly/Crossed(atom/movable/AM)
+ if(AM == target)
+ new /datum/hallucination/shock(target)
+
+/datum/hallucination/death
+
+/datum/hallucination/death/New(mob/living/carbon/C, forced = TRUE)
set waitfor = FALSE
..()
target.set_screwyhud(SCREWYHUD_DEAD)
@@ -1107,8 +1142,8 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
fakemob = target //ever been so lonely you had to haunt yourself?
if(fakemob)
sleep(rand(20, 50))
- to_chat(target, "DEAD: [fakemob.name] says, \"[pick("rip","hey [target.first_name()]","you too?","is the AI rogue?",\
- "i[prob(50)?" fucking":""] hate [pick("blood cult", "clock cult", "revenants", "abductors","double agents","viruses","badmins","you")]")]\"")
+ to_chat(target, "DEAD: [fakemob.name] says, \"[pick("rip","why did i just drop dead?","hey [target.first_name()]","git gud","you too?","is the AI rogue?",\
+ "i[prob(50)?" fucking":""] hate [pick("blood cult", "clock cult", "revenants", "this round","this","myself","admins","you")]")]\"")
sleep(rand(70,90))
target.set_screwyhud(SCREWYHUD_NONE)
target.SetKnockdown(0)
@@ -1116,38 +1151,93 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
qdel(src)
/datum/hallucination/fire
- cost = 25
+ var/active = TRUE
+ var/stage = 0
+ var/image/fire_overlay
-/datum/hallucination/fire/New(mob/living/carbon/T, forced = TRUE)
+/datum/hallucination/fire/New(mob/living/carbon/C, forced = TRUE)
set waitfor = FALSE
..()
- var/image/fire_overlay = image('icons/mob/OnFire.dmi', target, "Standing", ABOVE_MOB_LAYER)
+ target.fire_stacks = max(target.fire_stacks, 0.1) //Placebo flammability
+ fire_overlay = image('icons/mob/OnFire.dmi', target, "Standing", ABOVE_MOB_LAYER)
if(target.client)
target.client.images += fire_overlay
to_chat(target, "You're set on fire!")
target.throw_alert("fire", /obj/screen/alert/fire, override = TRUE)
sleep(20)
- target.throw_alert("temp", /obj/screen/alert/hot, 1, override = TRUE)
- sleep(30)
- target.clear_alert("temp", clear_override = TRUE)
- target.throw_alert("temp", /obj/screen/alert/hot, 2, override = TRUE)
- sleep(30)
- target.clear_alert("temp", clear_override = TRUE)
- target.throw_alert("temp", /obj/screen/alert/hot, 3, override = TRUE)
+ for(var/i in 1 to 3)
+ if(target.fire_stacks <= 0)
+ clear_fire()
+ return
+ stage++
+ update_temp()
+ sleep(30)
for(var/i in 1 to rand(5, 10))
+ if(target.fire_stacks <= 0)
+ clear_fire()
+ return
target.adjustStaminaLoss(15)
- sleep(25)
+ sleep(20)
+ clear_fire()
+
+/datum/hallucination/fire/proc/update_temp()
+ if(stage <= 0)
+ target.clear_alert("temp", clear_override = TRUE)
+ else
+ target.clear_alert("temp", clear_override = TRUE)
+ target.throw_alert("temp", /obj/screen/alert/hot, stage, override = TRUE)
+
+/datum/hallucination/fire/proc/clear_fire()
+ if(!active)
+ return
+ active = FALSE
target.clear_alert("fire", clear_override = TRUE)
- target.clear_alert("temp", clear_override = TRUE)
if(target.client)
target.client.images -= fire_overlay
QDEL_NULL(fire_overlay)
+ while(stage > 0)
+ stage--
+ update_temp()
+ sleep(30)
qdel(src)
-/datum/hallucination/husks
- cost = 20
+/datum/hallucination/shock
+ var/image/shock_image
+ var/image/electrocution_skeleton_anim
-/datum/hallucination/husks/New(mob/living/carbon/T, forced = TRUE)
+/datum/hallucination/shock/New(mob/living/carbon/C, forced = TRUE)
+ set waitfor = FALSE
+ ..()
+ shock_image = image(target, target, dir = target.dir)
+ shock_image.appearance_flags |= KEEP_APART
+ shock_image.color = rgb(0,0,0)
+ shock_image.override = TRUE
+ electrocution_skeleton_anim = image('icons/mob/human.dmi', target, icon_state = "electrocuted_base", layer=ABOVE_MOB_LAYER)
+ electrocution_skeleton_anim.appearance_flags |= RESET_COLOR|KEEP_APART
+ to_chat(target, "You feel a powerful shock course through your body!")
+ if(target.client)
+ target.client.images |= shock_image
+ target.client.images |= electrocution_skeleton_anim
+ addtimer(CALLBACK(src, .proc/reset_shock_animation), 40)
+ target.playsound_local(get_turf(src), "sparks", 100, 1)
+ target.staminaloss += 50
+ target.Stun(40)
+ target.jitteriness += 1000
+ target.do_jitter_animation(target.jitteriness)
+ addtimer(CALLBACK(src, .proc/shock_drop), 20)
+
+/datum/hallucination/shock/proc/reset_shock_animation()
+ if(target.client)
+ target.client.images.Remove(shock_image)
+ target.client.images.Remove(electrocution_skeleton_anim)
+
+/datum/hallucination/shock/proc/shock_drop()
+ target.jitteriness = max(target.jitteriness - 990, 10) //Still jittery, but vastly less
+ target.Knockdown(60)
+
+/datum/hallucination/husks
+
+/datum/hallucination/husks/New(mob/living/carbon/C, forced = TRUE)
set waitfor = FALSE
..()
if(!target.halbody)
@@ -1178,7 +1268,6 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
//hallucination projectile code in code/modules/projectiles/projectile/special.dm
/datum/hallucination/stray_bullet
- cost = 15
/datum/hallucination/stray_bullet/New(mob/living/carbon/C, forced = TRUE)
set waitfor = FALSE
@@ -1194,29 +1283,4 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
H.hal_target = target
H.preparePixelProjectile(target, start)
H.fire()
- qdel(src)
-
-//Reality Dissociation Syndrome hallucinations only trigger in special cases and have no cost
-/datum/hallucination/rds
- cost = 0
-
-/datum/hallucination/rds/fourth_wall/New(mob/living/carbon/C, forced = TRUE)
- ..()
- to_chat(C, "[pick("Leave the server" , "Close the game window")] [pick("immediately", "right now")].")
-
-/datum/hallucination/rds/supermatter/New(mob/living/carbon/C, forced = TRUE)
- ..()
- SEND_SOUND(C, 'sound/magic/charge.ogg')
- to_chat(C, "You feel reality distort for a moment...")
-
-/datum/hallucination/rds/narsie/New(mob/living/carbon/C, forced = TRUE)
- C.playsound_local(C, 'sound/creatures/narsie_rises.ogg', 50, FALSE, pressure_affected = FALSE)
- to_chat(C, "NAR-SIE HAS RISEN")
-
-/datum/hallucination/rds/ark/New(mob/living/carbon/C, forced = TRUE)
- set waitfor = FALSE
- ..()
- C.playsound_local(C, 'sound/machines/clockcult/ark_deathrattle.ogg', 50, FALSE, pressure_affected = FALSE)
- C.playsound_local(C, 'sound/effects/clockcult_gateway_disrupted.ogg', 50, FALSE, pressure_affected = FALSE)
- sleep(27)
- C.playsound_local(C, 'sound/effects/explosion_distant.ogg', 50, FALSE, pressure_affected = FALSE)
+ qdel(src)
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index 9d20369537..9c1cb5c848 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -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
@@ -344,6 +367,15 @@
list_reagents = list("limejuice" = 100)
foodtype = FRUIT
+/obj/item/reagent_containers/food/drinks/bottle/menthol
+ name = "menthol"
+ desc = "Tastes naturally minty, and imparts a very mild numbing sensation."
+ icon_state = "mentholbox"
+ item_state = "carton"
+ lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
+ isGlass = FALSE
+ list_reagents = list("menthol" = 100)
/obj/item/reagent_containers/food/drinks/bottle/grenadine
name = "Jester Grenadine"
diff --git a/code/modules/food_and_drinks/food/customizables.dm b/code/modules/food_and_drinks/food/customizables.dm
index 353bfc6538..3df4ca4bd0 100644
--- a/code/modules/food_and_drinks/food/customizables.dm
+++ b/code/modules/food_and_drinks/food/customizables.dm
@@ -158,7 +158,7 @@
desc = "A timeless classic."
ingredients_placement = INGREDIENTS_STACKPLUSTOP
icon = 'icons/obj/food/burgerbread.dmi'
- icon_state = "bun"
+ icon_state = "custburg"
foodtype = GRAIN
diff --git a/code/modules/food_and_drinks/food/snacks_bread.dm b/code/modules/food_and_drinks/food/snacks_bread.dm
index 2e2759913b..4282015eb5 100644
--- a/code/modules/food_and_drinks/food/snacks_bread.dm
+++ b/code/modules/food_and_drinks/food/snacks_bread.dm
@@ -13,7 +13,7 @@
custom_food_type = /obj/item/reagent_containers/food/snacks/customizable/sandwich
filling_color = "#FFA500"
list_reagents = list("nutriment" = 2)
- slot_flags = SLOT_HEAD
+ slot_flags = ITEM_SLOT_HEAD
customfoodfilling = 0 //to avoid infinite bread-ception
foodtype = GRAIN
diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
index 2522ec9cf2..edc2305261 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
@@ -299,8 +299,7 @@
qdel(S)
return TRUE
for(var/obj/item/stack/sheet/wetleather/WL in src)
- var/obj/item/stack/sheet/leather/L = new(drop_location())
- L.amount = WL.amount
+ new /obj/item/stack/sheet/leather(drop_location(), WL.amount)
qdel(WL)
return TRUE
return FALSE
diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm
index 6fb8f2cac4..3141a9340a 100644
--- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm
+++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm
@@ -139,7 +139,7 @@
required_reagents = list("tequila" = 2, "kahlua" = 1)
/datum/chemical_reaction/tequila_sunrise
- name = "tequila Sunrise"
+ name = "Tequila Sunrise"
id = "tequilasunrise"
results = list("tequilasunrise" = 5)
required_reagents = list("tequila" = 2, "orangejuice" = 2, "grenadine" = 1)
@@ -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)
diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm
index 401e55c9e5..be06f99d61 100644
--- a/code/modules/goonchat/browserOutput.dm
+++ b/code/modules/goonchat/browserOutput.dm
@@ -46,8 +46,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic
if(!owner)
return
- var/datum/asset/stuff = get_asset_datum(/datum/asset/simple/goonchat)
- stuff.register()
+ var/datum/asset/stuff = get_asset_datum(/datum/asset/group/goonchat)
stuff.send(owner)
owner << browse(file('code/modules/goonchat/browserassets/html/browserOutput.html'), "window=browseroutput")
@@ -106,19 +105,10 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic
//do not convert to to_chat()
SEND_TEXT(owner, "Failed to load fancy chat, reverting to old chat. Certain features won't work.")
- pingLoop()
-
/datum/chatOutput/proc/showChat()
winset(owner, "output", "is-visible=false")
winset(owner, "browseroutput", "is-disabled=false;is-visible=true")
-/datum/chatOutput/proc/pingLoop()
- set waitfor = FALSE
-
- while (owner)
- ehjax_send(data = owner.is_afk(29) ? "softPang" : "pang") // SoftPang isn't handled anywhere but it'll always reset the opts.lastPang.
- sleep(30)
-
/datum/chatOutput/proc/ehjax_send(client/C = owner, window = "browseroutput", data)
if(islist(data))
data = json_encode(data)
diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html
index d40fd75f39..fe3be9486c 100644
--- a/code/modules/goonchat/browserassets/html/browserOutput.html
+++ b/code/modules/goonchat/browserassets/html/browserOutput.html
@@ -6,6 +6,7 @@
+
diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm
index 4f740f4e61..701167c853 100644
--- a/code/modules/holiday/holidays.dm
+++ b/code/modules/holiday/holidays.dm
@@ -70,6 +70,7 @@
begin_month = DECEMBER
end_day = 2
end_month = JANUARY
+ drone_hat = /obj/item/clothing/head/festive
/datum/holiday/new_year/getStationPrefix()
return pick("Party","New","Hangover","Resolution")
@@ -78,6 +79,7 @@
name = "Groundhog Day"
begin_day = 2
begin_month = FEBRUARY
+ drone_hat = /obj/item/clothing/head/helmet/space/chronos
/datum/holiday/valentines
name = VALENTINES
@@ -92,6 +94,7 @@
name = "Birthday of Space Station 13"
begin_day = 16
begin_month = FEBRUARY
+ drone_hat = /obj/item/clothing/head/festive
/datum/holiday/birthday/greet()
var/game_age = text2num(time2text(world.timeofday, "YY")) - 3
@@ -202,6 +205,7 @@
name = "UFO Day"
begin_day = 2
begin_month = JULY
+ drone_hat = /obj/item/clothing/mask/facehugger/dead
/datum/holiday/UFO/getStationPrefix() //Is such a thing even possible?
return pick("Ayy","Truth","Tsoukalos","Mulder") //Yes it is!
@@ -272,11 +276,13 @@
name = "Smiling Day"
begin_day = 7
begin_month = OCTOBER
+ drone_hat = /obj/item/clothing/head/papersack/smiley
/datum/holiday/boss
name = "Boss' Day"
begin_day = 16
begin_month = OCTOBER
+ drone_hat = /obj/item/clothing/head/that
/datum/holiday/halloween
name = HALLOWEEN
@@ -305,6 +311,7 @@
name = "Flowers Day"
begin_day = 19
begin_month = NOVEMBER
+ drone_hat = /obj/item/reagent_containers/food/snacks/grown/moonflower
/datum/holiday/hello
name = "Saying-'Hello' Day"
@@ -312,7 +319,7 @@
begin_month = NOVEMBER
/datum/holiday/hello/greet()
- return "[pick(list("Aloha", "Bonjour", "Hello", "Hi", "Greetings", "Salutations", "Bienvenidos", "Hola", "Howdy"))]! " + ..()
+ return "[pick(list("Aloha", "Bonjour", "Hello", "Hi", "Greetings", "Salutations", "Bienvenidos", "Hola", "Howdy", "Ni hao", "Guten Tag", "Konnichiwa", "G'day cunt"))]! " + ..()
/datum/holiday/human_rights
name = "Human-Rights Day"
@@ -323,6 +330,7 @@
name = "Monkey Day"
begin_day = 14
begin_month = DECEMBER
+ drone_hat = /obj/item/clothing/mask/gas/monkeymask
/datum/holiday/thanksgiving
name = "Thanksgiving in the United States"
diff --git a/code/modules/holodeck/area_copy.dm b/code/modules/holodeck/area_copy.dm
index fee60605e3..8edc7090e4 100644
--- a/code/modules/holodeck/area_copy.dm
+++ b/code/modules/holodeck/area_copy.dm
@@ -36,7 +36,7 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars,list("tag", "datum_components", "area"
M.power_change()
if(holoitem)
- O.flags_2 |= HOLOGRAM_2
+ O.flags_1 |= HOLOGRAM_1
return O
diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm
index 7075b8502e..5a35597a34 100644
--- a/code/modules/hydroponics/beekeeping/beebox.dm
+++ b/code/modules/hydroponics/beekeeping/beebox.dm
@@ -18,8 +18,11 @@
/mob/living/carbon/human/bee_friendly()
if(dna && dna.species && dna.species.id == "pod") //bees pollinate plants, duh.
return 1
- if((wear_suit && (wear_suit.flags_1 & THICKMATERIAL_1)) && (head && (head.flags_1 & THICKMATERIAL_1)))
- return 1
+ if (wear_suit && head && is_type_in_typecache(wear_suit, GLOB.typecache_clothing) && is_type_in_typecache(wear_suit, GLOB.typecache_clothing))
+ var/obj/item/clothing/CS = wear_suit
+ var/obj/item/clothing/CH = head
+ if (CS.clothing_flags & CH.clothing_flags & THICKMATERIAL)
+ return 1
return 0
diff --git a/code/modules/hydroponics/beekeeping/beekeeper_suit.dm b/code/modules/hydroponics/beekeeping/beekeeper_suit.dm
index b871951b0f..7fa1a0dd2c 100644
--- a/code/modules/hydroponics/beekeeping/beekeeper_suit.dm
+++ b/code/modules/hydroponics/beekeeping/beekeeper_suit.dm
@@ -4,7 +4,7 @@
desc = "Keeps the lil buzzing buggers out of your eyes."
icon_state = "beekeeper"
item_state = "beekeeper"
- flags_1 = THICKMATERIAL_1
+ clothing_flags = THICKMATERIAL
/obj/item/clothing/suit/beekeeper_suit
@@ -12,5 +12,4 @@
desc = "Keeps the lil buzzing buggers away from your squishy bits."
icon_state = "beekeeper"
item_state = "beekeeper"
- flags_1 = THICKMATERIAL_1
-
+ clothing_flags = THICKMATERIAL
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index 624394f878..6da117da88 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -262,8 +262,7 @@
if(!check_cost(D.materials, amount))
return FALSE
- var/obj/item/stack/product = new D.build_path(loc)
- product.amount = amount
+ new D.build_path(drop_location(), amount)
for(var/R in D.make_reagents)
beaker.reagents.add_reagent(R, D.make_reagents[R]*amount)
else
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index dd1d1777d8..f0c7bba885 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -85,14 +85,15 @@
interact(user)
return
else if(istype(I, /obj/item/disk/plantgene))
- if(disk)
- to_chat(user, "A data disk is already loaded into the machine!")
- else
- if(!user.transferItemToLoc(I, src))
- return
- disk = I
- to_chat(user, "You add [I] to the machine.")
- interact(user)
+ if (operation)
+ to_chat(user, "Please complete current operation.")
+ return
+ eject_disk()
+ if(!user.transferItemToLoc(I, src))
+ return
+ disk = I
+ to_chat(user, "You add [I] to the machine.")
+ interact(user)
else
..()
@@ -266,18 +267,13 @@
to_chat(usr, "You add [I] to the machine.")
update_icon()
else if(href_list["eject_disk"] && !operation)
- if (disk)
- disk.forceMove(drop_location())
- disk.verb_pickup()
- disk = null
- update_genes()
- else
- var/obj/item/I = usr.get_active_held_item()
- if(istype(I, /obj/item/disk/plantgene))
- if(!usr.transferItemToLoc(I, src))
- return
- disk = I
- to_chat(usr, "You add [I] to the machine.")
+ var/obj/item/I = usr.get_active_held_item()
+ eject_disk()
+ if(istype(I, /obj/item/disk/plantgene))
+ if(!usr.transferItemToLoc(I, src))
+ return
+ disk = I
+ to_chat(usr, "You add [I] to the machine.")
else if(href_list["op"] == "insert" && disk && disk.gene && seed)
if(!operation) // Wait for confirmation
operation = "insert"
@@ -365,6 +361,16 @@
update_genes()
update_icon()
+/obj/machinery/plantgenes/proc/eject_disk()
+ if (disk && !operation)
+ if(Adjacent(usr) && !issilicon(usr))
+ if (!usr.put_in_hands(disk))
+ disk.forceMove(drop_location())
+ else
+ disk.forceMove(drop_location())
+ disk = null
+ update_genes()
+
/obj/machinery/plantgenes/proc/update_genes()
core_genes = list()
reagent_genes = list()
diff --git a/code/modules/hydroponics/grown/ambrosia.dm b/code/modules/hydroponics/grown/ambrosia.dm
index 05cd54a9f0..5883b4dd64 100644
--- a/code/modules/hydroponics/grown/ambrosia.dm
+++ b/code/modules/hydroponics/grown/ambrosia.dm
@@ -4,7 +4,7 @@
name = "ambrosia branch"
desc = "This is a plant."
icon_state = "ambrosiavulgaris"
- slot_flags = SLOT_HEAD
+ slot_flags = ITEM_SLOT_HEAD
filling_color = "#008000"
bitesize_mod = 2
foodtype = VEGETABLES
diff --git a/code/modules/hydroponics/grown/flowers.dm b/code/modules/hydroponics/grown/flowers.dm
index 18eae2f4fd..8455df887e 100644
--- a/code/modules/hydroponics/grown/flowers.dm
+++ b/code/modules/hydroponics/grown/flowers.dm
@@ -22,7 +22,7 @@
name = "poppy"
desc = "Long-used as a symbol of rest, peace, and death."
icon_state = "poppy"
- slot_flags = SLOT_HEAD
+ slot_flags = ITEM_SLOT_HEAD
filling_color = "#FF6347"
bitesize_mod = 3
foodtype = VEGETABLES | GROSS
@@ -86,7 +86,7 @@
name = "harebell"
desc = "\"I'll sweeten thy sad grave: thou shalt not lack the flower that's like thy face, pale primrose, nor the azured hare-bell, like thy veins; no, nor the leaf of eglantine, whom not to slander, out-sweeten'd not thy breath.\""
icon_state = "harebell"
- slot_flags = SLOT_HEAD
+ slot_flags = ITEM_SLOT_HEAD
filling_color = "#E6E6FA"
bitesize_mod = 3
@@ -118,7 +118,7 @@
righthand_file = 'icons/mob/inhands/weapons/plants_righthand.dmi'
damtype = "fire"
force = 0
- slot_flags = SLOT_HEAD
+ slot_flags = ITEM_SLOT_HEAD
throwforce = 0
w_class = WEIGHT_CLASS_TINY
throw_speed = 1
@@ -149,7 +149,7 @@
name = "moonflower"
desc = "Store in a location at least 50 yards away from werewolves."
icon_state = "moonflower"
- slot_flags = SLOT_HEAD
+ slot_flags = ITEM_SLOT_HEAD
filling_color = "#E6E6FA"
bitesize_mod = 2
@@ -176,7 +176,7 @@
righthand_file = 'icons/mob/inhands/weapons/plants_righthand.dmi'
damtype = "fire"
force = 0
- slot_flags = SLOT_HEAD
+ slot_flags = ITEM_SLOT_HEAD
throwforce = 0
w_class = WEIGHT_CLASS_TINY
throw_speed = 1
diff --git a/code/modules/hydroponics/grown/grass_carpet.dm b/code/modules/hydroponics/grown/grass_carpet.dm
index 630c072edb..8e55f8a15d 100644
--- a/code/modules/hydroponics/grown/grass_carpet.dm
+++ b/code/modules/hydroponics/grown/grass_carpet.dm
@@ -36,19 +36,8 @@
continue
grassAmt += 1 + round(G.seed.potency * tile_coefficient)
qdel(G)
- var/obj/item/stack/tile/GT = new stacktype(user.loc)
- while(grassAmt > GT.max_amount)
- GT.amount = GT.max_amount
- grassAmt -= GT.max_amount
- GT = new stacktype(user.loc)
- GT.amount = grassAmt
- for(var/obj/item/stack/tile/T in user.loc)
- if((T.type == stacktype) && (T.amount < T.max_amount))
- GT.merge(T)
- if(GT.amount <= 0)
- break
+ new stacktype(user.drop_location(), grassAmt)
qdel(src)
- return
// Carpet
/obj/item/seeds/grass/carpet
diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm
index 9eaa8747b9..55c0da91f2 100644
--- a/code/modules/hydroponics/grown/replicapod.dm
+++ b/code/modules/hydroponics/grown/replicapod.dm
@@ -22,7 +22,7 @@
var/blood_type = null
var/list/features = null
var/factions = null
- var/list/traits = null
+ var/list/quirks = null
var/contains_sample = 0
/obj/item/seeds/replicapod/Initialize()
@@ -42,7 +42,7 @@
blood_type = B.data["blood_type"]
features = B.data["features"]
factions = B.data["factions"]
- factions = B.data["traits"]
+ factions = B.data["quirks"]
contains_sample = TRUE
visible_message("The [src] is injected with a fresh blood sample.")
else
@@ -114,7 +114,7 @@
podman.faction |= factions
if(!features["mcolor"])
features["mcolor"] = "#59CE00"
- for(var/V in traits)
+ for(var/V in quirks)
new V(podman)
podman.hardset_dna(null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
podman.set_cloned_appearance()
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index 31e888fdad..591fdfd535 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -8,7 +8,7 @@
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
w_class = WEIGHT_CLASS_TINY
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
materials = list(MAT_METAL=30, MAT_GLASS=20)
// *************************************
@@ -112,7 +112,7 @@
w_class = WEIGHT_CLASS_BULKY
flags_1 = CONDUCT_1
armour_penetration = 20
- slot_flags = SLOT_BACK
+ slot_flags = ITEM_SLOT_BACK
attack_verb = list("chopped", "sliced", "cut", "reaped")
hitsound = 'sound/weapons/bladeslice.ogg'
var/swiping = FALSE
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 3890c8e317..fb6915aef9 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -56,22 +56,19 @@
return ..()
/obj/machinery/hydroponics/constructable/attackby(obj/item/I, mob/user, params)
- if(default_deconstruction_screwdriver(user, "hydrotray3", "hydrotray3", I))
- return
-
- if(default_pry_open(I))
- return
-
- if(default_unfasten_wrench(user, I))
- return
-
- if(istype(I, /obj/item/crowbar))
- if(using_irrigation)
- to_chat(user, "Disconnect the hoses first!")
- else if(default_deconstruction_crowbar(I, 1))
+ if (user.a_intent != INTENT_HARM)
+ // handle opening the panel
+ if(default_deconstruction_screwdriver(user, icon_state, icon_state, I))
return
- else
- return ..()
+
+ // handle deconstructing the machine, if permissible
+ if (I.tool_behaviour == TOOL_CROWBAR && using_irrigation)
+ to_chat(user, "Disconnect the hoses first!")
+ return
+ else if(default_deconstruction_crowbar(I))
+ return
+
+ return ..()
/obj/machinery/hydroponics/proc/FindConnected()
var/list/connected = list()
@@ -787,31 +784,13 @@
for(var/obj/item/reagent_containers/food/snacks/grown/G in locate(user.x,user.y,user.z))
O.SendSignal(COMSIG_TRY_STORAGE_INSERT, G, user, TRUE)
- else if(istype(O, /obj/item/wrench) && unwrenchable)
- if(using_irrigation)
- to_chat(user, "Disconnect the hoses first!")
- return
-
- if(!anchored && !isinspace())
- user.visible_message("[user] begins to wrench [src] into place.", \
- "You begin to wrench [src] in place...")
- if (O.use_tool(src, user, 20, volume=50))
- if(anchored)
- return
- anchored = TRUE
- user.visible_message("[user] wrenches [src] into place.", \
- "You wrench [src] in place.")
- else if(anchored)
- user.visible_message("[user] begins to unwrench [src].", \
- "You begin to unwrench [src]...")
- if (O.use_tool(src, user, 20, volume=50))
- if(!anchored)
- return
- anchored = FALSE
- user.visible_message("[user] unwrenches [src].", \
- "You unwrench [src].")
+ else if(default_unfasten_wrench(user, O))
+ return
else if(istype(O, /obj/item/wirecutters) && unwrenchable)
+ if (!anchored)
+ to_chat(user, "Anchor the tray first!")
+ return
using_irrigation = !using_irrigation
O.play_tool_sound(src)
user.visible_message("[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.", \
@@ -840,6 +819,17 @@
else
return ..()
+/obj/machinery/hydroponics/can_be_unfasten_wrench(mob/user, silent)
+ if (!unwrenchable) // case also covered by NODECONSTRUCT checks in default_unfasten_wrench
+ return CANT_UNFASTEN
+
+ if (using_irrigation)
+ if (!silent)
+ to_chat(user, "Disconnect the hoses first!")
+ return FAILED_UNFASTEN
+
+ return ..()
+
/obj/machinery/hydroponics/attack_hand(mob/user)
. = ..()
if(.)
diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm
index d44682991a..72c34b90cc 100644
--- a/code/modules/integrated_electronics/core/assemblies.dm
+++ b/code/modules/integrated_electronics/core/assemblies.dm
@@ -3,7 +3,7 @@
/obj/item/electronic_assembly
name = "electronic assembly"
- obj_flags = CAN_BE_HIT
+ obj_flags = CAN_BE_HIT | UNIQUE_RENAME
desc = "It's a case, for building small electronics with."
w_class = WEIGHT_CLASS_SMALL
icon = 'icons/obj/assemblies/electronic_setups.dmi'
@@ -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"
diff --git a/code/modules/integrated_electronics/core/saved_circuits.dm b/code/modules/integrated_electronics/core/saved_circuits.dm
index b389b0d2d9..f58378cf6d 100644
--- a/code/modules/integrated_electronics/core/saved_circuits.dm
+++ b/code/modules/integrated_electronics/core/saved_circuits.dm
@@ -124,6 +124,10 @@
// Save modified name
if(initial(name) != name)
assembly_params["name"] = name
+
+ // Save modified description
+ if(initial(desc) != desc)
+ assembly_params["desc"] = desc
// Save panel status
if(opened)
@@ -142,6 +146,8 @@
// Validate name and color
if(assembly_params["name"] && !reject_bad_name(assembly_params["name"], TRUE))
return "Bad assembly name."
+ if(assembly_params["desc"] && !reject_bad_text(assembly_params["desc"]))
+ return "Bad assembly description."
if(assembly_params["detail_color"] && !(assembly_params["detail_color"] in color_whitelist))
return "Bad assembly color."
@@ -151,6 +157,10 @@
// Load modified name, if any.
if(assembly_params["name"])
name = assembly_params["name"]
+
+ // Load modified description, if any.
+ if(assembly_params["desc"])
+ desc = assembly_params["desc"]
// Load panel status
if(assembly_params["opened"])
diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm
index 859c8910f3..244b4cb71b 100644
--- a/code/modules/integrated_electronics/passive/power.dm
+++ b/code/modules/integrated_electronics/passive/power.dm
@@ -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()
diff --git a/code/modules/integrated_electronics/subtypes/access.dm b/code/modules/integrated_electronics/subtypes/access.dm
index 63b258d782..bf710be0e2 100644
--- a/code/modules/integrated_electronics/subtypes/access.dm
+++ b/code/modules/integrated_electronics/subtypes/access.dm
@@ -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
diff --git a/code/modules/integrated_electronics/subtypes/arithmetic.dm b/code/modules/integrated_electronics/subtypes/arithmetic.dm
index 3a28c7b051..d4b854268b 100644
--- a/code/modules/integrated_electronics/subtypes/arithmetic.dm
+++ b/code/modules/integrated_electronics/subtypes/arithmetic.dm
@@ -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; \
result = ((((A / B) / C) / D) ... ) and so on, until all pins have been divided. \
Null pins, and pins containing 0, are ignored. Pin A must 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
diff --git a/code/modules/integrated_electronics/subtypes/converters.dm b/code/modules/integrated_electronics/subtypes/converters.dm
index 5f7dd24ad9..9382f70066 100644
--- a/code/modules/integrated_electronics/subtypes/converters.dm
+++ b/code/modules/integrated_electronics/subtypes/converters.dm
@@ -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)
@@ -142,21 +142,18 @@
/obj/item/integrated_circuit/converter/concatenator
name = "concatenator"
- desc = "This joins many strings together to get one big string."
+ desc = "This can join up to 8 strings together to get one big string."
complexity = 4
- inputs = list(
- "A" = IC_PINTYPE_STRING,
- "B" = IC_PINTYPE_STRING,
- "C" = IC_PINTYPE_STRING,
- "D" = IC_PINTYPE_STRING,
- "E" = IC_PINTYPE_STRING,
- "F" = IC_PINTYPE_STRING,
- "G" = IC_PINTYPE_STRING,
- "H" = IC_PINTYPE_STRING
- )
+ inputs = list()
outputs = list("result" = IC_PINTYPE_STRING)
activators = list("concatenate" = IC_PINTYPE_PULSE_IN, "on concatenated" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
+ var/number_of_pins = 8
+
+/obj/item/integrated_circuit/converter/concatenator/Initialize()
+ for(var/i = 1 to number_of_pins)
+ inputs["input [i]"] = IC_PINTYPE_STRING
+ . = ..()
/obj/item/integrated_circuit/converter/concatenator/do_work()
var/result = null
@@ -169,10 +166,22 @@
push_data()
activate_pin(2)
+/obj/item/integrated_circuit/converter/concatenator/small
+ name = "small concatenator"
+ desc = "This can join up to 4 strings together to get one big string."
+ complexity = 2
+ number_of_pins = 4
+
+/obj/item/integrated_circuit/converter/concatenator/large
+ name = "large concatenator"
+ desc = "This can join up to 16 strings together to get one very big string."
+ complexity = 6
+ number_of_pins = 16
+
/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 after the given index, including spaces. So 'a person' with an index of '3' \
will split into 'a p' and 'erson'."
icon_state = "split"
@@ -203,11 +212,38 @@
activate_pin(2)
+/obj/item/integrated_circuit/converter/indexer
+ name = "indexer"
+ desc = "This circuit takes a string and an index value, then returns the character found at in the string at the given index."
+ extended_desc = "Make sure the index is not longer or shorter than the string length. If you don't, the circuit will return empty."
+ icon_state = "split"
+ complexity = 4
+ inputs = list(
+ "string to index" = IC_PINTYPE_STRING,
+ "index" = IC_PINTYPE_NUMBER,
+ )
+ outputs = list(
+ "found character" = IC_PINTYPE_STRING
+ )
+ activators = list("index" = IC_PINTYPE_PULSE_IN, "on indexed" = IC_PINTYPE_PULSE_OUT)
+ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
+
+/obj/item/integrated_circuit/converter/indexer/do_work()
+ var/strin = get_pin_data(IC_INPUT, 1)
+ var/ind = get_pin_data(IC_INPUT, 2)
+ if(ind > 0 && ind <= length(strin))
+ set_pin_data(IC_OUTPUT, 1, strin[ind])
+ else
+ set_pin_data(IC_OUTPUT, 1, "")
+ push_data()
+ activate_pin(2)
+
/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,
@@ -216,14 +252,38 @@
outputs = list(
"position" = IC_PINTYPE_NUMBER
)
- activators = list("search" = IC_PINTYPE_PULSE_IN, "after search" = IC_PINTYPE_PULSE_OUT)
+ activators = list("search" = IC_PINTYPE_PULSE_IN, "after search" = IC_PINTYPE_PULSE_OUT, "found" = IC_PINTYPE_PULSE_OUT, "not found" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/findstring/do_work()
+ var/position = findtext(get_pin_data(IC_INPUT, 1),get_pin_data(IC_INPUT, 2))
- set_pin_data(IC_OUTPUT, 1, findtext(get_pin_data(IC_INPUT, 1),get_pin_data(IC_INPUT, 2)) )
+ set_pin_data(IC_OUTPUT, 1, position)
+ push_data()
+
+ activate_pin(2)
+ if(position)
+ activate_pin(3)
+ else
+ activate_pin(4)
+
+/obj/item/integrated_circuit/converter/stringlength
+ name = "get length"
+ desc = "This circuit will return the number of characters in a string."
+ complexity = 1
+ inputs = list(
+ "string" = IC_PINTYPE_STRING
+ )
+ outputs = list(
+ "length" = IC_PINTYPE_NUMBER
+ )
+ activators = list("get length" = IC_PINTYPE_PULSE_IN, "on acquisition" = IC_PINTYPE_PULSE_OUT)
+ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
+
+/obj/item/integrated_circuit/converter/stringlength/do_work()
+ set_pin_data(IC_OUTPUT, 1, length(get_pin_data(IC_INPUT, 1)))
push_data()
activate_pin(2)
@@ -232,7 +292,8 @@
name = "string exploder"
desc = "This splits a single string into a list of strings."
extended_desc = "This circuit splits a given string into a list of strings based on the string and given delimiter. \
- For example, 'eat this burger' will be converted to list('eat','this','burger')."
+ For example, 'eat this burger' will be converted to list('eat','this','burger'). Leave the delimiter null to get a list \
+ of every individual character."
icon_state = "split"
complexity = 4
inputs = list(
@@ -248,7 +309,10 @@
/obj/item/integrated_circuit/converter/exploders/do_work()
var/strin = get_pin_data(IC_INPUT, 1)
var/delimiter = get_pin_data(IC_INPUT, 2)
- set_pin_data(IC_OUTPUT, 1, splittext(strin, delimiter))
+ if(delimiter == null)
+ set_pin_data(IC_OUTPUT, 1, string2charlist(strin))
+ else
+ set_pin_data(IC_OUTPUT, 1, splittext(strin, delimiter))
push_data()
activate_pin(2)
@@ -350,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,
diff --git a/code/modules/integrated_electronics/subtypes/data_transfer.dm b/code/modules/integrated_electronics/subtypes/data_transfer.dm
index 481360f6cf..682d982373 100644
--- a/code/modules/integrated_electronics/subtypes/data_transfer.dm
+++ b/code/modules/integrated_electronics/subtypes/data_transfer.dm
@@ -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
diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm
index 042d6a3616..70e3bed5a7 100644
--- a/code/modules/integrated_electronics/subtypes/input.dm
+++ b/code/modules/integrated_electronics/subtypes/input.dm
@@ -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."
@@ -637,6 +637,7 @@
var/frequency = FREQ_SIGNALER
var/code = DEFAULT_SIGNALER_CODE
var/datum/radio_frequency/radio_connection
+ var/hearing_range = 1
/obj/item/integrated_circuit/input/signaler/Initialize()
. = ..()
@@ -690,15 +691,19 @@
return 0
activate_pin(3)
- audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 1)
+ audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
+ for(var/CHM in get_hearers_in_view(hearing_range, src))
+ if(ismob(CHM))
+ var/mob/LM = CHM
+ LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
/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
@@ -751,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
@@ -797,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()
@@ -824,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."
@@ -916,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
@@ -943,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()
@@ -976,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)
@@ -1011,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
diff --git a/code/modules/integrated_electronics/subtypes/lists.dm b/code/modules/integrated_electronics/subtypes/lists.dm
index c9744cc41c..a5c482c7de 100644
--- a/code/modules/integrated_electronics/subtypes/lists.dm
+++ b/code/modules/integrated_electronics/subtypes/lists.dm
@@ -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
diff --git a/code/modules/integrated_electronics/subtypes/logic.dm b/code/modules/integrated_electronics/subtypes/logic.dm
index 41917f2a44..e9dca8c330 100644
--- a/code/modules/integrated_electronics/subtypes/logic.dm
+++ b/code/modules/integrated_electronics/subtypes/logic.dm
@@ -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)
diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm
index 1744a468f5..f4cc363afb 100644
--- a/code/modules/integrated_electronics/subtypes/manipulation.dm
+++ b/code/modules/integrated_electronics/subtypes/manipulation.dm
@@ -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("[assembly] fires [installed_gun]!")
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. \
- 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("[assembly] has thrown [A]!")
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."
@@ -573,7 +588,7 @@
/obj/item/integrated_circuit/manipulation/matman/Initialize()
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE), 0,
- FALSE, list(/obj/item/stack, /obj/item/stack/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
+ FALSE, list(/obj/item/stack), CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.max_amount =100000
materials.precise_insertion = TRUE
.=..()
diff --git a/code/modules/integrated_electronics/subtypes/memory.dm b/code/modules/integrated_electronics/subtypes/memory.dm
index b54c433d35..fe74657532 100644
--- a/code/modules/integrated_electronics/subtypes/memory.dm
+++ b/code/modules/integrated_electronics/subtypes/memory.dm
@@ -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
@@ -79,6 +79,7 @@
activators = list("push data" = IC_PINTYPE_PULSE_IN)
var/accepting_refs = FALSE
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
+ number_of_pins = 0
/obj/item/integrated_circuit/memory/constant/do_work()
var/datum/integrated_io/O = outputs[1]
diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/code/modules/integrated_electronics/subtypes/output.dm
index 6f7fd6eef5..2d820b016e 100644
--- a/code/modules/integrated_electronics/subtypes/output.dm
+++ b/code/modules/integrated_electronics/subtypes/output.dm
@@ -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(
diff --git a/code/modules/integrated_electronics/subtypes/power.dm b/code/modules/integrated_electronics/subtypes/power.dm
index 018cd71006..e760b21f72 100644
--- a/code/modules/integrated_electronics/subtypes/power.dm
+++ b/code/modules/integrated_electronics/subtypes/power.dm
@@ -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
diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm
index 9f57dd6f43..73d162ff3a 100644
--- a/code/modules/integrated_electronics/subtypes/reagents.dm
+++ b/code/modules/integrated_electronics/subtypes/reagents.dm
@@ -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(
diff --git a/code/modules/integrated_electronics/subtypes/smart.dm b/code/modules/integrated_electronics/subtypes/smart.dm
index e0775f1a23..4445c1e1f3 100644
--- a/code/modules/integrated_electronics/subtypes/smart.dm
+++ b/code/modules/integrated_electronics/subtypes/smart.dm
@@ -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)
\ No newline at end of file
+ activate_pin(2)
diff --git a/code/modules/integrated_electronics/subtypes/time.dm b/code/modules/integrated_electronics/subtypes/time.dm
index 26bd1fc1d6..f72f5dbd74 100644
--- a/code/modules/integrated_electronics/subtypes/time.dm
+++ b/code/modules/integrated_electronics/subtypes/time.dm
@@ -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
..()
diff --git a/code/modules/jobs/job_exp.dm b/code/modules/jobs/job_exp.dm
index 3aad52e596..b4679ae479 100644
--- a/code/modules/jobs/job_exp.dm
+++ b/code/modules/jobs/job_exp.dm
@@ -226,9 +226,14 @@ GLOBAL_PROTECT(exp_to_update)
if(!rolefound)
play_records["Unknown"] += minutes
else
- play_records[EXP_TYPE_GHOST] += minutes
- if(announce_changes)
- to_chat(src,"You got: [minutes] Ghost EXP!")
+ if(holder && !holder.deadmined)
+ play_records[EXP_TYPE_ADMIN] += minutes
+ if(announce_changes)
+ to_chat(src,"You got: [minutes] Admin EXP!")
+ else
+ play_records[EXP_TYPE_GHOST] += minutes
+ if(announce_changes)
+ to_chat(src,"You got: [minutes] Ghost EXP!")
else if(isobserver(mob))
play_records[EXP_TYPE_GHOST] += minutes
if(announce_changes)
diff --git a/code/modules/jobs/job_types/cargo_service.dm b/code/modules/jobs/job_types/cargo_service.dm
index 479230e5be..1351d2beeb 100644
--- a/code/modules/jobs/job_types/cargo_service.dm
+++ b/code/modules/jobs/job_types/cargo_service.dm
@@ -111,7 +111,7 @@ Shaft Miner
mask = /obj/item/clothing/mask/gas/explorer
glasses = /obj/item/clothing/glasses/meson
suit_store = /obj/item/tank/internals/oxygen
- internals_slot = slot_s_store
+ internals_slot = SLOT_S_STORE
backpack_contents = list(
/obj/item/storage/bag/ore=1,
/obj/item/kitchen/knife/combat/survival=1,
@@ -220,7 +220,7 @@ Cook
var/list/possible_boxes = subtypesof(/obj/item/storage/box/ingredients)
var/chosen_box = pick(possible_boxes)
var/obj/item/storage/box/I = new chosen_box(src)
- H.equip_to_slot_or_del(I,slot_in_backpack)
+ H.equip_to_slot_or_del(I,SLOT_IN_BACKPACK)
var/datum/martial_art/cqc/under_siege/justacook = new
justacook.teach(H)
diff --git a/code/modules/jobs/job_types/civilian.dm b/code/modules/jobs/job_types/civilian.dm
index 3c36247c6d..e0202db132 100644
--- a/code/modules/jobs/job_types/civilian.dm
+++ b/code/modules/jobs/job_types/civilian.dm
@@ -91,7 +91,7 @@ Mime
uniform = /obj/item/clothing/under/rank/mime
mask = /obj/item/clothing/mask/gas/mime
gloves = /obj/item/clothing/gloves/color/white
- head = /obj/item/clothing/head/beret
+ head = /obj/item/clothing/head/frenchberet
suit = /obj/item/clothing/suit/suspenders
backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing=1)
diff --git a/code/modules/jobs/job_types/civilian_chaplain.dm b/code/modules/jobs/job_types/civilian_chaplain.dm
index 09eb9f34e9..1ef6be2e60 100644
--- a/code/modules/jobs/job_types/civilian_chaplain.dm
+++ b/code/modules/jobs/job_types/civilian_chaplain.dm
@@ -31,7 +31,7 @@ Chaplain
B.icon_state = SSreligion.bible_icon_state
B.item_state = SSreligion.bible_item_state
to_chat(H, "There is already an established religion onboard the station. You are an acolyte of [SSreligion.deity]. Defer to the Chaplain.")
- H.equip_to_slot_or_del(B, slot_in_backpack)
+ H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK)
var/nrt = SSreligion.holy_weapon_type || /obj/item/nullrod
var/obj/item/nullrod/N = new nrt(H)
H.put_in_hands(N)
@@ -79,7 +79,7 @@ Chaplain
SSreligion.bible_name = B.name
SSreligion.deity = B.deity_name
- H.equip_to_slot_or_del(B, slot_in_backpack)
+ H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK)
SSblackbox.record_feedback("text", "religion_name", 1, "[new_religion]", 1)
SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1)
diff --git a/code/modules/jobs/job_types/engineering.dm b/code/modules/jobs/job_types/engineering.dm
index 9717062770..d7f23f48c9 100644
--- a/code/modules/jobs/job_types/engineering.dm
+++ b/code/modules/jobs/job_types/engineering.dm
@@ -48,7 +48,7 @@ Chief Engineer
satchel = /obj/item/storage/backpack/satchel/eng
duffelbag = /obj/item/storage/backpack/duffelbag/engineering
box = /obj/item/storage/box/engineer
- pda_slot = slot_l_store
+ pda_slot = SLOT_L_STORE
/datum/outfit/job/ce/rig
name = "Chief Engineer (Hardsuit)"
@@ -59,7 +59,7 @@ Chief Engineer
suit_store = /obj/item/tank/internals/oxygen
gloves = /obj/item/clothing/gloves/color/yellow
head = null
- internals_slot = slot_s_store
+ internals_slot = SLOT_S_STORE
/*
@@ -102,7 +102,7 @@ Station Engineer
satchel = /obj/item/storage/backpack/satchel/eng
duffelbag = /obj/item/storage/backpack/duffelbag/engineering
box = /obj/item/storage/box/engineer
- pda_slot = slot_l_store
+ pda_slot = SLOT_L_STORE
backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
/datum/outfit/job/engineer/gloved
@@ -116,7 +116,7 @@ Station Engineer
suit = /obj/item/clothing/suit/space/hardsuit/engine
suit_store = /obj/item/tank/internals/oxygen
head = null
- internals_slot = slot_s_store
+ internals_slot = SLOT_S_STORE
/*
@@ -156,7 +156,7 @@ Atmospheric Technician
satchel = /obj/item/storage/backpack/satchel/eng
duffelbag = /obj/item/storage/backpack/duffelbag/engineering
box = /obj/item/storage/box/engineer
- pda_slot = slot_l_store
+ pda_slot = SLOT_L_STORE
backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
/datum/outfit/job/atmos/rig
@@ -165,4 +165,4 @@ Atmospheric Technician
mask = /obj/item/clothing/mask/gas
suit = /obj/item/clothing/suit/space/hardsuit/engine/atmos
suit_store = /obj/item/tank/internals/oxygen
- internals_slot = slot_s_store
+ internals_slot = SLOT_S_STORE
diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/job.dm
index 65ac5ea0d8..156e975a65 100644
--- a/code/modules/jobs/job_types/job.dm
+++ b/code/modules/jobs/job_types/job.dm
@@ -151,7 +151,7 @@
var/duffelbag = /obj/item/storage/backpack/duffelbag
var/box = /obj/item/storage/box/survival
- var/pda_slot = slot_belt
+ var/pda_slot = SLOT_BELT
/datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
switch(H.backbag)
diff --git a/code/modules/jobs/job_types/science.dm b/code/modules/jobs/job_types/science.dm
index d2f77319fc..b82a5d85d2 100644
--- a/code/modules/jobs/job_types/science.dm
+++ b/code/modules/jobs/job_types/science.dm
@@ -56,7 +56,7 @@ Research Director
mask = /obj/item/clothing/mask/breath
suit = /obj/item/clothing/suit/space/hardsuit/rd
suit_store = /obj/item/tank/internals/oxygen
- internals_slot = slot_s_store
+ internals_slot = SLOT_S_STORE
/*
Scientist
@@ -128,4 +128,4 @@ Roboticist
backpack = /obj/item/storage/backpack/science
satchel = /obj/item/storage/backpack/satchel/tox
- pda_slot = slot_l_store
+ pda_slot = SLOT_L_STORE
diff --git a/code/modules/jobs/job_types/security.dm b/code/modules/jobs/job_types/security.dm
index cc842d8e59..6295e9964e 100644
--- a/code/modules/jobs/job_types/security.dm
+++ b/code/modules/jobs/job_types/security.dm
@@ -244,7 +244,7 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S
if(ears)
if(H.ears)
qdel(H.ears)
- H.equip_to_slot_or_del(new ears(H),slot_ears)
+ H.equip_to_slot_or_del(new ears(H),SLOT_EARS)
var/obj/item/card/id/W = H.wear_id
W.access |= dep_access
diff --git a/code/modules/keybindings/bindings_human.dm b/code/modules/keybindings/bindings_human.dm
index 7c52917386..14890cc7e2 100644
--- a/code/modules/keybindings/bindings_human.dm
+++ b/code/modules/keybindings/bindings_human.dm
@@ -3,12 +3,12 @@
switch(_key)
if("E") // Put held thing in belt or take out most recent thing from belt
var/obj/item/thing = get_active_held_item()
- var/obj/item/storage/equipped_belt = get_item_by_slot(slot_belt)
+ var/obj/item/storage/equipped_belt = get_item_by_slot(SLOT_BELT)
if(!equipped_belt) // We also let you equip a belt like this
if(!thing)
to_chat(user, "You have no belt to take something out of.")
return
- equip_to_slot_if_possible(thing, slot_belt)
+ equip_to_slot_if_possible(thing, SLOT_BELT)
return
if(!istype(equipped_belt)) // not a storage item
if(!thing)
@@ -31,12 +31,12 @@
if("B") // Put held thing in backpack or take out most recent thing from backpack
var/obj/item/thing = get_active_held_item()
- var/obj/item/storage/equipped_backpack = get_item_by_slot(slot_back)
+ var/obj/item/storage/equipped_backpack = get_item_by_slot(SLOT_BACK)
if(!equipped_backpack) // We also let you equip a backpack like this
if(!thing)
to_chat(user, "You have no backpack to take something out of.")
return
- equip_to_slot_if_possible(thing, slot_back)
+ equip_to_slot_if_possible(thing, SLOT_BACK)
return
if(!istype(equipped_backpack)) // not a storage item
if(!thing)
diff --git a/code/modules/keybindings/readme.md b/code/modules/keybindings/readme.md
index 1170804436..6c0369d7c7 100644
--- a/code/modules/keybindings/readme.md
+++ b/code/modules/keybindings/readme.md
@@ -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
diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm
index 5f2e9963e7..8b9cc09dff 100644
--- a/code/modules/language/language.dm
+++ b/code/modules/language/language.dm
@@ -35,7 +35,8 @@
return TRUE
/datum/language/proc/get_icon()
- return "[icon2html(icon, world, icon_state)]"
+ var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat)
+ return sheet.icon_tag("language-[icon_state]")
/datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2)
if(!syllables || !syllables.len)
diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm
index 0bfb0b5f6d..61d439667d 100644
--- a/code/modules/mining/equipment/explorer_gear.dm
+++ b/code/modules/mining/equipment/explorer_gear.dm
@@ -25,11 +25,19 @@
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
resistance_flags = FIRE_PROOF
+/obj/item/clothing/suit/hooded/explorer/Initialize()
+ . = ..()
+ AddComponent(/datum/component/armor_plate)
+
+/obj/item/clothing/head/hooded/explorer/Initialize()
+ . = ..()
+ AddComponent(/datum/component/armor_plate)
+
/obj/item/clothing/mask/gas/explorer
name = "explorer gas mask"
desc = "A military-grade gas mask that can be connected to an air supply."
icon_state = "gas_mining"
- visor_flags = BLOCK_GAS_SMOKE_EFFECT_1 | MASKINTERNALS_1
+ visor_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS
visor_flags_inv = HIDEFACIALHAIR
visor_flags_cover = MASKCOVERSMOUTH
actions_types = list(/datum/action/item_action/adjust)
@@ -52,7 +60,7 @@
desc = "Hostile Environment Cross-Kinetic Suit: A suit designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner."
icon_state = "hostile_env"
item_state = "hostile_env"
- flags_1 = THICKMATERIAL_1 //not spaceproof
+ clothing_flags = THICKMATERIAL //not spaceproof
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | LAVA_PROOF
slowdown = 0
@@ -84,7 +92,7 @@
item_state = "hostile_env"
w_class = WEIGHT_CLASS_NORMAL
max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT
- flags_1 = THICKMATERIAL_1 // no space protection
+ clothing_flags = THICKMATERIAL // no space protection
armor = list("melee" = 70, "bullet" = 40, "laser" = 10, "energy" = 10, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
resistance_flags = FIRE_PROOF | LAVA_PROOF
@@ -106,4 +114,3 @@
var/mutable_appearance/M = mutable_appearance('icons/mob/head.dmi', "hostile_env_glass")
M.appearance_flags = RESET_COLOR
. += M
-
diff --git a/code/modules/mining/equipment/goliath_hide.dm b/code/modules/mining/equipment/goliath_hide.dm
index b266b92584..85feaecf73 100644
--- a/code/modules/mining/equipment/goliath_hide.dm
+++ b/code/modules/mining/equipment/goliath_hide.dm
@@ -9,38 +9,4 @@
novariants = FALSE
flags_1 = NOBLUDGEON_1
w_class = WEIGHT_CLASS_NORMAL
- layer = MOB_LAYER
- var/static/list/goliath_platable_armor_typecache = typecacheof(list(
- /obj/item/clothing/head/helmet/space/hardsuit/mining,
- /obj/item/clothing/suit/space/hardsuit/mining,
- /obj/item/clothing/head/hooded/explorer,
- /obj/item/clothing/suit/hooded/explorer))
-
-/obj/item/stack/sheet/animalhide/goliath_hide/afterattack(atom/target, mob/user, proximity_flag)
- if(!proximity_flag)
- return
- if(is_type_in_typecache(target, goliath_platable_armor_typecache))
- var/obj/item/clothing/C = target
- if(C.armor.melee < 60)
- C.armor = C.armor.setRating(melee = min(C.armor.melee + 10, 60))
- to_chat(user, "You strengthen [target], improving its resistance against melee attacks.")
- use(1)
- else
- to_chat(user, "You can't improve [C] any further!")
- else if(istype(target, /obj/mecha/working/ripley))
- var/obj/mecha/working/ripley/D = target
- if(D.hides < 3)
- D.hides++
- D.armor = D.armor.setRating(\
- melee = min(D.armor.melee + 10, 70),\
- bullet = min(D.armor.bullet + 5, 50),\
- laser = min(D.armor.laser + 5, 50))
- to_chat(user, "You strengthen [target], improving its resistance against melee attacks.")
- D.update_icon()
- if(D.hides == 3)
- D.desc = "Autonomous Power Loader Unit. It's wearing a fearsome carapace entirely composed of goliath hide plates - its pilot must be an experienced monster hunter."
- else
- D.desc = "Autonomous Power Loader Unit. Its armour is enhanced with some goliath hide plates."
- use(1)
- else
- to_chat(user, "You can't improve [D] any further!")
+ layer = MOB_LAYER
\ No newline at end of file
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index 5b86a2d340..558147af23 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -10,7 +10,7 @@
While it is an effective mining tool, it did little to aid any but the most skilled and/or suicidal miners against local fauna."
force = 20 //As much as a bone spear, but this is significantly more annoying to carry around due to requiring the use of both hands at all times
w_class = WEIGHT_CLASS_BULKY
- slot_flags = SLOT_BACK
+ slot_flags = ITEM_SLOT_BACK
force_unwielded = 20 //It's never not wielded so these are the same
force_wielded = 20
throwforce = 5
diff --git a/code/modules/mining/equipment/mineral_scanner.dm b/code/modules/mining/equipment/mineral_scanner.dm
index 7327b0c314..d7cdba8f7b 100644
--- a/code/modules/mining/equipment/mineral_scanner.dm
+++ b/code/modules/mining/equipment/mineral_scanner.dm
@@ -8,7 +8,7 @@
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
w_class = WEIGHT_CLASS_SMALL
flags_1 = CONDUCT_1
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
var/cooldown = 35
var/current_cooldown = 0
@@ -37,7 +37,7 @@
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
w_class = WEIGHT_CLASS_SMALL
flags_1 = CONDUCT_1
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
var/cooldown = 35
var/current_cooldown = 0
var/range = 7
diff --git a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm
index e73349198b..cbd8717869 100644
--- a/code/modules/mining/equipment/mining_tools.dm
+++ b/code/modules/mining/equipment/mining_tools.dm
@@ -4,7 +4,7 @@
icon = 'icons/obj/mining.dmi'
icon_state = "pickaxe"
flags_1 = CONDUCT_1
- slot_flags = SLOT_BELT | SLOT_BACK
+ slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
force = 15
throwforce = 10
item_state = "pickaxe"
@@ -30,7 +30,7 @@
icon_state = "minipick"
force = 10
throwforce = 7
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_NORMAL
materials = list(MAT_METAL=1000)
@@ -54,7 +54,7 @@
name = "mining drill"
icon_state = "handdrill"
item_state = "jackhammer"
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
toolspeed = 0.6 //available from roundstart, faster than a pickaxe.
usesound = 'sound/weapons/drill.ogg'
hitsound = 'sound/weapons/drill.ogg'
@@ -93,7 +93,7 @@
lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi'
flags_1 = CONDUCT_1
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
force = 8
tool_behaviour = TOOL_SHOVEL
toolspeed = 1
diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm
index 0737612211..b8ae25a87a 100644
--- a/code/modules/mining/equipment/wormhole_jaunter.dm
+++ b/code/modules/mining/equipment/wormhole_jaunter.dm
@@ -11,7 +11,7 @@
w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 5
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
/obj/item/wormhole_jaunter/attack_self(mob/user)
user.visible_message("[user.name] activates the [src.name]!")
@@ -53,7 +53,7 @@
/obj/item/wormhole_jaunter/emp_act(power)
var/triggered = FALSE
- if(usr.get_item_by_slot(slot_belt) == src)
+ if(usr.get_item_by_slot(SLOT_BELT) == src)
if(power == 1)
triggered = TRUE
else if(power == 2 && prob(50))
@@ -65,8 +65,8 @@
activate(usr)
/obj/item/wormhole_jaunter/proc/chasm_react(mob/user)
- if(user.get_item_by_slot(slot_belt) == src)
- to_chat(user, "Your [src] activates, saving you from the chasm!")
+ if(user.get_item_by_slot(SLOT_BELT) == src)
+ to_chat(user, "Your [name] activates, saving you from the chasm!")
SSblackbox.record_feedback("tally", "jaunter", 1, "Chasm") // chasm automatic activation
activate(user, FALSE)
else
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 27cc6c7450..272a66766e 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -438,7 +438,7 @@
desc = "Somehow, it's in two places at once."
icon = 'icons/obj/storage.dmi'
icon_state = "cultpack"
- slot_flags = SLOT_BACK
+ slot_flags = ITEM_SLOT_BACK
resistance_flags = INDESTRUCTIBLE
/obj/item/shared_storage/red
@@ -558,7 +558,7 @@
inhand_y_dimension = 64
icon_state = "cleaving_saw"
icon_state_on = "cleaving_saw_open"
- slot_flags = SLOT_BELT
+ slot_flags = ITEM_SLOT_BELT
attack_verb_off = list("attacked", "sawed", "sliced", "torn", "ripped", "diced", "cut")
attack_verb_on = list("cleaved", "swiped", "slashed", "chopped")
hitsound = 'sound/weapons/bladeslice.ogg'
@@ -816,7 +816,7 @@
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
icon = 'icons/obj/guns/magic.dmi'
- slot_flags = SLOT_BACK
+ slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
force = 25
damtype = BURN
@@ -993,7 +993,7 @@
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
inhand_x_dimension = 64
inhand_y_dimension = 64
- slot_flags = SLOT_BACK
+ slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
force = 15
attack_verb = list("clubbed", "beat", "pummeled")
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm
index bb5347a152..c7ba9ad6f4 100644
--- a/code/modules/mining/machine_processing.dm
+++ b/code/modules/mining/machine_processing.dm
@@ -84,7 +84,7 @@
/obj/machinery/mineral/processing_unit/Initialize()
. = ..()
proximity_monitor = new(src, 1)
- AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE), INFINITY)
+ AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE), INFINITY, FALSE, list(/obj/item/stack))
stored_research = new /datum/techweb/specialized/autounlocking/smelter
/obj/machinery/mineral/processing_unit/Destroy()
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index 63e00f5a38..d4735d1c75 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -28,7 +28,7 @@
/obj/machinery/mineral/ore_redemption/Initialize()
. = ..()
- AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE),INFINITY)
+ AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE),INFINITY, FALSE, list(/obj/item/stack))
stored_research = new /datum/techweb/specialized/autounlocking/smelter
/obj/machinery/mineral/ore_redemption/Destroy()
@@ -303,13 +303,12 @@
desired = input("How many sheets?", "How many sheets would you like to smelt?", 1) as null|num
var/amount = round(min(desired,50,smelt_amount))
materials.use_amount(alloy.materials, amount)
- var/output = new alloy.build_path(src)
- if(istype(output, /obj/item/stack/sheet))
- var/obj/item/stack/sheet/produced_alloy = output
- produced_alloy.amount = amount
- unload_mineral(produced_alloy)
+ var/output
+ if(ispath(alloy.build_path, /obj/item/stack/sheet))
+ output = new alloy.build_path(src, amount)
else
- unload_mineral(output)
+ output = new alloy.build_path(src)
+ unload_mineral(output)
else
to_chat(usr, "Required access not found.")
return TRUE
diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm
index e658f69395..0f84d11082 100644
--- a/code/modules/mining/machine_stacking.dm
+++ b/code/modules/mining/machine_stacking.dm
@@ -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, "[src] is not linked to a machine!")
+ 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, "You store linkage information in [I]'s buffer.")
+ return TRUE
+
/obj/machinery/mineral/stacking_unit_console/Topic(href, href_list)
if(..())
return
@@ -44,8 +54,7 @@
if(!(text2path(href_list["release"]) in machine.stack_list))
return //someone tried to spawn materials by spoofing hrefs
var/obj/item/stack/sheet/inp = machine.stack_list[text2path(href_list["release"])]
- var/obj/item/stack/sheet/out = new inp.type()
- out.amount = inp.amount
+ var/obj/item/stack/sheet/out = new inp.type(null, inp.amount)
inp.amount = 0
machine.unload_mineral(out)
@@ -63,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()
@@ -79,16 +89,26 @@
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, "The [I] has no linkage data in its buffer.")
+ return FALSE
+ else
+ CONSOLE = M.buffer
+ CONSOLE.machine = src
+ to_chat(user, "You link [src] to the console in [I]'s buffer.")
+ 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)
- s.amount = 0
+ var/obj/item/stack/sheet/s = new inp.type(src, 0)
stack_list[inp.type] = s
var/obj/item/stack/sheet/storage = stack_list[inp.type]
storage.amount += inp.amount //Stack the sheets
qdel(inp) //Let the old sheet garbage collect
while(storage.amount > stack_amt) //Get rid of excessive stackage
- var/obj/item/stack/sheet/out = new inp.type()
- out.amount = stack_amt
+ var/obj/item/stack/sheet/out = new inp.type(null, stack_amt)
unload_mineral(out)
storage.amount -= stack_amt
diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm
index ec4c9bd714..b7cc0db43f 100644
--- a/code/modules/mining/mint.dm
+++ b/code/modules/mining/mint.dm
@@ -16,7 +16,7 @@
/obj/machinery/mineral/mint/Initialize()
. = ..()
- AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_PLASMA, MAT_SILVER, MAT_GOLD, MAT_URANIUM, MAT_DIAMOND, MAT_BANANIUM), MINERAL_MATERIAL_AMOUNT * 50)
+ AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_PLASMA, MAT_SILVER, MAT_GOLD, MAT_URANIUM, MAT_DIAMOND, MAT_BANANIUM), MINERAL_MATERIAL_AMOUNT * 50, FALSE, list(/obj/item/stack))
/obj/machinery/mineral/mint/process()
var/turf/T = get_step(src, input_dir)
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 01ac36c57a..9de78d307d 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -234,6 +234,7 @@
if(POLLTYPE_IRV)
if (!href_list["IRVdata"])
to_chat(src, "No ordering data found. Please try again or contact an administrator.")
+ return
var/list/votelist = splittext(href_list["IRVdata"], ",")
if (!vote_on_irv_poll(pollid, votelist))
to_chat(src, "Vote failed, please try again or contact an administrator.")
@@ -400,7 +401,7 @@
SSticker.mode.make_antag_chance(humanc)
if(humanc && CONFIG_GET(flag/roundstart_traits))
- SStraits.AssignTraits(humanc, humanc.client, TRUE)
+ SSquirks.AssignQuirks(humanc, humanc.client, TRUE)
log_manifest(character.mind.key,character.mind,character,latejoin = TRUE)
diff --git a/code/modules/mob/dead/new_player/poll.dm b/code/modules/mob/dead/new_player/poll.dm
index d10e32a887..ce710e5186 100644
--- a/code/modules/mob/dead/new_player/poll.dm
+++ b/code/modules/mob/dead/new_player/poll.dm
@@ -211,7 +211,7 @@
src << browse(null ,"window=playerpolllist")
src << browse(output,"window=playerpoll;size=500x250")
if(POLLTYPE_IRV)
- var/datum/asset/irv_assets = get_asset_datum(/datum/asset/simple/IRV)
+ var/datum/asset/irv_assets = get_asset_datum(/datum/asset/group/IRV)
irv_assets.send(src)
var/datum/DBQuery/query_irv_get_votes = SSdbcore.NewQuery("SELECT optionid FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[ckey]'")
@@ -267,7 +267,7 @@
-
+
"}
- var/dat = "[station_name()] Stock Exchange[css]"
-
- dat += "Welcome, [station_name()] Cargo Department Credits: [balance()] "
- for (var/datum/stock/S in GLOB.stockExchange.last_read)
- var/list/LR = GLOB.stockExchange.last_read[S]
- if (!(logged_in in LR))
- LR[logged_in] = 0
- dat += "View mode:[vmode ? "Compact" : "Full"] "
- dat += "Stock Transaction Log:Check "
-
- dat += "This is a work in progress. Certain features may not be available."
-
- dat += "
Listed stocks
"
-
- if (vmode == 0)
- for (var/datum/stock/S in GLOB.stockExchange.stocks)
- var/mystocks = 0
- if (logged_in && (logged_in in S.shareholders))
- mystocks = S.shareholders[logged_in]
- dat += "
[S.name]([S.short_name])[S.bankrupt ? " BANKRUPT" : null] "
- if (S.last_unification)
- dat += "Unified shares [DisplayTimeText(world.time - S.last_unification)] ago. "
- dat += "Current value per share: [S.current_value] | View history
"
- dat += "You currently own [mystocks] shares in this company. There are [S.available_shares] purchasable shares on the market currently. "
- if (S.bankrupt)
- dat += "You cannot buy or sell shares in a bankrupt company!