diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm
index b1bae99bd21..aef18878bf9 100644
--- a/code/__DEFINES/ai.dm
+++ b/code/__DEFINES/ai.dm
@@ -68,7 +68,7 @@
#define BB_CUSTOMER_EATING "BB_customer_eating"
#define BB_CUSTOMER_ATTENDING_VENUE "BB_customer_attending_avenue"
#define BB_CUSTOMER_LEAVING "BB_customer_leaving"
-
+#define BB_CUSTOMER_CURRENT_TARGET "BB_customer_current_target"
///Dog AI controller blackboard keys
diff --git a/code/datums/ai/generic_actions.dm b/code/datums/ai/generic_actions.dm
index 99b75ae230a..d148a1578bd 100644
--- a/code/datums/ai/generic_actions.dm
+++ b/code/datums/ai/generic_actions.dm
@@ -22,3 +22,42 @@
/datum/ai_behavior/move_to_target/perform(delta_time, datum/ai_controller/controller)
. = ..()
finish_action(controller, TRUE)
+
+
+/datum/ai_behavior/break_spine
+ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT
+ action_cooldown = 0.7 SECONDS
+ var/target_key
+ var/give_up_distance = 10
+
+
+/datum/ai_behavior/break_spine/perform(delta_time, datum/ai_controller/controller)
+ var/mob/living/batman = controller.blackboard[target_key]
+ var/mob/living/big_guy = controller.pawn //he was molded by the darkness
+
+ if(batman.stat)
+ finish_action(controller, TRUE)
+
+ if(get_dist(batman, big_guy) >= give_up_distance)
+ finish_action(controller, FALSE)
+
+ big_guy.start_pulling(batman)
+ big_guy.setDir(get_dir(big_guy, batman))
+
+ batman.visible_message("[batman] gets a slightly too tight hug from [big_guy]!", "You feel your body break as [big_guy] embraces you!")
+
+ if(iscarbon(batman))
+ var/mob/living/carbon/carbon_batman = batman
+ for(var/obj/item/bodypart/bodypart_to_break in carbon_batman.bodyparts)
+ if(bodypart_to_break.body_zone == BODY_ZONE_HEAD)
+ continue
+ bodypart_to_break.receive_damage(brute = 15, wound_bonus = 35)
+ else
+ batman.adjustBruteLoss(150)
+
+ finish_action(controller, TRUE)
+
+/datum/ai_behavior/break_spine/finish_action(datum/ai_controller/controller, succeeded)
+ if(succeeded)
+ controller.blackboard[target_key] = null
+ return ..()
diff --git a/code/datums/ai/robot_customer/robot_customer_behaviors.dm b/code/datums/ai/robot_customer/robot_customer_behaviors.dm
index be4e2c04e68..ebdcda97e4b 100644
--- a/code/datums/ai/robot_customer/robot_customer_behaviors.dm
+++ b/code/datums/ai/robot_customer/robot_customer_behaviors.dm
@@ -110,3 +110,7 @@
. = ..()
qdel(controller.pawn) //save the world, my final message, goodbye.
finish_action(controller, TRUE)
+
+
+/datum/ai_behavior/break_spine/robot_customer
+ target_key = BB_CUSTOMER_CURRENT_TARGET
diff --git a/code/datums/ai/robot_customer/robot_customer_controller.dm b/code/datums/ai/robot_customer/robot_customer_controller.dm
index 7f17974c171..7050cae9ec3 100644
--- a/code/datums/ai/robot_customer/robot_customer_controller.dm
+++ b/code/datums/ai/robot_customer/robot_customer_controller.dm
@@ -1,6 +1,6 @@
/datum/ai_controller/robot_customer
ai_movement = /datum/ai_movement/basic_avoidance
- movement_delay = 1 SECONDS
+ movement_delay = 0.8 SECONDS
blackboard = list(BB_CUSTOMER_CURRENT_ORDER = null,
BB_CUSTOMER_MY_SEAT = null,
BB_CUSTOMER_PATIENCE = 999,
@@ -14,10 +14,12 @@
if(!istype(new_pawn, /mob/living/simple_animal/robot_customer))
return AI_CONTROLLER_INCOMPATIBLE
RegisterSignal(new_pawn, COMSIG_PARENT_ATTACKBY, .proc/on_attackby)
+ RegisterSignal(new_pawn, COMSIG_LIVING_GET_PULLED, .proc/on_get_pulled)
+ RegisterSignal(new_pawn, COMSIG_ATOM_ATTACK_HAND, .proc/on_get_punched)
return ..() //Run parent at end
/datum/ai_controller/robot_customer/UnpossessPawn(destroy)
- UnregisterSignal(pawn, list(COMSIG_PARENT_ATTACKBY))
+ UnregisterSignal(pawn, list(COMSIG_PARENT_ATTACKBY, COMSIG_LIVING_GET_PULLED, COMSIG_ATOM_ATTACK_HAND))
return ..() //Run parent at end
/datum/ai_controller/robot_customer/SelectBehaviors(delta_time)
@@ -28,6 +30,11 @@
current_behaviors += GET_AI_BEHAVIOR(/datum/ai_behavior/leave_venue)
return
+ if(blackboard[BB_CUSTOMER_CURRENT_TARGET])
+ current_movement_target = blackboard[BB_CUSTOMER_CURRENT_TARGET]
+ current_behaviors += GET_AI_BEHAVIOR(/datum/ai_behavior/break_spine/robot_customer)
+ return
+
var/obj/my_seat = blackboard[BB_CUSTOMER_MY_SEAT]
if(!my_seat) //We havn't got a seat yet! find one!
@@ -43,13 +50,15 @@
current_behaviors += GET_AI_BEHAVIOR(/datum/ai_behavior/wait_for_food)
-/datum/ai_controller/robot_customer/proc/on_attackby(datum/source, obj/item/I, mob/user)
+/datum/ai_controller/robot_customer/proc/on_attackby(datum/source, obj/item/I, mob/living/user)
SIGNAL_HANDLER
var/datum/venue/attending_venue = blackboard[BB_CUSTOMER_ATTENDING_VENUE]
if(attending_venue.is_correct_order(I, blackboard[BB_CUSTOMER_CURRENT_ORDER]))
to_chat(user, "You hand [I] to [pawn]")
eat_order(I, attending_venue)
return COMPONENT_NO_AFTERATTACK
+ else
+ INVOKE_ASYNC(src, .proc/warn_greytider, user)
/datum/ai_controller/robot_customer/proc/eat_order(obj/item/order_item, datum/venue/attending_venue)
@@ -58,3 +67,57 @@
attending_venue.on_get_order(pawn, order_item)
+///Called when
+/datum/ai_controller/robot_customer/proc/on_get_pulled(datum/source, mob/living/puller)
+ SIGNAL_HANDLER
+
+
+ INVOKE_ASYNC(src, .proc/async_on_get_pulled, source, puller)
+
+/datum/ai_controller/robot_customer/proc/async_on_get_pulled(datum/source, mob/living/puller)
+ var/mob/living/simple_animal/robot_customer/customer = pawn
+ var/datum/customer_data/customer_data = blackboard[BB_CUSTOMER_CUSTOMERINFO]
+ var/datum/venue/attending_venue = blackboard[BB_CUSTOMER_ATTENDING_VENUE]
+
+ var/obj/item/card/id/used_id = puller.get_idcard(TRUE)
+
+ if(used_id && (attending_venue.req_access in used_id?.GetAccess()))
+ customer.say(customer_data.friendly_pull_line)
+ return
+ warn_greytider(puller)
+ customer.resist()
+
+
+
+
+/datum/ai_controller/robot_customer/proc/warn_greytider(mob/living/greytider)
+ var/mob/living/simple_animal/robot_customer/customer = pawn
+ var/datum/venue/attending_venue = blackboard[BB_CUSTOMER_ATTENDING_VENUE]
+ var/datum/customer_data/customer_data = blackboard[BB_CUSTOMER_CUSTOMERINFO]
+ attending_venue.mob_blacklist[greytider] += 1
+
+ switch(attending_venue.mob_blacklist[greytider])
+ if(1)
+ customer.say(customer_data.first_warning_line)
+ return
+ if(2)
+ customer.say(customer_data.second_warning_line)
+ return
+ if(3)
+ customer.say(customer_data.self_defense_line)
+ blackboard[BB_CUSTOMER_CURRENT_TARGET] = greytider
+
+ CancelActions()
+
+/datum/ai_controller/robot_customer/proc/on_get_punched(datum/source, mob/living/living_hitter)
+ SIGNAL_HANDLER
+
+ var/datum/venue/attending_venue = blackboard[BB_CUSTOMER_ATTENDING_VENUE]
+
+ var/obj/item/card/id/used_id = living_hitter.get_idcard(hand_first = TRUE)
+
+ if(used_id && (attending_venue.req_access in used_id?.GetAccess()))
+ return
+
+ if(living_hitter.combat_mode)
+ INVOKE_ASYNC(src, .proc/warn_greytider, living_hitter)
diff --git a/code/modules/food_and_drinks/restaurant/_venue.dm b/code/modules/food_and_drinks/restaurant/_venue.dm
index 690b9e0beaa..151c5892594 100644
--- a/code/modules/food_and_drinks/restaurant/_venue.dm
+++ b/code/modules/food_and_drinks/restaurant/_venue.dm
@@ -20,6 +20,8 @@
var/max_time_between_visitor = 90 SECONDS
///Required access to mess with the venue
var/req_access = ACCESS_KITCHEN
+ ///Blacklist for idiots that attack bots. Key is the mob that did it, and the value is the amount of warnings they've received.
+ var/list/mob_blacklist = list()
///Seats linked to this venue, assoc list of key holosign of seat position, and value of robot assigned to it, if any.
var/list/linked_seats = list()
diff --git a/code/modules/food_and_drinks/restaurant/customers/_customer.dm b/code/modules/food_and_drinks/restaurant/customers/_customer.dm
index 903d59df455..01474fe5c7a 100644
--- a/code/modules/food_and_drinks/restaurant/customers/_customer.dm
+++ b/code/modules/food_and_drinks/restaurant/customers/_customer.dm
@@ -19,6 +19,15 @@
var/list/leave_happy_lines = list("Leaving with food")
///Lines the robot says when leaving waiting for food
var/list/wait_for_food_lines = list("I'm still waiting for food")
+ ///Line when pulled by a friendly venue owner
+ var/friendly_pull_line = "Where are we going?"
+ ///Line when harrased by someone for the first time
+ var/first_warning_line = "Don't touch me!"
+ ///Line when harrased by someone for the second time
+ var/second_warning_line = "This is your last warning!"
+ ///Line when harrased by someone for the last time
+ var/self_defense_line = "Omae wa mo, shinderou."
+
///Clothing sets to pick from when dressing the robot.
var/list/clothing_sets = list("amerifat_clothes")
///List of prefixes for our robots name
@@ -49,6 +58,10 @@
leave_mad_lines = list("NO TIP FOR YOU. GOODBYE!", "At least at SpaceDonalds they serve their food FAST!", "This venue is horrendous!", "I will speak to your manager!", "I'll be sure to leave a bad Yelp review.")
leave_happy_lines = list("An extra tip for you my friend.", "Thanks for the great food!", "Diabetes is a myth anyway!")
wait_for_food_lines = list("Listen buddy, I'm getting real impatient over here!", "I've been waiting for ages...")
+ friendly_pull_line = "Where are you taking me? Not to medbay I hope, I don't have insurance."
+ first_warning_line = "Don't tread on me!"
+ second_warning_line = "Last chance buddy! Don't tread on me!"
+ self_defense_line = "CASTLE DOCTRINE ACTIVATED!"
/datum/customer_data/italian
@@ -62,6 +75,10 @@
leave_mad_lines = list("I have-a not seen-a this much disrespect in years!", "What-a horrendous establishment!")
leave_happy_lines = list("That's amoreee!", "Just like momma used to make it!")
wait_for_food_lines = list("I'ma so hungry...")
+ friendly_pull_line = "No-a I'm a hungry! I don't want to go anywhere."
+ first_warning_line = "Do not-a touch me!"
+ second_warning_line = "Last warning! Do not touch my spaghet."
+ self_defense_line = "I'm going to knead you like mama kneaded her delicious meatballs!"
orderable_objects = list(
/datum/venue/restaurant = list(/obj/item/food/spaghetti/pastatomato = 20, /obj/item/food/spaghetti/copypasta = 6, /obj/item/food/spaghetti/meatballspaghetti = 4, /obj/item/food/pizza/vegetable = 2, /obj/item/food/pizza/mushroom = 2, /obj/item/food/pizza/meat = 2, /obj/item/food/pizza/margherita = 2),
/datum/venue/bar = list(/datum/reagent/consumable/ethanol/fanciulli = 5, /datum/reagent/consumable/ethanol/branca_menta = 3, /datum/reagent/consumable/ethanol/beer = 10, /datum/reagent/consumable/lemonade = 8, /datum/reagent/consumable/ethanol/godfather = 5))
@@ -77,6 +94,10 @@
leave_mad_lines = list("Sacre bleu!", "Merde! This place is shittier than the Rhine!")
leave_happy_lines = list("Hon hon hon.", "A good effort.")
wait_for_food_lines = list("Hon hon hon")
+ friendly_pull_line = "Your filthy hands on my outfit? Yegh, fine."
+ first_warning_line = "Get your hands off of me!"
+ second_warning_line = "Do not touch me you filthy animal, last warning!"
+ self_defense_line = "I will break you like a baguette!"
speech_sound = 'sound/creatures/tourist/tourist_talk_french.ogg'
orderable_objects = list(
/datum/venue/restaurant = list(/obj/item/food/baguette = 20, /obj/item/food/garlicbread = 5, /obj/item/food/soup/onion = 4, /obj/item/food/pie/berryclafoutis = 2, /obj/item/food/omelette = 15),
@@ -101,6 +122,10 @@
leave_mad_lines = list("I can't believe you did this! WAAAAAAAAAAAAAH!!", "I-It's not like I ever wanted your food! B-baka...", "I was gonna give you my tip!")
leave_happy_lines = list("Oh NOURISHMENT PROVIDER! This is the happiest day of my life. I love you!", "I take a potato chip.... AND EAT IT!", "Itadakimasuuu~", "Gochisousama desu!")
wait_for_food_lines = list("No food yet? I guess it can't be helped.", "I can't wait to finally meet you burger-sama...", "Give me my food, you meanie!")
+ friendly_pull_line = "O-oh, where are you taking me?"
+ first_warning_line = "Don't touch me you pervert!"
+ second_warning_line = "I'm going to go super saiyan if you touch me again! Last warning!"
+ self_defense_line = "OMAE WA MO, SHINDEROU!"
speech_sound = 'sound/creatures/tourist/tourist_talk_japanese1.ogg'
orderable_objects = list(
/datum/venue/restaurant = list(/obj/item/food/tofu = 5, /obj/item/food/breadslice/plain = 5, /obj/item/food/soup/milo = 10, /obj/item/food/soup/vegetable = 4, /obj/item/food/sashimi = 4, /obj/item/food/chawanmushi = 4, /obj/item/food/muffin/berry = 2, /obj/item/food/beef_stroganoff = 2),
@@ -121,6 +146,10 @@
leave_mad_lines = list("This place is just downright shameful, and I'm telling my coworkers.", "What a waste of my time.", "I hope you don't take pride in the operation you run here.")
leave_happy_lines = list("Thank you for the hospitality.", "Otsukaresama deshita.", "Business calls.")
wait_for_food_lines = list("Zzzzzzzzzz...", "Dame da ne~", "Dame yo dame na no yo~")
+ friendly_pull_line = "Are we going on a business trip?"
+ first_warning_line = "Hey, only my employer gets to mess with me like that."
+ second_warning_line = "Leave me be, I'm trying to focus. Last warning!"
+ self_defense_line = "I didn't want it to end up like this."
speech_sound = 'sound/creatures/tourist/tourist_talk_japanese2.ogg'
orderable_objects = list(
/datum/venue/restaurant = list(/obj/item/food/tofu = 5, /obj/item/food/soup/milo = 6, /obj/item/food/soup/vegetable = 4, /obj/item/food/sashimi = 4, /obj/item/food/chawanmushi = 4, /obj/item/food/meatbun = 4, /obj/item/food/beef_stroganoff = 2),
@@ -142,3 +171,7 @@
leave_mad_lines = list("Aye dios mio, I'm out of here.", "Esto es ridÃculo! I'm leaving!", "I've seen better cooking at taco campana!", "I though this was a restaurant, pero es porquerÃa!")
leave_happy_lines = list("Amigo, era delicio. Thank you!", "Yo tuve el mono, and you friend? You hit the spot.", "Just the right amount of spicy!")
wait_for_food_lines = list("Ay ay ay, what's taking so long...", "Are you ready yet, amigo?")
+ friendly_pull_line = "Amigo, where are we headed?"
+ first_warning_line = "Amigo! Don't touch me like that."
+ second_warning_line = "Compadre, enough is enough! Last warning!"
+ self_defense_line = "Time for you to find out what kind of robot I am, eh?"
diff --git a/code/modules/mob/living/simple_animal/friendly/robot_customer.dm b/code/modules/mob/living/simple_animal/friendly/robot_customer.dm
index 9363cb1d654..3185461c933 100644
--- a/code/modules/mob/living/simple_animal/friendly/robot_customer.dm
+++ b/code/modules/mob/living/simple_animal/friendly/robot_customer.dm
@@ -1,8 +1,8 @@
///Robot customers
/mob/living/simple_animal/robot_customer
name = "space-tourist bot"
- maxHealth = 1000 //go fuck yourself
- health = 1000
+ maxHealth = 150
+ health = 150
desc = "I wonder what they'll order..."
gender = NEUTER
icon = 'icons/mob/tourists.dmi'
@@ -25,6 +25,7 @@
/mob/living/simple_animal/robot_customer/Initialize(mapload, datum/customer_data/customer_data = /datum/customer_data/american, datum/venue/attending_venue = SSrestaurant.all_venues[/datum/venue/restaurant])
ADD_TRAIT(src, TRAIT_NOMOBSWAP, INNATE_TRAIT) //dont push me bitch
ADD_TRAIT(src, TRAIT_NO_TELEPORT, INNATE_TRAIT) //dont teleport me bitch
+ ADD_TRAIT(src, TRAIT_STRONG_GRABBER, INNATE_TRAIT) //strong arms bitch
AddComponent(/datum/component/footstep, FOOTSTEP_OBJ_ROBOT, 1, -6, vary = TRUE)
var/datum/customer_data/customer_info = SSrestaurant.all_customers[customer_data]
clothes_set = pick(customer_info.clothing_sets)
@@ -84,4 +85,3 @@
if(ai_controller.blackboard[BB_CUSTOMER_CURRENT_ORDER])
var/datum/venue/attending_venue = ai_controller.blackboard[BB_CUSTOMER_ATTENDING_VENUE]
. += "Their order was: \"[attending_venue.order_food_line(ai_controller.blackboard[BB_CUSTOMER_CURRENT_ORDER])].\""
-