Files
Bubberstation/code/modules/modular_computers/computers/item/tablet.dm
John Willard cb8ca472a1 Re-adds the clown's PDA virus honking (#71035)
## About The Pull Request

Re-adds the Clown's virus disk's ability to make machines, airlocks, and
computers honk, which was removed in the transition from PDA to modular
computer.

Fun fact: This was broken for a long time, I had fixed it in
https://github.com/tgstation/tgstation/pull/64443 before it got
accidentally wiped off the face of the earth.

To anyone who isn't aware:
- Clown's virus disk has 5 charges
- You can use these charges to install viruses in computers, airlocks,
and machines if they're screwed open (computers dont need to)
- This will make them honk when used.
- You can get charges back by slipping people with the PDA while the
virus disk is installed in it (which it is by default)
- The max charges you can get at once is 5.

## Why It's Good For The Game

A feature that was lost in the PDA to modular computer transition, now
re-added. It's a cool feature and I personally would use it if I played
bad jobs.

Things actually working is a 🛩️

## Changelog

🆑
fix: Clown PDA virus disk can once again be installed in machines,
computers, and airlocks.
/🆑
2022-11-16 08:39:16 +01:00

429 lines
14 KiB
Plaintext

/obj/item/modular_computer/tablet //Its called tablet for theme of 90ies but actually its a "big smartphone" sized
name = "tablet computer"
icon = 'icons/obj/modular_tablet.dmi'
icon_state = "tablet-red"
icon_state_unpowered = "tablet-red"
icon_state_powered = "tablet-red"
icon_state_menu = "menu"
inhand_icon_state = "electronic"
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
base_icon_state = "tablet"
worn_icon_state = "tablet"
hardware_flag = PROGRAM_TABLET
max_hardware_size = 1
max_idle_programs = 2
w_class = WEIGHT_CLASS_SMALL
max_bays = 3
steel_sheet_cost = 2
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
has_light = TRUE //LED flashlight!
comp_light_luminosity = 2.3 //Same as the PDA
looping_sound = FALSE
custom_materials = list(/datum/material/iron=300, /datum/material/glass=100, /datum/material/plastic=100)
interaction_flags_atom = INTERACT_ATOM_ALLOW_USER_LOCATION
var/has_variants = TRUE
var/finish_color = null
///The item currently inserted into the PDA, starts with a pen.
var/obj/item/inserted_item = /obj/item/pen
///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/clothing/mask/cigarette,
)
/obj/item/modular_computer/tablet/Initialize(mapload)
. = ..()
if(inserted_item)
inserted_item = new inserted_item(src)
/obj/item/modular_computer/tablet/Destroy()
if(istype(inserted_item))
QDEL_NULL(inserted_item)
return ..()
/obj/item/modular_computer/tablet/update_icon_state()
if(has_variants && !bypass_state)
if(!finish_color)
finish_color = pick("red", "blue", "brown", "green", "black")
icon_state = icon_state_powered = icon_state_unpowered = "[base_icon_state]-[finish_color]"
return ..()
/obj/item/modular_computer/tablet/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/tablet/pre_attack(atom/target, mob/living/user, params)
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/tablet/interact(mob/user)
. = ..()
if(HAS_TRAIT(src, TRAIT_PDA_MESSAGE_MENU_RIGGED))
explode(usr, from_message_menu = TRUE)
/obj/item/modular_computer/tablet/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/tablet/attackby(obj/item/W, mob/user)
. = ..()
if(is_type_in_list(W, contained_item))
if(W.w_class >= WEIGHT_CLASS_SMALL) // Anything equal to or larger than small won't work
user.balloon_alert(user, "too big!")
return
if(inserted_item)
balloon_alert(user, "no room!")
else
if(!user.transferItemToLoc(W, src))
return
balloon_alert(user, "inserted [W]")
inserted_item = W
playsound(src, 'sound/machines/pda_button1.ogg', 50, TRUE)
/obj/item/modular_computer/tablet/AltClick(mob/user)
. = ..()
if(.)
return
remove_pen(user)
/obj/item/modular_computer/tablet/CtrlClick(mob/user)
. = ..()
if(.)
return
remove_pen(user)
///Finds how hard it is to send a virus to this tablet, checking all programs downloaded.
/obj/item/modular_computer/tablet/proc/get_detomatix_difficulty()
var/detomatix_difficulty
for(var/datum/computer_file/program/downloaded_apps as anything in stored_files)
detomatix_difficulty += downloaded_apps.detomatix_resistance
return detomatix_difficulty
/obj/item/modular_computer/tablet/proc/tab_no_detonate()
SIGNAL_HANDLER
return COMPONENT_TABLET_NO_DETONATE
/obj/item/modular_computer/tablet/proc/remove_pen(mob/user)
if(issilicon(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE)) //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_button2.ogg', 50, TRUE)
else
balloon_alert(user, "nothing to remove!")
// Tablet 'splosion..
/obj/item/modular_computer/tablet/proc/explode(mob/target, mob/bomber, from_message_menu = FALSE)
var/turf/T = 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/M = loc
M.show_message(span_userdanger("Your [src] explodes!"), MSG_VISUAL, span_warning("You hear a loud *pop*!"), 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(T)
T.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:
* * ringtone_client - The client whose prefs we'll use to set the ringtone of this PDA.
*/
/obj/item/modular_computer/tablet/proc/update_ringtone(client/ringtone_client)
if(!ringtone_client)
return
var/new_ringtone = ringtone_client?.prefs?.read_preference(/datum/preference/text/pda_ringtone)
if(!new_ringtone || new_ringtone == MESSENGER_RINGTONE_DEFAULT)
return
for(var/datum/computer_file/program/messenger/messenger_app in stored_files)
messenger_app.ringtone = new_ringtone
// SUBTYPES
/obj/item/modular_computer/tablet/syndicate_contract_uplink
name = "contractor tablet"
icon = 'icons/obj/contractor_tablet.dmi'
icon_state = "tablet"
icon_state_unpowered = "tablet"
icon_state_powered = "tablet"
icon_state_menu = "assign"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
comp_light_luminosity = 6.3
has_variants = FALSE
/// Given to Nuke Ops members.
/obj/item/modular_computer/tablet/nukeops
icon_state = "tablet-syndicate"
icon_state_powered = "tablet-syndicate"
icon_state_unpowered = "tablet-syndicate"
comp_light_luminosity = 6.3
has_variants = FALSE
device_theme = "syndicate"
light_color = COLOR_RED
/obj/item/modular_computer/tablet/nukeops/emag_act(mob/user)
if(!enabled)
to_chat(user, span_warning("You'd need to turn the [src] on first."))
return FALSE
to_chat(user, span_notice("You swipe \the [src]. It's screen briefly shows a message reading \"MEMORY CODE INJECTION DETECTED AND SUCCESSFULLY QUARANTINED\"."))
return FALSE
/// Borg Built-in tablet interface
/obj/item/modular_computer/tablet/integrated
name = "modular interface"
icon_state = "tablet-silicon"
icon_state_powered = "tablet-silicon"
icon_state_unpowered = "tablet-silicon"
base_icon_state = "tablet-silicon"
has_light = FALSE //tablet light button actually enables/disables the borg lamp
comp_light_luminosity = 0
has_variants = FALSE
inserted_item = null
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/tablet/integrated/cyborg
starting_programs = list(
/datum/computer_file/program/computerconfig,
/datum/computer_file/program/filemanager,
/datum/computer_file/program/robotact,
)
/obj/item/modular_computer/tablet/integrated/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/tablet/integrated/install_default_programs()
for(var/programs in starting_programs)
var/datum/computer_file/program/program_type = new programs
store_file(program_type)
/obj/item/modular_computer/tablet/integrated/Destroy()
silicon_owner = null
return ..()
/obj/item/modular_computer/tablet/integrated/turn_on(mob/user, open_ui = FALSE)
if(silicon_owner?.stat != DEAD)
return ..()
return FALSE
/obj/item/modular_computer/tablet/integrated/get_ntnet_status(specific_action = 0)
//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/tablet/integrated/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 recieving 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/tablet/integrated/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/tablet/integrated/toggle_flashlight()
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/tablet/integrated/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/tablet/integrated/ui_state(mob/user)
return GLOB.reverse_contained_state
/obj/item/modular_computer/tablet/integrated/syndicate
icon_state = "tablet-silicon-syndicate"
icon_state_powered = "tablet-silicon-syndicate"
icon_state_unpowered = "tablet-silicon-syndicate"
device_theme = "syndicate"
/obj/item/modular_computer/tablet/integrated/syndicate/Initialize(mapload)
. = ..()
if(iscyborg(silicon_owner))
var/mob/living/silicon/robot/robo = silicon_owner
robo.lamp_color = COLOR_RED //Syndicate likes it red
// Round start tablets
/obj/item/modular_computer/tablet/pda
icon = 'icons/obj/modular_pda.dmi'
icon_state = "pda"
worn_icon_state = "pda"
greyscale_config = /datum/greyscale_config/tablet
greyscale_colors = "#999875#a92323"
max_capacity = 64
bypass_state = TRUE
allow_chunky = 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,
)
/obj/item/modular_computer/tablet/pda/install_default_programs()
for(var/programs as anything in (default_programs + pda_programs + starting_programs))
var/datum/computer_file/program/program_type = new programs
store_file(program_type)
/obj/item/modular_computer/tablet/pda/update_overlays()
. = ..()
var/obj/item/computer_hardware/card_slot/card = all_components[MC_CARD]
if(card?.stored_card)
. += mutable_appearance(initial(icon), "id_overlay")
if(light_on)
. += mutable_appearance(initial(icon), "light_overlay")
/obj/item/modular_computer/tablet/pda/attack_ai(mob/user)
to_chat(user, span_notice("It doesn't feel right to snoop around like that..."))
return // we don't want ais or cyborgs using a private role tablet
/obj/item/modular_computer/tablet/pda/Initialize(mapload)
. = ..()
install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer))
install_component(new /obj/item/computer_hardware/card_slot)