diff --git a/code/game/machinery/big_manipulator/big_manipulator.dm b/code/game/machinery/big_manipulator/big_manipulator.dm index 83ab74f9a03..eb78f7708a6 100644 --- a/code/game/machinery/big_manipulator/big_manipulator.dm +++ b/code/game/machinery/big_manipulator/big_manipulator.dm @@ -500,26 +500,26 @@ var/datum/manipulator_task/cargo/dropoff_base/use/t = task td["turf"] = "[t.offset_dx],[t.offset_dy]" td["filters_status"] = t.should_use_filters - td["filtering_mode"] = t.filtering_mode td["item_filters"] = _collect_filter_names(t.atom_filters) td["settings_list"] = _collect_priorities(t.interaction_priorities) td["worker_interaction"] = t.worker_interaction td["use_post_interaction"] = t.use_post_interaction td["worker_use_rmb"] = t.worker_use_rmb td["worker_combat_mode"] = t.worker_combat_mode + td["skip_anchored"] = t.skip_anchored else if(istype(task, /datum/manipulator_task/cargo/interact)) td["task_type"] = TASK_TYPE_INTERACT var/datum/manipulator_task/cargo/interact/t = task td["turf"] = "[t.offset_dx],[t.offset_dy]" td["filters_status"] = t.should_use_filters - td["filtering_mode"] = t.filtering_mode td["item_filters"] = _collect_filter_names(t.atom_filters) td["settings_list"] = _collect_priorities(t.interaction_priorities) td["worker_interaction"] = t.worker_interaction td["use_post_interaction"] = t.use_post_interaction td["worker_use_rmb"] = t.worker_use_rmb td["worker_combat_mode"] = t.worker_combat_mode + td["skip_anchored"] = t.skip_anchored else if(istype(task, /datum/manipulator_task/simple/wait)) td["task_type"] = TASK_TYPE_WAIT @@ -587,7 +587,10 @@ return TRUE if("unbuckle") - unbuckle_all_mobs() + var/mob/living/carbon/human/species/monkey/poor_monkey = monkey_worker?.resolve() + if(poor_monkey) + poor_monkey.drop_all_held_items() + poor_monkey.forceMove(get_turf(src)) monkey_worker = null return TRUE @@ -812,6 +815,8 @@ return TRUE if("cycle_filtering_mode") + if(istype(target_task, /datum/manipulator_task/cargo/dropoff_base/use) || istype(target_task, /datum/manipulator_task/cargo/interact)) + return FALSE if(!istype(target_task, /datum/manipulator_task/cargo)) return FALSE var/datum/manipulator_task/cargo/ct = target_task @@ -897,6 +902,17 @@ return TRUE return FALSE + if("toggle_skip_anchored") + if(istype(target_task, /datum/manipulator_task/cargo/dropoff_base/use)) + var/datum/manipulator_task/cargo/dropoff_base/use/unanchor_target = target_task + unanchor_target.skip_anchored = !unanchor_target.skip_anchored + return TRUE + if(istype(target_task, /datum/manipulator_task/cargo/interact)) + var/datum/manipulator_task/cargo/interact/unanchor_target = target_task + unanchor_target.skip_anchored = !unanchor_target.skip_anchored + return TRUE + return FALSE + /// Cycles the given value in the given list. /obj/machinery/big_manipulator/proc/cycle_value(current_value, list/possible_values) var/current_index = possible_values.Find(current_value) diff --git a/code/game/machinery/big_manipulator/big_manipulator_interactions.dm b/code/game/machinery/big_manipulator/big_manipulator_interactions.dm index 01500efdd5a..e5f7c361330 100644 --- a/code/game/machinery/big_manipulator/big_manipulator_interactions.dm +++ b/code/game/machinery/big_manipulator/big_manipulator_interactions.dm @@ -137,14 +137,18 @@ return FALSE var/obj/item/held_item = obj_resolve - var/atom/type_to_use = destination_task.find_type_priority() + var/atom/type_to_use = destination_task.find_type_priority(destination_task.skip_anchored) if(isnull(type_to_use)) - check_for_cycle_end_drop(destination_task, FALSE, work_done_at_point) + drop_held_after_use(destination_task) return FALSE if(isitem(type_to_use) && !destination_task.check_filters_for_atom(type_to_use)) - check_for_cycle_end_drop(destination_task, FALSE, work_done_at_point) + drop_held_after_use(destination_task) + return FALSE + + if(istype(destination_task, /datum/manipulator_task/cargo/interact) && destination_task.should_use_filters && isitem(type_to_use) && !destination_task.check_filters_for_atom(type_to_use)) + drop_held_after_use(destination_task) return FALSE var/original_loc = held_item.loc @@ -153,9 +157,10 @@ if(held_item.GetComponent(/datum/component/two_handed)) held_item.attack_self(monkey_resolve) + var/old_combat_mode = monkey_resolve.combat_mode monkey_resolve.combat_mode = destination_task.worker_combat_mode held_item.melee_attack_chain(monkey_resolve, type_to_use, list(RIGHT_CLICK = destination_task.worker_use_rmb ? TRUE : FALSE)) - monkey_resolve.combat_mode = FALSE + monkey_resolve.combat_mode = old_combat_mode do_attack_animation(destination_turf) manipulator_arm.do_attack_animation(destination_turf) @@ -217,7 +222,7 @@ obj_resolve.dir = get_dir(get_turf(obj_resolve), get_turf(src)) finish_manipulation() else - schedule_next_cycle() + addtimer(CALLBACK(src, PROC_REF(try_use_thing), destination_task, TRUE), BASE_INTERACTION_TIME * 2) /obj/machinery/big_manipulator/proc/throw_thing(datum/manipulator_task/cargo/dropoff_base/throw/throw_task) var/drop_turf = throw_task.interaction_turf @@ -241,21 +246,19 @@ finish_manipulation() return - var/atom/type_to_use = destination_task.find_type_priority() + var/atom/type_to_use = destination_task.find_type_priority(destination_task.skip_anchored) if(isnull(type_to_use)) check_end_of_use_for_use_with_empty_hand(destination_task, FALSE) return - if(isitem(type_to_use)) - var/obj/item/interact_with_item = type_to_use - var/resolve_loc = interact_with_item.loc - monkey_resolve.put_in_active_hand(interact_with_item) - interact_with_item.attack_self(monkey_resolve) - interact_with_item.forceMove(resolve_loc) - else - monkey_resolve.combat_mode = destination_task.worker_combat_mode - monkey_resolve.UnarmedAttack(type_to_use) - monkey_resolve.combat_mode = FALSE + if(destination_task.should_use_filters && isitem(type_to_use) && !destination_task.check_filters_for_atom(type_to_use)) + check_end_of_use_for_use_with_empty_hand(destination_task, FALSE) + return + + var/old_combat_mode = monkey_resolve.combat_mode + monkey_resolve.combat_mode = destination_task.worker_combat_mode + monkey_resolve.UnarmedAttack(type_to_use, modifiers = list(RIGHT_CLICK = destination_task.worker_use_rmb ? TRUE : FALSE)) + monkey_resolve.combat_mode = old_combat_mode var/turf/dest_turf = destination_task.interaction_turf if(dest_turf) @@ -277,6 +280,10 @@ /// Completes the current manipulation action and schedules the next step. /obj/machinery/big_manipulator/proc/finish_manipulation() + if(held_object) + var/obj/resolved = held_object.resolve() + if(resolved && resolved.loc == src) + resolved.forceMove(drop_location()) held_object = null manipulator_arm.update_claw(null) current_task = null diff --git a/code/game/machinery/big_manipulator/manipulator_tasks.dm b/code/game/machinery/big_manipulator/manipulator_tasks.dm index 48a136ff255..00fe1271577 100644 --- a/code/game/machinery/big_manipulator/manipulator_tasks.dm +++ b/code/game/machinery/big_manipulator/manipulator_tasks.dm @@ -100,7 +100,7 @@ /datum/manipulator_task/cargo/proc/fill_priority_list(manipulator_tier) return list() -/datum/manipulator_task/cargo/proc/find_type_priority() +/datum/manipulator_task/cargo/proc/find_type_priority(skip_anchored = FALSE) var/atom/movable/best_candidate = null var/best_priority_index = INFINITY @@ -117,6 +117,9 @@ if(!istype(thing, prio.atom_typepath)) continue + if(skip_anchored && thing.anchored) + continue + if(isliving(thing)) var/mob/living/living_mob = thing if(living_mob.stat == DEAD) @@ -299,12 +302,16 @@ return FALSE return TRUE -/datum/manipulator_task/cargo/dropoff_base/can_run(obj/machinery/big_manipulator/manipulator) +/datum/manipulator_task/cargo/dropoff_base/use/can_run(obj/machinery/big_manipulator/manipulator) if(!..()) return FALSE var/atom/movable/target = manipulator.held_object?.resolve() if(!target) return FALSE + if(!manipulator.monkey_worker?.resolve()) + return FALSE + if(!find_type_priority(skip_anchored)) + return FALSE return can_accept(target) /datum/manipulator_task/cargo/dropoff_base/run_task(obj/machinery/big_manipulator/manipulator) @@ -409,6 +416,7 @@ var/use_post_interaction = POST_INTERACTION_DROP_AT_POINT var/worker_combat_mode = FALSE var/worker_use_rmb = FALSE + var/skip_anchored = FALSE /datum/manipulator_task/cargo/dropoff_base/use/fill_priority_list(manipulator_tier) var/list/priorities = list( @@ -434,6 +442,7 @@ data["use_post_interaction"] = use_post_interaction data["worker_combat_mode"] = worker_combat_mode data["worker_use_rmb"] = worker_use_rmb + data["skip_anchored"] = skip_anchored return data /datum/manipulator_task/cargo/dropoff_base/use/New(turf/new_turf, manipulator_tier, serialized_data) @@ -443,6 +452,7 @@ use_post_interaction = serialized_data["use_post_interaction"] worker_combat_mode = !!serialized_data["worker_combat_mode"] worker_use_rmb = !!serialized_data["worker_use_rmb"] + skip_anchored = !!serialized_data["skip_anchored"] return /datum/manipulator_task/cargo/dropoff_base/use/do_dropoff(obj/machinery/big_manipulator/manipulator) @@ -456,6 +466,7 @@ var/use_post_interaction = POST_INTERACTION_DROP_AT_POINT var/worker_combat_mode = FALSE var/worker_use_rmb = FALSE + var/skip_anchored = FALSE /datum/manipulator_task/cargo/interact/fill_priority_list(manipulator_tier) var/list/priorities = list( @@ -482,6 +493,7 @@ data["use_post_interaction"] = use_post_interaction data["worker_combat_mode"] = worker_combat_mode data["worker_use_rmb"] = worker_use_rmb + data["skip_anchored"] = skip_anchored return data /datum/manipulator_task/cargo/interact/New(turf/new_turf, manipulator_tier, serialized_data) @@ -491,11 +503,15 @@ use_post_interaction = serialized_data["use_post_interaction"] worker_combat_mode = !!serialized_data["worker_combat_mode"] worker_use_rmb = !!serialized_data["worker_use_rmb"] + skip_anchored = !!serialized_data["skip_anchored"] return /datum/manipulator_task/cargo/interact/proc/try_interact(obj/machinery/big_manipulator/manipulator) var/atom/movable/held = manipulator.held_object?.resolve() if(held) + if(!manipulator.monkey_worker?.resolve()) + manipulator.nothing_ever_happens() + return manipulator.try_use_thing(src) else manipulator.use_thing_with_empty_hand(src) diff --git a/code/game/machinery/big_manipulator/tasking.dm b/code/game/machinery/big_manipulator/tasking.dm index cc91434363e..65d355c0b23 100644 --- a/code/game/machinery/big_manipulator/tasking.dm +++ b/code/game/machinery/big_manipulator/tasking.dm @@ -13,6 +13,8 @@ // Moves through the list, skipping tasks that can't run. /datum/tasking_strategy/sequential + /// Separate index for candidate selection to avoid corrupting the task index. + var/candidate_index = 1 /datum/tasking_strategy/sequential/get_next_task(list/tasks, obj/machinery/big_manipulator/manipulator) if(!length(tasks)) @@ -33,16 +35,18 @@ /datum/tasking_strategy/sequential/get_next_candidate(list/candidates) if(!length(candidates)) return null - if(current_index < 1 || current_index > length(candidates)) - current_index = 1 - var/candidate = candidates[current_index] - current_index++ - if(current_index > length(candidates)) - current_index = 1 + if(candidate_index < 1 || candidate_index > length(candidates)) + candidate_index = 1 + var/candidate = candidates[candidate_index] + candidate_index++ + if(candidate_index > length(candidates)) + candidate_index = 1 return candidate // Stays on the current task until it can run. /datum/tasking_strategy/strict + /// Separate index for candidate selection to avoid corrupting the task index. + var/candidate_index = 1 /datum/tasking_strategy/strict/get_next_task(list/tasks, obj/machinery/big_manipulator/manipulator) if(!length(tasks)) @@ -60,10 +64,10 @@ /datum/tasking_strategy/strict/get_next_candidate(list/candidates) if(!length(candidates)) return null - if(current_index < 1 || current_index > length(candidates)) - current_index = 1 - var/candidate = candidates[current_index] - current_index++ - if(current_index > length(candidates)) - current_index = 1 + if(candidate_index < 1 || candidate_index > length(candidates)) + candidate_index = 1 + var/candidate = candidates[candidate_index] + candidate_index++ + if(candidate_index > length(candidates)) + candidate_index = 1 return candidate diff --git a/tgui/packages/tgui/interfaces/BigManipulator/index.tsx b/tgui/packages/tgui/interfaces/BigManipulator/index.tsx index 144e9d3e94c..e56d1dd431f 100644 --- a/tgui/packages/tgui/interfaces/BigManipulator/index.tsx +++ b/tgui/packages/tgui/interfaces/BigManipulator/index.tsx @@ -173,7 +173,7 @@ function TaskEditModal(props: TaskEditModalProps) { const isCargo = !!task.turf; const isPickup = task.task_type.includes('pickup'); - const isDropoff = task.task_type.includes('dropoff'); + const isDropoff = task.task_type === 'drop' || task.task_type === 'throw' || task.task_type === 'use'; const isInteract = task.task_type.includes('interact'); const currentButton = task.turf @@ -236,12 +236,16 @@ function TaskEditModal(props: TaskEditModalProps) { - adjust('cycle_filtering_mode')} - tooltip="Cycle object category" - /> + {(task.task_type === 'pickup' || + task.task_type === 'drop' || + task.task_type === 'throw') && ( + adjust('cycle_filtering_mode')} + tooltip="Cycle object category" + /> + )} - adjust('cycle_interaction_mode')} - tooltip="Drop / Throw / Use" - /> - adjust('cycle_overflow_status')} - tooltip="Cycle overflow behaviour" - /> - {task.interaction_mode?.toUpperCase() === 'THROW' && ( + {task.task_type === 'drop' && ( + adjust('cycle_overflow_status')} + tooltip="Cycle overflow behaviour" + /> + )} + {task.task_type === 'throw' && ( )} - {(isDropoff || isInteract) && task.interaction_mode?.toUpperCase() !== 'THROW' && ( + {(task.task_type === 'use' || isInteract) && ( <> adjust('toggle_worker_combat')} tooltip="Use combat mode during interaction" /> + adjust('toggle_skip_anchored')} + tooltip="Skip anchored objects when looking for interaction targets" + />