Merge remote-tracking branch 'tgstation/master' into upstream-feb12-2026

# Conflicts:
#	.github/CODEOWNERS
#	.github/workflows/compile_changelogs.yml
#	.github/workflows/stale.yml
#	SQL/database_changelog.md
#	_maps/map_files/CatwalkStation/CatwalkStation_2023.dmm
#	code/__DEFINES/atom_hud.dm
#	code/__DEFINES/inventory.dm
#	code/__DEFINES/mobs.dm
#	code/__DEFINES/species_clothing_paths.dm
#	code/__DEFINES/subsystems.dm
#	code/__DEFINES/surgery.dm
#	code/__HELPERS/global_lists.dm
#	code/_globalvars/lists/maintenance_loot.dm
#	code/_globalvars/traits/_traits.dm
#	code/controllers/subsystem/minor_mapping.dm
#	code/controllers/subsystem/processing/quirks.dm
#	code/controllers/subsystem/shuttle.dm
#	code/datums/components/palette.dm
#	code/datums/components/surgery_initiator.dm
#	code/datums/diseases/advance/advance.dm
#	code/datums/hud.dm
#	code/datums/mood.dm
#	code/datums/mutations/chameleon.dm
#	code/datums/quirks/negative_quirks/nyctophobia.dm
#	code/datums/status_effects/debuffs/debuffs.dm
#	code/datums/status_effects/debuffs/drunk.dm
#	code/datums/status_effects/debuffs/slime/slime_leech.dm
#	code/datums/weather/weather.dm
#	code/game/data_huds.dm
#	code/game/objects/items.dm
#	code/game/objects/items/devices/scanners/health_analyzer.dm
#	code/game/objects/items/frog_statue.dm
#	code/game/objects/items/rcd/RLD.dm
#	code/game/objects/items/robot/items/hypo.dm
#	code/game/objects/items/stacks/medical.dm
#	code/game/objects/items/stacks/wrap.dm
#	code/game/objects/items/storage/garment.dm
#	code/game/objects/items/tools/medical/defib.dm
#	code/game/objects/items/weaponry.dm
#	code/game/objects/items/weaponry/melee/misc.dm
#	code/game/objects/structures/crates_lockers/closets/secure/security.dm
#	code/game/objects/structures/curtains.dm
#	code/game/objects/structures/dresser.dm
#	code/game/objects/structures/girders.dm
#	code/game/objects/structures/maintenance.dm
#	code/game/objects/structures/mirror.dm
#	code/modules/admin/greyscale_modify_menu.dm
#	code/modules/admin/verbs/light_debug.dm
#	code/modules/antagonists/ashwalker/ashwalker.dm
#	code/modules/antagonists/heretic/knowledge/starting_lore.dm
#	code/modules/antagonists/ninja/ninjaDrainAct.dm
#	code/modules/art/paintings.dm
#	code/modules/client/preferences.dm
#	code/modules/client/verbs/ooc.dm
#	code/modules/clothing/head/wig.dm
#	code/modules/events/disease_outbreak.dm
#	code/modules/holodeck/holo_effect.dm
#	code/modules/jobs/job_types/head_of_security.dm
#	code/modules/jobs/job_types/security_officer.dm
#	code/modules/library/skill_learning/generic_skillchips/point.dm
#	code/modules/mining/lavaland/ash_flora.dm
#	code/modules/mining/lavaland/mining_loot/megafauna/ash_drake.dm
#	code/modules/mob/dead/new_player/new_player.dm
#	code/modules/mob/living/basic/guardian/guardian.dm
#	code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm
#	code/modules/mob/living/carbon/carbon.dm
#	code/modules/mob/living/carbon/human/human.dm
#	code/modules/mob/living/carbon/human/human_defines.dm
#	code/modules/mob/living/carbon/life.dm
#	code/modules/mob/living/living.dm
#	code/modules/mob/living/living_defines.dm
#	code/modules/mob/mob.dm
#	code/modules/mob_spawn/ghost_roles/mining_roles.dm
#	code/modules/mod/mod_control.dm
#	code/modules/mod/modules/modules_general.dm
#	code/modules/modular_computers/computers/item/computer_ui.dm
#	code/modules/paperwork/paper.dm
#	code/modules/paperwork/paperbin.dm
#	code/modules/power/lighting/light.dm
#	code/modules/projectiles/guns/energy/kinetic_accelerator.dm
#	code/modules/projectiles/projectile.dm
#	code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm
#	code/modules/reagents/chemistry/reagents/food_reagents.dm
#	code/modules/reagents/chemistry/reagents/other_reagents.dm
#	code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
#	code/modules/research/xenobiology/crossbreeding/_clothing.dm
#	code/modules/research/xenobiology/crossbreeding/prismatic.dm
#	code/modules/surgery/advanced/brainwashing.dm
#	code/modules/surgery/advanced/lobotomy.dm
#	code/modules/surgery/amputation.dm
#	code/modules/surgery/blood_filter.dm
#	code/modules/surgery/bodyparts/_bodyparts.dm
#	code/modules/surgery/brain_surgery.dm
#	code/modules/surgery/cavity_implant.dm
#	code/modules/surgery/coronary_bypass.dm
#	code/modules/surgery/gastrectomy.dm
#	code/modules/surgery/healing.dm
#	code/modules/surgery/limb_augmentation.dm
#	code/modules/surgery/organ_manipulation.dm
#	code/modules/surgery/revival.dm
#	code/modules/surgery/sleeper_protocol.dm
#	code/modules/surgery/surgery_helpers.dm
#	code/modules/surgery/surgery_step.dm
#	code/modules/unit_tests/_unit_tests.dm
#	code/modules/unit_tests/designs.dm
#	code/modules/unit_tests/icon_state_worn.dm
#	code/modules/unit_tests/screenshots/screenshot_antag_icons_cultist.png
#	code/modules/unit_tests/screenshots/screenshot_antag_icons_headrevolutionary.png
#	code/modules/unit_tests/screenshots/screenshot_antag_icons_provocateur.png
#	code/modules/unit_tests/screenshots/screenshot_husk_body.png
#	code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png
#	icons/map_icons/clothing/head/_head.dmi
#	icons/map_icons/clothing/shoes.dmi
#	icons/map_icons/items/_item.dmi
#	icons/mob/huds/hud.dmi
#	icons/mob/inhands/64x64_lefthand.dmi
#	icons/mob/inhands/64x64_righthand.dmi
#	icons/obj/machines/computer.dmi
#	tgui/packages/tgui/interfaces/OperatingComputer.jsx
#	tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx
#	tgui/packages/tgui/interfaces/PreferencesMenu/types.ts
#	tgui/packages/tgui/interfaces/SurgeryInitiator.tsx
#	tools/icon_cutter/check.py
This commit is contained in:
nevimer
2026-02-12 23:50:09 -05:00
2374 changed files with 81136 additions and 52767 deletions
@@ -14,7 +14,7 @@
/// Station alert datum for showing alerts UI
var/datum/station_alert/alert_control
/datum/computer_file/program/alarm_monitor/on_install()
/datum/computer_file/program/alarm_monitor/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
//We want to send an alarm if we're in one of the mining home areas
//Or if we're on station. Otherwise, die.
@@ -34,8 +34,7 @@
if(computer.internal_cell && prob(25))
QDEL_NULL(computer.internal_cell)
computer.visible_message(span_notice("\The [computer]'s battery explodes in rain of sparks."))
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
spark_system.start()
do_sparks(3, FALSE, src)
/datum/computer_file/program/revelation/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
. = ..()
@@ -267,6 +267,8 @@ GLOBAL_LIST_EMPTY_TYPED(active_bets, /datum/active_bet)
return
//taking money out
if(text2num(existing_bets[2]) > money_betting)
if(money_betting < 0)
return
var/money_taking_out = text2num(existing_bets[2]) - money_betting
total_amount_bet -= money_taking_out
better.bank_card_talk("Refunded [money_taking_out][MONEY_SYMBOL] for taking money out of your bet on [name].")
@@ -274,7 +276,7 @@ GLOBAL_LIST_EMPTY_TYPED(active_bets, /datum/active_bet)
existing_bets[2] = "[money_betting]"
return
if(!better.adjust_money(-money_betting, "Gambling on [name]"))
if(money_betting <= 0 || !better.adjust_money(-money_betting, "Gambling on [name]"))
return
total_amount_bet += money_betting
options[option_betting] += list(list(better, "[money_betting]"))
@@ -174,7 +174,7 @@
program_open_overlay = "generic"
extended_desc = "This program allows for remote monitoring of mission-assigned cyborgs."
program_flags = PROGRAM_ON_SYNDINET_STORE
download_access = list()
download_access = null
circuit_comp_type = /obj/item/circuit_component/mod_program/borg_monitor/syndie
/datum/computer_file/program/borg_monitor/syndicate/evaluate_borg(mob/living/silicon/robot/R)
@@ -48,10 +48,9 @@
//Aquire access from the inserted ID card.
if(!length(access))
var/obj/item/card/id/D = computer?.stored_id?.GetID()
if(!D)
access = computer?.GetAccess()
if(!length(access))
return FALSE
access = D.GetAccess()
if(paccess_to_check in access)
return TRUE
@@ -173,6 +172,8 @@
/datum/computer_file/program/budgetorders/ui_static_data(mob/user)
var/list/data = list()
data["max_order"] = CARGO_MAX_ORDER
data["displayed_currency_full_name"] = " [MONEY_NAME]"
data["displayed_currency_name"] = " [MONEY_SYMBOL]"
return data
/datum/computer_file/program/budgetorders/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
@@ -26,7 +26,7 @@
/// Which departments this program has access to. See region defines.
var/target_dept
/datum/computer_file/program/card_mod/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
/datum/computer_file/program/card_mod/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
ADD_TRAIT(computer_installing, TRAIT_MODPC_TWO_ID_SLOTS, REF(src))
@@ -34,7 +34,7 @@
///Cooldown timer between pings.
COOLDOWN_DECLARE(ping_cooldown)
/datum/computer_file/program/chatclient/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
/datum/computer_file/program/chatclient/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
if(!username)
username = "DefaultUser[rand(100, 999)]"
@@ -26,18 +26,17 @@
if(computer.stored_id.registered_account.civilian_bounty)
data["id_bounty_info"] = computer.stored_id.registered_account.civilian_bounty.description
data["id_bounty_num"] = computer.stored_id.registered_account.bounty_num()
data["id_bounty_value"] = (computer.stored_id.registered_account.civilian_bounty.reward) * (CIV_BOUNTY_SPLIT/100)
data["id_bounty_value"] = (computer.stored_id.registered_account.civilian_bounty.get_bounty_reward()) * (CIV_BOUNTY_SPLIT / 100)
if(computer.stored_id.registered_account.bounties)
data["picking"] = TRUE
data["id_bounty_names"] = list(computer.stored_id.registered_account.bounties[1].name,
computer.stored_id.registered_account.bounties[2].name,
computer.stored_id.registered_account.bounties[3].name)
data["id_bounty_infos"] = list(computer.stored_id.registered_account.bounties[1].description,
computer.stored_id.registered_account.bounties[2].description,
computer.stored_id.registered_account.bounties[3].description)
data["id_bounty_values"] = list(computer.stored_id.registered_account.bounties[1].reward * (CIV_BOUNTY_SPLIT/100),
computer.stored_id.registered_account.bounties[2].reward * (CIV_BOUNTY_SPLIT/100),
computer.stored_id.registered_account.bounties[3].reward * (CIV_BOUNTY_SPLIT/100))
data["id_bounty_names"] = list()
data["id_bounty_infos"] = list()
data["id_bounty_values"] = list()
for(var/datum/bounty/bounty as anything in computer.stored_id.registered_account.bounties)
data["id_bounty_names"] += bounty.name
data["id_bounty_infos"] += bounty.description
data["id_bounty_values"] += bounty.get_bounty_reward() * (CIV_BOUNTY_SPLIT / 100)
else
data["picking"] = FALSE
@@ -61,11 +60,11 @@
var/time_left = DisplayTimeText(COOLDOWN_TIMELEFT(id_account, bounty_timer), round_seconds_to = 1)
computer.balloon_alert(user, "try again in [time_left]!")
return FALSE
if(!id_account.account_job)
if(!computer.stored_id.trim)
computer.say("Requesting ID card has no job assignment registered!")
return FALSE
var/list/datum/bounty/crumbs = generate_bounty_list(id_account.account_job.bounty_types)
var/list/datum/bounty/crumbs = computer.stored_id.trim.generate_bounty_list()
COOLDOWN_START(id_account, bounty_timer, (5 MINUTES) - cooldown_reduction)
id_account.bounties = crumbs
@@ -80,31 +79,8 @@
if(!id_account?.bounties?[choice])
playsound(computer.loc, 'sound/machines/synth/synth_no.ogg', 40 , TRUE)
return
id_account.civilian_bounty = id_account.bounties[choice]
id_account.bounties = null
id_account.set_bounty(id_account.bounties[choice], computer.stored_id)
SSblackbox.record_feedback("tally", "bounties_assigned", 1, id_account.civilian_bounty.type)
return id_account.civilian_bounty
/**
* Generates a list of bounties for use with the civilian bounty pad, this is virtually identical to the stuff contained within: code/game/machinery/civilian_bounties.dm
* @param bounty_types the define taken from a job for selection of a random_bounty() proc.
* @param bounty_rolls the number of bounties to be selected from.
* @param assistant_failsafe Do we guarentee one assistant bounty per generated list? Used for non-assistant jobs to give an easier alternative to that job's default bounties.
*/
/datum/computer_file/program/civilianbounties/proc/generate_bounty_list(bounty_types, bounty_rolls = 3, assistant_failsafe = TRUE)
var/list/rolling_list = list()
if(assistant_failsafe)
rolling_list += random_bounty(CIV_JOB_BASIC)
while(bounty_rolls > 1)
var/datum/bounty/potential_bounty = random_bounty(bounty_types)
var/repeats_bool = FALSE
for(var/datum/iterator in rolling_list)
if(iterator.type == potential_bounty.type)
repeats_bool = TRUE
if(repeats_bool)
continue
rolling_list += potential_bounty
bounty_rolls -= 1
return rolling_list
#undef CIV_BOUNTY_SPLIT
@@ -14,7 +14,7 @@
can_run_on_flags = PROGRAM_PDA //It relies on the PDA messenger to let you know of new codes
detomatix_resistance = DETOMATIX_RESIST_MALUS
/datum/computer_file/program/coupon/on_install()
/datum/computer_file/program/coupon/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
///set the discount_coupons list, which means SSmodular_computers will now begin to periodically produce new coupon codes.
LAZYINITLIST(SSmodular_computers.discount_coupons)
@@ -48,8 +48,10 @@ GLOBAL_VAR(department_cd_override)
/datum/computer_file/program/department_order/proc/set_linked_department(datum/job_department/department)
linked_department = department
var/datum/job_department/linked_department_real = SSjob.get_department_type(linked_department)
if (isnull(linked_department_real))
return
// Heads of staff can download
download_access |= linked_department_real.head_of_staff_access
LAZYOR(download_access, linked_department_real.head_of_staff_access)
// Heads of staff + anyone in the dept can run it
use_access |= linked_department_real.head_of_staff_access
use_access |= linked_department_real.department_access
@@ -164,7 +166,7 @@ GLOBAL_VAR(department_cd_override)
if(action == "override_order")
if(isnull(department_order) || !(department_order in SSshuttle.shopping_list))
return TRUE
if(length(download_access & id_card_access) <= 0)
if(LAZYLEN(download_access & id_card_access) <= 0)
computer.physical.balloon_alert(orderer, "requires head of staff access!")
playsound(computer, 'sound/machines/buzz/buzz-sigh.ogg', 30, TRUE)
return TRUE
@@ -71,7 +71,7 @@
if(!computer.can_store_file(F))
return FALSE
var/datum/computer_file/C = F.clone(FALSE)
computer.store_file(C)
computer.store_file(C, usr)
return TRUE
if("PRG_togglesilence")
var/datum/computer_file/program/binary = computer.find_file_by_name(params["name"])
@@ -18,7 +18,7 @@
/// The file under consideration.
var/datum/computer_file/data/ordnance/selected_file
/datum/computer_file/program/scipaper_program/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
/datum/computer_file/program/scipaper_program/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
paper_to_be = new
if(!CONFIG_GET(flag/no_default_techweb_link) && !linked_techweb)
@@ -9,7 +9,7 @@
program_icon = "user-secret"
alert_able = TRUE
/datum/computer_file/program/mafia/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
/datum/computer_file/program/mafia/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
RegisterSignal(SSdcs, COMSIG_MAFIA_GAME_START, PROC_REF(on_game_start))
@@ -23,7 +23,7 @@
desc = "Specialized internal camera protected from the hellish depths of SSWardrobe. \
Yell at coders if you somehow manage to see this"
/datum/computer_file/program/maintenance/camera/on_install()
/datum/computer_file/program/maintenance/camera/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
internal_camera = new(computer)
internal_camera.print_picture_on_snap = FALSE
@@ -17,7 +17,7 @@
. = ..()
RegisterSignal(src, COMSIG_COMPUTER_FILE_DELETE, PROC_REF(on_delete))
/datum/computer_file/program/maintenance/cool_sword/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
/datum/computer_file/program/maintenance/cool_sword/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
RegisterSignal(computer_installing, COMSIG_ITEM_EQUIPPED, PROC_REF(host_equipped))
RegisterSignal(computer_installing, COMSIG_ITEM_DROPPED, PROC_REF(host_dropped))
@@ -1,11 +1,19 @@
/// PDA themes that you can find in maintenance. Once installed by a player, it'll become available to them on future rounds as well.
/datum/computer_file/program/maintenance/theme
filename = "theme"
filedesc = "Theme holder"
extended_desc = "Holds a theme you can add to your Modular PC to set in the Themify application. Makes the application use more space"
size = 2
abstract_type = /datum/computer_file/program/maintenance/theme
///The type of theme we have
var/theme_name
///The Database ID of the theme. It's important that non-abstract types have it set.
var/theme_id
///The icon file for this theme
var/icon_file = PDA_THEMES_PROGRESS_SET
///The icon_state for this theme to show in the progress score tab
var/icon = ""
/datum/computer_file/program/maintenance/theme/New()
. = ..()
@@ -20,34 +28,48 @@
if(!theme_app)
return FALSE
//don't get the same one twice
if(theme_app.imported_themes.Find(theme_name))
if(LAZYFIND(theme_app.imported_themes, theme_name))
return FALSE
return TRUE
///Called post-installation of an application in a computer, after 'computer' var is set.
/datum/computer_file/program/maintenance/theme/on_install()
/datum/computer_file/program/maintenance/theme/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
SHOULD_CALL_PARENT(FALSE)
//add the theme to the computer and increase its size to match
var/datum/computer_file/program/themeify/theme_app = locate() in computer.stored_files
if(theme_app)
theme_app.imported_themes += theme_name
theme_app.size += size
qdel(src)
if(!theme_app)
return
LAZYADD(theme_app.imported_themes, theme_name)
theme_app.size += size
user?.client?.give_award(/datum/award/score/progress/pda_themes, user, theme_id, theme_name)
qdel(src)
/datum/computer_file/program/maintenance/theme/cat
theme_name = PDA_THEME_CAT_NAME
theme_id = PDA_THEME_ID_CAT
icon = "cat"
/datum/computer_file/program/maintenance/theme/lightmode
theme_name = PDA_THEME_LIGHT_MODE_NAME
theme_id = PDA_THEME_ID_LIGHT_MODE
icon = "light_mode"
/datum/computer_file/program/maintenance/theme/spooky
theme_name = PDA_THEME_SPOOKY_NAME
theme_id = PDA_THEME_ID_SPOOKY
icon = "eldritch"
/datum/computer_file/program/maintenance/theme/hacker
theme_name = PDA_THEME_HACKERMAN_NAME
theme_id = PDA_THEME_ID_HACKERMAN
icon = "hacker"
/datum/computer_file/program/maintenance/theme/roulette
theme_name = PDA_THEME_ROULETTE_NAME
theme_id = PDA_THEME_ID_ROULETTE
icon = "roulette"
/datum/computer_file/program/maintenance/theme/alien
theme_name = PDA_THEME_ABDUCTOR_NAME
theme_id = PDA_THEME_ID_ABDUCTOR
icon = "alien"
@@ -34,7 +34,7 @@
var/spam_mode = FALSE
/// An asssociative list of chats we have started, format: chatref -> pda_chat.
var/list/saved_chats = list()
var/list/saved_chats
/// Whose chatlogs we currently have open. If we are in the contacts list, this is null.
var/viewing_messages_of = null
@@ -74,7 +74,7 @@
/datum/computer_file/program/messenger/proc/on_imprint_reset(sender)
SIGNAL_HANDLER
remove_messenger(src)
saved_chats = list()
LAZYNULL(saved_chats)
selected_image = null
viewing_messages_of = null
@@ -117,7 +117,7 @@
data |= photo.picture_name
if(viewing_messages_of in saved_chats)
var/datum/pda_chat/chat = saved_chats[viewing_messages_of]
var/datum/pda_chat/chat = LAZYACCESS(saved_chats, viewing_messages_of)
for(var/datum/pda_message/message as anything in chat.messages)
if(isnull(message.photo_name))
continue
@@ -180,13 +180,13 @@
if("PDA_viewMessages")
if(viewing_messages_of in saved_chats)
var/datum/pda_chat/chat = saved_chats[viewing_messages_of]
var/datum/pda_chat/chat = LAZYACCESS(saved_chats, viewing_messages_of)
chat.unread_messages = 0
viewing_messages_of = params["ref"]
if (viewing_messages_of in saved_chats)
var/datum/pda_chat/chat = saved_chats[viewing_messages_of]
var/datum/pda_chat/chat = LAZYACCESS(saved_chats, viewing_messages_of)
chat.visible_in_recents = TRUE
selected_image = null
@@ -198,7 +198,7 @@
if(!(target in saved_chats))
return FALSE
var/datum/pda_chat/chat = saved_chats[target]
var/datum/pda_chat/chat = LAZYACCESS(saved_chats, target)
chat.visible_in_recents = FALSE
if(viewing_messages_of == target)
viewing_messages_of = null
@@ -208,9 +208,9 @@
var/chat_ref = params["ref"]
if(chat_ref in saved_chats)
saved_chats.Remove(chat_ref)
LAZYREMOVE(saved_chats, chat_ref)
else if(isnull(chat_ref))
saved_chats = list()
LAZYNULL(saved_chats)
viewing_messages_of = null
return TRUE
@@ -240,7 +240,7 @@
if(!(target_chat_ref in saved_chats))
return FALSE
var/datum/pda_chat/chat = saved_chats[target_chat_ref]
var/datum/pda_chat/chat = LAZYACCESS(saved_chats, target_chat_ref)
chat.message_draft = message_draft
@@ -252,7 +252,7 @@
if(!(target_chat_ref in saved_chats))
return FALSE
var/datum/pda_chat/chat = saved_chats[target_chat_ref]
var/datum/pda_chat/chat = LAZYACCESS(saved_chats, target_chat_ref)
chat.unread_messages = 0
return TRUE
@@ -269,14 +269,14 @@
var/target = null
if(target_ref in saved_chats)
target = saved_chats[target_ref]
target = LAZYACCESS(saved_chats, target_ref)
else if(target_ref in GLOB.pda_messengers)
target = GLOB.pda_messengers[target_ref]
else
return FALSE
if(sending_virus)
var/obj/item/computer_disk/virus/disk = computer.inserted_disk
var/obj/item/disk/computer/virus/disk = computer.inserted_disk
if(!istype(disk))
return FALSE
@@ -357,7 +357,7 @@
"job" = computer.saved_job,
"ref" = REF(src)
) : null)
data["saved_chats"] = chats_data
data["saved_chats"] = chats_data || list()
data["messengers"] = messengers
data["sort_by_job"] = sort_by_job
data["alert_silenced"] = alert_silenced
@@ -376,7 +376,7 @@
data["selected_photo_path"] = !isnull(selected_image) ? SSassets.transport.get_asset_url(selected_image) : null
data["on_spam_cooldown"] = !can_send_everyone_message()
var/obj/item/computer_disk/virus/disk = computer.inserted_disk
var/obj/item/disk/computer/virus/disk = computer.inserted_disk
if(istype(disk))
data["virus_attach"] = TRUE
data["sending_virus"] = sending_virus
@@ -412,8 +412,8 @@
for(var/mc in get_messengers())
messenger_targets += mc
for(var/chatref in saved_chats)
var/datum/pda_chat/chat = saved_chats[chatref]
for(var/chatref, data in saved_chats)
var/datum/pda_chat/chat = data
if(!(chat.recipient?.reference in messenger_targets)) // if its in messenger_targets, it's valid
continue
messenger_targets -= chat.recipient.reference
@@ -443,14 +443,14 @@
new_chat.cached_job = job
new_chat.can_reply = FALSE
saved_chats[REF(new_chat)] = new_chat
LAZYSET(saved_chats, REF(new_chat), new_chat)
return new_chat
/// Gets the chat by the recipient, either by their name or messenger ref
/datum/computer_file/program/messenger/proc/find_chat_by_recipient(recipient, fake_user = FALSE)
for(var/chat_ref in saved_chats)
var/datum/pda_chat/chat = saved_chats[chat_ref]
for(var/chat_ref, data in saved_chats)
var/datum/pda_chat/chat = data
if(fake_user && chat.cached_name == recipient)
return chat
else if(chat.recipient?.reference == recipient)
@@ -795,7 +795,7 @@
if("message")
if(!(target_href in saved_chats))
return
quick_reply_prompt(usr, saved_chats[target_href])
quick_reply_prompt(usr, LAZYACCESS(saved_chats, target_href))
if("open")
if(target_href in saved_chats)
@@ -9,7 +9,6 @@
program_icon = "book"
can_run_on_flags = PROGRAM_ALL
circuit_comp_type = /obj/item/circuit_component/mod_program/notepad
var/written_note = "Congratulations on your station upgrading to the new NtOS and Thinktronic based collaboration effort, \
bringing you the best in electronics and software since 2467!\n\
To help with navigation, we have provided the following definitions:\n\
@@ -50,7 +50,7 @@
data["owner_token"] = current_user.pay_token
data["money"] = current_user.account_balance
data["wanted_token"] = wanted_token
data["transaction_list"] = current_user.transaction_history
data["transaction_list"] = current_user.transaction_history || list()
return data
@@ -11,6 +11,8 @@
///The program currently being downloaded.
var/datum/computer_file/program/downloaded_file
///weak ref to the user who began the download
var/datum/weakref/download_user
///Boolean on whether the `downloaded_file` is being downloaded from the Syndicate store,
///in which case it will appear as 'ENCRYPTED' in logs, rather than display file name.
var/hacked_download = FALSE
@@ -35,7 +37,7 @@
ui_header = null
. = ..()
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename)
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename, mob/user)
if(downloaded_file)
return FALSE
@@ -64,6 +66,7 @@
hacked_download = FALSE
downloaded_file = PRG.clone()
download_user = WEAKREF(user)
// If the filesize is 0 (or somehow lower), we instantly download to avoid invalid number issues with stepwise download.
if(downloaded_file.size <= 0)
@@ -76,17 +79,19 @@
downloaded_file = null
download_completion = FALSE
ui_header = null
download_user = null
/datum/computer_file/program/ntnetdownload/proc/complete_file_download()
if(!downloaded_file)
return
generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].")
if(!computer || !computer.store_file(downloaded_file))
if(!computer || !computer.store_file(downloaded_file, download_user?.resolve()))
// The download failed
downloaderror = "I/O ERROR - Unable to save file. Check whether you have enough free space on your hard drive and whether your hard drive is properly connected. If the issue persists contact your system administrator for assistance."
downloaded_file = null
download_completion = FALSE
ui_header = "downloader_finished.gif"
download_user = null
/datum/computer_file/program/ntnetdownload/process_tick(seconds_per_tick)
if(!downloaded_file)
@@ -117,7 +122,7 @@
switch(action)
if("PRG_downloadfile")
if(!downloaded_file)
begin_file_download(params["filename"])
begin_file_download(params["filename"], usr)
return TRUE
if("PRG_reseterror")
if(downloaderror)
@@ -27,6 +27,8 @@
scan_data["raptor_speed"] = my_raptor.speed + intent_mod?.multiplicative_slowdown
scan_data["raptor_color"] = my_raptor.name
scan_data["raptor_gender"] = my_raptor.gender
scan_data["raptor_growth"] = my_raptor.growth_progress
scan_data["can_grow"] = my_raptor.growth_stage != RAPTOR_ADULT
scan_data["raptor_description"] = my_raptor.raptor_color.description
var/happiness_percentage = my_raptor.ai_controller?.blackboard[BB_BASIC_HAPPINESS]
@@ -38,7 +38,7 @@
filename = "syndeye"
filedesc = "SyndEye"
extended_desc = "This program allows for illegal access to security camera networks."
download_access = list()
download_access = null
can_run_on_flags = PROGRAM_ALL
program_flags = PROGRAM_ON_SYNDINET_STORE | PROGRAM_UNIQUE_COPY
@@ -69,7 +69,7 @@
)
spying = TRUE
/datum/computer_file/program/secureye/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
/datum/computer_file/program/secureye/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
// Map name has to start and end with an A-Z character,
// and definitely NOT with a square bracket or even a number.
@@ -174,7 +174,7 @@
CRASH("[src] was able to track [target] through /datum/trackable, but was not on a visible turf to cameras.")
for(var/obj/machinery/camera/cameras as anything in target_camerachunk.cameras[target.z])
// We need to find a particular camera that can see this turf
if(!(target_turf in cameras.can_see()))
if(length(cameras.can_see() & list(target_turf)))
continue
var/new_camera = WEAKREF(cameras)
if(camera_ref == new_camera)
@@ -21,7 +21,7 @@
/// Sequence var for the id cache
var/id_cache_seq = 1
/datum/computer_file/program/science/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
/datum/computer_file/program/science/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research)
CONNECT_TO_RND_SERVER_ROUNDSTART(stored_research, computer)
@@ -87,16 +87,8 @@
var/list/exp_to_process = stored_research.available_experiments.Copy()
for (var/comp_experi in stored_research.completed_experiments)
exp_to_process += stored_research.completed_experiments[comp_experi]
for (var/process_experi in exp_to_process)
var/datum/experiment/unf_experi = process_experi
data["experiments"][unf_experi.type] = list(
"name" = unf_experi.name,
"description" = unf_experi.description,
"tag" = unf_experi.exp_tag,
"progress" = unf_experi.check_progress(),
"completed" = unf_experi.completed,
"performance_hint" = unf_experi.performance_hint
)
for (var/datum/experiment/unf_experi as anything in exp_to_process)
data["experiments"][unf_experi.type] = unf_experi.to_ui_data()
return data
/datum/computer_file/program/science/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
@@ -10,14 +10,17 @@
program_icon = "paint-roller"
///List of all themes imported from maintenance apps.
var/list/imported_themes = list()
var/list/imported_themes
/datum/computer_file/program/themeify/ui_data(mob/user)
var/list/data = list()
if(computer.obj_flags & EMAGGED)
data["themes"] += list(list("theme_name" = PDA_THEME_SYNDICATE_NAME, "theme_ref" = GLOB.pda_name_to_theme[PDA_THEME_SYNDICATE_NAME]))
for(var/theme_key in GLOB.default_pda_themes + imported_themes)
var/list/available_themes = GLOB.default_pda_themes.Copy()
if(imported_themes)
available_themes += imported_themes
for(var/theme_key in available_themes)
data["themes"] += list(list("theme_name" = theme_key, "theme_ref" = GLOB.pda_name_to_theme[theme_key]))
return data
@@ -29,7 +32,7 @@
var/selected_theme = params["selected_theme"]
if( \
!GLOB.default_pda_themes.Find(selected_theme) && \
!imported_themes.Find(selected_theme) && \
!LAZYFIND(imported_themes, selected_theme) && \
!(computer.obj_flags & EMAGGED) \
)
return FALSE
@@ -121,7 +121,7 @@ GLOBAL_LIST_EMPTY(virtual_pets_list)
///cooldown till we can alter our pet's appearance again
COOLDOWN_DECLARE(alter_appearance_cooldown)
/datum/computer_file/program/virtual_pet/on_install()
/datum/computer_file/program/virtual_pet/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
. = ..()
profile_picture = getFlatIcon(image(icon = 'icons/ui/virtualpet/pet_state.dmi', icon_state = "pet_preview"))
GLOB.virtual_pets_list += src