diff --git a/code/datums/components/shell.dm b/code/datums/components/shell.dm index 2e9ee73c32a..bb3054aea6a 100644 --- a/code/datums/components/shell.dm +++ b/code/datums/components/shell.dm @@ -173,7 +173,7 @@ if(istype(item, /obj/item/inducer)) var/obj/item/inducer/inducer = item - INVOKE_ASYNC(inducer, TYPE_PROC_REF(/obj/item, attack_atom), attached_circuit || parent, attacker, list()) + INVOKE_ASYNC(inducer, TYPE_PROC_REF(/obj/item, interact_with_atom), attached_circuit || parent, attacker, list()) return COMPONENT_NO_AFTERATTACK if(attached_circuit) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index b0530b1595e..742e15e19d7 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1641,8 +1641,14 @@ /* End language procs */ -//Returns an atom's power cell, if it has one. Overload for individual items. -/atom/movable/proc/get_cell() +/** + * Returns an atom's power cell, if it has one. Overload for individual items. + * Args + * + * * /atom/movable/interface - the atom that is trying to interact with this cell + * * mob/user - the mob that is holding the interface + */ +/atom/movable/proc/get_cell(atom/movable/interface, mob/user) return /atom/movable/proc/can_be_pulled(user, grab_state, force) diff --git a/code/game/objects/items/inducer.dm b/code/game/objects/items/inducer.dm index 2404974d699..0f66cd4b6d1 100644 --- a/code/game/objects/items/inducer.dm +++ b/code/game/objects/items/inducer.dm @@ -7,212 +7,219 @@ lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' force = 7 + /// Multiplier that determines the speed at which this inducer works at. var/power_transfer_multiplier = 1 + /// Is the battery hatch opened var/opened = FALSE - var/cell_type = /obj/item/stock_parts/power_store/battery/high - var/obj/item/stock_parts/power_store/powerdevice + /// The cell for used in recharging cycles + var/obj/item/stock_parts/power_store/powerdevice = /obj/item/stock_parts/power_store/battery/high + /// Are we in the process of recharging something var/recharging = FALSE /obj/item/inducer/Initialize(mapload) . = ..() - if(!powerdevice && cell_type) - powerdevice = new cell_type -/obj/item/inducer/proc/induce(obj/item/stock_parts/power_store/target, coefficient) - var/obj/item/stock_parts/power_store/our_cell = get_cell() - var/rating_base = target.rating_base - var/totransfer = min(our_cell.charge, (rating_base * coefficient * power_transfer_multiplier)) - var/transferred = target.give(totransfer) + if(ispath(powerdevice)) + powerdevice = new powerdevice(src) - our_cell.use(transferred) - our_cell.update_appearance() - target.update_appearance() + register_context() + + update_appearance(UPDATE_OVERLAYS) + +/obj/item/inducer/Destroy(force) + QDEL_NULL(powerdevice) + . = ..() + +/obj/item/inducer/Exited(atom/movable/gone, direction) + . = ..() + if(gone == powerdevice) + powerdevice = null + +/obj/item/inducer/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = NONE + + if(isnull(held_item)) + if(opened && !QDELETED(powerdevice)) + context[SCREENTIP_CONTEXT_LMB] = "Remove Cell" + . = CONTEXTUAL_SCREENTIP_SET + return + + if(opened) + if(istype(held_item, /obj/item/stock_parts/power_store) && QDELETED(powerdevice)) + context[SCREENTIP_CONTEXT_LMB] = "Insert cell" + return CONTEXTUAL_SCREENTIP_SET + + if(istype(held_item, /obj/item/stack/sheet/mineral/plasma) && !QDELETED(powerdevice)) + context[SCREENTIP_CONTEXT_LMB] = "Charge cell" + return CONTEXTUAL_SCREENTIP_SET + + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "[opened ? "Close" : "Open"] Panel" + return CONTEXTUAL_SCREENTIP_SET + +/obj/item/inducer/examine(mob/living/user) + . = ..() + + if(!QDELETED(powerdevice)) + . += span_notice("Its display shows: [display_energy(powerdevice.charge)].") + if(opened) + . += span_notice("The cell can be removed with an empty hand.") + . += span_notice("Plasma sheets can be used to recharge the cell.") + else + . += span_warning("It's missing a power cell.") + + . += span_notice("Its battery compartment can be [EXAMINE_HINT("screwed")] [opened ? "shut" : "open"].") + +/obj/item/inducer/update_overlays() + . = ..() + if(!opened) + return + . += "inducer-[!QDELETED(powerdevice) ? "bat" : "nobat"]" /obj/item/inducer/get_cell() return powerdevice /obj/item/inducer/emp_act(severity) . = ..() - var/obj/item/stock_parts/power_store/our_cell = get_cell() - if(!isnull(our_cell) && !(. & EMP_PROTECT_CONTENTS)) - our_cell.emp_act(severity) - -/obj/item/inducer/attack_atom(obj/target, mob/living/carbon/user, params) - if(user.combat_mode) - return ..() - - if(cantbeused(user)) - return - - if(recharge(target, user)) - return - - return ..() - -/obj/item/inducer/proc/cantbeused(mob/user) - if(!ISADVANCEDTOOLUSER(user)) - to_chat(user, span_warning("You don't have the dexterity to use [src]!")) - return TRUE - - var/obj/item/stock_parts/power_store/our_cell = get_cell() - - if(isnull(our_cell)) - balloon_alert(user, "no cell installed!") - return TRUE - - if(!our_cell.charge) - balloon_alert(user, "no charge!") - return TRUE - return FALSE + if(!QDELETED(powerdevice) && !(. & EMP_PROTECT_CONTENTS)) + powerdevice.emp_act(severity) /obj/item/inducer/screwdriver_act(mob/living/user, obj/item/tool) - . = TRUE - tool.play_tool_sound(src) + . = NONE + + if(!tool.use_tool(src, user, delay = 0)) + return + + opened = !opened + to_chat(user, span_notice("You [opened ? "open" : "close"] the battery compartment.")) + update_appearance(UPDATE_OVERLAYS) + + return ITEM_INTERACT_SUCCESS + +/obj/item/inducer/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = NONE + if(user.combat_mode || !istype(tool) || tool.flags_1 & HOLOGRAM_1 || tool.item_flags & ABSTRACT) + return ITEM_INTERACT_SKIP_TO_ATTACK + if(!opened) - to_chat(user, span_notice("You unscrew the battery compartment.")) - opened = TRUE - update_appearance() - return - else - to_chat(user, span_notice("You close the battery compartment.")) - opened = FALSE - update_appearance() - return + balloon_alert(user, "open first!") + return ITEM_INTERACT_FAILURE -/obj/item/inducer/attackby(obj/item/used_item, mob/user) - var/obj/item/stock_parts/power_store/our_cell = get_cell() - if(istype(used_item, /obj/item/stock_parts/power_store)) - if(opened) - if(isnull(our_cell)) - if(!user.transferItemToLoc(used_item, src)) - return - to_chat(user, span_notice("You insert [used_item] into [src].")) - powerdevice = used_item - update_appearance() - return - else - to_chat(user, span_warning("[src] already has \a [our_cell] installed!")) - return + if(istype(tool, /obj/item/stock_parts/power_store)) + if(!QDELETED(powerdevice)) + balloon_alert(user, "cell already installed!") + return ITEM_INTERACT_FAILURE - if (istype(used_item, /obj/item/stack/sheet/mineral/plasma) && !isnull(our_cell)) - if(our_cell.charge == our_cell.maxcharge) - balloon_alert(user, "already fully charged!") - return - used_item.use(1) - our_cell.give(1.5 * STANDARD_CELL_CHARGE) + if(!user.transferItemToLoc(tool, src)) + balloon_alert(user, "stuck in hand!") + return ITEM_INTERACT_FAILURE + + powerdevice = tool + return ITEM_INTERACT_SUCCESS + + if(istype(tool, /obj/item/stack/sheet/mineral/plasma) && !QDELETED(powerdevice)) + if(!powerdevice.used_charge()) + balloon_alert(user, "fully charged!") + return ITEM_INTERACT_FAILURE + + tool.use(1) + powerdevice.give(1.5 * STANDARD_CELL_CHARGE) balloon_alert(user, "cell recharged") - return - if(cantbeused(user)) - return + return ITEM_INTERACT_SUCCESS - if(recharge(used_item, user)) - return +/obj/item/inducer/interact_with_atom(atom/movable/interacting_with, mob/living/user, list/modifiers) + . = NONE + if(user.combat_mode || !istype(interacting_with) || interacting_with.flags_1 & HOLOGRAM_1) + return ITEM_INTERACT_SKIP_TO_ATTACK - return ..() + //basic checks + if(opened) + balloon_alert(user, "close first!") + return ITEM_INTERACT_FAILURE -/obj/item/inducer/proc/recharge(atom/movable/target, mob/user) - if(!isturf(target) && user.loc == target) - return FALSE - if(recharging) - return TRUE + if(recharging || (!isturf(interacting_with) && user.loc == interacting_with)) + return ITEM_INTERACT_FAILURE + if(!ISADVANCEDTOOLUSER(user)) + to_chat(user, span_warning("You don't have the dexterity to use [src]!")) + return ITEM_INTERACT_FAILURE + + if(QDELETED(powerdevice)) + balloon_alert(user, "no cell installed!") + return ITEM_INTERACT_FAILURE + + if(!powerdevice.charge) + balloon_alert(user, "no charge!") + return ITEM_INTERACT_FAILURE + + var/obj/item/stock_parts/power_store/target_cell = interacting_with.get_cell(src, user) + + if(QDELETED(target_cell)) + return ITEM_INTERACT_FAILURE + + if(!target_cell.used_charge()) + balloon_alert(user, "fully charged!") + return ITEM_INTERACT_FAILURE + + //begin recharging recharging = TRUE - var/obj/item/stock_parts/power_store/our_cell = get_cell() - var/obj/item/stock_parts/power_store/target_cell = target.get_cell() - var/obj/target_as_object = target - var/coefficient = 1 + user.visible_message(span_notice("[user] starts recharging [interacting_with] with [src]."), span_notice("You start recharging [interacting_with] with [src].")) - if(istype(target, /obj/item/gun/energy) || istype(target, /obj/item/clothing/suit/space)) - to_chat(user, span_alert("Error: unable to interface with device.")) - return FALSE + var/done_any = FALSE + while(target_cell.used_charge()) + if(!do_after(user, 1 SECONDS, target = user)) + break - if(target_cell) - var/done_any = FALSE - if(target_cell.charge >= target_cell.maxcharge) - balloon_alert(user, "it's fully charged!") - recharging = FALSE - return TRUE + //transfer of charge + var/transferred = min(powerdevice.charge, target_cell.used_charge(), (target_cell.rating_base * target_cell.rating * power_transfer_multiplier)) + if(!transferred) + break + powerdevice.use(target_cell.give(transferred)) - user.visible_message(span_notice("[user] starts recharging [target] with [src]."), span_notice("You start recharging [target] with [src].")) + //update all appearances + powerdevice.update_appearance() + target_cell.update_appearance() + interacting_with.update_appearance() + + //sparks & update + do_sparks(1, FALSE, interacting_with) + done_any = TRUE - while(target_cell.charge < target_cell.maxcharge) - if(do_after(user, 1 SECONDS, target = user) && our_cell.charge) - done_any = TRUE - induce(target_cell, coefficient) - do_sparks(1, FALSE, target) - if(istype(target_as_object)) - target_as_object.update_appearance() - else - break - if(done_any) // Only show a message if we succeeded at least once - user.visible_message(span_notice("[user] recharged [target]!"), span_notice("You recharged [target]!")) - recharging = FALSE - return TRUE recharging = FALSE + // Only show a message if we succeeded at least once + if(done_any) + user.visible_message(span_notice("[user] recharges [interacting_with]!"), span_notice("You recharge [interacting_with]!")) -/obj/item/inducer/attack(mob/target, mob/living/user) - if(user.combat_mode) - return ..() - - if(cantbeused(user)) - return - - if(recharge(target, user)) - return - - return ..() - + return ITEM_INTERACT_SUCCESS /obj/item/inducer/attack_self(mob/user) - if(opened && powerdevice) + if(opened && !QDELETED(powerdevice)) user.visible_message(span_notice("[user] removes [powerdevice] from [src]!"), span_notice("You remove [powerdevice].")) powerdevice.update_appearance() user.put_in_hands(powerdevice) - powerdevice = null - update_appearance() - - -/obj/item/inducer/examine(mob/living/user) - . = ..() - var/obj/item/stock_parts/power_store/our_cell = get_cell() - if(!isnull(our_cell)) - . += span_notice("Its display shows: [display_energy(our_cell.charge)].") - else - . += span_notice("Its display is dark.") - if(opened) - . += span_notice("Its battery compartment is open.") - -/obj/item/inducer/update_overlays() - . = ..() - if(!opened) - return - . += "inducer-[!isnull(get_cell()) ? "bat" : "nobat"]" + update_appearance(UPDATE_OVERLAYS) /obj/item/inducer/empty - cell_type = null + powerdevice = null opened = TRUE /obj/item/inducer/orderable - cell_type = /obj/item/stock_parts/power_store/battery/upgraded + powerdevice = /obj/item/stock_parts/power_store/battery/upgraded opened = FALSE /obj/item/inducer/sci icon_state = "inducer-sci" inhand_icon_state = "inducer-sci" desc = "A tool for inductively charging internal power cells. This one has a science color scheme, and is less potent than its engineering counterpart." - cell_type = null + powerdevice = null opened = TRUE -/obj/item/inducer/sci/Initialize(mapload) - . = ..() - update_appearance() - /obj/item/inducer/syndicate icon_state = "inducer-syndi" inhand_icon_state = "inducer-syndi" desc = "A tool for inductively charging internal power cells. This one has a suspicious colour scheme, and seems to be rigged to transfer charge at a much faster rate." power_transfer_multiplier = 2 // 2x the base speed - cell_type = /obj/item/stock_parts/power_store/cell/super + powerdevice = /obj/item/stock_parts/power_store/battery/super diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index e4afe968fa1..5201d90c5f8 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -651,7 +651,7 @@ name = "Internal inducer" icon = 'icons/obj/tools.dmi' icon_state = "inducer-engi" - cell_type = null + powerdevice = null /obj/item/inducer/cyborg/get_cell() var/obj/item/robot_model/possible_model = loc @@ -660,7 +660,7 @@ . = silicon_friend.cell /obj/item/inducer/cyborg/screwdriver_act(mob/living/user, obj/item/tool) - return FALSE + return NONE /obj/item/borg/upgrade/pinpointer name = "medical cyborg crew pinpointer" diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm index 62d9e0adf50..fea48d13d37 100644 --- a/code/modules/clothing/spacesuits/_spacesuits.dm +++ b/code/modules/clothing/spacesuits/_spacesuits.dm @@ -167,7 +167,10 @@ thermal_on = FALSE // support for items that interact with the cell -/obj/item/clothing/suit/space/get_cell() +/obj/item/clothing/suit/space/get_cell(atom/movable/interface, mob/user) + if(istype(interface, /obj/item/inducer)) + to_chat(user, span_alert("Error: unable to interface with [interface].")) + return null return cell // Show the status of the suit and the cell diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 05d25cc2892..43d9712d271 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -77,7 +77,10 @@ recharge_newshot() //and try to charge a new shot update_appearance() -/obj/item/gun/energy/get_cell() +/obj/item/gun/energy/get_cell(atom/movable/interface, mob/user) + if(istype(interface, /obj/item/inducer)) + to_chat(user, span_alert("Error: unable to interface with [interface].")) + return null return cell /obj/item/gun/energy/Initialize(mapload)