Interactions tidyup (#8850)

* Updated interactions

* Update interaction_menu.dm

* Colors

* Update interaction_menu.dm

* Update interaction_menu.dm

* Update interaction_menu.dm

* Better code for all.

* Update interaction_component.dm

* Removes support for TARGET SPEAK and USER SPEAK due to instability.

* Update interactions.dm

* Update interaction_component.dm

* Enables you to interact from a distance again.
This commit is contained in:
Gandalf
2021-10-18 01:01:14 +01:00
committed by GitHub
parent 13a8a5606b
commit 72f6221689
11 changed files with 273 additions and 265 deletions

View File

@@ -0,0 +1,16 @@
#define INTERACTION_JSON_FOLDER "config/skyrat/interactions/"
// Special values
#define INTERACTION_MAX_CHAR 255
#define INTERACTION_COOLDOWN 1 SECONDS
// If an interaction has this category it will not be shown to players
#define INTERACTION_CAT_HIDE "hide"
// If you add a new requirement you also need to implement its checking. See /datum/interaction/proc/allow_act
#define INTERACTION_REQUIRE_SELF_HAND "self_hand"
#define INTERACTION_REQUIRE_TARGET_HAND "target_hand"
// Interaction Types: Do we do it to ourself or someone else
#define INTERACTION_SELF "self"
#define INTERACTION_OTHER "other"

View File

@@ -438,7 +438,7 @@
/mob/proc/ShiftMiddleClickOn(atom/A)
src.pointed(A)
return
//SKYRAT EDIT NOTE: CtrlShiftClick for HUMANS has been overriden in click.dm in the interaction module.
/atom/proc/CtrlShiftClick(mob/user)
if(!can_interact(user))
return FALSE

View File

@@ -71,6 +71,8 @@
LoadPolicy()
LoadChatFilter()
populate_interaction_instances() //SKYRAT EDIT ADDITION
loaded = TRUE
if (Master)

View File

@@ -10,8 +10,5 @@
"sound_use": 0,
"sound_possible": [
],
"sound_range": 7,
"interaction_requires": [
"self_speak"
]
"sound_range": 7
}

View File

@@ -16,8 +16,6 @@
"sound_range": 7,
"interaction_requires": [
"self_hand",
"self_speak",
"target_hand",
"target_speak"
"target_hand"
]
}

View File

@@ -0,0 +1,3 @@
/mob/living/carbon/human/CtrlShiftClick(mob/user) //We have to remove the can_interact check from humans.
SEND_SIGNAL(src, COMSIG_CLICK_CTRL_SHIFT, user)
return

View File

@@ -0,0 +1,113 @@
/datum/component/interactable
/// A hard reference to the parent
var/mob/living/carbon/human/self = null
/// A list of interactions that the user can engage in.
var/list/datum/interaction/interactions
var/interact_last = 0
var/interact_next = 0
/datum/component/interactable/Initialize(...)
if(QDELETED(parent))
qdel(src)
return
if(!ishuman(parent))
return COMPONENT_INCOMPATIBLE
self = parent
build_interactions_list()
/datum/component/interactable/proc/build_interactions_list()
interactions = list()
for(var/iterating_interaction_id in GLOB.interaction_instances)
var/datum/interaction/interaction = GLOB.interaction_instances[iterating_interaction_id]
if(interaction.lewd && !self.client?.prefs?.read_preference(/datum/preference/toggle/erp))
continue
interactions.Add(interaction)
/datum/component/interactable/RegisterWithParent()
RegisterSignal(parent, COMSIG_CLICK_CTRL_SHIFT, .proc/open_interaction_menu)
/datum/component/interactable/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_CLICK_CTRL_SHIFT)
/datum/component/interactable/Destroy(force, silent)
self = null
interactions = null
return ..()
/datum/component/interactable/proc/open_interaction_menu(datum/source, mob/user)
if(!ishuman(user))
return
build_interactions_list()
ui_interact(user)
/datum/component/interactable/proc/can_interact(datum/interaction/interaction, mob/living/carbon/human/target)
if(!interaction.allow_act(target, self))
return FALSE
if(interaction.lewd && !target.client?.prefs?.read_preference(/datum/preference/toggle/erp))
return FALSE
if(!interaction.distance_allowed && !target.Adjacent(self))
return FALSE
if(interaction.category == INTERACTION_CAT_HIDE)
return FALSE
if(self == target && interaction.usage == INTERACTION_OTHER)
return FALSE
return TRUE
/// UI Control
/datum/component/interactable/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "InteractionMenu")
ui.open()
/datum/component/interactable/ui_status(mob/user, datum/ui_state/state)
return UI_INTERACTIVE // This UI is always interactive as we handle distance flags via can_interact
/datum/component/interactable/ui_data(mob/user)
var/list/data = list()
var/list/descriptions = list()
var/list/categories = list()
var/list/colors = list()
for(var/datum/interaction/interaction in interactions)
if(!can_interact(interaction, user))
continue
if(!categories[interaction.category])
categories[interaction.category] = list(interaction.name)
else
categories[interaction.category] += interaction.name
descriptions[interaction.name] = interaction.description
colors[interaction.name] = interaction.color
data["categories"] = list()
data["descriptions"] = descriptions
data["colors"] = colors
for(var/category in categories)
data["categories"] += category
data["ref_user"] = REF(user)
data["ref_self"] = REF(self)
data["self"] = self.name
data["block_interact"] = interact_next >= world.time
data["interactions"] = categories
return data
/datum/component/interactable/ui_act(action, list/params)
. = ..()
if(.)
return
if(params["interaction"])
var/interaction_id = params["interaction"]
if(GLOB.interaction_instances[interaction_id])
var/mob/living/carbon/human/user = locate(params["userref"])
if(!can_interact(GLOB.interaction_instances[interaction_id], user))
return FALSE
GLOB.interaction_instances[interaction_id].act(user, locate(params["selfref"]))
var/datum/component/interactable/interaction_component = user.GetComponent(/datum/component/interactable)
interaction_component.interact_last = world.time
interact_next = interaction_component.interact_last + INTERACTION_COOLDOWN
interaction_component.interact_next = interact_next
return TRUE
message_admins("Unhandled interaction '[params["interaction"]]'. Inform coders.")

View File

@@ -1,162 +1,6 @@
#define INTERACTION_JSON_FOLDER "config/skyrat/interactions/"
GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
// Special values
#define INTERACTION_MAX_CHAR 255
#define INTERACTION_COOLDOWN 0.5 SECONDS
// If an interaction has this category it will not be shown to players
#define INTERACTION_CAT_HIDE "hide"
// I want these to be bitflags; but that would make json loading painful beyond compare
// If you add a new requirement you also need to implement its checking. See /datum/interaction/proc/allow_act
#define INTERACTION_REQUIRE_SELF_HAND "self_hand"
#define INTERACTION_REQUIRE_SELF_SPEAK "self_speak"
#define INTERACTION_REQUIRE_TARGET_HAND "target_hand"
#define INTERACTION_REQUIRE_TARGET_SPEAK "target_speak"
// Interaction Types: Do we do it to ourself or someone else
#define INTERACTION_SELF "self"
#define INTERACTION_OTHER "other"
/mob/living/carbon/human/CtrlShiftClickOn(atom/atom_on)
. = ..()
if(.) // already handled, ignore
return .
if(ishuman(atom_on))
var/mob/living/carbon/human/clicked_living = atom_on
var/datum/component/interactable/clicked_int = clicked_living.GetComponent(/datum/component/interactable)
if(!clicked_int)
message_admins("Interactable CtrlShiftClickOn failure. Inform Coders.")
clicked_int.ui_interact(src)
/proc/populate_interaction_instances()
if(GLOB.interaction_instances.len)
return
for(var/spath in subtypesof(/datum/interaction))
var/datum/interaction/interaction = new spath()
GLOB.interaction_instances[interaction.name] = interaction
populate_interaction_jsons(INTERACTION_JSON_FOLDER)
/proc/populate_interaction_jsons(directory)
for(var/file in flist(directory))
if(flist(directory + file) && !findlasttext(directory + file, ".json"))
populate_interaction_instances(directory + file)
continue
if(findlasttext(directory + file, ".master.json")) // This is a master json which has special handling
populate_interaction_jsons_master(directory + file)
continue
var/datum/interaction/int = new()
if(int.load_from_json(directory + file))
GLOB.interaction_instances[int.name] = int
else message_admins("Error loading interaction from file: '[directory + file]'. Inform coders.")
/proc/populate_interaction_jsons_master(path)
if(!fexists(path))
message_admins("We are attempting to load an interaction master without the file existing! '[path]'")
return
var/file = file(path)
var/list/json = json_load(file)
for(var/iname in json)
if(GLOB.interaction_instances[iname])
message_admins("Interaction Master '[path]' contained a duplicate interaction! '[iname]'")
continue
var/list/ijson = json[iname]
if(ijson["name"] != iname)
message_admins("Interaction Master '[path]' contained an invalid interaction! '[iname]'")
continue
var/datum/interaction/int = new()
int.distance_allowed = sanitize_integer(ijson["distance_allowed"], 0, 1, 0)
int.message = sanitize_islist(ijson["message"], list("json error"))
int.category = sanitize_text(ijson["category"])
int.usage = sanitize_text(ijson["usage"])
int.sound_use = sanitize_integer(ijson["sound_use"], 0, 1, 0)
int.sound_range = sanitize_integer(ijson["sound_range"], 1, 7, 1)
int.sound_possible = sanitize_islist(ijson["sound_possible"], list("json error"))
int.interaction_requires = sanitize_islist(ijson["interaction_requires"], list())
int.user_messages = sanitize_islist(ijson["user_messages"], list())
int.user_required_parts = sanitize_islist(ijson["user_required_parts"], list())
int.user_arousal = sanitize_integer(ijson["user_arousal"], 0, 100, 0)
int.user_pleasure = sanitize_integer(ijson["user_pleasure"], 0, 100, 0)
int.user_pain = sanitize_integer(ijson["user_pain"], 0, 100, 0)
int.target_messages = sanitize_islist(ijson["target_messages"], list())
int.target_required_parts = sanitize_islist(ijson["target_required_parts"], list())
int.target_arousal = sanitize_integer(ijson["target_arousal"], 0, 100, 0)
int.target_pleasure = sanitize_integer(ijson["target_pleasure"], 0, 100, 0)
int.target_pain = sanitize_integer(ijson["target_pain"], 0, 100, 0)
int.lewd = sanitize_integer(ijson["lewd"], 0, 1, 0)
GLOB.interaction_instances[iname] = int
/datum/interaction/proc/load_from_json(path)
var/fpath = path
if(!fexists(fpath))
message_admins("Attempted to load an interaction from json and the file does not exist")
qdel(src)
return FALSE
var/file = file(fpath)
var/list/json = json_load(file)
name = sanitize_text(json["name"])
description = sanitize_text(json["description"])
distance_allowed = sanitize_integer(json["distance_allowed"], 0, 1, 0)
message = sanitize_islist(json["message"], list("json error"))
category = sanitize_text(json["category"])
usage = sanitize_text(json["usage"])
sound_use = sanitize_integer(json["sound_use"], 0, 1, 0)
sound_range = sanitize_integer(json["sound_range"], 1, 7, 1)
sound_possible = sanitize_islist(json["sound_possible"], list("json error"))
interaction_requires = sanitize_islist(json["interaction_requires"], list())
user_messages = sanitize_islist(json["user_messages"], list())
user_required_parts = sanitize_islist(json["user_required_parts"], list())
user_arousal = sanitize_integer(json["user_arousal"], 0, 100, 0)
user_pleasure = sanitize_integer(json["user_pleasure"], 0, 100, 0)
user_pain = sanitize_integer(json["user_pain"], 0, 100, 0)
target_messages = sanitize_islist(json["target_messages"], list())
target_required_parts = sanitize_islist(json["target_required_parts"], list())
target_arousal = sanitize_integer(json["target_arousal"], 0, 100, 0)
target_pleasure = sanitize_integer(json["target_pleasure"], 0, 100, 0)
target_pain = sanitize_integer(json["target_pain"], 0, 100, 0)
lewd = sanitize_integer(json["lewd"], 0, 1, 0)
return TRUE
/datum/interaction/proc/json_save(path)
var/fpath = path
if(fexists(fpath))
fdel(fpath)
var/list/json = list(
"name" = name,
"description" = description,
"distance_allowed" = distance_allowed,
"message" = message,
"category" = category,
"usage" = usage,
"sound_use" = sound_use,
"sound_range" = sound_range,
"sound_possible" = sound_possible,
"interaction_requires" = interaction_requires,
"user_messages" = user_messages,
"user_required_parts" = user_required_parts,
"user_arousal" = user_arousal,
"user_pleasure" = user_pleasure,
"user_pain" = user_pain,
"target_messages" = target_messages,
"target_required_parts" = target_required_parts,
"target_arousal" = target_arousal,
"target_pleasure" = target_pleasure,
"target_pain" = target_pain,
"lewd" = lewd,
)
var/file = file(fpath)
WRITE_FILE(file, json_encode(json))
return TRUE
/datum/interaction
/// The name to be displayed in the interaction menu for this interaction
var/name = "broken interaction"
@@ -202,6 +46,8 @@ GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
var/list/sound_possible = list()
/// What requirements does this interaction have? See defines.
var/list/interaction_requires = list()
/// What color should the interaction button be?
var/color = "blue"
/datum/interaction/proc/allow_act(mob/living/carbon/human/user, mob/living/carbon/human/target)
if(target == user && usage == INTERACTION_OTHER)
@@ -228,21 +74,16 @@ GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
if(INTERACTION_REQUIRE_SELF_HAND)
if(!user.get_active_hand())
return FALSE
if(INTERACTION_REQUIRE_SELF_SPEAK)
if(!user.can_speak())
return FALSE
if(INTERACTION_REQUIRE_TARGET_HAND)
if(!target.get_active_hand())
return FALSE
if(INTERACTION_REQUIRE_TARGET_SPEAK)
if(!target.can_speak())
return FALSE
else
message_admins("Unimplemented interaction requirement '[requirement]'.")
CRASH("Unimplemented interaction requirement '[requirement]'")
return TRUE
/datum/interaction/proc/act(mob/living/carbon/human/user, mob/living/carbon/human/target)
if(!allow_act(user, target))
return
if(!message)
message_admins("Interaction had a null message list. '[name]'")
return
@@ -256,9 +97,11 @@ GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
user.emote("subtler", null, msg, TRUE)
else
user.manual_emote(msg)
if(user_messages.len)
var/user_msg = pick(user_messages)
user_msg = replacetext(replacetext(user_msg, "%TARGET%", "[target]"), "%USER%", "[user]")
to_chat(user, user_msg)
if(target_messages.len)
var/target_msg = pick(target_messages)
target_msg = replacetext(replacetext(target_msg, "%TARGET%", "[target]"), "%USER%", "[user]")
to_chat(target, target_msg)
@@ -281,101 +124,134 @@ GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
target.adjustArousal(target_arousal)
target.adjustPain(target_pain)
/datum/component/interactable
var/mob/living/carbon/human/self = null
var/interact_last = 0
var/interact_next = 0
/datum/interaction/proc/load_from_json(path)
var/fpath = path
if(!fexists(fpath))
message_admins("Attempted to load an interaction from json and the file does not exist")
qdel(src)
return FALSE
var/file = file(fpath)
var/list/json = json_load(file)
name = sanitize_text(json["name"])
description = sanitize_text(json["description"])
distance_allowed = sanitize_integer(json["distance_allowed"], 0, 1, 0)
message = sanitize_islist(json["message"], list("json error"))
category = sanitize_text(json["category"])
usage = sanitize_text(json["usage"])
sound_use = sanitize_integer(json["sound_use"], 0, 1, 0)
sound_range = sanitize_integer(json["sound_range"], 1, 7, 1)
sound_possible = sanitize_islist(json["sound_possible"], list("json error"))
interaction_requires = sanitize_islist(json["interaction_requires"], list())
color = sanitize_text(json["color"])
/datum/component/interactable/proc/can_interact(datum/interaction/interaction, mob/living/carbon/human/user)
if(!interaction.allow_act(user, self))
return FALSE
if(!interaction.distance_allowed && !user.Adjacent(self))
return FALSE
if(interaction.category == INTERACTION_CAT_HIDE)
return FALSE
if(self == user && interaction.usage == INTERACTION_OTHER)
return FALSE
user_messages = sanitize_islist(json["user_messages"], list())
user_required_parts = sanitize_islist(json["user_required_parts"], list())
user_arousal = sanitize_integer(json["user_arousal"], 0, 100, 0)
user_pleasure = sanitize_integer(json["user_pleasure"], 0, 100, 0)
user_pain = sanitize_integer(json["user_pain"], 0, 100, 0)
target_messages = sanitize_islist(json["target_messages"], list())
target_required_parts = sanitize_islist(json["target_required_parts"], list())
target_arousal = sanitize_integer(json["target_arousal"], 0, 100, 0)
target_pleasure = sanitize_integer(json["target_pleasure"], 0, 100, 0)
target_pain = sanitize_integer(json["target_pain"], 0, 100, 0)
lewd = sanitize_integer(json["lewd"], 0, 1, 0)
return TRUE
/datum/component/interactable/proc/make_interact_list(datum/component/interactable/other)
populate_interaction_instances()
var/list/ints = list()
for(var/interaction in GLOB.interaction_instances)
if(other.can_interact(GLOB.interaction_instances[interaction], self))
ints += GLOB.interaction_instances[interaction]
return ints
/datum/component/interactable/proc/mil_mob(mob/user)
var/datum/other = user.GetComponent(/datum/component/interactable)
if(!other)
CRASH("Unable to locate the interactable component for the given mob.")
return make_interact_list(other)
/datum/component/interactable/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "InteractionMenu")
ui.set_autoupdate(TRUE)
ui.open()
/datum/component/interactable/ui_status(mob/user, datum/ui_state/state)
return UI_INTERACTIVE // This UI is always interactive as we handle distance flags via can_interact
/datum/interaction/proc/json_save(path)
var/fpath = path
if(fexists(fpath))
fdel(fpath)
var/list/json = list(
"name" = name,
"description" = description,
"distance_allowed" = distance_allowed,
"message" = message,
"category" = category,
"usage" = usage,
"sound_use" = sound_use,
"sound_range" = sound_range,
"sound_possible" = sound_possible,
"interaction_requires" = interaction_requires,
"color" = color,
"user_messages" = user_messages,
"user_required_parts" = user_required_parts,
"user_arousal" = user_arousal,
"user_pleasure" = user_pleasure,
"user_pain" = user_pain,
"target_messages" = target_messages,
"target_required_parts" = target_required_parts,
"target_arousal" = target_arousal,
"target_pleasure" = target_pleasure,
"target_pain" = target_pain,
"lewd" = lewd,
)
var/file = file(fpath)
WRITE_FILE(file, json_encode(json))
return TRUE
/mob/living/carbon/human/ComponentInitialize()
. = ..()
AddComponent(/datum/component/interactable)
/datum/component/interactable/Initialize(...)
. = ..()
self = parent
/// Global loading procs
/proc/populate_interaction_instances()
for(var/spath in subtypesof(/datum/interaction))
var/datum/interaction/interaction = new spath()
GLOB.interaction_instances[interaction.name] = interaction
populate_interaction_jsons(INTERACTION_JSON_FOLDER)
/mob/living/carbon/human/verb/cmd_interact()
set src in view()
set category = "IC"
set name = "Interact"
/proc/populate_interaction_jsons(directory)
for(var/file in flist(directory))
if(flist(directory + file) && !findlasttext(directory + file, ".json"))
populate_interaction_instances(directory + file)
continue
if(findlasttext(directory + file, ".master.json")) // This is a master json which has special handling
populate_interaction_jsons_master(directory + file)
continue
var/datum/interaction/interaction = new()
if(interaction.load_from_json(directory + file))
GLOB.interaction_instances[interaction.name] = interaction
else message_admins("Error loading interaction from file: '[directory + file]'. Inform coders.")
if(isobserver(usr) || isdead(usr) || usr.stat == DEAD)
to_chat(usr, "You are dead.")
/proc/populate_interaction_jsons_master(path)
if(!fexists(path))
message_admins("We are attempting to load an interaction master without the file existing! '[path]'")
return
var/file = file(path)
var/list/json = json_load(file)
var/datum/component/interactable/int = GetComponent(/datum/component/interactable)
int.ui_interact(get_mob_by_ckey(usr.ckey))
for(var/iname in json)
if(GLOB.interaction_instances[iname])
message_admins("Interaction Master '[path]' contained a duplicate interaction! '[iname]'")
continue
/datum/component/interactable/ui_data(mob/user)
var/list/data = list()
var/list/datum/interaction/ints = mil_mob(user)
var/list/ijson = json[iname]
if(ijson["name"] != iname)
message_admins("Interaction Master '[path]' contained an invalid interaction! '[iname]'")
continue
var/list/descs = list()
var/list/cats = list()
for(var/datum/interaction/int in ints)
if(!cats[int.category])
cats[int.category] = list(int.name)
else cats[int.category] += int.name
descs[int.name] = int.description
data["categories"] = list()
data["descs"] = descs
for(var/cat in cats)
data["categories"] += cat
var/datum/interaction/interaction = new()
data["ref_user"] = REF(user)
data["ref_self"] = REF(self)
data["self"] = self.name
data["ints"] = cats
data["block_interact"] = interact_next >= world.time
return data
interaction.distance_allowed = sanitize_integer(ijson["distance_allowed"], 0, 1, 0)
interaction.message = sanitize_islist(ijson["message"], list("json error"))
interaction.category = sanitize_text(ijson["category"])
interaction.usage = sanitize_text(ijson["usage"])
interaction.sound_use = sanitize_integer(ijson["sound_use"], 0, 1, 0)
interaction.sound_range = sanitize_integer(ijson["sound_range"], 1, 7, 1)
interaction.sound_possible = sanitize_islist(ijson["sound_possible"], list("json error"))
interaction.interaction_requires = sanitize_islist(ijson["interaction_requires"], list())
interaction.color = sanitize_text(ijson["color"])
/datum/component/interactable/ui_act(action, list/params)
. = ..()
if(.)
return
populate_interaction_instances()
for(var/interaction in GLOB.interaction_instances)
if(interaction == params["interaction"])
GLOB.interaction_instances[interaction].act(locate(params["userref"]), locate(params["selfref"]))
var/mob/living/carbon/human/user = locate(params["userref"])
var/datum/component/interactable/int = user.GetComponent(/datum/component/interactable)
int.interact_last = world.time
interact_next = int.interact_last + INTERACTION_COOLDOWN
int.interact_next = interact_next
return TRUE
message_admins("Unhandled interaction '[params["interaction"]]'. Inform coders.")
interaction.user_messages = sanitize_islist(ijson["user_messages"], list())
interaction.user_required_parts = sanitize_islist(ijson["user_required_parts"], list())
interaction.user_arousal = sanitize_integer(ijson["user_arousal"], 0, 100, 0)
interaction.user_pleasure = sanitize_integer(ijson["user_pleasure"], 0, 100, 0)
interaction.user_pain = sanitize_integer(ijson["user_pain"], 0, 100, 0)
interaction.target_messages = sanitize_islist(ijson["target_messages"], list())
interaction.target_required_parts = sanitize_islist(ijson["target_required_parts"], list())
interaction.target_arousal = sanitize_integer(ijson["target_arousal"], 0, 100, 0)
interaction.target_pleasure = sanitize_integer(ijson["target_pleasure"], 0, 100, 0)
interaction.target_pain = sanitize_integer(ijson["target_pain"], 0, 100, 0)
interaction.lewd = sanitize_integer(ijson["lewd"], 0, 1, 0)
GLOB.interaction_instances[iname] = interaction

View File

@@ -189,6 +189,7 @@
#include "code\__DEFINES\~skyrat_defines\game_options.dm"
#include "code\__DEFINES\~skyrat_defines\gun.dm"
#include "code\__DEFINES\~skyrat_defines\integrated_electronics.dm"
#include "code\__DEFINES\~skyrat_defines\interactions.dm"
#include "code\__DEFINES\~skyrat_defines\inventory.dm"
#include "code\__DEFINES\~skyrat_defines\jobs.dm"
#include "code\__DEFINES\~skyrat_defines\keybindings.dm"
@@ -4606,7 +4607,9 @@
#include "modular_skyrat\modules\indicators\code\ssd_indicator.dm"
#include "modular_skyrat\modules\indicators\code\typing_indicator.dm"
#include "modular_skyrat\modules\inflatables\code\inflatable.dm"
#include "modular_skyrat\modules\interaction_menu\code\interaction_menu.dm"
#include "modular_skyrat\modules\interaction_menu\code\click.dm"
#include "modular_skyrat\modules\interaction_menu\code\interaction_component.dm"
#include "modular_skyrat\modules\interaction_menu\code\interaction_datum.dm"
#include "modular_skyrat\modules\jukebox\code\controllers\subsystem\jukeboxes.dm"
#include "modular_skyrat\modules\jukebox\code\controllers\subsystem\game\machinery\dance_machine.dm"
#include "modular_skyrat\modules\jungle\code\game\objects\structures\flora.dm"

View File

@@ -4,7 +4,7 @@ import { Window } from '../layouts';
export const InteractionMenu = (props, context) => {
const { act, data } = useBackend(context);
const { categories, ints, descs } = data; // Interaction categories
const { categories, interactions, descriptions, colors } = data;
const { self, ref_self, ref_user } = data;
const { block_interact } = data;
@@ -19,17 +19,17 @@ export const InteractionMenu = (props, context) => {
<Section key="interactions">
{categories.map((category) => (
<Section key={category} title={category}>
{ints[category].map((interaction) => (
{interactions[category].map((interaction) => (
<Section key={interaction}>
<left>
<Button margin={0} padding={0}
disabled={block_interact}
color={block_interact ? "grey" : "blue"}
color={block_interact ? "grey" : colors[interaction]}
content={interaction}
icon="exclamation-circle"
onClick={() => act('interact', { interaction: interaction, selfref: ref_self, userref: ref_user })}
/><br />
{descs[interaction]}
{descriptions[interaction]}
</left>
</Section>
))}