diff --git a/code/__DEFINES/~skyrat_defines/signals.dm b/code/__DEFINES/~skyrat_defines/signals.dm new file mode 100644 index 00000000000..5d82939b5ca --- /dev/null +++ b/code/__DEFINES/~skyrat_defines/signals.dm @@ -0,0 +1,6 @@ +// Movable signals +#define COMSIG_MOVABLE_RADIO_TALK_INTO "movable_radio_talk_into" //from radio talk_into(): (obj/item/radio/radio, message, channel, list/spans, datum/language/language, direct) +// Mob signals +#define COMSIG_MOB_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (obj/item) +// Living signals +#define COMSIG_LIVING_UPDATED_MOBILITY "living_updated_mobility" //from base of (/mob/living/proc/update_mobility): (mobility_flags) diff --git a/code/__DEFINES/~skyrat_defines/traits.dm b/code/__DEFINES/~skyrat_defines/traits.dm new file mode 100644 index 00000000000..e8581b0f667 --- /dev/null +++ b/code/__DEFINES/~skyrat_defines/traits.dm @@ -0,0 +1 @@ +#define TRAIT_NORUNNING "norunning" // You walk! diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index bcdd5c85004..bd34ec85f86 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -80,6 +80,7 @@ GLOBAL_LIST_EMPTY(radial_menus) var/hudfix_method = TRUE //TRUE to change anchor to user, FALSE to shift by py_shift var/py_shift = 0 var/entry_animation = TRUE + var/icon_path = 'icons/mob/radial.dmi' //SKYRAT EDIT ADDITION - GUNPOINT //If we swap to vis_contens inventory these will need a redo /datum/radial_menu/proc/check_screen_border(mob/user) @@ -122,6 +123,7 @@ GLOBAL_LIST_EMPTY(radial_menus) var/elements_to_add = max_elements - elements.len for(var/i in 1 to elements_to_add) //Create all elements var/obj/screen/radial/slice/new_element = new /obj/screen/radial/slice + new_element.icon = icon_path //SKYRAT EDIT ADDITION - GUNPOINT new_element.tooltips = use_tooltips new_element.parent = src elements += new_element diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 226a44f3c7b..e6f074c4e98 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -23,6 +23,7 @@ /obj/item/proc/attack_self(mob/user) if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, user) & COMPONENT_NO_INTERACT) return + SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK_SELF, src) //SKYRAT EDIT ADDITION - GUNPOINT interact(user) /** diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index c02c9c86f3e..f09a42cdfed 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -61,7 +61,8 @@ GLOBAL_LIST_INIT(channel_tokens, list( QDEL_NULL(keyslot2) return ..() -/obj/item/radio/headset/talk_into(mob/living/M, message, channel, list/spans, datum/language/language, list/message_mods) +///obj/item/radio/headset/talk_into(mob/living/M, message, channel, list/spans, datum/language/language, list/message_mods) - ORIGINAL +/obj/item/radio/headset/talk_into(mob/living/M, message, channel, list/spans, datum/language/language, list/message_mods, direct = TRUE) //SKYRAT EDIT CHANGE - GUNPOINT if (!listening) return ITALICS | REDUCE_RANGE return ..() diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 5de46b3ae22..dcad8df672b 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -185,7 +185,8 @@ recalculateChannels() . = TRUE -/obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language, list/message_mods) +///obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language, list/message_mods) - ORIGINAL +/obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language, list/message_mods, direct = TRUE) //SKYRAT EDIT CHANGE - GUNPOINT if(HAS_TRAIT(M, TRAIT_SIGN_LANG)) //Forces Sign Language users to wear the translation gloves to speak over radios var/mob/living/carbon/mute = M if(istype(mute)) @@ -203,6 +204,7 @@ spans = list(M.speech_span) if(!language) language = M.get_selected_language() + SEND_SIGNAL(M, COMSIG_MOVABLE_RADIO_TALK_INTO, src, message, channel, spans, language, direct) //SKYRAT EDIT ADDITION - GUNPOINT INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language, message_mods) return ITALICS | REDUCE_RANGE @@ -298,7 +300,7 @@ if (idx && (idx % 2) == (message_mods[RADIO_EXTENSION] == MODE_L_HAND)) return - talk_into(speaker, raw_message, , spans, language=message_language) + talk_into(speaker, raw_message, , spans, language=message_language, direct=FALSE) //SKYRAT EDIT CHANGE - GUNPOINT // Checks if this radio can receive on the given frequency. /obj/item/radio/proc/can_receive(freq, level) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index c37f098337f..0615d925cce 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -428,6 +428,13 @@ "\[Add comment\]"), "") else if(isobserver(user)) . += "Traits: [get_quirk_string(FALSE, CAT_QUIRK_ALL)]" + //SKYRAT EDIT ADDITION BEGIN - GUNPOINT + if(gunpointing) + . += "[t_He] [t_is] holding [gunpointing.target.name] at gunpoint with [gunpointing.aimed_gun.name]!\n" + if(length(gunpointed)) + for(var/datum/gunpoint/GP in gunpointed) + . += "[GP.source.name] [GP.source.p_are()] holding [t_him] at gunpoint with [GP.aimed_gun.name]!\n" + //SKYRAT EDIT ADDITION END //SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION for(var/genital in list("penis", "testicles", "vagina", "breasts")) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 607490e1b26..95ed02846f9 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -116,6 +116,22 @@ if(!(world.time % 5)) to_chat(src, "[L] is restraining [P], you cannot push past.") return TRUE + //SKYRAT EDIT ADDITION BEGIN - GUNPOINT + if(L.gunpointed.len) + var/is_pointing = FALSE + for(var/datum/gunpoint/gp in L.gunpointed) + if(gp.source == src) + is_pointing = TRUE + break + if(!is_pointing) + if(!(world.time % 5)) + to_chat(src, "[L] is being held at gunpoint, it's not wise to push him.") + return TRUE + if(L.gunpointing) + if(!(world.time % 5)) + to_chat(src, "[L] is holding someone at gunpoint, you cannot push past.") + return TRUE + //SKYRAT EDIT ADDITION END if(moving_diagonally)//no mob swap during diagonal moves. return TRUE @@ -1282,6 +1298,7 @@ add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown) else remove_movespeed_modifier(/datum/movespeed_modifier/limbless) + SEND_SIGNAL(src, COMSIG_LIVING_UPDATED_MOBILITY, mobility_flags) //SKYRAT EDIT ADDITION - GUNPOINT ///Called when mob changes from a standing position into a prone while lacking the ability to stand up at the moment, through update_mobility() diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 7714c32b124..d75260cad46 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -449,6 +449,11 @@ if(m_intent == MOVE_INTENT_RUN) m_intent = MOVE_INTENT_WALK else + //SKYRAT EDIT ADDITION BEGIN - GUNPOINT + if (HAS_TRAIT(src,TRAIT_NORUNNING)) + to_chat(src, "You find yourself unable to run.") + return FALSE + //SKYRAT EDIT ADDITION END m_intent = MOVE_INTENT_RUN if(hud_used && hud_used.static_inventory) for(var/obj/screen/mov_intent/selector in hud_used.static_inventory) diff --git a/modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint.dm b/modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint.dm new file mode 100644 index 00000000000..6a6c0b0fe59 --- /dev/null +++ b/modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint.dm @@ -0,0 +1,54 @@ +/mob/living + ///Who is the person gunpointing at? If they are + var/datum/gunpoint/gunpointing + ///Who is gunpointing at our person? + var/list/gunpointed = list() + ///The effect from gunpointing, to make sure we dont create multiples + var/obj/effect/overlay/gunpoint_effect/gp_effect + +/mob/living/carbon/Move(atom/newloc, direct = 0) + . = ..() + if(gunpointing) + var/dir = get_dir(get_turf(gunpointing.source),get_turf(gunpointing.target)) + if(dir) + setDir(dir) + +/mob/living/ShiftMiddleClickOn(atom/A) + var/obj/item/gun/G = get_active_held_item() + if(istype(G, /obj/item/gun)) + DoGunpoint(A, G) + else + src.pointed(A) + return + +/mob/living/proc/DoGunpoint(atom/A, obj/item/gun/G) + if(A == src) + return + if(!isliving(A)) + if(gunpointing) //Cancelling a gunpoint by shift + MMB on a non-mob + gunpointing.Destroy() + return + var/mob/living/L = A + if(gunpointing && L == gunpointing.target) //Cancelling a gunpoint by shift + MMB on the target + gunpointing.ClickDestroy() + else + if(!CanGunpointAt(L, TRUE)) + return + if(gunpointing) //We're gunpoint and we already know we're locking onto a different, valid target + gunpointing.Destroy() + gunpointing = new(src, L, G) + +/mob/living/proc/CanGunpointAt(mob/living/L, notice = FALSE) + if(!(src.mobility_flags & MOBILITY_STAND)) + if(notice) + to_chat(src, "You need to be standing to get a good aim!") + return FALSE + if(!(L in viewers(8, src))) + if(notice) + to_chat(src, "Your target is out of your view!") + return FALSE + if(L.alpha < 70) + if(notice) + to_chat(src, "You can't quite make out your target!") + return FALSE + return TRUE diff --git a/modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint_datum.dm b/modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint_datum.dm new file mode 100644 index 00000000000..c3d3f48f5b8 --- /dev/null +++ b/modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint_datum.dm @@ -0,0 +1,261 @@ +/obj/effect/overlay/gunpoint_effect + icon = 'modular_skyrat/modules/gunpoint/icons/targeted.dmi' + icon_state = "locking" + layer = FLY_LAYER + plane = GAME_PLANE + appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART + mouse_opacity = 0 + +/datum/gunpoint + var/mob/living/source + var/mob/living/target + var/datum/radial_menu/gunpoint/gunpoint_gui + var/allow_move = FALSE + var/allow_radio = FALSE + var/allow_use = FALSE + + var/obj/item/gun/aimed_gun + + var/safeguard_time = 0 + var/next_autoshot = 0 + var/locked = FALSE + var/was_running = FALSE + + var/moved_counter = 0 + + var/static/radio_forbid = image(icon = 'modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi', icon_state = "radial_radio_forbid") + var/static/radio_allow = image(icon = 'modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi', icon_state = "radial_radio") + var/static/use_forbid = image(icon = 'modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi', icon_state = "radial_use_forbid") + var/static/use_allow = image(icon = 'modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi', icon_state = "radial_use") + var/static/move_forbid = image(icon = 'modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi', icon_state = "radial_move_forbid") + var/static/move_allow = image(icon = 'modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi', icon_state = "radial_move") + +/datum/gunpoint/New(user, tar, gun) + source = user + source.gunpointing = src + target = tar + target.gunpointed += src + aimed_gun = gun + + source.face_atom(target) + source.visible_message("[source.name] aims at [target.name] with the [aimed_gun.name]!") + + was_running = (source.m_intent == MOVE_INTENT_RUN) + if(was_running) + source.toggle_move_intent() + ADD_TRAIT(source, TRAIT_NORUNNING, "gunpoint") + + if(!target.gp_effect) + target.gp_effect = new + target.vis_contents += target.gp_effect + + RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/MovedReact) + RegisterSignal(source, COMSIG_MOVABLE_MOVED, .proc/SourceMoved) + + RegisterSignal(target, COMSIG_MOB_FIRED_GUN, .proc/UseReact) + + RegisterSignal(source, COMSIG_LIVING_STATUS_STUN, .proc/SourceCC) + RegisterSignal(source, COMSIG_LIVING_STATUS_KNOCKDOWN, .proc/SourceCC) + RegisterSignal(source, COMSIG_LIVING_STATUS_PARALYZE, .proc/SourceCC) + RegisterSignal(source, COMSIG_LIVING_UPDATED_MOBILITY, .proc/SourceUpdatedMobility) + + RegisterSignal(aimed_gun, COMSIG_ITEM_EQUIPPED,.proc/ClickDestroy) + RegisterSignal(aimed_gun, COMSIG_ITEM_DROPPED,.proc/ClickDestroy) + + RegisterSignal(target, COMSIG_MOVABLE_RADIO_TALK_INTO,.proc/RadioReact) + + RegisterSignal(target, COMSIG_MOB_ITEM_ATTACK, .proc/UseReact) + RegisterSignal(target, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/MeleeAttackReact) + RegisterSignal(target, COMSIG_MOB_ITEM_ATTACK_SELF, .proc/UseReact) + RegisterSignal(target, COMSIG_MOB_ITEM_AFTERATTACK, .proc/UseReact) + + RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Destroy) + RegisterSignal(source, COMSIG_PARENT_QDELETING, .proc/Destroy) + + + addtimer(CALLBACK(src, .proc/LockOn), 7) + +/datum/gunpoint/proc/MeleeAttackReact(datum/source_datum, atom/target) + if(!CheckContinuity()) + Destroy() + return + if(!allow_use && CanReact()) + source.log_message("[source] shot [target] because they attacked/disarmed/pulled", LOG_ATTACK) + to_chat(source, "You pull the trigger instinctively to [target.name] actions!") + ShootTarget() + +/datum/gunpoint/proc/LockOn() + if(src) //if we're not present then locking on failed and this datum is deleted + if(!CheckContinuity()) + Destroy() + return + locked = TRUE + log_combat(target, source, "locked onto with aiming") + playsound(get_turf(source), 'modular_skyrat/modules/gunpoint/sound/targeton.ogg', 50,1) + to_chat(source, "You lock onto [target.name]!") + target.visible_message("[source.name] holds [target.name] at gunpoint with the [aimed_gun.name]!", "[source.name] holds you at gunpoint with the [aimed_gun.name]!") + if(target.gunpointed.len == 1)//First case + to_chat(target, "You'll get shot if you use radio, move or interact with items!") + to_chat(target, "You can however take items out, toss harmless items or drop them.") + var/list/choice_list = ConstructChoiceList() + gunpoint_gui = show_radial_menu_gunpoint(source, target , choice_list, select_proc = CALLBACK(src, .proc/GunpointGuiReact, source), radius = 42) + if(target.gp_effect.icon_state != "locked") + target.gp_effect.icon_state = "locked" + safeguard_time = world.time + 30 + +/datum/gunpoint/proc/CheckContinuity() + if(!target) + return FALSE + if(source.CanGunpointAt(target)) + source.face_atom(target) + return TRUE + return FALSE + +/datum/gunpoint/proc/CanReact() + if(locked && (world.time >= safeguard_time) && !(target.stat == DEAD || target.stat == HARD_CRIT || target.stat == SOFT_CRIT) && source.next_move <= world.time && next_autoshot <= world.time) + return TRUE + return FALSE + +/datum/gunpoint/Destroy() + UnregisterSignal(aimed_gun, list(COMSIG_ITEM_DROPPED, COMSIG_ITEM_EQUIPPED)) + UnregisterSignal(target, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_ITEM_AFTERATTACK, COMSIG_MOB_ITEM_ATTACK_SELF, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ITEM_ATTACK, COMSIG_MOVABLE_RADIO_TALK_INTO, COMSIG_MOB_FIRED_GUN, COMSIG_MOVABLE_MOVED)) + UnregisterSignal(source, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIVING_STATUS_STUN, COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_LIVING_STATUS_PARALYZE, COMSIG_LIVING_UPDATED_MOBILITY)) + + REMOVE_TRAIT(source, TRAIT_NORUNNING, "gunpoint") + if(was_running) + source.toggle_move_intent() + if(target.gunpointed.len == 1) //Last instance being deleted + target.vis_contents -= target.gp_effect + QDEL_NULL(target.gp_effect) + target.gunpointed -= src + source.gunpointing = null + if(locked) + QDEL_NULL(gunpoint_gui) + target.visible_message("[source.name] no longer holds [target.name] at gunpoint.", "[source.name] no longer holds you at gunpoint.") + source = null + target = null + aimed_gun = null + return ..() + +/datum/gunpoint/proc/ClickDestroy() + if(locked) + playsound(get_turf(source), 'modular_skyrat/modules/gunpoint/sound/targetoff.ogg', 50,1) + Destroy() + +/datum/gunpoint/proc/SourceCC(datum/source, amount, update, ignore) + if(amount && !ignore) + Destroy() + +/datum/gunpoint/proc/ShootTarget() + next_autoshot = world.time + 5 + log_combat(target, source, "auto-shot with aim") + aimed_gun.afterattack(target, source) + +/datum/gunpoint/proc/RadioReact(datum/datum_source, obj/item/radio/radio, message, channel, list/spans, datum/language/language, direct) + if(!allow_radio && CanReact()) + if(direct) + source.log_message("[source] shot [target] because they spoke on radio", LOG_ATTACK) + to_chat(source, "You pull the trigger instinctively as [target.name] speaks on the radio!") + ShootTarget() + +/datum/gunpoint/proc/MovedReact(datum/datum_source, atom/moved, direction, forced) + if(!CheckContinuity()) + Destroy() + return + if(!allow_move && CanReact() && !(target.pulledby && target.pulledby == source)) //Don't shoot him if we're pulling them + MovedShootProc() + +/datum/gunpoint/proc/MovedShootProc() //This exists in case of someone moving several tiles in one tick, such as dashes or diagonal movement + moved_counter += 1 + var/count = moved_counter + sleep(1) + if(src && count == moved_counter) + source.log_message("[source] shot [target] because they moved", LOG_ATTACK) + ShootTarget() + +/datum/gunpoint/proc/UseReact(datum/datum_source) + if(!CheckContinuity()) + Destroy() + return + if(!allow_use && CanReact()) + source.log_message("[source] shot [target] because they used an item", LOG_ATTACK) + to_chat(source, "You pull the trigger instinctively as [target.name] uses an item!") + ShootTarget() + +/datum/gunpoint/proc/SourceMoved(datum/datum_source) + if(!CheckContinuity()) + Destroy() + +/datum/gunpoint/proc/SourceUpdatedMobility() + if(!(source.mobility_flags & MOBILITY_STAND)) + Destroy() + +/datum/gunpoint/proc/ConstructChoiceList() + var/image/radio_image = (allow_radio ? radio_allow : radio_forbid) + var/image/use_image = (allow_use ? use_allow : use_forbid) + var/image/move_image = (allow_move ? move_allow : move_forbid) + var/list/L = list("radio" = radio_image, "use" = use_image, "move" = move_image) + return L + +/datum/gunpoint/proc/GunpointGuiReact(mob/living/user,choice) + switch(choice) + if("radio") + allow_radio = !allow_radio + if(allow_radio) + var/safe = TRUE + for(var/datum/gunpoint/gp in target.gunpointed) + if(gp.allow_radio == FALSE) + safe = FALSE + break + if(safe) + to_chat(target, "[source.name] signals you can use radio.") + else + to_chat(target, "[source.name] signals you can use radio, however other people still don't") + else + var/forbid_counts = 0 + for(var/datum/gunpoint/gp in target.gunpointed) + if(gp.allow_radio == FALSE) + forbid_counts += 1 + if(forbid_counts == 1) //Only first one warns the victim + to_chat(target, "[source.name] signals you can't use radio.") + if("use") + allow_use = !allow_use + if(allow_use) + var/safe = TRUE + for(var/datum/gunpoint/gp in target.gunpointed) + if(gp.allow_use == FALSE) + safe = FALSE + break + if(safe) + to_chat(target, "[source.name] signals you can interact with items.") + else + to_chat(target, "[source.name] signals you can interact with items, however other people still don't") + else + var/forbid_counts = 0 + for(var/datum/gunpoint/gp in target.gunpointed) + if(gp.allow_use == FALSE) + forbid_counts += 1 + if(forbid_counts == 1) //Only first one warns the victim + to_chat(target, "[source.name] signals you can't interact with items.") + if("move") + allow_move = !allow_move + if(allow_move) + var/safe = TRUE + for(var/datum/gunpoint/gp in target.gunpointed) + if(gp.allow_move == FALSE) + safe = FALSE + break + if(safe) + to_chat(target, "[source.name] signals you can move.") + else + to_chat(target, "[source.name] signals you can move, however other people still don't") + else + var/forbid_counts = 0 + for(var/datum/gunpoint/gp in target.gunpointed) + if(gp.allow_move == FALSE) + forbid_counts += 1 + if(forbid_counts == 1) //Only first one warns the victim + to_chat(target, "[source.name] signals you can't move.") + var/list/new_choices = ConstructChoiceList() + gunpoint_gui.entry_animation = FALSE + gunpoint_gui.change_choices(new_choices,FALSE) diff --git a/modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint_radial.dm b/modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint_radial.dm new file mode 100644 index 00000000000..f21ca00191c --- /dev/null +++ b/modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint_radial.dm @@ -0,0 +1,45 @@ +/datum/radial_menu/gunpoint + var/uniqueid + var/datum/callback/select_proc_callback + icon_path = 'modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi' + +/datum/radial_menu/gunpoint/New() + + +/datum/radial_menu/gunpoint/element_chosen(choice_id,mob/user) + select_proc_callback.Invoke(choices_values[choice_id]) + + +/datum/radial_menu/gunpoint/proc/change_choices(list/newchoices, tooltips) + if(!newchoices.len) + return + Reset() + set_choices(newchoices,tooltips) + +/datum/radial_menu/gunpoint/Destroy() + QDEL_NULL(select_proc_callback) + GLOB.radial_menus -= uniqueid + Reset() + hide() + . = ..() + +/proc/show_radial_menu_gunpoint(mob/user, atom/anchor, list/choices, datum/callback/select_proc, uniqueid, radius, tooltips = FALSE) + if(!user || !anchor || !length(choices) || !select_proc) + return + if(!uniqueid) + uniqueid = "defmenu_[REF(user)]_[REF(anchor)]" + + if(GLOB.radial_menus[uniqueid]) + return + + var/datum/radial_menu/gunpoint/menu = new + menu.uniqueid = uniqueid + GLOB.radial_menus[uniqueid] = menu + if(radius) + menu.radius = radius + menu.select_proc_callback = select_proc + menu.anchor = anchor + menu.check_screen_border(user) //Do what's needed to make it look good near borders or on hud + menu.set_choices(choices, tooltips) + menu.show_to(user) + return menu diff --git a/modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi b/modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi new file mode 100644 index 00000000000..71f4f4edb73 Binary files /dev/null and b/modular_skyrat/modules/gunpoint/icons/radial_gunpoint.dmi differ diff --git a/modular_skyrat/modules/gunpoint/icons/targeted.dmi b/modular_skyrat/modules/gunpoint/icons/targeted.dmi new file mode 100644 index 00000000000..71d17cbcdef Binary files /dev/null and b/modular_skyrat/modules/gunpoint/icons/targeted.dmi differ diff --git a/modular_skyrat/modules/gunpoint/readme.md b/modular_skyrat/modules/gunpoint/readme.md new file mode 100644 index 00000000000..1ff911ed860 --- /dev/null +++ b/modular_skyrat/modules/gunpoint/readme.md @@ -0,0 +1,36 @@ +## Title: Gunpoint + +MODULE ID: GUNPOINT + +### Description: + +Allows anyone with a gun to use SHIFT + MMB to hold someone at gunpoint, much like how baystation does it, but in a more visually clear way + +### TG Proc Changes: + + ./modular_skyrat/modules/gunpoint/code/datum/gunpoint/gunpoint.dm > /mob/living/ShiftMiddleClickOn() > CHILD PROC + ./code/_onclick/hud/radial.dm > /datum/radial_menu/proc/setup_menu() + ./code/_onclick/item_attack.dm > /obj/item/proc/attack_self() + ./code/game/objects/items/devices/radio/radio.dm > /obj/item/radio/talk_into() + ./code/game/objects/items/devices/radio/headset.dm > /obj/item/radio/headset/talk_into() + ./code/modules/mob/living/carbon/human/examine.dm > /mob/living/carbon/human/examine() + ./code/modules/mob/living/living.dm > /mob/living/proc/update_mobility() + ./code/modules/mob/living/living.dm > /mob/living/proc/MobBump() + ./code/modules/mob/mob_movement.dm > /mob/proc/toggle_move_intent() + +### Defines: + + ./code/_onclick/hud/radial.dm > /datum/radial_menu - var/icon_path + ./code/__DEFINES/~skyrat_defines/signals.dm - COMSIG_MOVABLE_RADIO_TALK_INTO, COMSIG_MOB_ITEM_ATTACK_SELF, COMSIG_LIVING_UPDATED_MOBILITY + ./code/__DEFINES/~skyrat_defines/traits.dm - TRAIT_NORUNNING + +### Master file additions + +- N/A + +### Included files that are not contained in this module: + +- N/A + +### Credits: +Azarak - original code & porting diff --git a/modular_skyrat/modules/gunpoint/sound/targetoff.ogg b/modular_skyrat/modules/gunpoint/sound/targetoff.ogg new file mode 100644 index 00000000000..b8657aab27e Binary files /dev/null and b/modular_skyrat/modules/gunpoint/sound/targetoff.ogg differ diff --git a/modular_skyrat/modules/gunpoint/sound/targeton.ogg b/modular_skyrat/modules/gunpoint/sound/targeton.ogg new file mode 100644 index 00000000000..93a2f68f326 Binary files /dev/null and b/modular_skyrat/modules/gunpoint/sound/targeton.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 4ba38750558..e675acfe1bc 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -131,6 +131,8 @@ #include "code\__DEFINES\dcs\signals.dm" #include "code\__DEFINES\research\anomalies.dm" #include "code\__DEFINES\~skyrat_defines\blueshield.dm" +#include "code\__DEFINES\~skyrat_defines\signals.dm" +#include "code\__DEFINES\~skyrat_defines\traits.dm" #include "code\__DEFINES\~skyrat_defines\DNA.dm" #include "code\__DEFINES\~skyrat_defines\obj_flags.dm" #include "code\__DEFINES\~skyrat_defines\say.dm" @@ -3272,6 +3274,9 @@ #include "modular_skyrat\modules\blueshield\code\modules\clothing\under\jobs\security.dm" #include "modular_skyrat\modules\blueshield\code\modules\clothing\under\jobs\Plasmaman\security.dm" #include "modular_skyrat\modules\blueshield\code\modules\jobs\job_types\blueshield.dm" +#include "modular_skyrat\modules\gunpoint\code\datum\gunpoint\gunpoint.dm" +#include "modular_skyrat\modules\gunpoint\code\datum\gunpoint\gunpoint_datum.dm" +#include "modular_skyrat\modules\gunpoint\code\datum\gunpoint\gunpoint_radial.dm" #include "modular_skyrat\modules\blueshield\code\modules\projectiles\guns\energy\special.dm" #include "modular_skyrat\modules\customization\__DEFINES\inventory.dm" #include "modular_skyrat\modules\customization\__DEFINES\lists.dm"