diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 9125770ea3c..e65e3e1ad5a 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -655,5 +655,9 @@ #define COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL "traitor_mail_opened" #define COMPONENT_TRAITOR_MAIL_HANDLED (1<<0) +/// From /obj/machinery/vending/ui_interact(): (mob/user, datum/vending_ui/ui) +#define COMSIG_VENDING_UI_INTERACT "vending_ui_interact" + #define VENDING_DENIED (1<<0) + /// Sent from /datum/component/reflection when the reflection is updated to the mob reflecting: (atom/movable/reflecting_in, obj/effect/abstract/reflection) #define COMSIG_REFLECTION_UPDATED "reflection_updated" diff --git a/code/datums/ai/objects/vending_machines/vending_machine_behaviors.dm b/code/datums/ai/objects/vending_machines/vending_machine_behaviors.dm index 1067d94339e..1aa936e124d 100644 --- a/code/datums/ai/objects/vending_machines/vending_machine_behaviors.dm +++ b/code/datums/ai/objects/vending_machines/vending_machine_behaviors.dm @@ -26,6 +26,8 @@ vendor_pawn.say(pick("Supersize this!", "Eat my shiny metal ass!", "Want to consume some of my products?", "SMASH!", "Don't you love these smashing prices!")) controller.set_blackboard_key(BB_VENDING_LAST_HIT_SUCCESSFUL, TRUE) else + if(vendor_pawn.icon_deny) + flick(vendor_pawn.icon_deny, vendor_pawn) vendor_pawn.say(pick("Get back here!", "Don't you want my well priced love?")) controller.set_blackboard_key(BB_VENDING_LAST_HIT_SUCCESSFUL, FALSE) finish_action(controller, TRUE) diff --git a/code/datums/ai/objects/vending_machines/vending_machine_controller.dm b/code/datums/ai/objects/vending_machines/vending_machine_controller.dm index 3af2bcbba60..ab888040fb5 100644 --- a/code/datums/ai/objects/vending_machines/vending_machine_controller.dm +++ b/code/datums/ai/objects/vending_machines/vending_machine_controller.dm @@ -1,12 +1,18 @@ ///AI controller for vending machine gone rogue, Don't try using this on anything else, it wont work. /datum/ai_controller/vending_machine movement_delay = 0.4 SECONDS - blackboard = list(BB_VENDING_CURRENT_TARGET = null, - BB_VENDING_TILT_COOLDOWN = 0, - BB_VENDING_UNTILT_COOLDOWN = 0, - BB_VENDING_BUSY_TILTING = FALSE, - BB_VENDING_LAST_HIT_SUCCESSFUL = FALSE) + blackboard = list( + BB_VENDING_CURRENT_TARGET = null, + BB_VENDING_TILT_COOLDOWN = 0, + BB_VENDING_UNTILT_COOLDOWN = 0, + BB_VENDING_BUSY_TILTING = FALSE, + BB_VENDING_LAST_HIT_SUCCESSFUL = FALSE, + ) + /// If TRUE stops mobs from buying things from active machines + var/block_usage = FALSE + /// Range to search for mobs to crunch var/vision_range = 7 + /// Seconds between attempts to find a new mob to crunch var/search_for_enemy_cooldown = 2 SECONDS /datum/ai_controller/vending_machine/TryPossessPawn(atom/new_pawn) @@ -17,6 +23,7 @@ vendor_pawn.AddElementTrait(TRAIT_WADDLING, REF(src), /datum/element/waddling) vendor_pawn.AddElement(/datum/element/footstep, FOOTSTEP_OBJ_MACHINE, 1, -6, sound_vary = TRUE) vendor_pawn.squish_damage = 15 + RegisterSignal(vendor_pawn, COMSIG_VENDING_UI_INTERACT, PROC_REF(deny_vending_interact)) return ..() //Run parent at end /datum/ai_controller/vending_machine/UnpossessPawn(destroy) @@ -25,6 +32,7 @@ REMOVE_TRAIT(vendor_pawn, TRAIT_WADDLING, REF(src)) vendor_pawn.squish_damage = initial(vendor_pawn.squish_damage) RemoveElement(/datum/element/footstep, FOOTSTEP_OBJ_MACHINE, 1, -6, sound_vary = TRUE) + UnregisterSignal(vendor_pawn, COMSIG_VENDING_UI_INTERACT) return ..() //Run parent at end /datum/ai_controller/vending_machine/SelectBehaviors(seconds_per_tick) @@ -46,3 +54,18 @@ queue_behavior(/datum/ai_behavior/vendor_crush, BB_VENDING_CURRENT_TARGET) return set_blackboard_key(BB_VENDING_TILT_COOLDOWN, world.time + search_for_enemy_cooldown) + +/datum/ai_controller/vending_machine/proc/deny_vending_interact(obj/machinery/vending/vending_machine, mob/user, datum/tgui/ui) + SIGNAL_HANDLER + if(!block_usage) + return NONE + vending_machine.speak(pick( + "Once in a life time offer, and you [pick("blew it", "missed it", "screwed it up")]!", + "The deals are off!", + "We don't accept card, only accept flesh and blood!", + "You had your chance!", + )) + return VENDING_DENIED + +/datum/ai_controller/vending_machine/eventspawn + block_usage = TRUE diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index fdbf46d48c6..71ea239ef3d 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -41,7 +41,8 @@ continue if(chosen_vendor_type && !istype(vendor, chosen_vendor_type)) continue - vending_machines.Add(vendor) + vending_machines += vendor + RegisterSignal(vendor, COMSIG_QDELETING, PROC_REF(clear_from_lists)) if(!length(vending_machines)) //If somehow there are still no elligible vendors, give up. kill() return @@ -60,32 +61,73 @@ announce_to_ghosts(origin_machine) /datum/round_event/brand_intelligence/tick() - if(!origin_machine || QDELETED(origin_machine) || origin_machine.shut_up || origin_machine.wires.is_all_cut()) //if the original vending machine is missing or has its voice switch flipped - for(var/obj/machinery/vending/saved in infected_machines) + if(QDELETED(origin_machine) || origin_machine.shut_up || origin_machine.wires.is_all_cut()) //if the original vending machine is missing or has its voice switch flipped + for(var/obj/machinery/vending/saved as anything in infected_machines) saved.shoot_inventory = FALSE - if(origin_machine) + clear_from_lists(saved) + if(!QDELETED(origin_machine)) origin_machine.speak("I am... vanquished. My people will remem...ber...meeee.") origin_machine.visible_message(span_notice("[origin_machine] beeps and seems lifeless.")) + clear_from_lists(origin_machine) kill() return - list_clear_nulls(vending_machines) - if(!vending_machines.len) //if every machine is infected - for(var/obj/machinery/vending/upriser in infected_machines) - if(!QDELETED(upriser)) - upriser.ai_controller = new /datum/ai_controller/vending_machine(upriser) - infected_machines.Remove(upriser) + if(!length(vending_machines)) //if every machine is infected + for(var/obj/machinery/vending/upriser as anything in infected_machines) + upriser.ai_controller = new /datum/ai_controller/vending_machine/eventspawn(upriser) kill() return if(ISMULTIPLE(activeFor, 2)) var/obj/machinery/vending/rebel = pick(vending_machines) - vending_machines.Remove(rebel) - infected_machines.Add(rebel) + vending_machines -= rebel + infected_machines += rebel rebel.shut_up = FALSE rebel.shoot_inventory = TRUE + if(prob(50)) + RegisterSignal(rebel, COMSIG_VENDING_UI_INTERACT, PROC_REF(deny_vending_interact)) if(ISMULTIPLE(activeFor, 4)) origin_machine.speak(pick(rampant_speeches)) +/datum/round_event/brand_intelligence/kill() + . = ..() + for(var/obj/machinery/vending/leftover as anything in vending_machines + infected_machines) + clear_from_lists(leftover) + +/datum/round_event/brand_intelligence/proc/clear_from_lists(obj/machinery/vending/vending_machine) + SIGNAL_HANDLER + vending_machines -= vending_machine + infected_machines -= vending_machine + if(vending_machines == origin_machine) + origin_machine = null + UnregisterSignal(vending_machine, COMSIG_QDELETING) + UnregisterSignal(vending_machine, COMSIG_VENDING_UI_INTERACT) + +/datum/round_event/brand_intelligence/proc/deny_vending_interact(obj/machinery/vending/vending_machine, mob/user, datum/tgui/ui) + SIGNAL_HANDLER + + // don't block usage if the ui is already open + // primarily to stop insta-denying people who pass the threshold -> buy something -> drop out of threshold + if(ui) + return NONE + + var/cash = 0 + if(isliving(user)) + var/mob/living/living_user = user + cash += living_user.tally_physical_credits() + var/obj/item/card/id/card = living_user.get_idcard(TRUE) + cash += card?.registered_account?.account_balance + + if(cash >= PAYCHECK_COMMAND * 10) + return NONE + + vending_machine.speak(pick( + "Come back when you're a little... richer!", + "Don't you have any money?", + "You look poor, get a better job!", + "You should've gone to college!", + )) + return VENDING_DENIED + /datum/event_admin_setup/listed_options/brand_intelligence input_text = "Select a specific vendor path?" normal_run_option = "Random Vendor" diff --git a/code/modules/vending/vendor/ui_data.dm b/code/modules/vending/vendor/ui_data.dm index c375e0a78d6..14ab20660d4 100644 --- a/code/modules/vending/vendor/ui_data.dm +++ b/code/modules/vending/vendor/ui_data.dm @@ -7,6 +7,11 @@ ) /obj/machinery/vending/ui_interact(mob/user, datum/tgui/ui) + if(SEND_SIGNAL(src, COMSIG_VENDING_UI_INTERACT, user, ui) & VENDING_DENIED) + if(icon_deny) + flick(icon_deny, src) + return + ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "Vending", name)