mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 02:34:00 +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 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 isbrain(A) istype(A, /mob/living/carbon/brain)
|
||||||
|
|
||||||
#define iscarbon(A) istype(A, /mob/living/carbon)
|
#define iscarbon(A) istype(A, /mob/living/carbon)
|
||||||
|
|||||||
@@ -1,87 +1,87 @@
|
|||||||
/**
|
/**
|
||||||
* Startup hook.
|
* Startup hook.
|
||||||
* Called in world.dm when the server starts.
|
* Called in world.dm when the server starts.
|
||||||
*/
|
*/
|
||||||
/hook/startup
|
/hook/startup
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Roundstart hook.
|
* Roundstart hook.
|
||||||
* Called in gameticker.dm when a round starts.
|
* Called in gameticker.dm when a round starts.
|
||||||
*/
|
*/
|
||||||
/hook/roundstart
|
/hook/roundstart
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Roundend hook.
|
* Roundend hook.
|
||||||
* Called in gameticker.dm when a round ends.
|
* Called in gameticker.dm when a round ends.
|
||||||
*/
|
*/
|
||||||
/hook/roundend
|
/hook/roundend
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Death hook.
|
* Death hook.
|
||||||
* Called in death.dm when someone dies.
|
* Called in death.dm when someone dies.
|
||||||
* Parameters: var/mob/living/carbon/human, var/gibbed
|
* Parameters: var/mob/living/carbon/human, var/gibbed
|
||||||
*/
|
*/
|
||||||
/hook/death
|
/hook/death
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cloning hook.
|
* Cloning hook.
|
||||||
* Called in cloning.dm when someone is brought back by the wonders of modern science.
|
* Called in cloning.dm when someone is brought back by the wonders of modern science.
|
||||||
* Parameters: var/mob/living/carbon/human
|
* Parameters: var/mob/living/carbon/human
|
||||||
*/
|
*/
|
||||||
/hook/clone
|
/hook/clone
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debrained hook.
|
* Debrained hook.
|
||||||
* Called in brain_item.dm when someone gets debrained.
|
* Called in brain_item.dm when someone gets debrained.
|
||||||
* Parameters: var/obj/item/organ/brain
|
* Parameters: var/obj/item/organ/brain
|
||||||
*/
|
*/
|
||||||
/hook/debrain
|
/hook/debrain
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Borged hook.
|
* Borged hook.
|
||||||
* Called in robot_parts.dm when someone gets turned into a cyborg.
|
* Called in robot_parts.dm when someone gets turned into a cyborg.
|
||||||
* Parameters: var/mob/living/silicon/robot
|
* Parameters: var/mob/living/silicon/robot
|
||||||
*/
|
*/
|
||||||
/hook/borgify
|
/hook/borgify
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Podman hook.
|
* Podman hook.
|
||||||
* Called in podmen.dm when someone is brought back as a Diona.
|
* Called in podmen.dm when someone is brought back as a Diona.
|
||||||
* Parameters: var/mob/living/carbon/alien/diona
|
* Parameters: var/mob/living/carbon/alien/diona
|
||||||
*/
|
*/
|
||||||
/hook/harvest_podman
|
/hook/harvest_podman
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payroll revoked hook.
|
* Payroll revoked hook.
|
||||||
* Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal.
|
* Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal.
|
||||||
* Parameters: var/datum/money_account
|
* Parameters: var/datum/money_account
|
||||||
*/
|
*/
|
||||||
/hook/revoke_payroll
|
/hook/revoke_payroll
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account suspension hook.
|
* Account suspension hook.
|
||||||
* Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal.
|
* Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal.
|
||||||
* Parameters: var/datum/money_account
|
* Parameters: var/datum/money_account
|
||||||
*/
|
*/
|
||||||
/hook/change_account_status
|
/hook/change_account_status
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Employee reassignment hook.
|
* Employee reassignment hook.
|
||||||
* Called in card.dm when someone's card is reassigned at the HoP's desk.
|
* Called in card.dm when someone's card is reassigned at the HoP's desk.
|
||||||
* Parameters: var/obj/item/weapon/card/id
|
* Parameters: var/obj/item/weapon/card/id
|
||||||
*/
|
*/
|
||||||
/hook/reassign_employee
|
/hook/reassign_employee
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Employee terminated hook.
|
* Employee terminated hook.
|
||||||
* Called in card.dm when someone's card is terminated at the HoP's desk.
|
* Called in card.dm when someone's card is terminated at the HoP's desk.
|
||||||
* Parameters: var/obj/item/weapon/card/id
|
* Parameters: var/obj/item/weapon/card/id
|
||||||
*/
|
*/
|
||||||
/hook/terminate_employee
|
/hook/terminate_employee
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crate sold hook.
|
* Crate sold hook.
|
||||||
* Called in supplyshuttle.dm when a crate is sold on the shuttle.
|
* Called in supplyshuttle.dm when a crate is sold on the shuttle.
|
||||||
* Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle
|
* Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle
|
||||||
*/
|
*/
|
||||||
/hook/sell_crate
|
/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)
|
origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1)
|
||||||
var/obj/machinery/telecomms/buffer // simple machine buffer for device linkage
|
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
|
item_cost = 3
|
||||||
path = /obj/item/weapon/card/emag
|
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
|
/datum/uplink_item/item/tools/clerical
|
||||||
name = "Morphic Clerical Kit"
|
name = "Morphic Clerical Kit"
|
||||||
item_cost = 3
|
item_cost = 3
|
||||||
|
|||||||
@@ -127,6 +127,8 @@
|
|||||||
#include "code\controllers\subsystems.dm"
|
#include "code\controllers\subsystems.dm"
|
||||||
#include "code\controllers\verbs.dm"
|
#include "code\controllers\verbs.dm"
|
||||||
#include "code\controllers\voting.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\air.dm"
|
||||||
#include "code\controllers\Processes\alarm.dm"
|
#include "code\controllers\Processes\alarm.dm"
|
||||||
#include "code\controllers\Processes\chemistry.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\flash.dm"
|
||||||
#include "code\game\objects\items\devices\flashlight.dm"
|
#include "code\game\objects\items\devices\flashlight.dm"
|
||||||
#include "code\game\objects\items\devices\floor_painter.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\lightreplacer.dm"
|
||||||
#include "code\game\objects\items\devices\locker_painter.dm"
|
#include "code\game\objects\items\devices\locker_painter.dm"
|
||||||
#include "code\game\objects\items\devices\megaphone.dm"
|
#include "code\game\objects\items\devices\megaphone.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user