mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 05:00:55 +01:00
Ghosts once again can see people's true names and roundstart jobs (#84951)
## About The Pull Request #83186 made it so ghosts are fooled by disguises, like wearing a mask and an ID. This PR fixes that behavior, instead always displaying the person's real name and their face/ID name (if their face name is somehow different from real name) in brackets. Additionally, this PR makes orbit menu prioritize "real" job name and icon, aka the ones the person spawned with. If they don't have an assigned job, it will fall back to current behavior of looking it up from their ID. Also, searching people includes both their fake and real name. ## Why It's Good For The Game Ghosts really, really shouldn't be fooled by wearing a gas mask and an ID. **Especially** admin ghosts. ## Changelog 🆑 qol: Ghost orbit menu now always displays person's real name and their roundstart job and cannot be fooled by disguises. /🆑
This commit is contained in:
@@ -113,5 +113,6 @@
|
||||
return name_chaser
|
||||
|
||||
/// Used by mobs to determine the name for someone wearing a mask, or with a disfigured or missing face. By default just returns the atom's name. add_id_name will control whether or not we append "(as [id_name])".
|
||||
/atom/proc/get_visible_name(add_id_name)
|
||||
/// force_real_name will always return real_name and add (as face_name/id_name) if it doesn't match their appearance
|
||||
/atom/proc/get_visible_name(add_id_name, force_real_name)
|
||||
return name
|
||||
|
||||
@@ -211,14 +211,26 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new)
|
||||
if(issilicon(player))
|
||||
serialized["job"] = player.job
|
||||
serialized["icon"] = "borg"
|
||||
else
|
||||
var/obj/item/card/id/id_card = player.get_idcard(hand_first = FALSE)
|
||||
serialized["job"] = id_card?.get_trim_assignment()
|
||||
serialized["icon"] = id_card?.get_trim_sechud_icon_state()
|
||||
return serialized
|
||||
|
||||
var/obj/item/card/id/id_card = player.get_idcard(hand_first = FALSE)
|
||||
serialized["job"] = id_card?.get_trim_assignment()
|
||||
serialized["icon"] = id_card?.get_trim_sechud_icon_state()
|
||||
|
||||
var/datum/job/job = player.mind?.assigned_role
|
||||
if (isnull(job))
|
||||
return serialized
|
||||
|
||||
serialized["mind_job"] = job.title
|
||||
var/datum/outfit/outfit = job.get_outfit()
|
||||
if (isnull(outfit))
|
||||
return serialized
|
||||
|
||||
var/datum/id_trim/trim = outfit.id_trim
|
||||
if (!isnull(trim))
|
||||
serialized["mind_icon"] = trim::sechud_icon_state
|
||||
return serialized
|
||||
|
||||
|
||||
/// Gets a list: Misc data and whether it's critical. Handles all snowflakey type cases
|
||||
/datum/orbit_menu/proc/get_misc_data(atom/movable/atom_poi) as /list
|
||||
var/list/misc = list()
|
||||
|
||||
@@ -57,15 +57,27 @@
|
||||
return if_no_id
|
||||
|
||||
//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a separate proc as it'll be useful elsewhere
|
||||
/mob/living/carbon/human/get_visible_name(add_id_name = TRUE)
|
||||
if(HAS_TRAIT(src, TRAIT_UNKNOWN))
|
||||
return "Unknown"
|
||||
/mob/living/carbon/human/get_visible_name(add_id_name = TRUE, force_real_name = FALSE)
|
||||
var/list/identity = list(null, null)
|
||||
SEND_SIGNAL(src, COMSIG_HUMAN_GET_VISIBLE_NAME, identity)
|
||||
var/signal_face = LAZYACCESS(identity, VISIBLE_NAME_FACE)
|
||||
var/signal_id = LAZYACCESS(identity, VISIBLE_NAME_ID)
|
||||
var/face_name = !isnull(signal_face) ? signal_face : get_face_name("")
|
||||
var/id_name = !isnull(signal_id) ? signal_id : get_id_name("")
|
||||
if (force_real_name)
|
||||
var/fake_name
|
||||
if (face_name && face_name != real_name)
|
||||
fake_name = face_name
|
||||
if(add_id_name && id_name && id_name != real_name)
|
||||
if (!isnull(fake_name) && id_name != face_name)
|
||||
fake_name = "[fake_name]/[id_name]"
|
||||
else
|
||||
fake_name = id_name
|
||||
if (HAS_TRAIT(src, TRAIT_UNKNOWN) || (!face_name && !id_name))
|
||||
fake_name = "Unknown"
|
||||
return "[real_name][fake_name ? " (as [fake_name])" : ""]"
|
||||
if(HAS_TRAIT(src, TRAIT_UNKNOWN))
|
||||
return "Unknown"
|
||||
if(face_name)
|
||||
if(add_id_name && id_name && (id_name != face_name))
|
||||
return "[face_name] (as [id_name])"
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Antagonist, Observable } from './types';
|
||||
|
||||
type Props = {
|
||||
item: Observable | Antagonist;
|
||||
realNameDisplay: boolean;
|
||||
};
|
||||
|
||||
type IconSettings = {
|
||||
@@ -22,7 +23,7 @@ const antagIcon: IconSettings = {
|
||||
};
|
||||
|
||||
export function JobIcon(props: Props) {
|
||||
const { item } = props;
|
||||
const { item, realNameDisplay } = props;
|
||||
|
||||
let iconSettings: IconSettings;
|
||||
if ('antag' in item) {
|
||||
@@ -32,16 +33,18 @@ export function JobIcon(props: Props) {
|
||||
}
|
||||
|
||||
// We don't need to cast here but typescript isn't smart enough to know that
|
||||
const { icon = '', job = '' } = item;
|
||||
const { icon = '', job = '', mind_icon = '', mind_job = '' } = item;
|
||||
const usedIcon = realNameDisplay ? mind_icon || icon : icon;
|
||||
const usedJob = realNameDisplay ? mind_job || job : job;
|
||||
|
||||
return (
|
||||
<div className="JobIcon">
|
||||
{icon === 'borg' ? (
|
||||
<Icon color="lightblue" name={JOB2ICON[job]} ml={0.3} mt={0.4} />
|
||||
<Icon color="lightblue" name={JOB2ICON[usedJob]} ml={0.3} mt={0.4} />
|
||||
) : (
|
||||
<DmIcon
|
||||
icon={iconSettings.dmi}
|
||||
icon_state={icon}
|
||||
icon_state={usedIcon}
|
||||
style={{
|
||||
transform: iconSettings.transform,
|
||||
}}
|
||||
|
||||
@@ -21,7 +21,8 @@ export function OrbitBlade(props) {
|
||||
const { data } = useBackend<OrbitData>();
|
||||
const { orbiting } = data;
|
||||
|
||||
const { setBladeOpen } = useContext(OrbitContext);
|
||||
const { setBladeOpen, realNameDisplay, setRealNameDisplay } =
|
||||
useContext(OrbitContext);
|
||||
|
||||
return (
|
||||
<Stack vertical width="244px">
|
||||
@@ -44,6 +45,24 @@ export function OrbitBlade(props) {
|
||||
<Stack.Item>
|
||||
<ViewModeSelector />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Section
|
||||
buttons={
|
||||
<Button
|
||||
color="transparent"
|
||||
icon="passport"
|
||||
selected={realNameDisplay}
|
||||
onClick={() => setRealNameDisplay(!realNameDisplay)}
|
||||
/>
|
||||
}
|
||||
color="label"
|
||||
title="Real Name Display"
|
||||
>
|
||||
Real Name mode will display actual character names and their
|
||||
roundstart jobs insteas of being based on their worn ID. If the person
|
||||
lacks a roundstart job, it will still display their ID job icon.
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
{!!orbiting && (
|
||||
<Stack.Item>
|
||||
<OrbitInfo />
|
||||
@@ -115,7 +134,7 @@ function OrbitInfo(props) {
|
||||
<Stack.Item>
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<JobIcon item={orbiting} />
|
||||
<JobIcon item={orbiting} realNameDisplay={false} />
|
||||
</Stack.Item>
|
||||
<Stack.Item color="label" grow>
|
||||
{job}
|
||||
|
||||
@@ -25,7 +25,8 @@ type Props = {
|
||||
export function OrbitCollapsible(props: Props) {
|
||||
const { color, section = [], title } = props;
|
||||
|
||||
const { autoObserve, searchQuery, viewMode } = useContext(OrbitContext);
|
||||
const { autoObserve, realNameDisplay, searchQuery, viewMode } =
|
||||
useContext(OrbitContext);
|
||||
|
||||
const filteredSection = section.filter((observable) =>
|
||||
isJobOrNameMatch(observable, searchQuery),
|
||||
@@ -53,6 +54,7 @@ export function OrbitCollapsible(props: Props) {
|
||||
const content = (
|
||||
<OrbitItem
|
||||
autoObserve={autoObserve}
|
||||
realNameDisplay={realNameDisplay}
|
||||
color={color}
|
||||
item={item}
|
||||
key={item.ref}
|
||||
@@ -66,7 +68,7 @@ export function OrbitCollapsible(props: Props) {
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={<OrbitTooltip item={item} />}
|
||||
content={<OrbitTooltip item={item} realNameDisplay={false} />}
|
||||
key={item.ref}
|
||||
position="bottom-start"
|
||||
>
|
||||
|
||||
@@ -9,13 +9,14 @@ import { Antagonist, Observable, OrbitData, ViewMode } from './types';
|
||||
type Props = {
|
||||
item: Observable | Antagonist;
|
||||
autoObserve: boolean;
|
||||
realNameDisplay: boolean;
|
||||
viewMode: ViewMode;
|
||||
color: string | undefined;
|
||||
};
|
||||
|
||||
/** Each button on the observable section */
|
||||
export function OrbitItem(props: Props) {
|
||||
const { item, autoObserve, viewMode, color } = props;
|
||||
const { item, autoObserve, realNameDisplay, viewMode, color } = props;
|
||||
const { full_name, icon, job, name, orbiters, ref } = item;
|
||||
|
||||
const { act, data } = useBackend<OrbitData>();
|
||||
@@ -33,7 +34,7 @@ export function OrbitItem(props: Props) {
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
{validIcon && <JobIcon item={item} />}
|
||||
{validIcon && <JobIcon item={item} realNameDisplay={realNameDisplay} />}
|
||||
|
||||
<Button
|
||||
color={getDisplayColor(item, viewMode, color)}
|
||||
@@ -41,7 +42,9 @@ export function OrbitItem(props: Props) {
|
||||
>
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
{capitalizeFirst(getDisplayName(full_name, name))}
|
||||
{realNameDisplay
|
||||
? capitalizeFirst(name || full_name)
|
||||
: capitalizeFirst(getDisplayName(full_name, name))}
|
||||
</Stack.Item>
|
||||
{!!orbiters && (
|
||||
<Stack.Item>
|
||||
|
||||
@@ -12,10 +12,12 @@ export function OrbitSearchBar(props) {
|
||||
const {
|
||||
autoObserve,
|
||||
bladeOpen,
|
||||
realNameDisplay,
|
||||
searchQuery,
|
||||
viewMode,
|
||||
setAutoObserve,
|
||||
setBladeOpen,
|
||||
setRealNameDisplay,
|
||||
setSearchQuery,
|
||||
setViewMode,
|
||||
} = useContext(OrbitContext);
|
||||
@@ -103,6 +105,17 @@ export function OrbitSearchBar(props) {
|
||||
tooltipPosition="bottom-start"
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
color="transparent"
|
||||
icon="passport"
|
||||
onClick={() => setRealNameDisplay(!realNameDisplay)}
|
||||
selected={realNameDisplay}
|
||||
tooltip="Toggle real name display. When active, you'll see real
|
||||
names instead of disguises in orbit menu."
|
||||
tooltipPosition="bottom-start"
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
color="transparent"
|
||||
|
||||
@@ -3,12 +3,13 @@ import { Antagonist, Observable } from './types';
|
||||
|
||||
type Props = {
|
||||
item: Observable | Antagonist;
|
||||
realNameDisplay: boolean;
|
||||
};
|
||||
|
||||
/** Displays some info on the mob as a tooltip. */
|
||||
export function OrbitTooltip(props: Props) {
|
||||
const { item } = props;
|
||||
const { extra, full_name, health, job } = item;
|
||||
const { item, realNameDisplay } = props;
|
||||
const { extra, full_name, health, job, mind_job } = item;
|
||||
|
||||
let antag;
|
||||
if ('antag' in item) {
|
||||
@@ -18,6 +19,7 @@ export function OrbitTooltip(props: Props) {
|
||||
const extraInfo = extra?.split(':');
|
||||
const displayHealth = !!health && health >= 0 ? `${health}%` : 'Critical';
|
||||
const showAFK = 'client' in item && !item.client;
|
||||
const displayJob = realNameDisplay ? mind_job : job;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -34,8 +36,8 @@ export function OrbitTooltip(props: Props) {
|
||||
{!!full_name && (
|
||||
<LabeledList.Item label="Real ID">{full_name}</LabeledList.Item>
|
||||
)}
|
||||
{!!job && !antag && (
|
||||
<LabeledList.Item label="Job">{job}</LabeledList.Item>
|
||||
{!!displayJob && !antag && (
|
||||
<LabeledList.Item label="Job">{displayJob}</LabeledList.Item>
|
||||
)}
|
||||
{!!antag && (
|
||||
<LabeledList.Item label="Threat">{antag}</LabeledList.Item>
|
||||
|
||||
@@ -126,10 +126,11 @@ export function isJobOrNameMatch(
|
||||
): boolean {
|
||||
if (!searchQuery) return true;
|
||||
|
||||
const { full_name, job } = observable;
|
||||
const { full_name, job, name } = observable;
|
||||
|
||||
return (
|
||||
full_name?.toLowerCase().includes(searchQuery?.toLowerCase()) ||
|
||||
name?.toLowerCase().includes(searchQuery?.toLowerCase()) ||
|
||||
job?.toLowerCase().includes(searchQuery?.toLowerCase()) ||
|
||||
false
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ViewMode } from './types';
|
||||
export function Orbit(props) {
|
||||
const [autoObserve, setAutoObserve] = useState(false);
|
||||
const [bladeOpen, setBladeOpen] = useState(false);
|
||||
const [realNameDisplay, setRealNameDisplay] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [viewMode, setViewMode] = useState<ViewMode>(VIEWMODE.Health);
|
||||
|
||||
@@ -23,6 +24,8 @@ export function Orbit(props) {
|
||||
setAutoObserve,
|
||||
bladeOpen,
|
||||
setBladeOpen,
|
||||
realNameDisplay,
|
||||
setRealNameDisplay,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
viewMode,
|
||||
@@ -59,6 +62,8 @@ type Context = {
|
||||
setAutoObserve: Dispatch<SetStateAction<boolean>>;
|
||||
bladeOpen: boolean;
|
||||
setBladeOpen: Dispatch<SetStateAction<boolean>>;
|
||||
realNameDisplay: boolean;
|
||||
setRealNameDisplay: Dispatch<SetStateAction<boolean>>;
|
||||
searchQuery: string;
|
||||
setSearchQuery: Dispatch<SetStateAction<string>>;
|
||||
viewMode: ViewMode;
|
||||
|
||||
@@ -27,7 +27,9 @@ export type Observable = {
|
||||
extra: string;
|
||||
health: number;
|
||||
icon: string;
|
||||
mind_icon: string;
|
||||
job: string;
|
||||
mind_job: string;
|
||||
name: string;
|
||||
orbiters: number;
|
||||
}>;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.JobIcon {
|
||||
background: black;
|
||||
height: 20px;
|
||||
overflow: clip;
|
||||
padding: 1px 1px 0 1px;
|
||||
overflow: hidden;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user