mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
154 lines
3.9 KiB
TypeScript
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>
|
|
);
|
|
}
|
|
}
|