fix: misc Big Manipulator bug fixes (#96374)

This commit is contained in:
mcbalaam
2026-06-09 13:47:03 +02:00
committed by GitHub
parent b08ec39e1b
commit 516e13d836
6 changed files with 105 additions and 55 deletions
@@ -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)
@@ -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
@@ -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)
+16 -12
View File
@@ -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
@@ -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) {
</Stack.Item>
<Stack.Item grow>
<Table>
<ConfigRow
label="Object Type"
content={getFilteringModeText(task.filtering_mode ?? 1)}
onClick={() => adjust('cycle_filtering_mode')}
tooltip="Cycle object category"
/>
{(task.task_type === 'pickup' ||
task.task_type === 'drop' ||
task.task_type === 'throw') && (
<ConfigRow
label="Object Type"
content={getFilteringModeText(task.filtering_mode ?? 1)}
onClick={() => adjust('cycle_filtering_mode')}
tooltip="Cycle object category"
/>
)}
<ConfigRow
label="Use Filters"
content={task.filters_status ? 'TRUE' : 'FALSE'}
@@ -258,19 +262,15 @@ function TaskEditModal(props: TaskEditModalProps) {
)}
{isDropoff && (
<>
<ConfigRow
label="Mode"
content={(task.interaction_mode ?? '').toUpperCase()}
onClick={() => adjust('cycle_interaction_mode')}
tooltip="Drop / Throw / Use"
/>
<ConfigRow
label="Overflow"
content={task.overflow_status ?? '—'}
onClick={() => adjust('cycle_overflow_status')}
tooltip="Cycle overflow behaviour"
/>
{task.interaction_mode?.toUpperCase() === 'THROW' && (
{task.task_type === 'drop' && (
<ConfigRow
label="Overflow"
content={task.overflow_status ?? '—'}
onClick={() => adjust('cycle_overflow_status')}
tooltip="Cycle overflow behaviour"
/>
)}
{task.task_type === 'throw' && (
<ConfigRow
label="Throw Range"
content={`${task.throw_range} TILES`}
@@ -280,7 +280,7 @@ function TaskEditModal(props: TaskEditModalProps) {
)}
</>
)}
{(isDropoff || isInteract) && task.interaction_mode?.toUpperCase() !== 'THROW' && (
{(task.task_type === 'use' || isInteract) && (
<>
<ConfigRow
label="Worker Action"
@@ -300,6 +300,12 @@ function TaskEditModal(props: TaskEditModalProps) {
onClick={() => adjust('toggle_worker_combat')}
tooltip="Use combat mode during interaction"
/>
<ConfigRow
label="Skip Anchored"
content={task.skip_anchored ? 'TRUE' : 'FALSE'}
onClick={() => adjust('toggle_skip_anchored')}
tooltip="Skip anchored objects when looking for interaction targets"
/>
<ConfigRow
label="No Uses Left"
content={task.use_post_interaction ?? '—'}
@@ -33,8 +33,9 @@ export interface ManipulatorTask {
use_post_interaction?: string;
worker_use_rmb?: BooleanLike;
worker_combat_mode?: BooleanLike;
skip_anchored?: BooleanLike;
// interact only
// (worker_interaction, use_post_interaction, worker_use_rmb, worker_combat_mode shared with dropoff)
// (worker_interaction, use_post_interaction, worker_use_rmb, worker_combat_mode, skip_anchored shared with dropoff)
time?: number;
}