Files
CHOMPStation2/tgui/packages/tgui_ch/components/BodyZoneSelector.tsx
2023-06-19 19:41:48 +02:00

154 lines
3.9 KiB
TypeScript

import { Component, createRef } from 'inferno';
import { resolveAsset } from '../assets';
import { Box } from './Box';
export enum BodyZone {
Head = 'head',
Chest = 'chest',
LeftArm = 'l_arm',
RightArm = 'r_arm',
LeftLeg = 'l_leg',
RightLeg = 'r_leg',
Eyes = 'eyes',
Mouth = 'mouth',
Groin = 'groin',
}
const bodyZonePixelToZone = (x: number, y: number): BodyZone | null => {
// TypeScript translation of /atom/movable/screen/zone_sel/proc/get_zone_at
if (y < 1) {
return null;
} else if (y < 10) {
if (x > 10 && x < 15) {
return BodyZone.RightLeg;
} else if (x > 17 && x < 22) {
return BodyZone.LeftLeg;
}
} else if (y < 13) {
if (x > 8 && x < 11) {
return BodyZone.RightArm;
} else if (x > 12 && x < 20) {
return BodyZone.Groin;
} else if (x > 21 && x < 24) {
return BodyZone.LeftArm;
}
} else if (y < 22) {
if (x > 8 && x < 11) {
return BodyZone.RightArm;
} else if (x > 12 && x < 20) {
return BodyZone.Chest;
} else if (x > 21 && x < 24) {
return BodyZone.LeftArm;
}
} else if (y < 30 && x > 12 && x < 20) {
if (y > 23 && y < 24 && x > 15 && x < 17) {
return BodyZone.Mouth;
} else if (y > 25 && y < 27 && x > 14 && x < 18) {
return BodyZone.Eyes;
} else {
return BodyZone.Head;
}
}
return null;
};
type BodyZoneSelectorProps = {
onClick?: (zone: BodyZone) => void;
scale?: number;
selectedZone: BodyZone | null;
theme?: string;
};
type BodyZoneSelectorState = {
hoverZone: BodyZone | null;
};
export class BodyZoneSelector extends Component<
BodyZoneSelectorProps,
BodyZoneSelectorState
> {
ref = createRef<HTMLDivElement>();
state: BodyZoneSelectorState = {
hoverZone: null,
};
render() {
const { hoverZone } = this.state;
const { scale = 3, selectedZone, theme = 'midnight' } = this.props;
return (
<div
ref={this.ref}
style={{
width: `${32 * scale}px`,
height: `${32 * scale}px`,
position: 'relative',
}}>
<Box
as="img"
src={resolveAsset(`body_zones.base_${theme}.png`)}
onClick={() => {
const onClick = this.props.onClick;
if (onClick && this.state.hoverZone) {
onClick(this.state.hoverZone);
}
}}
onMouseMove={(event) => {
if (!this.props.onClick) {
return;
}
const rect = this.ref.current?.getBoundingClientRect();
if (!rect) {
return;
}
const x = event.clientX - rect.left;
const y = 32 * scale - (event.clientY - rect.top);
this.setState({
hoverZone: bodyZonePixelToZone(x / scale, y / scale),
});
}}
style={{
'-ms-interpolation-mode': 'nearest-neighbor',
'position': 'absolute',
'width': `${32 * scale}px`,
'height': `${32 * scale}px`,
}}
/>
{selectedZone && (
<Box
as="img"
src={resolveAsset(`body_zones.${selectedZone}.png`)}
style={{
'-ms-interpolation-mode': 'nearest-neighbor',
'pointer-events': 'none',
'position': 'absolute',
'width': `${32 * scale}px`,
'height': `${32 * scale}px`,
}}
/>
)}
{hoverZone && hoverZone !== selectedZone && (
<Box
as="img"
src={resolveAsset(`body_zones.${hoverZone}.png`)}
style={{
'-ms-interpolation-mode': 'nearest-neighbor',
'opacity': 0.5,
'pointer-events': 'none',
'position': 'absolute',
'width': `${32 * scale}px`,
'height': `${32 * scale}px`,
}}
/>
)}
</div>
);
}
}