mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-16 09:39:22 +01:00
Revival of https://github.com/tgstation/tgstation/pull/86482, which is even more doable now that we have rustg iconforge generation. What this PR does: - Sets up every single GAGS icon in the game to have their own preview icon autogenerated during compile. This is configurable to not run during live. The icons are created in `icons/map_icons/..` - This also has the side effect of providing accurate GAGS icons for things like the loadout menu. No more having to create your own previews.  <details><summary>Mappers rejoice!</summary>   </details> <details><summary>Uses iconforge so it does not take up much time during init</summary>  </details> --- this still applies: Note for Spriters: After you've assigned the correct values to vars, you must run the game through init on your local machine and commit the changes to the map icon dmi files. Unit tests should catch all cases of forgetting to assign the correct vars, or not running through init. Note for Server Operators: In order to not generate these icons on live I've added a new config entry which should be disabled on live called GENERATE_ASSETS_IN_INIT in the config.txt No more error icons in SDMM and loadout. 🆑 refactor: preview icons for greyscale items are now automatically generated, meaning you can see GAGS as they actually appear ingame while mapping or viewing the loadout menu. /🆑 --------- Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
453 lines
16 KiB
Plaintext
453 lines
16 KiB
Plaintext
/obj/item/modular_computer/pda
|
|
name = "pda"
|
|
icon = 'icons/map_icons/items/pda.dmi'
|
|
icon_state = "/obj/item/modular_computer/pda"
|
|
post_init_icon_state = "pda"
|
|
worn_icon_state = "nothing"
|
|
base_icon_state = "tablet"
|
|
greyscale_config = /datum/greyscale_config/tablet
|
|
greyscale_colors = "#999875#a92323"
|
|
|
|
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
|
|
inhand_icon_state = "electronic"
|
|
|
|
overlays_icon = 'icons/obj/devices/modular_pda.dmi'
|
|
|
|
steel_sheet_cost = 2
|
|
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT * 3, /datum/material/glass=SMALL_MATERIAL_AMOUNT, /datum/material/plastic=SMALL_MATERIAL_AMOUNT)
|
|
interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_ALLOW_USER_LOCATION | INTERACT_ATOM_IGNORE_MOBILITY
|
|
|
|
icon_state_menu = "menu"
|
|
max_capacity = 64
|
|
allow_chunky = TRUE
|
|
hardware_flag = PROGRAM_PDA
|
|
max_idle_programs = 2
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
|
|
has_light = TRUE //LED flashlight!
|
|
comp_light_luminosity = 2.3 //this is what old PDAs were set to
|
|
looping_sound = FALSE
|
|
|
|
shell_capacity = SHELL_CAPACITY_SMALL
|
|
action_slots = ALL
|
|
|
|
///The item currently inserted into the PDA, starts with a pen.
|
|
var/obj/item/inserted_item = /obj/item/pen
|
|
|
|
///Whether the PDA should have 'pda_programs' apps installed on Initialize.
|
|
var/has_pda_programs = TRUE
|
|
///Static list of default PDA apps to install on Initialize.
|
|
var/static/list/datum/computer_file/pda_programs = list(
|
|
/datum/computer_file/program/messenger,
|
|
/datum/computer_file/program/nt_pay,
|
|
/datum/computer_file/program/notepad,
|
|
/datum/computer_file/program/crew_manifest,
|
|
// BUBBER EDIT ADDITION START
|
|
/datum/computer_file/program/maintenance/camera, // Adds camera to all base tablets
|
|
/datum/computer_file/program/crew_self_serve, // Crew Self Serve
|
|
// BUBBER EDIT ADDITION END
|
|
)
|
|
///List of items that can be stored in a PDA
|
|
var/static/list/contained_item = list(
|
|
/obj/item/pen,
|
|
/obj/item/toy/crayon,
|
|
/obj/item/lipstick,
|
|
/obj/item/flashlight/pen,
|
|
/obj/item/reagent_containers/hypospray/medipen,
|
|
/obj/item/cigarette,
|
|
)
|
|
|
|
/obj/item/modular_computer/pda/Initialize(mapload)
|
|
. = ..()
|
|
if(inserted_item)
|
|
inserted_item = new inserted_item(src)
|
|
|
|
/obj/item/modular_computer/pda/Destroy()
|
|
if(istype(inserted_item))
|
|
QDEL_NULL(inserted_item)
|
|
return ..()
|
|
|
|
/obj/item/modular_computer/pda/install_default_programs()
|
|
var/list/apps_to_download = list()
|
|
if(has_pda_programs)
|
|
apps_to_download += default_programs + pda_programs
|
|
apps_to_download += starting_programs
|
|
|
|
for(var/programs as anything in apps_to_download)
|
|
var/datum/computer_file/program/program_type = new programs
|
|
store_file(program_type)
|
|
|
|
/obj/item/modular_computer/pda/update_overlays()
|
|
. = ..()
|
|
if(computer_id_slot)
|
|
. += mutable_appearance(overlays_icon, "id_overlay")
|
|
if(light_on)
|
|
. += mutable_appearance(overlays_icon, "light_overlay")
|
|
if(inserted_pai)
|
|
. += mutable_appearance(overlays_icon, "pai_inserted")
|
|
|
|
/obj/item/modular_computer/pda/interact(mob/user)
|
|
. = ..()
|
|
if(HAS_TRAIT(src, TRAIT_PDA_MESSAGE_MENU_RIGGED))
|
|
explode(user, from_message_menu = TRUE)
|
|
|
|
/obj/item/modular_computer/pda/attack_self(mob/user)
|
|
// bypass literacy checks to access syndicate uplink
|
|
var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink)
|
|
if(hidden_uplink?.owner && HAS_TRAIT(user, TRAIT_ILLITERATE))
|
|
if(hidden_uplink.owner != user.key)
|
|
return ..()
|
|
|
|
hidden_uplink.locked = FALSE
|
|
hidden_uplink.interact(null, user)
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
return ..()
|
|
|
|
/obj/item/modular_computer/pda/pre_attack(atom/target, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
if(!inserted_disk || !ismachinery(target))
|
|
return ..()
|
|
|
|
var/obj/machinery/target_machine = target
|
|
if(!target_machine.panel_open && !istype(target, /obj/machinery/computer))
|
|
return ..()
|
|
|
|
if(!istype(inserted_disk, /obj/item/computer_disk/virus/clown))
|
|
return ..()
|
|
var/obj/item/computer_disk/virus/clown/installed_cartridge = inserted_disk
|
|
if(!installed_cartridge.charges)
|
|
to_chat(user, span_notice("Out of virus charges."))
|
|
return ..()
|
|
|
|
to_chat(user, span_notice("You upload the virus to [target]!"))
|
|
var/sig_list = list(COMSIG_ATOM_ATTACK_HAND)
|
|
if(istype(target,/obj/machinery/door/airlock))
|
|
sig_list = list(COMSIG_AIRLOCK_OPEN, COMSIG_AIRLOCK_CLOSE)
|
|
|
|
installed_cartridge.charges--
|
|
target.AddComponent(
|
|
/datum/component/sound_player, \
|
|
uses = rand(15,20), \
|
|
signal_list = sig_list, \
|
|
)
|
|
return TRUE
|
|
|
|
/obj/item/modular_computer/pda/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
|
. = ..()
|
|
|
|
if(inserted_item)
|
|
context[SCREENTIP_CONTEXT_CTRL_LMB] = "Remove [inserted_item]"
|
|
. = CONTEXTUAL_SCREENTIP_SET
|
|
else if(istype(held_item) && is_type_in_list(held_item, contained_item))
|
|
context[SCREENTIP_CONTEXT_LMB] = "Insert [held_item]"
|
|
. = CONTEXTUAL_SCREENTIP_SET
|
|
|
|
return . || NONE
|
|
|
|
/obj/item/modular_computer/pda/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
|
|
if(iscash(interacting_with))
|
|
return money_act(user,interacting_with)
|
|
return NONE
|
|
|
|
/obj/item/modular_computer/pda/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
|
. = ..()
|
|
if(.)
|
|
return .
|
|
if(!is_type_in_list(tool, contained_item))
|
|
return NONE
|
|
if(tool.w_class >= WEIGHT_CLASS_SMALL) // Anything equal to or larger than small won't work
|
|
user.balloon_alert(user, "too big!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(!user.transferItemToLoc(tool, src))
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(inserted_item)
|
|
swap_pen(user, tool)
|
|
else
|
|
balloon_alert(user, "inserted [tool]")
|
|
inserted_item = tool
|
|
playsound(src, 'sound/machines/pda_button/pda_button1.ogg', 50, TRUE)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
|
|
/obj/item/modular_computer/pda/item_ctrl_click(mob/user)
|
|
remove_pen(user)
|
|
return CLICK_ACTION_SUCCESS
|
|
|
|
///Finds how hard it is to send a virus to this tablet, checking all programs downloaded.
|
|
/obj/item/modular_computer/pda/proc/get_detomatix_difficulty()
|
|
var/detomatix_difficulty
|
|
|
|
for(var/datum/computer_file/program/downloaded_apps in stored_files)
|
|
detomatix_difficulty += downloaded_apps.detomatix_resistance
|
|
|
|
return detomatix_difficulty
|
|
|
|
/obj/item/modular_computer/pda/proc/remove_pen(mob/user)
|
|
|
|
if(issilicon(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH | NEED_DEXTERITY)) //TK doesn't work even with this removed but here for readability
|
|
return
|
|
|
|
if(inserted_item)
|
|
balloon_alert(user, "removed [inserted_item]")
|
|
user.put_in_hands(inserted_item)
|
|
inserted_item = null
|
|
update_appearance()
|
|
playsound(src, 'sound/machines/pda_button/pda_button2.ogg', 50, TRUE)
|
|
|
|
/obj/item/modular_computer/pda/proc/swap_pen(mob/user, obj/item/tool)
|
|
if(inserted_item)
|
|
balloon_alert(user, "swapped pens")
|
|
user.put_in_hands(inserted_item)
|
|
inserted_item = tool
|
|
update_appearance()
|
|
playsound(src, 'sound/machines/pda_button/pda_button1.ogg', 50, TRUE)
|
|
|
|
/obj/item/modular_computer/pda/proc/explode(mob/target, mob/bomber, from_message_menu = FALSE)
|
|
var/turf/current_turf = get_turf(src)
|
|
|
|
if(from_message_menu)
|
|
log_bomber(null, null, target, "'s tablet exploded as [target.p_they()] tried to open their tablet message menu because of a recent tablet bomb.")
|
|
else
|
|
log_bomber(bomber, "successfully tablet-bombed", target, "as [target.p_they()] tried to reply to a rigged tablet message [bomber && !is_special_character(bomber) ? "(SENT BY NON-ANTAG)" : ""]")
|
|
|
|
if (ismob(loc))
|
|
var/mob/loc_mob = loc
|
|
loc_mob.show_message(
|
|
msg = span_userdanger("Your [src] explodes!"),
|
|
type = MSG_VISUAL,
|
|
alt_msg = span_warning("You hear a loud *pop*!"),
|
|
alt_type = MSG_AUDIBLE,
|
|
)
|
|
else
|
|
visible_message(span_danger("[src] explodes!"), span_warning("You hear a loud *pop*!"))
|
|
|
|
target.client?.give_award(/datum/award/achievement/misc/clickbait, target)
|
|
|
|
if(current_turf)
|
|
current_turf.hotspot_expose(700,125)
|
|
if(istype(inserted_disk, /obj/item/computer_disk/virus/detomatix))
|
|
explosion(src, devastation_range = -1, heavy_impact_range = 1, light_impact_range = 3, flash_range = 4)
|
|
else
|
|
explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2, flash_range = 3)
|
|
qdel(src)
|
|
|
|
|
|
/**
|
|
* A simple helper proc that applies the client's ringtone prefs to the tablet's messenger app,
|
|
* if it has one.
|
|
*
|
|
* Arguments:
|
|
* * owner_client - The client whose prefs we'll use to set the ringtone of this PDA.
|
|
*/
|
|
/obj/item/modular_computer/pda/proc/update_pda_prefs(client/owner_client)
|
|
if(!owner_client)
|
|
return
|
|
|
|
var/new_ringtone = owner_client.prefs.read_preference(/datum/preference/text/pda_ringtone)
|
|
if(new_ringtone && (new_ringtone != MESSENGER_RINGTONE_DEFAULT))
|
|
update_ringtone(new_ringtone)
|
|
|
|
var/new_theme = owner_client.prefs.read_preference(/datum/preference/choiced/pda_theme)
|
|
if(new_theme)
|
|
device_theme = GLOB.pda_name_to_theme[new_theme]
|
|
|
|
/// A simple proc to set the ringtone from a pda.
|
|
/obj/item/modular_computer/pda/proc/update_ringtone(new_ringtone)
|
|
if(!istext(new_ringtone))
|
|
return
|
|
var/datum/computer_file/program/messenger/messenger_app = locate() in stored_files
|
|
if(messenger_app)
|
|
messenger_app.ringtone = new_ringtone
|
|
|
|
/**
|
|
* Nuclear PDA
|
|
*
|
|
* PDA that doesn't come with the default apps but has Fission360
|
|
* Resistant to emags, these are given to nukies for disk pinpointer stuff.
|
|
*/
|
|
/obj/item/modular_computer/pda/nukeops
|
|
name = "nuclear pda"
|
|
icon_state = "/obj/item/modular_computer/pda/nukeops"
|
|
device_theme = PDA_THEME_SYNDICATE
|
|
comp_light_luminosity = 6.3 //matching a flashlight
|
|
light_color = COLOR_RED
|
|
greyscale_config = /datum/greyscale_config/tablet/stripe_thick
|
|
greyscale_colors = "#a80001#5C070F#000000"
|
|
long_ranged = TRUE
|
|
starting_programs = list(
|
|
/datum/computer_file/program/radar/fission360,
|
|
)
|
|
|
|
/obj/item/modular_computer/pda/nukeops/Initialize(mapload)
|
|
. = ..()
|
|
emag_act(forced = TRUE)
|
|
var/datum/computer_file/program/messenger/msg = locate() in stored_files
|
|
if(msg)
|
|
msg.invisible = TRUE
|
|
|
|
/obj/item/modular_computer/pda/syndicate_contract_uplink
|
|
name = "contractor tablet"
|
|
icon_state = "/obj/item/modular_computer/pda/syndicate_contract_uplink"
|
|
icon_state_menu = "contractor-assign"
|
|
device_theme = PDA_THEME_SYNDICATE
|
|
comp_light_luminosity = 6.3
|
|
has_pda_programs = FALSE
|
|
greyscale_config = /datum/greyscale_config/tablet/stripe_double
|
|
greyscale_colors = "#696969#000000#FFA500"
|
|
|
|
starting_programs = list(
|
|
/datum/computer_file/program/contract_uplink,
|
|
/datum/computer_file/program/secureye/syndicate,
|
|
)
|
|
|
|
/**
|
|
* Silicon PDA
|
|
*
|
|
* PDAs that are built-in to Silicons and should not exist at any point without being inside of one.
|
|
*/
|
|
/obj/item/modular_computer/pda/silicon
|
|
name = "modular interface"
|
|
icon = 'icons/obj/devices/modular_pda.dmi'
|
|
icon_state = "tablet-silicon"
|
|
post_init_icon_state = null
|
|
base_icon_state = "tablet-silicon"
|
|
greyscale_config = null
|
|
greyscale_colors = null
|
|
|
|
has_light = FALSE //tablet light button actually enables/disables the borg lamp
|
|
comp_light_luminosity = 0
|
|
inserted_item = null
|
|
has_pda_programs = FALSE
|
|
starting_programs = list(
|
|
/datum/computer_file/program/messenger,
|
|
)
|
|
|
|
///Ref to the RoboTact app. Important enough to borgs to deserve a ref.
|
|
var/datum/computer_file/program/robotact/robotact
|
|
///IC log that borgs can view in their personal management app
|
|
var/list/borglog = list()
|
|
///Ref to the silicon we're installed in. Set by the silicon itself during its creation.
|
|
var/mob/living/silicon/silicon_owner
|
|
|
|
/obj/item/modular_computer/pda/silicon/pai
|
|
starting_programs = list(
|
|
/datum/computer_file/program/messenger,
|
|
/datum/computer_file/program/chatclient,
|
|
)
|
|
|
|
/obj/item/modular_computer/pda/silicon/cyborg
|
|
starting_programs = list(
|
|
/datum/computer_file/program/filemanager,
|
|
/datum/computer_file/program/robotact,
|
|
/datum/computer_file/program/crew_manifest, // SKYRAT EDIT ADDITION - Manifests for borgs
|
|
/datum/computer_file/program/messenger, // SKYRAT EDIT ADDITION - Messenger for borgs
|
|
/datum/computer_file/program/borg_monitor,
|
|
/datum/computer_file/program/atmosscan,
|
|
/datum/computer_file/program/crew_manifest,
|
|
)
|
|
|
|
/obj/item/modular_computer/pda/silicon/Initialize(mapload)
|
|
. = ..()
|
|
vis_flags |= VIS_INHERIT_ID
|
|
silicon_owner = loc
|
|
if(!istype(silicon_owner))
|
|
silicon_owner = null
|
|
stack_trace("[type] initialized outside of a silicon, deleting.")
|
|
return INITIALIZE_HINT_QDEL
|
|
|
|
/obj/item/modular_computer/pda/silicon/Destroy()
|
|
silicon_owner = null
|
|
return ..()
|
|
|
|
///Silicons don't have the tools (or hands) to make circuits setups with their own PDAs.
|
|
/obj/item/modular_computer/pda/silicon/add_shell_component(capacity)
|
|
return
|
|
|
|
/obj/item/modular_computer/pda/silicon/turn_on(mob/user, open_ui = FALSE)
|
|
if(silicon_owner?.stat != DEAD)
|
|
return ..()
|
|
return FALSE
|
|
|
|
/obj/item/modular_computer/pda/silicon/get_ntnet_status()
|
|
//No borg found
|
|
if(!silicon_owner)
|
|
return FALSE
|
|
// no AIs/pAIs
|
|
var/mob/living/silicon/robot/cyborg_check = silicon_owner
|
|
if(!istype(cyborg_check))
|
|
return ..()
|
|
//lockdown restricts borg networking
|
|
if(cyborg_check.lockcharge)
|
|
return FALSE
|
|
//borg cell dying restricts borg networking
|
|
if(!cyborg_check.cell || cyborg_check.cell.charge == 0)
|
|
return FALSE
|
|
|
|
return ..()
|
|
|
|
/**
|
|
* Returns a ref to the RoboTact app, creating the app if need be.
|
|
*
|
|
* The RoboTact app is important for borgs, and so should always be available.
|
|
* This proc will look for it in the tablet's robotact var, then check the
|
|
* hard drive if the robotact var is unset, and finally attempt to create a new
|
|
* copy if the hard drive does not contain the app. If the hard drive rejects
|
|
* the new copy (such as due to lack of space), the proc will crash with an error.
|
|
* RoboTact is supposed to be undeletable, so these will create runtime messages.
|
|
*/
|
|
/obj/item/modular_computer/pda/silicon/proc/get_robotact()
|
|
if(robotact)
|
|
return robotact
|
|
robotact = find_file_by_name("robotact")
|
|
if(robotact)
|
|
return robotact
|
|
stack_trace("Cyborg [silicon_owner] ( [silicon_owner.type] ) was somehow missing their self-manage app in their tablet. A new copy has been created.")
|
|
robotact = new(src)
|
|
if(store_file(robotact))
|
|
return robotact
|
|
qdel(robotact)
|
|
robotact = null
|
|
CRASH("Cyborg [silicon_owner]'s tablet hard drive rejected receiving a new copy of the self-manage app. To fix, check the hard drive's space remaining. Please make a bug report about this.")
|
|
|
|
//Makes the light settings reflect the borg's headlamp settings
|
|
/obj/item/modular_computer/pda/silicon/cyborg/ui_data(mob/user)
|
|
. = ..()
|
|
.["has_light"] = TRUE
|
|
if(iscyborg(silicon_owner))
|
|
var/mob/living/silicon/robot/robo = silicon_owner
|
|
.["light_on"] = robo.lamp_enabled
|
|
.["comp_light_color"] = robo.lamp_color
|
|
|
|
//Makes the flashlight button affect the borg rather than the tablet
|
|
/obj/item/modular_computer/pda/silicon/toggle_flashlight(mob/user)
|
|
if(!silicon_owner || QDELETED(silicon_owner))
|
|
return FALSE
|
|
if(iscyborg(silicon_owner))
|
|
var/mob/living/silicon/robot/robo = silicon_owner
|
|
robo.toggle_headlamp()
|
|
return TRUE
|
|
|
|
//Makes the flashlight color setting affect the borg rather than the tablet
|
|
/obj/item/modular_computer/pda/silicon/set_flashlight_color(color)
|
|
if(!silicon_owner || QDELETED(silicon_owner) || !color)
|
|
return FALSE
|
|
if(iscyborg(silicon_owner))
|
|
var/mob/living/silicon/robot/robo = silicon_owner
|
|
robo.lamp_color = color
|
|
robo.toggle_headlamp(FALSE, TRUE)
|
|
return TRUE
|
|
|
|
/obj/item/modular_computer/pda/silicon/ui_state(mob/user)
|
|
return GLOB.deep_inventory_state
|
|
|
|
/obj/item/modular_computer/pda/silicon/cyborg/syndicate
|
|
icon_state = "tablet-silicon-syndicate"
|
|
device_theme = PDA_THEME_SYNDICATE
|
|
|
|
/obj/item/modular_computer/pda/silicon/cyborg/syndicate/Initialize(mapload)
|
|
. = ..()
|
|
if(iscyborg(silicon_owner))
|
|
var/mob/living/silicon/robot/robo = silicon_owner
|
|
robo.lamp_color = COLOR_RED //Syndicate likes it red
|