diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm index 6b38454f7fe..3f783311e85 100644 --- a/code/__defines/dcs/signals.dm +++ b/code/__defines/dcs/signals.dm @@ -52,6 +52,7 @@ // /mob signals #define COMSIG_MOB_FACEDIR "mob_facedir" +#define COMSIG_MOB_POINT "mob_point" // /obj signals /// when a hood is unequipped diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 9769f6fab74..024df7446a7 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -672,3 +672,6 @@ /atom/proc/handle_middle_mouse_click(var/mob/user) return FALSE + +/atom/proc/handle_pointed_at(var/mob/pointer) + return diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm b/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm index 2bf73f92d09..7ef7826ea95 100644 --- a/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm +++ b/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm @@ -1,19 +1,24 @@ /mob/living/simple_animal/hostile/commanded name = "commanded" + var/short_name = null stance = COMMANDED_STOP melee_damage_lower = 0 melee_damage_upper = 0 density = FALSE belongs_to_station = TRUE hostile_nameable = TRUE - var/short_name = null + var/list/command_buffer = list() var/list/known_commands = list("stay", "stop", "attack", "follow") - var/mob/master = null //undisputed master. Their commands hold ultimate sway and ultimate power. - var/list/allowed_targets = list() //WHO CAN I KILL D: - var/retribution = 1 //whether or not they will attack us if we attack them like some kinda dick. + var/list/sad_emote = list("whimpers") + var/mob/master = null //undisputed master. Their commands hold ultimate sway and ultimate power. + var/datum/weakref/following_mob_ref + var/list/allowed_targets = list() //WHO CAN I KILL D: + + var/retribution = 1 //whether or not they will attack us if we attack them like some kinda dick. + /mob/living/simple_animal/hostile/commanded/Initialize() . = ..() if(!short_name) @@ -69,6 +74,11 @@ commanded_stop() /mob/living/simple_animal/hostile/commanded/change_stance(var/new_stance) + if(following_mob_ref) + var/mob/mob_to_follow = following_mob_ref.resolve() + UnregisterSignal(mob_to_follow, COMSIG_MOB_POINT) + following_mob_ref = null + . = ..() if(!.) return @@ -113,10 +123,9 @@ /mob/living/simple_animal/hostile/commanded/proc/follow_target() stop_automated_movement = 1 - if(!target_mob) - return - if(get_dist(src, target_mob) <= 10) - walk_to(src,target_mob,1,move_to_delay) + var/mob/mob_to_follow = following_mob_ref?.resolve() + if(mob_to_follow && get_dist(src, mob_to_follow) <= 10) + walk_to(src,mob_to_follow,1,move_to_delay) /mob/living/simple_animal/hostile/commanded/proc/commanded_stop() //basically a proc that runs whenever we are asked to stay put. Probably going to remain unused. return @@ -164,15 +173,19 @@ . += M -/mob/living/simple_animal/hostile/commanded/proc/attack_command(var/mob/speaker,var/text) +/mob/living/simple_animal/hostile/commanded/proc/attack_command(var/mob/speaker, var/text, var/mob/mob_target) target_mob = null //want me to attack something? Well I better forget my old target. walk_to(src,0) - change_stance(HOSTILE_STANCE_IDLE) + change_stance(HOSTILE_STANCE_ATTACKING) if(text == "attack" || findtext(text,"everyone") || findtext(text,"anybody") || findtext(text, "somebody") || findtext(text, "someone")) //if its just 'attack' then just attack anybody, same for if they say 'everyone', somebody, anybody. Assuming non-pickiness. allowed_targets = list("everyone")//everyone? EVERYONE return 1 - allowed_targets += get_targets_by_name(text) + if(mob_target) + allowed_targets += mob_target + friends -= mob_target + else + allowed_targets += get_targets_by_name(text) if(emote_hear && emote_hear.len) audible_emote("[pick(emote_hear)].",0) return targets.len != 0 @@ -181,41 +194,67 @@ target_mob = null change_stance(COMMANDED_STOP) stop_automated_movement = 1 - walk_to(src,0) + walk_to(src, 0) if(emote_hear && emote_hear.len) audible_emote("[pick(emote_hear)].",0) return 1 /mob/living/simple_animal/hostile/commanded/proc/stop_command(var/mob/speaker,var/text) allowed_targets = list() - walk_to(src,0) - target_mob = null //gotta stop SOMETHIN + walk_to(src, 0) change_stance(HOSTILE_STANCE_IDLE) stop_automated_movement = 0 if(emote_hear && emote_hear.len) audible_emote("[pick(emote_hear)].",0) return 1 -/mob/living/simple_animal/hostile/commanded/proc/follow_command(var/mob/speaker,var/text) - //we can assume 'stop following' is handled by stop_command - if(findtext(text,"me")) - change_stance(COMMANDED_FOLLOW) - target_mob = speaker //this wont bite me in the ass later. - return 1 - var/list/targets = get_targets_by_name(text) - if(targets.len > 1 || !targets.len) //CONFUSED. WHO DO I FOLLOW? - return 0 +/mob/living/simple_animal/hostile/commanded/proc/follow_command(var/mob/speaker, var/text, var/mob/mob_target) + allowed_targets = list() + walk_to(src, 0) if(emote_hear && emote_hear.len) audible_emote("[pick(emote_hear)].",0) + + if(!mob_target) + if(findtext(text, "me")) + mob_target = speaker + else + var/list/targets = get_targets_by_name(text) + if(targets.len > 1 || !targets.len) //CONFUSED. WHO DO I FOLLOW? + return FALSE + mob_target = targets[1] + change_stance(COMMANDED_FOLLOW) //GOT SOMEBODY. BETTER FOLLOW EM. - target_mob = targets[1] //YEAH GOOD IDEA + following_mob_ref = WEAKREF(mob_target) + friends |= mob_target + RegisterSignal(mob_target, COMSIG_MOB_POINT, PROC_REF(point_command)) return 1 /mob/living/simple_animal/hostile/commanded/proc/misc_command(var/mob/speaker,var/text) return 0 +/mob/living/simple_animal/hostile/commanded/handle_pointed_at(var/mob/pointer) + if(pointer != master && !(pointer in friends)) + return + var/mob_to_follow = following_mob_ref?.resolve() + if(stance != COMMANDED_FOLLOW || mob_to_follow != pointer) + follow_command(pointer, mob_target = pointer) + else + stop_command(pointer) + +/mob/living/simple_animal/hostile/commanded/proc/point_command(var/mob/pointer, var/atom/pointed_at) + SIGNAL_HANDLER + + if(pointed_at == src || pointer == pointed_at || !isliving(pointed_at)) + return + + switch(pointer.a_intent) + if(I_GRAB) + INVOKE_ASYNC(src, PROC_REF(follow_command), pointer, null, pointed_at) + if(I_HURT) + if(pointed_at != master || (!(pointed_at in friends) || pointer == master)) + INVOKE_ASYNC(src, PROC_REF(attack_command), pointer, null, pointed_at) /mob/living/simple_animal/hostile/commanded/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) //if they attack us, we want to kill them. None of that "you weren't given a command so free kill" bullshit. @@ -278,9 +317,8 @@ change_stance(HOSTILE_STANCE_IDLE) audible_emote("[pick(sad_emote)].",0) -/mob/living/simple_animal/hostile/commanded/attackby(var/obj/item/O, var/mob/user) +/mob/living/simple_animal/hostile/commanded/handle_attack_by(var/obj/item/O, var/mob/user) ..() - // We forgive our master if(user == master) target_mob = null diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index cacf9dde455..8894de81bd1 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -120,7 +120,7 @@ target_mob = P.firer change_stance(HOSTILE_STANCE_ATTACK) -/mob/living/simple_animal/hostile/attackby(var/obj/item/O, var/mob/user) +/mob/living/simple_animal/hostile/handle_attack_by(var/mob/user) ..() if(target_mob != user) target_mob = user diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 888d6b35afe..50bd69182ea 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -415,6 +415,8 @@ var/atom/movable/M = A M.add_filter("pointglow", 1, list(type = "drop_shadow", x = 0, y = -1, offset = 1, size = 1, color = "#F00")) addtimer(CALLBACK(M, TYPE_PROC_REF(/atom/movable, remove_filter), "pointglow"), 2 SECONDS) + A.handle_pointed_at(src) + SEND_SIGNAL(src, COMSIG_MOB_POINT, A) return TRUE /mob/proc/end_pointing_effect() diff --git a/html/changelogs/geeves-commanded_tweaks.yml b/html/changelogs/geeves-commanded_tweaks.yml new file mode 100644 index 00000000000..e8986cb7b77 --- /dev/null +++ b/html/changelogs/geeves-commanded_tweaks.yml @@ -0,0 +1,7 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "You can now use pointing to command commandable animals. Pointing them with any intent will make them either follow you or stop following you, provided you're their master or one of their friends (being set to follow adds you to their friend list). While the animal is following you, pointing at someone with grab intent will make it follow them. Pointing at them on harm intent will make it attack them." + - bugfix: "Hostile/commandable animals will no longer attack you when you heal them. Petting a service dog will still get you bit." \ No newline at end of file