diff --git a/modular_skyrat/modules/armaments/code/armament_component.dm b/modular_skyrat/modules/armaments/code/armament_component.dm index 6b2ba7e8129..94aef7a7308 100644 --- a/modular_skyrat/modules/armaments/code/armament_component.dm +++ b/modular_skyrat/modules/armaments/code/armament_component.dm @@ -1,7 +1,7 @@ /** - * This is the componentised version of the armaments vendor. + * This is the component that runs the armaments vendor. * - * It's intended to be used with NPC vendors, or atoms that otherwise aren't vending machines. + * It's intended to be used with the armament vendor, or other atoms that otherwise aren't vending machines. */ /datum/component/armament @@ -11,8 +11,14 @@ var/list/required_access /// Our parent machine. var/atom/parent_atom + /// The points card that is currently inserted into the parent. + var/obj/item/armament_points_card/inserted_card + /// Used to keep track of what categories have been used. + var/list/used_categories = list() + /// Used to keep track of what items have been purchased. + var/list/purchased_items = list() -/datum/component/armament/Initialize(list/required_products, list/required_access) +/datum/component/armament/Initialize(list/required_products, list/needed_access) if(!required_products) stack_trace("No products specified for armament") return COMPONENT_INCOMPATIBLE @@ -24,9 +30,31 @@ products = required_products + required_access = needed_access RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/on_attack_hand) + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/on_attackby) +/datum/component/armament/Destroy(force, silent) + if(inserted_card) + inserted_card.forceMove(parent_atom.drop_location()) + inserted_card = null + return ..() + +/datum/component/armament/proc/on_attackby(atom/target, obj/item, mob/user) + SIGNAL_HANDLER + + if(!user || !item) + return + + if(!user.can_interact_with(parent_atom)) + return + + if(!istype(item, /obj/item/armament_points_card)) + return + + item.forceMove(parent_atom) + inserted_card = item /datum/component/armament/proc/on_attack_hand(datum/source, mob/living/user) SIGNAL_HANDLER @@ -37,6 +65,10 @@ if(!user.can_interact_with(parent_atom)) return + if(!check_access(user)) + to_chat(user, span_warning("You don't have the required access!")) + return + INVOKE_ASYNC(src, .proc/ui_interact, user) /datum/component/armament/ui_interact(mob/user, datum/tgui/ui) @@ -45,5 +77,172 @@ ui = new(user, src, "ArmamentStation") ui.open() +/datum/component/armament/ui_data(mob/user) + var/list/data = list() + data["card_inserted"] = inserted_card ? TRUE : FALSE + data["card_name"] = "unknown" + data["card_points"] = 0 + if(inserted_card) + data["card_points"] = inserted_card.points + data["card_name"] = inserted_card.name + data["armaments_list"] = list() + for(var/armament_category as anything in GLOB.armament_entries) + var/list/armament_subcategories = list() + for(var/subcategory as anything in GLOB.armament_entries[armament_category][CATEGORY_ENTRY]) + var/list/subcategory_items = list() + for(var/datum/armament_entry/armament_entry as anything in GLOB.armament_entries[armament_category][CATEGORY_ENTRY][subcategory]) + if(products && !(armament_entry.type in products)) + continue + subcategory_items += list(list( + "ref" = REF(armament_entry), + "icon" = armament_entry.cached_base64, + "name" = armament_entry.name, + "cost" = armament_entry.cost, + "buyable_ammo" = armament_entry.magazine ? TRUE : FALSE, + "magazine_cost" = armament_entry.magazine_cost, + "quantity" = armament_entry.max_purchase, + "purchased" = purchased_items[armament_entry] ? purchased_items[armament_entry] : 0, + "description" = armament_entry.description, + "armament_category" = armament_entry.category, + "equipment_subcategory" = armament_entry.subcategory, + )) + if(!LAZYLEN(subcategory_items)) + continue + armament_subcategories += list(list( + "subcategory" = subcategory, + "items" = subcategory_items, + )) + if(!LAZYLEN(armament_subcategories)) + continue + data["armaments_list"] += list(list( + "category" = armament_category, + "category_limit" = GLOB.armament_entries[armament_category][CATEGORY_LIMIT], + "category_uses" = used_categories[armament_category], + "subcategories" = armament_subcategories, + )) + + return data + +/datum/component/armament/ui_act(action, list/params) + . = ..() + if(.) + return + + switch(action) + if("equip_item") + var/check = check_item(params["armament_ref"]) + if(!check) + return + select_armament(usr, check) + if("buy_ammo") + var/check = check_item(params["armament_ref"]) + if(!check) + return + buy_ammo(usr, check, params["quantity"]) + if("eject_card") + eject_card(usr) + +/datum/component/armament/proc/buy_ammo(mob/user, datum/armament_entry/armament_entry, quantity = 1) + if(!armament_entry.magazine) + return + if(!inserted_card) + to_chat(user, span_warning("No card inserted!")) + return + var/quantity_cost = armament_entry.magazine_cost * quantity + if(!inserted_card.use_points(quantity_cost)) + to_chat(user, span_warning("Not enough points!")) + return + for(var/i in 1 to quantity) + new armament_entry.magazine(parent_atom.drop_location()) + +/datum/component/armament/proc/check_item(reference) + var/datum/armament_entry/armament_entry + for(var/category in GLOB.armament_entries) + for(var/subcategory in GLOB.armament_entries[category][CATEGORY_ENTRY]) + armament_entry = locate(reference) in GLOB.armament_entries[category][CATEGORY_ENTRY][subcategory] + if(armament_entry) + break + if(armament_entry) + break + if(!armament_entry) + return FALSE + if(products && !(armament_entry.type in products)) + return FALSE + return armament_entry + +/datum/component/armament/proc/eject_card(mob/user) + if(!inserted_card) + to_chat(user, span_warning("No card inserted!")) + return + inserted_card.forceMove(parent_atom.drop_location()) + user.put_in_hands(inserted_card) + inserted_card = null + to_chat(user, span_notice("Card ejected!")) + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 70) + +/datum/component/armament/proc/select_armament(mob/user, datum/armament_entry/armament_entry) + if(!inserted_card) + to_chat(user, span_warning("No card inserted!")) + return + if(used_categories[armament_entry.category] >= GLOB.armament_entries[armament_entry.category][CATEGORY_LIMIT]) + to_chat(user, span_warning("Category limit reached!")) + return + if(purchased_items[armament_entry] >= armament_entry.max_purchase) + to_chat(user, span_warning("Item limit reached!")) + return + if(!ishuman(user)) + return + if(!inserted_card.use_points(armament_entry.cost)) + to_chat(user, span_warning("Not enough points!")) + return + + var/mob/living/carbon/human/human_to_equip = user + + var/obj/item/new_item = new armament_entry.item_type(parent_atom.drop_location()) + + used_categories[armament_entry.category]++ + purchased_items[armament_entry]++ + + playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3) + + if(armament_entry.equip_to_human(human_to_equip, new_item)) + to_chat(user, span_notice("Equipped directly to your person.")) + playsound(src, 'sound/items/equip/toolbelt_equip.ogg', 100) + armament_entry.after_equip(parent_atom.drop_location(), new_item) + +/datum/component/armament/proc/check_access(mob/living/user) + if(!user) + return FALSE + + if(!required_access) + return TRUE + + if(issilicon(user)) + if(ispAI(user)) + return FALSE + return TRUE //AI can do whatever it wants + + if(isAdminGhostAI(user)) + return TRUE + + //If the mob has the simple_access component with the requried access, the check passes + else if(SEND_SIGNAL(user, COMSIG_MOB_TRIED_ACCESS, src) & ACCESS_ALLOWED) + return TRUE + + //If the mob is holding a valid ID, they pass the access check + else if(check_access(user.get_active_held_item())) + return TRUE + + //if they are wearing a card that has access and are human, that works + else if(ishuman(user)) + var/mob/living/carbon/human/human_user = user + if(check_access(human_user.wear_id)) + return TRUE + + //if they're strange and have a hacky ID card as an animal + else if(isanimal(user)) + var/mob/living/simple_animal/animal = user + if(check_access(animal.access_card)) + return TRUE diff --git a/modular_skyrat/modules/armaments/code/armament_station.dm b/modular_skyrat/modules/armaments/code/armament_station.dm index 5f5a9f9e358..c47632479c9 100644 --- a/modular_skyrat/modules/armaments/code/armament_station.dm +++ b/modular_skyrat/modules/armaments/code/armament_station.dm @@ -2,7 +2,7 @@ * Armament Station * * These are the stations designed to be used by players to outfit themselves. - * They contain a "products" variable which you can populate with your own set of armament entries. + * They are a container for the armament component, which must be supplied with a type path of armament entries, and optionally a list of required accesses to use the vendor. * * If you plan on making your own station, it is strongly recommended you use your own armament entries for whatever it is you're doing. * @@ -10,176 +10,23 @@ * * @author Gandalf2k15 */ - /obj/machinery/armament_station name = "Armament Outfitting Station" desc = "A versatile station for equipping your weapons." icon = 'icons/obj/vending.dmi' icon_state = "liberationstation" density = TRUE - /// Used to keep track of what categories have been used - var/list/used_categories = list() - /// Used to keep track of what items have been purchased - var/list/purchased_items = list() - /// If set, will limit this station to the products within this list. - var/list/products - /// The points card that is currently inserted. - var/obj/item/armament_points_card/inserted_card + /// The armament entry type path that will fill the armament station's list. + var/armament_type + /// The access needed to use the vendor + var/list/required_access = list() -/obj/machinery/armament_station/attackby(obj/item/weapon, mob/user, params) +/obj/machinery/armament_station/ComponentInitialize() . = ..() - if(istype(weapon, /obj/item/armament_points_card)) - var/obj/item/inserting_card = weapon - if(inserted_card) - to_chat(user, span_warning("There is already a card inserted into [src]!")) - return - inserted_card = inserting_card - inserted_card.forceMove(src) - to_chat(user, span_notice("You insert [inserting_card] into [src]!")) - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 70) - -/obj/machinery/armament_station/ui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "ArmamentStation") - ui.open() - -// This data proc may look complex. That's because it is. -/obj/machinery/armament_station/ui_data(mob/user) - var/list/data = list() - - data["card_inserted"] = inserted_card ? TRUE : FALSE - data["card_name"] = "unknown" - data["card_points"] = 0 - if(inserted_card) - data["card_points"] = inserted_card.points - data["card_name"] = inserted_card.name - - data["armaments_list"] = list() - for(var/armament_category as anything in GLOB.armament_entries) - var/list/armament_subcategories = list() - for(var/subcategory as anything in GLOB.armament_entries[armament_category][CATEGORY_ENTRY]) - var/list/subcategory_items = list() - for(var/datum/armament_entry/armament_entry as anything in GLOB.armament_entries[armament_category][CATEGORY_ENTRY][subcategory]) - if(products && !(armament_entry.type in products)) - continue - subcategory_items += list(list( - "ref" = REF(armament_entry), - "icon" = armament_entry.cached_base64, - "name" = armament_entry.name, - "cost" = armament_entry.cost, - "buyable_ammo" = armament_entry.magazine ? TRUE : FALSE, - "magazine_cost" = armament_entry.magazine_cost, - "quantity" = armament_entry.max_purchase, - "purchased" = purchased_items[armament_entry] ? purchased_items[armament_entry] : 0, - "description" = armament_entry.description, - "armament_category" = armament_entry.category, - "equipment_subcategory" = armament_entry.subcategory, - )) - if(!LAZYLEN(subcategory_items)) - continue - armament_subcategories += list(list( - "subcategory" = subcategory, - "items" = subcategory_items, - )) - if(!LAZYLEN(armament_subcategories)) - continue - data["armaments_list"] += list(list( - "category" = armament_category, - "category_limit" = GLOB.armament_entries[armament_category][CATEGORY_LIMIT], - "category_uses" = used_categories[armament_category], - "subcategories" = armament_subcategories, - )) - - return data - -/obj/machinery/armament_station/ui_act(action, list/params) - . = ..() - if(.) + if(!armament_type) return + AddComponent(/datum/component/armament, subtypesof(armament_type), ACCESS_SYNDICATE) - switch(action) - if("equip_item") - var/check = check_item(params["armament_ref"]) - if(!check) - return - select_armament(usr, check) - if("buy_ammo") - var/check = check_item(params["armament_ref"]) - if(!check) - return - buy_ammo(usr, check, params["quantity"]) - if("eject_card") - eject_card(usr) - -/obj/machinery/armament_station/proc/buy_ammo(mob/user, datum/armament_entry/armament_entry, quantity = 1) - if(!armament_entry.magazine) - return - if(!inserted_card) - to_chat(user, span_warning("No card inserted!")) - return - var/quantity_cost = armament_entry.magazine_cost * quantity - if(!inserted_card.use_points(quantity_cost)) - to_chat(user, span_warning("Not enough points!")) - return - for(var/i in 1 to quantity) - new armament_entry.magazine(drop_location()) - - -/obj/machinery/armament_station/proc/check_item(reference) - var/datum/armament_entry/armament_entry - for(var/category in GLOB.armament_entries) - for(var/subcategory in GLOB.armament_entries[category][CATEGORY_ENTRY]) - armament_entry = locate(reference) in GLOB.armament_entries[category][CATEGORY_ENTRY][subcategory] - if(armament_entry) - break - if(armament_entry) - break - if(!armament_entry) - return FALSE - if(products && !(armament_entry.type in products)) - return FALSE - return armament_entry - -/obj/machinery/armament_station/proc/eject_card(mob/user) - if(!inserted_card) - to_chat(user, span_warning("No card inserted!")) - return - inserted_card.forceMove(drop_location()) - user.put_in_hands(inserted_card) - inserted_card = null - to_chat(user, span_notice("Card ejected!")) - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 70) - -/obj/machinery/armament_station/proc/select_armament(mob/user, datum/armament_entry/armament_entry) - if(!inserted_card) - to_chat(user, span_warning("No card inserted!")) - return - if(used_categories[armament_entry.category] >= GLOB.armament_entries[armament_entry.category][CATEGORY_LIMIT]) - to_chat(user, span_warning("Category limit reached!")) - return - if(purchased_items[armament_entry] >= armament_entry.max_purchase) - to_chat(user, span_warning("Item limit reached!")) - return - if(!ishuman(user)) - return - if(!inserted_card.use_points(armament_entry.cost)) - to_chat(user, span_warning("Not enough points!")) - return - - var/mob/living/carbon/human/human_to_equip = user - - var/obj/item/new_item = new armament_entry.item_type(drop_location()) - - used_categories[armament_entry.category]++ - purchased_items[armament_entry]++ - - playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3) - - if(armament_entry.equip_to_human(human_to_equip, new_item)) - to_chat(user, span_notice("Equipped directly to your person.")) - playsound(src, 'sound/items/equip/toolbelt_equip.ogg', 100) - armament_entry.after_equip(drop_location(), new_item) /** * Armament points card diff --git a/modular_skyrat/modules/assault_operatives/code/armaments/assaultops_armament_station.dm b/modular_skyrat/modules/assault_operatives/code/armaments/assaultops_armament_station.dm index 919d0d4ddc2..2a4ad551205 100644 --- a/modular_skyrat/modules/assault_operatives/code/armaments/assaultops_armament_station.dm +++ b/modular_skyrat/modules/assault_operatives/code/armaments/assaultops_armament_station.dm @@ -2,13 +2,9 @@ /obj/machinery/armament_station/assault_operatives name = "Military Grade Armament Station" - req_access = list(ACCESS_SYNDICATE) - - -/obj/machinery/armament_station/assault_operatives/Initialize(mapload) - . = ..() - products = subtypesof(/datum/armament_entry/assault_operatives) + required_access = list(ACCESS_SYNDICATE) + armament_type = /datum/armament_entry/assault_operatives // POINTS CARDS /obj/item/armament_points_card/assaultops