mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-13 11:12:14 +00:00
* Refactors move procs to support multitle objects * Update _blob.dm Co-authored-by: Rohesie <rohesie@gmail.com> Co-authored-by: Gandalf <jzo123@hotmail.com>
309 lines
10 KiB
Plaintext
309 lines
10 KiB
Plaintext
#define SKILLCHIP_IMPLANT_TIME 15 SECONDS
|
|
#define SKILLCHIP_REMOVAL_TIME 15 SECONDS
|
|
|
|
/obj/machinery/skill_station
|
|
name = "\improper Skillsoft station"
|
|
desc = "Learn skills with only minimal chance for brain damage."
|
|
|
|
icon = 'icons/obj/machines/implantchair.dmi'
|
|
icon_state = "implantchair"
|
|
occupant_typecache = list(/mob/living/carbon) //todo make occupant_typecache per type
|
|
state_open = TRUE
|
|
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND //Don't call ui_interac by default - we only want that when inside
|
|
circuit = /obj/item/circuitboard/machine/skill_station
|
|
/// Currently implanting/removing
|
|
var/working = FALSE
|
|
/// Timer until implanting/removing finishes.
|
|
var/work_timer
|
|
/// What we're implanting
|
|
var/obj/item/skillchip/inserted_skillchip
|
|
|
|
/obj/machinery/skill_station/Initialize()
|
|
. = ..()
|
|
update_appearance()
|
|
|
|
//Only usable by the person inside
|
|
/obj/machinery/skill_station/ui_state(mob/user)
|
|
return GLOB.contained_state
|
|
|
|
/obj/machinery/skill_station/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "SkillStation", name)
|
|
ui.open()
|
|
|
|
/obj/machinery/skill_station/update_icon_state()
|
|
icon_state = initial(icon_state)
|
|
if(state_open)
|
|
icon_state += "_open"
|
|
if(occupant)
|
|
icon_state += "_occupied"
|
|
return ..()
|
|
|
|
/obj/machinery/skill_station/update_overlays()
|
|
. = ..()
|
|
if(working)
|
|
. += "working"
|
|
|
|
/obj/machinery/skill_station/relaymove(mob/living/user, direction)
|
|
open_machine()
|
|
|
|
/obj/machinery/skill_station/open_machine()
|
|
. = ..()
|
|
interrupt_operation()
|
|
|
|
/obj/machinery/skill_station/Exited(atom/movable/gone, direction)
|
|
. = ..()
|
|
if(gone == inserted_skillchip)
|
|
inserted_skillchip = null
|
|
interrupt_operation()
|
|
|
|
/obj/machinery/skill_station/power_change()
|
|
. = ..()
|
|
if(working)
|
|
interrupt_operation()
|
|
|
|
/obj/machinery/skill_station/close_machine(atom/movable/target)
|
|
. = ..()
|
|
if(occupant)
|
|
ui_interact(occupant)
|
|
|
|
/obj/machinery/skill_station/proc/interrupt_operation()
|
|
working = FALSE
|
|
if(work_timer)
|
|
deltimer(work_timer)
|
|
work_timer = null
|
|
update_appearance()
|
|
|
|
/obj/machinery/skill_station/interact(mob/user)
|
|
. = ..()
|
|
if(user == occupant)
|
|
ui_interact(user)
|
|
else
|
|
toggle_open()
|
|
|
|
/obj/machinery/skill_station/attackby(obj/item/I, mob/living/user, params)
|
|
if(istype(I,/obj/item/skillchip))
|
|
if(inserted_skillchip)
|
|
to_chat(user,span_notice("There's already a skillchip inside."))
|
|
return
|
|
if(!user.transferItemToLoc(I, src))
|
|
return
|
|
inserted_skillchip = I
|
|
return
|
|
return ..()
|
|
|
|
/obj/machinery/skill_station/dump_contents()
|
|
. = ..()
|
|
inserted_skillchip = null
|
|
|
|
/obj/machinery/skill_station/dump_inventory_contents(list/subset = null)
|
|
// Don't drop the skillchip, it's directly inserted into the machine.
|
|
// dump_contents() will drop everything including the skillchip as an alternative to this.
|
|
subset = contents - inserted_skillchip
|
|
return ..()
|
|
|
|
/obj/machinery/skill_station/proc/toggle_open(mob/user)
|
|
state_open ? close_machine() : open_machine()
|
|
|
|
// Functions below do not validate occupant exists - should be handled outer wrappers.
|
|
/// Start implanting.
|
|
/obj/machinery/skill_station/proc/start_implanting()
|
|
var/mob/living/carbon/carbon_occupant = occupant
|
|
|
|
if(inserted_skillchip.has_mob_incompatibility(carbon_occupant))
|
|
CRASH("Unusual error - [usr] attempted to start implanting of [inserted_skillchip] when the interface state should not have allowed it.")
|
|
|
|
working = TRUE
|
|
work_timer = addtimer(CALLBACK(src,.proc/implant),SKILLCHIP_IMPLANT_TIME,TIMER_STOPPABLE)
|
|
update_appearance()
|
|
|
|
/// Finish implanting.
|
|
/obj/machinery/skill_station/proc/implant()
|
|
working = FALSE
|
|
work_timer = null
|
|
var/mob/living/carbon/carbon_occupant = occupant
|
|
var/implant_msg = carbon_occupant.implant_skillchip(inserted_skillchip, FALSE)
|
|
if(implant_msg)
|
|
to_chat(carbon_occupant,span_notice("Operation failed! [implant_msg]"))
|
|
else
|
|
to_chat(carbon_occupant,span_notice("Operation complete!"))
|
|
inserted_skillchip = null
|
|
|
|
update_appearance()
|
|
|
|
/// Start removal.
|
|
/obj/machinery/skill_station/proc/start_removal(obj/item/skillchip/to_be_removed)
|
|
if(!to_be_removed)
|
|
return
|
|
|
|
if(to_be_removed.is_on_cooldown())
|
|
to_chat(occupant, span_notice("DANGER! Operation cannot be completed, removal is unsafe."))
|
|
CRASH("Unusual error - [usr] attempted to start removal of [to_be_removed] when the interface state should not have allowed it.")
|
|
|
|
working = TRUE
|
|
work_timer = addtimer(CALLBACK(src,.proc/remove_skillchip,to_be_removed),SKILLCHIP_REMOVAL_TIME,TIMER_STOPPABLE)
|
|
update_appearance()
|
|
|
|
/// Finish removal.
|
|
/obj/machinery/skill_station/proc/remove_skillchip(obj/item/skillchip/to_be_removed)
|
|
working = FALSE
|
|
work_timer = null
|
|
update_appearance()
|
|
|
|
var/mob/living/carbon/carbon_occupant = occupant
|
|
|
|
if(to_be_removed.is_on_cooldown())
|
|
to_chat(carbon_occupant,span_notice("Safety mechanisms activated! Skillchip cannot be safely removed."))
|
|
return
|
|
|
|
if(!istype(carbon_occupant))
|
|
to_chat(carbon_occupant,span_notice("Occupant does not appear to be a carbon-based lifeform!"))
|
|
return
|
|
|
|
if(!carbon_occupant.remove_skillchip(to_be_removed))
|
|
to_chat(carbon_occupant,span_notice("Failed to remove skillchip!"))
|
|
return
|
|
|
|
if(to_be_removed.removable)
|
|
carbon_occupant.put_in_hands(to_be_removed)
|
|
else
|
|
qdel(to_be_removed)
|
|
|
|
to_chat(carbon_occupant, span_notice("Operation complete!"))
|
|
|
|
/obj/machinery/skill_station/proc/toggle_chip_active(obj/item/skillchip/to_be_toggled)
|
|
var/mob/living/carbon/carbon_occupant = occupant
|
|
|
|
if(to_be_toggled.is_on_cooldown())
|
|
to_chat(carbon_occupant,span_notice("Safety mechanisms activated! Skillchip cannot be safely modified."))
|
|
return
|
|
|
|
if(!istype(carbon_occupant))
|
|
to_chat(carbon_occupant,span_notice("Occupant does not appear to be a carbon-based lifeform!"))
|
|
return
|
|
|
|
if(to_be_toggled.is_active())
|
|
var/active_msg = to_be_toggled.try_deactivate_skillchip(FALSE, FALSE)
|
|
if(active_msg)
|
|
to_chat(carbon_occupant,span_notice("Failed to deactivate skillchip! [active_msg]"))
|
|
return
|
|
|
|
// This code will fire when to_be_toggled.active is FALSE
|
|
var/active_msg = to_be_toggled.try_activate_skillchip(FALSE, FALSE)
|
|
if(active_msg)
|
|
to_chat(carbon_occupant,span_notice("Failed to activate skillchip! [active_msg]"))
|
|
|
|
/obj/machinery/skill_station/ui_data(mob/user)
|
|
. = ..()
|
|
.["working"] = working
|
|
.["timeleft"] = work_timer ? timeleft(work_timer) : null
|
|
var/mob/living/carbon/carbon_occupant = occupant
|
|
|
|
.["skillchip_ready"] = inserted_skillchip ? TRUE : FALSE
|
|
if(inserted_skillchip)
|
|
// This is safe, incompatibility check can accept a null or invalid mob.
|
|
var/incompatibility_check = inserted_skillchip.has_mob_incompatibility(carbon_occupant)
|
|
// Grab chip data. We do this because of special chips like Chameleon that may want to
|
|
// spoof their information.
|
|
var/list/inserted_chip_data = inserted_skillchip.get_chip_data()
|
|
if(incompatibility_check)
|
|
.["implantable"] = FALSE
|
|
.["implantable_reason"] = incompatibility_check
|
|
else
|
|
.["implantable"] = TRUE
|
|
.["implantable_reason"] = null
|
|
.["skill_name"] = inserted_chip_data["name"]
|
|
.["skill_desc"] = inserted_chip_data["desc"]
|
|
.["skill_icon"] = inserted_chip_data["icon"]
|
|
.["complexity"] = inserted_chip_data["complexity"]
|
|
.["slot_use"] = inserted_chip_data["slot_use"]
|
|
|
|
// If there's no occupant, we don't need to worry about what skillchips are in their brain.
|
|
if(!carbon_occupant)
|
|
.["error"] = "No valid occupant detected. Please consult nearest medical practitioner."
|
|
.["current"] = null
|
|
.["complexity_used"] = null
|
|
.["complexity_max"] = null
|
|
.["slots_used"] = null
|
|
.["slots_max"] = null
|
|
return
|
|
|
|
var/obj/item/organ/brain/occupant_brain = carbon_occupant.getorganslot(ORGAN_SLOT_BRAIN)
|
|
|
|
// If there's no brain, we don't need to worry either.
|
|
if(QDELETED(occupant_brain))
|
|
.["error"] = "Brain not detected. Please consult nearest medical practitioner."
|
|
.["current"] = null
|
|
.["complexity_used"] = null
|
|
.["complexity_max"] = null
|
|
.["slots_used"] = null
|
|
.["slots_max"] = null
|
|
return
|
|
|
|
.["complexity_used"] = occupant_brain.get_used_skillchip_complexity()
|
|
.["complexity_max"] = occupant_brain.get_max_skillchip_complexity()
|
|
.["slots_used"] = occupant_brain.get_used_skillchip_slots()
|
|
.["slots_max"] = occupant_brain.get_max_skillchip_slots()
|
|
|
|
// If we got here, we have both an occupant and it has a brain, so we can check for skillchips.
|
|
var/list/current_skills = list()
|
|
for(var/obj/item/skillchip/skill_chip in occupant_brain.skillchips)
|
|
current_skills += list(skill_chip.get_chip_data())
|
|
.["current"] = current_skills
|
|
|
|
/obj/machinery/skill_station/ui_act(action, list/params)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
if(usr != occupant)
|
|
return
|
|
switch(action)
|
|
if("implant")
|
|
if(working)
|
|
stack_trace("[usr] tried to start skillchip implanting when [src] was in an invalid state.")
|
|
return TRUE
|
|
if(occupant && inserted_skillchip)
|
|
start_implanting()
|
|
return TRUE
|
|
if("remove")
|
|
if(working)
|
|
stack_trace("[usr] tried to start skillchip removal when [src] was in an invalid state.")
|
|
return TRUE
|
|
var/chipref = params["ref"]
|
|
var/mob/living/carbon/carbon_occupant = occupant
|
|
var/obj/item/organ/brain/occupant_brain = carbon_occupant.getorganslot(ORGAN_SLOT_BRAIN)
|
|
if(QDELETED(carbon_occupant) || QDELETED(occupant_brain))
|
|
return TRUE
|
|
var/obj/item/skillchip/to_be_removed = locate(chipref) in occupant_brain.skillchips
|
|
if(!to_be_removed)
|
|
return TRUE
|
|
start_removal(to_be_removed)
|
|
return TRUE
|
|
if("eject")
|
|
if(working)
|
|
stack_trace("[usr] tried to toggle skillchip activation when [src] was in an invalid state.")
|
|
return TRUE
|
|
if(inserted_skillchip)
|
|
to_chat(occupant,span_notice("You eject the skillchip."))
|
|
var/mob/living/carbon/human/H = occupant
|
|
H.put_in_hands(inserted_skillchip)
|
|
inserted_skillchip = null
|
|
return TRUE
|
|
if("toggle_activate")
|
|
var/chipref = params["ref"]
|
|
// Check if the machine is already working. If it is, this act should not have sent.
|
|
if(working)
|
|
stack_trace("[usr] tried to toggle skillchip activation when [src] was in an invalid state.")
|
|
return TRUE
|
|
var/mob/living/carbon/carbon_occupant = occupant
|
|
var/obj/item/organ/brain/occupant_brain = carbon_occupant.getorganslot(ORGAN_SLOT_BRAIN)
|
|
if(QDELETED(carbon_occupant) || QDELETED(occupant_brain))
|
|
return TRUE
|
|
var/obj/item/skillchip/to_be_removed = locate(chipref) in occupant_brain.skillchips
|
|
if(!to_be_removed)
|
|
return TRUE
|
|
toggle_chip_active(to_be_removed)
|
|
return TRUE
|
|
|