mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-28 18:11:16 +00:00
## About The Pull Request Melee attack chain now has a list passed along with it, `attack_modifiers`, which you can stick force modifiers to change the resulting attack This is basically a soft implementation of damage packets until a more definitive pr, but one that only applies to item attack chain, and not unarmed attacks. This change was done to facilitate a baton refactor - batons no longer hack together their own attack chain, and are now integrated straight into the real attack chain. This refactor itself was done because batons don't send any attack signals, which has been annoying in the past (for swing combat). ## Changelog 🆑 Melbert refactor: Batons have been refactored again. Baton stuns now properly count as an attack, when before it was a nothing. Report any oddities, particularly in regards to harmbatonning vs normal batonning. refactor: The method of adjusting item damage mid-attack has been refactored - some affected items include the Nullblade and knives. Report any strange happenings with damage numbers. refactor: A few objects have been moved to the new interaction chain - records consoles, mawed crucible, alien weeds and space vines, hedges, restaurant portals, and some mobs - to name a few. fix: Spears only deal bonus damage against secure lockers, not all closet types (including crates) /🆑
553 lines
20 KiB
Plaintext
553 lines
20 KiB
Plaintext
/proc/make_link_visual_generic(datum/mod_link/mod_link, proc_path)
|
|
var/mob/living/user = mod_link.get_user_callback.Invoke()
|
|
var/obj/effect/overlay/link_visual = new()
|
|
link_visual.name = "holocall ([mod_link.id])"
|
|
link_visual.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
|
LAZYADD(mod_link.holder.update_on_z, link_visual)
|
|
link_visual.appearance_flags |= KEEP_TOGETHER
|
|
link_visual.makeHologram(0.75)
|
|
mod_link.visual_overlays = user.overlays - user.active_thinking_indicator
|
|
link_visual.add_overlay(mod_link.visual_overlays)
|
|
mod_link.visual = link_visual
|
|
mod_link.holder.become_hearing_sensitive(REF(mod_link))
|
|
mod_link.holder.RegisterSignals(user, list(COMSIG_CARBON_APPLY_OVERLAY, COMSIG_CARBON_REMOVE_OVERLAY), proc_path)
|
|
return link_visual
|
|
|
|
/proc/get_link_visual_generic(datum/mod_link/mod_link, atom/movable/visuals, proc_path)
|
|
var/mob/living/user = mod_link.get_user_callback.Invoke()
|
|
playsound(mod_link.holder, 'sound/machines/terminal/terminal_processing.ogg', 50, vary = TRUE)
|
|
visuals.add_overlay(mutable_appearance('icons/effects/effects.dmi', "static_base", ABOVE_NORMAL_TURF_LAYER))
|
|
visuals.add_overlay(mutable_appearance('icons/effects/effects.dmi', "modlink", ABOVE_ALL_MOB_LAYER))
|
|
visuals.add_filter("crop_square", 1, alpha_mask_filter(icon = icon('icons/effects/effects.dmi', "modlink_filter")))
|
|
visuals.maptext_height = 6
|
|
visuals.alpha = 0
|
|
user.vis_contents += visuals
|
|
visuals.forceMove(user)
|
|
animate(visuals, 0.5 SECONDS, alpha = 255)
|
|
var/datum/callback/setdir_callback = CALLBACK(mod_link.holder, proc_path)
|
|
setdir_callback.Invoke(user, user.dir, user.dir)
|
|
mod_link.holder.RegisterSignal(mod_link.holder.loc, COMSIG_ATOM_DIR_CHANGE, proc_path)
|
|
|
|
/proc/delete_link_visual_generic(datum/mod_link/mod_link)
|
|
var/mob/living/user = mod_link.get_user_callback.Invoke()
|
|
playsound(mod_link.get_other().holder, 'sound/machines/terminal/terminal_processing.ogg', 50, vary = TRUE, frequency = -1)
|
|
LAZYREMOVE(mod_link.holder.update_on_z, mod_link.visual)
|
|
mod_link.holder.lose_hearing_sensitivity(REF(mod_link))
|
|
mod_link.holder.UnregisterSignal(user, list(COMSIG_CARBON_APPLY_OVERLAY, COMSIG_CARBON_REMOVE_OVERLAY, COMSIG_ATOM_DIR_CHANGE))
|
|
QDEL_NULL(mod_link.visual)
|
|
|
|
/proc/on_user_set_dir_generic(datum/mod_link/mod_link, newdir)
|
|
var/atom/other_visual = mod_link.get_other().visual
|
|
if(!newdir) //can sometimes be null or 0
|
|
return
|
|
other_visual.setDir(SOUTH)
|
|
other_visual.pixel_x = 0
|
|
other_visual.pixel_y = 0
|
|
var/matrix/new_transform = matrix()
|
|
if(newdir & NORTH)
|
|
other_visual.pixel_y = 13
|
|
other_visual.layer = BELOW_MOB_LAYER
|
|
if(newdir & SOUTH)
|
|
other_visual.pixel_y = -24
|
|
other_visual.layer = ABOVE_ALL_MOB_LAYER
|
|
new_transform.Scale(-1, 1)
|
|
new_transform.Translate(-1, 0)
|
|
if(newdir & EAST)
|
|
other_visual.pixel_x = 14
|
|
other_visual.layer = BELOW_MOB_LAYER
|
|
new_transform.Shear(0.5, 0)
|
|
new_transform.Scale(0.65, 1)
|
|
if(newdir & WEST)
|
|
other_visual.pixel_x = -14
|
|
other_visual.layer = BELOW_MOB_LAYER
|
|
new_transform.Shear(-0.5, 0)
|
|
new_transform.Scale(0.65, 1)
|
|
other_visual.transform = new_transform
|
|
|
|
/obj/item/mod/control/Initialize(mapload, datum/mod_theme/new_theme, new_skin, obj/item/mod/core/new_core)
|
|
. = ..()
|
|
mod_link = new(
|
|
src,
|
|
starting_frequency,
|
|
CALLBACK(src, PROC_REF(get_wearer)),
|
|
CALLBACK(src, PROC_REF(can_call)),
|
|
CALLBACK(src, PROC_REF(make_link_visual)),
|
|
CALLBACK(src, PROC_REF(get_link_visual)),
|
|
CALLBACK(src, PROC_REF(delete_link_visual))
|
|
)
|
|
|
|
/obj/item/mod/control/multitool_act_secondary(mob/living/user, obj/item/multitool/tool)
|
|
. = NONE
|
|
|
|
var/tool_frequency = null
|
|
if(istype(tool.buffer, /datum/mod_link))
|
|
var/datum/mod_link/buffer_link = tool.buffer
|
|
tool_frequency = buffer_link.frequency
|
|
balloon_alert(user, "frequency set")
|
|
. = ITEM_INTERACT_SUCCESS
|
|
if(!tool_frequency && mod_link.frequency)
|
|
tool.set_buffer(mod_link)
|
|
balloon_alert(user, "frequency copied")
|
|
. = ITEM_INTERACT_SUCCESS
|
|
else if(tool_frequency && !mod_link.frequency)
|
|
mod_link.frequency = tool_frequency
|
|
. = ITEM_INTERACT_SUCCESS
|
|
else if(tool_frequency && mod_link.frequency)
|
|
var/response = tgui_alert(user, "Would you like to copy or imprint the frequency?", "MODlink Frequency", list("Copy", "Imprint"))
|
|
if(!user.is_holding(tool))
|
|
return ITEM_INTERACT_BLOCKING
|
|
switch(response)
|
|
if("Copy")
|
|
tool.set_buffer(mod_link)
|
|
balloon_alert(user, "frequency copied")
|
|
. = ITEM_INTERACT_SUCCESS
|
|
if("Imprint")
|
|
mod_link.frequency = tool_frequency
|
|
balloon_alert(user, "frequency set")
|
|
. = ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/item/mod/control/proc/can_call()
|
|
return get_charge() && wearer && wearer.stat < DEAD
|
|
|
|
/obj/item/mod/control/proc/make_link_visual()
|
|
return make_link_visual_generic(mod_link, PROC_REF(on_overlay_change))
|
|
|
|
/obj/item/mod/control/proc/get_link_visual(atom/movable/visuals)
|
|
return get_link_visual_generic(mod_link, visuals, PROC_REF(on_wearer_set_dir))
|
|
|
|
/obj/item/mod/control/proc/delete_link_visual()
|
|
return delete_link_visual_generic(mod_link)
|
|
|
|
/obj/item/mod/control/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
|
|
. = ..()
|
|
if(speaker != wearer && speaker != ai_assistant)
|
|
return
|
|
mod_link.visual.say(raw_message, sanitize = FALSE, message_range = 2)
|
|
|
|
/obj/item/mod/control/proc/on_overlay_change(atom/source, cache_index, overlay)
|
|
SIGNAL_HANDLER
|
|
addtimer(CALLBACK(src, PROC_REF(update_link_visual)), 1 TICKS, TIMER_UNIQUE)
|
|
|
|
/obj/item/mod/control/proc/update_link_visual()
|
|
if(QDELETED(mod_link.link_call))
|
|
return
|
|
mod_link.visual.cut_overlay(mod_link.visual_overlays)
|
|
mod_link.visual_overlays = wearer.overlays - wearer.active_thinking_indicator
|
|
mod_link.visual.add_overlay(mod_link.visual_overlays)
|
|
|
|
/obj/item/mod/control/proc/on_wearer_set_dir(atom/source, dir, newdir)
|
|
SIGNAL_HANDLER
|
|
on_user_set_dir_generic(mod_link, newdir || SOUTH)
|
|
|
|
/obj/item/clothing/neck/link_scryer
|
|
name = "\improper MODlink scryer"
|
|
desc = "An intricate piece of machinery that creates a holographic video call with another MODlink-compatible device. Essentially a video necklace."
|
|
icon_state = "modlink"
|
|
actions_types = list(/datum/action/item_action/call_link)
|
|
/// The installed power cell.
|
|
var/obj/item/stock_parts/power_store/cell
|
|
/// The MODlink datum we operate.
|
|
var/datum/mod_link/mod_link
|
|
/// Initial frequency of the MODlink.
|
|
var/starting_frequency
|
|
/// An additional name tag for the scryer, seen as "MODlink scryer - [label]"
|
|
var/label
|
|
|
|
/obj/item/clothing/neck/link_scryer/Initialize(mapload)
|
|
. = ..()
|
|
mod_link = new(
|
|
src,
|
|
starting_frequency,
|
|
CALLBACK(src, PROC_REF(get_user)),
|
|
CALLBACK(src, PROC_REF(can_call)),
|
|
CALLBACK(src, PROC_REF(make_link_visual)),
|
|
CALLBACK(src, PROC_REF(get_link_visual)),
|
|
CALLBACK(src, PROC_REF(delete_link_visual))
|
|
)
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
/obj/item/clothing/neck/link_scryer/Destroy()
|
|
QDEL_NULL(cell)
|
|
QDEL_NULL(mod_link)
|
|
STOP_PROCESSING(SSobj, src)
|
|
return ..()
|
|
|
|
/obj/item/clothing/neck/link_scryer/examine(mob/user)
|
|
. = ..()
|
|
if(cell)
|
|
. += span_notice("The battery charge reads [cell.percent()]%. <b>Right-click</b> with an empty hand to remove it.")
|
|
else
|
|
. += span_notice("It is missing a battery, one can be installed by clicking with a power cell on it.")
|
|
. += span_notice("The MODlink ID is [mod_link.id], frequency is [mod_link.frequency || "unset"]. <b>Right-click</b> with multitool to copy/imprint frequency.")
|
|
. += span_notice("Use in hand to set name.")
|
|
|
|
/obj/item/clothing/neck/link_scryer/equipped(mob/living/user, slot)
|
|
. = ..()
|
|
if(slot != ITEM_SLOT_NECK)
|
|
mod_link?.end_call()
|
|
|
|
/obj/item/clothing/neck/link_scryer/dropped(mob/living/user)
|
|
. = ..()
|
|
mod_link?.end_call()
|
|
|
|
/obj/item/clothing/neck/link_scryer/attack_self(mob/user, modifiers)
|
|
var/new_label = reject_bad_text(tgui_input_text(user, "Change the visible name", "Set Name", label, MAX_NAME_LEN))
|
|
if(!user.is_holding(src))
|
|
return
|
|
if(!new_label)
|
|
balloon_alert(user, "invalid name!")
|
|
return
|
|
label = new_label
|
|
balloon_alert(user, "name set")
|
|
update_name()
|
|
|
|
/obj/item/clothing/neck/link_scryer/process(seconds_per_tick)
|
|
if(!mod_link.link_call)
|
|
return
|
|
cell.use(0.02 * STANDARD_CELL_RATE * seconds_per_tick, force = TRUE)
|
|
|
|
/obj/item/clothing/neck/link_scryer/attackby(obj/item/attacked_by, mob/user, list/modifiers, list/attack_modifiers)
|
|
. = ..()
|
|
if(cell || !istype(attacked_by, /obj/item/stock_parts/power_store/cell))
|
|
return
|
|
if(!user.transferItemToLoc(attacked_by, src))
|
|
return
|
|
cell = attacked_by
|
|
balloon_alert(user, "cell installed")
|
|
|
|
/obj/item/clothing/neck/link_scryer/update_name(updates)
|
|
. = ..()
|
|
name = "[initial(name)][label ? " - [label]" : ""]"
|
|
|
|
/obj/item/clothing/neck/link_scryer/Exited(atom/movable/gone, direction)
|
|
. = ..()
|
|
if(gone == cell)
|
|
cell = null
|
|
|
|
/obj/item/clothing/neck/link_scryer/attack_hand_secondary(mob/user, list/modifiers)
|
|
if(!cell)
|
|
return SECONDARY_ATTACK_CONTINUE_CHAIN
|
|
balloon_alert(user, "cell removed")
|
|
user.put_in_hands(cell)
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/item/clothing/neck/link_scryer/multitool_act_secondary(mob/living/user, obj/item/multitool/tool)
|
|
. = NONE
|
|
|
|
var/tool_frequency = null
|
|
if(istype(tool.buffer, /datum/mod_link))
|
|
var/datum/mod_link/buffer_link = tool.buffer
|
|
tool_frequency = buffer_link.frequency
|
|
balloon_alert(user, "frequency set")
|
|
. = ITEM_INTERACT_SUCCESS
|
|
if(!tool_frequency && mod_link.frequency)
|
|
tool.set_buffer(mod_link)
|
|
balloon_alert(user, "frequency copied")
|
|
. = ITEM_INTERACT_SUCCESS
|
|
else if(tool_frequency && !mod_link.frequency)
|
|
mod_link.frequency = tool_frequency
|
|
. = ITEM_INTERACT_SUCCESS
|
|
else if(tool_frequency && mod_link.frequency)
|
|
var/response = tgui_alert(user, "Would you like to copy or imprint the frequency?", "MODlink Frequency", list("Copy", "Imprint"))
|
|
if(!user.is_holding(tool))
|
|
return ITEM_INTERACT_BLOCKING
|
|
switch(response)
|
|
if("Copy")
|
|
tool.set_buffer(mod_link)
|
|
balloon_alert(user, "frequency copied")
|
|
. = ITEM_INTERACT_SUCCESS
|
|
if("Imprint")
|
|
mod_link.frequency = tool_frequency
|
|
balloon_alert(user, "frequency set")
|
|
. = ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/item/clothing/neck/link_scryer/worn_overlays(mutable_appearance/standing, isinhands)
|
|
. = ..()
|
|
if(!QDELETED(mod_link.link_call))
|
|
. += mutable_appearance('icons/mob/clothing/neck.dmi', "modlink_active")
|
|
|
|
/obj/item/clothing/neck/link_scryer/ui_action_click(mob/user)
|
|
if(mod_link.link_call)
|
|
mod_link.end_call()
|
|
else if(QDELETED(cell))
|
|
user.balloon_alert(user, "no cell installed!")
|
|
else if(!cell.charge)
|
|
user.balloon_alert(user, "no charge!")
|
|
else
|
|
call_link(user, mod_link)
|
|
|
|
/obj/item/clothing/neck/link_scryer/proc/get_user()
|
|
var/mob/living/carbon/user = loc
|
|
return istype(user) && user.wear_neck == src ? user : null
|
|
|
|
/obj/item/clothing/neck/link_scryer/proc/can_call()
|
|
var/mob/living/user = loc
|
|
return istype(user) && cell?.charge && user.stat < DEAD
|
|
|
|
/obj/item/clothing/neck/link_scryer/proc/make_link_visual()
|
|
var/mob/living/user = mod_link.get_user_callback.Invoke()
|
|
user.update_worn_neck()
|
|
return make_link_visual_generic(mod_link, PROC_REF(on_overlay_change))
|
|
|
|
/obj/item/clothing/neck/link_scryer/proc/get_link_visual(atom/movable/visuals)
|
|
return get_link_visual_generic(mod_link, visuals, PROC_REF(on_user_set_dir))
|
|
|
|
/obj/item/clothing/neck/link_scryer/proc/delete_link_visual()
|
|
var/mob/living/user = mod_link.get_user_callback.Invoke()
|
|
if(!QDELETED(user))
|
|
user.update_worn_neck()
|
|
return delete_link_visual_generic(mod_link)
|
|
|
|
/obj/item/clothing/neck/link_scryer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
|
|
. = ..()
|
|
if(speaker != loc)
|
|
return
|
|
mod_link.visual.say(raw_message, sanitize = FALSE, message_range = 3)
|
|
|
|
/obj/item/clothing/neck/link_scryer/proc/on_overlay_change(atom/source, cache_index, overlay)
|
|
SIGNAL_HANDLER
|
|
addtimer(CALLBACK(src, PROC_REF(update_link_visual)), 1 TICKS, TIMER_UNIQUE)
|
|
|
|
/obj/item/clothing/neck/link_scryer/proc/update_link_visual()
|
|
if(QDELETED(mod_link.link_call))
|
|
return
|
|
var/mob/living/user = loc
|
|
mod_link.visual.cut_overlay(mod_link.visual_overlays)
|
|
mod_link.visual_overlays = user.overlays - user.active_thinking_indicator
|
|
mod_link.visual.add_overlay(mod_link.visual_overlays)
|
|
|
|
/obj/item/clothing/neck/link_scryer/proc/on_user_set_dir(atom/source, dir, newdir)
|
|
SIGNAL_HANDLER
|
|
on_user_set_dir_generic(mod_link, newdir || SOUTH)
|
|
|
|
/obj/item/clothing/neck/link_scryer/loaded
|
|
starting_frequency = MODLINK_FREQ_NANOTRASEN
|
|
|
|
/obj/item/clothing/neck/link_scryer/loaded/Initialize(mapload)
|
|
. = ..()
|
|
cell = new /obj/item/stock_parts/power_store/cell/high(src)
|
|
|
|
/obj/item/clothing/neck/link_scryer/loaded/charlie
|
|
starting_frequency = MODLINK_FREQ_CHARLIE
|
|
|
|
/// A MODlink datum, used to handle unique functions that will be used in the MODlink call.
|
|
/datum/mod_link
|
|
/// Generic name for multitool buffers.
|
|
var/name = "MODlink"
|
|
/// The frequency of the MODlink. You can only call other MODlinks on the same frequency.
|
|
var/frequency
|
|
/// The unique ID of the MODlink.
|
|
var/id = ""
|
|
/// The atom that holds the MODlink.
|
|
var/atom/movable/holder
|
|
/// A reference to the visuals generated by the MODlink.
|
|
var/atom/movable/visual
|
|
/// A list of all overlays of the user, copied everytime they have an overlay change.
|
|
var/list/visual_overlays = list()
|
|
/// A reference to the call between two MODlinks.
|
|
var/datum/mod_link_call/link_call
|
|
/// A callback that returns the user of the MODlink.
|
|
var/datum/callback/get_user_callback
|
|
/// A callback that returns whether the MODlink can currently call.
|
|
var/datum/callback/can_call_callback
|
|
/// A callback that returns the visuals of the MODlink.
|
|
var/datum/callback/make_visual_callback
|
|
/// A callback that receives the visuals of the other MODlink.
|
|
var/datum/callback/get_visual_callback
|
|
/// A callback that deletes the visuals of the MODlink.
|
|
var/datum/callback/delete_visual_callback
|
|
|
|
/datum/mod_link/New(
|
|
atom/holder,
|
|
frequency,
|
|
datum/callback/get_user_callback,
|
|
datum/callback/can_call_callback,
|
|
datum/callback/make_visual_callback,
|
|
datum/callback/get_visual_callback,
|
|
datum/callback/delete_visual_callback
|
|
)
|
|
var/attempts = 0
|
|
var/digits_to_make = 3
|
|
do
|
|
if(attempts == 10)
|
|
attempts = 0
|
|
digits_to_make++
|
|
id = ""
|
|
for(var/i in 1 to digits_to_make)
|
|
id += num2text(rand(0,9))
|
|
attempts++
|
|
while(GLOB.mod_link_ids[id])
|
|
GLOB.mod_link_ids[id] = src
|
|
src.frequency = frequency
|
|
src.holder = holder
|
|
src.get_user_callback = get_user_callback
|
|
src.can_call_callback = can_call_callback
|
|
src.make_visual_callback = make_visual_callback
|
|
src.get_visual_callback = get_visual_callback
|
|
src.delete_visual_callback = delete_visual_callback
|
|
RegisterSignal(holder, COMSIG_QDELETING, PROC_REF(on_holder_delete))
|
|
|
|
/datum/mod_link/Destroy()
|
|
GLOB.mod_link_ids -= id
|
|
if(link_call)
|
|
end_call()
|
|
get_user_callback = null
|
|
make_visual_callback = null
|
|
get_visual_callback = null
|
|
delete_visual_callback = null
|
|
return ..()
|
|
|
|
/datum/mod_link/proc/get_other()
|
|
RETURN_TYPE(/datum/mod_link)
|
|
if(!link_call)
|
|
return
|
|
return link_call.link_caller == src ? link_call.link_receiver : link_call.link_caller
|
|
|
|
/datum/mod_link/proc/call_link(datum/mod_link/called, mob/user)
|
|
if(!frequency)
|
|
return
|
|
if(!istype(called))
|
|
holder.balloon_alert(user, "invalid target!")
|
|
return
|
|
var/mob/living/link_user = get_user_callback.Invoke()
|
|
if(!link_user)
|
|
return
|
|
if(HAS_TRAIT(link_user, TRAIT_IN_CALL))
|
|
holder.balloon_alert(user, "already calling!")
|
|
return
|
|
var/mob/living/link_target = called.get_user_callback.Invoke()
|
|
if(!link_target)
|
|
holder.balloon_alert(user, "invalid target!")
|
|
return
|
|
if(HAS_TRAIT(link_target, TRAIT_IN_CALL))
|
|
holder.balloon_alert(user, "target already in call!")
|
|
return
|
|
if(!can_call_callback.Invoke() || !called.can_call_callback.Invoke())
|
|
holder.balloon_alert(user, "can't call!")
|
|
return
|
|
link_target.playsound_local(get_turf(called.holder), 'sound/items/weapons/ring.ogg', 15, vary = TRUE)
|
|
var/atom/movable/screen/alert/modlink_call/alert = link_target.throw_alert("[REF(src)]_modlink", /atom/movable/screen/alert/modlink_call)
|
|
alert.desc = "[holder] ([id]) is calling you! Left-click this to accept the call. Right-click to deny it."
|
|
alert.link_caller_ref = WEAKREF(src)
|
|
alert.link_receiver_ref = WEAKREF(called)
|
|
alert.user_ref = WEAKREF(user)
|
|
|
|
/datum/mod_link/proc/end_call()
|
|
QDEL_NULL(link_call)
|
|
|
|
/datum/mod_link/proc/on_holder_delete(atom/source)
|
|
SIGNAL_HANDLER
|
|
qdel(src)
|
|
|
|
/// A MODlink call datum, used to handle the call between two MODlinks.
|
|
/datum/mod_link_call
|
|
/// The MODlink that is calling.
|
|
var/datum/mod_link/link_caller
|
|
/// The MODlink that is being called.
|
|
var/datum/mod_link/link_receiver
|
|
|
|
/datum/mod_link_call/New(datum/mod_link/link_caller, datum/mod_link/link_receiver)
|
|
link_caller.link_call = src
|
|
link_receiver.link_call = src
|
|
src.link_caller = link_caller
|
|
src.link_receiver = link_receiver
|
|
var/mob/living/caller_mob = link_caller.get_user_callback.Invoke()
|
|
ADD_TRAIT(caller_mob, TRAIT_IN_CALL, REF(src))
|
|
var/mob/living/receiver_mob = link_receiver.get_user_callback.Invoke()
|
|
ADD_TRAIT(receiver_mob, TRAIT_IN_CALL, REF(src))
|
|
make_visuals()
|
|
START_PROCESSING(SSprocessing, src)
|
|
|
|
/datum/mod_link_call/Destroy()
|
|
var/mob/living/caller_mob = link_caller.get_user_callback.Invoke()
|
|
if(!QDELETED(caller_mob))
|
|
REMOVE_TRAIT(caller_mob, TRAIT_IN_CALL, REF(src))
|
|
var/mob/living/receiver_mob = link_receiver.get_user_callback.Invoke()
|
|
if(!QDELETED(receiver_mob))
|
|
REMOVE_TRAIT(receiver_mob, TRAIT_IN_CALL, REF(src))
|
|
STOP_PROCESSING(SSprocessing, src)
|
|
clear_visuals()
|
|
link_caller.link_call = null
|
|
link_receiver.link_call = null
|
|
return ..()
|
|
|
|
/datum/mod_link_call/process(seconds_per_tick)
|
|
if(can_continue_call())
|
|
return
|
|
qdel(src)
|
|
|
|
/datum/mod_link_call/proc/can_continue_call()
|
|
return link_caller.frequency == link_receiver.frequency && link_caller.can_call_callback.Invoke() && link_receiver.can_call_callback.Invoke()
|
|
|
|
/datum/mod_link_call/proc/make_visuals()
|
|
var/caller_visual = link_caller.make_visual_callback.Invoke()
|
|
var/receiver_visual = link_receiver.make_visual_callback.Invoke()
|
|
link_caller.get_visual_callback.Invoke(receiver_visual)
|
|
link_receiver.get_visual_callback.Invoke(caller_visual)
|
|
|
|
/datum/mod_link_call/proc/clear_visuals()
|
|
link_caller.delete_visual_callback.Invoke()
|
|
link_receiver.delete_visual_callback.Invoke()
|
|
|
|
/proc/call_link(mob/user, datum/mod_link/calling_link)
|
|
if(!calling_link.frequency)
|
|
return
|
|
var/list/callers = list()
|
|
for(var/id in GLOB.mod_link_ids)
|
|
var/datum/mod_link/link = GLOB.mod_link_ids[id]
|
|
if(link.frequency != calling_link.frequency)
|
|
continue
|
|
if(link == calling_link)
|
|
continue
|
|
if(!link.can_call_callback.Invoke())
|
|
continue
|
|
callers["[link.holder] ([id])"] = id
|
|
if(!length(callers))
|
|
calling_link.holder.balloon_alert(user, "no targets on freq [calling_link.frequency]!")
|
|
return
|
|
var/chosen_link = tgui_input_list(user, "Choose ID to call from [calling_link.frequency] frequency", "MODlink", callers)
|
|
if(!chosen_link)
|
|
return
|
|
calling_link.call_link(GLOB.mod_link_ids[callers[chosen_link]], user)
|
|
|
|
/atom/movable/screen/alert/modlink_call
|
|
name = "MODlink Call Incoming"
|
|
desc = "Someone is calling you! Left-click this to accept the call. Right-click to deny it."
|
|
icon_state = "called"
|
|
timeout = 10 SECONDS
|
|
clickable_glow = TRUE
|
|
var/end_message = "call timed out!"
|
|
/// A weak reference to the MODlink that is calling.
|
|
var/datum/weakref/link_caller_ref
|
|
/// A weak reference to the MODlink that is being called.
|
|
var/datum/weakref/link_receiver_ref
|
|
/// A weak reference to the mob that is calling.
|
|
var/datum/weakref/user_ref
|
|
|
|
/atom/movable/screen/alert/modlink_call/Click(location, control, params)
|
|
. = ..()
|
|
if(usr != owner)
|
|
return
|
|
var/datum/mod_link/link_caller = link_caller_ref.resolve()
|
|
var/datum/mod_link/link_receiver = link_receiver_ref.resolve()
|
|
if(!link_caller || !link_receiver)
|
|
return
|
|
if(link_caller.link_call || link_receiver.link_call)
|
|
return
|
|
var/list/modifiers = params2list(params)
|
|
if(LAZYACCESS(modifiers, RIGHT_CLICK))
|
|
end_message = "call denied!"
|
|
owner.clear_alert("[REF(link_caller)]_modlink")
|
|
return
|
|
end_message = "call accepted"
|
|
new /datum/mod_link_call(link_caller, link_receiver)
|
|
owner.clear_alert("[REF(link_caller)]_modlink")
|
|
|
|
/atom/movable/screen/alert/modlink_call/Destroy()
|
|
var/mob/living/user = user_ref?.resolve()
|
|
var/datum/mod_link/link_caller = link_caller_ref?.resolve()
|
|
if(!user || !link_caller)
|
|
return ..()
|
|
link_caller.holder.balloon_alert(user, end_message)
|
|
return ..()
|