mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
107 lines
4.2 KiB
TypeScript
107 lines
4.2 KiB
TypeScript
import {Class, MedicState, PlayerState, SpyState, Team, WorldBoundaries} from "../Data/Parser";
|
|
|
|
export interface PlayerProp {
|
|
player: PlayerState;
|
|
mapBoundary: WorldBoundaries;
|
|
targetSize: {
|
|
width: number;
|
|
height: number;
|
|
};
|
|
scale: number;
|
|
onHover: (userId: number) => void;
|
|
highlighted: boolean;
|
|
players: PlayerState[];
|
|
}
|
|
|
|
const healthMap = {
|
|
0: 100, //fallback
|
|
1: 125,//scout
|
|
2: 150,//sniper
|
|
3: 200,//soldier,
|
|
4: 175,//demoman,
|
|
5: 150,//medic,
|
|
6: 300,//heavy,
|
|
7: 175,//pyro
|
|
8: 125,//spy
|
|
9: 125,//engineer
|
|
};
|
|
|
|
const imageMap = {
|
|
0: '',
|
|
1: require("inline://images/class_icons/scout.svg"),
|
|
2: require("inline://images/class_icons/sniper.svg"),
|
|
3: require("inline://images/class_icons/soldier.svg"),
|
|
4: require("inline://images/class_icons/demoman.svg"),
|
|
5: require("inline://images/class_icons/medic.svg"),
|
|
6: require("inline://images/class_icons/heavy.svg"),
|
|
7: require("inline://images/class_icons/pyro.svg"),
|
|
8: require("inline://images/class_icons/spy.svg"),
|
|
9: require("inline://images/class_icons/engineer.svg"),
|
|
};
|
|
|
|
export function Player(props: PlayerProp) {
|
|
const worldWidth = props.mapBoundary.boundary_max.x - props.mapBoundary.boundary_min.x;
|
|
const worldHeight = props.mapBoundary.boundary_max.y - props.mapBoundary.boundary_min.y;
|
|
const x = () => props.player.position.x - props.mapBoundary.boundary_min.x;
|
|
const y = () => props.player.position.y - props.mapBoundary.boundary_min.y;
|
|
const scaledX = () => x() / worldWidth * props.targetSize.width;
|
|
const scaledY = () => (worldHeight - y()) / worldHeight * props.targetSize.height;
|
|
const maxHealth = () => healthMap[props.player.playerClass];
|
|
const alpha = () => props.player.health / maxHealth();
|
|
const teamColor = () => (props.player.team === Team.Red) ? '#a75d50' : '#5b818f';
|
|
const imageOpacity = () => props.player.health === 0 ? 0 : (1 + alpha()) / 2;
|
|
const transform = () => `translate(${scaledX()} ${scaledY()}) scale(${1 / props.scale})`;
|
|
const rotate = () => `rotate(${270 - props.player.angle})`;
|
|
const filter = () => props.player.ubered ? ((props.player.team === Team.Red) ? 'url(#sofGlowRed)' : 'url(#sofGlowBlue)') : '';
|
|
const circleStrokeStyle = () => {
|
|
switch (props.player.playerClass) {
|
|
case Class.Medic:
|
|
return `${(props.player.class_data as MedicState).charge} 100`
|
|
case Class.Spy:
|
|
return `${(props.player.class_data as SpyState).cloak} 100`
|
|
default:
|
|
return "none";
|
|
}
|
|
}
|
|
const teamHatch = () => (props.player.team === Team.Red) ? `url(#diagonalHatchRed)` : `url(#diagonalHatchBlue)`;
|
|
const teamDisguiseHatch = () => (props.player.team === Team.Red) ? `url(#diagonalHatchRedBlue)` : `url(#diagonalHatchBlueRed)`;
|
|
const fill = () => {
|
|
if (props.player.cloaked) {
|
|
return teamHatch();
|
|
}
|
|
if (props.player.playerClass === Class.Spy && (props.player.class_data as SpyState).disguise_team !== props.player.team && (props.player.class_data as SpyState).disguise_class > 0) {
|
|
return teamDisguiseHatch();
|
|
}
|
|
return teamColor();
|
|
};
|
|
|
|
return (
|
|
<g
|
|
onmouseover={() => props.onHover(props.player.info.userId)}
|
|
onmouseout={() => props.onHover(0)}
|
|
transform={transform()}>
|
|
<polygon points="-6,14 0, 16 6,14 0,24" fill="white"
|
|
opacity={imageOpacity()}
|
|
transform={rotate()}/>
|
|
<circle r={16} stroke-width={props.highlighted ? 4 : 1.5} stroke="white"
|
|
stroke-dasharray={circleStrokeStyle()}
|
|
fill={fill()}
|
|
opacity={alpha()}
|
|
filter={filter()}
|
|
/>
|
|
{getClassImage(props.player, imageOpacity())}
|
|
</g>)
|
|
}
|
|
|
|
function getClassImage(player: PlayerState, imageOpacity: number) {
|
|
const image = imageMap[player.playerClass];
|
|
if (!image) {
|
|
return [];
|
|
}
|
|
return <image href={image}
|
|
class={"player-icon " + player.team}
|
|
opacity={imageOpacity}
|
|
height={32}
|
|
width={32}
|
|
transform={`translate(-16 -16)`}/>
|
|
}
|