"
@@ -115,8 +123,9 @@
if(QDELETED(M))
selected_mobs -= i
continue
- dat += "
"
@@ -142,9 +151,9 @@
// Search results
var/tdStyleTime = "width:80px; text-align:center;"
var/tdStyleType = "width:80px; text-align:center;"
- var/tdStyleWho = "width:300px; text-align:center;"
+ var/tdStyleWho = "width:400px; text-align:center;"
var/tdStyleWhere = "width:150px; text-align:center;"
- dat += "
"
+ dat += "
"
dat += "
"
dat += "| When | Type | Who | What | Target | Where |
"
for(var/i in log_records)
@@ -158,7 +167,7 @@
dat += "
"
dat += "
"
- var/datum/browser/popup = new(user, "Log viewer", "Log viewer", 1400, 600)
+ var/datum/browser/popup = new(user, "Log Viewer", "Log Viewer", 1500, 600)
popup.set_content(dat)
popup.open()
@@ -203,6 +212,11 @@
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a mob: ", mobs)
A.on_close(CALLBACK(src, .proc/add_mob, usr))
return
+ if(href_list["add_mob_ckey"])
+ var/list/mobs = get_assoc_mob_list_by_ckey()
+ var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a ckey: ", mobs)
+ A.on_close(CALLBACK(src, .proc/add_mob, usr))
+ return
if(href_list["remove_mob"])
var/mob/M = locate(href_list["remove_mob"])
if(M)
@@ -233,3 +247,11 @@
if(MISC_LOG)
return "gray"
return "slategray"
+
+/datum/log_viewer/proc/get_display_name(mob/M)
+ var/name = M.name
+ if(M.name != M.real_name)
+ name = "[name] ([M.real_name])"
+ if(isobserver(M))
+ name = "[name] (DEAD)"
+ return name
diff --git a/code/game/gamemodes/blob/blob_report.dm b/code/game/gamemodes/blob/blob_report.dm
index 9c7fb99fe81..8f6ba965222 100644
--- a/code/game/gamemodes/blob/blob_report.dm
+++ b/code/game/gamemodes/blob/blob_report.dm
@@ -18,7 +18,7 @@
intercepttext += "
Note in the event of a quarantine breach or uncontrolled spread of the biohazard, the directive 7-10 may be upgraded to a directive 7-12.
"
intercepttext += "Message ends."
if(2)
- var/nukecode = rand(10000, 99999)
+ var/nukecode = "[rand(10000, 99999)]"
for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
if(bomb && bomb.r_code)
if(is_station_level(bomb.z))
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 5fed8ae00f4..8316364781b 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -53,7 +53,6 @@ proc/issyndicate(mob/living/M as mob)
for(var/datum/mind/synd_mind in syndicates)
synd_mind.assigned_role = SPECIAL_ROLE_NUKEOPS //So they aren't chosen for other jobs.
synd_mind.special_role = SPECIAL_ROLE_NUKEOPS
- synd_mind.offstation_role = TRUE
return 1
@@ -113,7 +112,7 @@ proc/issyndicate(mob/living/M as mob)
if(spawnpos > synd_spawn.len)
spawnpos = 2
synd_mind.current.loc = synd_spawn[spawnpos]
-
+ synd_mind.offstation_role = TRUE
forge_syndicate_objectives(synd_mind)
create_syndicate(synd_mind)
greet_syndicate(synd_mind)
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 36196ea4eca..2e0c4c54375 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -302,6 +302,7 @@
// Eject dead people
if(occupant.stat == DEAD)
go_out()
+ return
// Allow a gap between entering the pod and actually despawning.
if(world.time - time_entered < time_till_despawn)
diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm
index 5916d0f96c7..2248c37f518 100644
--- a/code/game/mecha/equipment/tools/mining_tools.dm
+++ b/code/game/mecha/equipment/tools/mining_tools.dm
@@ -94,7 +94,7 @@
/obj/item/mecha_parts/mecha_equipment/drill/proc/drill_mob(mob/living/target, mob/user)
target.visible_message("
[chassis] is drilling [target] with [src]!",
"
[chassis] is drilling you with [src]!")
- add_attack_logs(user, target, "DRILLED with [src] (INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
+ add_attack_logs(user, target, "DRILLED with [src] ([uppertext(user.a_intent)]) ([uppertext(damtype)])")
if(target.stat == DEAD && target.getBruteLoss() >= 200)
add_attack_logs(user, target, "gibbed")
if(LAZYLEN(target.butcher_results))
diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm
index 63eeb21e165..5962a1eccbb 100644
--- a/code/game/mecha/equipment/tools/work_tools.dm
+++ b/code/game/mecha/equipment/tools/work_tools.dm
@@ -60,7 +60,7 @@
target.visible_message("
[chassis] squeezes [target].", \
"
[chassis] squeezes [target].",\
"
You hear something crack.")
- add_attack_logs(chassis.occupant, M, "Squeezed with [src] (INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYE: [uppertext(damtype)])")
+ add_attack_logs(chassis.occupant, M, "Squeezed with [src] ([uppertext(chassis.occupant.a_intent)]) ([uppertext(damtype)])")
start_cooldown()
else
step_away(M,chassis)
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 1dc09d13e63..540e1074844 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -870,7 +870,7 @@
return 0
use_power(melee_energy_drain)
if(M.damtype == BRUTE || M.damtype == BURN)
- add_attack_logs(M.occupant, src, "Mecha-attacked with [M] (INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])")
+ add_attack_logs(M.occupant, src, "Mecha-attacked with [M] ([uppertext(M.occupant.a_intent)]) ([uppertext(M.damtype)])")
. = ..()
/obj/mecha/emag_act(mob/user)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 76361776b0a..baaf0cab16b 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -506,7 +506,7 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
"
You stab yourself in the eyes with [src]!" \
)
- add_attack_logs(user, M, "Eye-stabbed with [src] (INTENT: [uppertext(user.a_intent)])")
+ add_attack_logs(user, M, "Eye-stabbed with [src] ([uppertext(user.a_intent)])")
if(istype(H))
var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes)
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 7cf09199cfd..b497bc518b0 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -411,11 +411,16 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
jobname = "Unknown"
voicemask = TRUE
+ // Copy the message pieces so we can safely edit comms line without affecting the actual line
+ var/list/message_pieces_copy = list()
+ for(var/datum/multilingual_say_piece/S in message_pieces)
+ message_pieces_copy += new /datum/multilingual_say_piece(S.speaking, S.message)
+
// Make us a message datum!
var/datum/tcomms_message/tcm = new
tcm.sender_name = displayname
tcm.sender_job = jobname
- tcm.message_pieces = message_pieces
+ tcm.message_pieces = message_pieces_copy
tcm.source_level = position.z
tcm.freq = connection.frequency
tcm.vmask = voicemask
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index eae59151a38..f1487a09986 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -29,7 +29,7 @@
"
[user] has prodded you with [src]!")
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
- add_attack_logs(user, M, "Stunned with [src] (INTENT: [uppertext(user.a_intent)])")
+ add_attack_logs(user, M, "Stunned with [src] ([uppertext(user.a_intent)])")
/obj/item/borg/overdrive
name = "Overdrive"
diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm
index 4ff769a7d3f..1e22015bc97 100644
--- a/code/game/objects/items/weapons/storage/firstaid.dm
+++ b/code/game/objects/items/weapons/storage/firstaid.dm
@@ -205,7 +205,7 @@
if(empty)
return
new /obj/item/reagent_containers/hypospray/combat(src)
- new /obj/item/reagent_containers/applicator/dual(src) // Because you ain't got no time to look at what damage dey taking yo
+ new /obj/item/reagent_containers/applicator/dual/syndi(src) // Because you ain't got no time to look at what damage dey taking yo
new /obj/item/defibrillator/compact/combat/loaded(src)
new /obj/item/clothing/glasses/hud/health/night(src)
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 5fea799ecb0..6d27b21e686 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -76,14 +76,14 @@
if(istype(W,/obj/item/stack/rods))
var/obj/item/stack/rods/S = W
if(state == GIRDER_DISPLACED)
- if(S.get_amount() < 2)
- to_chat(user, "
You need at least two rods to create a false wall!")
+ if(S.get_amount() < 5)
+ to_chat(user, "
You need at least five rods to create a false wall!")
return
to_chat(user, "
You start building a reinforced false wall...")
if(do_after(user, 20, target = src))
- if(!loc || !S || S.get_amount() < 2)
+ if(!loc || !S || S.get_amount() < 5)
return
- S.use(2)
+ S.use(5)
to_chat(user, "
You create a false wall. Push on it to open or close the passage.")
var/obj/structure/falsewall/iron/FW = new (loc)
transfer_fingerprints_to(FW)
diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm
index 9aab12234d2..293504919d4 100644
--- a/code/modules/admin/NewBan.dm
+++ b/code/modules/admin/NewBan.dm
@@ -103,7 +103,8 @@ GLOBAL_PROTECT(banlist_savefile) // Obvious reasons
GLOB.banlist_savefile.cd = "/base"
if( GLOB.banlist_savefile.dir.Find("[ckey][computerid]") )
- to_chat(usr, "
Ban already exists.")
+ if(usr)
+ to_chat(usr, "
Ban already exists.")
return 0
else
GLOB.banlist_savefile.dir.Add("[ckey][computerid]")
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 1eed8083a97..958dedae362 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -78,6 +78,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
body += " \[
Heal\] "
body += "
\[ "
+ body += "
LOGS - "
body += "
VV - "
body += "[ADMIN_TP(M,"TP")] - "
if(M.client)
diff --git a/code/modules/admin/sql_notes.dm b/code/modules/admin/sql_notes.dm
index a438a43eaec..04e28737479 100644
--- a/code/modules/admin/sql_notes.dm
+++ b/code/modules/admin/sql_notes.dm
@@ -2,7 +2,8 @@
if(checkrights && !check_rights(R_ADMIN|R_MOD))
return
if(!GLOB.dbcon.IsConnected())
- to_chat(usr, "
Failed to establish database connection.")
+ if(usr)
+ to_chat(usr, "
Failed to establish database connection.")
return
if(!target_ckey)
@@ -19,7 +20,8 @@
log_game("SQL ERROR obtaining ckey from player table. Error : \[[err]\]\n")
return
if(!query_find_ckey.NextRow())
- to_chat(usr, "
[target_ckey] has not been seen before, you can only add notes to known players.")
+ if(usr)
+ to_chat(usr, "
[target_ckey] has not been seen before, you can only add notes to known players.")
return
var/exp_data = query_find_ckey.item[2]
@@ -52,8 +54,8 @@
log_game("SQL ERROR adding new note to table. Error : \[[err]\]\n")
return
if(logged)
- log_admin("[key_name(usr)] has added a note to [target_ckey]: [notetext]")
- message_admins("[key_name_admin(usr)] has added a note to [target_ckey]:
[notetext]")
+ log_admin("[usr ? key_name(usr) : adminckey] has added a note to [target_ckey]: [notetext]")
+ message_admins("[usr ? key_name_admin(usr) : adminckey] has added a note to [target_ckey]:
[notetext]")
show_note(target_ckey)
/proc/remove_note(note_id)
@@ -63,7 +65,8 @@
var/notetext
var/adminckey
if(!GLOB.dbcon.IsConnected())
- to_chat(usr, "
Failed to establish database connection.")
+ if(usr)
+ to_chat(usr, "
Failed to establish database connection.")
return
if(!note_id)
return
@@ -82,15 +85,16 @@
var/err = query_del_note.ErrorMsg()
log_game("SQL ERROR removing note from table. Error : \[[err]\]\n")
return
- log_admin("[key_name(usr)] has removed a note made by [adminckey] from [ckey]: [notetext]")
- message_admins("[key_name_admin(usr)] has removed a note made by [adminckey] from [ckey]:
[notetext]")
+ log_admin("[usr ? key_name(usr) : "Bot"] has removed a note made by [adminckey] from [ckey]: [notetext]")
+ message_admins("[usr ? key_name_admin(usr) : "Bot"] has removed a note made by [adminckey] from [ckey]:
[notetext]")
show_note(ckey)
/proc/edit_note(note_id)
if(!check_rights(R_ADMIN|R_MOD))
return
if(!GLOB.dbcon.IsConnected())
- to_chat(usr, "
Failed to establish database connection.")
+ if(usr)
+ to_chat(usr, "
Failed to establish database connection.")
return
if(!note_id)
return
@@ -117,8 +121,8 @@
var/err = query_update_note.ErrorMsg()
log_game("SQL ERROR editing note. Error : \[[err]\]\n")
return
- log_admin("[key_name(usr)] has edited [target_ckey]'s note made by [adminckey] from \"[old_note]\" to \"[new_note]\"")
- message_admins("[key_name_admin(usr)] has edited [target_ckey]'s note made by [adminckey] from \"[old_note]\" to \"[new_note]\"")
+ log_admin("[usr ? key_name(usr) : "Bot"] has edited [target_ckey]'s note made by [adminckey] from \"[old_note]\" to \"[new_note]\"")
+ message_admins("[usr ? key_name_admin(usr) : "Bot"] has edited [target_ckey]'s note made by [adminckey] from \"[old_note]\" to \"[new_note]\"")
show_note(target_ckey)
/proc/show_note(target_ckey, index, linkless = 0)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 19bbc40ba25..1d2c75aff0a 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -911,6 +911,11 @@
//M.client = null
qdel(M.client)
+ else if(href_list["open_logging_view"])
+ var/mob/M = locateUID(href_list["open_logging_view"])
+ if(ismob(M))
+ usr.client.open_logging_view(list(M), TRUE)
+
//Player Notes
else if(href_list["addnote"])
var/target_ckey = href_list["addnote"]
diff --git a/code/modules/admin/verbs/logging_view.dm b/code/modules/admin/verbs/logging_view.dm
index 903926f4923..cafaab8f1d7 100644
--- a/code/modules/admin/verbs/logging_view.dm
+++ b/code/modules/admin/verbs/logging_view.dm
@@ -2,10 +2,20 @@ GLOBAL_LIST_INIT(open_logging_views, list())
/client/proc/cmd_admin_open_logging_view()
set category = "Admin"
- set name = "Open Logging View"
+ set name = "Logging View"
set desc = "Opens the detailed logging viewer"
+ open_logging_view()
- if(!GLOB.open_logging_views[usr.client.ckey])
- GLOB.open_logging_views[usr.client.ckey] = new /datum/log_viewer()
- var/datum/log_viewer/LV = GLOB.open_logging_views[usr.client.ckey]
- LV.show_ui(usr)
+/client/proc/open_logging_view(list/mob/mobs_to_add = null, clear_view = FALSE)
+ var/datum/log_viewer/cur_view = GLOB.open_logging_views[usr.client.ckey]
+ if(!cur_view)
+ cur_view = new /datum/log_viewer()
+ GLOB.open_logging_views[usr.client.ckey] = cur_view
+ else if(clear_view)
+ cur_view.clear_all()
+
+ if(mobs_to_add?.len)
+ cur_view.add_mobs(mobs_to_add)
+
+ cur_view.show_ui(usr)
+
diff --git a/code/modules/client/preference/loadout/loadout_accessories.dm b/code/modules/client/preference/loadout/loadout_accessories.dm
index 8805c6dd9a9..b9318fd9e8c 100644
--- a/code/modules/client/preference/loadout/loadout_accessories.dm
+++ b/code/modules/client/preference/loadout/loadout_accessories.dm
@@ -154,9 +154,6 @@
display_name = "corset, blue"
path = /obj/item/clothing/accessory/corset/blue
-/datum/gear/accessory/armband/job
- subtype_path = /datum/gear/accessory/armband/job
- subtype_cost_overlap = FALSE
/datum/gear/accessory/armband_red
display_name = "armband"
@@ -166,41 +163,41 @@
display_name = "armband, blue-yellow"
path = /obj/item/clothing/accessory/armband/yb
-/datum/gear/accessory/armband/job/sec
+/datum/gear/accessory/armband_job
+ subtype_path = /datum/gear/accessory/armband_job
+ subtype_cost_overlap = FALSE
+
+/datum/gear/accessory/armband_job/sec
display_name = " armband, security"
path = /obj/item/clothing/accessory/armband/sec
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Brig Physician", "Security Pod Pilot")
-/datum/gear/accessory/armband/job/cargo
+/datum/gear/accessory/armband_job/cargo
display_name = "cargo armband"
path = /obj/item/clothing/accessory/armband/cargo
allowed_roles = list("Quartermaster","Cargo Technician", "Shaft Miner")
-/datum/gear/accessory/armband/job/medical
+/datum/gear/accessory/armband_job/medical
display_name = "armband, medical"
path = /obj/item/clothing/accessory/armband/med
allowed_roles = list("Chief Medical Officer", "Medical Doctor", "Coroner", "Paramedic", "Brig Physician")
-/datum/gear/accessory/armband/job/emt
+/datum/gear/accessory/armband_job/emt
display_name = "armband, EMT"
path = /obj/item/clothing/accessory/armband/medgreen
allowed_roles = list("Paramedic", "Brig Physician")
-/datum/gear/accessory/armband/job/engineering
+/datum/gear/accessory/armband_job/engineering
display_name = "armband, engineering"
path = /obj/item/clothing/accessory/armband/engine
allowed_roles = list("Chief Engineer","Station Engineer", "Life Support Specialist")
-/datum/gear/accessory/armband/job/hydro
+/datum/gear/accessory/armband_job/hydro
display_name = "armband, hydroponics"
path = /obj/item/clothing/accessory/armband/hydro
allowed_roles = list("Botanist")
-/datum/gear/accessory/armband/job/sci
+/datum/gear/accessory/armband_job/sci
display_name = "armband, science"
path = /obj/item/clothing/accessory/armband/science
allowed_roles = list("Research Director","Scientist", "Roboticist")
-
-
-
-
diff --git a/code/modules/client/preference/loadout/loadout_hat.dm b/code/modules/client/preference/loadout/loadout_hat.dm
index 758e70f654f..4993c8502ea 100644
--- a/code/modules/client/preference/loadout/loadout_hat.dm
+++ b/code/modules/client/preference/loadout/loadout_hat.dm
@@ -108,50 +108,47 @@
display_name = "cowboy hat, pink"
path = /obj/item/clothing/head/cowboyhat/pink
-//Berets Refactor
-//Defining all Job Berets as no-overlap
-//Somehow this doesn't break the DB.
-/datum/gear/hat/beret/job
- subtype_path = /datum/gear/hat/beret/job
- subtype_cost_overlap = FALSE
-
-/datum/gear/hat/beret/purple
+/datum/gear/hat/beret_purple
display_name = "beret, purple"
path = /obj/item/clothing/head/beret/purple_normal
-/datum/gear/hat/beret/black
+/datum/gear/hat/beret_black
display_name = "beret, black"
path = /obj/item/clothing/head/beret/black
-/datum/gear/hat/beret/blue
+/datum/gear/hat/beret_blue
display_name = "beret, blue"
path = /obj/item/clothing/head/beret/blue
-/datum/gear/hat/beret/red
+/datum/gear/hat/beret_red
display_name = "beret, red"
path = /obj/item/clothing/head/beret
-/datum/gear/hat/beret/job/sec
+/datum/gear/hat/beret_job
+ subtype_path = /datum/gear/hat/beret_job
+ subtype_cost_overlap = FALSE
+
+/datum/gear/hat/beret_job/sec
display_name = "security beret"
path = /obj/item/clothing/head/beret/sec
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot")
-/datum/gear/hat/beret/job/sci
+/datum/gear/hat/beret_job/sci
display_name = "science beret"
path = /obj/item/clothing/head/beret/sci
allowed_roles = list("Research Director", "Scientist")
-/datum/gear/hat/beret/job/med
+/datum/gear/hat/beret_job/med
display_name = "medical beret"
path = /obj/item/clothing/head/beret/med
allowed_roles = list("Chief Medical Officer", "Medical Doctor" , "Virologist", "Brig Physician" , "Coroner")
-/datum/gear/hat/beret/job/eng
+/datum/gear/hat/beret_job/eng
display_name = "engineering beret"
path = /obj/item/clothing/head/beret/eng
allowed_roles = list("Chief Engineer", "Station Engineer")
-/datum/gear/hat/beret/job/atmos
+/datum/gear/hat/beret_job/atmos
display_name = "atmospherics beret"
path = /obj/item/clothing/head/beret/atmos
allowed_roles = list("Chief Engineer", "Life Support Specialist")
diff --git a/code/modules/events/mass_hallucination.dm b/code/modules/events/mass_hallucination.dm
index b8bde0a1a67..b8f45023a27 100644
--- a/code/modules/events/mass_hallucination.dm
+++ b/code/modules/events/mass_hallucination.dm
@@ -6,6 +6,9 @@
var/mob/living/carbon/human/H = thing
if(H.stat == DEAD)
continue
+ var/turf/T = get_turf(H)
+ if(!is_station_level(T.z))
+ continue
var/armor = H.getarmor(type = "rad")
if((RADIMMUNE in H.dna.species.species_traits) || armor >= 75) // Leave radiation-immune species/rad armored players completely unaffected
continue
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index 905b629a0b9..21b99acb910 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -149,10 +149,12 @@ Gunshots/explosions/opening doors/less rare audio (done)
/obj/effect/hallucination/fake_flood/process()
if(!target)
qdel(src)
+ return
if(next_expand <= world.time)
radius++
if(radius > FAKE_FLOOD_MAX_RADIUS)
qdel(src)
+ return
Expand()
if((get_turf(target) in flood_turfs) && !target.internal)
target.hallucinate("fake_alert", "too_much_tox")
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index 5ad8a5f32f4..bad8813ea01 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -117,6 +117,7 @@
/obj/item/reagent_containers/food/snacks/grown/throw_impact(atom/hit_atom)
if(!..()) //was it caught by a mob?
if(seed)
+ log_action(thrownby, hit_atom, "Thrown [src] at")
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_throw_impact(src, hit_atom)
if(seed.get_gene(/datum/plant_gene/trait/squash))
@@ -147,11 +148,11 @@
qdel(src)
-/obj/item/reagent_containers/food/snacks/grown/On_Consume()
- if(iscarbon(usr))
+/obj/item/reagent_containers/food/snacks/grown/On_Consume(mob/M, mob/user)
+ if(iscarbon(M))
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_consume(src, usr)
+ T.on_consume(src, M)
..()
/obj/item/reagent_containers/food/snacks/grown/after_slip(mob/living/carbon/human/H)
@@ -190,3 +191,16 @@
else
return ..()
+/obj/item/reagent_containers/food/snacks/grown/proc/log_action(mob/user, atom/target, what_done)
+ var/reagent_str = reagents.log_list()
+ var/genes_str = "No genes"
+ if(seed && length(seed.genes))
+ var/list/plant_gene_names = list()
+ for(var/thing in seed.genes)
+ var/datum/plant_gene/G = thing
+ if(G.dangerous)
+ plant_gene_names += G.name
+ genes_str = english_list(plant_gene_names)
+
+ add_attack_logs(user, target, "[what_done] ([reagent_str] | [genes_str])")
+
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index a4c6fe7280d..c2f4914351c 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -1,5 +1,7 @@
/datum/plant_gene
var/name
+ /// Used to determine if the trait should be logged when the holder is used
+ var/dangerous = FALSE
/datum/plant_gene/proc/get_name() // Used for manipulator display and gene disk name.
return name
@@ -194,6 +196,7 @@
name = "Liquid Contents"
examine_line = "
It has a lot of liquid contents inside."
origin_tech = list("biotech" = 5)
+ dangerous = TRUE
/datum/plant_gene/trait/slip
// Makes plant slippery, unless it has a grown-type trash. Then the trash gets slippery.
@@ -201,6 +204,7 @@
name = "Slippery Skin"
rate = 0.1
examine_line = "
It has a very slippery skin."
+ dangerous = TRUE
/datum/plant_gene/trait/slip/on_new(obj/item/reagent_containers/food/snacks/grown/G, newloc)
. = ..()
@@ -224,6 +228,7 @@
name = "Electrical Activity"
rate = 0.2
origin_tech = list("powerstorage" = 5)
+ dangerous = TRUE
/datum/plant_gene/trait/cell_charge/on_slip(obj/item/reagent_containers/food/snacks/grown/G, mob/living/carbon/C)
var/power = G.seed.potency*rate
@@ -298,6 +303,7 @@
name = "Bluespace Activity"
rate = 0.1
origin_tech = list("bluespace" = 5)
+ dangerous = TRUE
/datum/plant_gene/trait/teleport/on_squash(obj/item/reagent_containers/food/snacks/grown/G, atom/target)
if(isliving(target))
@@ -385,6 +391,7 @@
/datum/plant_gene/trait/stinging
name = "Hypodermic Prickles"
+ dangerous = TRUE
/datum/plant_gene/trait/stinging/on_throw_impact(obj/item/reagent_containers/food/snacks/grown/G, atom/target)
if(isliving(target) && G.reagents && G.reagents.total_volume)
@@ -398,6 +405,7 @@
/datum/plant_gene/trait/smoke
name = "gaseous decomposition"
+ dangerous = TRUE
/datum/plant_gene/trait/smoke/on_squash(obj/item/reagent_containers/food/snacks/grown/G, atom/target)
var/datum/effect_system/smoke_spread/chem/S = new
diff --git a/code/modules/mining/lavaland/loot/ashdragon_loot.dm b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
index a0ea3eb7639..21bc247b0df 100644
--- a/code/modules/mining/lavaland/loot/ashdragon_loot.dm
+++ b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
@@ -120,18 +120,13 @@
return
var/mob/living/carbon/human/H = user
- var/random = rand(1,3)
+ var/random = rand(1,2)
switch(random)
if(1)
to_chat(user, "
Your flesh begins to melt! Miraculously, you seem fine otherwise.")
H.set_species(/datum/species/skeleton)
if(2)
- to_chat(user, "
Power courses through you! You can now shift your form at will.")
- if(user.mind)
- var/obj/effect/proc_holder/spell/targeted/shapeshift/dragon/D = new
- user.mind.AddSpell(D)
- if(3)
to_chat(user, "You feel like you could walk straight through lava now.")
H.weather_immunities |= "lava"
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index 10c2ac8f119..b69c13987b9 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -308,14 +308,14 @@
m_type = 1
if("bow", "bows")
- if(!buckled)
+ if(!restrained())
var/M = handle_emote_param(param)
message = "[src] bows[M ? " to [M]" : ""]."
m_type = 1
if("salute", "salutes")
- if(!buckled)
+ if(!restrained())
var/M = handle_emote_param(param)
message = "[src] salutes[M ? " to [M]" : ""]."
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index b38f1819524..1f0f1cfa0f4 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -113,7 +113,7 @@
var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].", I.armour_penetration)
apply_damage(I.throwforce, dtype, zone, armor, is_sharp(I), I)
if(I.thrownby)
- add_attack_logs(I.thrownby, src, "Hit with thrown [I]")
+ add_attack_logs(I.thrownby, src, "Hit with thrown [I]", !I.throwforce ? ATKLOG_ALMOSTALL : null) // Only message if the person gets damages
else
return 1
else
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index 3276416fe7f..3419279ffe5 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -95,6 +95,10 @@
for(var/mob/A in searched_for)
. += A
+// All bee sprites are made up of overlays. They do not have any special sprite overlays for items placed on them, such as collars, so this proc is unneeded.
+/mob/living/simple_animal/hostile/poison/bees/regenerate_icons()
+ return
+
/mob/living/simple_animal/hostile/poison/bees/proc/generate_bee_visuals()
overlays.Cut()
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index 80b10ab3a8b..bead9c935ef 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -127,6 +127,8 @@
/obj/singularity/narsie/proc/acquire(var/mob/food)
if(food == target)
return
+ if(!target)
+ return
to_chat(target, "[uppertext(SSticker.cultdat.entity_name)] HAS LOST INTEREST IN YOU")
target = food
if(ishuman(target))
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index f2740676314..abdf0305934 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -56,7 +56,6 @@
/datum/chemical_reaction/nitroglycerin
name = "Nitroglycerin"
id = "nitroglycerin"
- result = "nitroglycerin"
required_reagents = list("glycerol" = 1, "facid" = 1, "sacid" = 1)
result_amount = 2
diff --git a/code/modules/reagents/reagent_containers/applicator.dm b/code/modules/reagents/reagent_containers/applicator.dm
index 73c3c3759b1..962f12b4a08 100644
--- a/code/modules/reagents/reagent_containers/applicator.dm
+++ b/code/modules/reagents/reagent_containers/applicator.dm
@@ -5,6 +5,7 @@
icon_state = "mender"
item_state = "mender"
volume = 200
+ possible_transfer_amounts = null
resistance_flags = ACID_PROOF
container_type = REFILLABLE | AMOUNT_VISIBLE
temperature_min = 270
@@ -93,6 +94,20 @@
playsound(get_turf(src), pick('sound/goonstation/items/mender.ogg', 'sound/goonstation/items/mender2.ogg'), 50, 1)
+/obj/item/reagent_containers/applicator/verb/empty()
+ set name = "Empty Applicator"
+ set category = "Object"
+ set src in usr
+
+ if(usr.incapacitated())
+ return
+ if(alert(usr, "Are you sure you want to empty [src]?", "Empty Applicator:", "Yes", "No") != "Yes")
+ return
+ if(!usr.incapacitated() && isturf(usr.loc) && loc == usr)
+ to_chat(usr, "You empty [src] onto the floor.")
+ reagents.reaction(usr.loc)
+ reagents.clear_reagents()
+
/obj/item/reagent_containers/applicator/brute
name = "brute auto-mender"
list_reagents = list("styptic_powder" = 200)
@@ -104,3 +119,6 @@
/obj/item/reagent_containers/applicator/dual
name = "dual auto-mender"
list_reagents = list("synthflesh" = 200)
+
+/obj/item/reagent_containers/applicator/dual/syndi // It magically goes through hardsuits. Don't ask how.
+ ignore_flags = TRUE
diff --git a/code/modules/reagents/reagent_containers/glass_containers.dm b/code/modules/reagents/reagent_containers/glass_containers.dm
index 1e42899111b..175ae757df4 100644
--- a/code/modules/reagents/reagent_containers/glass_containers.dm
+++ b/code/modules/reagents/reagent_containers/glass_containers.dm
@@ -47,6 +47,9 @@
reagents.reaction(M, REAGENT_TOUCH)
reagents.clear_reagents()
else
+ if(!iscarbon(M)) // Non-carbons can't process reagents
+ to_chat(user, "You cannot find a way to feed [M].")
+ return
if(M != user)
M.visible_message("[user] attempts to feed something to [M].", \
"[user] attempts to feed something to you.")
diff --git a/goon/browserassets/js/browserOutput.js b/goon/browserassets/js/browserOutput.js
index 40a69245188..3cac81ca8e2 100644
--- a/goon/browserassets/js/browserOutput.js
+++ b/goon/browserassets/js/browserOutput.js
@@ -166,30 +166,79 @@ function emojiparse(el) {
}
}
-// Colorizes the highlight spans
-function setHighlightColor(match) {
- match.style.background = opts.highlightColor
+// Recolorizes the highlight spans
+function setHighlightColor() {
+ var highlightspans = document.getElementsByClassName("highlight")
+ for(var i in highlightspans){
+ highlightspans[i].setAttribute("style","background-color:"+opts.highlightColor)
+ }
+}
+
+function escapeRegexCharacters(input){ //escapes any characters that could be interpreted as regex patterns, potentially causing patterns to break if not escaped
+ return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
//Highlights words based on user settings
function highlightTerms(el) {
- if(regexHasError) return; //just stop right there ig the regex is gonna except
+
+ if (regexHasError) return; //just stop right there ig the regex is gonna except
+
+ function highlightRecursor(element, term){ //recursor function to do the highlighting proper
+ var regex = new RegExp(term, "gi");
+
+ function replace(str) {
+ return str.replace(regex, '$&');
+ }
+
+ var s = '';
+ var work = element.innerHTML;
+ var ind = 0;
+
+ while(ind < work.length) {
+
+ var next_term = work.substring(ind).search(regex);
+ if(next_term != -1) next_term += ind;
+ var next_tag = work.indexOf('<', ind);
+ if(next_tag == -1) {
+ s+=replace(work.substring(ind));
+ break;
+ }
+ else if(next_term==-1) {
+ s += work.substring(ind);
+ break;
+ }
+ else if(next_tag < next_term) {
+ var temp = work.indexOf('>', next_tag);
+ s += work.substring(ind,temp+1);
+ ind = temp+1;
+ }
+ else {
+ s += replace(work.substring(ind, next_tag));
+ ind = next_tag;
+ }
+ }
+
+ element.innerHTML = s;
+ }
+
for (var i = 0; i < opts.highlightTerms.length; i++) { //Each highlight term
if(opts.highlightTerms[i]) {
if(!opts.highlightRegexEnable){
- if(el.innerText.toString().toLowerCase().includes(opts.highlightTerms[i].toLowerCase())) //match normally
- el.innerHTML = ''+el.innerHTML+'' //encloseincludes
- continue;
+ var innerTerms = opts.highlightTerms[i].split(" ")
+ for(var a in innerTerms){
+ highlightRecursor(el, escapeRegexCharacters(innerTerms[a]))
+ }
}
- var rexp;
- try{
- rexp = new RegExp(opts.highlightTerms[i],"gmi")
- } catch(e){
- el.innerHTML+='
Your highlight regex - '+opts.highlightTerms[i]+' - is malformed. Thrown exception: '+e+''
- regexHasError = true;
- return;
+ else {
+ try{
+ new RegExp(opts.highlightTerms[i], "gmi"); // check to make sure the pattern wont cause issues
+ } catch(e){
+ el.innerHTML += '
Your highlight regex pattern -- ' + opts.highlightTerms[i] + ' -- is malformed.
Your highlights have been disabled until they are next edited
Thrown exception: '+e+'';
+ regexHasError = true;
+ return;
+ }
+ highlightRecursor(el, opts.highlightTerms[i]);
}
- el.innerHTML = el.innerHTML.replace(rexp,"$0") //i cant figure out a proper, non snowflakey way to let people select the group that gets highlighted
}
}
}
@@ -1043,15 +1092,21 @@ $(function() {
count++;
}
- var color = $('#highlightColor').val();
opts.highlightRegexEnable = document.querySelector("#highlightRegexEnable").checked
- color = color.trim();
- if (color == '' || color.charAt(0) != '#') {
- opts.highlightColor = '#FFFF00';
- } else {
- opts.highlightColor = color;
+
+ var color = $('#highlightColor').val();
+ if(color != opts.highlightColor) { // did the color even change?
+ color = color.trim();
+ if (color == '' || color.charAt(0) != '#') {
+ opts.highlightColor = '#FFFF00';
+ } else {
+ opts.highlightColor = color;
+ }
+ setHighlightColor();
}
+
regexHasError = false; //they changed the regex so it might be valid now
+ internalOutput('Highlights have been updated.',"internal") // simplest way to test if pattern works, why reinvent the wheel?
var $popup = $('#highlightPopup').closest('.popup');
$popup.remove();
diff --git a/tgui/yarn.lock b/tgui/yarn.lock
index 8cc9b0c818e..84cab5eb253 100644
--- a/tgui/yarn.lock
+++ b/tgui/yarn.lock
@@ -1241,9 +1241,9 @@ bluebird@^3.5.5:
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
- version "4.11.8"
- resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
- integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
+ version "4.11.9"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
+ integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
body-parser@1.19.0:
version "1.19.0"
@@ -2198,9 +2198,9 @@ electron-to-chromium@^1.3.390:
integrity sha512-DbCBdwtARI0l3e3m6ZIxVaTNahb6dSsmGjuag/twiVcWuM4MSpL5IfsJsJSyqLqxosE/m0CXlZaBmxegQW/dAg==
elliptic@^6.0.0:
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762"
- integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==
+ version "6.5.3"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
+ integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
dependencies:
bn.js "^4.4.0"
brorand "^1.0.1"