mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 08:08:49 +01:00
## About The Pull Request Completely removes individual inventory UI handling from mob and HUD code and moves it to slot datums. ``/datum/inventory_slot`` now is responsible for displaying items on the player UI and does so through vis_contests as opposed to screen_loc - which ensures that wide items will display properly rather than be offset to the right. Centralized, slot_id based handling allows us to significantly simplify inventory and HUD code (see how many lines were removed) as you no longer need to individually track all items for both the HUD owner and the observer, and makes it easier for us to fully datumize inventory handling in the future. Also fixes a bug where observers would see players' storage UI and have the items linger on-screen after its closed. ## Why It's Good For The Game Makes working with inventories and HUDs easier, fixes visual issues with wide items, I need this for human rendering refactors. ## Changelog 🆑 refactor: Refactors inventory UI to be completely datum and vis_contents-based fix: Observers should no longer see doubled up inventory UIs /🆑 --------- Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
341 lines
11 KiB
Plaintext
341 lines
11 KiB
Plaintext
//These procs handle putting stuff in your hand. It's probably best to use these rather than setting stuff manually
|
|
//as they handle all relevant stuff like adding it to the player's screen and such
|
|
|
|
/**
|
|
* Returns the thing in our active hand (whatever is in our active module-slot, in this case)
|
|
*/
|
|
/mob/living/silicon/robot/get_active_held_item()
|
|
return module_active
|
|
|
|
/**
|
|
* Parent proc - triggers when an item/module is unequipped from a cyborg.
|
|
*/
|
|
/obj/item/proc/cyborg_unequip(mob/user)
|
|
return
|
|
|
|
/**
|
|
* Finds the first available slot and attemps to put item item_module in it.
|
|
*
|
|
* Arguments
|
|
* * item_module - the item being equipped to a slot.
|
|
*/
|
|
/mob/living/silicon/robot/proc/activate_module(obj/item/item_module)
|
|
if(QDELETED(item_module))
|
|
CRASH("activate_module called with improper item_module")
|
|
|
|
if(!(item_module in model.modules))
|
|
CRASH("activate_module called with item_module not in model.modules")
|
|
|
|
if(activated(item_module))
|
|
to_chat(src, span_warning("That module is already activated."))
|
|
return FALSE
|
|
|
|
if(disabled_modules & BORG_MODULE_ALL_DISABLED)
|
|
to_chat(src, span_warning("All modules are disabled!"))
|
|
return FALSE
|
|
|
|
/// What's the first free slot for the borg?
|
|
var/first_free_slot = !held_items[1] ? 1 : (!held_items[2] ? 2 : (!held_items[3] ? 3 : null))
|
|
|
|
if(!first_free_slot || is_invalid_module_number(first_free_slot))
|
|
to_chat(src, span_warning("Deactivate a module first!"))
|
|
return FALSE
|
|
|
|
return put_in_hand(item_module, first_free_slot)
|
|
|
|
/mob/living/silicon/robot/put_in_hand(obj/item/item_module, hand_index, forced = FALSE, ignore_anim = TRUE, visuals_only = FALSE)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
item_module.mouse_opacity = initial(item_module.mouse_opacity)
|
|
observer_screen_update(item_module)
|
|
|
|
///Helper for cyborgs unequipping things.
|
|
/mob/living/silicon/robot/proc/deactivate_module(obj/item/item_module)
|
|
return transferItemToLoc(item_module, newloc = model)
|
|
|
|
/mob/living/silicon/robot/doUnEquip(obj/item/item_dropping, force, atom/newloc, no_move, invdrop, silent)
|
|
//borgs can drop items that aren't part of the module (used for apparatus modules, the stored item isn't a module).
|
|
if(isnull(model) || !(item_dropping in model.modules))
|
|
return ..()
|
|
|
|
if(newloc != model)
|
|
to_chat(src, span_notice("You can't drop your [item_dropping.name] module."))
|
|
return FALSE
|
|
|
|
var/module_num = get_selected_module()
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
item_dropping.mouse_opacity = MOUSE_OPACITY_OPAQUE
|
|
//this is the cyborg equivalent of dropped(), though we call that too in doUnEquip.
|
|
item_dropping.cyborg_unequip(src)
|
|
deselect_module(module_num)
|
|
playsound_local(src, SFX_RUSTLE, 40, TRUE)
|
|
|
|
/mob/living/silicon/robot/put_in_hand_check(obj/item/item_equipping)
|
|
return (item_equipping in model.modules)
|
|
|
|
/**
|
|
* Breaks the slot number, changing the icon.
|
|
*
|
|
* Arguments
|
|
* * module_num - the slot number being repaired.
|
|
*/
|
|
/mob/living/silicon/robot/proc/break_cyborg_slot(module_num)
|
|
if(is_invalid_module_number(module_num, TRUE))
|
|
return FALSE
|
|
|
|
if(held_items[module_num]) //If there's a held item, unequip it first.
|
|
if(!deactivate_module(held_items[module_num])) //If we fail to unequip it, then don't continue
|
|
return FALSE
|
|
|
|
switch(module_num)
|
|
if(BORG_CHOOSE_MODULE_ONE)
|
|
if(disabled_modules & BORG_MODULE_ALL_DISABLED)
|
|
return FALSE
|
|
|
|
disabled_modules |= BORG_MODULE_ALL_DISABLED
|
|
|
|
playsound(src, 'sound/machines/warning-buzzer.ogg', 75, TRUE, TRUE)
|
|
audible_message(span_warning("[src] sounds an alarm! \"CRITICAL ERROR: ALL modules OFFLINE.\""))
|
|
|
|
if(builtInCamera)
|
|
builtInCamera.camera_enabled = FALSE
|
|
to_chat(src, span_userdanger("CRITICAL ERROR: Built in security camera OFFLINE."))
|
|
|
|
to_chat(src, span_userdanger("CRITICAL ERROR: ALL modules OFFLINE."))
|
|
|
|
if(BORG_CHOOSE_MODULE_TWO)
|
|
if(disabled_modules & BORG_MODULE_TWO_DISABLED)
|
|
return FALSE
|
|
|
|
disabled_modules |= BORG_MODULE_TWO_DISABLED
|
|
|
|
playsound(src, 'sound/machines/warning-buzzer.ogg', 60, TRUE, TRUE)
|
|
audible_message(span_warning("[src] sounds an alarm! \"SYSTEM ERROR: Module [module_num] OFFLINE.\""))
|
|
to_chat(src, span_userdanger("SYSTEM ERROR: Module [module_num] OFFLINE."))
|
|
|
|
if(BORG_CHOOSE_MODULE_THREE)
|
|
if(disabled_modules & BORG_MODULE_THREE_DISABLED)
|
|
return FALSE
|
|
|
|
disabled_modules |= BORG_MODULE_THREE_DISABLED
|
|
|
|
playsound(src, 'sound/machines/warning-buzzer.ogg', 50, TRUE, TRUE)
|
|
audible_message(span_warning("[src] sounds an alarm! \"SYSTEM ERROR: Module [module_num] OFFLINE.\""))
|
|
to_chat(src, span_userdanger("SYSTEM ERROR: Module [module_num] OFFLINE."))
|
|
|
|
var/atom/movable/screen/robot/module_slot/module = hud_used?.screen_objects[HUD_KEY_HAND_SLOT(module_num)]
|
|
if(module)
|
|
module.icon_state = "[module.base_icon_state] +b"
|
|
return TRUE
|
|
|
|
/**
|
|
* Breaks all of a cyborg's slots.
|
|
*/
|
|
/mob/living/silicon/robot/proc/break_all_cyborg_slots()
|
|
for(var/cyborg_slot in 1 to 3)
|
|
break_cyborg_slot(cyborg_slot)
|
|
|
|
/**
|
|
* Repairs the slot number, updating the icon.
|
|
*
|
|
* Arguments
|
|
* * module_num - the module number being repaired.
|
|
*/
|
|
/mob/living/silicon/robot/proc/repair_cyborg_slot(module_num)
|
|
if(is_invalid_module_number(module_num, TRUE))
|
|
return FALSE
|
|
|
|
switch(module_num)
|
|
if(BORG_CHOOSE_MODULE_ONE)
|
|
if(!(disabled_modules & BORG_MODULE_ALL_DISABLED))
|
|
return FALSE
|
|
|
|
disabled_modules &= ~BORG_MODULE_ALL_DISABLED
|
|
if(builtInCamera)
|
|
builtInCamera.camera_enabled = TRUE
|
|
to_chat(src, span_notice("You hear your built in security camera focus adjust as it comes back online!"))
|
|
|
|
if(BORG_CHOOSE_MODULE_TWO)
|
|
if(!(disabled_modules & BORG_MODULE_TWO_DISABLED))
|
|
return FALSE
|
|
|
|
disabled_modules &= ~BORG_MODULE_TWO_DISABLED
|
|
|
|
if(BORG_CHOOSE_MODULE_THREE)
|
|
if(!(disabled_modules & BORG_MODULE_THREE_DISABLED))
|
|
return FALSE
|
|
|
|
disabled_modules &= ~BORG_MODULE_THREE_DISABLED
|
|
|
|
to_chat(src, span_notice("ERROR CLEARED: Module [module_num] back online."))
|
|
var/atom/movable/screen/robot/module_slot/module = hud_used?.screen_objects[HUD_KEY_HAND_SLOT(module_num)]
|
|
if(module)
|
|
module.icon_state = module.base_icon_state
|
|
return TRUE
|
|
|
|
/**
|
|
* Repairs all slots. Unbroken slots are unaffected.
|
|
*/
|
|
/mob/living/silicon/robot/proc/repair_all_cyborg_slots()
|
|
for(var/cyborg_slot in 1 to 3)
|
|
repair_cyborg_slot(cyborg_slot)
|
|
|
|
/**
|
|
* Unequips the active held item, if there is one.
|
|
*/
|
|
/mob/living/silicon/robot/proc/uneq_active()
|
|
if(module_active)
|
|
deactivate_module(module_active)
|
|
|
|
// Technically none of the items are dropped, only unequipped
|
|
/mob/living/silicon/robot/drop_all_held_items()
|
|
for(var/cyborg_slot in 1 to length(held_items))
|
|
if(!held_items[cyborg_slot])
|
|
continue
|
|
deactivate_module(held_items[cyborg_slot])
|
|
|
|
/**
|
|
* Checks if the item is currently in a slot.
|
|
*
|
|
* If the item is found in a slot, this returns TRUE. Otherwise, it returns FALSE
|
|
* Arguments
|
|
* * item_module - the item being checked
|
|
*/
|
|
/mob/living/silicon/robot/proc/activated(obj/item/item_module)
|
|
if(item_module in held_items)
|
|
return TRUE
|
|
if(item_module.loc in held_items) //Apparatus check
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/**
|
|
* Checks if the provided module number is a valid number.
|
|
*
|
|
* If the number is between 1 and 3 (if check_all_slots is true) or between 1 and the number of disabled
|
|
* modules (if check_all_slots is false), then it returns FALSE. Otherwise, it returns TRUE.
|
|
* Arguments
|
|
* * module_num - the passed module num that is checked for validity.
|
|
* * check_all_slots - TRUE = the proc checks all slots | FALSE = the proc only checks un-disabled slots
|
|
*/
|
|
/mob/living/silicon/robot/proc/is_invalid_module_number(module_num, check_all_slots = FALSE)
|
|
if(!module_num)
|
|
return TRUE
|
|
|
|
/// The number of module slots we're checking
|
|
var/max_number = 3
|
|
if(!check_all_slots)
|
|
if(disabled_modules & BORG_MODULE_ALL_DISABLED)
|
|
max_number = 0
|
|
else if(disabled_modules & BORG_MODULE_TWO_DISABLED)
|
|
max_number = 1
|
|
else if(disabled_modules & BORG_MODULE_THREE_DISABLED)
|
|
max_number = 2
|
|
|
|
return module_num < 1 || module_num > max_number
|
|
|
|
/**
|
|
* Returns the slot number of the selected module, or zero if no modules are selected.
|
|
*/
|
|
/mob/living/silicon/robot/proc/get_selected_module()
|
|
if(module_active)
|
|
return held_items.Find(module_active)
|
|
return FALSE
|
|
|
|
/**
|
|
* Selects the module in the slot module_num.
|
|
* Arguments
|
|
* * module_num - the slot number being selected
|
|
*/
|
|
/mob/living/silicon/robot/proc/select_module(module_num)
|
|
if(is_invalid_module_number(module_num) || !held_items[module_num]) //If the slot number is invalid, or there's nothing there, we have nothing to equip
|
|
return FALSE
|
|
|
|
var/atom/movable/screen/robot/module_slot/module = hud_used?.screen_objects[HUD_KEY_HAND_SLOT(module_num)]
|
|
if(module && module_active != held_items[module_num])
|
|
module.icon_state = "[module.base_icon_state] +a"
|
|
module_active = held_items[module_num]
|
|
SEND_SIGNAL(module_active, COMSIG_SILICON_MODULE_ACTIVATION, TRUE)
|
|
return TRUE
|
|
|
|
/**
|
|
* Deselects the module in the slot module_num.
|
|
* Arguments
|
|
* * module_num - the slot number being de-selected
|
|
*/
|
|
/mob/living/silicon/robot/proc/deselect_module(module_num)
|
|
var/atom/movable/screen/robot/module_slot/module = hud_used?.screen_objects[HUD_KEY_HAND_SLOT(module_num)]
|
|
if(module)
|
|
module.icon_state = module.base_icon_state
|
|
if(module_active)
|
|
SEND_SIGNAL(module_active, COMSIG_SILICON_MODULE_ACTIVATION, FALSE)
|
|
module_active = null
|
|
return TRUE
|
|
|
|
/**
|
|
* Toggles selection of the module in the slot module_num.
|
|
* Arguments
|
|
* * module_num - the slot number being toggled
|
|
*/
|
|
/mob/living/silicon/robot/proc/toggle_module(module_num)
|
|
if(is_invalid_module_number(module_num))
|
|
return FALSE
|
|
|
|
if(module_num == get_selected_module())
|
|
deselect_module(module_num)
|
|
return TRUE
|
|
|
|
if(module_active != held_items[module_num])
|
|
deselect_module(get_selected_module())
|
|
|
|
return select_module(module_num)
|
|
|
|
/**
|
|
* Cycles through the list of enabled modules, deselecting the current one and selecting the next one.
|
|
*/
|
|
/mob/living/silicon/robot/proc/cycle_modules()
|
|
var/slot_start = get_selected_module()
|
|
var/slot_num
|
|
if(slot_start)
|
|
deselect_module(slot_start) //Only deselect if we have a selected slot.
|
|
slot_num = slot_start + 1
|
|
else
|
|
slot_num = 1
|
|
slot_start = 4
|
|
|
|
while(slot_num != slot_start) //If we wrap around without finding any free slots, just give up.
|
|
if(select_module(slot_num))
|
|
return
|
|
slot_num++
|
|
if(slot_num > 4) // not >3 otherwise cycling with just one item on module 3 wouldn't work
|
|
slot_num = 1 //Wrap around.
|
|
|
|
/mob/living/silicon/robot/perform_hand_swap()
|
|
cycle_modules()
|
|
return TRUE
|
|
|
|
/mob/living/silicon/robot/can_hold_items(obj/item/I)
|
|
return (I && (I in model.modules)) //Only if it's part of our model.
|
|
|
|
/**
|
|
* ## Please do not use
|
|
* Updates the observers's screens with cyborg items.
|
|
* Currently inventory code handling for observers is tied to carbon (get_held_overlays), meaning this snowflake code for borgs is
|
|
* necessary so observers watching borgs don't bug out. Once that's moved to the living, replace this with it.
|
|
* Removing from the screen is handled by 'doUnEquip'
|
|
* Arg:
|
|
* * item_module - the item being added to the screen.
|
|
*/
|
|
/mob/living/silicon/robot/proc/observer_screen_update(obj/item/item_module)
|
|
if(!observers?.len)
|
|
return
|
|
for(var/mob/dead/observe as anything in observers)
|
|
if(!observe.client || observe.client.eye != src)
|
|
observers -= observe
|
|
if(!observers.len)
|
|
observers = null
|
|
return
|
|
observe.client.screen += item_module
|