diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index a8d9c860354..2456ce0ddd1 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -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) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 474a04b743d..6633dfeedd8 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -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) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 4624aa98441..686194c3d0b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -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) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index cc70a3b97bd..11919c51e8b 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -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)) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index c1c6cead2c3..e61485b7ad8 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -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) diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index a79ea75efe8..6fe9c0a987c 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -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("[src] drives over [H]!", \ "[src] drives over you!") @@ -829,6 +838,23 @@ if(.) visible_message("[src]'s safeties are locked on.") +/// 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) + diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 7aecab4da50..7df1a38839f 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -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))