From 9a1e46b9690c1c4f84c84406beb64137d83c3e4a Mon Sep 17 00:00:00 2001 From: Christasmurf <25437893+Christasmurf@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:44:30 +0000 Subject: [PATCH 01/43] ATM resprite (#24345) * sprites * pixel shift * sprite update --- icons/obj/terminals.dmi | Bin 28876 -> 36847 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/terminals.dmi b/icons/obj/terminals.dmi index 07f61e68ea86136db6ea54f3d80d5f064d39e5d3..c749a2b1360ca5c9f89266ef9cebdf5dce8ed7d3 100644 GIT binary patch literal 36847 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 literal 28876 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 From d8935d07ff2d7b20f7f080cfb39b08ba8d4a408a Mon Sep 17 00:00:00 2001 From: Yata <108077473+Yata9arasu@users.noreply.github.com> Date: Tue, 5 Mar 2024 15:27:36 +0700 Subject: [PATCH 02/43] Toxins fixed (#1059) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Что этот PR делает Удаляет лишние стены из комнаты для нагревания плазмы, что мешали ей очиститься после открытия ставней, добавляет вентилятор в комнате запуска бомб для предотвращения разгерметизации. ## Почему это хорошо для игры Микс комнату можно наконец опустошить. Бомбы запускаются без проблем. ## Изображения изменений ## Тестирование Работает ## Changelog :cl: fix: Отредактированы помарки в комнате токсинов и комнате запуска на Дельте /:cl: Co-authored-by: Yata --- _maps/map_files220/delta/delta.dmm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_maps/map_files220/delta/delta.dmm b/_maps/map_files220/delta/delta.dmm index 3099c86bc5fe..e928421aa5a7 100644 --- a/_maps/map_files220/delta/delta.dmm +++ b/_maps/map_files220/delta/delta.dmm @@ -62411,7 +62411,7 @@ name = "Toxins Venting Bay Door"; power_state = 0 }, -/turf/simulated/wall/r_wall, +/turf/simulated/floor/engine, /area/station/science/toxins/mixing) "ivI" = ( /obj/item/kirbyplants, @@ -62485,6 +62485,7 @@ name = "Toxins Launcher Bay Door"; protected = 0 }, +/obj/structure/fans/tiny, /turf/simulated/floor/plating, /area/station/science/toxins/launch) "ixA" = ( From bcdfda3efa4ea4a5e2fda40400acd0910d02d8b5 Mon Sep 17 00:00:00 2001 From: Mikhail Dzianishchyts Date: Wed, 6 Mar 2024 13:18:02 +0300 Subject: [PATCH 03/43] More TTS acronyms (#1061) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Что этот PR делает Пара медицинских аббревиатур и все. ## Почему это хорошо для игры Хорошо звучит. ## Тестирование На проде. ## Changelog :cl: Maxiemar tweak: Изменена TTS озвучка нескольких медицинских аббревиатур. /:cl: --- modular_ss220/text_to_speech/code/tts_subsystem.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modular_ss220/text_to_speech/code/tts_subsystem.dm b/modular_ss220/text_to_speech/code/tts_subsystem.dm index 935e695a8954..27c17ed1d6f0 100644 --- a/modular_ss220/text_to_speech/code/tts_subsystem.dm +++ b/modular_ss220/text_to_speech/code/tts_subsystem.dm @@ -119,6 +119,8 @@ SUBSYSTEM_DEF(tts220) "мед" = "м ед", "меде" = "м еде", "кз" = "Кэ Зэ", + "дтпа" = "Дэ Тэ Пэ А", + "слр" = "Эс Эл Эр" ) var/static/list/tts_job_replacements = list( From 60239285767b634cd85ea0b5379ce9989e2adfdc Mon Sep 17 00:00:00 2001 From: Mikhail Dzianishchyts Date: Wed, 6 Mar 2024 13:20:57 +0300 Subject: [PATCH 04/43] Rename Intern to Medical Intern (#1060) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Что этот PR делает Есть уже у ассистента альтернативное название Intern. Из-за этого конфликта медицинский интерн мог перемещаться в отдел Misc в манифесте и не имел соответствующего цвета должности в рации. Такое переименование должно исправить проблему. ## Почему это хорошо для игры Интерн полноценный сотрудник отдела. ## Тестирование Должность цветастая, интерн плотно зафиксирован на своем месте в манифесте. ![image](https://github.com/ss220club/Paradise-SS220/assets/39908528/81e37fd8-62ae-41bc-ab2e-b072a400c1ca) ## Changelog :cl: Maxiemar tweak: Intern в медицинском отделе переименован в Medical Intern. fix: Исправлены ошибки, связанные с предыдущим именованием интерна. /:cl: --- code/datums/datacore.dm | 2 +- config/example/config.toml | 2 +- modular_ss220/jobs/code/card_id.dm | 2 +- modular_ss220/jobs/code/job/medical_jobs.dm | 4 ++-- modular_ss220/jobs/code/jobs.dm | 2 +- modular_ss220/jobs/code/jobs_character.dm | 2 +- modular_ss220/jobs/code/jobs_global_list.dm | 2 +- modular_ss220/jobs/code/objects/job_objects.dm | 6 +++--- modular_ss220/text_to_speech/code/tts_subsystem.dm | 1 + 9 files changed, 12 insertions(+), 11 deletions(-) diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index ac79cfb2597b..94657d3c038d 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -500,7 +500,7 @@ GLOBAL_VAR_INIT(record_id_num, 1001) clothes_s = new /icon('modular_ss220/jobs/icons/clothing/mob/uniform.dmi', "student_s") clothes_s.Blend(new /icon('icons/mob/clothing/feet.dmi', "white"), ICON_UNDERLAY) clothes_s.Blend(new /icon('icons/mob/clothing/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY) - if("Intern") + if("Medical Intern") clothes_s = new /icon('modular_ss220/jobs/icons/clothing/mob/uniform.dmi', "intern_s") clothes_s.Blend(new /icon('icons/mob/clothing/feet.dmi', "white"), ICON_UNDERLAY) clothes_s.Blend(new /icon('icons/mob/clothing/suit.dmi', "labcoat_open"), ICON_OVERLAY) diff --git a/config/example/config.toml b/config/example/config.toml index 846855eb666f..3a1e6f4271e0 100644 --- a/config/example/config.toml +++ b/config/example/config.toml @@ -426,7 +426,7 @@ job_slot_amounts = [ {name = "Chemist", lowpop = 2, highpop = 2}, {name = "Geneticist", lowpop = 2, highpop = 2}, {name = "Medical Doctor", lowpop = 5, highpop = 6}, - {name = "Intern", lowpop = 0, highpop = 0}, + {name = "Medical Intern", lowpop = 0, highpop = 0}, {name = "Virologist", lowpop = 1, highpop = 1}, # Science {name = "Roboticist", lowpop = 2, highpop = 2}, diff --git a/modular_ss220/jobs/code/card_id.dm b/modular_ss220/jobs/code/card_id.dm index c9fab4da4333..1dee1d1375f9 100644 --- a/modular_ss220/jobs/code/card_id.dm +++ b/modular_ss220/jobs/code/card_id.dm @@ -38,7 +38,7 @@ GLOBAL_LIST_INIT(card_skins_donor_ss220, list( registered_name = "Intern" icon = 'modular_ss220/aesthetics/better_ids/icons/better_ids.dmi' icon_state = "intern" - rank = "Intern" + rank = "Medical Intern" /obj/item/card/id/research/student name = "Student ID" diff --git a/modular_ss220/jobs/code/job/medical_jobs.dm b/modular_ss220/jobs/code/job/medical_jobs.dm index b95e491954d0..35e9ccdb1b4b 100644 --- a/modular_ss220/jobs/code/job/medical_jobs.dm +++ b/modular_ss220/jobs/code/job/medical_jobs.dm @@ -1,5 +1,5 @@ /datum/job/doctor/intern - title = "Intern" + title = "Medical Intern" flag = JOB_INTERN total_positions = 0 spawn_positions = 3 @@ -10,7 +10,7 @@ important_information = "Ваша должность ограничена во всех взаимодействиях с рабочим имуществом отдела и экипажем станции, при отсутствии приставленного к нему квалифицированного сотрудника или полученного разрешения от вышестоящего начальства." /datum/outfit/job/doctor/intern - name = "Intern" + name = "Medical Intern" jobtype = /datum/job/doctor/intern uniform = /obj/item/clothing/under/rank/medical/doctor/intern diff --git a/modular_ss220/jobs/code/jobs.dm b/modular_ss220/jobs/code/jobs.dm index 6173b770444a..4102ffc5c5e7 100644 --- a/modular_ss220/jobs/code/jobs.dm +++ b/modular_ss220/jobs/code/jobs.dm @@ -10,7 +10,7 @@ var/is_extra_job = FALSE // Special Jobs Window /datum/job/doctor - relate_job = "Intern" + relate_job = "Medical Intern" is_relate_positions = TRUE /datum/job/doctor/intern relate_job = "Medical Doctor" diff --git a/modular_ss220/jobs/code/jobs_character.dm b/modular_ss220/jobs/code/jobs_character.dm index 179a60381f11..5753a4aa3f36 100644 --- a/modular_ss220/jobs/code/jobs_character.dm +++ b/modular_ss220/jobs/code/jobs_character.dm @@ -8,7 +8,7 @@ if("Security Cadet") O = new /datum/outfit/plasmaman/security - if("Intern") + if("Medical Intern") O = new /datum/outfit/plasmaman/medical if("Student Scientist") diff --git a/modular_ss220/jobs/code/jobs_global_list.dm b/modular_ss220/jobs/code/jobs_global_list.dm index 3027eaf4d0ae..6da25d934924 100644 --- a/modular_ss220/jobs/code/jobs_global_list.dm +++ b/modular_ss220/jobs/code/jobs_global_list.dm @@ -1,7 +1,7 @@ // ===================== STATION ===================== GLOBAL_LIST_INIT(medical_positions_ss220, list( - "Intern", + "Medical Intern", )) GLOBAL_LIST_INIT(science_positions_ss220, list( diff --git a/modular_ss220/jobs/code/objects/job_objects.dm b/modular_ss220/jobs/code/objects/job_objects.dm index 406798ce86c7..c18d26beb14c 100644 --- a/modular_ss220/jobs/code/objects/job_objects.dm +++ b/modular_ss220/jobs/code/objects/job_objects.dm @@ -7,9 +7,9 @@ ) /obj/effect/mob_spawn/human/intern - name = "Intern" - mob_name = "Intern" - id_job = "Intern" + name = "Medical Intern" + mob_name = "Medical Intern" + id_job = "Medical Intern" outfit = /datum/outfit/job/doctor/intern /obj/effect/mob_spawn/human/trainee diff --git a/modular_ss220/text_to_speech/code/tts_subsystem.dm b/modular_ss220/text_to_speech/code/tts_subsystem.dm index 27c17ed1d6f0..d098d8a075c5 100644 --- a/modular_ss220/text_to_speech/code/tts_subsystem.dm +++ b/modular_ss220/text_to_speech/code/tts_subsystem.dm @@ -151,6 +151,7 @@ SUBSYSTEM_DEF(tts220) "chief medical officer" = "Главный врач", "medical doctor" = "Врач", "Intern" = "Интерн", + "Medical Intern" = "Медицинский Интерн", "Student Medical Doctor" = "Врач-практикант", "Medical Assistant" = "Ассистирующий врач", "surgeon" = "Хирург", From a46ce1f0bba8dff5a484efece916f64e6b4d42d3 Mon Sep 17 00:00:00 2001 From: Mikhail Dzianishchyts Date: Wed, 6 Mar 2024 13:21:07 +0300 Subject: [PATCH 05/43] Make immovable rod able to go through platform (#1053) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Что этот PR делает Продавливает палку через платформу. ## Почему это хорошо для игры Палка продавлена через платформу. ## Тестирование https://github.com/ss220club/Paradise-SS220/assets/39908528/a875bbfd-8984-463e-a3b4-aabc1cce9089 ## Changelog :cl: Maxiemar fix: Палка мага теперь свободно пролетает через платформы. /:cl: --------- Co-authored-by: Mikhail G. --- modular_ss220/objects/code/platform.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modular_ss220/objects/code/platform.dm b/modular_ss220/objects/code/platform.dm index 94c6c9812dbc..7a74fc70d1c2 100644 --- a/modular_ss220/objects/code/platform.dm +++ b/modular_ss220/objects/code/platform.dm @@ -92,7 +92,7 @@ CheckLayer() if(istype(O, /obj/structure/platform)) return FALSE - if(istype(O, /obj/item/projectile)) + if(istype(O, /obj/item/projectile) || istype(O, /obj/effect)) return TRUE if(corner) return !density From b7d6f13e886474bda39948899f88e3d60e8af357 Mon Sep 17 00:00:00 2001 From: Mikhail Dzianishchyts Date: Wed, 6 Mar 2024 13:37:45 +0300 Subject: [PATCH 06/43] Medborg gripper fixes (#1057) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Что этот PR делает Ну складывались таблетки в холодос, да не выкладывались из захвата, что приводило к множеству ссылок на одно и тоже, телепортам и т.п. Еще согласно здравому смыслу разрешаем медборгам хватать патчи. ## Почему это хорошо для игры Баги плохо. ## Тестирование Ну локально работает. ## Changelog :cl: Maxiemar tweak: Медицинские борги теперь могут хватать патчи с помощью устройства захвата. fix: Исправлена проблема, возникающая при помещении боргом предметов в холодильник. /:cl: --- modular_ss220/objects/_objects.dme | 1 + modular_ss220/objects/code/smartfridge.dm | 10 ++++++++++ modular_ss220/silicons/code/items/gripper.dm | 1 + 3 files changed, 12 insertions(+) create mode 100644 modular_ss220/objects/code/smartfridge.dm diff --git a/modular_ss220/objects/_objects.dme b/modular_ss220/objects/_objects.dme index 542f5e2442f7..8d79b524a5f9 100644 --- a/modular_ss220/objects/_objects.dme +++ b/modular_ss220/objects/_objects.dme @@ -19,6 +19,7 @@ #include "code/plastic_chair.dm" #include "code/platform.dm" #include "code/posters.dm" +#include "code/smartfridge.dm" #include "code/tribune.dm" #include "code/weapons.dm" #include "code/key.dm" diff --git a/modular_ss220/objects/code/smartfridge.dm b/modular_ss220/objects/code/smartfridge.dm new file mode 100644 index 000000000000..68d578745a38 --- /dev/null +++ b/modular_ss220/objects/code/smartfridge.dm @@ -0,0 +1,10 @@ +/obj/machinery/smartfridge/load(obj/I, mob/user) + var/item_loc_origin = I.loc + if(!..()) + return FALSE + + if(istype(item_loc_origin, /obj/item/gripper)) + var/obj/item/gripper/gripper = item_loc_origin + gripper.drop_gripped_item(silent = TRUE) + I.forceMove(src) + return TRUE diff --git a/modular_ss220/silicons/code/items/gripper.dm b/modular_ss220/silicons/code/items/gripper.dm index 7c7697e028e9..8da623777ed8 100644 --- a/modular_ss220/silicons/code/items/gripper.dm +++ b/modular_ss220/silicons/code/items/gripper.dm @@ -54,6 +54,7 @@ /obj/item/stack/sheet/mineral/plasma, // for repair plasmamans /obj/item/mmi, /obj/item/reagent_containers/pill, + /obj/item/reagent_containers/patch, /obj/item/reagent_containers/drinks, /obj/item/reagent_containers/glass, /obj/item/reagent_containers/syringe, From 21d919b6444a97100c2459fa424b02c3bfca1ca9 Mon Sep 17 00:00:00 2001 From: Charlie Nolan Date: Wed, 6 Mar 2024 05:21:02 -0800 Subject: [PATCH 07/43] Removed a few not-useful wrench comments. (#24453) --- code/game/objects/items/tools/wrench.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm index f5249ae91696..438421f849ce 100644 --- a/code/game/objects/items/tools/wrench.dm +++ b/code/game/objects/items/tools/wrench.dm @@ -1,4 +1,3 @@ -//Wrench /obj/item/wrench name = "wrench" desc = "A wrench with common uses. Can be found in your hand." @@ -54,8 +53,8 @@ belt_icon = "hand_drill" usesound = 'sound/items/drill_use.ogg' materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get - force = 8 //might or might not be too high, subject to change + origin_tech = "materials=2;engineering=2" + force = 8 throwforce = 8 attack_verb = list("drilled", "screwed", "jabbed") toolspeed = 0.25 From 32e15d26d4792afdb8fb0fc9d399635b8176fbff Mon Sep 17 00:00:00 2001 From: GDN <96800819+GDNgit@users.noreply.github.com> Date: Wed, 6 Mar 2024 07:21:12 -0600 Subject: [PATCH 08/43] fixes a bogus runtime (#24431) --- code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm index b56ff3677864..b204d27f0419 100644 --- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm +++ b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm @@ -379,7 +379,7 @@ current_power = new_power current_cable = null forceMove(current_power) // we go inside the machine - RegisterSignal(current_power, COMSIG_ATOM_EMP_ACT, PROC_REF(handle_emp)) + RegisterSignal(current_power, COMSIG_ATOM_EMP_ACT, PROC_REF(handle_emp), TRUE) playsound(src, 'sound/effects/eleczap.ogg', 15, TRUE) do_sparks(rand(2, 4), FALSE, src) if(isapc(current_power)) From f6449107136560c5bcadf0c105b867ac2d219a58 Mon Sep 17 00:00:00 2001 From: ike709 Date: Wed, 6 Mar 2024 06:21:35 -0700 Subject: [PATCH 09/43] OpenDream Typemaker Prep (#24430) * OpenDream Typemaker Prep * Update code/datums/radio_frequency.dm Co-authored-by: GDN <96800819+GDNgit@users.noreply.github.com> --------- Co-authored-by: GDN <96800819+GDNgit@users.noreply.github.com> --- code/datums/radio_frequency.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/radio_frequency.dm b/code/datums/radio_frequency.dm index cf14ba3c956d..71e891ed3ce6 100644 --- a/code/datums/radio_frequency.dm +++ b/code/datums/radio_frequency.dm @@ -1,6 +1,6 @@ /datum/radio_frequency - var/frequency as num + var/frequency var/list/obj/devices = list() /datum/radio_frequency/proc/post_signal(obj/source as obj|null, datum/signal/signal, filter = null as text|null, range = null as num|null) From 4912a1c0739aa8b76a2e22487674405d7dabf39e Mon Sep 17 00:00:00 2001 From: Charlie Nolan Date: Wed, 6 Mar 2024 05:22:22 -0800 Subject: [PATCH 10/43] Let simplemobs see_through_darkness (#24418) --- code/_onclick/hud/other_mobs_hud.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/_onclick/hud/other_mobs_hud.dm b/code/_onclick/hud/other_mobs_hud.dm index 8e87c837df20..27fe7bf55241 100644 --- a/code/_onclick/hud/other_mobs_hud.dm +++ b/code/_onclick/hud/other_mobs_hud.dm @@ -13,6 +13,8 @@ static_inventory += using action_intent = using + user.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/see_through_darkness) + /mob/living/simple_animal/pet/create_mob_hud() if(client && !hud_used) From e43fb1ce343c68513d71d94075836c9d32c0ed99 Mon Sep 17 00:00:00 2001 From: YoursTrulyHollow <100510026+Hollow1364781653786@users.noreply.github.com> Date: Wed, 6 Mar 2024 20:22:35 +0700 Subject: [PATCH 11/43] fixes the error where chicks lose their custom name when growing into chickens (#24409) * fixes chicks * Update code/modules/mob/living/simple_animal/friendly/farm_animals.dm Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> * Update code/modules/mob/living/simple_animal/friendly/farm_animals.dm Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> --------- Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> --- code/modules/mob/living/simple_animal/friendly/farm_animals.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index cc34a767dea6..c6dffb129727 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -229,6 +229,8 @@ amount_grown += rand(1,2) if(amount_grown >= 100) var/mob/living/simple_animal/chicken/C = new /mob/living/simple_animal/chicken(loc) + if(name != initial(name)) + C.name = name if(mind) mind.transfer_to(C) qdel(src) From d7c7cacc52c9cd88da826079ebe1bb0fca008e54 Mon Sep 17 00:00:00 2001 From: Qwertytoforty <52090703+Qwertytoforty@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:25:38 -0500 Subject: [PATCH 12/43] Adds The Qani-Laaca Sensory Computer and mephedrone. Ready for review into merge (#23926) * Surely this will not have any critical balance implications * Apply suggestions from code review Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> * oops * marm fixes * fixes signal * how on earth did I do that * adds twitch to nanocalcium * respect armor, lowers throw * IPC can use, fuck up heartless people * no crawl slowdown / meth * *slightly* turns down the drug effect * renames it will deal with pr desc soon * finishes it * rnd version empable * Apply suggestions from code review Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> * Nerfs twitches visuals, due to a reported novastation bug where the visuals would endlessly stack * Apply suggestions from code review Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> * C-C-C-Changes * Epilepsy Warning: Drug has vibrant visual effects! * safety * Apply suggestions from code review Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * removes twitch name, make mix explode * oops --------- Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com> --- code/__DEFINES/dcs/signals.dm | 7 + code/__DEFINES/directions.dm | 3 + code/__DEFINES/misc_defines.dm | 4 +- code/__HELPERS/filters.dm | 4 +- code/__HELPERS/trait_helpers.dm | 2 + code/_globalvars/traits.dm | 4 +- code/_onclick/hud/human_hud.dm | 1 + code/datums/elements/shatters_when_thrown.dm | 56 ++++ code/datums/uplink_items/uplink_general.dm | 2 +- code/datums/uplink_items/uplink_traitor.dm | 12 + code/game/atoms.dm | 3 + .../effects/temporary_visuals/misc_visuals.dm | 10 +- code/game/objects/items/weapons/twohanded.dm | 2 + .../mob/living/carbon/human/human_defense.dm | 2 +- .../living/carbon/human/species/_species.dm | 2 +- code/modules/projectiles/projectile_base.dm | 5 +- .../reagents/chemistry/reagents/drugs.dm | 300 ++++++++++++++++++ .../reagents/chemistry/reagents/medicine.dm | 9 +- .../reagents/chemistry/reagents_datum.dm | 3 + .../reagents/chemistry/reagents_holder.dm | 1 + .../chemistry/recipes/drugs_reactions.dm | 15 + .../research/designs/medical_designs.dm | 15 + .../surgery/organs/augments_internal.dm | 128 ++++++++ code/modules/surgery/organs/autosurgeon.dm | 14 + code/modules/surgery/organs/organ_internal.dm | 1 + icons/mob/human_races/robotic.dmi | Bin 1538 -> 2505 bytes icons/obj/surgery.dmi | Bin 30742 -> 31650 bytes paradise.dme | 1 + 28 files changed, 589 insertions(+), 17 deletions(-) create mode 100644 code/datums/elements/shatters_when_thrown.dm diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index f680b67faaba..4628c23ba2c3 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -185,6 +185,10 @@ #define COMSIG_ATOM_HITBY "atom_hitby" /// Called when an atom is sharpened or dulled. #define COMSIG_ATOM_UPDATE_SHARPNESS "atom_update_sharpness" +///from base of atom/atom_prehit(obj/item/projectile/P): +#define COMSIG_ATOM_PREHIT "atom_prehit" + #define ATOM_PREHIT_SUCCESS (1<<0) + #define ATOM_PREHIT_FAILURE (1<<1) // Attack signals. These should share the returned flags, to standardize the attack chain. // The chain currently works like: @@ -774,6 +778,9 @@ #define COMSIG_HUMAN_CHECK_SHIELDS "human_check_shields" #define SHIELD_BLOCK (1<<0) +///from /mob/living/carbon/human/create_mob_hud() +#define COMSIG_HUMAN_CREATE_MOB_HUD "human_create_mob_hud" + // /datum/species signals ///from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species) diff --git a/code/__DEFINES/directions.dm b/code/__DEFINES/directions.dm index dfe3b2ecc789..7e4dd3c9769a 100644 --- a/code/__DEFINES/directions.dm +++ b/code/__DEFINES/directions.dm @@ -28,3 +28,6 @@ #define IS_DIR_DIAGONAL(dir) (dir & (dir - 1)) /// returns TRUE if direction is cardinal and false if not #define IS_DIR_CARDINAL(dir) (!IS_DIR_DIAGONAL(dir)) + +/// Inverse direction, taking into account UP|DOWN if necessary. +#define REVERSE_DIR(dir) ( ((dir & 85) << 1) | ((dir & 170) >> 1) ) diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm index a5e9e129d505..4dd81e1afd3a 100644 --- a/code/__DEFINES/misc_defines.dm +++ b/code/__DEFINES/misc_defines.dm @@ -171,8 +171,8 @@ #define MUTANTRACE_LAYER 39 #define TAIL_UNDERLIMBS_LAYER 38 //Tail split-rendering. #define LIMBS_LAYER 37 -#define INTORGAN_LAYER 36 -#define MARKINGS_LAYER 35 +#define MARKINGS_LAYER 36 +#define INTORGAN_LAYER 35 #define UNDERWEAR_LAYER 34 #define MUTATIONS_LAYER 33 #define H_DAMAGE_LAYER 32 diff --git a/code/__HELPERS/filters.dm b/code/__HELPERS/filters.dm index b9a89f4d33aa..9550f4c9bfc4 100644 --- a/code/__HELPERS/filters.dm +++ b/code/__HELPERS/filters.dm @@ -22,15 +22,13 @@ GLOBAL_LIST_INIT(master_filter_info, list( "size" = 1 ) ), - /* Not supported because making a proper matrix editor on the frontend would be a huge dick pain. - Uncomment if you ever implement it + // According to TG, this is not implimented. Anyway, let's use this! "color" = list( "defaults" = list( "color" = matrix(), "space" = FILTER_COLOR_RGB ) ), - */ "displace" = list( "defaults" = list( "x" = 0, diff --git a/code/__HELPERS/trait_helpers.dm b/code/__HELPERS/trait_helpers.dm index e3feed27c701..d8cd8a104c58 100644 --- a/code/__HELPERS/trait_helpers.dm +++ b/code/__HELPERS/trait_helpers.dm @@ -223,6 +223,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_CAN_VIEW_HEALTH "can_view_health" // Also used for /Stat #define TRAIT_MAGPULSE "magnetificent" // Used for anything that is magboot related #define TRAIT_NOSLIP "noslip" +#define TRAIT_MEPHEDRONE_ADAPTED "mephedrone_adapted" // Trait that changes the ending effects of twitch leaving your system +#define TRAIT_NOKNOCKDOWNSLOWDOWN "noknockdownslowdown" //If this person has this trait, they are not slowed via knockdown, but they can be hit by bullets like a self knockdown //***** MIND TRAITS *****/ #define TRAIT_HOLY "is_holy" // The mob is holy in regards to religion diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 036e141d9ed9..0d3ded12c71a 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -87,7 +87,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BADASS" = TRAIT_BADASS, "TRAIT_FORCED_STANDING" = TRAIT_FORCED_STANDING, "TRAIT_NOSLIP" = TRAIT_NOSLIP, - "TRAIT_MAGPULSE" = TRAIT_MAGPULSE + "TRAIT_MAGPULSE" = TRAIT_MAGPULSE, + "TRAIT_MEPHEDRONE_ADAPTED" = TRAIT_MEPHEDRONE_ADAPTED, + "TRAIT_NOKNOCKDOWNSLOWDOWN" = TRAIT_NOKNOCKDOWNSLOWDOWN ), /datum/mind = list( diff --git a/code/_onclick/hud/human_hud.dm b/code/_onclick/hud/human_hud.dm index 67c9e2e66215..c69e78f64043 100644 --- a/code/_onclick/hud/human_hud.dm +++ b/code/_onclick/hud/human_hud.dm @@ -52,6 +52,7 @@ /mob/living/carbon/human/create_mob_hud() if(client && !hud_used) hud_used = new /datum/hud/human(src, ui_style2icon(client.prefs.UI_style), client.prefs.UI_style_color, client.prefs.UI_style_alpha) + SEND_SIGNAL(src, COMSIG_HUMAN_CREATE_MOB_HUD) /datum/hud/human var/hud_alpha = 255 diff --git a/code/datums/elements/shatters_when_thrown.dm b/code/datums/elements/shatters_when_thrown.dm new file mode 100644 index 000000000000..441d365e58c5 --- /dev/null +++ b/code/datums/elements/shatters_when_thrown.dm @@ -0,0 +1,56 @@ +/** + * When attached to something, will make that thing shatter into shards on throw impact or z level falling + */ +/datum/element/shatters_when_thrown + element_flags = ELEMENT_BESPOKE + + /// What type of item is spawned as a 'shard' once the shattering happens + var/obj/item/shard_type + /// How many shards total are made when the thing we're attached to shatters + var/number_of_shards + /// What sound plays when the thing we're attached to shatters + var/shattering_sound + +/datum/element/shatters_when_thrown/Attach(datum/target, shard_type = /obj/item/shard, number_of_shards = 5, shattering_sound = "shatter") + . = ..() + + if(!ismovable(target)) + return ELEMENT_INCOMPATIBLE + + src.shard_type = shard_type + src.number_of_shards = number_of_shards + src.shattering_sound = shattering_sound + + RegisterSignal(target, COMSIG_MOVABLE_IMPACT, PROC_REF(on_throw_impact)) + +/datum/element/shatters_when_thrown/Detach(datum/target) + . = ..() + + UnregisterSignal(target,COMSIG_MOVABLE_IMPACT) + +/// Tells the parent to shatter if we are thrown and impact something +/datum/element/shatters_when_thrown/proc/on_throw_impact(datum/source, atom/hit_atom) + SIGNAL_HANDLER + INVOKE_ASYNC(src, PROC_REF(shatter), source, hit_atom) + +/// Handles the actual shattering part, throwing shards of whatever is defined on the component everywhere +/datum/element/shatters_when_thrown/proc/shatter(atom/movable/source, atom/hit_atom) + var/generator/scatter_gen = generator("circle", 0, 48, NORMAL_RAND) + var/scatter_turf = get_turf(hit_atom) + + for(var/obj/item/scattered_item as anything in source.contents) + scattered_item.forceMove(scatter_turf) + var/list/scatter_vector = scatter_gen.Rand() + scattered_item.pixel_x = scatter_vector[1] + scattered_item.pixel_y = scatter_vector[2] + + for(var/iteration in 1 to number_of_shards) + var/obj/item/shard = new shard_type(scatter_turf) + shard.pixel_x = rand(-6, 6) + shard.pixel_y = rand(-6, 6) + playsound(scatter_turf, shattering_sound, 60, TRUE) + if(isobj(source)) + var/obj/obj_source = source + obj_source.deconstruct(FALSE) + return + qdel(source) diff --git a/code/datums/uplink_items/uplink_general.dm b/code/datums/uplink_items/uplink_general.dm index 43713e9bdd03..9e9ae2b023d3 100644 --- a/code/datums/uplink_items/uplink_general.dm +++ b/code/datums/uplink_items/uplink_general.dm @@ -827,7 +827,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) name = "Binyat Wireless Hacking System Autoimplanter" desc = "This implant will allow you to wirelessly emag from a distance. However, it will slightly burn you \ on use, and will be quite visual as you are emaging the object. \ - Will not show on unupgraded body scanners." + Will not show on unupgraded body scanners. Incompatible with the Qani-Laaca Sensory Computer." reference = "HKR" item = /obj/item/autosurgeon/organ/syndicate/hackerman_deck cost = 30 // Probably slightly less useful than an emag with heat / cooldown, but I am not going to make it cheaper or everyone picks it over emag diff --git a/code/datums/uplink_items/uplink_traitor.dm b/code/datums/uplink_items/uplink_traitor.dm index e13bdf4b7b8e..db79ccb1a6c5 100644 --- a/code/datums/uplink_items/uplink_traitor.dm +++ b/code/datums/uplink_items/uplink_traitor.dm @@ -529,6 +529,18 @@ surplus = 0 cant_discount = TRUE +/datum/uplink_item/cyber_implants/sensory_enhancer + name = "Qani-Laaca Sensory Computer Autoimplanter" + desc = "Epilepsy Warning: Drug has vibrant visual effects! \ + This spinal implant will inject mephedrone into your system, a powerful stimulant that causes slight heart damage.\ + This stimulant will provide faster movement speed, slight pain resistance, immunity to crawling slowdown, and faster attack speed, though no antistun.\ + Overdosing will cause massive heart damage, but will allow the user to dodge bullets for a minute and attack even faster.\ + Two minute normal uptime, 5 minute cooldown, unlimited uses. Incompatible with the Binyat Wireless Hacking System." + reference = "QLSC" + item = /obj/item/autosurgeon/organ/syndicate/sensory_enhancer + cost = 40 + excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST) //No, nukies do not get to dodge bullets. + /datum/uplink_item/badass/syndiecards name = "Syndicate Playing Cards" desc = "A special deck of space-grade playing cards with a mono-molecular edge and metal reinforcement, making them lethal weapons both when wielded as a blade and when thrown. \ diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 69c272f84647..7d8b6506423e 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1291,3 +1291,6 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons) if(caller && (caller.pass_flags & pass_flags_self)) return TRUE . = !density + +/atom/proc/atom_prehit(obj/item/projectile/P) + return SEND_SIGNAL(src, COMSIG_ATOM_PREHIT, P) diff --git a/code/game/objects/effects/temporary_visuals/misc_visuals.dm b/code/game/objects/effects/temporary_visuals/misc_visuals.dm index 334c9bfe64f8..aec954ae0855 100644 --- a/code/game/objects/effects/temporary_visuals/misc_visuals.dm +++ b/code/game/objects/effects/temporary_visuals/misc_visuals.dm @@ -130,17 +130,19 @@ desc = "It's a decoy!" duration = 15 -/obj/effect/temp_visual/decoy/New(loc, atom/mimiced_atom) - ..() +/obj/effect/temp_visual/decoy/Initialize(mapload, atom/mimiced_atom) + . = ..() alpha = initial(alpha) if(mimiced_atom) name = mimiced_atom.name appearance = mimiced_atom.appearance + invisibility = mimiced_atom.invisibility + alpha = mimiced_atom.alpha setDir(mimiced_atom.dir) mouse_opacity = MOUSE_OPACITY_TRANSPARENT -/obj/effect/temp_visual/decoy/fading/New(loc, atom/mimiced_atom) - ..() +/obj/effect/temp_visual/decoy/fading/Initialize(mapload, atom/mimiced_atom) + . = ..() animate(src, alpha = 0, time = duration) /obj/effect/temp_visual/decoy/fading/threesecond diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 5e76d2e44f9e..eec8b373fca8 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -523,6 +523,8 @@ return if(!isliving(target)) //no buff from attacking inanimate objects return + if(user.reagents.get_reagent_amount("mephedrone") > 15) // No patrick, you do not get to be chainsaw stun immune and bullet immune at once + return if(target.stat != DEAD) //no buff from attacking dead targets user.apply_status_effect(STATUS_EFFECT_CHAINSAW_SLAYING) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 766fb4ec678f..823e29789523 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -800,5 +800,5 @@ emp_act return TRUE /mob/living/carbon/human/projectile_hit_check(obj/item/projectile/P) - return HAS_TRAIT(src, TRAIT_FLOORED) && !density // hit mobs that are intentionally lying down to prevent combat crawling. + return (HAS_TRAIT(src, TRAIT_FLOORED) || HAS_TRAIT(src, TRAIT_NOKNOCKDOWNSLOWDOWN)) && !density // hit mobs that are intentionally lying down to prevent combat crawling. diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index ff78b9ddd8e9..c3dee83a8128 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -284,7 +284,7 @@ if(!has_gravity(H)) return - if(!IS_HORIZONTAL(H)) + if(!IS_HORIZONTAL(H) || (HAS_TRAIT(H, TRAIT_NOKNOCKDOWNSLOWDOWN) && !H.resting)) //You are slowed if crawling without noknockdownslowdown. However, if you are self crawling, you don't ignore it, so no self crawling to not drop items if(HAS_TRAIT(H, TRAIT_GOTTAGOFAST)) . -= 1 else if(HAS_TRAIT(H, TRAIT_GOTTAGONOTSOFAST)) diff --git a/code/modules/projectiles/projectile_base.dm b/code/modules/projectiles/projectile_base.dm index 178f037096d0..a975f1e80290 100644 --- a/code/modules/projectiles/projectile_base.dm +++ b/code/modules/projectiles/projectile_base.dm @@ -279,7 +279,10 @@ var/turf/target_turf = get_turf(A) prehit(A) - var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null + var/pre_permutation = A.atom_prehit(src) + var/permutation = -1 + if(pre_permutation != ATOM_PREHIT_FAILURE) + permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null if(permutation == -1 || forcedodge)// the bullet passes through a dense object! if(forcedodge) forcedodge -= 1 diff --git a/code/modules/reagents/chemistry/reagents/drugs.dm b/code/modules/reagents/chemistry/reagents/drugs.dm index da1e5407c06c..4f5eaba5b801 100644 --- a/code/modules/reagents/chemistry/reagents/drugs.dm +++ b/code/modules/reagents/chemistry/reagents/drugs.dm @@ -802,6 +802,306 @@ animate(pm_controller.controlled_planes[key], transform = matrix(), time = 5, easing = QUAD_EASING) ..() +// Mephedrone. + +#define CONSTANT_DOSE_SAFE_LIMIT 60 +#define CONSTANT_DOSE_DEATH_LIMIT 600 + +#define MEPHEDRONE_SCREEN_FILTER "mephedrone_screen_filter" +#define MEPHEDRONE_SCREEN_BLUR "mephedrone_screen_blur" + +#define MEPHEDRONE_BLUR_EFFECT "mephedrone_dodge_blur" +#define MEPHEDRONE_OVERDOSE_BLUR_EFFECT "mephedrone_overdose_blur" + +// Mephedrone drug, makes the takers of it faster and able to dodge bullets while in their system, to potentially bad side effects +/datum/reagent/mephedrone + name = "Mephedrone" + id = "mephedrone" + description = "A drug originally developed by and for plutonians to assist them during raids. \ + Does not see wide use due to the whole reality-disassociation and heart disease thing afterwards. \ + Can be intentionally overdosed to increase the drug's effects." + reagent_state = LIQUID + color = "#c22a44" + taste_description = "television static" + metabolization_rate = 0.375 * REAGENTS_METABOLISM + overdose_threshold = 15 + addiction_chance = 3 + addiction_threshold = 15 + shock_reduction = 40 // Slight shock reduction to assist with damage / disablers + allowed_overdose_process = TRUE + process_flags = ORGANIC | SYNTHETIC + /// How much time has the drug been in them? + var/constant_dose_time = 0 + /// Keeps track of how many chemicals we are delaying the changeling by. + var/changeling_chemical_tracker = 0 + + +/datum/reagent/mephedrone/on_mob_add(mob/living/carbon/L) + ADD_TRAIT(L, TRAIT_GOTTAGOFAST, id) + ADD_TRAIT(L, TRAIT_NOKNOCKDOWNSLOWDOWN, id) + L.next_move_modifier -= 0.3 // For the duration of this you move and attack faster + + L.sound_environment_override = SOUND_ENVIRONMENT_DIZZY + + RegisterSignal(L, COMSIG_MOVABLE_MOVED, PROC_REF(on_movement)) + RegisterSignal(L, COMSIG_HUMAN_CREATE_MOB_HUD, PROC_REF(no_hud_cheese)) + + if(!L.hud_used) + return + + var/atom/movable/plane_master_controller/game_plane_master_controller = L.hud_used?.plane_master_controllers[PLANE_MASTERS_GAME] + + var/static/list/col_filter_green = list(0.5,0,0,0, 0,1,0,0, 0,0,0.5,0, 0,0,0,1) + + game_plane_master_controller.add_filter(MEPHEDRONE_SCREEN_FILTER, 10, color_matrix_filter(col_filter_green, FILTER_COLOR_RGB)) + + game_plane_master_controller.add_filter(MEPHEDRONE_SCREEN_BLUR, 1, list("type" = "radial_blur", "size" = 0.1)) + + if(!ischangeling(L) || HAS_TRAIT(L, TRAIT_MEPHEDRONE_ADAPTED)) + return + var/datum/antagonist/changeling/cling = L.mind.has_antag_datum(/datum/antagonist/changeling) + cling.chem_recharge_slowdown += 1 + changeling_chemical_tracker += 1 + +/datum/reagent/mephedrone/on_mob_delete(mob/living/carbon/L) + REMOVE_TRAIT(L, TRAIT_GOTTAGOFAST, id) + REMOVE_TRAIT(L, TRAIT_NOKNOCKDOWNSLOWDOWN, id) + var/overdosed = (id in L.reagents.overdose_list()) + L.next_move_modifier += (overdosed ? 0.5 : 0.3) + + L.sound_environment_override = NONE + + UnregisterSignal(L, COMSIG_MOVABLE_MOVED) + if(overdosed) + UnregisterSignal(L, COMSIG_ATOM_PREHIT) + + if(ischangeling(L)) + var/datum/antagonist/changeling/cling = L.mind.has_antag_datum(/datum/antagonist/changeling) + cling.chem_recharge_slowdown -= changeling_chemical_tracker + changeling_chemical_tracker = 0 + + if(constant_dose_time < CONSTANT_DOSE_SAFE_LIMIT) // Anything less than this and you'll come out fiiiine, aside from a big hit of stamina damage + L.visible_message( + "[L] suddenly slows from their inhuman speeds, coming back with a wicked nosebleed!", + "You suddenly slow back to normal, a stream of blood gushing from your nose!") + L.adjustStaminaLoss(constant_dose_time) + else // Much longer than that however, and you're not gonna have a good day + L.visible_message( + "[L] suddenly snaps back from their inhumans speeds, coughing up a spray of blood!", + "As you snap back to normal speed you cough up a worrying amount of blood. You feel like you've just been run over by a power loader.") + L.custom_emote(EMOTE_VISIBLE, "coughs up blood!") + L.bleed(25) + L.apply_damage(max(constant_dose_time / 3, 60), STAMINA) + L.KnockDown((constant_dose_time / 15) SECONDS) // a minute is a 4 second knockdown, 2 is 8, etc + if(!HAS_TRAIT(L, TRAIT_MEPHEDRONE_ADAPTED) || constant_dose_time >= CONSTANT_DOSE_DEATH_LIMIT) //If you are going infinite with mito and you run out, you deserve this even with an implant + if(ishuman(L)) + var/mob/living/carbon/human/H = L + var/datum/organ/heart/datum_heart = H.get_int_organ_datum(ORGAN_DATUM_HEART) + if(datum_heart) + var/obj/item/organ/internal/our_heart = datum_heart.linked_organ + our_heart.receive_damage(0.15 * constant_dose_time, TRUE) // Basically you might die. Especially if you are a slime. + else + handle_heartless(L, 0.15 * constant_dose_time) + + + if(!L.hud_used) + return + + var/atom/movable/plane_master_controller/game_plane_master_controller = L.hud_used?.plane_master_controllers[PLANE_MASTERS_GAME] + + game_plane_master_controller.remove_filter(MEPHEDRONE_SCREEN_FILTER) + game_plane_master_controller.remove_filter(MEPHEDRONE_SCREEN_BLUR) + + +/// Leaves an afterimage behind the mob when they move +/datum/reagent/mephedrone/proc/on_movement(mob/living/carbon/L, atom/old_loc) + SIGNAL_HANDLER + if(HAS_TRAIT(L, TRAIT_IMMOBILIZED)) //No, dead people floating through space do not need afterimages + return NONE + var/overdosed = (id in L.reagents.overdose_list()) + new /obj/effect/temp_visual/decoy/mephedrone_afterimage(old_loc, L, overdosed ? 1.25 SECONDS : 0.75 SECONDS) + +/// Tries to dodge incoming bullets if we aren't disabled for any reasons +/datum/reagent/mephedrone/proc/dodge_bullets(mob/living/carbon/human/source, obj/item/projectile/hitting_projectile) + SIGNAL_HANDLER + + if(HAS_TRAIT(source, TRAIT_IMMOBILIZED)) + return NONE + source.visible_message( + "[source] effortlessly dodges [hitting_projectile]!", + "You effortlessly evade [hitting_projectile]!", + ) + playsound(source, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE) + source.add_filter(MEPHEDRONE_BLUR_EFFECT, 2, gauss_blur_filter(5)) + addtimer(CALLBACK(source, TYPE_PROC_REF(/atom, remove_filter), MEPHEDRONE_BLUR_EFFECT), 0.5 SECONDS) + return ATOM_PREHIT_FAILURE + + +/// So. If a person changes up their hud settings (Changing their ui theme), the visual effects for this reagent will break, and they will be able to see easily. This 3 part proc waits for the plane controlers to be setup, and over 2 other procs, rengages the visuals +/datum/reagent/mephedrone/proc/no_hud_cheese(mob/living/carbon/L) + SIGNAL_HANDLER + addtimer(CALLBACK(src, PROC_REF(no_hud_cheese_2), L), 2 SECONDS) //Calling it instantly will not work, need to give it a moment + +/// This part of the anticheese sets up the basic visual effects normally setup when the reagent gets into your system. +/datum/reagent/mephedrone/proc/no_hud_cheese_2(mob/living/carbon/L) //Basically if you change the UI you would remove the visuals. This fixes that. + var/atom/movable/plane_master_controller/game_plane_master_controller = L.hud_used?.plane_master_controllers[PLANE_MASTERS_GAME] + game_plane_master_controller.remove_filter(MEPHEDRONE_SCREEN_FILTER) + game_plane_master_controller.remove_filter(MEPHEDRONE_SCREEN_BLUR) + + var/static/list/col_filter_green = list(0.5,0,0,0, 0,1,0,0, 0,0,0.5,0, 0,0,0,1) + + game_plane_master_controller.add_filter(MEPHEDRONE_SCREEN_FILTER, 10, color_matrix_filter(col_filter_green, FILTER_COLOR_RGB)) + + game_plane_master_controller.add_filter(MEPHEDRONE_SCREEN_BLUR, 1, list("type" = "radial_blur", "size" = 0.1)) + + var/overdosed = (id in L.reagents.overdose_list()) + if(overdosed) + addtimer(CALLBACK(src, PROC_REF(no_hud_cheese_3), L), 1 SECONDS) //still needs a moment + +///This part sets up the OD visual effects. +/datum/reagent/mephedrone/proc/no_hud_cheese_3(mob/living/carbon/L) + var/atom/movable/plane_master_controller/game_plane_master_controller = L?.hud_used.plane_master_controllers[PLANE_MASTERS_GAME] + var/list/col_filter_ourple = list(1,0,0,0, 0,0.5,0,0, 0,0,1,0, 0,0,0,1) + + for(var/filter in game_plane_master_controller.get_filters(MEPHEDRONE_SCREEN_FILTER)) + animate(filter, loop = -1, color = col_filter_ourple, time = 4 SECONDS, easing = BOUNCE_EASING) + +/datum/reagent/mephedrone/on_mob_life(mob/living/carbon/L) + . = ..() + + constant_dose_time += 2 + + if(ishuman(L)) + var/heart_damage = 0.1 + if(L.reagents.has_reagent("methamphetamine")) //We want people to use something other than meth, since meths downside is knockdowns / be orginal + heart_damage = 1.1 + var/mob/living/carbon/human/H = L + var/datum/organ/heart/datum_heart = H.get_int_organ_datum(ORGAN_DATUM_HEART) + if(datum_heart) + var/obj/item/organ/internal/our_heart = datum_heart.linked_organ + our_heart.receive_damage(heart_damage, TRUE) + else + handle_heartless(L, heart_damage) + +/datum/reagent/mephedrone/overdose_start(mob/living/L) + + RegisterSignal(L, COMSIG_ATOM_PREHIT, PROC_REF(dodge_bullets)) + + L.next_move_modifier -= 0.2 // Overdosing makes you a liiitle faster but you know has some really bad consequences + if(ischangeling(L)) + var/datum/antagonist/changeling/cling = L.mind.has_antag_datum(/datum/antagonist/changeling) + cling.chem_recharge_slowdown += 1 + changeling_chemical_tracker += 1 + + if(!L.hud_used) + return + + var/atom/movable/plane_master_controller/game_plane_master_controller = L?.hud_used.plane_master_controllers[PLANE_MASTERS_GAME] + + var/list/col_filter_ourple = list(1,0,0,0, 0,0.5,0,0, 0,0,1,0, 0,0,0,1) + + for(var/filter in game_plane_master_controller.get_filters(MEPHEDRONE_SCREEN_FILTER)) + animate(filter, loop = -1, color = col_filter_ourple, time = 4 SECONDS, easing = BOUNCE_EASING) + ..() + + +/datum/reagent/mephedrone/overdose_end(mob/living/L) + UnregisterSignal(L, COMSIG_ATOM_PREHIT) + + L.next_move_modifier += 0.2 + + if(ischangeling(L)) + var/datum/antagonist/changeling/cling = L.mind.has_antag_datum(/datum/antagonist/changeling) + if(changeling_chemical_tracker > 0) //Just in case this gets called somehow after on_remove is done + cling.chem_recharge_slowdown -= 1 + changeling_chemical_tracker -= 1 + + if(!L.hud_used) + return + + var/atom/movable/plane_master_controller/game_plane_master_controller = L.hud_used?.plane_master_controllers[PLANE_MASTERS_GAME] //Restart the base filters. + + game_plane_master_controller.remove_filter(MEPHEDRONE_SCREEN_FILTER) + + game_plane_master_controller.remove_filter(MEPHEDRONE_SCREEN_BLUR) + + var/static/list/col_filter_green = list(0.5,0,0,0, 0,1,0,0, 0,0,0.5,0, 0,0,0,1) + + game_plane_master_controller.add_filter(MEPHEDRONE_SCREEN_FILTER, 10, color_matrix_filter(col_filter_green, FILTER_COLOR_RGB)) + + game_plane_master_controller.add_filter(MEPHEDRONE_SCREEN_BLUR, 1, list("type" = "radial_blur", "size" = 0.1)) + + +/datum/reagent/mephedrone/overdose_process(mob/living/carbon/L) + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + var/datum/organ/heart/datum_heart = H.get_int_organ_datum(ORGAN_DATUM_HEART) + if(datum_heart) + var/obj/item/organ/internal/our_heart = datum_heart.linked_organ + our_heart.receive_damage(0.9, TRUE) + else + handle_heartless(L, 0.9) + + + if(prob(5)) + L.custom_emote(EMOTE_VISIBLE, "coughs up blood!") + L.bleed(5) + + if(prob(10)) + L.add_filter(MEPHEDRONE_OVERDOSE_BLUR_EFFECT, 2, phase_filter(8)) + addtimer(CALLBACK(L, TYPE_PROC_REF(/atom, remove_filter), MEPHEDRONE_OVERDOSE_BLUR_EFFECT), 0.5 SECONDS) + + var/update_flags = STATUS_UPDATE_NONE + L.Jitter(2.2 SECONDS) // Slowly will build up over time due to low process rate + update_flags |= L.adjustToxLoss(1 * REAGENTS_EFFECT_MULTIPLIER, FALSE) + return ..() | update_flags + +//This proc is for IPCS, skeletons, golems, and people with corazone. IPCS are treated lightly, power loss and brain damage. +//IPC brain damage gets an increase with liquid solder, so it matters +//Otherwise, the user hallucinates a bunch, and as well takes stamina damage. This will block passive stamina regen, and most likely require antistun drugs to use as well + +/datum/reagent/mephedrone/proc/handle_heartless(mob/living/carbon/L, damage_input) + if(ismachineperson(L)) + L.adjust_nutrition(-damage_input * 7.5) + if(damage_input == 0.9) //This is the input from the OD + L.adjustBrainLoss(1.75) + if(L.reagents.has_reagent("liquid_solder")) + L.adjustBrainLoss(2.75) + else //Corazone or skeletons. We go hard on them. + L.Hallucinate(damage_input * 50 SECONDS) + L.apply_damage(damage_input * 3, STAMINA) + +/// This filter proc makes a visual effect where the object is split into fragments, with vertical lines cut out of them. It will appear as 2 seperate things are made of the one object that was cut out +/proc/phase_filter(size) + . = list("type" = "wave") + .["x"] = 1 + if(!isnull(size)) + .["size"] = size + + +// Temp visual that changes color for that bootleg sandevistan effect +/obj/effect/temp_visual/decoy/mephedrone_afterimage + duration = 0.75 SECONDS + /// The color matrix it should be at spawn + var/list/matrix_start = list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, 0,0.1,0.4,0) + /// The color matrix it should be by the time it despawns + var/list/matrix_end = list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, 0,0.5,0,0) + +/obj/effect/temp_visual/decoy/mephedrone_afterimage/Initialize(mapload, atom/mimiced_atom, our_duration = 0.75 SECONDS) + duration = our_duration + . = ..() + color = matrix_start + animate(src, color = matrix_end, time = duration, easing = EASE_OUT) + animate(src, alpha = 0, time = duration, easing = EASE_OUT) + +#undef MEPHEDRONE_SCREEN_FILTER +#undef MEPHEDRONE_SCREEN_BLUR + +#undef MEPHEDRONE_BLUR_EFFECT +#undef MEPHEDRONE_OVERDOSE_BLUR_EFFECT + + ////////////////////////////// // Synth-Drugs // ////////////////////////////// diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm index 7057b02f99ba..9ba2163d191a 100644 --- a/code/modules/reagents/chemistry/reagents/medicine.dm +++ b/code/modules/reagents/chemistry/reagents/medicine.dm @@ -101,10 +101,13 @@ /datum/reagent/medicine/mitocholide/on_mob_life(mob/living/M) if(ishuman(M)) var/mob/living/carbon/human/H = M + var/heal_modifier = 0.4 + if(M.reagents.has_reagent("mephedrone")) + heal_modifier -= 0.3 //This lowers the healing to 0.1. As such, you need time off the drug to heal heart damage, but can be on the drug endlessly when not oding IF you keep your supply going. //Mitocholide is hard enough to get, it's probably fair to make this all internal organs for(var/obj/item/organ/internal/I in H.internal_organs) - I.heal_internal_damage(0.4) + I.heal_internal_damage(heal_modifier) return ..() /datum/reagent/medicine/mitocholide/reaction_obj(obj/O, volume) @@ -1213,7 +1216,7 @@ color = "#FFDCFF" taste_description = "stability" harmless = FALSE - var/list/drug_list = list("crank", "methamphetamine", "space_drugs", "synaptizine", "psilocybin", "ephedrine", "epinephrine", "stimulants", "stimulative_agent", "bath_salts", "lsd", "thc") + var/list/drug_list = list("crank", "methamphetamine", "space_drugs", "synaptizine", "psilocybin", "ephedrine", "epinephrine", "stimulants", "stimulative_agent", "bath_salts", "lsd", "thc", "mephedrone") /datum/reagent/medicine/haloperidol/on_mob_life(mob/living/M) var/update_flags = STATUS_UPDATE_NONE @@ -1467,7 +1470,7 @@ metabolization_rate = 0.5 harmless = FALSE taste_description = "2 minutes of suffering" - var/list/stimulant_list = list("methamphetamine", "crank", "bath_salts", "stimulative_agent", "stimulants") + var/list/stimulant_list = list("methamphetamine", "crank", "bath_salts", "stimulative_agent", "stimulants", "mephedrone") /datum/reagent/medicine/nanocalcium/on_mob_life(mob/living/carbon/human/M) var/update_flags = STATUS_UPDATE_NONE diff --git a/code/modules/reagents/chemistry/reagents_datum.dm b/code/modules/reagents/chemistry/reagents_datum.dm index fa5aa62e8842..90cb9a79e576 100644 --- a/code/modules/reagents/chemistry/reagents_datum.dm +++ b/code/modules/reagents/chemistry/reagents_datum.dm @@ -205,6 +205,9 @@ /datum/reagent/proc/overdose_start(mob/living/M) return +/datum/reagent/proc/overdose_end(mob/living/M) + return + /datum/reagent/proc/addiction_act_stage1(mob/living/M) return STATUS_UPDATE_NONE diff --git a/code/modules/reagents/chemistry/reagents_holder.dm b/code/modules/reagents/chemistry/reagents_holder.dm index 9be2cdc7df8a..3a08aa5fd75c 100644 --- a/code/modules/reagents/chemistry/reagents_holder.dm +++ b/code/modules/reagents/chemistry/reagents_holder.dm @@ -352,6 +352,7 @@ update_flags |= R.on_mob_overdose_life(M) //We want to drain reagents but not do the entire mob life. if(R.volume < R.overdose_threshold && R.overdosed) R.overdosed = FALSE + R.overdose_end(M) if(R.overdosed) var/list/overdose_results = R.overdose_process(M, R.volume >= R.overdose_threshold * 2 ? 2 : 1) if(overdose_results) // to protect against poorly-coded overdose procs diff --git a/code/modules/reagents/chemistry/recipes/drugs_reactions.dm b/code/modules/reagents/chemistry/recipes/drugs_reactions.dm index d9d928ff7ec9..78c9fd9e9226 100644 --- a/code/modules/reagents/chemistry/recipes/drugs_reactions.dm +++ b/code/modules/reagents/chemistry/recipes/drugs_reactions.dm @@ -68,6 +68,21 @@ mix_message = "Tiny cubic crystals precipitate out of the mixture. Huh." mix_sound = 'sound/goonstation/misc/fuse.ogg' +/datum/chemical_reaction/mephedrone + name = "Mephedrone" + id = "mephedrone" + result = "mephedrone" + required_reagents = list("bath_salts" = 5, "carpotoxin" = 5, "teslium" = 5) + result_amount = 10 + min_temp = T0C + 100 + mix_message = "The mixture fizzes into a vibrant red solution that doesn't stay still." + mix_sound = 'sound/goonstation/misc/fuse.ogg' + +/datum/chemical_reaction/mephedrone/on_reaction(datum/reagents/holder) //Will make it harder for botany, need a chem heater or will suffer, and mixing in plants wont work + var/turf/T = get_turf(holder.my_atom) + fireflash(holder.my_atom, 3, 500) + explosion(T, 0, 0, 2, 2, flame_range = 2) + /datum/chemical_reaction/jenkem name = "Jenkem" id = "jenkem" diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 7e981736a9d7..4f9c1c4d4ba4 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -399,6 +399,21 @@ build_path = /obj/item/organ/internal/cyberimp/arm/razorwire category = list("Medical") +/datum/design/cyberimp_sensory_enhancer + name = "Qani-Laaca Sensory Computer Implant" + desc = "An experimental implant replacing the spine of organics. When activated, it can give a temporary boost to mental processing speed, \ + which many users perceive as a slowing of time and quickening of their ability to act. Due to its nature, it is incompatible with \ + systems that heavily influence the user's nervous system, like the central nervous system rebooter. \ + As a bonus effect, you are immune to the burst of heart damage that comes at the end of mephedrone usage, as the computer is able to regulate \ + your heart's rhythm back to normal after its use." + id = "ci-sensory-enhancer" + req_tech = list("combat" = 7, "biotech" = 7, "syndicate" = 5) + build_type = PROTOLATHE | MECHFAB + materials = list(MAT_METAL = 10000, MAT_SILVER = 2000, MAT_PLASMA = 10000, MAT_DIAMOND = 4000, MAT_BLUESPACE = 4000) + construction_time = 10 SECONDS + build_path = /obj/item/organ/internal/cyberimp/brain/sensory_enhancer/rnd + category = list("Medical") + /datum/design/cyberimp_toolset_abductor name = "Abductor Toolset Implant" desc = "An alien toolset, designed to be installed on subject's arm." diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm index e0733411b137..c348540cc8b8 100644 --- a/code/modules/surgery/organs/augments_internal.dm +++ b/code/modules/surgery/organs/augments_internal.dm @@ -304,6 +304,134 @@ origin_tech = "materials=6;programming=6;biotech=6" emp_proof = TRUE +// An implant that injects you with mephedrone on demand, acting like a bootleg sandevistan + +/obj/item/organ/internal/cyberimp/brain/sensory_enhancer + name = "\improper Qani-Laaca sensory computer" + desc = "An experimental implant replacing the spine of organics. When activated, it can give a temporary boost to mental processing speed, \ + which many users perceive as a slowing of time and quickening of their ability to act. Due to its nature, it is incompatible with \ + systems that heavily influence the user's nervous system, like the central nervous system rebooter. \ + As a bonus effect, you are immune to the burst of heart damage that comes at the end of mephedrone usage, as the computer is able to regulate \ + your heart's rhythm back to normal after its use." + icon_state = "sandy" + implant_overlay = null + implant_color = null + slot = "brain_antistun" + emp_proof = TRUE + actions_types = list(/datum/action/item_action/organ_action/toggle/sensory_enhancer) + origin_tech = "combat=6;biotech=6;syndicate=4" + ///The icon state used for the on mob sprite. Default is sandy. Drask and vox have their own unique sprites + var/custom_mob_sprite = "sandy" + COOLDOWN_DECLARE(sensory_enhancer_cooldown) + +/obj/item/organ/internal/cyberimp/brain/sensory_enhancer/rnd + emp_proof = FALSE + +/obj/item/organ/internal/cyberimp/brain/sensory_enhancer/examine(mob/user) + . = ..() + . += "Epilepsy Warning: Drug has vibrant visual effects!" + +/obj/item/organ/internal/cyberimp/brain/sensory_enhancer/examine_more(mob/user) + . = ..() + . += "Developed by Biotech Solutions this revolutionary full spinal cord replacement implant uses an integrated chemical synthesizer designed to administer Mephedrone: \ + a potent stimulant and hyper-movement drug. This implant dramatically enhances the user's reflexes, with many reporting an almost time-slowing effect during its operation." + . += "Biotech's experimentation with stimulant drug research has long been a cornerstone of their competitive edge, especially against their rival: \ + Interydyne Pharmaceuticals, whose efforts yielded a drug capable of enhancing reflexes, although they were never mitigate the adverse effects of said product. \ + A premature leak of the prototype implant pressured the company into accelerating its development, leaving the drug's side effects unresolved. \ + They completed the spinal implant, which is uniquely equipped with built-in vials for Mephedrone delivery. \ + Its material is solid plastitanium, and while strong in material, it surprisingly feels light, considering its spinal integration." + . += "The implant is highly sought after because of its extreme capabilities in combat. Many military groups pay a handsome fee simply for the licensing of the item. \ + In spite of this, recent Biotech shipments have come under fire from piracy, with the company quick to blame Interdyne for said attacks. Said allegations remain unverified." + + +/obj/item/organ/internal/cyberimp/brain/sensory_enhancer/insert(mob/living/carbon/M, special = 0) + . = ..() + ADD_TRAIT(M, TRAIT_MEPHEDRONE_ADAPTED, "[UID()]") + +/obj/item/organ/internal/cyberimp/brain/sensory_enhancer/remove(mob/living/carbon/M, special = 0) + . = ..() + REMOVE_TRAIT(M, TRAIT_MEPHEDRONE_ADAPTED, "[UID()]") + +/obj/item/organ/internal/cyberimp/brain/sensory_enhancer/render() + if(isvox(owner)) + custom_mob_sprite = "vox_sandy" + else if(isdrask(owner)) + custom_mob_sprite = "drask_sandy" + else + custom_mob_sprite = "sandy" + var/mutable_appearance/our_MA = mutable_appearance('icons/mob/human_races/robotic.dmi', icon_state, layer = -INTORGAN_LAYER) + return our_MA + +/obj/item/organ/internal/cyberimp/brain/sensory_enhancer/emp_act(severity) + if(COOLDOWN_FINISHED(src, sensory_enhancer_cooldown)) //Not on cooldown? Drug them up. Heavily. We don't want people self emping to bypass cooldown. + if(prob(100 / severity) && owner) + for(var/datum/action/item_action/organ_action/toggle/sensory_enhancer/SE in owner.actions) + SE.Trigger(FALSE, TRUE, TRUE) + . = ..() + +/datum/action/item_action/organ_action/toggle/sensory_enhancer + name = "Activate Qani-Laaca System" + desc = "Activates your Qani-Laaca computer and grants you its powers. LMB: Short, safer activation. ALT/MIDDLE: Longer, more powerful, more dangerous activation." + button_icon = 'icons/obj/surgery.dmi' + button_icon_state = "sandy" + check_flags = AB_CHECK_CONSCIOUS + /// Keeps track of how much mephedrone we inject into people on activation + var/injection_amount = 10 + + +/datum/action/item_action/organ_action/toggle/sensory_enhancer/AltTrigger() + Trigger(FALSE, TRUE) + +/datum/action/item_action/organ_action/toggle/sensory_enhancer/Trigger(left_click, attack_self, emp_triggered = FALSE) + . = ..() + if(istype(target, /obj/item/organ/internal/cyberimp/brain/sensory_enhancer)) + var/obj/item/organ/internal/cyberimp/brain/sensory_enhancer/ourtarget = target + if(!COOLDOWN_FINISHED(ourtarget, sensory_enhancer_cooldown)) + to_chat(owner, "[ourtarget] is still on cooldown for another [round(COOLDOWN_TIMELEFT(ourtarget, sensory_enhancer_cooldown), 1 SECONDS) / 10] seconds!") + return + + COOLDOWN_START(ourtarget, sensory_enhancer_cooldown, 5 MINUTES) + + injection_amount = 10 + + if(!left_click) + injection_amount = 20 + if(emp_triggered) + injection_amount = 40 //Time for a quick medical visit + Activate() + + +/datum/action/item_action/organ_action/toggle/sensory_enhancer/proc/Activate(atom/target) + + var/mob/living/carbon/human/human_owner = owner + + human_owner.reagents.add_reagent("mephedrone", injection_amount) + + owner.visible_message("[owner.name] jolts suddenly as two small glass vials are fired from ports in the implant on [owner.p_their()] spine, shattering as they land.", \ + "You jolt suddenly as your Qani-Laaca system ejects two empty glass vials rearward, shattering as they land.") + playsound(human_owner, 'sound/goonstation/items/hypo.ogg', 80, TRUE) + + var/obj/item/telegraph_vial = new /obj/item/qani_laaca_telegraph(get_turf(owner)) + var/turf/turf_we_throw_at = get_edge_target_turf(owner, REVERSE_DIR(owner.dir)) + telegraph_vial.throw_at(turf_we_throw_at, 5, 1) + + // Safety net in case the injection amount doesn't get reset. Apparently it happened to someone in a round. + injection_amount = initial(injection_amount) + +/obj/item/qani_laaca_telegraph + name = "spent Qani-Laaca cartridge" + desc = "A small glass vial, usually kept in a large stack inside a Qani-Laaca implant, that is broken open and ejected \ + each time the implant is used. If you're looking at one long enough to think about it this long, you either have fast eyes \ + or were lucky enough to catch one before it broke." + icon = 'icons/obj/surgery.dmi' + icon_state = "blastoff_ampoule_empty" + w_class = WEIGHT_CLASS_TINY + +/obj/item/qani_laaca_telegraph/Initialize(mapload) + . = ..() + AddElement(/datum/element/shatters_when_thrown, /obj/effect/decal/cleanable/glass, 1, "shatter") + transform = transform.Scale(0.75, 0.75) + /obj/item/organ/internal/cyberimp/brain/hackerman_deck name = "\improper Binyat wireless hacking system" desc = "A rare-to-find neural chip that allows its user to interface with nearby machinery from a distance \ diff --git a/code/modules/surgery/organs/autosurgeon.dm b/code/modules/surgery/organs/autosurgeon.dm index f64f973273bd..881f797ad940 100644 --- a/code/modules/surgery/organs/autosurgeon.dm +++ b/code/modules/surgery/organs/autosurgeon.dm @@ -121,6 +121,20 @@ . += "As of modern times, the BWHS is heavily vetted under Cybersun Inc. due to its dangerous nature and rather difficult detection. \ However, this hasn't stopped the flow of these implants from reaching the black market, whether by inside or outside influences." +/obj/item/autosurgeon/organ/syndicate/sensory_enhancer + desc = "A single use autosurgeon that contains a Qani-Laaca sensory computer. A screwdriver can be used to remove it, but implants can't be placed back in." + uses = 1 + starting_organ = /obj/item/organ/internal/cyberimp/brain/sensory_enhancer + +/obj/item/autosurgeon/organ/syndicate/sensory_enhancer/examine(mob/user) + . = ..() + . += "Epilepsy Warning: Drug has vibrant visual effects!" + +/obj/item/autosurgeon/organ/syndicate/sensory_enhancer/examine_more(mob/user) + . = ..() + if(storedorgan) + return storedorgan.examine_more() + /obj/item/autosurgeon/organ/syndicate/thermal_eyes starting_organ = /obj/item/organ/internal/eyes/cybernetic/thermals/hardened diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 2087f6208e45..9f624bc55c5c 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -59,6 +59,7 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M parent = H.get_organ(check_zone(parent_organ)) + H.update_int_organs() if(!istype(parent)) stack_trace("[src] attempted to insert into a [parent_organ], but [parent_organ] wasn't an organ! [atom_loc_line(M)]") else diff --git a/icons/mob/human_races/robotic.dmi b/icons/mob/human_races/robotic.dmi index f956c6a6f20a5ee8bcfe332bf2069c37d516d292..2d73cf8ff74f305bafe1c9a35ae2fddc8e5256bd 100644 GIT binary patch literal 2505 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 literal 1538 zcmV+d2L1VoP)o5}g-Q0(zqLzAC>fF~7=snt z;8-Aw_WDWMp;M{0C-@{Ds5STgF-)c#2mJ)935&Uz>*1)?D|wFFa5-xgA%)1Fp|WGx zVw3HR$c(RQ0K42CNi6Q@a=ly1%1t?&Puvk5!9 z2$D>IU^xGm)0gzUvZzF0000000000000000002Md{AOwOTLZPPR!2gKUz6v z(JITu*g@52L{)|Z#Fa9BilLI4v-(&3%NYJ@BmEV`h5<%eb5{R`S!N#q0000000000 z002B1C8xE}z|*>+Chg3(>S;aQATJ|0Hg8DmMF)IV()DfwyMNukJdCufHM*GC&M?SM z44X!V3u1tV_oHXf>|ggUkFhi8STkT(zzmMO2K4~fe+^mz&O3u!7iTp2ZWBOW0{{R3 zK*7{cyQN*26AED;p11ob=Ex<;E$zrmP~|I*+XX*zOJ6Fx%5mHd#UEGIOFJ_MwR6me z!-3hkK|!I4~Co<1(qjH=Uh;<~)?R&O#X;}h>N8_r44KbCf6E~x#CFpIX=%S$(b zFSCunSH$*LKAlheI@j>jjX&QElF>h%IKI^J58?SFx1OHEK^eXq->Uk*TfZ~kZ}uNQ zrw>63FeD43`%#%~I{>Hl@8-P69h34AM^K()#_4y9b4;7TTH6thoWb%Lr{ArBar)f~ z7^mL>000000B}FMq_C-&S^uJC0eTMm5R`}M-En86{i8v-5~QOy*Sx>Usc&ipI5j1a z+DqMTQ1#g|J4fN|H}zYZPOwNDXBU8MMY zU9+Wr2&bJ4a8`jm`QC=wy?r#7%cWr_IOsyW!Z;`utFbYf1UtanE@-L%14%28+^>(z zX9`d-aFj$;BQF}~-_);q5<4jyWV|aAlG94@_Hg;SG@^ghYQ&W+fm2nr60&_L&rMx5 z`Ke^fIJ^`fotxjEznimMlieo9jTuyP=l>1O-`tCr^Ja07udgqy=)BGSS7KT!9XOO1 zV9yerDnKPMNPKSMOB{+)$-b#g_>2Jmyx#=){>OS#CiPBym`eKES<%-zc}oA7$kVTG z^6Ro!6GEMSr<@BmRe;Mtoqnf$H%a%u`wJ9XX_PL{6Dv0vbAD`#WvSb{wY*^%E0C^$ zobA$MJedt+w^#0F5C8xG000000N5z`sg!jlT?WWkLSE35SBp)TWr#l4r|+dMDhiYN zGc|+sIiYYnNrTgQG%ppKWoFnzAyTFLq^&oF)NR^Mw; zq`6_v+@3Es=rpmuZ#NBeP5u7NXy~?3f`mJFFXi6LJLZ_dvgoa&S-=kf000000KitT zD&f{%DaY)+SI(=k+DnJ_SHyBpqrG@2gzxwgD~@A(%X$Oc?|po2cLw7%7UxI324i?D zz6Q5{7X<(S0Op3NSH>Bn?nwVXD0ZzqW;{j|;{H;JLHb;ezSj~+{`Tn8qh!6R|6ymE z8Psc49wh4tr62=~6olVT^j&!X0000006=k!Jqy2d$S0Kl^s6?P5AD6z)R`pTM2q!C zcoo>bb%707*qoM6N<$f)@DBYybcN diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index 7153ac1b94c0b3ef6a9a057fbc6e53ed7574feb5..bfd47a9ec1363e07af05f785b0bc4fa25832a0a2 100644 GIT binary patch literal 31650 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 literal 30742 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 Date: Wed, 6 Mar 2024 07:27:50 -0600 Subject: [PATCH 13/43] Adds shards to glass and plasmaglass crafting menu (#24226) --- code/game/objects/items/stacks/sheets/glass.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index ef50232da87f..49734f15e06f 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -15,6 +15,7 @@ */ GLOBAL_LIST_INIT(glass_recipes, list ( + new /datum/stack_recipe("glass shard", /obj/item/shard, time = 0 SECONDS), new /datum/stack_recipe/window("directional window", /obj/structure/window/basic, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE), new /datum/stack_recipe/window("fulltile window", /obj/structure/window/full/basic, 2, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE), new /datum/stack_recipe("fishbowl", /obj/machinery/fishtank/bowl, 1, time = 1 SECONDS), @@ -92,6 +93,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( */ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( + new /datum/stack_recipe("glass shard", /obj/item/shard, time = 0 SECONDS), new /datum/stack_recipe/window("windoor frame", /obj/structure/windoor_assembly, 5, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE), null, new /datum/stack_recipe/window("directional reinforced window", /obj/structure/window/reinforced, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE), @@ -128,6 +130,7 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( . += "Reinforced glass is much stronger against damage than normal glass, otherwise it functions like normal glass does." GLOBAL_LIST_INIT(pglass_recipes, list ( + new /datum/stack_recipe("plasma shard", /obj/item/shard/plasma, time = 0 SECONDS), new /datum/stack_recipe/window("directional window", /obj/structure/window/plasmabasic, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE), new /datum/stack_recipe/window("fulltile window", /obj/structure/window/full/plasmabasic, 2, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE) )) @@ -184,6 +187,7 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( */ GLOBAL_LIST_INIT(prglass_recipes, list ( + new /datum/stack_recipe("plasma shard", /obj/item/shard/plasma, time = 0 SECONDS), new /datum/stack_recipe/window("directional reinforced window", /obj/structure/window/plasmareinforced, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE), new /datum/stack_recipe/window("fulltile reinforced window", /obj/structure/window/full/plasmareinforced, 2, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE) )) From 6e9f01b4f91fcf69b34391cabc25242877dac4ef Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Wed, 6 Mar 2024 08:30:23 -0500 Subject: [PATCH 14/43] ci: update maplint for APC mapping helpers (#24367) --- tools/maplint/lints/apc_pixel_shifts.yml | 7 ----- tools/maplint/lints/directional_apcs.yml | 33 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) delete mode 100644 tools/maplint/lints/apc_pixel_shifts.yml create mode 100644 tools/maplint/lints/directional_apcs.yml diff --git a/tools/maplint/lints/apc_pixel_shifts.yml b/tools/maplint/lints/apc_pixel_shifts.yml deleted file mode 100644 index 1556f73dc8e1..000000000000 --- a/tools/maplint/lints/apc_pixel_shifts.yml +++ /dev/null @@ -1,7 +0,0 @@ -help: "Use the directional variants when possible." -/obj/machinery/power/apc: - banned_variables: - pixel_x: - allow: [24, -24] - pixel_y: - allow: [24, -24] diff --git a/tools/maplint/lints/directional_apcs.yml b/tools/maplint/lints/directional_apcs.yml new file mode 100644 index 000000000000..ff6bdf2e42e2 --- /dev/null +++ b/tools/maplint/lints/directional_apcs.yml @@ -0,0 +1,33 @@ +help: "Use the specific directional subtypes for this APC." +/obj/machinery/power/apc: + banned_variables: + - pixel_x + - pixel_y +=/obj/machinery/power/apc: + banned: true +=/obj/machinery/power/apc/directional: + banned: true +=/obj/machinery/power/apc/important: + banned: true +=/obj/machinery/power/apc/important/directional: + banned: true +=/obj/machinery/power/apc/critical: + banned: true +=/obj/machinery/power/apc/critical/directional: + banned: true +=/obj/machinery/power/apc/off_station: + banned: true +=/obj/machinery/power/apc/off_station/directional: + banned: true +=/obj/machinery/power/apc/syndicate: + banned: true +=/obj/machinery/power/apc/syndicate/directional: + banned: true +=/obj/machinery/power/apc/syndicate/off: + banned: true +=/obj/machinery/power/apc/syndicate/off/directional: + banned: true +=/obj/machinery/power/apc/worn_out: + banned: true +=/obj/machinery/power/apc/worn_out/directional: + banned: true From 980af06a6bac4f9e30fd6feca36723ae0f50b677 Mon Sep 17 00:00:00 2001 From: Adrer Date: Wed, 6 Mar 2024 15:27:31 +0100 Subject: [PATCH 15/43] HUD is now updated properly when mob goes invisible. (#24332) Co-authored-by: adrermail@gmail.com --- code/modules/mob/mob_misc_procs.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/mob/mob_misc_procs.dm b/code/modules/mob/mob_misc_procs.dm index c388d4fc4a41..6030bf2004aa 100644 --- a/code/modules/mob/mob_misc_procs.dm +++ b/code/modules/mob/mob_misc_procs.dm @@ -817,3 +817,7 @@ actual_hud.invisibility = invis_value else actual_hud.invisibility = initial(actual_hud.invisibility) + // Yes we need to remove the HUD from all HUDs then re-add it to update the HUD being invisible. + // No, I don't like it either. + remove_from_all_data_huds() + add_to_all_human_data_huds() From 00c0f227889e2eb228ed437c8c35aefd6e57c47c Mon Sep 17 00:00:00 2001 From: GDN <96800819+GDNgit@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:28:18 -0600 Subject: [PATCH 16/43] fixes deleted cultists still being considered cultists (#24336) --- code/game/gamemodes/cult/cult_mode.dm | 2 ++ code/modules/mob/living/simple_animal/constructs.dm | 7 +++++-- code/modules/mob/living/simple_animal/shade.dm | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/code/game/gamemodes/cult/cult_mode.dm b/code/game/gamemodes/cult/cult_mode.dm index 4f2d21d8b5c1..98a73d955844 100644 --- a/code/game/gamemodes/cult/cult_mode.dm +++ b/code/game/gamemodes/cult/cult_mode.dm @@ -164,6 +164,7 @@ cult_objs.study(cult_mind.current) to_chat(cult_mind.current, "For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Cultist)") RegisterSignal(cult_mind.current, COMSIG_MOB_STATCHANGE, PROC_REF(cultist_stat_change)) + RegisterSignal(cult_mind.current, COMSIG_PARENT_QDELETING, PROC_REF(remove_cultist)) return TRUE /datum/game_mode/proc/remove_cultist(datum/mind/cult_mind, show_message = TRUE, remove_gear = FALSE, mob/target_mob) @@ -204,6 +205,7 @@ cultist.visible_message("[cultist] looks like [cultist.p_they()] just reverted to [cultist.p_their()] old faith!", "An unfamiliar white light flashes through your mind, cleansing the taint of [SSticker.cultdat ? SSticker.cultdat.entity_title1 : "Nar'Sie"] and the memories of your time as their servant with it.") UnregisterSignal(cult_mind.current, COMSIG_MOB_STATCHANGE) + UnregisterSignal(cult_mind.current, COMSIG_PARENT_QDELETING) /datum/game_mode/proc/add_cult_immunity(mob/living/target) ADD_TRAIT(target, TRAIT_CULT_IMMUNITY, CULT_TRAIT) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index c1187ee2682e..cd5bc149f7d7 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -57,7 +57,6 @@ return ..() /mob/living/simple_animal/hostile/construct/death(gibbed) - SSticker.mode.remove_cultist(show_message = FALSE, target_mob = src) if(held_body) // Null check for empty bodies held_body.forceMove(get_turf(src)) SSticker.mode.add_cult_immunity(held_body) @@ -71,7 +70,11 @@ held_body.cancel_camera() new /obj/effect/temp_visual/cult/sparks(get_turf(src)) playsound(src, 'sound/effects/pylon_shatter.ogg', 40, TRUE) - . = ..() + return ..() + +/mob/living/simple_animal/hostile/construct/Destroy() + SSticker.mode.remove_cultist(show_message = FALSE, target_mob = src) + return ..() /mob/living/simple_animal/hostile/construct/proc/add_held_body(atom/movable/body) held_body = body diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index 789e61be2146..7b49bb26964a 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -38,9 +38,9 @@ . = ..() icon_state = SSticker.cultdat?.shade_icon_state -/mob/living/simple_animal/shade/death(gibbed) - . = ..() +/mob/living/simple_animal/shade/Destroy() SSticker.mode.remove_cultist(show_message = FALSE, target_mob = src) + return ..() /mob/living/simple_animal/shade/attackby(obj/item/O, mob/user) //Marker -Agouri if(istype(O, /obj/item/soulstone)) From 6eb4f325393f7c3f5e0c4edefcc620805fd3cf97 Mon Sep 17 00:00:00 2001 From: cybercapitalism <98280110+cybercapitalism@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:30:01 -0600 Subject: [PATCH 17/43] check if species can use an emote even if their mob type can't (#24361) --- code/datums/emote.dm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/datums/emote.dm b/code/datums/emote.dm index 42304b2f8795..c813add82fe0 100644 --- a/code/datums/emote.dm +++ b/code/datums/emote.dm @@ -477,9 +477,9 @@ . = TRUE if(!is_type_in_typecache(user, mob_type_allowed_typecache)) return FALSE - if(is_type_in_typecache(user, mob_type_blacklist_typecache)) - return FALSE + // the user's mob type may not be allowed, but its species could be + var/species_can_use = FALSE if(ishuman(user)) var/mob/living/carbon/human/H = user if(H.dna) @@ -489,6 +489,10 @@ if(species_type_blacklist_typecache && is_type_in_typecache(H.dna.species, species_type_blacklist_typecache)) return FALSE + species_can_use = TRUE + + if(is_type_in_typecache(user, mob_type_blacklist_typecache) && !species_can_use) + return FALSE if(intentional && only_unintentional) return FALSE From 529d26eb6644a5437dfc4f2b2025b66283d32f07 Mon Sep 17 00:00:00 2001 From: Mikhail Dzianishchyts Date: Wed, 6 Mar 2024 17:30:27 +0300 Subject: [PATCH 18/43] Make the safe at Moon Outpost 19 be unknown to captain (#24369) --- _maps/map_files/RandomRuins/SpaceRuins/moonoutpost19.dmm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/_maps/map_files/RandomRuins/SpaceRuins/moonoutpost19.dmm b/_maps/map_files/RandomRuins/SpaceRuins/moonoutpost19.dmm index 7afde38c1526..4ed9278cd1c8 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/moonoutpost19.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/moonoutpost19.dmm @@ -10522,9 +10522,7 @@ }, /area/ruin/space/moonbase19) "On" = ( -/obj/structure/safe/floor{ - known_by = list("captain") - }, +/obj/structure/safe/floor, /obj/structure/sign/singulo{ pixel_y = 32 }, From d6f7046e2e8aa7ce3fbdd80a5a49c99f7aba796b Mon Sep 17 00:00:00 2001 From: Charlie Nolan Date: Wed, 6 Mar 2024 06:31:01 -0800 Subject: [PATCH 19/43] Borgs without a client can be reset now (#24466) --- code/modules/mob/living/silicon/robot/robot_mob.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/silicon/robot/robot_mob.dm b/code/modules/mob/living/silicon/robot/robot_mob.dm index 13a3652075ca..c922efd11328 100644 --- a/code/modules/mob/living/silicon/robot/robot_mob.dm +++ b/code/modules/mob/living/silicon/robot/robot_mob.dm @@ -518,8 +518,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( notify_ai(2) shown_robot_modules = 0 - client.screen -= robot_modules_background - client.screen -= hud_used.module_store_icon + client?.screen -= robot_modules_background + client?.screen -= hud_used.module_store_icon uneq_all() SStgui.close_user_uis(src) sight_mode = null From df8e93b4320d7a1b028e5e382f440e958eabd5ab Mon Sep 17 00:00:00 2001 From: Charlie Nolan Date: Wed, 6 Mar 2024 06:32:30 -0800 Subject: [PATCH 20/43] Fixed lastproduce initialization for grass. (#24339) --- code/modules/hydroponics/hydroponics_tray.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/hydroponics/hydroponics_tray.dm b/code/modules/hydroponics/hydroponics_tray.dm index 42fe9a3adff7..caaf5502565b 100644 --- a/code/modules/hydroponics/hydroponics_tray.dm +++ b/code/modules/hydroponics/hydroponics_tray.dm @@ -152,7 +152,7 @@ if(myseed && !dead) // Advance age age++ - if(age < myseed.maturation) + if(age <= myseed.maturation) lastproduce = age needs_update = 1 @@ -227,7 +227,7 @@ adjustHealth(-rand(1,5) / rating) // Harvest code - if(age > myseed.production && (age - lastproduce) > myseed.production && (!harvest && !dead)) + if(age > myseed.production && (age - lastproduce) >= myseed.production && (!harvest && !dead)) nutrimentMutation() if(myseed && myseed.yield != -1) // Unharvestable shouldn't be harvested harvest = TRUE From 6805e816a4b4f7266c1aac7913f6c9ef0af9bc1a Mon Sep 17 00:00:00 2001 From: Rerik007 <120549107+Rerik007@users.noreply.github.com> Date: Wed, 6 Mar 2024 17:36:50 +0300 Subject: [PATCH 21/43] fix bot emag in ion storm (#24424) --- code/modules/events/ion_storm.dm | 18 +++++++++--------- .../mob/living/simple_animal/bot/bot.dm | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index c37ab566734a..fc511c39892b 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -22,20 +22,20 @@ /datum/event/ion_storm/start() //AI laws - for(var/mob/living/silicon/ai/M in GLOB.alive_mob_list) - if(M.stat != DEAD && M.see_in_dark != FALSE) + for(var/mob/living/silicon/ai/ai_player as anything in GLOB.ai_list) + if(ai_player.stat != DEAD && ai_player.see_in_dark != FALSE) var/message = generate_ion_law(ionMessage) if(message) - M.add_ion_law(message) - to_chat(M, "
") - to_chat(M, "[message] ...LAWS UPDATED") - to_chat(M, "
") + ai_player.add_ion_law(message) + to_chat(ai_player, "
") + to_chat(ai_player, "[message] ...LAWS UPDATED") + to_chat(ai_player, "
") - for(var/player in GLOB.dead_mob_list) - to_chat(player, "[M] ([ghost_follow_link(M, player)]) has received an ion law:\n'[message]'") + for(var/ghost in GLOB.dead_mob_list) + to_chat(ghost, "[ai_player] ([ghost_follow_link(ai_player, ghost)]) has received an ion law:\n'[message]'") if(botEmagChance) - for(var/mob/living/simple_animal/bot/bot in GLOB.machines) + for(var/mob/living/simple_animal/bot/bot as anything in GLOB.bots_list) if(prob(botEmagChance)) bot.emag_act() diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 08fc714f25d1..7445fed15fd8 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -262,7 +262,8 @@ turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP. to_chat(src, "(#$*#$^^( OVERRIDE DETECTED") show_laws() - add_attack_logs(user, src, "Emagged") + if(user) + add_attack_logs(user, src, "Emagged") return TRUE else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet. to_chat(user, "You need to open maintenance panel first!") From 2e61b6c51fa92adab091ee82d18c2684cd70e806 Mon Sep 17 00:00:00 2001 From: Aylong <69762909+AyIong@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:37:50 +0200 Subject: [PATCH 22/43] Refresh TGUI blank window fix (#24392) * Refresh TGUI blank window fix * Whoopsie * Separate things --- code/modules/tgui/tgui_panel/tgui_panel_external.dm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/code/modules/tgui/tgui_panel/tgui_panel_external.dm b/code/modules/tgui/tgui_panel/tgui_panel_external.dm index 67cd6d612e23..7de8a6705f02 100644 --- a/code/modules/tgui/tgui_panel/tgui_panel_external.dm +++ b/code/modules/tgui/tgui_panel/tgui_panel_external.dm @@ -39,6 +39,19 @@ set name = "Refresh TGUI" set category = "Special Verbs" + var/choice = alert(usr, + "Use it ONLY if you have trouble with TGUI window.\ + That's UI's with EYE on top-left corner.\ + Otherwise, you can get a white window that will only close when you restart the game!", "Refresh TGUI", "Refresh", "Cancel") + if(choice != "Refresh") + return + var/refreshed_count = 0 for(var/window_id in tgui_windows) var/datum/tgui_window/window = tgui_windows[window_id] + if(!window.locked) + window.acquire_lock() + continue window.reinitialize() + refreshed_count++ + to_chat(usr, "TGUI windows refreshed - [refreshed_count].
If you have blank window - restart the game, or open previous TGUI window.
") + From adc58d9302dac4fc911dd8afe0707569e05ac07e Mon Sep 17 00:00:00 2001 From: HMBGERDO <61080616+HMBGERDO@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:40:44 +0100 Subject: [PATCH 23/43] *deathgasp (#24403) --- .../chemistry/reagents/food_reagents.dm | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index e1e666e56ab3..1db066db7dc0 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -222,27 +222,8 @@ if(method == REAGENT_TOUCH) if(ishuman(M)) var/mob/living/carbon/human/victim = M - var/mouth_covered = FALSE - var/eyes_covered = FALSE - var/obj/item/safe_thing = null - if(victim.wear_mask) - if(victim.wear_mask.flags_cover & MASKCOVERSEYES) - eyes_covered = TRUE - safe_thing = victim.wear_mask - if(victim.wear_mask.flags_cover & MASKCOVERSMOUTH) - mouth_covered = TRUE - safe_thing = victim.wear_mask - if(victim.head) - if(victim.head.flags_cover & MASKCOVERSEYES) - eyes_covered = TRUE - safe_thing = victim.head - if(victim.head.flags_cover & MASKCOVERSMOUTH) - mouth_covered = TRUE - safe_thing = victim.head - - if(eyes_covered && mouth_covered) - to_chat(victim, "Your [safe_thing] protects you from the pepperspray!") - return + var/mouth_covered = victim.is_mouth_covered() + var/eyes_covered = victim.is_eyes_covered() if(!mouth_covered) victim.apply_status_effect(STATUS_EFFECT_PEPPERSPRAYED) From e6a147e3da2881ecec1cc1bfe9bb3b68f5d4c265 Mon Sep 17 00:00:00 2001 From: Divulf <134484326+Divulf@users.noreply.github.com> Date: Thu, 7 Mar 2024 03:42:49 +1300 Subject: [PATCH 24/43] Puts some of the stack crafting code onto the stack recipe datum. (#24252) * Puts some of the stack crafting code onto the stack recipe datum to allow for more and easier customization of what happens when a recipe is crafted. * Very important spacing. * Better returns. * Removed \the macro, fixed bug in message that occurs when lacking resources for a construction. * The do_after() should probably be on do_build() --- code/game/objects/items/stacks/stack.dm | 68 ++------------ .../game/objects/items/stacks/stack_recipe.dm | 91 +++++++++++++++++-- 2 files changed, 87 insertions(+), 72 deletions(-) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 9a23693e8cd9..59fbda65aa8e 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -213,75 +213,19 @@ message_admins("[key_name_admin(usr)] just attempted to href exploit sheet crafting with an invalid multiplier. Ban highly advised.") multiplier = 1 - if(get_amount() < R.req_amount * multiplier) - if(R.req_amount * multiplier > 1) - to_chat(usr, "You haven't got enough [src] to build \the [R.req_amount * multiplier] [R.title]\s!") - else - to_chat(usr, "You haven't got enough [src] to build \the [R.title]!") - return FALSE - - if(R.window_checks && !valid_window_location(get_turf(src), usr.dir)) - to_chat(usr, "\The [R.title] won't fit here!") - return FALSE - - if(R.one_per_turf && (locate(R.result_type) in get_turf(src))) - to_chat(usr, "There is another [R.title] here!") - return FALSE - - if(R.on_floor && !issimulatedturf(get_turf(src))) - to_chat(usr, "\The [R.title] must be constructed on the floor!") - return FALSE - if(R.on_floor_or_lattice && !(issimulatedturf(get_turf(src)) || locate(/obj/structure/lattice) in get_turf(src))) - to_chat(usr, "\The [R.title] must be constructed on the floor or lattice!") - return FALSE - - if(R.cult_structure) - if(usr.holy_check()) - return - if(!is_level_reachable(usr.z)) - to_chat(usr, "The energies of this place interfere with the metal shaping!") - return - if(locate(/obj/structure/cult) in get_turf(src)) - to_chat(usr, "There is a structure here!") - return FALSE - - if(R.time) - to_chat(usr, "Building [R.title]...") - if(!do_after(usr, R.time, target = loc)) - return FALSE - - if(R.cult_structure && locate(/obj/structure/cult) in get_turf(src)) //Check again after do_after to prevent queuing construction exploit. - to_chat(usr, "There is a structure here!") - return FALSE - - if(get_amount() < R.req_amount * multiplier) + if(!R.try_build(usr, src, multiplier)) return - - var/atom/O - if(R.max_res_amount > 1) //Is it a stack? - O = new R.result_type(get_turf(src), R.res_amount * multiplier) - else - O = new R.result_type(get_turf(src)) - O.setDir(usr.dir) - use(R.req_amount * multiplier) - updateUsrDialog() - - R.post_build(src, O) + var/obj/O + O = R.do_build(usr, src, multiplier, O) + if(!O) + return + R.post_build(usr, src, O) if(amount < 1) // Just in case a stack's amount ends up fractional somehow var/oldsrc = src src = null //dont kill proc after qdel() usr.unEquip(oldsrc, 1) qdel(oldsrc) - if(isitem(O)) - usr.put_in_hands(O) - - O.add_fingerprint(usr) - //BubbleWrap - so newly formed boxes are empty - if(isstorage(O)) - for(var/obj/item/I in O) - qdel(I) - //BubbleWrap END if(src && usr.machine == src) //do not reopen closed window spawn(0) diff --git a/code/game/objects/items/stacks/stack_recipe.dm b/code/game/objects/items/stacks/stack_recipe.dm index 67e80bd9156d..13acf7b06e43 100644 --- a/code/game/objects/items/stacks/stack_recipe.dm +++ b/code/game/objects/items/stacks/stack_recipe.dm @@ -28,34 +28,104 @@ src.window_checks = window_checks src.cult_structure = cult_structure -/datum/stack_recipe/proc/post_build(obj/item/stack/S, obj/result) - return +/// Returns TRUE if the recipe can be built, otherwise returns FALSE. This proc is only meant as a series of tests to check if construction is possible; the actual creation of the resulting atom should be handled in do_build() +/datum/stack_recipe/proc/try_build(mob/user, obj/item/stack/S, multiplier) + if(S.get_amount() < req_amount * multiplier) + if(req_amount * multiplier > 1) + to_chat(user, "You haven't got enough [S] to build [res_amount * multiplier] [title]\s!") + else + to_chat(user, "You haven't got enough [S] to build [title]!") + return FALSE + + if(window_checks && !valid_window_location(get_turf(S), user.dir)) + to_chat(user, "[title] won't fit here!") + return FALSE + + if(one_per_turf && (locate(result_type) in get_turf(S))) + to_chat(user, "There is another [title] here!") + return FALSE + + if(on_floor && !issimulatedturf(get_turf(S))) + to_chat(user, "[title] must be constructed on the floor!") + return FALSE + if(on_floor_or_lattice && !(issimulatedturf(get_turf(S)) || locate(/obj/structure/lattice) in get_turf(S))) + to_chat(user, "[title] must be constructed on the floor or lattice!") + return FALSE + + if(cult_structure) + if(user.holy_check()) + return FALSE + if(!is_level_reachable(user.z)) + to_chat(user, "The energies of this place interfere with the metal shaping!") + return FALSE + if(locate(/obj/structure/cult) in get_turf(S)) + to_chat(user, "There is a structure here!") + return FALSE + + return TRUE + +/// Creates the atom defined by the recipe. Should always return the object it creates or FALSE. This proc assumes that the construction is already possible; for checking whether a recipe *can* be built before construction, use try_build() +/datum/stack_recipe/proc/do_build(mob/user, obj/item/stack/S, multiplier, atom/O) + if(time) + to_chat(user, "Building [title]...") + if(!do_after(user, time, target = S.loc)) + return FALSE + + if(cult_structure && locate(/obj/structure/cult) in get_turf(S)) //Check again after do_after to prevent queuing construction exploit. + to_chat(user, "There is a structure here!") + return FALSE + + if(S.get_amount() < req_amount * multiplier) // Check they still have enough. + return FALSE + + if(max_res_amount > 1) //Is it a stack? + O = new result_type(get_turf(S), res_amount * multiplier) + else + O = new result_type(get_turf(S)) + O.setDir(user.dir) + S.use(req_amount * multiplier) + S.updateUsrDialog() + return O + +/// What should be done after the object is built? obj/item/stack/O might not actually be a stack, but this proc needs access to merge() to work, which is on obj/item/stack, so declare it as obj/item/stack anyways. +/datum/stack_recipe/proc/post_build(mob/user, obj/item/stack/S, obj/item/stack/O) + O.add_fingerprint(user) + + if(isitem(O)) + if(isstack(O) && istype(O, user.get_inactive_hand())) + O.merge(user.get_inactive_hand()) + user.put_in_hands(O) + + //BubbleWrap - so newly formed boxes are empty + if(isstorage(O)) + for(var/obj/item/I in O) + qdel(I) + //BubbleWrap END /* Special Recipes */ /datum/stack_recipe/cable_restraints -/datum/stack_recipe/cable_restraints/post_build(obj/item/stack/S, obj/result) +/datum/stack_recipe/cable_restraints/post_build(mob/user, obj/item/stack/S, obj/result) if(istype(result, /obj/item/restraints/handcuffs/cable)) result.color = S.color ..() - /datum/stack_recipe/dangerous -/datum/stack_recipe/dangerous/post_build(obj/item/stack/S, obj/result) - var/turf/targ = get_turf(usr) - message_admins("[title] made by [key_name_admin(usr)](
?) in [get_area(usr)] [ADMIN_COORDJMP(targ)]!",0,1) - log_game("[title] made by [key_name_admin(usr)] at [get_area(usr)] [targ.x], [targ.y], [targ.z].") +/datum/stack_recipe/dangerous/post_build(mob/user, obj/item/stack/S, obj/result) + var/turf/targ = get_turf(user) + message_admins("[title] made by [key_name_admin(user)](?) in [get_area(user)] [ADMIN_COORDJMP(targ)]!",0,1) + log_game("[title] made by [key_name_admin(user)] at [get_area(user)] [targ.x], [targ.y], [targ.z].") ..() /datum/stack_recipe/rods -/datum/stack_recipe/rods/post_build(obj/item/stack/S, obj/result) +/datum/stack_recipe/rods/post_build(mob/user, obj/item/stack/S, obj/result) if(istype(result, /obj/item/stack/rods)) var/obj/item/stack/rods/R = result R.update_icon() ..() /datum/stack_recipe/window -/datum/stack_recipe/window/post_build(obj/item/stack/S, obj/result) +/datum/stack_recipe/window/post_build(mob/user, obj/item/stack/S, obj/result) if(istype(result, /obj/structure/windoor_assembly)) var/obj/structure/windoor_assembly/W = result W.ini_dir = W.dir @@ -64,6 +134,7 @@ W.ini_dir = W.dir W.anchored = FALSE W.state = WINDOW_OUT_OF_FRAME + ..() /* * Recipe list datum From 8f11c1dfd38ebf45b1a33911a61b216ab3e15e2e Mon Sep 17 00:00:00 2001 From: HMBGERDO <61080616+HMBGERDO@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:44:46 +0100 Subject: [PATCH 25/43] Throwing fix (#24087) * non gravity movement, flat second immobilized removed * let it be * naming * Update code/controllers/subsystem/SSthrowing.dm * Update code/controllers/subsystem/SSthrowing.dm Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> * Revert "Update code/controllers/subsystem/SSthrowing.dm" This reverts commit 20ef2af3510090ec14388e9f4fab937ec34eead9. * comment update --------- Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> --- code/controllers/subsystem/SSthrowing.dm | 16 +++++++++++++++- code/game/atoms_movable.dm | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/SSthrowing.dm b/code/controllers/subsystem/SSthrowing.dm index 10944b42c338..ffb81987b4de 100644 --- a/code/controllers/subsystem/SSthrowing.dm +++ b/code/controllers/subsystem/SSthrowing.dm @@ -71,6 +71,8 @@ SUBSYSTEM_DEF(throwing) ///When this variable is false, non dense mobs will be hit by a thrown item. useful for things that you dont want to be cheesed by crawling, EG. gravitational anomalies var/dodgeable = TRUE /// Can a thrown mob move themselves to stop the throw? + var/should_block_movement = TRUE + /// Will thrownthing datum actually block movement? this might be FALSE with some circumstances even if var/should_block_movement is TRUE. This variable change automatically during the throw var/block_movement = TRUE /datum/thrownthing/proc/tick() @@ -94,7 +96,19 @@ SUBSYSTEM_DEF(throwing) //calculate how many tiles to move, making up for any missed ticks. var/tilestomove = CEILING(min(((((world.time + world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed * MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1) while(tilestomove-- > 0) - if((dist_travelled >= maxrange || AM.loc == target_turf) && has_gravity(AM, AM.loc)) + var/gravity + if(ismob(AM)) + var/mob/mob = AM + gravity = mob.mob_has_gravity(mob.loc) + else + gravity = has_gravity(AM, AM.loc) + + if(!gravity) + block_movement = FALSE // you should be able to move if there is no gravity, supports jetpack movement during throw + else + block_movement = should_block_movement + + if((dist_travelled >= maxrange || AM.loc == target_turf) && gravity) hitcheck() //Just to be sure finalize() return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 98c6784021b5..77b7b969f935 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -442,7 +442,7 @@ TT.diagonals_first = diagonals_first TT.callback = callback TT.dodgeable = dodgeable - TT.block_movement = block_movement + TT.should_block_movement = block_movement var/dist_x = abs(target.x - src.x) var/dist_y = abs(target.y - src.y) From ce7c7f98850b9cff3b5f19120a16965c52d1de8a Mon Sep 17 00:00:00 2001 From: Deniz <66401072+Oyu07@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:05:39 +0000 Subject: [PATCH 26/43] Yet another Bot refactor. 2.0 (#23900) * test 1 claim_job comment spaces start * yay, its BROKE * Update bot.dm * alcohol is the only escape * static * it works * spacing * cleanbot list cleanup * comments * space AREA This is what insanity looks like. Every bot PR breaks something, without fail. fixed replace tiles? broke hull breach fixed hullbreach? broke cleanbots fixed hullbreach? well also broke it * Comment Sorting * comments 2/2 * comments 3/? * comments 4/? * autodoc 1/? * maketile doesnt drop * maketile update * floor - snake_case + if else * Floor - comments * floor - snake_case 2/? * cleanbot turf reservation comment * floorbot ignore list * comments * var/atom/A * target check. null runtime * tile clean comment removal * again * reviews. final_result removal * comment block * avoid bot TRUE * comments ?/? I lost track of how manny comment commits there are * autodocs * autodoc * autodocs * ignore_job -= target.UID() additions * anchored Noticed that, if a tile is in space, they will dance around it as they do not anchor. Now they do * runtime fix * ignore_job edits. clean after 30 * typo * fix before replace, DUH * ignore job clearing * Time Dilation 106% no more * eat tile fix, oops * replace plating * comment shift * lets try again * mode ! * process_type = null + to_chat cleanup + ignore_job bot_reset * remove extra ignore_job * target.loc * TRUE * ignore job and revert loc * move speed and such * comment with proc * God I hate myself * TRUE / FALSE * comments :) * else if * pesky comment * mods are asleep, rename the vars * small edits * Make ignore_job culling based on amount of bots alive. 1 job per bot * Revert move speed changes. Bots move slower than security on cere * Emag fixes oof * ++ * + 1? * ++ * comment * dropped metal amount * paranthesis * no need for absolute * Thanks VSC conflict resolver for duplicating this here * Emag is a bool now, self remind comment removed * Documentation * move speed null nulled * replace_tile lag / freeze fix + removed extra job stuff * clarification about which list is being used in comment --- .../mob/living/simple_animal/bot/bot.dm | 352 ++++++++++-------- .../mob/living/simple_animal/bot/cleanbot.dm | 5 +- .../mob/living/simple_animal/bot/floorbot.dm | 110 +++--- 3 files changed, 265 insertions(+), 202 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 7445fed15fd8..1dbf4a1c62fe 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -15,7 +15,7 @@ minbodytemp = 0 has_unlimited_silicon_privilege = TRUE sentience_type = SENTIENCE_ARTIFICIAL - status_flags = 0 //no default canpush + status_flags = 0 // No default canpush can_strip = FALSE speak_emote = list("states") @@ -23,66 +23,104 @@ bubble_icon = "machine" faction = list("neutral", "silicon") - var/list/users = list() //for dialog updates + var/list/users = list() // For dialog updates var/window_id = "bot_control" - var/window_name = "Protobot 1.0" //Popup title - var/window_width = 0 //0 for default size + var/window_name = "Protobot 1.0" // Popup title + var/window_width = 0 // 0 for default size var/window_height = 0 - var/obj/item/paicard/paicard // Inserted pai card. - var/allow_pai = TRUE // Are we even allowed to insert a pai card. + var/obj/item/paicard/paicard // Inserted pai card. + var/allow_pai = TRUE // Are we even allowed to insert a pai card. var/bot_name var/disabling_timer_id = null var/list/player_access = list() var/emagged = FALSE - var/obj/item/card/id/access_card // the ID card that the bot "holds" + /// The ID card that the bot "holds" + var/obj/item/card/id/access_card var/list/prev_access = list() var/on = TRUE - var/open = FALSE //Maint panel + /// Maint panel + var/open = FALSE var/locked = TRUE - var/hacked = FALSE //Used to differentiate between being hacked by silicons and emagged by humans. + /// Used to differentiate between being hacked by silicons and emagged by humans. + var/hacked = FALSE /// Is currently hijacked by a pulse demon? var/hijacked = FALSE - var/text_hack = "" //Custom text returned to a silicon upon hacking a bot. - var/text_dehack = "" //Text shown when resetting a bots hacked status to normal. - var/text_dehack_fail = "" //Shown when a silicon tries to reset a bot emagged with the emag item, which cannot be reset. - var/declare_message = "" //What the bot will display to the HUD user. - var/frustration = 0 //Used by some bots for tracking failures to reach their target. - var/base_speed = 2 //The speed at which the bot moves, or the number of times it moves per process() tick. - var/turf/ai_waypoint //The end point of a bot's path, or the target location. - var/list/path = list() //List of turfs through which a bot 'steps' to reach the waypoint + /// Custom text returned to a silicon upon hacking a bot. + var/text_hack = "" + /// Text shown when resetting a bots hacked status to normal. + var/text_dehack = "" + /// Shown when a silicon tries to reset a bot emagged with the emag item, which cannot be reset. + var/text_dehack_fail = "" + /// What the bot will display to the HUD user. + var/declare_message = "" + /// Used by some bots for tracking failures to reach their target. + var/frustration = 0 + /// The speed at which the bot moves, or the number of times it moves per process() tick. + var/base_speed = 2 + /// The end point of a bot's path, or the target location. + var/turf/ai_waypoint + /// List of turfs through which a bot 'steps' to reach the waypoint + var/list/path = list() var/pathset = FALSE - var/list/ignore_list = list() //List of unreachable targets for an ignore-list enabled bot to ignore. - var/mode = BOT_IDLE //Standardizes the vars that indicate the bot is busy with its function. - var/tries = 0 //Number of times the bot tried and failed to move. - var/remote_disabled = FALSE //If enabled, the AI cannot *Remotely* control a bot. It can still control it through cameras. - var/mob/living/silicon/ai/calling_ai //Links a bot to the AI calling it. - var/obj/item/radio/Radio //The bot's radio, for speaking to people. - var/list/radio_config = null //which channels can the bot listen to - var/radio_channel = "Common" //The bot's default radio channel - var/auto_patrol = FALSE // set to make bot automatically patrol - var/turf/patrol_target // this is turf to navigate to (location of beacon) - var/turf/summon_target // The turf of a user summoning a bot. - var/new_destination // pending new destination (waiting for beacon response) - var/destination // destination description tag - var/next_destination // the next destination in the patrol route - var/ignorelistcleanuptimer = 1 // This ticks up every automated action, at 300 we clean the ignore list + /// List of unreachable targets for an ignore-list enabled bot to ignore. + var/list/ignore_list = list() + /// List of jobs claimed by bot + var/static/list/ignore_job = list() + /// Standardizes the vars that indicate the bot is busy with its function. + var/mode = BOT_IDLE + /// Number of times the bot tried and failed to move. + var/tries = 0 + /// If enabled, the AI cannot *Remotely* control a bot. It can still control it through cameras. + var/remote_disabled = FALSE + /// Links a bot to the AI calling it. + var/mob/living/silicon/ai/calling_ai + /// The bot's radio, for speaking to people. + var/obj/item/radio/Radio + /// Which channels can the bot listen to + var/list/radio_config = null + /// The bot's default radio channel + var/radio_channel = "Common" + /// Set to make bot automatically patrol + var/auto_patrol = FALSE + /// This is turf to navigate to (location of beacon) + var/turf/patrol_target + /// The turf of a user summoning a bot. + var/turf/summon_target + /// Pending new destination (waiting for beacon response) + var/new_destination + /// Destination description tag + var/destination + /// The next destination in the patrol route + var/next_destination + /// This ticks up every automated action, at 300 we clean the ignore list + var/ignore_list_cleanup_timer = 1 var/robot_arm = /obj/item/robot_parts/r_arm - var/blockcount = 0 //number of times retried a blocked path - var/awaiting_beacon = 0 // count of pticks awaiting a beacon response + /// Number of times retried a blocked path + var/blockcount = 0 + /// Count of pticks awaiting a beacon response + var/awaiting_beacon = 0 - var/nearest_beacon // the nearest beacon's tag - var/turf/nearest_beacon_loc // the nearest beacon's location + /// The nearest beacon's tag + var/nearest_beacon + /// The nearest beacon's location + var/turf/nearest_beacon_loc - var/model = "" //The type of bot it is. + ///The type of bot it is. + var/model = "" + /// Bot Purpose under Show Laws var/bot_purpose = "improve the station to the best of your ability" - var/control_freq = BOT_FREQ // bot control frequency - var/bot_filter // The radio filter the bot uses to identify itself on the network. - var/bot_type = 0 //The type of bot it is, for radio control. + /// Bot control frequency + var/control_freq = BOT_FREQ + + /// The radio filter the bot uses to identify itself on the network. + var/bot_filter + /// The type of bot it is, for radio control. + var/bot_type = 0 /// The type of data HUD the bot uses. Diagnostic by default. var/data_hud_type = DATA_HUD_DIAGNOSTIC_BASIC - //This holds text for what the bot is mode doing, reported on the remote bot control interface. + // This holds text for what the bot is mode doing, reported on the remote bot control interface. var/list/mode_name = list("In Pursuit","Preparing to Arrest", "Arresting", \ "Beginning Patrol", "Patrolling", "Summoned by PDA", \ "Cleaning", "Repairing", "Proceeding to work site", "Healing", \ @@ -94,11 +132,11 @@ /// List of access values you can have to access the bot. Consider this as req_one_access var/list/req_access = list() - hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD)//Diagnostic HUD views + hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD) // Diagnostic HUD views - /// storing last chased target known location + /// Storing last chased target known location var/turf/last_target_location - /// will be true if we lost target we were chasing + /// Will be true if we lost target we were chasing var/lost_target = FALSE /obj/item/radio/headset/bot @@ -110,7 +148,7 @@ if(istype(B)) if(!B.radio_config) B.radio_config = list("AI Private" = 1) - if(!(B.radio_channel in B.radio_config)) // put it first so it's the :h channel + if(!(B.radio_channel in B.radio_config)) // Put it first so it's the :h channel B.radio_config.Insert(1, "[B.radio_channel]") B.radio_config["[B.radio_channel]"] = 1 config(B.radio_config) @@ -146,7 +184,7 @@ frustration++ /mob/living/simple_animal/bot/proc/get_mode() - if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player. + if(client) // Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player. if(paicard) return "pAI Controlled" else @@ -164,20 +202,20 @@ if(disabling_timer_id) return FALSE if(stat) - return 0 + return FALSE on = TRUE REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, "depowered") set_light(initial(light_range)) update_icon(UPDATE_ICON_STATE | UPDATE_OVERLAYS) update_controls() diag_hud_set_botstat() - return 1 + return TRUE /mob/living/simple_animal/bot/proc/turn_off() on = FALSE ADD_TRAIT(src, TRAIT_IMMOBILIZED, "depowered") set_light(0) - bot_reset() //Resets an AI's call, should it exist. + bot_reset() // Resets an AI's call, should it exist. update_icon(UPDATE_ICON_STATE | UPDATE_OVERLAYS) update_controls() @@ -187,7 +225,7 @@ icon_living = icon_state icon_dead = icon_state access_card = new /obj/item/card/id(src) - //This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first. + // This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first. access_card.access += ACCESS_ROBOTICS set_custom_texts() Radio = new/obj/item/radio/headset/bot(src) @@ -210,10 +248,10 @@ /mob/living/simple_animal/bot/med_hud_set_health() - return //we use a different hud + return // We use a different hud /mob/living/simple_animal/bot/med_hud_set_status() - return //we use a different hud + return // We use a different hud /mob/living/simple_animal/bot/Destroy() @@ -250,21 +288,23 @@ qdel(src) /mob/living/simple_animal/bot/emag_act(mob/user) - if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again. + if(locked) // First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again. locked = FALSE to_chat(user, "You bypass [src]'s controls.") return TRUE + if(!locked && open) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging. emagged = TRUE - remote_disabled = TRUE //Manually emagging the bot locks out the AI built in panel. - locked = TRUE //Access denied forever! + remote_disabled = TRUE // Manually emagging the bot locks out the AI built in panel. + locked = TRUE // Access denied forever! bot_reset() - turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP. + turn_on() // The bot automatically turns on when emagged, unless recently hit with EMP. to_chat(src, "(#$*#$^^( OVERRIDE DETECTED") show_laws() if(user) add_attack_logs(user, src, "Emagged") return TRUE + else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet. to_chat(user, "You need to open maintenance panel first!") @@ -290,14 +330,14 @@ /mob/living/simple_animal/bot/handle_automated_action() diag_hud_set_botmode() - if(ignorelistcleanuptimer % 300 == 0) // Every 300 actions, clean up the ignore list from old junk + if(++ignore_list_cleanup_timer == 300) // Every 300 actions, clean up the ignore list from old junk for(var/uid in ignore_list) - var/atom/referredatom = locateUID(uid) - if(!referredatom || QDELETED(referredatom)) + var/atom/referred_atom = locateUID(uid) + if(!referred_atom || QDELETED(referred_atom)) ignore_list -= uid - ignorelistcleanuptimer = 1 + ignore_list_cleanup_timer = 0 else - ignorelistcleanuptimer++ + ignore_list_cleanup_timer++ if(!on) return @@ -305,14 +345,14 @@ if(hijacked) return - switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command. - if(BOT_RESPONDING) //Called by the AI. + switch(mode) // High-priority overrides are processed first. Bots can do nothing else while under direct command. + if(BOT_RESPONDING) // Called by the AI. call_mode() return - if(BOT_SUMMON) //Called by PDA + if(BOT_SUMMON) // Called by PDA bot_summon() return - return 1 //Successful completion. Used to prevent child process() continuing if this one is ended early. + return TRUE // Successful completion. Used to prevent child process() continuing if this one is ended early. /mob/living/simple_animal/bot/attack_alien(mob/living/carbon/alien/user) user.changeNext_move(CLICK_CD_MELEE) @@ -407,7 +447,7 @@ return ..() if(locked) to_chat(user, "The maintenance panel is locked.") - return TRUE // must be true or we attempt to stab the bot + return TRUE // Must be true or we attempt to stab the bot open = !open I.play_tool_sound(src) @@ -418,7 +458,7 @@ /mob/living/simple_animal/bot/welder_act(mob/user, obj/item/I) if(user.a_intent != INTENT_HELP) return - if(user == src) //No self-repair dummy + if(user == src) // No self-repair dummy return . = TRUE if(health >= maxHealth) @@ -467,7 +507,7 @@ /mob/living/simple_animal/bot/proc/disable(time) if(disabling_timer_id) - deltimer(disabling_timer_id) // if we already have disabling timer, lets replace it with new one + deltimer(disabling_timer_id) // If we already have disabling timer, lets replace it with new one if(on) turn_off() disabling_timer_id = addtimer(CALLBACK(src, PROC_REF(enable)), time, TIMER_STOPPABLE) @@ -486,12 +526,12 @@ set_custom_texts() return TRUE -/mob/living/simple_animal/bot/proc/set_custom_texts() //Superclass for setting hack texts. Appears only if a set is not given to a bot locally. +/mob/living/simple_animal/bot/proc/set_custom_texts() // Superclass for setting hack texts. Appears only if a set is not given to a bot locally. text_hack = "You hack [name]." text_dehack = "You reset [name]." text_dehack_fail = "You fail to reset [name]." -/mob/living/simple_animal/bot/proc/speak(message, channel) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio. +/mob/living/simple_animal/bot/proc/speak(message, channel) // Pass a message to have the bot say() it. Pass a frequency to say it on the radio. if((!on) || (!message)) return if(channel) @@ -500,74 +540,73 @@ say(message) return -//Generalized behavior code, override where needed! +// Generalized behavior code, override where needed! /* scan() will search for a given type (such as turfs, human mobs, or objects) in the bot's view range, and return a single result. Arguments: The object type to be searched (such as "/mob/living/carbon/human"), the old scan result to be ignored, if one exists, and the view range, which defaults to 7 (full screen) if an override is not passed. If the bot maintains an ignore list, it is also checked here. -If the bot has avoid_bot, which inserts its own path, it will ignore turfs with the same bot type - +If avoid_bot = TRUE, it will claim it's target. List of bots that use it: Cleanbot and Floorbot Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1) The proc would return a human next to the bot to be set to the patient var. Pass the desired type path itself, declaring a temporary var beforehand is not required. */ /mob/living/simple_animal/bot/proc/scan(atom/scan_type, atom/old_target, scan_range = DEFAULT_SCAN_RANGE, avoid_bot) - var/final_result - for(var/scan in view(scan_range, src)) //Search for something in range! - var/atom/A = scan - if(!istype(A, scan_type)) //Check that the thing we found is the type we want! - continue //If not, keep searching! - if((A.UID() in ignore_list) || (A == old_target)) //Filter for blacklisted elements, usually unreachable or previously processed oness + for(var/atom/A in view(scan_range, src)) // Search for something in range! + if(!istype(A, scan_type)) // Check that the thing we found is the type we want! + continue // If not, keep searching! + if((A.UID() in ignore_list) || (A == old_target)) // Filter for blacklisted elements, usually unreachable or previously processed oness continue - if(turf_has_bot(avoid_bot, get_turf(A))) //Ignores targets that already have a bot of the same type on it, meant for cleanbot and floorbot seperation + var/scan_result = process_scan(A) // Some bots may require additional processing when a result is selected. + if(!scan_result) + continue // The current element failed assessment, move on to the next. + if(assign_bot(A, avoid_bot)) // Is the target claimed by a bot continue - var/scan_result = process_scan(A) //Some bots may require additional processing when a result is selected. - if(scan_result) - final_result = scan_result - else - continue //The current element failed assessment, move on to the next. - return final_result + return scan_result -/mob/living/simple_animal/bot/proc/turf_has_bot(avoid_bot, turf/turf_to_search) - if(!avoid_bot) +/mob/living/simple_animal/bot/proc/assign_bot(atom/A, avoid_bot) + if(!avoid_bot) // Only bots with avoid bot should be considered return FALSE - for(var/bot in turf_to_search) - if(istype(bot, avoid_bot)) - return TRUE - return FALSE + if(A.UID() in ignore_job) // Is this target already claimed by a bot + return TRUE + claim_job(A) // Claim the job so other bots don't come -//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default. +/mob/living/simple_animal/bot/proc/claim_job(atom/A) // Adds the target to ignore_job list + var/ignore_amount = length(GLOB.bots_list) // 1 claim per bot + if(length(ignore_job) >= ++ignore_amount) // Something went wrong, cull the herd + ignore_job.Cut() + ignore_job |= A.UID() + +// When the scan finds a target, run bot specific processing to select it for the next step. Empty by default. /mob/living/simple_animal/bot/proc/process_scan(atom/scan_target) return scan_target /mob/living/simple_animal/bot/proc/add_to_ignore(atom/A) - if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot. - ignore_list |= A.UID() - else //If the list is full, insert newest, delete oldest. - ignore_list.Cut(1, 2) - ignore_list |= A.UID() + if(length(ignore_list) >= 50) // This will help keep track of them, so the bot is always trying to reach a blocked spot. + ignore_list.Cut(1, 2) // If the list is full, insert newest, delete oldest. + ignore_list |= A.UID() + /* Movement proc for stepping a bot through a path generated through A-star. Pass a positive integer as an argument to override a bot's default speed. */ /mob/living/simple_animal/bot/proc/bot_move(dest, move_speed) - if(!dest || !path || !length(path)) //A-star failed or a path/destination was not set. + if(!dest || !path || !length(path)) // A-star failed or a path/destination was not set. set_path(null) return FALSE - dest = get_turf(dest) //We must always compare turfs, so get the turf of the dest var if dest was originally something else. - var/turf/last_node = get_turf(path[length(path)]) //This is the turf at the end of the path, it should be equal to dest. - if(get_turf(src) == dest) //We have arrived, no need to move again. + dest = get_turf(dest) // We must always compare turfs, so get the turf of the dest var if dest was originally something else. + var/turf/last_node = get_turf(path[length(path)]) // This is the turf at the end of the path, it should be equal to dest. + if(get_turf(src) == dest) // We have arrived, no need to move again. return TRUE - else if(dest != last_node) //The path should lead us to our given destination. If this is not true, we must stop. + else if(dest != last_node) // The path should lead us to our given destination. If this is not true, we must stop. set_path(null) return FALSE - var/step_count = move_speed ? move_speed : base_speed //If a value is passed into move_speed, use that instead of the default speed var. + var/step_count = move_speed ? move_speed : base_speed // If a value is passed into move_speed, use that instead of the default speed var. if(step_count >= 1 && tries < BOT_STEP_MAX_RETRIES) for(var/step_number in 1 to step_count) @@ -578,7 +617,7 @@ Pass a positive integer as an argument to override a bot's default speed. return TRUE -/mob/living/simple_animal/bot/proc/bot_step() //Step,increase tries if failed +/mob/living/simple_animal/bot/proc/bot_step() // Step,increase tries if failed if(!length(path)) return FALSE @@ -596,19 +635,19 @@ Pass a positive integer as an argument to override a bot's default speed. access_card.access = prev_access /mob/living/simple_animal/bot/proc/call_bot(caller, turf/waypoint, message=TRUE) - bot_reset() //Reset a bot before setting it to call mode. + bot_reset() // Reset a bot before setting it to call mode. var/area/end_area = get_area(waypoint) var/datum/job/captain/All = new/datum/job/captain access_card.access = All.get_access() // Give the bot temporary all access set_path(get_path_to(src, waypoint, 200, id = access_card)) - calling_ai = caller //Link the AI to the bot! + calling_ai = caller // Link the AI to the bot! ai_waypoint = waypoint - if(path && length(path)) //Ensures that a valid path is calculated! + if(path && length(path)) // Ensures that a valid path is calculated! if(!on) - turn_on() //Saves the AI the hassle of having to activate a bot manually. + turn_on() // Saves the AI the hassle of having to activate a bot manually. if(client) reset_access_timer_id = addtimer(CALLBACK(src, PROC_REF(bot_reset)), 600, TIMER_OVERRIDE|TIMER_STOPPABLE) //if the bot is player controlled, they get the extra access for a limited time to_chat(src, "Priority waypoint set by [calling_ai] [caller]. Proceed to [end_area.name].
[length(path)-1] meters to destination. You have been granted additional door access for 60 seconds.
") @@ -624,8 +663,8 @@ Pass a positive integer as an argument to override a bot's default speed. access_card.access = prev_access // Don't forget to reset it set_path(null) -/mob/living/simple_animal/bot/proc/call_mode() //Handles preparing a bot for a call, as well as calling the move proc. -//Handles the bot's movement during a call. +/mob/living/simple_animal/bot/proc/call_mode() // Handles preparing a bot for a call, as well as calling the move proc. +// Handles the bot's movement during a call. var/success = bot_move(ai_waypoint, 3) if(!success) if(calling_ai) @@ -634,13 +673,14 @@ Pass a positive integer as an argument to override a bot's default speed. bot_reset() /mob/living/simple_animal/bot/proc/bot_reset() - if(calling_ai) //Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot. + if(calling_ai) // Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot. to_chat(calling_ai, "Call command to a bot has been reset.") calling_ai = null if(reset_access_timer_id) deltimer(reset_access_timer_id) reset_access_timer_id = null set_path(null) + ignore_job.Cut() last_target_location = null lost_target = FALSE summon_target = null @@ -668,21 +708,21 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/start_patrol() set_path(null) - if(tries >= BOT_STEP_MAX_RETRIES) //Bot is trapped, so stop trying to patrol. + if(tries >= BOT_STEP_MAX_RETRIES) // Bot is trapped, so stop trying to patrol. auto_patrol = FALSE tries = 0 speak("Unable to start patrol.") return - if(!auto_patrol) //A bot not set to patrol should not be patrolling. + if(!auto_patrol) // A bot not set to patrol should not be patrolling. mode = BOT_IDLE return if(patrol_target) // has patrol target INVOKE_ASYNC(src, PROC_REF(target_patrol)) - else // no patrol target, so need a new one + else // No patrol target, so need a new one speak("Engaging patrol mode.") find_patrol_target() tries++ @@ -694,30 +734,30 @@ Pass a positive integer as an argument to override a bot's default speed. return mode = BOT_PATROL -// perform a single patrol step +// Perform a single patrol step /mob/living/simple_animal/bot/proc/patrol_step() if(client) // In use by player, don't actually move. return - if(loc == patrol_target) // reached target - //Find the next beacon matching the target. + if(loc == patrol_target) // Reached target + // Find the next beacon matching the target. if(!get_next_patrol_target()) - find_patrol_target() //If it fails, look for the nearest one instead. + find_patrol_target() // If it fails, look for the nearest one instead. return - else if(length(path) && patrol_target) // valid path + else if(length(path) && patrol_target) // Valid path if(path[1] == loc) increment_path() return - var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move - if(!moved) //Couldn't proceed the next step of the path BOT_STEP_MAX_RETRIES times + var/moved = bot_move(patrol_target) // step_towards(src, next) // attempt to move + if(!moved) // Couldn't proceed the next step of the path BOT_STEP_MAX_RETRIES times addtimer(CALLBACK(src, PROC_REF(patrol_step_not_moved)), 2) - else // no path, so calculate new one + else // No path, so calculate new one mode = BOT_START_PATROL /mob/living/simple_animal/bot/proc/patrol_step_not_moved() @@ -726,7 +766,7 @@ Pass a positive integer as an argument to override a bot's default speed. find_patrol_target() tries = 0 -// finds the nearest beacon to self +// Finds the nearest beacon to self /mob/living/simple_animal/bot/proc/find_patrol_target() nearest_beacon = null new_destination = null @@ -740,13 +780,13 @@ Pass a positive integer as an argument to override a bot's default speed. speak("Disengaging patrol mode.") /mob/living/simple_animal/bot/proc/get_next_patrol_target() - // search the beacon list for the next target in the list. + // Search the beacon list for the next target in the list. for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"]) - if(NB.location == next_destination) //Does the Beacon location text match the destination? - destination = new_destination //We now know the name of where we want to go. - patrol_target = NB.loc //Get its location and set it as the target. - next_destination = NB.codes["next_patrol"] //Also get the name of the next beacon in line. - return 1 + if(NB.location == next_destination) // Does the Beacon location text match the destination? + destination = new_destination // We now know the name of where we want to go. + patrol_target = NB.loc // Get its location and set it as the target. + next_destination = NB.codes["next_patrol"] // Also get the name of the next beacon in line. + return TRUE /mob/living/simple_animal/bot/proc/find_nearest_beacon() for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"]) @@ -786,17 +826,17 @@ Pass a positive integer as an argument to override a bot's default speed. if(!on) return FALSE - // check to see if we are the commanded bot - if(emagged || remote_disabled || hijacked) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands. + // Check to see if we are the commanded bot + if(emagged || remote_disabled || hijacked) // Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands. return FALSE if(client) bot_control_message(command, user, params["target"] ? params["target"] : "Unknown") - // process control input + // Process control input switch(command) if("stop") - bot_reset() //HOLD IT!! + bot_reset() // HOLD IT!! auto_patrol = FALSE if("go") @@ -808,7 +848,7 @@ Pass a positive integer as an argument to override a bot's default speed. summon_target = params["target"] // Location of the user if(length(user_access)) - access_card.access = user_access + prev_access //Adds the user's access, if any. + access_card.access = user_access + prev_access // Adds the user's access, if any. mode = BOT_SUMMON calc_summon_path() @@ -817,11 +857,11 @@ Pass a positive integer as an argument to override a bot's default speed. return TRUE -/mob/living/simple_animal/bot/proc/bot_summon() // summoned to PDA +/mob/living/simple_animal/bot/proc/bot_summon() // Summoned to PDA summon_step() -// calculates a path to the current destination -// given an optional turf to avoid +// Calculates a path to the current destination +// Given an optional turf to avoid /mob/living/simple_animal/bot/proc/calc_path(turf/avoid) check_bot_access() set_path(get_path_to(src, patrol_target, 120, id=access_card, exclude=avoid)) @@ -830,7 +870,7 @@ Pass a positive integer as an argument to override a bot's default speed. set waitfor = FALSE check_bot_access() set_path(get_path_to(src, summon_target, 150, id=access_card, exclude=avoid)) - if(!length(path)) //Cannot reach target. Give up and announce the issue. + if(!length(path)) // Cannot reach target. Give up and announce the issue. speak("Summon command failed, destination unreachable.",radio_channel) bot_reset() @@ -854,7 +894,7 @@ Pass a positive integer as an argument to override a bot's default speed. addtimer(CALLBACK(src, PROC_REF(try_calc_path)), 2) - else // no path, so calculate new one + else // No path, so calculate new one calc_summon_path() /mob/living/simple_animal/bot/proc/try_calc_path() @@ -886,22 +926,22 @@ Pass a positive integer as an argument to override a bot's default speed. return "PROTOBOT - NOT FOR USE" /mob/living/simple_animal/bot/proc/allowed(mob/M) - var/acc = M.get_access() //see mob.dm + var/acc = M.get_access() // See mob.dm if(acc == IGNORE_ACCESS || M.can_admin_interact()) - return TRUE //Mob ignores access + return TRUE // Mob ignores access return has_access(list(), req_access, acc) /mob/living/simple_animal/bot/Topic(href, href_list) - if(href_list["close"])// HUE HUE + if(href_list["close"]) // HUE HUE if(usr in users) users.Remove(usr) - return 1 + return TRUE if(topic_denied(usr)) to_chat(usr, "[src]'s interface is not responding!") - return 1 + return TRUE add_fingerprint(usr) if((href_list["power"]) && (allowed(usr) || !locked || usr.can_admin_interact())) @@ -927,7 +967,7 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/canhack(mob/M) return ((issilicon(M) && (!emagged || hacked)) || M.can_admin_interact()) -/mob/living/simple_animal/bot/proc/handle_hacking(mob/M) // refactored out of Topic/ to allow re-use by TGUIs +/mob/living/simple_animal/bot/proc/handle_hacking(mob/M) // Refactored out of Topic/ to allow re-use by TGUIs if(!canhack(M)) return if(!emagged) @@ -951,15 +991,15 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/update_icon_state() icon_state = "[initial(icon_state)][on]" -/mob/living/simple_animal/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired. +/mob/living/simple_animal/bot/proc/topic_denied(mob/user) // Access check proc for bot topics! Remember to place in a bot's individual Topic if desired. if(user.can_admin_interact()) return FALSE if(user.incapacitated() || !(issilicon(user) || in_range(src, user))) return TRUE - if(emagged) //An emagged bot cannot be controlled by humans, silicons can if one hacked it. - if(!hacked) //Manually emagged by a human - access denied to all. + if(emagged) // An emagged bot cannot be controlled by humans, silicons can if one hacked it. + if(!hacked) // Manually emagged by a human - access denied to all. return TRUE - else if(!(issilicon(user) || ispulsedemon(user))) //Bot is hacked, so only silicons are allowed access. + else if(!(issilicon(user) || ispulsedemon(user))) // Bot is hacked, so only silicons are allowed access. return TRUE if(hijacked && !ispulsedemon(user)) return FALSE @@ -969,10 +1009,10 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/hack(mob/user) var/hack - if(issilicon(user) || user.can_admin_interact()) //Allows silicons or admins to toggle the emag status of a bot. + if(issilicon(user) || user.can_admin_interact()) // Allows silicons or admins to toggle the emag status of a bot. hack += "[emagged ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
" hack += "Harm Prevention Safety System: [emagged ? "DANGER" : "Engaged"]
" - else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control. + else if(!locked) // Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control. hack += "Remote network control radio: [remote_disabled ? "Disconnected" : "Connected"]
" return hack @@ -1095,7 +1135,7 @@ Pass a positive integer as an argument to override a bot's default speed. used_radios += Radio /mob/living/simple_animal/bot/is_mechanical() - return 1 + return TRUE /mob/living/simple_animal/bot/proc/set_path(list/newpath) path = newpath ? newpath : list() @@ -1112,13 +1152,13 @@ Pass a positive integer as an argument to override a bot's default speed. // Common data shared among all the bots, used by BotStatus.js /mob/living/simple_animal/bot/ui_data(mob/user) var/list/data = list() - data["locked"] = locked // controls, locked or not - data["noaccess"] = topic_denied(user) // does the current user have access? admins, silicons etc can still access bots with locked controls + data["locked"] = locked // Controls, locked or not + data["noaccess"] = topic_denied(user) // Does the current user have access? admins, silicons etc can still access bots with locked controls data["maintpanel"] = open data["on"] = on data["autopatrol"] = auto_patrol data["painame"] = paicard ? paicard.pai.name : null data["canhack"] = canhack(user) - data["emagged"] = emagged // this is an int, NOT a boolean + data["emagged"] = emagged data["remote_disabled"] = remote_disabled return data diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index cba5965884b0..10090833b576 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -124,7 +124,7 @@ audible_message("[src] makes an excited beeping booping sound!") if(!target) //Search for cleanables it can see. - target = scan(/obj/effect/decal/cleanable, avoid_bot = /mob/living/simple_animal/bot/cleanbot) + target = scan(/obj/effect/decal/cleanable, avoid_bot = TRUE) if(!target && auto_patrol) //Search for cleanables it can see. if(mode == BOT_IDLE || mode == BOT_START_PATROL) @@ -143,12 +143,14 @@ //Try to produce a path to the target, and ignore airlocks to which it has access. path = get_path_to(src, target, 30, id=access_card) if(!bot_move(target)) + ignore_job -= target.UID() add_to_ignore(target) target = null path = list() return mode = BOT_MOVING else if(!bot_move(target)) + ignore_job -= target.UID() target = null mode = BOT_IDLE return @@ -164,6 +166,7 @@ /mob/living/simple_animal/bot/cleanbot/proc/do_clean(obj/effect/decal/cleanable/target) if(mode == BOT_CLEANING) + ignore_job -= target.UID() QDEL_NULL(target) anchored = FALSE mode = BOT_IDLE diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index bfbbcc187028..a8e7e3d06536 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -1,4 +1,4 @@ -//Floorbot +// Floorbot /mob/living/simple_animal/bot/floorbot name = "\improper Floorbot" desc = "A little floor repairing robot, he looks so excited!" @@ -167,37 +167,37 @@ if(prob(5)) audible_message("[src] makes an excited booping beeping sound!") - //Normal scanning procedure. We have tiles loaded, are not emagged. + // Normal scanning procedure. We have tiles loaded, are not emagged. if(!target && !emagged && amount) if(!target) - process_type = HULL_BREACH //Ensures the floorbot does not try to "fix" space areas or shuttle docking zones. - target = scan(/turf/space, avoid_bot = /mob/living/simple_animal/bot/floorbot) + process_type = HULL_BREACH // Ensures the floorbot does not try to "fix" space areas or shuttle docking zones. + target = scan(/turf/space, avoid_bot = TRUE) - if(!target && replace_tiles) //Finds a floor without a tile and gives it one. - process_type = REPLACE_TILE //The target must be the floor and not a tile. The floor must not already have a floortile. - target = scan(/turf/simulated/floor, avoid_bot = /mob/living/simple_animal/bot/floorbot) - - if(!target && fix_floor) //Repairs damaged floors and tiles. + if(!target && fix_floor) // Repairs damaged floors and tiles. process_type = FIX_TILE - target = scan(/turf/simulated/floor, avoid_bot = /mob/living/simple_animal/bot/floorbot) + target = scan(/turf/simulated/floor, avoid_bot = TRUE) + + if(!target && replace_tiles) // Finds a floor without a tile and gives it one. + process_type = REPLACE_TILE // The target must be the floor and not a tile. The floor must not already have a floortile. + target = scan(/turf/simulated/floor/plating, avoid_bot = TRUE) - if(!target && emagged) //We are emagged! Time to rip up the floors! + if(!target && emagged) // We are emagged! Time to rip up the floors! process_type = TILE_EMAG - target = scan(/turf/simulated/floor, avoid_bot = /mob/living/simple_animal/bot/floorbot) + target = scan(/turf/simulated/floor, avoid_bot = TRUE) + + if(amount < MAX_AMOUNT && !target) // Out of tiles! We must refill! - if(amount < MAX_AMOUNT && !target) //Out of tiles! We must refill! - if(eat_tiles) //Configured to find and consume floortiles! + if(!target && eat_tiles) // Configured to find and consume floortiles! process_type = null target = scan(/obj/item/stack/tile/plasteel) - if(!target && make_tiles) //We did not manage to find any floor tiles! Scan for metal stacks and make our own! + if(!target && make_tiles) // We did not manage to find any floor tiles! Scan for metal stacks and make our own! process_type = null target = scan(/obj/item/stack/sheet/metal) - if(!target && nag_on_empty) //Floorbot is empty and cannot acquire more tiles, nag the engineers for more! + if(!target && nag_on_empty) // Floorbot is empty and cannot acquire more tiles, nag the engineers for more! nag() - if(!target) if(auto_patrol) @@ -211,10 +211,10 @@ if(loc == target || loc == target.loc) if(istype(target, /obj/item/stack/tile/plasteel)) - start_eattile(target) + start_eat_tile(target) if(istype(target, /obj/item/stack/sheet/metal)) - start_maketile(target) + start_make_tile(target) if(isturf(target) && !emagged) repair(target) @@ -232,7 +232,7 @@ path = list() return - if(!length(path)) + if(!length(path)) // No path, need a new one if(!isturf(target)) var/turf/TL = get_turf(target) path = get_path_to(src, TL, 30, id = access_card, simulated_only = 0) @@ -241,10 +241,12 @@ if(!bot_move(target)) add_to_ignore(target) + ignore_job -= target.UID() target = null mode = BOT_IDLE return else if(!bot_move(target)) + ignore_job -= target.UID() target = null mode = BOT_IDLE return @@ -255,45 +257,50 @@ amount ++ anchored = FALSE mode = BOT_IDLE + ignore_job -= target.UID() target = null -/mob/living/simple_animal/bot/floorbot/proc/nag() //Annoy everyone on the channel to refill us! +/mob/living/simple_animal/bot/floorbot/proc/nag() // Annoy everyone on the channel to refill us! if(!nagged) speak("Requesting refill [MAX_AMOUNT - amount] at [get_area(src)]!", radio_channel) nagged = TRUE -/mob/living/simple_animal/bot/floorbot/proc/is_hull_breach(turf/t) //Ignore space tiles not considered part of a structure, also ignores shuttle docking areas. +/mob/living/simple_animal/bot/floorbot/proc/is_hull_breach(turf/t) // Ignore space tiles not considered part of a structure, also ignores shuttle docking areas. return !istype(get_area(t), /area/space) -//Floorbots, having several functions, need sort out special conditions here. +// Floorbots, having several functions, need sort out special conditions here. /mob/living/simple_animal/bot/floorbot/process_scan(atom/scan_target) var/result var/turf/simulated/floor/F switch(process_type) - if(HULL_BREACH) //The most common job, patching breaches in the station's hull. - if(is_hull_breach(scan_target)) //Ensure that the targeted space turf is actually part of the station, and not random space. + if(HULL_BREACH) // The most common job, patching breaches in the station's hull. + if(is_hull_breach(scan_target)) // Ensure that the targeted space turf is actually part of the station, and not random space. result = scan_target - anchored = TRUE //Prevent the floorbot being blown off-course while trying to reach a hull breach. + anchored = TRUE // Prevent the floorbot being blown off-course while trying to reach a hull breach. if(REPLACE_TILE) F = scan_target - if(istype(F, /turf/simulated/floor/plating)) //The floor must not already have a tile. + if(istype(F, /turf/simulated/floor/plating)) // The floor must not already have a tile. + if(locate(/obj/structure/window) in get_turf(F)) // Targeting plating under window + add_to_ignore(scan_target) + return FALSE result = F - if(FIX_TILE) //Selects only damaged floors. + if(FIX_TILE) // Selects only damaged floors. F = scan_target if(istype(F) && (F.broken || F.burnt)) result = F - if(TILE_EMAG) //Emag mode! Rip up the floor and cause breaches to space! + if(TILE_EMAG) // Emag mode! Rip up the floor and cause breaches to space! F = scan_target if(!istype(F, /turf/simulated/floor/plating)) result = F - else //If no special processing is needed, simply return the result. + else // If no special processing is needed, simply return the result. result = scan_target return result /mob/living/simple_animal/bot/floorbot/proc/repair(turf/target_turf) if(isspaceturf(target_turf)) - //Must be a hull breach to continue. + // Must be a hull breach to continue. if(!is_hull_breach(target_turf)) + ignore_job -= target.UID() target = null return @@ -302,12 +309,13 @@ if(amount <= 0) mode = BOT_IDLE + ignore_job -= target.UID() target = null return anchored = TRUE - if(isspaceturf(target_turf)) //If we are fixing an area not part of pure space, it is + if(isspaceturf(target_turf)) // If we are fixing an area not part of pure space, it is visible_message("[src] begins to repair the hole.") mode = BOT_REPAIRING update_icon(UPDATE_OVERLAYS) @@ -326,6 +334,8 @@ if(mode != BOT_REPAIRING) return + ignore_job -= target_turf.UID() // If called after the tile fix, turf changes and the UID with it + if(autotile || replace_tiles) if(process_type != HULL_BREACH) F.break_tile_to_plating() @@ -339,15 +349,16 @@ anchored = FALSE target = null -/mob/living/simple_animal/bot/floorbot/proc/start_eattile(obj/item/stack/tile/plasteel/T) +/mob/living/simple_animal/bot/floorbot/proc/start_eat_tile(obj/item/stack/tile/plasteel/T) if(!istype(T, /obj/item/stack/tile/plasteel)) return + anchored = TRUE visible_message("[src] begins to collect tiles.") mode = BOT_EAT_TILE update_icon(UPDATE_OVERLAYS) - addtimer(CALLBACK(src, PROC_REF(do_eattile), T), 2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(do_eat_tile), T), 2 SECONDS) -/mob/living/simple_animal/bot/floorbot/proc/do_eattile(obj/item/stack/tile/plasteel/T) +/mob/living/simple_animal/bot/floorbot/proc/do_eat_tile(obj/item/stack/tile/plasteel/T) if(isnull(T)) target = null mode = BOT_IDLE @@ -359,30 +370,39 @@ else amount += T.amount qdel(T) + anchored = FALSE target = null mode = BOT_IDLE update_icon(UPDATE_OVERLAYS) -/mob/living/simple_animal/bot/floorbot/proc/start_maketile(obj/item/stack/sheet/metal/M) +/mob/living/simple_animal/bot/floorbot/proc/start_make_tile(obj/item/stack/sheet/metal/M) if(!istype(M, /obj/item/stack/sheet/metal)) return + anchored = TRUE visible_message("[src] begins to create tiles.") mode = BOT_MAKE_TILE update_icon(UPDATE_OVERLAYS) - addtimer(CALLBACK(src, PROC_REF(do_maketile), M), 2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(do_make_tile), M), 2 SECONDS) -/mob/living/simple_animal/bot/floorbot/proc/do_maketile(obj/item/stack/sheet/metal/M) +/mob/living/simple_animal/bot/floorbot/proc/do_make_tile(obj/item/stack/sheet/metal/M) if(isnull(M)) target = null mode = BOT_IDLE return - var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel - T.amount = 4 - T.forceMove(M.loc) + + if((amount + 4) > MAX_AMOUNT) // 1 metal = 4 tiles, hence + 4 + var/missing_amount = MAX_AMOUNT - amount + var/extra = amount + 4 - MAX_AMOUNT + amount += missing_amount + new /obj/item/stack/tile/plasteel(get_turf(src), extra) + else + amount += 4 + if(M.amount > 1) - M.amount-- + M.amount -- else qdel(M) + anchored = FALSE target = null mode = BOT_IDLE update_icon(UPDATE_OVERLAYS) @@ -408,7 +428,7 @@ if(prob(50)) drop_part(robot_arm, Tsec) - while(amount)//Dumps the tiles into the appropriate sized stacks + while(amount)// Dumps the tiles into the appropriate sized stacks if(amount >= 16) var/obj/item/stack/tile/plasteel/T = new (Tsec) T.amount = 16 @@ -425,9 +445,9 @@ if(isturf(A)) repair(A) else if(istype(A,/obj/item/stack/tile/plasteel)) - start_eattile(A) + start_eat_tile(A) else if(istype(A,/obj/item/stack/sheet/metal)) - start_maketile(A) + start_make_tile(A) else ..() From 14baa57030ec829665b9164c7df8848e000acd8e Mon Sep 17 00:00:00 2001 From: GDN <96800819+GDNgit@users.noreply.github.com> Date: Wed, 6 Mar 2024 09:11:36 -0600 Subject: [PATCH 27/43] tgui chat message stacking and message amount improvements (#24130) * tgui chat message stacking improvements * drops to 30 * baller * reviews * Update tgui/packages/tgui-panel/settings/SettingsPanel.js Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com> * Update tgui-panel.bundle.js --------- Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com> --- tgui/packages/tgui-panel/chat/constants.js | 4 +- tgui/packages/tgui-panel/chat/middleware.js | 5 +- tgui/packages/tgui-panel/chat/renderer.js | 24 +++-- .../tgui-panel/settings/SettingsPanel.js | 53 +++++++++- tgui/packages/tgui-panel/settings/reducer.js | 2 + tgui/public/tgui-panel.bundle.js | 98 +++++++++---------- 6 files changed, 117 insertions(+), 69 deletions(-) diff --git a/tgui/packages/tgui-panel/chat/constants.js b/tgui/packages/tgui-panel/chat/constants.js index 31aaf993148d..9214a3af37d2 100644 --- a/tgui/packages/tgui-panel/chat/constants.js +++ b/tgui/packages/tgui-panel/chat/constants.js @@ -4,12 +4,10 @@ * @license MIT */ -export const MAX_VISIBLE_MESSAGES = 2500; -export const MAX_PERSISTED_MESSAGES = 1000; export const MESSAGE_SAVE_INTERVAL = 10000; +// 60 seconds. We use MS for this export const MESSAGE_PRUNE_INTERVAL = 60000; export const COMBINE_MAX_MESSAGES = 5; -export const COMBINE_MAX_TIME_WINDOW = 5000; export const IMAGE_RETRY_DELAY = 250; export const IMAGE_RETRY_LIMIT = 10; export const IMAGE_RETRY_MESSAGE_AGE = 60000; diff --git a/tgui/packages/tgui-panel/chat/middleware.js b/tgui/packages/tgui-panel/chat/middleware.js index 281fe29b846d..94683fe2725f 100644 --- a/tgui/packages/tgui-panel/chat/middleware.js +++ b/tgui/packages/tgui-panel/chat/middleware.js @@ -26,7 +26,7 @@ import { removeChatPage, saveChatToDisk, } from './actions'; -import { MAX_PERSISTED_MESSAGES, MESSAGE_SAVE_INTERVAL } from './constants'; +import { MESSAGE_SAVE_INTERVAL } from './constants'; import { createMessage, serializeMessage } from './model'; import { chatRenderer } from './renderer'; import { selectChat, selectCurrentChatPage } from './selectors'; @@ -38,7 +38,7 @@ const saveChatToStorage = async (store) => { const state = selectChat(store.getState()); const fromIndex = Math.max( 0, - chatRenderer.messages.length - MAX_PERSISTED_MESSAGES + chatRenderer.messages.length - chatRenderer.maxTotalMessage ); const messages = chatRenderer.messages .slice(fromIndex) @@ -176,7 +176,6 @@ export const chatMiddleware = (store) => { settings.highlightSettings, settings.highlightSettingById ); - return; } if (type === 'roundrestart') { diff --git a/tgui/packages/tgui-panel/chat/renderer.js b/tgui/packages/tgui-panel/chat/renderer.js index 039506a0543c..dcc3264eab06 100644 --- a/tgui/packages/tgui-panel/chat/renderer.js +++ b/tgui/packages/tgui-panel/chat/renderer.js @@ -9,12 +9,9 @@ import { classes } from 'common/react'; import { createLogger } from 'tgui/logging'; import { COMBINE_MAX_MESSAGES, - COMBINE_MAX_TIME_WINDOW, IMAGE_RETRY_DELAY, IMAGE_RETRY_LIMIT, IMAGE_RETRY_MESSAGE_AGE, - MAX_PERSISTED_MESSAGES, - MAX_VISIBLE_MESSAGES, MESSAGE_PRUNE_INTERVAL, MESSAGE_TYPES, MESSAGE_TYPE_INTERNAL, @@ -112,6 +109,8 @@ class ChatRenderer { this.visibleMessages = []; this.page = null; this.events = new EventEmitter(); + this.messageStackInSeconds = 30; + this.maxTotalMessage = 10000; // Scroll handler /** @type {HTMLElement} */ this.scrollNode = null; @@ -264,6 +263,14 @@ class ChatRenderer { }); } + setMessageDelayStacking(value) { + this.messageStackInSeconds = value; + } + + setMessageTotal(value) { + this.maxTotalMessage = value; + } + scrollToBottom() { // scrollHeight is always bigger than scrollTop and is // automatically clamped to the valid range. @@ -310,7 +317,7 @@ class ChatRenderer { // Text payload must fully match && isSameMessage(message, predicate) // Must land within the specified time window - && now < message.createdAt + COMBINE_MAX_TIME_WINDOW + && now < message.createdAt + (this.messageStackInSeconds * 1000) ); if (matches) { return message; @@ -449,7 +456,7 @@ class ChatRenderer { // Visible messages { const messages = this.visibleMessages; - const fromIndex = Math.max(0, messages.length - MAX_VISIBLE_MESSAGES); + const fromIndex = Math.max(0, messages.length - this.maxTotalMessage); if (fromIndex > 0) { this.visibleMessages = messages.slice(fromIndex); for (let i = 0; i < fromIndex; i++) { @@ -470,7 +477,7 @@ class ChatRenderer { { const fromIndex = Math.max( 0, - this.messages.length - MAX_PERSISTED_MESSAGES + this.messages.length - this.maxTotalMessage ); if (fromIndex > 0) { this.messages = this.messages.slice(fromIndex); @@ -484,10 +491,7 @@ class ChatRenderer { return; } // Make a copy of messages - const fromIndex = Math.max( - 0, - this.messages.length - MAX_PERSISTED_MESSAGES - ); + const fromIndex = Math.max(0, this.messages.length - this.maxTotalMessage); const messages = this.messages.slice(fromIndex); // Remove existing nodes for (let message of messages) { diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.js b/tgui/packages/tgui-panel/settings/SettingsPanel.js index b1751e650073..87b693bd703a 100644 --- a/tgui/packages/tgui-panel/settings/SettingsPanel.js +++ b/tgui/packages/tgui-panel/settings/SettingsPanel.js @@ -38,6 +38,7 @@ import { selectHighlightSettings, selectHighlightSettingById, } from './selectors'; +import { chatRenderer } from '../chat/renderer'; export const SettingsPanel = (props, context) => { const activeTab = useSelector(context, selectActiveTab); @@ -75,10 +76,14 @@ export const SettingsPanel = (props, context) => { }; export const SettingsGeneral = (props, context) => { - const { theme, fontFamily, fontSize, lineHeight } = useSelector( - context, - selectSettings - ); + const { + theme, + fontFamily, + fontSize, + lineHeight, + messageStackInSeconds, + maxTotalMessage, + } = useSelector(context, selectSettings); const dispatch = useDispatch(context); const [freeFont, setFreeFont] = useLocalState(context, 'freeFont', false); return ( @@ -155,6 +160,20 @@ export const SettingsGeneral = (props, context) => { ) } /> + + Maximum messages displayed: + + toFixed(value)} + onChange={(e, value) => SetMessageTotal(value, context)} + /> { ) } /> + + Stacked message expiration: + + toFixed(value)} + onChange={(e, value) => SetMessageStackingTime(value, context)} + /> @@ -348,3 +381,15 @@ const TextHighlightSetting = (props, context) => { ); }; + +const SetMessageStackingTime = (value, context) => { + const dispatch = useDispatch(context); + dispatch(updateSettings({ messageStackInSeconds: value })); + chatRenderer.setMessageDelayStacking(value); +}; + +const SetMessageTotal = (value, context) => { + const dispatch = useDispatch(context); + dispatch(updateSettings({ maxTotalMessage: value })); + chatRenderer.setMessageDelayStacking(value); +}; diff --git a/tgui/packages/tgui-panel/settings/reducer.js b/tgui/packages/tgui-panel/settings/reducer.js index 155f591e72f8..171359149e61 100644 --- a/tgui/packages/tgui-panel/settings/reducer.js +++ b/tgui/packages/tgui-panel/settings/reducer.js @@ -26,6 +26,8 @@ const initialState = { lineHeight: 1.2, theme: 'dark', adminMusicVolume: 0.5, + messageStackInSeconds: 30, + maxTotalMessage: 10000, // Keep these two state vars for compatibility with other servers highlightText: '', highlightColor: '#ffdd44', diff --git a/tgui/public/tgui-panel.bundle.js b/tgui/public/tgui-panel.bundle.js index d79866fe641c..ede671d4c004 100644 --- a/tgui/public/tgui-panel.bundle.js +++ b/tgui/public/tgui-panel.bundle.js @@ -1,8 +1,8 @@ -(function(){(function(){var An={15113:function(S,e,t){"use strict";e.__esModule=!0,e.createPopper=void 0,e.popperGenerator=p;var n=u(t(28770)),r=u(t(12866)),o=u(t(88577)),a=u(t(29727)),i=u(t(13657)),v=u(t(97902)),c=u(t(57547)),h=u(t(4709));e.detectOverflow=h.default;var f=t(65601);function u(g){return g&&g.__esModule?g:{default:g}}var d={placement:"bottom",modifiers:[],strategy:"absolute"};function s(){for(var g=arguments.length,m=new Array(g),E=0;E0&&(0,r.round)(u.width)/c.offsetWidth||1,s=c.offsetHeight>0&&(0,r.round)(u.height)/c.offsetHeight||1);var p=(0,n.isElement)(c)?(0,o.default)(c):window,l=p.visualViewport,g=!(0,a.default)()&&f,m=(u.left+(g&&l?l.offsetLeft:0))/d,E=(u.top+(g&&l?l.offsetTop:0))/s,O=u.width/d,I=u.height/s;return{width:O,height:I,top:E,right:m+O,bottom:E+I,left:m,x:m,y:E}}},98310:function(S,e,t){"use strict";e.__esModule=!0,e.default=I;var n=t(37802),r=g(t(63064)),o=g(t(16940)),a=g(t(88577)),i=g(t(29727)),v=g(t(9252)),c=g(t(75663)),h=t(65601),f=g(t(83199)),u=g(t(16292)),d=g(t(11848)),s=g(t(1707)),p=g(t(21194)),l=t(79257);function g(T){return T&&T.__esModule?T:{default:T}}function m(T,y){var b=(0,f.default)(T,!1,y==="fixed");return b.top=b.top+T.clientTop,b.left=b.left+T.clientLeft,b.bottom=b.top+T.clientHeight,b.right=b.left+T.clientWidth,b.width=T.clientWidth,b.height=T.clientHeight,b.x=b.left,b.y=b.top,b}function E(T,y,b){return y===n.viewport?(0,p.default)((0,r.default)(T,b)):(0,h.isElement)(y)?m(y,b):(0,p.default)((0,o.default)((0,v.default)(T)))}function O(T){var y=(0,a.default)((0,u.default)(T)),b=["absolute","fixed"].indexOf((0,c.default)(T).position)>=0,C=b&&(0,h.isHTMLElement)(T)?(0,i.default)(T):T;return(0,h.isElement)(C)?y.filter(function(P){return(0,h.isElement)(P)&&(0,d.default)(P,C)&&(0,s.default)(P)!=="body"}):[]}function I(T,y,b,C){var P=y==="clippingParents"?O(T):[].concat(y),N=[].concat(P,[b]),w=N[0],M=N.reduce(function(L,K){var x=E(T,K,C);return L.top=(0,l.max)(x.top,L.top),L.right=(0,l.min)(x.right,L.right),L.bottom=(0,l.min)(x.bottom,L.bottom),L.left=(0,l.max)(x.left,L.left),L},E(T,w,C));return M.width=M.right-M.left,M.height=M.bottom-M.top,M.x=M.left,M.y=M.top,M}},28770:function(S,e,t){"use strict";e.__esModule=!0,e.default=d;var n=f(t(83199)),r=f(t(3107)),o=f(t(1707)),a=t(65601),i=f(t(94889)),v=f(t(9252)),c=f(t(27703)),h=t(79257);function f(s){return s&&s.__esModule?s:{default:s}}function u(s){var p=s.getBoundingClientRect(),l=(0,h.round)(p.width)/s.offsetWidth||1,g=(0,h.round)(p.height)/s.offsetHeight||1;return l!==1||g!==1}function d(s,p,l){l===void 0&&(l=!1);var g=(0,a.isHTMLElement)(p),m=(0,a.isHTMLElement)(p)&&u(p),E=(0,v.default)(p),O=(0,n.default)(s,m,l),I={scrollLeft:0,scrollTop:0},T={x:0,y:0};return(g||!g&&!l)&&(((0,o.default)(p)!=="body"||(0,c.default)(E))&&(I=(0,r.default)(p)),(0,a.isHTMLElement)(p)?(T=(0,n.default)(p,!0),T.x+=p.clientLeft,T.y+=p.clientTop):E&&(T.x=(0,i.default)(E))),{x:O.left+I.scrollLeft-T.x,y:O.top+I.scrollTop-T.y,width:O.width,height:O.height}}},75663:function(S,e,t){"use strict";e.__esModule=!0,e.default=o;var n=r(t(44901));function r(a){return a&&a.__esModule?a:{default:a}}function o(a){return(0,n.default)(a).getComputedStyle(a)}},9252:function(S,e,t){"use strict";e.__esModule=!0,e.default=r;var n=t(65601);function r(o){return(((0,n.isElement)(o)?o.ownerDocument:o.document)||window.document).documentElement}},16940:function(S,e,t){"use strict";e.__esModule=!0,e.default=c;var n=v(t(9252)),r=v(t(75663)),o=v(t(94889)),a=v(t(42532)),i=t(79257);function v(h){return h&&h.__esModule?h:{default:h}}function c(h){var f,u=(0,n.default)(h),d=(0,a.default)(h),s=(f=h.ownerDocument)==null?void 0:f.body,p=(0,i.max)(u.scrollWidth,u.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),l=(0,i.max)(u.scrollHeight,u.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),g=-d.scrollLeft+(0,o.default)(h),m=-d.scrollTop;return(0,r.default)(s||u).direction==="rtl"&&(g+=(0,i.max)(u.clientWidth,s?s.clientWidth:0)-p),{width:p,height:l,x:g,y:m}}},89741:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n){return{scrollLeft:n.scrollLeft,scrollTop:n.scrollTop}}},12866:function(S,e,t){"use strict";e.__esModule=!0,e.default=o;var n=r(t(83199));function r(a){return a&&a.__esModule?a:{default:a}}function o(a){var i=(0,n.default)(a),v=a.offsetWidth,c=a.offsetHeight;return Math.abs(i.width-v)<=1&&(v=i.width),Math.abs(i.height-c)<=1&&(c=i.height),{x:a.offsetLeft,y:a.offsetTop,width:v,height:c}}},1707:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n){return n?(n.nodeName||"").toLowerCase():null}},3107:function(S,e,t){"use strict";e.__esModule=!0,e.default=v;var n=i(t(42532)),r=i(t(44901)),o=t(65601),a=i(t(89741));function i(c){return c&&c.__esModule?c:{default:c}}function v(c){return c===(0,r.default)(c)||!(0,o.isHTMLElement)(c)?(0,n.default)(c):(0,a.default)(c)}},29727:function(S,e,t){"use strict";e.__esModule=!0,e.default=d;var n=h(t(44901)),r=h(t(1707)),o=h(t(75663)),a=t(65601),i=h(t(36875)),v=h(t(16292)),c=h(t(88492));function h(s){return s&&s.__esModule?s:{default:s}}function f(s){return!(0,a.isHTMLElement)(s)||(0,o.default)(s).position==="fixed"?null:s.offsetParent}function u(s){var p=/firefox/i.test((0,c.default)()),l=/Trident/i.test((0,c.default)());if(l&&(0,a.isHTMLElement)(s)){var g=(0,o.default)(s);if(g.position==="fixed")return null}var m=(0,v.default)(s);for((0,a.isShadowRoot)(m)&&(m=m.host);(0,a.isHTMLElement)(m)&&["html","body"].indexOf((0,r.default)(m))<0;){var E=(0,o.default)(m);if(E.transform!=="none"||E.perspective!=="none"||E.contain==="paint"||["transform","perspective"].indexOf(E.willChange)!==-1||p&&E.willChange==="filter"||p&&E.filter&&E.filter!=="none")return m;m=m.parentNode}return null}function d(s){for(var p=(0,n.default)(s),l=f(s);l&&(0,i.default)(l)&&(0,o.default)(l).position==="static";)l=f(l);return l&&((0,r.default)(l)==="html"||(0,r.default)(l)==="body"&&(0,o.default)(l).position==="static")?p:l||u(s)||p}},16292:function(S,e,t){"use strict";e.__esModule=!0,e.default=i;var n=a(t(1707)),r=a(t(9252)),o=t(65601);function a(v){return v&&v.__esModule?v:{default:v}}function i(v){return(0,n.default)(v)==="html"?v:v.assignedSlot||v.parentNode||((0,o.isShadowRoot)(v)?v.host:null)||(0,r.default)(v)}},87899:function(S,e,t){"use strict";e.__esModule=!0,e.default=v;var n=i(t(16292)),r=i(t(27703)),o=i(t(1707)),a=t(65601);function i(c){return c&&c.__esModule?c:{default:c}}function v(c){return["html","body","#document"].indexOf((0,o.default)(c))>=0?c.ownerDocument.body:(0,a.isHTMLElement)(c)&&(0,r.default)(c)?c:v((0,n.default)(c))}},63064:function(S,e,t){"use strict";e.__esModule=!0,e.default=v;var n=i(t(44901)),r=i(t(9252)),o=i(t(94889)),a=i(t(95294));function i(c){return c&&c.__esModule?c:{default:c}}function v(c,h){var f=(0,n.default)(c),u=(0,r.default)(c),d=f.visualViewport,s=u.clientWidth,p=u.clientHeight,l=0,g=0;if(d){s=d.width,p=d.height;var m=(0,a.default)();(m||!m&&h==="fixed")&&(l=d.offsetLeft,g=d.offsetTop)}return{width:s,height:p,x:l+(0,o.default)(c),y:g}}},44901:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n){if(n==null)return window;if(n.toString()!=="[object Window]"){var r=n.ownerDocument;return r&&r.defaultView||window}return n}},42532:function(S,e,t){"use strict";e.__esModule=!0,e.default=o;var n=r(t(44901));function r(a){return a&&a.__esModule?a:{default:a}}function o(a){var i=(0,n.default)(a),v=i.pageXOffset,c=i.pageYOffset;return{scrollLeft:v,scrollTop:c}}},94889:function(S,e,t){"use strict";e.__esModule=!0,e.default=i;var n=a(t(83199)),r=a(t(9252)),o=a(t(42532));function a(v){return v&&v.__esModule?v:{default:v}}function i(v){return(0,n.default)((0,r.default)(v)).left+(0,o.default)(v).scrollLeft}},65601:function(S,e,t){"use strict";e.__esModule=!0,e.isElement=o,e.isHTMLElement=a,e.isShadowRoot=i;var n=r(t(44901));function r(v){return v&&v.__esModule?v:{default:v}}function o(v){var c=(0,n.default)(v).Element;return v instanceof c||v instanceof Element}function a(v){var c=(0,n.default)(v).HTMLElement;return v instanceof c||v instanceof HTMLElement}function i(v){if(typeof ShadowRoot=="undefined")return!1;var c=(0,n.default)(v).ShadowRoot;return v instanceof c||v instanceof ShadowRoot}},95294:function(S,e,t){"use strict";e.__esModule=!0,e.default=o;var n=r(t(88492));function r(a){return a&&a.__esModule?a:{default:a}}function o(){return!/^((?!chrome|android).)*safari/i.test((0,n.default)())}},27703:function(S,e,t){"use strict";e.__esModule=!0,e.default=o;var n=r(t(75663));function r(a){return a&&a.__esModule?a:{default:a}}function o(a){var i=(0,n.default)(a),v=i.overflow,c=i.overflowX,h=i.overflowY;return/auto|scroll|overlay|hidden/.test(v+h+c)}},36875:function(S,e,t){"use strict";e.__esModule=!0,e.default=o;var n=r(t(1707));function r(a){return a&&a.__esModule?a:{default:a}}function o(a){return["table","td","th"].indexOf((0,n.default)(a))>=0}},88577:function(S,e,t){"use strict";e.__esModule=!0,e.default=v;var n=i(t(87899)),r=i(t(16292)),o=i(t(44901)),a=i(t(27703));function i(c){return c&&c.__esModule?c:{default:c}}function v(c,h){var f;h===void 0&&(h=[]);var u=(0,n.default)(c),d=u===((f=c.ownerDocument)==null?void 0:f.body),s=(0,o.default)(u),p=d?[s].concat(s.visualViewport||[],(0,a.default)(u)?u:[]):u,l=h.concat(p);return d?l:l.concat(v((0,r.default)(p)))}},37802:function(S,e){"use strict";e.__esModule=!0,e.write=e.viewport=e.variationPlacements=e.top=e.start=e.right=e.reference=e.read=e.popper=e.placements=e.modifierPhases=e.main=e.left=e.end=e.clippingParents=e.bottom=e.beforeWrite=e.beforeRead=e.beforeMain=e.basePlacements=e.auto=e.afterWrite=e.afterRead=e.afterMain=void 0;var t=e.top="top",n=e.bottom="bottom",r=e.right="right",o=e.left="left",a=e.auto="auto",i=e.basePlacements=[t,n,r,o],v=e.start="start",c=e.end="end",h=e.clippingParents="clippingParents",f=e.viewport="viewport",u=e.popper="popper",d=e.reference="reference",s=e.variationPlacements=i.reduce(function(P,N){return P.concat([N+"-"+v,N+"-"+c])},[]),p=e.placements=[].concat(i,[a]).reduce(function(P,N){return P.concat([N,N+"-"+v,N+"-"+c])},[]),l=e.beforeRead="beforeRead",g=e.read="read",m=e.afterRead="afterRead",E=e.beforeMain="beforeMain",O=e.main="main",I=e.afterMain="afterMain",T=e.beforeWrite="beforeWrite",y=e.write="write",b=e.afterWrite="afterWrite",C=e.modifierPhases=[l,g,m,E,O,I,T,y,b]},60028:function(S,e,t){"use strict";e.__esModule=!0;var n={popperGenerator:!0,detectOverflow:!0,createPopperBase:!0,createPopper:!0,createPopperLite:!0};e.popperGenerator=e.detectOverflow=e.createPopperLite=e.createPopperBase=e.createPopper=void 0;var r=t(37802);Object.keys(r).forEach(function(c){c==="default"||c==="__esModule"||Object.prototype.hasOwnProperty.call(n,c)||c in e&&e[c]===r[c]||(e[c]=r[c])});var o=t(16055);Object.keys(o).forEach(function(c){c==="default"||c==="__esModule"||Object.prototype.hasOwnProperty.call(n,c)||c in e&&e[c]===o[c]||(e[c]=o[c])});var a=t(15113);e.popperGenerator=a.popperGenerator,e.detectOverflow=a.detectOverflow,e.createPopperBase=a.createPopper;var i=t(98420);e.createPopper=i.createPopper;var v=t(22008);e.createPopperLite=v.createPopper},20637:function(S,e,t){"use strict";e.__esModule=!0,e.default=void 0;var n=o(t(1707)),r=t(65601);function o(c){return c&&c.__esModule?c:{default:c}}function a(c){var h=c.state;Object.keys(h.elements).forEach(function(f){var u=h.styles[f]||{},d=h.attributes[f]||{},s=h.elements[f];!(0,r.isHTMLElement)(s)||!(0,n.default)(s)||(Object.assign(s.style,u),Object.keys(d).forEach(function(p){var l=d[p];l===!1?s.removeAttribute(p):s.setAttribute(p,l===!0?"":l)}))})}function i(c){var h=c.state,f={popper:{position:h.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(h.elements.popper.style,f.popper),h.styles=f,h.elements.arrow&&Object.assign(h.elements.arrow.style,f.arrow),function(){Object.keys(h.elements).forEach(function(u){var d=h.elements[u],s=h.attributes[u]||{},p=Object.keys(h.styles.hasOwnProperty(u)?h.styles[u]:f[u]),l=p.reduce(function(g,m){return g[m]="",g},{});!(0,r.isHTMLElement)(d)||!(0,n.default)(d)||(Object.assign(d.style,l),Object.keys(s).forEach(function(g){d.removeAttribute(g)}))})}}var v=e.default={name:"applyStyles",enabled:!0,phase:"write",fn:a,effect:i,requires:["computeStyles"]}},11106:function(S,e,t){"use strict";e.__esModule=!0,e.default=void 0;var n=u(t(16275)),r=u(t(12866)),o=u(t(11848)),a=u(t(29727)),i=u(t(26608)),v=t(87415),c=u(t(41e3)),h=u(t(62605)),f=t(37802);function u(g){return g&&g.__esModule?g:{default:g}}var d=function(){function g(m,E){return m=typeof m=="function"?m(Object.assign({},E.rects,{placement:E.placement})):m,(0,c.default)(typeof m!="number"?m:(0,h.default)(m,f.basePlacements))}return g}();function s(g){var m,E=g.state,O=g.name,I=g.options,T=E.elements.arrow,y=E.modifiersData.popperOffsets,b=(0,n.default)(E.placement),C=(0,i.default)(b),P=[f.left,f.right].indexOf(b)>=0,N=P?"height":"width";if(!(!T||!y)){var w=d(I.padding,E),M=(0,r.default)(T),L=C==="y"?f.top:f.left,K=C==="y"?f.bottom:f.right,x=E.rects.reference[N]+E.rects.reference[C]-y[C]-E.rects.popper[N],U=y[C]-E.rects.reference[C],G=(0,a.default)(T),D=G?C==="y"?G.clientHeight||0:G.clientWidth||0:0,F=x/2-U/2,V=w[L],$=D-M[N]-w[K],Y=D/2-M[N]/2+F,z=(0,v.within)(V,Y,$),et=C;E.modifiersData[O]=(m={},m[et]=z,m.centerOffset=z-Y,m)}}function p(g){var m=g.state,E=g.options,O=E.element,I=O===void 0?"[data-popper-arrow]":O;I!=null&&(typeof I=="string"&&(I=m.elements.popper.querySelector(I),!I)||(0,o.default)(m.elements.popper,I)&&(m.elements.arrow=I))}var l=e.default={name:"arrow",enabled:!0,phase:"main",fn:s,effect:p,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]}},85445:function(S,e,t){"use strict";e.__esModule=!0,e.default=void 0,e.mapToStyles=s;var n=t(37802),r=f(t(29727)),o=f(t(44901)),a=f(t(9252)),i=f(t(75663)),v=f(t(16275)),c=f(t(56918)),h=t(79257);function f(g){return g&&g.__esModule?g:{default:g}}var u={top:"auto",right:"auto",bottom:"auto",left:"auto"};function d(g,m){var E=g.x,O=g.y,I=m.devicePixelRatio||1;return{x:(0,h.round)(E*I)/I||0,y:(0,h.round)(O*I)/I||0}}function s(g){var m,E=g.popper,O=g.popperRect,I=g.placement,T=g.variation,y=g.offsets,b=g.position,C=g.gpuAcceleration,P=g.adaptive,N=g.roundOffsets,w=g.isFixed,M=y.x,L=M===void 0?0:M,K=y.y,x=K===void 0?0:K,U=typeof N=="function"?N({x:L,y:x}):{x:L,y:x};L=U.x,x=U.y;var G=y.hasOwnProperty("x"),D=y.hasOwnProperty("y"),F=n.left,V=n.top,$=window;if(P){var Y=(0,r.default)(E),z="clientHeight",et="clientWidth";if(Y===(0,o.default)(E)&&(Y=(0,a.default)(E),(0,i.default)(Y).position!=="static"&&b==="absolute"&&(z="scrollHeight",et="scrollWidth")),Y=Y,I===n.top||(I===n.left||I===n.right)&&T===n.end){V=n.bottom;var at=w&&Y===$&&$.visualViewport?$.visualViewport.height:Y[z];x-=at-O.height,x*=C?1:-1}if(I===n.left||(I===n.top||I===n.bottom)&&T===n.end){F=n.right;var ft=w&&Y===$&&$.visualViewport?$.visualViewport.width:Y[et];L-=ft-O.width,L*=C?1:-1}}var W=Object.assign({position:b},P&&u),X=N===!0?d({x:L,y:x},(0,o.default)(E)):{x:L,y:x};if(L=X.x,x=X.y,C){var nt;return Object.assign({},W,(nt={},nt[V]=D?"0":"",nt[F]=G?"0":"",nt.transform=($.devicePixelRatio||1)<=1?"translate("+L+"px, "+x+"px)":"translate3d("+L+"px, "+x+"px, 0)",nt))}return Object.assign({},W,(m={},m[V]=D?x+"px":"",m[F]=G?L+"px":"",m.transform="",m))}function p(g){var m=g.state,E=g.options,O=E.gpuAcceleration,I=O===void 0?!0:O,T=E.adaptive,y=T===void 0?!0:T,b=E.roundOffsets,C=b===void 0?!0:b,P={placement:(0,v.default)(m.placement),variation:(0,c.default)(m.placement),popper:m.elements.popper,popperRect:m.rects.popper,gpuAcceleration:I,isFixed:m.options.strategy==="fixed"};m.modifiersData.popperOffsets!=null&&(m.styles.popper=Object.assign({},m.styles.popper,s(Object.assign({},P,{offsets:m.modifiersData.popperOffsets,position:m.options.strategy,adaptive:y,roundOffsets:C})))),m.modifiersData.arrow!=null&&(m.styles.arrow=Object.assign({},m.styles.arrow,s(Object.assign({},P,{offsets:m.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:C})))),m.attributes.popper=Object.assign({},m.attributes.popper,{"data-popper-placement":m.placement})}var l=e.default={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:p,data:{}}},21068:function(S,e,t){"use strict";e.__esModule=!0,e.default=void 0;var n=r(t(44901));function r(v){return v&&v.__esModule?v:{default:v}}var o={passive:!0};function a(v){var c=v.state,h=v.instance,f=v.options,u=f.scroll,d=u===void 0?!0:u,s=f.resize,p=s===void 0?!0:s,l=(0,n.default)(c.elements.popper),g=[].concat(c.scrollParents.reference,c.scrollParents.popper);return d&&g.forEach(function(m){m.addEventListener("scroll",h.update,o)}),p&&l.addEventListener("resize",h.update,o),function(){d&&g.forEach(function(m){m.removeEventListener("scroll",h.update,o)}),p&&l.removeEventListener("resize",h.update,o)}}var i=e.default={name:"eventListeners",enabled:!0,phase:"write",fn:function(){function v(){}return v}(),effect:a,data:{}}},51825:function(S,e,t){"use strict";e.__esModule=!0,e.default=void 0;var n=h(t(96346)),r=h(t(16275)),o=h(t(15022)),a=h(t(4709)),i=h(t(36705)),v=t(37802),c=h(t(56918));function h(s){return s&&s.__esModule?s:{default:s}}function f(s){if((0,r.default)(s)===v.auto)return[];var p=(0,n.default)(s);return[(0,o.default)(s),p,(0,o.default)(p)]}function u(s){var p=s.state,l=s.options,g=s.name;if(!p.modifiersData[g]._skip){for(var m=l.mainAxis,E=m===void 0?!0:m,O=l.altAxis,I=O===void 0?!0:O,T=l.fallbackPlacements,y=l.padding,b=l.boundary,C=l.rootBoundary,P=l.altBoundary,N=l.flipVariations,w=N===void 0?!0:N,M=l.allowedAutoPlacements,L=p.options.placement,K=(0,r.default)(L),x=K===L,U=T||(x||!w?[(0,n.default)(L)]:f(L)),G=[L].concat(U).reduce(function(dt,J){return dt.concat((0,r.default)(J)===v.auto?(0,i.default)(p,{placement:J,boundary:b,rootBoundary:C,padding:y,flipVariations:w,allowedAutoPlacements:M}):J)},[]),D=p.rects.reference,F=p.rects.popper,V=new Map,$=!0,Y=G[0],z=0;z=0,X=W?"width":"height",nt=(0,a.default)(p,{placement:et,boundary:b,rootBoundary:C,altBoundary:P,padding:y}),ct=W?ft?v.right:v.left:ft?v.bottom:v.top;D[X]>F[X]&&(ct=(0,n.default)(ct));var it=(0,n.default)(ct),St=[];if(E&&St.push(nt[at]<=0),I&&St.push(nt[ct]<=0,nt[it]<=0),St.every(function(dt){return dt})){Y=et,$=!1;break}V.set(et,St)}if($)for(var Pt=w?3:1,Mt=function(){function dt(J){var Z=G.find(function(ot){var gt=V.get(ot);if(gt)return gt.slice(0,J).every(function(Et){return Et})});if(Z)return Y=Z,"break"}return dt}(),Nt=Pt;Nt>0;Nt--){var ht=Mt(Nt);if(ht==="break")break}p.placement!==Y&&(p.modifiersData[g]._skip=!0,p.placement=Y,p.reset=!0)}}var d=e.default={name:"flip",enabled:!0,phase:"main",fn:u,requiresIfExists:["offset"],data:{_skip:!1}}},44677:function(S,e,t){"use strict";e.__esModule=!0,e.default=void 0;var n=t(37802),r=o(t(4709));function o(h){return h&&h.__esModule?h:{default:h}}function a(h,f,u){return u===void 0&&(u={x:0,y:0}),{top:h.top-f.height-u.y,right:h.right-f.width+u.x,bottom:h.bottom-f.height+u.y,left:h.left-f.width-u.x}}function i(h){return[n.top,n.right,n.bottom,n.left].some(function(f){return h[f]>=0})}function v(h){var f=h.state,u=h.name,d=f.rects.reference,s=f.rects.popper,p=f.modifiersData.preventOverflow,l=(0,r.default)(f,{elementContext:"reference"}),g=(0,r.default)(f,{altBoundary:!0}),m=a(l,d),E=a(g,s,p),O=i(m),I=i(E);f.modifiersData[u]={referenceClippingOffsets:m,popperEscapeOffsets:E,isReferenceHidden:O,hasPopperEscaped:I},f.attributes.popper=Object.assign({},f.attributes.popper,{"data-popper-reference-hidden":O,"data-popper-escaped":I})}var c=e.default={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:v}},16055:function(S,e,t){"use strict";e.__esModule=!0,e.preventOverflow=e.popperOffsets=e.offset=e.hide=e.flip=e.eventListeners=e.computeStyles=e.arrow=e.applyStyles=void 0;var n=u(t(20637));e.applyStyles=n.default;var r=u(t(11106));e.arrow=r.default;var o=u(t(85445));e.computeStyles=o.default;var a=u(t(21068));e.eventListeners=a.default;var i=u(t(51825));e.flip=i.default;var v=u(t(44677));e.hide=v.default;var c=u(t(34331));e.offset=c.default;var h=u(t(56154));e.popperOffsets=h.default;var f=u(t(69770));e.preventOverflow=f.default;function u(d){return d&&d.__esModule?d:{default:d}}},34331:function(S,e,t){"use strict";e.__esModule=!0,e.default=void 0,e.distanceAndSkiddingToXY=a;var n=o(t(16275)),r=t(37802);function o(c){return c&&c.__esModule?c:{default:c}}function a(c,h,f){var u=(0,n.default)(c),d=[r.left,r.top].indexOf(u)>=0?-1:1,s=typeof f=="function"?f(Object.assign({},h,{placement:c})):f,p=s[0],l=s[1];return p=p||0,l=(l||0)*d,[r.left,r.right].indexOf(u)>=0?{x:l,y:p}:{x:p,y:l}}function i(c){var h=c.state,f=c.options,u=c.name,d=f.offset,s=d===void 0?[0,0]:d,p=r.placements.reduce(function(E,O){return E[O]=a(O,h.rects,s),E},{}),l=p[h.placement],g=l.x,m=l.y;h.modifiersData.popperOffsets!=null&&(h.modifiersData.popperOffsets.x+=g,h.modifiersData.popperOffsets.y+=m),h.modifiersData[u]=p}var v=e.default={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:i}},56154:function(S,e,t){"use strict";e.__esModule=!0,e.default=void 0;var n=r(t(49306));function r(i){return i&&i.__esModule?i:{default:i}}function o(i){var v=i.state,c=i.name;v.modifiersData[c]=(0,n.default)({reference:v.rects.reference,element:v.rects.popper,strategy:"absolute",placement:v.placement})}var a=e.default={name:"popperOffsets",enabled:!0,phase:"read",fn:o,data:{}}},69770:function(S,e,t){"use strict";e.__esModule=!0,e.default=void 0;var n=t(37802),r=s(t(16275)),o=s(t(26608)),a=s(t(49903)),i=t(87415),v=s(t(12866)),c=s(t(29727)),h=s(t(4709)),f=s(t(56918)),u=s(t(26143)),d=t(79257);function s(g){return g&&g.__esModule?g:{default:g}}function p(g){var m=g.state,E=g.options,O=g.name,I=E.mainAxis,T=I===void 0?!0:I,y=E.altAxis,b=y===void 0?!1:y,C=E.boundary,P=E.rootBoundary,N=E.altBoundary,w=E.padding,M=E.tether,L=M===void 0?!0:M,K=E.tetherOffset,x=K===void 0?0:K,U=(0,h.default)(m,{boundary:C,rootBoundary:P,padding:w,altBoundary:N}),G=(0,r.default)(m.placement),D=(0,f.default)(m.placement),F=!D,V=(0,o.default)(G),$=(0,a.default)(V),Y=m.modifiersData.popperOffsets,z=m.rects.reference,et=m.rects.popper,at=typeof x=="function"?x(Object.assign({},m.rects,{placement:m.placement})):x,ft=typeof at=="number"?{mainAxis:at,altAxis:at}:Object.assign({mainAxis:0,altAxis:0},at),W=m.modifiersData.offset?m.modifiersData.offset[m.placement]:null,X={x:0,y:0};if(Y){if(T){var nt,ct=V==="y"?n.top:n.left,it=V==="y"?n.bottom:n.right,St=V==="y"?"height":"width",Pt=Y[V],Mt=Pt+U[ct],Nt=Pt-U[it],ht=L?-et[St]/2:0,dt=D===n.start?z[St]:et[St],J=D===n.start?-et[St]:-z[St],Z=m.elements.arrow,ot=L&&Z?(0,v.default)(Z):{width:0,height:0},gt=m.modifiersData["arrow#persistent"]?m.modifiersData["arrow#persistent"].padding:(0,u.default)(),Et=gt[ct],ut=gt[it],pt=(0,i.within)(0,z[St],ot[St]),rt=F?z[St]/2-ht-pt-Et-ft.mainAxis:dt-pt-Et-ft.mainAxis,q=F?-z[St]/2+ht+pt+ut+ft.mainAxis:J+pt+ut+ft.mainAxis,mt=m.elements.arrow&&(0,c.default)(m.elements.arrow),Tt=mt?V==="y"?mt.clientTop||0:mt.clientLeft||0:0,wt=(nt=W==null?void 0:W[V])!=null?nt:0,xt=Pt+rt-wt-Tt,Ut=Pt+q-wt,Ot=(0,i.within)(L?(0,d.min)(Mt,xt):Mt,Pt,L?(0,d.max)(Nt,Ut):Nt);Y[V]=Ot,X[V]=Ot-Pt}if(b){var lt,yt=V==="x"?n.top:n.left,Ct=V==="x"?n.bottom:n.right,bt=Y[$],It=$==="y"?"height":"width",Lt=bt+U[yt],Vt=bt-U[Ct],$t=[n.top,n.left].indexOf(G)!==-1,kt=(lt=W==null?void 0:W[$])!=null?lt:0,Yt=$t?Lt:bt-z[It]-et[It]-kt+ft.altAxis,Ht=$t?bt+z[It]+et[It]-kt-ft.altAxis:Vt,Jt=L&&$t?(0,i.withinMaxClamp)(Yt,bt,Ht):(0,i.within)(L?Yt:Lt,bt,L?Ht:Vt);Y[$]=Jt,X[$]=Jt-bt}m.modifiersData[O]=X}}var l=e.default={name:"preventOverflow",enabled:!0,phase:"main",fn:p,requiresIfExists:["offset"]}},22008:function(S,e,t){"use strict";e.__esModule=!0,e.defaultModifiers=e.createPopper=void 0;var n=t(15113);e.popperGenerator=n.popperGenerator,e.detectOverflow=n.detectOverflow;var r=v(t(21068)),o=v(t(56154)),a=v(t(85445)),i=v(t(20637));function v(f){return f&&f.__esModule?f:{default:f}}var c=e.defaultModifiers=[r.default,o.default,a.default,i.default],h=e.createPopper=(0,n.popperGenerator)({defaultModifiers:c})},98420:function(S,e,t){"use strict";e.__esModule=!0;var n={createPopper:!0,createPopperLite:!0,defaultModifiers:!0,popperGenerator:!0,detectOverflow:!0};e.defaultModifiers=e.createPopperLite=e.createPopper=void 0;var r=t(15113);e.popperGenerator=r.popperGenerator,e.detectOverflow=r.detectOverflow;var o=l(t(21068)),a=l(t(56154)),i=l(t(85445)),v=l(t(20637)),c=l(t(34331)),h=l(t(51825)),f=l(t(69770)),u=l(t(11106)),d=l(t(44677)),s=t(22008);e.createPopperLite=s.createPopper;var p=t(16055);Object.keys(p).forEach(function(E){E==="default"||E==="__esModule"||Object.prototype.hasOwnProperty.call(n,E)||E in e&&e[E]===p[E]||(e[E]=p[E])});function l(E){return E&&E.__esModule?E:{default:E}}var g=e.defaultModifiers=[o.default,a.default,i.default,v.default,c.default,h.default,f.default,u.default,d.default],m=e.createPopperLite=e.createPopper=(0,r.popperGenerator)({defaultModifiers:g})},36705:function(S,e,t){"use strict";e.__esModule=!0,e.default=v;var n=i(t(56918)),r=t(37802),o=i(t(4709)),a=i(t(16275));function i(c){return c&&c.__esModule?c:{default:c}}function v(c,h){h===void 0&&(h={});var f=h,u=f.placement,d=f.boundary,s=f.rootBoundary,p=f.padding,l=f.flipVariations,g=f.allowedAutoPlacements,m=g===void 0?r.placements:g,E=(0,n.default)(u),O=E?l?r.variationPlacements:r.variationPlacements.filter(function(y){return(0,n.default)(y)===E}):r.basePlacements,I=O.filter(function(y){return m.indexOf(y)>=0});I.length===0&&(I=O);var T=I.reduce(function(y,b){return y[b]=(0,o.default)(c,{placement:b,boundary:d,rootBoundary:s,padding:p})[(0,a.default)(b)],y},{});return Object.keys(T).sort(function(y,b){return T[y]-T[b]})}},49306:function(S,e,t){"use strict";e.__esModule=!0,e.default=v;var n=i(t(16275)),r=i(t(56918)),o=i(t(26608)),a=t(37802);function i(c){return c&&c.__esModule?c:{default:c}}function v(c){var h=c.reference,f=c.element,u=c.placement,d=u?(0,n.default)(u):null,s=u?(0,r.default)(u):null,p=h.x+h.width/2-f.width/2,l=h.y+h.height/2-f.height/2,g;switch(d){case a.top:g={x:p,y:h.y-f.height};break;case a.bottom:g={x:p,y:h.y+h.height};break;case a.right:g={x:h.x+h.width,y:l};break;case a.left:g={x:h.x-f.width,y:l};break;default:g={x:h.x,y:h.y}}var m=d?(0,o.default)(d):null;if(m!=null){var E=m==="y"?"height":"width";switch(s){case a.start:g[m]=g[m]-(h[E]/2-f[E]/2);break;case a.end:g[m]=g[m]+(h[E]/2-f[E]/2);break;default:}}return g}},97902:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n){var r;return function(){return r||(r=new Promise(function(o){Promise.resolve().then(function(){r=void 0,o(n())})})),r}}},4709:function(S,e,t){"use strict";e.__esModule=!0,e.default=d;var n=u(t(98310)),r=u(t(9252)),o=u(t(83199)),a=u(t(49306)),i=u(t(21194)),v=t(37802),c=t(65601),h=u(t(41e3)),f=u(t(62605));function u(s){return s&&s.__esModule?s:{default:s}}function d(s,p){p===void 0&&(p={});var l=p,g=l.placement,m=g===void 0?s.placement:g,E=l.strategy,O=E===void 0?s.strategy:E,I=l.boundary,T=I===void 0?v.clippingParents:I,y=l.rootBoundary,b=y===void 0?v.viewport:y,C=l.elementContext,P=C===void 0?v.popper:C,N=l.altBoundary,w=N===void 0?!1:N,M=l.padding,L=M===void 0?0:M,K=(0,h.default)(typeof L!="number"?L:(0,f.default)(L,v.basePlacements)),x=P===v.popper?v.reference:v.popper,U=s.rects.popper,G=s.elements[w?x:P],D=(0,n.default)((0,c.isElement)(G)?G:G.contextElement||(0,r.default)(s.elements.popper),T,b,O),F=(0,o.default)(s.elements.reference),V=(0,a.default)({reference:F,element:U,strategy:"absolute",placement:m}),$=(0,i.default)(Object.assign({},U,V)),Y=P===v.popper?$:F,z={top:D.top-Y.top+K.top,bottom:Y.bottom-D.bottom+K.bottom,left:D.left-Y.left+K.left,right:Y.right-D.right+K.right},et=s.modifiersData.offset;if(P===v.popper&&et){var at=et[m];Object.keys(z).forEach(function(ft){var W=[v.right,v.bottom].indexOf(ft)>=0?1:-1,X=[v.top,v.bottom].indexOf(ft)>=0?"y":"x";z[ft]+=at[X]*W})}return z}},62605:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n,r){return r.reduce(function(o,a){return o[a]=n,o},{})}},49903:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n){return n==="x"?"y":"x"}},16275:function(S,e,t){"use strict";e.__esModule=!0,e.default=r;var n=t(37802);function r(o){return o.split("-")[0]}},26143:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(){return{top:0,right:0,bottom:0,left:0}}},26608:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n){return["top","bottom"].indexOf(n)>=0?"x":"y"}},96346:function(S,e){"use strict";e.__esModule=!0,e.default=n;var t={left:"right",right:"left",bottom:"top",top:"bottom"};function n(r){return r.replace(/left|right|bottom|top/g,function(o){return t[o]})}},15022:function(S,e){"use strict";e.__esModule=!0,e.default=n;var t={start:"end",end:"start"};function n(r){return r.replace(/start|end/g,function(o){return t[o]})}},56918:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n){return n.split("-")[1]}},79257:function(S,e){"use strict";e.__esModule=!0,e.round=e.min=e.max=void 0;var t=e.max=Math.max,n=e.min=Math.min,r=e.round=Math.round},57547:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n){var r=n.reduce(function(o,a){var i=o[a.name];return o[a.name]=i?Object.assign({},i,a,{options:Object.assign({},i.options,a.options),data:Object.assign({},i.data,a.data)}):a,o},{});return Object.keys(r).map(function(o){return r[o]})}},41e3:function(S,e,t){"use strict";e.__esModule=!0,e.default=o;var n=r(t(26143));function r(a){return a&&a.__esModule?a:{default:a}}function o(a){return Object.assign({},(0,n.default)(),a)}},13657:function(S,e,t){"use strict";e.__esModule=!0,e.default=o;var n=t(37802);function r(a){var i=new Map,v=new Set,c=[];a.forEach(function(f){i.set(f.name,f)});function h(f){v.add(f.name);var u=[].concat(f.requires||[],f.requiresIfExists||[]);u.forEach(function(d){if(!v.has(d)){var s=i.get(d);s&&h(s)}}),c.push(f)}return a.forEach(function(f){v.has(f.name)||h(f)}),c}function o(a){var i=r(a);return n.modifierPhases.reduce(function(v,c){return v.concat(i.filter(function(h){return h.phase===c}))},[])}},21194:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(n){return Object.assign({},n,{left:n.x,top:n.y,right:n.x+n.width,bottom:n.y+n.height})}},88492:function(S,e){"use strict";e.__esModule=!0,e.default=t;function t(){var n=navigator.userAgentData;return n!=null&&n.brands&&Array.isArray(n.brands)?n.brands.map(function(r){return r.brand+"/"+r.version}).join(" "):navigator.userAgent}},87415:function(S,e,t){"use strict";e.__esModule=!0,e.within=r,e.withinMaxClamp=o;var n=t(79257);function r(a,i,v){return(0,n.max)(a,(0,n.min)(i,v))}function o(a,i,v){var c=r(a,i,v);return c>v?v:c}},85966:function(S){"use strict";/*! @license DOMPurify 2.4.7 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.4.7/LICENSE */(function(e,t){S.exports=t()})(void 0,function(){"use strict";function e(rt){"@babel/helpers - typeof";return e=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(q){return typeof q}:function(q){return q&&typeof Symbol=="function"&&q.constructor===Symbol&&q!==Symbol.prototype?"symbol":typeof q},e(rt)}function t(rt,q){return t=Object.setPrototypeOf||function(){function mt(Tt,wt){return Tt.__proto__=wt,Tt}return mt}(),t(rt,q)}function n(){if(typeof Reflect=="undefined"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(rt){return!1}}function r(rt,q,mt){return n()?r=Reflect.construct:r=function(){function Tt(wt,xt,Ut){var Ot=[null];Ot.push.apply(Ot,xt);var lt=Function.bind.apply(wt,Ot),yt=new lt;return Ut&&t(yt,Ut.prototype),yt}return Tt}(),r.apply(null,arguments)}function o(rt){return a(rt)||i(rt)||v(rt)||h()}function a(rt){if(Array.isArray(rt))return c(rt)}function i(rt){if(typeof Symbol!="undefined"&&rt[Symbol.iterator]!=null||rt["@@iterator"]!=null)return Array.from(rt)}function v(rt,q){if(rt){if(typeof rt=="string")return c(rt,q);var mt=Object.prototype.toString.call(rt).slice(8,-1);if(mt==="Object"&&rt.constructor&&(mt=rt.constructor.name),mt==="Map"||mt==="Set")return Array.from(rt);if(mt==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(mt))return c(rt,q)}}function c(rt,q){(q==null||q>rt.length)&&(q=rt.length);for(var mt=0,Tt=new Array(q);mt1?mt-1:0),wt=1;wt/gm),Mt=g(/\${[\w\W]*}/gm),Nt=g(/^data-[\-\w.\u00B7-\uFFFF]/),ht=g(/^aria-[\-\w]+$/),dt=g(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),J=g(/^(?:\w+script|data):/i),Z=g(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),ot=g(/^html$/i),gt=function(){function rt(){return typeof window=="undefined"?null:window}return rt}(),Et=function(){function rt(q,mt){if(e(q)!=="object"||typeof q.createPolicy!="function")return null;var Tt=null,wt="data-tt-policy-suffix";mt.currentScript&&mt.currentScript.hasAttribute(wt)&&(Tt=mt.currentScript.getAttribute(wt));var xt="dompurify"+(Tt?"#"+Tt:"");try{return q.createPolicy(xt,{createHTML:function(){function Ut(Ot){return Ot}return Ut}(),createScriptURL:function(){function Ut(Ot){return Ot}return Ut}()})}catch(Ut){return null}}return rt}();function ut(){var rt=arguments.length>0&&arguments[0]!==void 0?arguments[0]:gt(),q=function(){function k(j){return ut(j)}return k}();if(q.version="2.4.7",q.removed=[],!rt||!rt.document||rt.document.nodeType!==9)return q.isSupported=!1,q;var mt=rt.document,Tt=rt.document,wt=rt.DocumentFragment,xt=rt.HTMLTemplateElement,Ut=rt.Node,Ot=rt.Element,lt=rt.NodeFilter,yt=rt.NamedNodeMap,Ct=yt===void 0?rt.NamedNodeMap||rt.MozNamedAttrMap:yt,bt=rt.HTMLFormElement,It=rt.DOMParser,Lt=rt.trustedTypes,Vt=Ot.prototype,$t=V(Vt,"cloneNode"),kt=V(Vt,"nextSibling"),Yt=V(Vt,"childNodes"),Ht=V(Vt,"parentNode");if(typeof xt=="function"){var Jt=Tt.createElement("template");Jt.content&&Jt.content.ownerDocument&&(Tt=Jt.content.ownerDocument)}var qt=Et(Lt,mt),Ae=qt?qt.createHTML(""):"",Ee=Tt,be=Ee.implementation,on=Ee.createNodeIterator,an=Ee.createDocumentFragment,un=Ee.getElementsByTagName,xe=mt.importNode,Fe={};try{Fe=F(Tt).documentMode?Tt.documentMode:{}}catch(k){}var ne={};q.isSupported=typeof Ht=="function"&&be&&be.createHTMLDocument!==void 0&&Fe!==9;var Pe=St,Ve=Pt,je=Mt,Ne=Nt,Te=ht,te=J,re=Z,le=dt,zt=null,Ce=D({},[].concat(o($),o(Y),o(z),o(at),o(W))),Qt=null,sn=D({},[].concat(o(X),o(nt),o(ct),o(it))),Xt=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Oe=null,Ie=null,Ue=!0,we=!0,Ke=!1,Me=!0,Wt=!1,fe=!1,$e=!1,Re=!1,de=!1,oe=!1,Le=!1,cn=!0,ln=!1,fn="user-content-",Ge=!0,me=!1,ye={},Zt=null,dn=D({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),vn=null,hn=D({},["audio","video","img","source","image","track"]),Ye=null,gn=D({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),De="http://www.w3.org/1998/Math/MathML",Se="http://www.w3.org/2000/svg",ue="http://www.w3.org/1999/xhtml",ve=ue,He=!1,We=null,yn=D({},[De,Se,ue],P),he,Sn=["application/xhtml+xml","text/html"],En="text/html",Gt,se=null,pn=Tt.createElement("form"),mn=function(){function k(j){return j instanceof RegExp||j instanceof Function}return k}(),ke=function(){function k(j){se&&se===j||((!j||e(j)!=="object")&&(j={}),j=F(j),he=Sn.indexOf(j.PARSER_MEDIA_TYPE)===-1?he=En:he=j.PARSER_MEDIA_TYPE,Gt=he==="application/xhtml+xml"?P:C,zt="ALLOWED_TAGS"in j?D({},j.ALLOWED_TAGS,Gt):Ce,Qt="ALLOWED_ATTR"in j?D({},j.ALLOWED_ATTR,Gt):sn,We="ALLOWED_NAMESPACES"in j?D({},j.ALLOWED_NAMESPACES,P):yn,Ye="ADD_URI_SAFE_ATTR"in j?D(F(gn),j.ADD_URI_SAFE_ATTR,Gt):gn,vn="ADD_DATA_URI_TAGS"in j?D(F(hn),j.ADD_DATA_URI_TAGS,Gt):hn,Zt="FORBID_CONTENTS"in j?D({},j.FORBID_CONTENTS,Gt):dn,Oe="FORBID_TAGS"in j?D({},j.FORBID_TAGS,Gt):{},Ie="FORBID_ATTR"in j?D({},j.FORBID_ATTR,Gt):{},ye="USE_PROFILES"in j?j.USE_PROFILES:!1,Ue=j.ALLOW_ARIA_ATTR!==!1,we=j.ALLOW_DATA_ATTR!==!1,Ke=j.ALLOW_UNKNOWN_PROTOCOLS||!1,Me=j.ALLOW_SELF_CLOSE_IN_ATTR!==!1,Wt=j.SAFE_FOR_TEMPLATES||!1,fe=j.WHOLE_DOCUMENT||!1,de=j.RETURN_DOM||!1,oe=j.RETURN_DOM_FRAGMENT||!1,Le=j.RETURN_TRUSTED_TYPE||!1,Re=j.FORCE_BODY||!1,cn=j.SANITIZE_DOM!==!1,ln=j.SANITIZE_NAMED_PROPS||!1,Ge=j.KEEP_CONTENT!==!1,me=j.IN_PLACE||!1,le=j.ALLOWED_URI_REGEXP||le,ve=j.NAMESPACE||ue,Xt=j.CUSTOM_ELEMENT_HANDLING||{},j.CUSTOM_ELEMENT_HANDLING&&mn(j.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Xt.tagNameCheck=j.CUSTOM_ELEMENT_HANDLING.tagNameCheck),j.CUSTOM_ELEMENT_HANDLING&&mn(j.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Xt.attributeNameCheck=j.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),j.CUSTOM_ELEMENT_HANDLING&&typeof j.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(Xt.allowCustomizedBuiltInElements=j.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Wt&&(we=!1),oe&&(de=!0),ye&&(zt=D({},o(W)),Qt=[],ye.html===!0&&(D(zt,$),D(Qt,X)),ye.svg===!0&&(D(zt,Y),D(Qt,nt),D(Qt,it)),ye.svgFilters===!0&&(D(zt,z),D(Qt,nt),D(Qt,it)),ye.mathMl===!0&&(D(zt,at),D(Qt,ct),D(Qt,it))),j.ADD_TAGS&&(zt===Ce&&(zt=F(zt)),D(zt,j.ADD_TAGS,Gt)),j.ADD_ATTR&&(Qt===sn&&(Qt=F(Qt)),D(Qt,j.ADD_ATTR,Gt)),j.ADD_URI_SAFE_ATTR&&D(Ye,j.ADD_URI_SAFE_ATTR,Gt),j.FORBID_CONTENTS&&(Zt===dn&&(Zt=F(Zt)),D(Zt,j.FORBID_CONTENTS,Gt)),Ge&&(zt["#text"]=!0),fe&&D(zt,["html","head","body"]),zt.table&&(D(zt,["tbody"]),delete Oe.tbody),l&&l(j),se=j)}return k}(),ze=D({},["mi","mo","mn","ms","mtext"]),Xe=D({},["foreignobject","desc","title","annotation-xml"]),bn=D({},["title","style","font","a","script"]),ge=D({},Y);D(ge,z),D(ge,et);var Qe=D({},at);D(Qe,ft);var Je=function(){function k(j){var st=Ht(j);(!st||!st.tagName)&&(st={namespaceURI:ve,tagName:"template"});var vt=C(j.tagName),At=C(st.tagName);return We[j.namespaceURI]?j.namespaceURI===Se?st.namespaceURI===ue?vt==="svg":st.namespaceURI===De?vt==="svg"&&(At==="annotation-xml"||ze[At]):!!ge[vt]:j.namespaceURI===De?st.namespaceURI===ue?vt==="math":st.namespaceURI===Se?vt==="math"&&Xe[At]:!!Qe[vt]:j.namespaceURI===ue?st.namespaceURI===Se&&!Xe[At]||st.namespaceURI===De&&!ze[At]?!1:!Qe[vt]&&(bn[vt]||!ge[vt]):!!(he==="application/xhtml+xml"&&We[j.namespaceURI]):!1}return k}(),ae=function(){function k(j){b(q.removed,{element:j});try{j.parentNode.removeChild(j)}catch(st){try{j.outerHTML=Ae}catch(vt){j.remove()}}}return k}(),Ze=function(){function k(j,st){try{b(q.removed,{attribute:st.getAttributeNode(j),from:st})}catch(vt){b(q.removed,{attribute:null,from:st})}if(st.removeAttribute(j),j==="is"&&!Qt[j])if(de||oe)try{ae(st)}catch(vt){}else try{st.setAttribute(j,"")}catch(vt){}}return k}(),_e=function(){function k(j){var st,vt;if(Re)j=""+j;else{var At=N(j,/^[\r\n\t ]+/);vt=At&&At[0]}he==="application/xhtml+xml"&&ve===ue&&(j=''+j+"");var Rt=qt?qt.createHTML(j):j;if(ve===ue)try{st=new It().parseFromString(Rt,he)}catch(Ft){}if(!st||!st.documentElement){st=be.createDocument(ve,"template",null);try{st.documentElement.innerHTML=He?Ae:Rt}catch(Ft){}}var Dt=st.body||st.documentElement;return j&&vt&&Dt.insertBefore(Tt.createTextNode(vt),Dt.childNodes[0]||null),ve===ue?un.call(st,fe?"html":"body")[0]:fe?st.documentElement:Dt}return k}(),qe=function(){function k(j){return on.call(j.ownerDocument||j,j,lt.SHOW_ELEMENT|lt.SHOW_COMMENT|lt.SHOW_TEXT,null,!1)}return k}(),tn=function(){function k(j){return j instanceof bt&&(typeof j.nodeName!="string"||typeof j.textContent!="string"||typeof j.removeChild!="function"||!(j.attributes instanceof Ct)||typeof j.removeAttribute!="function"||typeof j.setAttribute!="function"||typeof j.namespaceURI!="string"||typeof j.insertBefore!="function"||typeof j.hasChildNodes!="function")}return k}(),Be=function(){function k(j){return e(Ut)==="object"?j instanceof Ut:j&&e(j)==="object"&&typeof j.nodeType=="number"&&typeof j.nodeName=="string"}return k}(),A=function(){function k(j,st,vt){ne[j]&&T(ne[j],function(At){At.call(q,st,vt,se)})}return k}(),R=function(){function k(j){var st;if(A("beforeSanitizeElements",j,null),tn(j)||K(/[\u0080-\uFFFF]/,j.nodeName))return ae(j),!0;var vt=Gt(j.nodeName);if(A("uponSanitizeElement",j,{tagName:vt,allowedTags:zt}),j.hasChildNodes()&&!Be(j.firstElementChild)&&(!Be(j.content)||!Be(j.content.firstElementChild))&&K(/<[/\w]/g,j.innerHTML)&&K(/<[/\w]/g,j.textContent)||vt==="select"&&K(/