mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 08:08:49 +01:00
Mulebots are no longer bugged into horrific, merciless machines of gore and destruction. (#57378)
About The Pull Request In https://github.com/tgstation/tgstation/pull/57010/files#diff-08a9c12575e75bb692c000da3f7eea30c0340da26171c5c788fd2b17afef92b5 Floyd did an undocumented change to Mulebot behaviour. He moved crushing from the /human/Crossed level to mulebot/Cross. The problem is: image Cross (and Crossed) are called when some other object Crosses us, not when we Cross some other object. This meant that... Well... Walking into a mulebot was deadly. Buckling to a mulebot was deadly. lGrnThJEWG And being buckled to a mulebot that ended up moving was deadly multiplied by the number of times the mulebot moved. QJNXqBHZ8m Also why can you push mulebots when things are buckled to it? That seems like an oversight. I added new signals to the atom/movable/...Cross... series of procs that are sent from the thing crossing our AM. The thing crossing our AM can then listen for that signal on itself, and it now knows when it's crossing something! BOOM! CRUSH TIME! I've also added a check to /mob/living/proc/PushAM to prevent pushing an AM buckled to a thing when you wouldn't be able to pull them. This check also takes into account if you'd just have the raw movement force to push the thing they're buckled to as well. This should put a stop to being able to push mulebots around when they have mobs buckled to them. Also, you can swap places with active Mulebots. This is probably not intended. I've added TRAIT_NOMOBSWAP to them. The end result? Mulebots that just work. And don't worry, you can still crawl under them. Why It's Good For The Game Feex. Changelog 🆑 fix: Mulebots no longer murder people just because that person dared to bump into them. /🆑
This commit is contained in:
@@ -356,6 +356,15 @@
|
||||
#define COMPONENT_MOVABLE_BLOCK_UNCROSS (1<<0)
|
||||
///from base of atom/movable/Uncrossed(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_UNCROSSED "movable_uncrossed"
|
||||
///from base of atom/movable/Cross(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_CROSS_OVER "movable_cross_am"
|
||||
///from base of atom/movable/Crossed(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_CROSSED_OVER "movable_crossed_am"
|
||||
///from base of atom/movable/Uncross(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_UNCROSS_OVER "movable_uncross_am"
|
||||
#define COMPONENT_MOVABLE_BLOCK_UNCROSS_OVER (1<<0)
|
||||
///from base of atom/movable/Uncrossed(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_UNCROSSED_OVER "movable_uncross_am"
|
||||
///from base of atom/movable/Bump(): (/atom)
|
||||
#define COMSIG_MOVABLE_BUMP "movable_bump"
|
||||
///from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum)
|
||||
@@ -432,6 +441,20 @@
|
||||
#define COMSIG_MOB_ALTCLICKON "mob_altclickon"
|
||||
#define COMSIG_MOB_CANCEL_CLICKON (1<<0)
|
||||
|
||||
/// From base of /mob/living/simple_animal/bot/proc/bot_step()
|
||||
#define COMSIG_MOB_BOT_PRE_STEP "mob_bot_pre_step"
|
||||
/// Should always match COMPONENT_MOVABLE_BLOCK_PRE_MOVE as these are interchangeable and used to block movement.
|
||||
#define COMPONENT_MOB_BOT_BLOCK_PRE_STEP COMPONENT_MOVABLE_BLOCK_PRE_MOVE
|
||||
/// From base of /mob/living/simple_animal/bot/proc/bot_step()
|
||||
#define COMSIG_MOB_BOT_STEP "mob_bot_step"
|
||||
|
||||
/// From base of /client/Move()
|
||||
#define COMSIG_MOB_CLIENT_PRE_MOVE "mob_client_pre_move"
|
||||
/// Should always match COMPONENT_MOVABLE_BLOCK_PRE_MOVE as these are interchangeable and used to block movement.
|
||||
#define COMSIG_MOB_CLIENT_BLOCK_PRE_MOVE COMPONENT_MOVABLE_BLOCK_PRE_MOVE
|
||||
/// From base of /client/Move()
|
||||
#define COMSIG_MOB_CLIENT_MOVED "mob_client_moved"
|
||||
|
||||
///from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj
|
||||
#define COMSIG_MOB_ALLOWED "mob_allowed"
|
||||
///from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources)
|
||||
|
||||
@@ -511,6 +511,7 @@
|
||||
/atom/movable/Cross(atom/movable/AM)
|
||||
. = TRUE
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_CROSS, AM)
|
||||
SEND_SIGNAL(AM, COMSIG_MOVABLE_CROSS_OVER, src)
|
||||
return CanPass(AM, AM.loc, TRUE)
|
||||
|
||||
//oldloc = old location on atom, inserted when forceMove is called and ONLY when forceMove is called!
|
||||
@@ -518,16 +519,20 @@
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
. = ..()
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_CROSSED, AM)
|
||||
SEND_SIGNAL(AM, COMSIG_MOVABLE_CROSSED_OVER, src)
|
||||
|
||||
/atom/movable/Uncross(atom/movable/AM, atom/newloc)
|
||||
. = ..()
|
||||
if(SEND_SIGNAL(src, COMSIG_MOVABLE_UNCROSS, AM) & COMPONENT_MOVABLE_BLOCK_UNCROSS)
|
||||
return FALSE
|
||||
if(SEND_SIGNAL(AM, COMSIG_MOVABLE_UNCROSS_OVER, src) & COMPONENT_MOVABLE_BLOCK_UNCROSS_OVER)
|
||||
return FALSE
|
||||
if(isturf(newloc) && !CheckExit(AM, newloc))
|
||||
return FALSE
|
||||
|
||||
/atom/movable/Uncrossed(atom/movable/AM)
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_UNCROSSED, AM)
|
||||
SEND_SIGNAL(AM, COMSIG_MOVABLE_UNCROSSED_OVER, src)
|
||||
|
||||
/atom/movable/Bump(atom/A)
|
||||
if(!A)
|
||||
|
||||
@@ -188,7 +188,6 @@
|
||||
popup.open()
|
||||
|
||||
// called when something steps onto a human
|
||||
// this could be made more general, but for now just handle mulebot
|
||||
/mob/living/carbon/human/Crossed(atom/movable/AM)
|
||||
. = ..()
|
||||
spreadFire(AM)
|
||||
|
||||
@@ -228,10 +228,18 @@
|
||||
if((AM.move_resist * MOVE_FORCE_FORCEPUSH_RATIO) <= force) //trigger move_crush and/or force_push regardless of if we can push it normally
|
||||
if(force_push(AM, move_force, dir_to_target, push_anchored))
|
||||
push_anchored = TRUE
|
||||
if(ismob(AM))
|
||||
var/mob/mob_to_push = AM
|
||||
var/atom/movable/mob_buckle = mob_to_push.buckled
|
||||
// If we can't pull them because of what they're buckled to, make sure we can push the thing they're buckled to instead.
|
||||
// If neither are true, we're not pushing anymore.
|
||||
if(mob_buckle && (mob_buckle.buckle_prevents_pull || (force < (mob_buckle.move_resist * MOVE_FORCE_PUSH_RATIO))))
|
||||
now_pushing = FALSE
|
||||
return
|
||||
if((AM.anchored && !push_anchored) || (force < (AM.move_resist * MOVE_FORCE_PUSH_RATIO)))
|
||||
now_pushing = FALSE
|
||||
return
|
||||
if (istype(AM, /obj/structure/window))
|
||||
if(istype(AM, /obj/structure/window))
|
||||
var/obj/structure/window/W = AM
|
||||
if(W.fulltile)
|
||||
for(var/obj/structure/window/win in get_step(W, dir_to_target))
|
||||
|
||||
@@ -528,26 +528,26 @@ Pass a positive integer as an argument to override a bot's default speed.
|
||||
|
||||
if(step_count >= 1 && tries < BOT_STEP_MAX_RETRIES)
|
||||
for(var/step_number = 0, step_number < step_count,step_number++)
|
||||
addtimer(CALLBACK(src, .proc/bot_step, dest), BOT_STEP_DELAY*step_number)
|
||||
addtimer(CALLBACK(src, .proc/bot_step), BOT_STEP_DELAY*step_number)
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/proc/bot_step(dest) //Step,increase tries if failed
|
||||
if(!path)
|
||||
/// Performs a step_towards and increments the path if successful. Returns TRUE if the bot moved and FALSE otherwise.
|
||||
/mob/living/simple_animal/bot/proc/bot_step()
|
||||
if(!length(path))
|
||||
return FALSE
|
||||
if(path.len > 1)
|
||||
step_towards(src, path[1])
|
||||
if(get_turf(src) == path[1]) //Successful move
|
||||
increment_path()
|
||||
tries = 0
|
||||
else
|
||||
tries++
|
||||
return FALSE
|
||||
else if(path.len == 1)
|
||||
step_to(src, dest)
|
||||
set_path(null)
|
||||
|
||||
if(SEND_SIGNAL(src, COMSIG_MOB_BOT_PRE_STEP) & COMPONENT_MOB_BOT_BLOCK_PRE_STEP)
|
||||
return FALSE
|
||||
|
||||
if(!step_towards(src, path[1]))
|
||||
tries++
|
||||
return FALSE
|
||||
|
||||
increment_path()
|
||||
tries = 0
|
||||
SEND_SIGNAL(src, COMSIG_MOB_BOT_STEP)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -1075,12 +1075,15 @@ Pass a positive integer as an argument to override a bot's default speed.
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/proc/increment_path()
|
||||
if(!path || !path.len)
|
||||
if(!length(path))
|
||||
return
|
||||
var/image/I = path[path[1]]
|
||||
if(I)
|
||||
I.icon_state = null
|
||||
path.Cut(1, 2)
|
||||
|
||||
if(!length(path))
|
||||
set_path(null)
|
||||
|
||||
/mob/living/simple_animal/bot/rust_heretic_act()
|
||||
adjustBruteLoss(400)
|
||||
|
||||
@@ -60,6 +60,15 @@
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
RegisterSignal(src, COMSIG_MOB_BOT_PRE_STEP, .proc/check_pre_step)
|
||||
RegisterSignal(src, COMSIG_MOB_CLIENT_PRE_MOVE, .proc/check_pre_step)
|
||||
RegisterSignal(src, COMSIG_MOB_BOT_STEP, .proc/on_bot_step)
|
||||
RegisterSignal(src, COMSIG_MOB_CLIENT_MOVED, .proc/on_bot_step)
|
||||
RegisterSignal(src, COMSIG_MOVABLE_CROSSED_OVER, .proc/on_crossed_over)
|
||||
|
||||
ADD_TRAIT(src, TRAIT_NOMOBSWAP, INNATE_TRAIT)
|
||||
|
||||
if(prob(0.666) && mapload)
|
||||
new /mob/living/simple_animal/bot/mulebot/paranormal(loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
@@ -105,6 +114,7 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Destroy()
|
||||
UnregisterSignal(src, COMSIG_MOB_BOT_PRE_STEP, COMSIG_MOB_CLIENT_PRE_MOVE, COMSIG_MOB_BOT_STEP, COMSIG_MOB_CLIENT_MOVED, COMSIG_MOVABLE_CROSSED_OVER)
|
||||
unload(0)
|
||||
QDEL_NULL(wires)
|
||||
QDEL_NULL(cell)
|
||||
@@ -118,13 +128,6 @@
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Cross(atom/movable/AM)
|
||||
. = ..()
|
||||
if(ishuman(AM))
|
||||
RunOver(AM)
|
||||
|
||||
|
||||
|
||||
/// returns true if the bot is fully powered.
|
||||
/mob/living/simple_animal/bot/mulebot/proc/has_power(bypass_open_check)
|
||||
return (!open || bypass_open_check) && cell && cell.charge > 0 && (!wires.is_cut(WIRE_POWER1) && !wires.is_cut(WIRE_POWER2))
|
||||
@@ -529,9 +532,6 @@
|
||||
start()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Move(atom/newloc, direct) //handle leaving bloody tracks. can't be done via Moved() since that can end up putting the tracks somewhere BEFORE we get bloody.
|
||||
if(!has_power((client || paicard))) //turn off if we ran out of power.
|
||||
turn_off()
|
||||
return FALSE
|
||||
if(!bloodiness) //important to check this first since Bump() is called in the Move() -> Entered() chain
|
||||
return ..()
|
||||
var/atom/oldLoc = loc
|
||||
@@ -543,13 +543,20 @@
|
||||
B.setDir(direct)
|
||||
bloodiness--
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Moved() //make sure we always use power after moving.
|
||||
/**
|
||||
* Signal handler for COMSIG_MOVABLE_CROSSED_OVER signals sent by this mulebot.
|
||||
*
|
||||
* Intended to be used to crush various things.
|
||||
*/
|
||||
/mob/living/simple_animal/bot/mulebot/proc/on_crossed_over(atom/movable/source, atom/movable/crossed_atom)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(ishuman(crossed_atom))
|
||||
run_over(crossed_atom)
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Moved()
|
||||
. = ..()
|
||||
if(!cell)
|
||||
return
|
||||
cell.use(cell_move_power_usage)
|
||||
if(cell.charge < cell_move_power_usage) //make sure we have enough power to move again, otherwise turn off.
|
||||
turn_off()
|
||||
|
||||
diag_hud_set_mulebotcell()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/handle_automated_action()
|
||||
@@ -588,12 +595,14 @@
|
||||
path -= next
|
||||
return
|
||||
if(isturf(next))
|
||||
if(SEND_SIGNAL(src, COMSIG_MOB_BOT_PRE_STEP) & COMPONENT_MOB_BOT_BLOCK_PRE_STEP)
|
||||
return
|
||||
var/oldloc = loc
|
||||
var/moved = step_towards(src, next) // attempt to move
|
||||
if(moved && oldloc!=loc) // successful move
|
||||
SEND_SIGNAL(src, COMSIG_MOB_BOT_STEP)
|
||||
blockcount = 0
|
||||
path -= loc
|
||||
|
||||
if(destination == home_destination)
|
||||
mode = BOT_GO_HOME
|
||||
else
|
||||
@@ -735,7 +744,7 @@
|
||||
return ..()
|
||||
|
||||
// when mulebot is in the same loc
|
||||
/mob/living/simple_animal/bot/mulebot/proc/RunOver(mob/living/carbon/human/H)
|
||||
/mob/living/simple_animal/bot/mulebot/proc/run_over(mob/living/carbon/human/H)
|
||||
log_combat(src, H, "run over", null, "(DAMTYPE: [uppertext(BRUTE)])")
|
||||
H.visible_message("<span class='danger'>[src] drives over [H]!</span>", \
|
||||
"<span class='userdanger'>[src] drives over you!</span>")
|
||||
@@ -829,6 +838,23 @@
|
||||
if(.)
|
||||
visible_message("<span class='notice'>[src]'s safeties are locked on.</span>")
|
||||
|
||||
/// Checks whether the bot can complete a step_towards, checking whether the bot is on and has the charge to do the move. Returns COMPONENT_MOB_BOT_CANCELSTEP if the bot should not step.
|
||||
/mob/living/simple_animal/bot/mulebot/proc/check_pre_step(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!on)
|
||||
return COMPONENT_MOB_BOT_BLOCK_PRE_STEP
|
||||
|
||||
if((cell && (cell.charge < cell_move_power_usage)) || !has_power((client || paicard)))
|
||||
turn_off()
|
||||
return COMPONENT_MOB_BOT_BLOCK_PRE_STEP
|
||||
|
||||
/// Uses power from the cell when the bot steps.
|
||||
/mob/living/simple_animal/bot/mulebot/proc/on_bot_step(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
cell?.use(cell_move_power_usage)
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/paranormal//allows ghosts only unless hacked to actually be useful
|
||||
name = "\improper GHOULbot"
|
||||
desc = "A rather ghastly looking... Multiple Utility Load Effector bot? It only seems to accept paranormal forces, and for this reason is fucking useless."
|
||||
@@ -883,7 +909,6 @@
|
||||
mode = BOT_IDLE
|
||||
update_appearance()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/paranormal/update_overlays()
|
||||
. = ..()
|
||||
if(!isobserver(load))
|
||||
@@ -909,3 +934,4 @@
|
||||
|
||||
/obj/machinery/bot_core/mulebot
|
||||
req_access = list(ACCESS_CARGO)
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
* (if you ask me, this should be at the top of the move so you don't dance around)
|
||||
*
|
||||
*/
|
||||
/client/Move(n, direct)
|
||||
/client/Move(new_loc, direct)
|
||||
if(world.time < move_delay) //do not move anything ahead of this check please
|
||||
return FALSE
|
||||
else
|
||||
@@ -76,14 +76,14 @@
|
||||
move_delay = world.time + world.tick_lag //this is here because Move() can now be called mutiple times per tick
|
||||
if(!mob || !mob.loc)
|
||||
return FALSE
|
||||
if(!n || !direct)
|
||||
if(!new_loc || !direct)
|
||||
return FALSE
|
||||
if(mob.notransform)
|
||||
return FALSE //This is sota the goto stop mobs from moving var
|
||||
if(mob.control_object)
|
||||
return Move_object(direct)
|
||||
if(!isliving(mob))
|
||||
return mob.Move(n, direct)
|
||||
return mob.Move(new_loc, direct)
|
||||
if(mob.stat == DEAD)
|
||||
mob.ghostize()
|
||||
return FALSE
|
||||
@@ -99,7 +99,7 @@
|
||||
return mob.remote_control.relaymove(mob, direct)
|
||||
|
||||
if(isAI(mob))
|
||||
return AIMove(n,direct,mob)
|
||||
return AIMove(new_loc,direct,mob)
|
||||
|
||||
if(Process_Grab()) //are we restrained by someone's grip?
|
||||
return
|
||||
@@ -116,6 +116,10 @@
|
||||
|
||||
if(!mob.Process_Spacemove(direct))
|
||||
return FALSE
|
||||
|
||||
if(SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_PRE_MOVE, new_loc) & COMSIG_MOB_CLIENT_BLOCK_PRE_MOVE)
|
||||
return FALSE
|
||||
|
||||
//We are now going to move
|
||||
var/add_delay = mob.cached_multiplicative_slowdown
|
||||
mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay * ( (NSCOMPONENT(direct) && EWCOMPONENT(direct)) ? 2 : 1 ) )) // set it now in case of pulled objects
|
||||
@@ -135,11 +139,11 @@
|
||||
newdir = angle2dir(dir2angle(direct) + pick(45, -45))
|
||||
if(newdir)
|
||||
direct = newdir
|
||||
n = get_step(L, direct)
|
||||
new_loc = get_step(L, direct)
|
||||
|
||||
. = ..()
|
||||
|
||||
if((direct & (direct - 1)) && mob.loc == n) //moved diagonally successfully
|
||||
if((direct & (direct - 1)) && mob.loc == new_loc) //moved diagonally successfully
|
||||
add_delay *= 2
|
||||
mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay))
|
||||
move_delay += add_delay
|
||||
@@ -147,6 +151,10 @@
|
||||
if(mob.throwing)
|
||||
mob.throwing.finalize(FALSE)
|
||||
|
||||
// At this point we've moved the client's attached mob. This is one of the only ways to guess that a move was done
|
||||
// as a result of player input and not because they were pulled or any other magic.
|
||||
SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_MOVED)
|
||||
|
||||
var/atom/movable/P = mob.pulling
|
||||
if(P && !ismob(P) && P.density)
|
||||
mob.setDir(turn(mob.dir, 180))
|
||||
|
||||
Reference in New Issue
Block a user