mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 10:12:45 +00:00
Hacktool (#1607)
* Adds hacking tool. In normal mode a hacking tool acts and functions just like any multitool. Use a screwdriver to toggle between normal and hacking mode. Hacking attempts will take 20 +(0 to 20) seconds (triangular distribution, averages at +10 seconds). Once an airlock has been successfully hacked the user will have full access to the door operation interface normally restricted to silicons. A hacking tool will remember the last 6 to 8 hacked airlocks. No time is needed to again hack remembered airlocks. Once the limit has been reached the least recently accessed airlock is forgotten. Hacking a remembered airlock will update the last accessed time. Also adds a basic observer/listener pattern implementation to, for example, make it easier to catch when objects have been destroyed and clear references. * Corrects and adds more sanity checking. * Adds hacktool to uplink devices
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
|
||||
#define isanimal(A) istype(A, /mob/living/simple_animal)
|
||||
|
||||
#define isairlock(A) istype(A, /obj/machinery/door/airlock)
|
||||
|
||||
#define isbrain(A) istype(A, /mob/living/carbon/brain)
|
||||
|
||||
#define iscarbon(A) istype(A, /mob/living/carbon)
|
||||
|
||||
@@ -1,87 +1,87 @@
|
||||
/**
|
||||
* Startup hook.
|
||||
* Called in world.dm when the server starts.
|
||||
*/
|
||||
/hook/startup
|
||||
|
||||
/**
|
||||
* Roundstart hook.
|
||||
* Called in gameticker.dm when a round starts.
|
||||
*/
|
||||
/hook/roundstart
|
||||
|
||||
/**
|
||||
* Roundend hook.
|
||||
* Called in gameticker.dm when a round ends.
|
||||
*/
|
||||
/hook/roundend
|
||||
|
||||
/**
|
||||
* Death hook.
|
||||
* Called in death.dm when someone dies.
|
||||
* Parameters: var/mob/living/carbon/human, var/gibbed
|
||||
*/
|
||||
/hook/death
|
||||
|
||||
/**
|
||||
* Cloning hook.
|
||||
* Called in cloning.dm when someone is brought back by the wonders of modern science.
|
||||
* Parameters: var/mob/living/carbon/human
|
||||
*/
|
||||
/hook/clone
|
||||
|
||||
/**
|
||||
* Debrained hook.
|
||||
* Called in brain_item.dm when someone gets debrained.
|
||||
* Parameters: var/obj/item/organ/brain
|
||||
*/
|
||||
/hook/debrain
|
||||
|
||||
/**
|
||||
* Borged hook.
|
||||
* Called in robot_parts.dm when someone gets turned into a cyborg.
|
||||
* Parameters: var/mob/living/silicon/robot
|
||||
*/
|
||||
/hook/borgify
|
||||
|
||||
/**
|
||||
* Podman hook.
|
||||
* Called in podmen.dm when someone is brought back as a Diona.
|
||||
* Parameters: var/mob/living/carbon/alien/diona
|
||||
*/
|
||||
/hook/harvest_podman
|
||||
|
||||
/**
|
||||
* Payroll revoked hook.
|
||||
* Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal.
|
||||
* Parameters: var/datum/money_account
|
||||
*/
|
||||
/hook/revoke_payroll
|
||||
|
||||
/**
|
||||
* Account suspension hook.
|
||||
* Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal.
|
||||
* Parameters: var/datum/money_account
|
||||
*/
|
||||
/hook/change_account_status
|
||||
|
||||
/**
|
||||
* Employee reassignment hook.
|
||||
* Called in card.dm when someone's card is reassigned at the HoP's desk.
|
||||
* Parameters: var/obj/item/weapon/card/id
|
||||
*/
|
||||
/hook/reassign_employee
|
||||
|
||||
/**
|
||||
* Employee terminated hook.
|
||||
* Called in card.dm when someone's card is terminated at the HoP's desk.
|
||||
* Parameters: var/obj/item/weapon/card/id
|
||||
*/
|
||||
/hook/terminate_employee
|
||||
|
||||
/**
|
||||
* Crate sold hook.
|
||||
* Called in supplyshuttle.dm when a crate is sold on the shuttle.
|
||||
* Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle
|
||||
*/
|
||||
/hook/sell_crate
|
||||
/**
|
||||
* Startup hook.
|
||||
* Called in world.dm when the server starts.
|
||||
*/
|
||||
/hook/startup
|
||||
|
||||
/**
|
||||
* Roundstart hook.
|
||||
* Called in gameticker.dm when a round starts.
|
||||
*/
|
||||
/hook/roundstart
|
||||
|
||||
/**
|
||||
* Roundend hook.
|
||||
* Called in gameticker.dm when a round ends.
|
||||
*/
|
||||
/hook/roundend
|
||||
|
||||
/**
|
||||
* Death hook.
|
||||
* Called in death.dm when someone dies.
|
||||
* Parameters: var/mob/living/carbon/human, var/gibbed
|
||||
*/
|
||||
/hook/death
|
||||
|
||||
/**
|
||||
* Cloning hook.
|
||||
* Called in cloning.dm when someone is brought back by the wonders of modern science.
|
||||
* Parameters: var/mob/living/carbon/human
|
||||
*/
|
||||
/hook/clone
|
||||
|
||||
/**
|
||||
* Debrained hook.
|
||||
* Called in brain_item.dm when someone gets debrained.
|
||||
* Parameters: var/obj/item/organ/brain
|
||||
*/
|
||||
/hook/debrain
|
||||
|
||||
/**
|
||||
* Borged hook.
|
||||
* Called in robot_parts.dm when someone gets turned into a cyborg.
|
||||
* Parameters: var/mob/living/silicon/robot
|
||||
*/
|
||||
/hook/borgify
|
||||
|
||||
/**
|
||||
* Podman hook.
|
||||
* Called in podmen.dm when someone is brought back as a Diona.
|
||||
* Parameters: var/mob/living/carbon/alien/diona
|
||||
*/
|
||||
/hook/harvest_podman
|
||||
|
||||
/**
|
||||
* Payroll revoked hook.
|
||||
* Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal.
|
||||
* Parameters: var/datum/money_account
|
||||
*/
|
||||
/hook/revoke_payroll
|
||||
|
||||
/**
|
||||
* Account suspension hook.
|
||||
* Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal.
|
||||
* Parameters: var/datum/money_account
|
||||
*/
|
||||
/hook/change_account_status
|
||||
|
||||
/**
|
||||
* Employee reassignment hook.
|
||||
* Called in card.dm when someone's card is reassigned at the HoP's desk.
|
||||
* Parameters: var/obj/item/weapon/card/id
|
||||
*/
|
||||
/hook/reassign_employee
|
||||
|
||||
/**
|
||||
* Employee terminated hook.
|
||||
* Called in card.dm when someone's card is terminated at the HoP's desk.
|
||||
* Parameters: var/obj/item/weapon/card/id
|
||||
*/
|
||||
/hook/terminate_employee
|
||||
|
||||
/**
|
||||
* Crate sold hook.
|
||||
* Called in supplyshuttle.dm when a crate is sold on the shuttle.
|
||||
* Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle
|
||||
*/
|
||||
/hook/sell_crate
|
||||
|
||||
31
code/controllers/observer_listener/atom/observer.dm
Normal file
31
code/controllers/observer_listener/atom/observer.dm
Normal file
@@ -0,0 +1,31 @@
|
||||
#define OBSERVER_EVENT_DESTROY "OnDestroy"
|
||||
|
||||
/atom
|
||||
var/list/observer_events
|
||||
|
||||
/atom/Destroy()
|
||||
var/list/destroy_listeners = get_listener_list_from_event(OBSERVER_EVENT_DESTROY)
|
||||
if(destroy_listeners)
|
||||
for(var/destroy_listener in destroy_listeners)
|
||||
call(destroy_listener, destroy_listeners[destroy_listener])(src)
|
||||
|
||||
for(var/list/listeners in observer_events)
|
||||
listeners.Cut()
|
||||
|
||||
return ..()
|
||||
|
||||
/atom/proc/register(var/event, var/procOwner, var/proc_call)
|
||||
var/list/listeners = get_listener_list_from_event(event)
|
||||
listeners[procOwner] = proc_call
|
||||
|
||||
/atom/proc/unregister(var/event, var/procOwner)
|
||||
var/list/listeners = get_listener_list_from_event(event)
|
||||
listeners -= procOwner
|
||||
|
||||
/atom/proc/get_listener_list_from_event(var/observer_event)
|
||||
if(!observer_events) observer_events = list()
|
||||
var/list/listeners = observer_events[observer_event]
|
||||
if(!listeners)
|
||||
listeners = list()
|
||||
observer_events[observer_event] = listeners
|
||||
return listeners
|
||||
28
code/controllers/observer_listener/datum/observer.dm
Normal file
28
code/controllers/observer_listener/datum/observer.dm
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
#define OBSERVER_EVENT_DESTROY "OnDestroy"
|
||||
|
||||
/datum
|
||||
var/list/observer_events
|
||||
|
||||
/datum/Destroy()
|
||||
for(var/list/listeners in observer_events)
|
||||
listeners.Cut()
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/proc/register(var/event, var/procOwner, var/proc_call)
|
||||
var/list/listeners = get_listener_list_from_event(event)
|
||||
listeners[procOwner] = proc_call
|
||||
|
||||
/datum/proc/unregister(var/event, var/procOwner)
|
||||
var/list/listeners = get_listener_list_from_event(event)
|
||||
listeners -= procOwner
|
||||
|
||||
/datum/proc/get_listener_list_from_event(var/observer_event)
|
||||
if(!observer_events) observer_events = list()
|
||||
var/list/listeners = observer_events[observer_event]
|
||||
if(!listeners)
|
||||
listeners = list()
|
||||
observer_events[observer_event] = listeners
|
||||
return listeners
|
||||
*/
|
||||
100
code/game/objects/items/devices/hacktool.dm
Normal file
100
code/game/objects/items/devices/hacktool.dm
Normal file
@@ -0,0 +1,100 @@
|
||||
/obj/item/device/multitool/hacktool
|
||||
var/is_hacking = 0
|
||||
var/max_known_targets
|
||||
|
||||
var/in_hack_mode = 0
|
||||
var/list/known_targets
|
||||
var/list/supported_types
|
||||
var/datum/topic_state/default/must_hack/hack_state
|
||||
|
||||
/obj/item/device/multitool/hacktool/New()
|
||||
..()
|
||||
known_targets = list()
|
||||
max_known_targets = 5 + rand(1,3)
|
||||
supported_types = list(/obj/machinery/door/airlock)
|
||||
hack_state = new(src)
|
||||
|
||||
/obj/item/device/multitool/hacktool/Destroy()
|
||||
for(var/T in known_targets)
|
||||
var/atom/target = T
|
||||
target.unregister(OBSERVER_EVENT_DESTROY, src)
|
||||
known_targets.Cut()
|
||||
qdel(hack_state)
|
||||
hack_state = null
|
||||
return ..()
|
||||
|
||||
/obj/item/device/multitool/hacktool/attackby(var/obj/W, var/mob/user)
|
||||
if(isscrewdriver(W))
|
||||
in_hack_mode = !in_hack_mode
|
||||
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/device/multitool/hacktool/resolve_attackby(atom/A, mob/user)
|
||||
sanity_check()
|
||||
|
||||
if(!in_hack_mode)
|
||||
return ..()
|
||||
|
||||
if(!attempt_hack(user, A))
|
||||
return 0
|
||||
|
||||
A.ui_interact(user, state = hack_state)
|
||||
return 1
|
||||
|
||||
/obj/item/device/multitool/hacktool/proc/attempt_hack(var/mob/user, var/atom/target)
|
||||
if(is_hacking)
|
||||
user << "<span class='warning'>You are already hacking!</span>"
|
||||
return 0
|
||||
if(!is_type_in_list(target, supported_types))
|
||||
user << "\icon[src] <span class='warning'>Unable to hack this target!</span>"
|
||||
return 0
|
||||
var/found = known_targets.Find(target)
|
||||
if(found)
|
||||
known_targets.Swap(1, found) // Move the last hacked item first
|
||||
return 1
|
||||
|
||||
user << "<span class='notice'>You begin hacking \the [target]...</span>"
|
||||
is_hacking = 1
|
||||
// On average hackin takes ~30 seconds. Fairly small random span to avoid people simply aborting and trying again
|
||||
var/hack_result = do_after(user, (20 SECONDS + rand(0, 10 SECONDS) + rand(0, 10 SECONDS)))
|
||||
is_hacking = 0
|
||||
|
||||
if(hack_result && in_hack_mode)
|
||||
user << "<span class='notice'>Your hacking attempt was succesful!</span>"
|
||||
playsound(src.loc, 'sound/piano/A#6.ogg', 75)
|
||||
else
|
||||
user << "<span class='warning'>Your hacking attempt failed!</span>"
|
||||
return 0
|
||||
|
||||
known_targets.Insert(1, target) // Insert the newly hacked target first,
|
||||
target.register(OBSERVER_EVENT_DESTROY, src, /obj/item/device/multitool/hacktool/proc/on_target_destroy)
|
||||
return 1
|
||||
|
||||
/obj/item/device/multitool/hacktool/proc/sanity_check()
|
||||
if(max_known_targets < 1) max_known_targets = 1
|
||||
// Cut away the oldest items if the capacity has been reached
|
||||
if(known_targets.len > max_known_targets)
|
||||
for(var/i = (max_known_targets + 1) to known_targets.len)
|
||||
var/atom/A = known_targets[i]
|
||||
A.unregister(OBSERVER_EVENT_DESTROY, src)
|
||||
known_targets.Cut(max_known_targets + 1)
|
||||
|
||||
/obj/item/device/multitool/hacktool/proc/on_target_destroy(var/target)
|
||||
known_targets -= target
|
||||
|
||||
/datum/topic_state/default/must_hack
|
||||
var/obj/item/device/multitool/hacktool/hacktool
|
||||
|
||||
/datum/topic_state/default/must_hack/New(var/hacktool)
|
||||
src.hacktool = hacktool
|
||||
..()
|
||||
|
||||
/datum/topic_state/default/must_hack/Destroy()
|
||||
hacktool = null
|
||||
return ..()
|
||||
|
||||
/datum/topic_state/default/must_hack/can_use_topic(var/src_object, var/mob/user)
|
||||
if(!hacktool || !hacktool.in_hack_mode || !(src_object in hacktool.known_targets))
|
||||
return STATUS_CLOSE
|
||||
return ..()
|
||||
@@ -20,4 +20,4 @@
|
||||
|
||||
origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1)
|
||||
var/obj/machinery/telecomms/buffer // simple machine buffer for device linkage
|
||||
var/obj/machinery/clonepod/connecting //same for cryopod linkage
|
||||
var/obj/machinery/clonepod/connecting //same for cryopod linkage
|
||||
|
||||
@@ -411,6 +411,14 @@ datum/uplink_item/dd_SortValue()
|
||||
item_cost = 3
|
||||
path = /obj/item/weapon/card/emag
|
||||
|
||||
/datum/uplink_item/item/tools/hacking_tool
|
||||
name = "Door Hacking Tool"
|
||||
item_cost = 2
|
||||
path = /obj/item/device/multitool/hacktool
|
||||
desc = "Appears and functions as a standard multitool until the mode is toggled by applying a screwdriver appropriately. \
|
||||
When in hacking mode this device will grant full access to any standard airlock within 20 to 40 seconds. \
|
||||
This device will also be able to immediately access the last 6 to 8 hacked airlocks."
|
||||
|
||||
/datum/uplink_item/item/tools/clerical
|
||||
name = "Morphic Clerical Kit"
|
||||
item_cost = 3
|
||||
|
||||
@@ -127,6 +127,8 @@
|
||||
#include "code\controllers\subsystems.dm"
|
||||
#include "code\controllers\verbs.dm"
|
||||
#include "code\controllers\voting.dm"
|
||||
#include "code\controllers\observer_listener\atom\observer.dm"
|
||||
#include "code\controllers\observer_listener\datum\observer.dm"
|
||||
#include "code\controllers\Processes\air.dm"
|
||||
#include "code\controllers\Processes\alarm.dm"
|
||||
#include "code\controllers\Processes\chemistry.dm"
|
||||
@@ -612,6 +614,7 @@
|
||||
#include "code\game\objects\items\devices\flash.dm"
|
||||
#include "code\game\objects\items\devices\flashlight.dm"
|
||||
#include "code\game\objects\items\devices\floor_painter.dm"
|
||||
#include "code\game\objects\items\devices\hacktool.dm"
|
||||
#include "code\game\objects\items\devices\lightreplacer.dm"
|
||||
#include "code\game\objects\items\devices\locker_painter.dm"
|
||||
#include "code\game\objects\items\devices\megaphone.dm"
|
||||
|
||||
Reference in New Issue
Block a user