mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
185 lines
5.6 KiB
TypeScript
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>
|
|
);
|
|
}
|