mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-25 08:34:23 +00:00
## About The Pull Request Ok so tracking (from the datum) worked, but when used to follow someone it had a noticable delay from the datum needing to wait for process to fire to do its work This would be an expensive proc to run constantly, but we don't really have to (there are not that many ai eyes in the world). So rather then only processing to keep step, let's track the target mob by its movement, and then fall back on a process loop to handle rechecking in case of camera memes. This does technically mean you won't "break" the track if the cameras go out until the tracked mob moves, but I think that's a reasonable price to pay for more responsive movement. I think I could make our current system work with it too, though it would be a bit more wasteful. John if you have opinions just lay into me. I've also renamed/pulled apart the helper procs for the trackable datum, with the hope of making how they are used more understandable at a glance Oh and rather then holding a weakref since I needed MOVED anyway I just use QDELETING to free the ref if the mob goes away ### Edit: #### Glide size touchups Implements glide size mirroring so we move at the same speed as our target Also moves the existing signal to send to the trackable datum itself, as appears intended from the doc comment #### AI behavior changes Rewrites ai movement to be less dumb OK so 2 things here. One is a behavior change, the other is a visual QOL thing. The way ai movement works is we move graduated "steps". Either moving 1, 2, or 3 steps per tick. We do this by, so long as input is held down, incrementing a number called "sprint" Currently it'll go from 10 to 50 (formula effectively looks like steps = (sprint / 20) + 1)) Anyway, this is... not fine but ok, but the way we handle deceleration is ass IMO. It's literally just wait 0.5 seconds and sprint resets. I think this feels crummy, so instead I've made it decay depending on how long you go between inputs, at 7x greater rate then it increases. That's the behavior change. Visual change is a lot easier. Ais were not gliding properly. They assumed they had 4 ticks to move a tile, rather then 1. This meant they'd jump around constantly, to catch up to where we expect them to be. I've fixed this by giving them 1 tick instead. Should feel a lot better ## Why It's Good For The Game Snappier response times, cleaner code ## Changelog 🆑 add: AI's acceleration now smoothly decays, instead of just falling back down to 0 after 0.5 seconds fix: AI's standard movement (non accelerated) is smooth now, instead of constantly jumping around fix: AIs will now follow their targets more closely, shouldn't have any issues with them lagging behind anymore /🆑
270 lines
6.9 KiB
Plaintext
270 lines
6.9 KiB
Plaintext
/*
|
|
AI ClickOn()
|
|
|
|
The AI can double click to move the camera (this was already true but is cleaner),
|
|
or double click a mob to track them.
|
|
|
|
Note that AI have no need for the adjacency proc, and so this proc is a lot cleaner.
|
|
*/
|
|
/mob/living/silicon/ai/DblClickOn(atom/A, params)
|
|
if(control_disabled || incapacitated())
|
|
return
|
|
|
|
if(ismob(A))
|
|
ai_tracking_tool.track_mob(src, A)
|
|
else
|
|
A.move_camera_by_click()
|
|
|
|
/mob/living/silicon/ai/ClickOn(atom/A, params)
|
|
if(world.time <= next_click)
|
|
return
|
|
next_click = world.time + 1
|
|
|
|
var/list/modifiers = params2list(params)
|
|
|
|
if(SEND_SIGNAL(src, COMSIG_MOB_CLICKON, A, modifiers) & COMSIG_MOB_CANCEL_CLICKON)
|
|
return
|
|
|
|
if(!can_interact_with(A))
|
|
return
|
|
|
|
if(multicam_on)
|
|
var/turf/T = get_turf(A)
|
|
if(T)
|
|
for(var/atom/movable/screen/movable/pic_in_pic/ai/P in T.vis_locs)
|
|
if(P.ai == src)
|
|
P.Click(params)
|
|
break
|
|
|
|
if(check_click_intercept(params,A))
|
|
return
|
|
|
|
if(control_disabled || incapacitated())
|
|
return
|
|
|
|
var/turf/pixel_turf = get_turf_pixel(A)
|
|
if(isnull(pixel_turf))
|
|
return
|
|
if(!can_see(A))
|
|
return
|
|
|
|
if(LAZYACCESS(modifiers, SHIFT_CLICK))
|
|
if(LAZYACCESS(modifiers, CTRL_CLICK))
|
|
CtrlShiftClickOn(A)
|
|
return
|
|
ShiftClickOn(A)
|
|
return
|
|
if(LAZYACCESS(modifiers, ALT_CLICK)) // alt and alt-gr (rightalt)
|
|
AltClickOn(A)
|
|
return
|
|
if(LAZYACCESS(modifiers, CTRL_CLICK))
|
|
CtrlClickOn(A)
|
|
return
|
|
if(LAZYACCESS(modifiers, MIDDLE_CLICK))
|
|
MiddleClickOn(A, params)
|
|
return
|
|
if(LAZYACCESS(modifiers, RIGHT_CLICK))
|
|
var/secondary_result = A.attack_ai_secondary(src, modifiers)
|
|
if(secondary_result == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN || secondary_result == SECONDARY_ATTACK_CONTINUE_CHAIN)
|
|
return
|
|
else if(secondary_result != SECONDARY_ATTACK_CALL_NORMAL)
|
|
CRASH("attack_ai_secondary did not return a SECONDARY_ATTACK_* define.")
|
|
|
|
if(world.time <= next_move)
|
|
return
|
|
|
|
if(waypoint_mode)
|
|
waypoint_mode = 0
|
|
set_waypoint(A)
|
|
return
|
|
|
|
A.attack_ai(src)
|
|
|
|
/*
|
|
AI has no need for the UnarmedAttack() and RangedAttack() procs,
|
|
because the AI code is not generic; attack_ai() is used instead.
|
|
The below is only really for safety, or you can alter the way
|
|
it functions and re-insert it above.
|
|
*/
|
|
/mob/living/silicon/ai/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
|
|
A.attack_ai(src)
|
|
|
|
/mob/living/silicon/ai/RangedAttack(atom/A)
|
|
A.attack_ai(src)
|
|
|
|
/atom/proc/attack_ai(mob/user)
|
|
return
|
|
|
|
/**
|
|
* What happens when the AI holds right-click on an item. Returns a SECONDARY_ATTACK_* value.
|
|
*
|
|
* Arguments:
|
|
* * user The mob holding the right click
|
|
* * modifiers The list of the custom click modifiers
|
|
*/
|
|
/atom/proc/attack_ai_secondary(mob/user, list/modifiers)
|
|
return SECONDARY_ATTACK_CALL_NORMAL
|
|
|
|
/*
|
|
Since the AI handles shift, ctrl, and alt-click differently
|
|
than anything else in the game, atoms have separate procs
|
|
for AI shift, ctrl, and alt clicking.
|
|
*/
|
|
|
|
/mob/living/silicon/ai/CtrlShiftClickOn(atom/target)
|
|
target.AICtrlShiftClick(src)
|
|
|
|
/mob/living/silicon/ai/ShiftClickOn(atom/target)
|
|
target.AIShiftClick(src)
|
|
|
|
/mob/living/silicon/ai/CtrlClickOn(atom/target)
|
|
target.AICtrlClick(src)
|
|
|
|
/mob/living/silicon/ai/AltClickOn(atom/target)
|
|
target.AIAltClick(src)
|
|
|
|
/*
|
|
The following criminally helpful code is just the previous code cleaned up;
|
|
I have no idea why it was in atoms.dm instead of respective files.
|
|
*/
|
|
/* Questions: Instead of an Emag check on every function, can we not add to airlocks onclick if emag return? */
|
|
|
|
/* Atom Procs */
|
|
/atom/proc/AICtrlClick(mob/living/silicon/ai/user)
|
|
return
|
|
|
|
/atom/proc/AIAltClick(mob/living/silicon/ai/user)
|
|
AltClick(user)
|
|
return
|
|
|
|
/atom/proc/AIShiftClick(mob/living/silicon/ai/user)
|
|
return
|
|
|
|
/atom/proc/AICtrlShiftClick(mob/living/silicon/ai/user)
|
|
return
|
|
|
|
/* Airlocks */
|
|
/obj/machinery/door/airlock/AICtrlClick(mob/living/silicon/ai/user) // Bolts doors
|
|
if(obj_flags & EMAGGED)
|
|
return
|
|
|
|
toggle_bolt(user)
|
|
add_hiddenprint(user)
|
|
|
|
/obj/machinery/door/airlock/AIAltClick(mob/living/silicon/ai/user) // Eletrifies doors.
|
|
if(obj_flags & EMAGGED)
|
|
return
|
|
|
|
if(!secondsElectrified)
|
|
shock_perm(user)
|
|
else
|
|
shock_restore(user)
|
|
|
|
/obj/machinery/door/airlock/AIShiftClick(mob/living/silicon/ai/user) // Opens and closes doors!
|
|
if(obj_flags & EMAGGED)
|
|
return
|
|
|
|
user_toggle_open(user)
|
|
add_hiddenprint(user)
|
|
|
|
/obj/machinery/door/airlock/AICtrlShiftClick(mob/living/silicon/ai/user) // Sets/Unsets Emergency Access Override
|
|
if(obj_flags & EMAGGED)
|
|
return
|
|
|
|
toggle_emergency(user)
|
|
add_hiddenprint(user)
|
|
|
|
/////////////
|
|
/* APC */
|
|
/////////////
|
|
|
|
/// Toggle APC power settings
|
|
/obj/machinery/power/apc/AICtrlClick(mob/living/silicon/ai/user)
|
|
if(!can_use(user, loud = TRUE))
|
|
return
|
|
|
|
toggle_breaker(user)
|
|
|
|
/// Toggle APC environment settings (atmos)
|
|
/obj/machinery/power/apc/AICtrlShiftClick(mob/living/silicon/ai/user)
|
|
if(!can_use(user, loud = TRUE))
|
|
return
|
|
|
|
if(!is_operational || failure_timer)
|
|
return
|
|
|
|
environ = environ ? APC_CHANNEL_OFF : APC_CHANNEL_ON
|
|
if (user)
|
|
add_hiddenprint(user)
|
|
var/enabled_or_disabled = environ ? "enabled" : "disabled"
|
|
balloon_alert(user, "environment power [enabled_or_disabled]")
|
|
user.log_message("[enabled_or_disabled] the [src] environment settings", LOG_GAME)
|
|
update_appearance()
|
|
update()
|
|
|
|
/// Toggle APC lighting settings
|
|
/obj/machinery/power/apc/AIShiftClick(mob/living/silicon/ai/user)
|
|
if(!can_use(user, loud = TRUE))
|
|
return
|
|
|
|
if(!is_operational || failure_timer)
|
|
return
|
|
|
|
lighting = lighting ? APC_CHANNEL_OFF : APC_CHANNEL_ON
|
|
if (user)
|
|
var/enabled_or_disabled = lighting ? "enabled" : "disabled"
|
|
add_hiddenprint(user)
|
|
balloon_alert(user, "lighting power toggled [enabled_or_disabled]")
|
|
user.log_message("turned [enabled_or_disabled] the [src] lighting settings", LOG_GAME)
|
|
update_appearance()
|
|
update()
|
|
|
|
/// Toggle APC equipment settings
|
|
/obj/machinery/power/apc/AIAltClick(mob/living/silicon/ai/user)
|
|
if(!can_use(user, loud = TRUE))
|
|
return
|
|
|
|
if(!is_operational || failure_timer)
|
|
return
|
|
|
|
equipment = equipment ? APC_CHANNEL_OFF : APC_CHANNEL_ON
|
|
if (user)
|
|
var/enabled_or_disabled = equipment ? "enabled" : "disabled"
|
|
balloon_alert(user, "equipment power toggled [enabled_or_disabled]")
|
|
add_hiddenprint(user)
|
|
user.log_message("turned [enabled_or_disabled] the [src] equipment settings", LOG_GAME)
|
|
update_appearance()
|
|
update()
|
|
|
|
/obj/machinery/power/apc/attack_ai_secondary(mob/living/silicon/user, list/modifiers)
|
|
if(!can_use(user, loud = TRUE))
|
|
return
|
|
|
|
togglelock(user)
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/* AI Turrets */
|
|
/obj/machinery/turretid/AIAltClick(mob/living/silicon/ai/user) //toggles lethal on turrets
|
|
if(ailock)
|
|
return
|
|
toggle_lethal(user)
|
|
|
|
/obj/machinery/turretid/AICtrlClick(mob/living/silicon/ai/user) //turns off/on Turrets
|
|
if(ailock)
|
|
return
|
|
toggle_on(user)
|
|
|
|
/* Holopads */
|
|
/obj/machinery/holopad/AIAltClick(mob/living/silicon/ai/user)
|
|
if (user)
|
|
balloon_alert(user, "disrupted all active calls")
|
|
add_hiddenprint(user)
|
|
hangup_all_calls()
|
|
|
|
//
|
|
// Override TurfAdjacent for AltClicking
|
|
//
|
|
|
|
/mob/living/silicon/ai/TurfAdjacent(turf/target_turf)
|
|
return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(target_turf))
|