mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 08:08:49 +01:00
Simple skill/skillchip framework (#52314)
* Simple skills framework. * Map changes. * Adds skillchips to vendor * Adds skill stations to the map. * Circuitboards * Fix typo * Some minimal instability * Fixes,tweaks etc * Suggest better names or we'll end up with these. * sharpness thing * tgui build * Makes wine from booze synthetizer show to wine tasters. * Makes wine from dispenser have taste for wine tasters. * Apply suggestions from code review Co-authored-by: Rohesie <rohesie@gmail.com> * Swaps to carbon var. * wordy helper proc * While i'm at it, other relaymoves Co-authored-by: Rohesie <rohesie@gmail.com>
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
#define SKILLCHIP_IMPLANT_TIME 1 MINUTES
|
||||
#define SKILLCHIP_REMOVAL_TIME 30 SECONDS
|
||||
|
||||
/obj/machinery/skill_station
|
||||
name = "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_icon()
|
||||
|
||||
//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.set_autoupdate(FALSE)
|
||||
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"
|
||||
|
||||
/obj/machinery/skill_station/update_overlays()
|
||||
. = ..()
|
||||
if(working)
|
||||
. += "working"
|
||||
|
||||
/obj/machinery/skill_station/relaymove(mob/user)
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/skill_station/open_machine()
|
||||
. = ..()
|
||||
interrupt_operation()
|
||||
|
||||
/obj/machinery/skill_station/Exited(atom/movable/AM, atom/newloc)
|
||||
. = ..()
|
||||
if(AM == 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_icon()
|
||||
|
||||
/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 class='notice'>There's already a skillchip inside.</span>")
|
||||
return
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
inserted_skillchip = I
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/skill_station/dropContents(list/subset)
|
||||
subset = contents - inserted_skillchip
|
||||
return ..() //This is kinda annoying
|
||||
|
||||
/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()
|
||||
if(!inserted_skillchip?.can_be_implanted(occupant))
|
||||
return
|
||||
working = TRUE
|
||||
work_timer = addtimer(CALLBACK(src,.proc/implant),SKILLCHIP_IMPLANT_TIME,TIMER_STOPPABLE)
|
||||
update_icon()
|
||||
|
||||
/// Finish implanting.
|
||||
/obj/machinery/skill_station/proc/implant()
|
||||
working = FALSE
|
||||
work_timer = null
|
||||
if(inserted_skillchip?.can_be_implanted(occupant))
|
||||
implant_skillchip(occupant,inserted_skillchip)
|
||||
update_icon()
|
||||
SStgui.update_uis(src)
|
||||
to_chat(occupant,"<span class='notice'>Operation complete!</span>")
|
||||
|
||||
/// Start removal.
|
||||
/obj/machinery/skill_station/proc/start_removal(obj/item/skillchip/to_be_removed)
|
||||
if(!to_be_removed)
|
||||
return
|
||||
working = TRUE
|
||||
work_timer = addtimer(CALLBACK(src,.proc/remove_skillchip,to_be_removed),SKILLCHIP_REMOVAL_TIME,TIMER_STOPPABLE)
|
||||
update_icon()
|
||||
|
||||
/// Finish removal.
|
||||
/obj/machinery/skill_station/proc/remove_skillchip(obj/item/skillchip/to_be_removed)
|
||||
working = FALSE
|
||||
work_timer = null
|
||||
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) || !(to_be_removed in occupant_brain.skillchips))
|
||||
return
|
||||
to_be_removed.on_removal(carbon_occupant, silent=FALSE)
|
||||
LAZYREMOVE(occupant_brain.skillchips, to_be_removed)
|
||||
if(to_be_removed.removable)
|
||||
carbon_occupant.put_in_hands(to_be_removed)
|
||||
else
|
||||
qdel(to_be_removed)
|
||||
update_icon()
|
||||
SStgui.update_uis(src)
|
||||
to_chat(carbon_occupant,"<span class='notice'>Operation complete!</span>")
|
||||
|
||||
/obj/machinery/skill_station/proc/implant_skillchip(mob/living/carbon/target,obj/item/skillchip/chip)
|
||||
var/obj/item/organ/brain/target_brain = target.getorganslot(ORGAN_SLOT_BRAIN)
|
||||
chip.on_apply(target, silent = FALSE)
|
||||
chip.forceMove(target_brain)
|
||||
LAZYADD(target_brain.skillchips, chip)
|
||||
|
||||
/obj/machinery/skill_station/ui_data(mob/user)
|
||||
. = ..()
|
||||
.["working"] = working
|
||||
.["timeleft"] = work_timer ? timeleft(work_timer) : null
|
||||
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))
|
||||
.["error"] = "Brain not detected. Please consult nearest medical practitioner."
|
||||
else
|
||||
var/list/current_skills = list()
|
||||
for(var/obj/item/skillchip/skill_chip in occupant_brain)
|
||||
current_skills += list(list("name"=skill_chip.skill_name,"icon"=skill_chip.skill_icon,"cost"=skill_chip.slot_cost,"ref"=REF(skill_chip),"active"=(skill_chip in occupant_brain.skillchips)))
|
||||
.["current"] = current_skills
|
||||
.["slots_used"] = carbon_occupant.used_skillchip_slots
|
||||
.["slots_max"] = carbon_occupant.max_skillchip_slots
|
||||
|
||||
.["skillchip_ready"] = inserted_skillchip ? TRUE : FALSE
|
||||
if(inserted_skillchip)
|
||||
.["implantable"] = inserted_skillchip.can_be_implanted(occupant)
|
||||
.["implantable_reason"] = inserted_skillchip.can_be_implanted_message(occupant)
|
||||
.["skill_name"] = inserted_skillchip.skill_name
|
||||
.["skill_desc"] = inserted_skillchip.skill_description
|
||||
.["skill_icon"] = inserted_skillchip.skill_icon
|
||||
.["skill_cost"] = inserted_skillchip.slot_cost
|
||||
|
||||
/obj/machinery/skill_station/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(usr != occupant)
|
||||
return
|
||||
switch(action)
|
||||
if("implant")
|
||||
if(occupant && inserted_skillchip)
|
||||
start_implanting()
|
||||
return TRUE
|
||||
if("remove")
|
||||
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
|
||||
if(!to_be_removed)
|
||||
return TRUE
|
||||
start_removal(to_be_removed)
|
||||
return TRUE
|
||||
if("eject")
|
||||
if(inserted_skillchip)
|
||||
to_chat(occupant,"<span class='notice'>You eject the skillchip.</span>")
|
||||
var/mob/living/carbon/human/H = occupant
|
||||
H.put_in_hands(inserted_skillchip)
|
||||
inserted_skillchip = null
|
||||
return TRUE
|
||||
@@ -0,0 +1,98 @@
|
||||
/obj/item/skillchip
|
||||
name = "skillchip"
|
||||
desc = "This biochip integrates with user's brain to enable mastery of specific skill. Consult certified Nanotrasen neurosurgeon before use."
|
||||
|
||||
icon = 'icons/obj/card.dmi'
|
||||
icon_state = "data_3"
|
||||
custom_price = 500
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/// Trait automatically granted by this chip, optional
|
||||
var/auto_trait
|
||||
/// Skill name shown on UI
|
||||
var/skill_name
|
||||
/// Skill description shown on UI
|
||||
var/skill_description
|
||||
/// FS icon show on UI
|
||||
var/skill_icon = "brain"
|
||||
/// Message shown when implanting the chip
|
||||
var/implanting_message
|
||||
/// Message shown when extracting the chip
|
||||
var/removal_message
|
||||
//If set to TRUE, trying to extract the chip will destroy it instead
|
||||
var/removable = TRUE
|
||||
/// How many skillslots this one takes
|
||||
var/slot_cost = 1
|
||||
|
||||
/// Called after implantation and/or brain entering new body
|
||||
/obj/item/skillchip/proc/on_apply(mob/living/carbon/user,silent=TRUE)
|
||||
if(!silent && implanting_message)
|
||||
to_chat(user,implanting_message)
|
||||
if(auto_trait)
|
||||
ADD_TRAIT(user,auto_trait,SKILLCHIP_TRAIT)
|
||||
user.used_skillchip_slots += slot_cost
|
||||
|
||||
/// Called after removal and/or brain exiting the body
|
||||
/obj/item/skillchip/proc/on_removal(mob/living/carbon/user,silent=TRUE)
|
||||
if(!silent && removal_message)
|
||||
to_chat(user,removal_message)
|
||||
if(auto_trait)
|
||||
REMOVE_TRAIT(user,auto_trait,SKILLCHIP_TRAIT)
|
||||
user.used_skillchip_slots -= slot_cost
|
||||
|
||||
/// Checks if this implant is valid to implant in a given mob.
|
||||
/obj/item/skillchip/proc/can_be_implanted(mob/living/carbon/target)
|
||||
//No brain
|
||||
var/obj/item/organ/brain/target_brain = target.getorganslot(ORGAN_SLOT_BRAIN)
|
||||
if(QDELETED(target_brain))
|
||||
return FALSE
|
||||
//No skill slots left
|
||||
if(target.used_skillchip_slots + slot_cost > target.max_skillchip_slots)
|
||||
return FALSE
|
||||
//Only one copy of each for now.
|
||||
if(locate(type) in target_brain.skillchips)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// Returns readable reason why implanting cannot succeed --todo switch to flag retval in can_be_implanted to cut down copypaste
|
||||
/obj/item/skillchip/proc/can_be_implanted_message(mob/living/carbon/target)
|
||||
//No brain
|
||||
var/obj/item/organ/brain/target_brain = target.getorganslot(ORGAN_SLOT_BRAIN)
|
||||
if(QDELETED(target_brain))
|
||||
return "No brain detected."
|
||||
//No skill slots left
|
||||
if(target.used_skillchip_slots + slot_cost > target.max_skillchip_slots)
|
||||
return "Complexity limit exceeded."
|
||||
//Only one copy of each for now.
|
||||
if(locate(type) in target_brain.skillchips)
|
||||
return "Duplicate chip detected."
|
||||
return "Chip ready for implantation."
|
||||
|
||||
/obj/item/skillchip/basketweaving
|
||||
name = "Basketsoft 3000 skillchip"
|
||||
desc = "Underwater edition."
|
||||
auto_trait = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE
|
||||
skill_name = "Underwater Basketweaving"
|
||||
skill_description = "Master intricate art of using twine to create perfect baskets while submerged."
|
||||
skill_icon = "shopping-basket"
|
||||
implanting_message = "<span class='notice'>You're one with the twine and the sea.</span>"
|
||||
removal_message = "<span class='notice'>Higher mysteries of underwater basketweaving leave your mind.</span>"
|
||||
|
||||
/obj/item/skillchip/wine_taster
|
||||
name = "WINE skillchip"
|
||||
desc = "Wine.Is.Not.Equal version 5."
|
||||
auto_trait = TRAIT_WINE_TASTER
|
||||
skill_name = "Wine Tasting"
|
||||
skill_description = "Recognize wine vintage from taste alone. Never again lack an opinion when presented with an unknown drink."
|
||||
skill_icon = "wine-bottle"
|
||||
implanting_message = "<span class='notice'>You recall wine taste.</span>"
|
||||
removal_message = "<span class='notice'>Your memories of wine evaporate.</span>"
|
||||
|
||||
/obj/item/skillchip/bonsai
|
||||
name = "Hedge 3 skillchip"
|
||||
auto_trait = TRAIT_BONSAI
|
||||
skill_name = "Hedgetrimming"
|
||||
skill_description = "Trim hedges and potted plants into marvelous new shapes with any old knife. Not applicable to plastic plants."
|
||||
skill_icon = "spa"
|
||||
implanting_message = "<span class='notice'>Your mind is filled with plant arrangments.</span>"
|
||||
removal_message = "<span class='notice'>Your can't remember how a hedge looks like anymore.</span>"
|
||||
Reference in New Issue
Block a user