diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 07a0bdb0df3..834ecbe88b7 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -31,7 +31,7 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.r_wings_list,roundstart = TRUE)
init_sprite_accessory_subtypes(/datum/sprite_accessory/caps, GLOB.caps_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
-
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, GLOB.moth_markings_list)
//Species
for(var/spath in subtypesof(/datum/species))
@@ -52,7 +52,7 @@
// Keybindings
init_keybindings()
-
+
GLOB.emote_list = init_emote_list()
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm
index 881e0ebd90c..eae7522511d 100644
--- a/code/datums/mutations/actions.dm
+++ b/code/datums/mutations/actions.dm
@@ -187,7 +187,7 @@
if(!isturf(user.loc))
return FALSE
-/obj/effect/proc_holder/spell/self/void/cast(mob/user = usr)
+/obj/effect/proc_holder/spell/self/void/cast(list/targets, mob/user = usr)
. = ..()
new /obj/effect/immortality_talisman/void(get_turf(user), user)
@@ -210,7 +210,7 @@
charge_max = 100
action_icon_state = "autotomy"
-/obj/effect/proc_holder/spell/self/self_amputation/cast(mob/user = usr)
+/obj/effect/proc_holder/spell/self/self_amputation/cast(list/targets, mob/user = usr)
if(!iscarbon(user))
return
@@ -252,7 +252,7 @@
action_icon_state = "spike"
var/spike_path = /obj/item/hardened_spike
-/obj/effect/proc_holder/spell/self/tongue_spike/cast(mob/user = usr)
+/obj/effect/proc_holder/spell/self/tongue_spike/cast(list/targets, mob/user = usr)
if(!iscarbon(user))
return
@@ -408,7 +408,7 @@
to_chat(user, "There's already a web here!")
return FALSE
-/obj/effect/proc_holder/spell/self/lay_genetic_web/cast(mob/user = usr)
+/obj/effect/proc_holder/spell/self/lay_genetic_web/cast(list/targets, mob/user = usr)
var/turf/T = get_turf(user)
user.visible_message("[user] begins to secrete a sticky substance.","You begin to lay a web.")
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index a245750cec0..062e5f909a3 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -57,14 +57,14 @@
/obj/item/storage/bag/trash/update_icon_state()
switch(contents.len)
- if(0)
- icon_state = "[initial(icon_state)]"
- if(0 to 11)
- icon_state = "[initial(icon_state)]1"
+ if(20 to INFINITY)
+ icon_state = "[initial(icon_state)]3"
if(11 to 20)
icon_state = "[initial(icon_state)]2"
+ if(1 to 11)
+ icon_state = "[initial(icon_state)]1"
else
- icon_state = "[initial(icon_state)]3"
+ icon_state = "[initial(icon_state)]"
/obj/item/storage/bag/trash/cyborg
insertable = FALSE
diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm
index a8e479f4875..b6a761b4b34 100644
--- a/code/modules/assembly/timer.dm
+++ b/code/modules/assembly/timer.dm
@@ -4,14 +4,15 @@
icon_state = "timer"
custom_materials = list(/datum/material/iron=500, /datum/material/glass=50)
attachable = TRUE
-
+ drop_sound = 'sound/items/handling/component_drop.ogg'
+ pickup_sound = 'sound/items/handling/component_pickup.ogg'
+ var/ui_x = 275
+ var/ui_y = 115
var/timing = FALSE
var/time = 5
var/saved_time = 5
var/loop = FALSE
var/hearing_range = 3
- drop_sound = 'sound/items/handling/component_drop.ogg'
- pickup_sound = 'sound/items/handling/component_pickup.ogg'
/obj/item/assembly/timer/suicide_act(mob/living/user)
user.visible_message("[user] looks at the timer and decides [user.p_their()] fate! It looks like [user.p_theyre()] going to commit suicide!")
@@ -43,7 +44,6 @@
update_icon()
return TRUE
-
/obj/item/assembly/timer/toggle_secure()
secured = !secured
if(secured)
@@ -54,7 +54,6 @@
update_icon()
return secured
-
/obj/item/assembly/timer/proc/timer_end()
if(!secured || next_activate > world.time)
return FALSE
@@ -68,7 +67,6 @@
timing = TRUE
update_icon()
-
/obj/item/assembly/timer/process()
if(!timing)
return
@@ -78,7 +76,6 @@
timer_end()
time = saved_time
-
/obj/item/assembly/timer/update_icon()
cut_overlays()
attached_overlays = list()
@@ -88,48 +85,44 @@
if(holder)
holder.update_icon()
-
-/obj/item/assembly/timer/ui_interact(mob/user)//TODO: Have this use the wires
- . = ..()
+/obj/item/assembly/timer/ui_status(mob/user)
if(is_secured(user))
- var/second = time % 60
- var/minute = (time - second) / 60
- var/dat = "Timing Unit"
- dat += "
[(timing ? "Timing" : "Not Timing")] [minute]:[second]"
- dat += "
- - + +"
- dat += "
Stop repeating" : "1'>Set to repeat")]"
- dat += "
Refresh"
- dat += "
Close"
- var/datum/browser/popup = new(user, "timer", name)
- popup.set_content(dat)
- popup.open()
+ return ..()
+ return UI_CLOSE
+/obj/item/assembly/timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "timer", name, ui_x, ui_y, master_ui, state)
+ ui.open()
-/obj/item/assembly/timer/Topic(href, href_list)
- ..()
- if(!usr.canUseTopic(src, BE_CLOSE))
- usr << browse(null, "window=timer")
- onclose(usr, "timer")
+/obj/item/assembly/timer/ui_data(mob/user)
+ var/list/data = list()
+ var/time_left = time
+ data["seconds"] = round(time_left % 60)
+ data["minutes"] = round((time_left - data["seconds"]) / 60)
+ data["timing"] = timing
+ data["loop"] = loop
+ return data
+
+/obj/item/assembly/timer/ui_act(action, params)
+ if(..())
return
- if(href_list["time"])
- timing = text2num(href_list["time"])
- if(timing && istype(holder, /obj/item/transfer_valve))
- log_bomber(usr, "activated a", src, "attachment on [holder]")
-
- update_icon()
- if(href_list["repeat"])
- loop = text2num(href_list["repeat"])
-
- if(href_list["tp"])
- var/tp = text2num(href_list["tp"])
- time += tp
- time = min(max(round(time), 1), 600)
- saved_time = time
-
- if(href_list["close"])
- usr << browse(null, "window=timer")
- return
-
- if(usr)
- attack_self(usr)
+ switch(action)
+ if("time")
+ timing = !timing
+ if(timing && istype(holder, /obj/item/transfer_valve))
+ log_bomber(usr, "activated a", src, "attachment on [holder]")
+ update_icon()
+ . = TRUE
+ if("repeat")
+ loop = !loop
+ . = TRUE
+ if("input")
+ var/value = text2num(params["adjust"])
+ if(value)
+ time = min(max(round(time+value), 1), 600)
+ saved_time = time
+ . = TRUE
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 3b8237dde68..6231006c5bb 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -46,7 +46,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key)
parent.update_movement_keys(src)
to_chat(parent, "Empty keybindings, setting default to [hotkeys ? "Hotkey" : "Classic"] mode")
-
+
if(current_version < 30)
if(clientfps == 0)
clientfps = 60
@@ -329,6 +329,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["backpack"] >> backpack
S["jumpsuit_style"] >> jumpsuit_style
S["uplink_loc"] >> uplink_spawn_loc
+ S["phobia"] >> phobia
S["randomise"] >> randomise
S["feature_mcolor"] >> features["mcolor"]
S["feature_ethcolor"] >> features["ethcolor"]
@@ -468,6 +469,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc)
WRITE_FILE(S["randomise"] , randomise)
WRITE_FILE(S["species"] , pref_species.id)
+ WRITE_FILE(S["phobia"], phobia)
WRITE_FILE(S["feature_mcolor"] , features["mcolor"])
WRITE_FILE(S["feature_ethcolor"] , features["ethcolor"])
WRITE_FILE(S["feature_lizard_tail"] , features["tail_lizard"])
diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm
index 94912dfc554..92aadd3ca04 100644
--- a/code/modules/mining/machine_silo.dm
+++ b/code/modules/mining/machine_silo.dm
@@ -232,8 +232,9 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
var/list/msg = list("([timestamp]) [machine_name] in [area_name]
[action] [abs(amount)]x [noun]
")
var/sep = ""
for(var/key in materials)
+ var/datum/material/M = key
var/val = round(materials[key]) / MINERAL_MATERIAL_AMOUNT
msg += sep
sep = ", "
- msg += "[amount < 0 ? "-" : "+"][val] [copytext(key, length(key[1]) + 1)]"
+ msg += "[amount < 0 ? "-" : "+"][val] [M.name]"
formatted = msg.Join()
diff --git a/code/modules/research/bepis.dm b/code/modules/research/bepis.dm
index ddd0ccd74cb..0329fe1e321 100644
--- a/code/modules/research/bepis.dm
+++ b/code/modules/research/bepis.dm
@@ -111,11 +111,19 @@
return
/obj/machinery/rnd/bepis/proc/calcsuccess()
- var/turf/dropturf = get_turf(pick(view(1,src)))
+ var/turf/dropturf = null
var/gauss_major = 0
var/gauss_minor = 0
var/gauss_real = 0
- if(!dropturf) //Check to verify the turf exists and the reward isn't lost somehow.
+ var/list/turfs = block(locate(x-1,y-1,z),locate(x+1,y+1,z)) //NO MORE DISCS IN WINDOWS
+ while(length(turfs))
+ var/turf/T = pick_n_take(turfs)
+ if(is_blocked_turf(T, exclude_mobs=TRUE))
+ continue
+ else
+ dropturf = T
+ break
+ if (!dropturf)
dropturf = drop_location()
gauss_major = (gaussian(major_threshold, std) - negative_cash_offset) //This is the randomized profit value that this experiment has to surpass to unlock a tech.
gauss_minor = (gaussian(minor_threshold, std) - negative_cash_offset) //And this is the threshold to instead get a minor prize.
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index d6e908a8131..75c613f70f2 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -1082,6 +1082,10 @@
description = "A bored scientist was thinking to himself for very long...and then realized his coffee got cold! He made this invention to solve this extreme problem."
prereq_ids = list("base")
design_ids = list("mauna_mug")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
+ export_price = 2500
+ hidden = TRUE
+ experimental = TRUE
/datum/techweb_node/spec_eng
id = "spec_eng"
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index d27728018e8..ff88b3cca1e 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -552,7 +552,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
school = "restoration"
sound = 'sound/magic/staff_healing.ogg'
-/obj/effect/proc_holder/spell/self/basic_heal/cast(mob/living/carbon/human/user) //Note the lack of "list/targets" here. Instead, use a "user" var depending on mob requirements.
+/obj/effect/proc_holder/spell/self/basic_heal/cast(list/targets, mob/living/carbon/human/user) //Note the lack of "list/targets" here. Instead, use a "user" var depending on mob requirements.
//Also, notice the lack of a "for()" statement that looks through the targets. This is, again, because the spell can only have a single target.
user.visible_message("A wreath of gentle light passes over [user]!", "You wreath yourself in healing light!")
user.adjustBruteLoss(-10)
diff --git a/code/modules/spells/spell_types/soultap.dm b/code/modules/spells/spell_types/soultap.dm
index eb4fa112d29..c152c89f8c0 100644
--- a/code/modules/spells/spell_types/soultap.dm
+++ b/code/modules/spells/spell_types/soultap.dm
@@ -17,7 +17,7 @@
action_icon = 'icons/mob/actions/actions_spells.dmi'
action_icon_state = "soultap"
-/obj/effect/proc_holder/spell/self/tap/cast(mob/living/user = usr)
+/obj/effect/proc_holder/spell/self/tap/cast(list/targets, mob/living/user = usr)
if(!user.mind.hasSoul)
to_chat(user, "You do not possess a soul to tap into!")
return
diff --git a/html/changelogs/AutoChangeLog-pr-48902.yml b/html/changelogs/AutoChangeLog-pr-48902.yml
new file mode 100644
index 00000000000..51b068e14e6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-48902.yml
@@ -0,0 +1,4 @@
+author: "ArcaneMusic"
+delete-after: True
+changes:
+ - bugfix: "The B.E.P.I.S. no longer shunts rewards into the walls and windows of the station."
diff --git a/html/changelogs/AutoChangeLog-pr-48979.yml b/html/changelogs/AutoChangeLog-pr-48979.yml
new file mode 100644
index 00000000000..3844770d806
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-48979.yml
@@ -0,0 +1,4 @@
+author: "TheVekter"
+delete-after: True
+changes:
+ - bugfix: "Fixes the Mauna Mug research being available from roundstart."
diff --git a/html/changelogs/AutoChangeLog-pr-48980.yml b/html/changelogs/AutoChangeLog-pr-48980.yml
new file mode 100644
index 00000000000..fa1ea2e0079
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-48980.yml
@@ -0,0 +1,4 @@
+author: "Arkatos"
+delete-after: True
+changes:
+ - bugfix: "Removed rogue pixel on salbutamol pen inhand sprite."
diff --git a/html/changelogs/AutoChangeLog-pr-48981.yml b/html/changelogs/AutoChangeLog-pr-48981.yml
new file mode 100644
index 00000000000..3731d13caaf
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-48981.yml
@@ -0,0 +1,4 @@
+author: "Arkatos"
+delete-after: True
+changes:
+ - rscadd: "Timer assembly now uses tgui-next."
diff --git a/html/changelogs/AutoChangeLog-pr-49001.yml b/html/changelogs/AutoChangeLog-pr-49001.yml
new file mode 100644
index 00000000000..459be4301e8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-49001.yml
@@ -0,0 +1,4 @@
+author: "Arkatos"
+delete-after: True
+changes:
+ - bugfix: "Trashbag will now properly update its icon."
diff --git a/html/changelogs/AutoChangeLog-pr-49005.yml b/html/changelogs/AutoChangeLog-pr-49005.yml
new file mode 100644
index 00000000000..39878742cd3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-49005.yml
@@ -0,0 +1,4 @@
+author: "Names-Are-Hard"
+delete-after: True
+changes:
+ - bugfix: "phobia quirk properly saves now"
diff --git a/html/changelogs/AutoChangeLog-pr-49006.yml b/html/changelogs/AutoChangeLog-pr-49006.yml
new file mode 100644
index 00000000000..7cc59f3720d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-49006.yml
@@ -0,0 +1,4 @@
+author: "Names-Are-Hard"
+delete-after: True
+changes:
+ - bugfix: "Fixed moth markings not saving properly"
diff --git a/icons/mob/inhands/equipment/medical_lefthand.dmi b/icons/mob/inhands/equipment/medical_lefthand.dmi
index e26eb4e04da..a1e711eee38 100644
Binary files a/icons/mob/inhands/equipment/medical_lefthand.dmi and b/icons/mob/inhands/equipment/medical_lefthand.dmi differ
diff --git a/tgui-next/packages/tgui/interfaces/Timer.js b/tgui-next/packages/tgui/interfaces/Timer.js
new file mode 100644
index 00000000000..0b7328cb81f
--- /dev/null
+++ b/tgui-next/packages/tgui/interfaces/Timer.js
@@ -0,0 +1,48 @@
+import { Fragment } from 'inferno';
+import { useBackend } from '../backend';
+import { Button, Section } from '../components';
+
+export const Timer = props => {
+ const { act, data } = useBackend(props);
+ const {
+ minutes,
+ seconds,
+ timing,
+ loop,
+ } = data;
+ return (
+
+
+ );
+};
diff --git a/tgui-next/packages/tgui/routes.js b/tgui-next/packages/tgui/routes.js
index 5002ea19054..a741f5c6644 100644
--- a/tgui-next/packages/tgui/routes.js
+++ b/tgui-next/packages/tgui/routes.js
@@ -99,6 +99,7 @@ import { Tank } from './interfaces/Tank';
import { TankDispenser } from './interfaces/TankDispenser';
import { Teleporter } from './interfaces/Teleporter';
import { ThermoMachine } from './interfaces/ThermoMachine';
+import { Timer } from './interfaces/Timer';
import { TurbineComputer } from './interfaces/TurbineComputer';
import { Uplink } from './interfaces/Uplink';
import { VaultController } from './interfaces/VaultController';
@@ -553,6 +554,10 @@ const ROUTES = {
component: () => ThermoMachine,
scrollable: false,
},
+ timer: {
+ component: () => Timer,
+ scrollable: false,
+ },
turbine_computer: {
component: () => TurbineComputer,
scrollable: false,