frontend/script/viewer/Analyse/Render/PlayerSpec.tsx
Robin Appelman d33a8df45d
All checks were successful
CI / checks (push) Successful in 59s
heal beam
2025-06-28 23:05:57 +02:00

185 lines
5.6 KiB
TypeScript

import {Class, MedigunType, PlayerState, SpyState} from "../Data/Parser";
export interface PlayerSpecProps {
player: PlayerState;
onHover: (userId: number) => void;
highlighted: boolean;
}
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 classMap = {
1: "scout",
2: "sniper",
3: "soldier",
4: "demoman",
5: "medic",
6: "heavy",
7: "pyro",
8: "spy",
9: "engineer"
};
const classSort = {
1: 1, //scout
3: 2, //soldier
7: 3, //pyro
4: 4, //demoman
6: 5, //heavy
9: 6, //engineer
5: 7, //medic
2: 8, //sniper
8: 9, //spy
};
const teamMap = {
0: "other",
1: "spectator",
2: "red",
3: "blue",
}
export interface PlayersSpecProps {
players: PlayerState[];
onHover: (userId: number) => void;
highlighted: number;
}
function sortPlayer(a, b) {
return classSort[a.playerClass] - classSort[b.playerClass];
}
function filterPlayers(players: PlayerState[], team: number): PlayerState[] {
const filtered = players.filter((player) => player.team === team);
filtered.sort(sortPlayer);
return filtered;
}
export function medics(players: PlayerState[]): PlayerState[] {
return players.filter(player => player.playerClass === Class.Medic);
}
export function PlayersSpec(props: PlayersSpecProps) {
const redPlayers = () => filterPlayers(props.players, 2);
const bluePlayers = () => filterPlayers(props.players, 3);
const redMedics = () => medics(redPlayers());
const blueMedics = () => medics(bluePlayers());
return (<div>
<div class="redSpecHolder">
<For each={redPlayers()}>{(player: PlayerState) =>
<PlayerSpec player={player} highlighted={player.info.userId == props.highlighted}
onHover={props.onHover}/>
}</For>
<For each={redMedics()}>{(player) =>
<UberSpec
team={teamMap[player.team]}
chargeLevel={player.class_data.charge}
medigun={player.class_data.medigun}
isDeath={player.health < 1}
/>
}</For>
</div>
<div class="blueSpecHolder">
<For each={bluePlayers()}>{(player) =>
<PlayerSpec player={player} highlighted={player.info.userId == props.highlighted}
onHover={props.onHover}/>
}</For>
<For each={blueMedics()}>{(player) =>
<UberSpec
team={teamMap[player.team]}
chargeLevel={player.class_data.charge}
medigun={player.class_data.medigun}
isDeath={player.health < 1}
/>
}</For>
</div>
</div>);
}
export function PlayerSpec(props: PlayerSpecProps) {
const healthPercent = () => Math.min(100, props.player.health / healthMap[props.player.playerClass] * 100);
const healthStatusClass = () => (props.player.health > healthMap[props.player.playerClass]) ? 'overhealed' : (props.player.health <= 0 ? 'dead' : '');
return (
<div
onmouseover={() => props.onHover(props.player.info.userId)}
onmouseout={() => props.onHover(0)}
classList={{
"playerspec": true,
[teamMap[props.player.team]]: true,
"webp": true,
[healthStatusClass()]: true,
highlighted: props.highlighted,
}}>
{getPlayerIcon(props.player)}
<div class="health-container">
<div class="healthbar"
style={{width: healthPercent() + '%'}}/>
<span class="player-name">{props.player.info.name}</span>
<span class="health">{props.player.health}</span>
</div>
</div>
);
}
function getPlayerIcon(player: PlayerState) {
if (classMap[player.playerClass]) {
const className = classMap[player.playerClass];
if (player.playerClass === Class.Spy && classMap[(player.class_data as SpyState).disguise_class]) {
const disguiseClassName = classMap[(player.class_data as SpyState).disguise_class];
return (<div class={className + " class-icon"}>
<div class={disguiseClassName + " disguise"}/>
</div>)
} else {
return <div class={className + " class-icon"}/>
}
} else {
return <div class={"class-icon"}/>
}
}
export interface UberSpecProps {
chargeLevel: number;
medigun: MedigunType;
team: string;
isDeath: boolean;
}
export function UberSpec(props: UberSpecProps) {
const healthStatusClass = (props.isDeath) ? 'dead' : '';
const medigunName = () => {
switch (props.medigun) {
case MedigunType.Kritzkrieg:
return "Kritzkrieg";
case MedigunType.Quickfix:
return "Quickfix";
case MedigunType.Vaccinator:
return "Vaccinator";
default:
return "Ubercharge";
}
}
return (
<div class={`playerspec uber ${props.team} ${healthStatusClass}`}>
<div class={"uber class-icon"}/>
<div class="health-container">
<div class="healthbar"
style={{width: props.chargeLevel + '%'}}/>
<span class="player-name">{medigunName()}</span>
<span class="health">{Math.round(props.chargeLevel)}</span>
</div>
</div>
);
}