diff --git a/code/__DEFINES/equipment.dm b/code/__DEFINES/equipment.dm index 81c3bd289f..c20740ea29 100644 --- a/code/__DEFINES/equipment.dm +++ b/code/__DEFINES/equipment.dm @@ -94,6 +94,8 @@ #define HEALING_ITEM (1<<16) /// This item is classified as ammunition for the sake of human AI #define AMMUNITION_ITEM (1<<17) +/// This item is classified as a grenade for the sake of human AI +#define GRENADE_ITEM (1<<18) //========================================================================================== diff --git a/code/__DEFINES/human_ai.dm b/code/__DEFINES/human_ai.dm index 076224e13f..be6a6d62e8 100644 --- a/code/__DEFINES/human_ai.dm +++ b/code/__DEFINES/human_ai.dm @@ -1,5 +1,6 @@ #define HUMAN_AI_HEALTHITEMS "health" #define HUMAN_AI_AMMUNITION "ammo" +#define HUMAN_AI_GRENADES "grenades" /// Action is completed, delete this and move onto the next ongoing action #define ONGOING_ACTION_COMPLETED "completed" diff --git a/code/game/objects/items/explosives/grenades/grenade.dm b/code/game/objects/items/explosives/grenades/grenade.dm index b2f95646a9..9c4efc4d8b 100644 --- a/code/game/objects/items/explosives/grenades/grenade.dm +++ b/code/game/objects/items/explosives/grenades/grenade.dm @@ -9,6 +9,7 @@ throw_range = 7 flags_atom = FPRINT|CONDUCT flags_equip_slot = SLOT_WAIST + flags_item = GRENADE_ITEM hitsound = 'sound/weapons/smash.ogg' allowed_sensors = list(/obj/item/device/assembly/timer) max_container_volume = 60 @@ -151,3 +152,21 @@ walk(src, null, null) ..() return + +/obj/item/explosive/grenade/ai_can_use(mob/living/carbon/human/user) + return TRUE + +/obj/item/explosive/grenade/ai_use(mob/living/carbon/human/ai/user, turf/target_turf) + attack_self(user) + user.toggle_throw_mode(THROW_MODE_NORMAL) + user.ai_brain.ensure_primary_hand(src) + sleep(det_time * 0.4) + if(QDELETED(src) || (loc != user)) + return + + user.ai_brain.say_grenade_thrown_line() + sleep(det_time * 0.4) + if(QDELETED(src) || (loc != user)) + return + + user.throw_item(user.ai_brain.target_floor) diff --git a/code/modules/mob/living/carbon/human/ai/action_datums/item_pickup.dm b/code/modules/mob/living/carbon/human/ai/action_datums/item_pickup.dm index de113f8231..8d5322e346 100644 --- a/code/modules/mob/living/carbon/human/ai/action_datums/item_pickup.dm +++ b/code/modules/mob/living/carbon/human/ai/action_datums/item_pickup.dm @@ -55,11 +55,22 @@ return ONGOING_ACTION_COMPLETED if(is_type_in_list(to_pickup, brain.all_medical_items)) - brain.store_item(to_pickup, storage_spot) + brain.tied_human.put_in_hands(to_pickup, TRUE) + brain.store_item(to_pickup, storage_spot, HUMAN_AI_HEALTHITEMS) return ONGOING_ACTION_COMPLETED if(brain.primary_weapon && istype(to_pickup, /obj/item/ammo_magazine)) var/obj/item/ammo_magazine/mag = to_pickup if(istype(brain.primary_weapon, mag.gun_type)) - brain.store_item(to_pickup, storage_spot) + brain.tied_human.put_in_hands(to_pickup, TRUE) + brain.store_item(to_pickup, storage_spot, HUMAN_AI_AMMUNITION) + return ONGOING_ACTION_COMPLETED + + if(istype(to_pickup, /obj/item/explosive/grenade)) + var/obj/item/explosive/grenade/nade = to_pickup + if(!nade.active) + brain.tied_human.put_in_hands(to_pickup, TRUE) + brain.store_item(to_pickup, storage_spot, HUMAN_AI_GRENADES) return ONGOING_ACTION_COMPLETED + + return ONGOING_ACTION_COMPLETED diff --git a/code/modules/mob/living/carbon/human/ai/action_datums/throw_grenade.dm b/code/modules/mob/living/carbon/human/ai/action_datums/throw_grenade.dm new file mode 100644 index 0000000000..9cae1ad53d --- /dev/null +++ b/code/modules/mob/living/carbon/human/ai/action_datums/throw_grenade.dm @@ -0,0 +1,31 @@ +/datum/ongoing_action/throw_grenade + name = "Throw Grenade" + var/obj/item/explosive/grenade/throwing + var/turf/target_turf + var/mid_throw = FALSE + +/datum/ongoing_action/throw_grenade/New(datum/human_ai_brain/brain, list/arguments) + . = ..() + throwing = arguments[2] + target_turf = arguments[3] + +/datum/ongoing_action/throw_grenade/Destroy(force, ...) + throwing = null + target_turf = null + return ..() + +/datum/ongoing_action/throw_grenade/trigger_action() + if(QDELETED(throwing) || !target_turf) + return ONGOING_ACTION_COMPLETED + + if(mid_throw) + return ONGOING_ACTION_UNFINISHED_BLOCK + + mid_throw = TRUE + brain.holster_primary() + brain.equip_item_from_equipment_map(HUMAN_AI_GRENADES, throwing) + sleep(brain.short_action_delay * brain.action_delay_mult) + if(QDELETED(throwing) || (throwing.loc != brain.tied_human)) + return ONGOING_ACTION_COMPLETED + throwing.ai_use(brain.tied_human, target_turf) + return ONGOING_ACTION_COMPLETED diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain.dm index 4977d452c4..e68000b1c4 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain.dm @@ -60,6 +60,7 @@ GLOBAL_LIST_EMPTY(human_ai_brains) target_floor = null ongoing_order = null GLOB.human_ai_brains -= src + gun_data = null return ..() /datum/human_ai_brain/process(delta_time) diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_communication.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_communication.dm index bbd1417f2b..65c3167029 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_communication.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_communication.dm @@ -10,7 +10,7 @@ "Hostile spotted, engaging!", "Enemy hostiles here!", "Being fired upon!", - "Blast 'em!" + "Blast 'em!", ) var/list/exit_combat_lines = list( @@ -30,25 +30,42 @@ "Goddamn it.", "Fuck!", "Shit, our squad's down a man!", - "Squad integrity's failing!" + "Squad integrity's failing!", + ) + + var/list/grenade_thrown_lines = list( + "Nade out!", + "Tossing a grenade!", + "Smoking 'em out!", + "Throwing a nade!", + "Grenade out!", + "Tossing a nade!", + "Pineapple out!", + "Fragging 'em!", ) var/in_combat_line_chance = 40 var/exit_combat_line_chance = 40 var/squad_member_death_line_chance = 20 + var/grenade_thrown_line_chance = 60 /datum/human_ai_brain/proc/say_in_combat_line(chance = in_combat_line_chance) - if(!prob(chance)) + if(!length(in_combat_lines) || !prob(chance)) return tied_human.say(pick(in_combat_lines)) /datum/human_ai_brain/proc/say_exit_combat_line(chance = exit_combat_line_chance) - if(!prob(chance)) + if(!length(exit_combat_lines) || !prob(chance)) return tied_human.say(pick(exit_combat_lines)) /datum/human_ai_brain/proc/on_squad_member_death(mob/living/carbon/human/dead_member) - if(!prob(squad_member_death_line_chance)) + if(!length(squad_member_death_lines) || !prob(squad_member_death_line_chance)) return tied_human.say(pick(squad_member_death_lines)) + +/datum/human_ai_brain/proc/say_grenade_thrown_line(chance = grenade_thrown_line_chance) + if(!length(grenade_thrown_lines) || !prob(chance)) + return + tied_human.say(pick(grenade_thrown_lines)) diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_factions.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_factions.dm index 19a87a3afb..ff7fc67efb 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_factions.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_factions.dm @@ -5,6 +5,7 @@ VAR_PROTECTED/list/in_combat_lines = list() VAR_PROTECTED/list/exit_combat_lines = list() VAR_PROTECTED/list/squad_member_death_lines = list() + VAR_PROTECTED/list/grenade_thrown_lines = list() VAR_PROTECTED/list/friendly_factions = list() VAR_PROTECTED/list/neutral_factions = list() @@ -19,6 +20,9 @@ if(length(squad_member_death_lines)) brain.squad_member_death_lines = squad_member_death_lines + if(length(grenade_thrown_lines)) + brain.grenade_thrown_lines = grenade_thrown_lines + brain.shoot_to_kill = shoot_to_kill brain.friendly_factions = friendly_factions brain.neutral_factions = neutral_factions @@ -102,35 +106,36 @@ FACTION_MERCENARY, FACTION_TWE, ) - in_combat_lines = list( // zonenote: tweak these. They're entirely the stereotype of "communist russkie" when we can do better than that. also languages - "For the UPP!", - "Die, you animal!", - "Capitalist dog!", - "Shoot them!", - "For glorious Union!", - "Attacking!", - "We will bury them!", - "Uraaaa!!", - "URAAA!!", - "To your last breath!", - "You're worth nothing!", - "This is the end, for you!", - "Die!", - ) - exit_combat_lines = list( - "I need a break...", - "Phew, that was tough work.", - "I think we can stop shooting now?", - "One step closer to victory!", - "Finally, break time.", - ) - squad_member_death_lines = list( - "Man down!", - "Comrade!!", - "Get together!", - "Damn!", - "Taking hits!", - ) + in_combat_lines = list( // zonenote: tweak these. They're entirely the stereotype of "communist russkie" when we can do better than that. also languages + "For the UPP!", + "Die, you animal!", + "Capitalist dog!", + "Shoot them!", + "For glorious Union!", + "Attacking!", + "We will bury them!", + "Uraaaa!!", + "URAAA!!", + "To your last breath!", + "You're worth nothing!", + "This is the end, for you!", + "Die!", + "*warcry", + ) + exit_combat_lines = list( + "I need a break...", + "Phew, that was tough work.", + "I think we can stop shooting now?", + "One step closer to victory!", + "Finally, break time.", + ) + squad_member_death_lines = list( + "Man down!", + "Comrade!!", + "Get together!", + "Damn!", + "Taking hits!", + ) /datum/human_ai_faction/wy @@ -169,3 +174,4 @@ "Allied unit decomissioned.", "Friendly unit disabled." ) + grenade_thrown_lines = list() // Wouldn't need to call this out diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_guns.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_guns.dm index 192d22c1b0..ce0c36e8ab 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_guns.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_guns.dm @@ -81,4 +81,9 @@ return mag /datum/human_ai_brain/proc/should_reload_primary() - return (primary_weapon?.current_mag?.current_rounds <= 0) + if(gun_data?.disposable) + return FALSE + + if(primary_weapon?.current_mag?.current_rounds <= 0) + return TRUE + return FALSE diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_items.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_items.dm index 3e29b4931b..4ca353fd76 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_items.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_items.dm @@ -5,6 +5,7 @@ var/list/equipment_map = list( HUMAN_AI_HEALTHITEMS = list(), HUMAN_AI_AMMUNITION = list(), + HUMAN_AI_GRENADES = list(), ) var/list/container_refs = list( @@ -21,6 +22,8 @@ WEAR_R_STORE, ) + var/static/important_storage_slots_bitflag = SLOT_BACK | SLOT_WAIST | SLOT_STORE + /datum/human_ai_brain/proc/get_object_from_loc(object_loc) RETURN_TYPE(/obj/item/storage) @@ -44,10 +47,11 @@ var/obj/item/storage/storage_object = get_object_from_loc(object_loc) storage_object.remove_from_storage(object_ref, tied_human) + tied_human.put_in_active_hand(object_ref) equipped_items_original_loc[object_ref] = object_loc RegisterSignal(object_ref, COMSIG_ITEM_DROPPED, PROC_REF(on_equipment_dropped), override = TRUE) -/datum/human_ai_brain/proc/store_item(obj/item/object_ref, object_loc) +/datum/human_ai_brain/proc/store_item(obj/item/object_ref, object_loc, slot_type) if(object_ref.loc != tied_human) return @@ -58,6 +62,8 @@ else if(object_loc) // we assume that we've already checked if something will fit or not var/obj/item/storage/storage_item = container_refs[object_loc] storage_item.attempt_item_insertion(object_ref, FALSE, tied_human) + if(slot_type) + equipment_map[slot_type][object_ref] = object_loc /// Whenever an item is deleted, purge it from anywhere it may be stored in here @@ -87,9 +93,9 @@ /datum/human_ai_brain/proc/on_item_unequip(datum/source, obj/item/equipment, slot) SIGNAL_HANDLER - if((slot in important_storage_slots) && istype(equipment, /obj/item/storage)) + if((important_storage_slots_bitflag & slot) && istype(equipment, /obj/item/storage)) recalculate_containers() - appraise_inventory(slot == WEAR_WAIST, slot == WEAR_BACK, slot == WEAR_L_STORE, slot == WEAR_R_STORE) + appraise_inventory(slot == SLOT_WAIST, slot == SLOT_BACK, slot == SLOT_STORE, slot == SLOT_STORE) if(isgun(equipment)) appraise_inventory(FALSE, FALSE, FALSE, FALSE) @@ -110,14 +116,12 @@ if(previous_faction != tied_human.faction) previous_faction = tied_human.faction var/datum/human_ai_faction/our_faction = SShuman_ai.human_ai_factions[tied_human.faction] - if(!our_faction) - return - our_faction.apply_faction_data(src) + our_faction?.apply_faction_data(src) tried_reload = FALSE // We don't really need to do this in a smart way if(belt) if(!istype(tied_human.belt, /obj/item/storage)) // belts can be backpacks, don't ask - return + goto back_statement for(var/id in equipment_map) for(var/obj/item/item as anything in equipment_map[id]) @@ -130,70 +134,75 @@ for(var/obj/item/inv_item as anything in tied_human.belt) RegisterSignal(inv_item, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) if(inv_item.flags_item & HEALING_ITEM) - // only trauma kits and similar for now for ease of development equipment_map[HUMAN_AI_HEALTHITEMS][inv_item] = "belt" else if(inv_item.flags_item & AMMUNITION_ITEM) equipment_map[HUMAN_AI_AMMUNITION][inv_item] = "belt" + else if(inv_item.flags_item & GRENADE_ITEM) + equipment_map[HUMAN_AI_GRENADES][inv_item] = "belt" + back_statement: + if(back) + if(!istype(tied_human.back, /obj/item/storage/backpack)) + goto l_pocket_statement + + for(var/id in equipment_map) + for(var/obj/item/item as anything in equipment_map[id]) + if(equipment_map[id][item] != "backpack") + continue + + equipment_map[id] -= item + + RegisterSignal(tied_human.back, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) + for(var/obj/item/inv_item as anything in tied_human.back) + RegisterSignal(inv_item, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) + if(inv_item.flags_item & HEALING_ITEM) + equipment_map[HUMAN_AI_HEALTHITEMS][inv_item] = "backpack" + else if(inv_item.flags_item & AMMUNITION_ITEM) + equipment_map[HUMAN_AI_AMMUNITION][inv_item] = "backpack" + else if(inv_item.flags_item & GRENADE_ITEM) + equipment_map[HUMAN_AI_GRENADES][inv_item] = "backpack" + l_pocket_statement: + if(pocket_l) + if(!istype(tied_human.l_store, /obj/item/storage/pouch)) + goto r_pocket_statement + + for(var/id in equipment_map) + for(var/obj/item/item as anything in equipment_map[id]) + if(equipment_map[id][item] != "left_pocket") + continue + + equipment_map[id] -= item + + RegisterSignal(tied_human.l_store, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) + for(var/obj/item/inv_item as anything in tied_human.l_store) + RegisterSignal(inv_item, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) + if(inv_item.flags_item & HEALING_ITEM) + equipment_map[HUMAN_AI_HEALTHITEMS][inv_item] = "left_pocket" + else if(inv_item.flags_item & AMMUNITION_ITEM) + equipment_map[HUMAN_AI_AMMUNITION][inv_item] = "left_pocket" + else if(inv_item.flags_item & GRENADE_ITEM) + equipment_map[HUMAN_AI_GRENADES][inv_item] = "left_pocket" + r_pocket_statement: + if(pocket_r) + if(!istype(tied_human.r_store, /obj/item/storage/pouch)) + return - if(back) - if(!istype(tied_human.back, /obj/item/storage/backpack)) - return - - for(var/id in equipment_map) - for(var/obj/item/item as anything in equipment_map[id]) - if(equipment_map[id][item] != "backpack") - continue - - equipment_map[id] -= item - - RegisterSignal(tied_human.back, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) - for(var/obj/item/inv_item as anything in tied_human.back) - RegisterSignal(inv_item, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) - if(inv_item.flags_item & HEALING_ITEM) - // only trauma kits and similar for now for ease of development - equipment_map[HUMAN_AI_HEALTHITEMS][inv_item] = "backpack" - else if(inv_item.flags_item & AMMUNITION_ITEM) - equipment_map[HUMAN_AI_AMMUNITION][inv_item] = "backpack" - - if(pocket_l) - if(!istype(tied_human.l_store, /obj/item/storage/pouch)) - return - - for(var/id in equipment_map) - for(var/obj/item/item as anything in equipment_map[id]) - if(equipment_map[id][item] != "left_pocket") - continue - - equipment_map[id] -= item - - RegisterSignal(tied_human.l_store, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) - for(var/obj/item/inv_item as anything in tied_human.l_store) - RegisterSignal(inv_item, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) - if(inv_item.flags_item & HEALING_ITEM) - // only trauma kits and similar for now for ease of development - equipment_map[HUMAN_AI_HEALTHITEMS][inv_item] = "left_pocket" - else if(inv_item.flags_item & AMMUNITION_ITEM) - equipment_map[HUMAN_AI_AMMUNITION][inv_item] = "left_pocket" - - if(pocket_r) - if(!istype(tied_human.r_store, /obj/item/storage/pouch)) - return + for(var/id in equipment_map) + for(var/obj/item/item as anything in equipment_map[id]) + if(equipment_map[id][item] != "right_pocket") + continue - for(var/id in equipment_map) - for(var/obj/item/item as anything in equipment_map[id]) - if(equipment_map[id][item] != "right_pocket") - continue - - equipment_map[id] -= item + equipment_map[id] -= item - RegisterSignal(tied_human.r_store, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) - for(var/obj/item/inv_item as anything in tied_human.r_store) - RegisterSignal(inv_item, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) - if(inv_item.flags_item & HEALING_ITEM) - // only trauma kits and similar for now for ease of development - equipment_map[HUMAN_AI_HEALTHITEMS][inv_item] = "right_pocket" - else if(inv_item.flags_item & AMMUNITION_ITEM) - equipment_map[HUMAN_AI_AMMUNITION][inv_item] = "right_pocket" + RegisterSignal(tied_human.r_store, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) + for(var/obj/item/inv_item as anything in tied_human.r_store) + RegisterSignal(inv_item, COMSIG_PARENT_QDELETING, PROC_REF(on_item_delete), TRUE) + if(inv_item.flags_item & HEALING_ITEM) + // only trauma kits and similar for now for ease of development + equipment_map[HUMAN_AI_HEALTHITEMS][inv_item] = "right_pocket" + else if(inv_item.flags_item & AMMUNITION_ITEM) + equipment_map[HUMAN_AI_AMMUNITION][inv_item] = "right_pocket" + else if(inv_item.flags_item & GRENADE_ITEM) + equipment_map[HUMAN_AI_GRENADES][inv_item] = "right_pocket" /datum/human_ai_brain/proc/clear_main_hand() var/obj/item/active_hand = tied_human.get_active_hand() @@ -267,37 +276,51 @@ gun_data = default /datum/human_ai_brain/proc/item_search(list/things_around) - for(var/obj/item/thing in things_around) - if(!isturf(thing.loc)) - continue + search_loop: + for(var/obj/item/thing in things_around) + if(!isturf(thing.loc)) + continue + + if(!primary_weapon && isgun(thing)) + var/obj/item/weapon/gun/thing_gun = thing + for(var/datum/firearm_appraisal/appraisal as anything in GLOB.firearm_appraisals) + if(is_type_in_list(thing_gun, appraisal.gun_types)) + if(appraisal.disposable && thing_gun.current_mag?.current_rounds <= 0) + continue search_loop + break - if(!primary_weapon && isgun(thing)) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) - break - - if(istype(thing, /obj/item/storage/belt) && !container_refs["belt"]) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) - break + ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + break - if(istype(thing, /obj/item/storage/backpack) && !container_refs["backpack"]) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) - break + if(istype(thing, /obj/item/storage/belt) && !container_refs["belt"]) + ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + break - if(istype(thing, /obj/item/storage/pouch) && (!container_refs["left_pocket"] || !container_refs["right_pocket"])) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) - break + if(istype(thing, /obj/item/storage/backpack) && !container_refs["backpack"]) + ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + break - var/storage_spot = storage_has_room(thing) - if(!storage_spot || !thing.ai_can_use(tied_human)) - continue + if(istype(thing, /obj/item/storage/pouch) && (!container_refs["left_pocket"] || !container_refs["right_pocket"])) + ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + break - if(is_type_in_list(thing, all_medical_items)) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) - break + var/storage_spot = storage_has_room(thing) + if(!storage_spot || !thing.ai_can_use(tied_human)) + continue - else if(primary_weapon && istype(thing, /obj/item/ammo_magazine)) - var/obj/item/ammo_magazine/mag = thing - if(istype(primary_weapon, mag.gun_type)) + if(is_type_in_list(thing, all_medical_items)) ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) break + else if(primary_weapon && istype(thing, /obj/item/ammo_magazine)) + var/obj/item/ammo_magazine/mag = thing + if(istype(primary_weapon, mag.gun_type)) + ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + break + + else if(istype(thing, /obj/item/explosive/grenade)) + var/obj/item/explosive/grenade/nade = thing + if(nade.active) + continue + ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_targeting.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_targeting.dm index aa97231ed7..9168ef2e22 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_targeting.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_targeting.dm @@ -11,6 +11,8 @@ var/turf/open/target_floor /// If TRUE, the AI is allowed to establish overwatches var/overwatch_allowed = FALSE + /// If TRUE, the AI will throw grenades at enemies who enter cover + var/grenading_allowed = TRUE /// List of overwatched turfs var/list/turf/open/overwatch_turfs = list() @@ -207,12 +209,18 @@ if(primary_weapon.current_mag?.current_rounds <= 1) // bullet removal comes after comsig is triggered end_gun_fire() + if(gun_data?.disposable) + var/obj/item/gun = primary_weapon + set_primary_weapon(null) + tied_human.drop_held_item(gun) return if(!(current_target in viewers(world.view, tied_human))) end_gun_fire() if(overwatch_allowed) establish_overwatch() + else if(grenading_allowed) + throw_grenade_cover() return if(istype(primary_weapon, /obj/item/weapon/gun/shotgun/pump)) @@ -294,4 +302,14 @@ current_target = entering attack_target() +/datum/human_ai_brain/proc/throw_grenade_cover() + if(!target_floor || has_ongoing_action(/datum/ongoing_action/throw_grenade)) + return + + var/obj/item/explosive/grenade/nade = locate() in equipment_map[HUMAN_AI_GRENADES] + if(!nade) + return + + ADD_ONGOING_ACTION(src, /datum/ongoing_action/throw_grenade, nade, target_floor) + #undef EXTRA_CHECK_DISTANCE_MULTIPLIER diff --git a/code/modules/mob/living/carbon/human/ai/firearm_appraisal.dm b/code/modules/mob/living/carbon/human/ai/firearm_appraisal.dm index 5d484c8902..132e7fbea0 100644 --- a/code/modules/mob/living/carbon/human/ai/firearm_appraisal.dm +++ b/code/modules/mob/living/carbon/human/ai/firearm_appraisal.dm @@ -17,6 +17,8 @@ GLOBAL_LIST_INIT_TYPED(firearm_appraisals, /datum/firearm_appraisal, build_firea var/burst_amount_max = 8 /// List of types that set the human AI to this appraisal type var/list/gun_types = list() + /// If TRUE, this gun is disposable and isn't worth trying to reload + var/disposable = FALSE /// List of things we do before our next fire based on weapon type /datum/firearm_appraisal/proc/before_fire(obj/item/weapon/gun/firearm, mob/living/carbon/user, datum/human_ai_brain/AI) @@ -32,6 +34,12 @@ GLOBAL_LIST_INIT_TYPED(firearm_appraisals, /datum/firearm_appraisal, build_firea /obj/item/weapon/gun/rifle, ) +/datum/firearm_appraisal/smartgun + burst_amount_max = 18 + gun_types = list( + /obj/item/weapon/gun/smartgun, + ) + /datum/firearm_appraisal/smg burst_amount_max = 10 optimal_range = 5 @@ -88,5 +96,12 @@ GLOBAL_LIST_INIT_TYPED(firearm_appraisals, /datum/firearm_appraisal, build_firea minimum_range = 5 optimal_range = 6 gun_types = list( - /obj/item/weapon/gun/launcher/rocket, + /obj/item/weapon/gun/launcher/rocket/anti_tank, + ) + disposable = TRUE + +/datum/firearm_appraisal/rpg/multi_use + gun_types = list( + /obj/item/weapon/gun/launcher/rocket ) + disposable = TRUE diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index bb832cecab..b01a72f4fb 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -102,12 +102,16 @@ . = ..() /mob/living/carbon/human/u_equip(obj/item/I, atom/newloc, nomoveupdate, force) + var/slot + if(I) + if(I == back) + slot = SLOT_BACK + else if(I == wear_mask) + slot = SLOT_FACE . = ..() if(!. || !I) return FALSE - var/slot - if(I == wear_suit) if(s_store && !(s_store.flags_equip_slot & SLOT_SUIT_STORE)) drop_inv_item_on_ground(s_store) diff --git a/colonialmarines.dme b/colonialmarines.dme index e11d4e4f5e..4f47474ae3 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -1982,6 +1982,7 @@ #include "code\modules\mob\living\carbon\human\ai\ai_management_menu.dm" #include "code\modules\mob\living\carbon\human\ai\faction_management_panel.dm" #include "code\modules\mob\living\carbon\human\ai\action_datums\pickup_primary.dm" +#include "code\modules\mob\living\carbon\human\ai\action_datums\throw_grenade.dm" #include "code\modules\mob\living\carbon\human\ai\action_datums\orders\order_action.dm" #include "code\modules\mob\living\carbon\human\ai\action_datums\orders\patrol_waypoints.dm" #include "code\modules\mob\living\carbon\human\ai\brain\ai_brain_communication.dm"