mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
highlight player dot/spec on hover
This commit is contained in:
parent
04ae714282
commit
3644dbda6e
7 changed files with 355 additions and 298 deletions
|
|
@ -71,7 +71,7 @@ export function KillFeedDestroyedItem(props: KillFeedDestroyedItemProps) {
|
|||
return <li class="kill">
|
||||
<PlayerNames players={[attacker, assister]}/>
|
||||
<KillIcon kill={props.event}/>
|
||||
<PlayerName player={victim}/><span className={teamMap[victim.team]}>({props.event.building_type})</span>
|
||||
<PlayerName player={victim}/><span class={teamMap[victim.team]}>({props.event.building_type})</span>
|
||||
</li>
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ interface PlayerNameProps {
|
|||
|
||||
export function PlayerName(props: PlayerNameProps) {
|
||||
return <Show when={props.player}>
|
||||
<span className={"player " + teamMap[props.player.team]}>
|
||||
<span class={"player " + teamMap[props.player.team]}>
|
||||
{props.player.info.name}
|
||||
</span>
|
||||
</Show>
|
||||
|
|
@ -111,7 +111,7 @@ interface PlayerNamesProps {
|
|||
export function PlayerNames(props: PlayerNamesProps) {
|
||||
return <For each={props.players}>{(player, i) => <>
|
||||
<Show when={i() > 0 && player}>
|
||||
<span className={teamMap[player.team]}>+</span>
|
||||
<span class={teamMap[player.team]}>+</span>
|
||||
</Show>
|
||||
<PlayerName player={player}/>
|
||||
</>}</For>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ export interface PlayerProp {
|
|||
height: number;
|
||||
};
|
||||
scale: number;
|
||||
onHover: (userId: number) => void;
|
||||
highlighted: boolean;
|
||||
}
|
||||
|
||||
const healthMap = {
|
||||
|
|
@ -51,12 +53,15 @@ export function Player(props: PlayerProp) {
|
|||
const rotate = () => `rotate(${270 - props.player.angle})`;
|
||||
|
||||
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={1.5} stroke="white" fill={teamColor()}
|
||||
opacity={alpha()}/>
|
||||
<circle r={16} stroke-width={props.highlighted ? 5 : 1.5} stroke="white" fill={teamColor()}
|
||||
opacity={alpha()}
|
||||
/>
|
||||
{getClassImage(props.player, imageOpacity())}
|
||||
</g>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,146 +2,162 @@ import {PlayerState} from "../Data/Parser";
|
|||
import {KillFeedItem} from "./KillFeed";
|
||||
|
||||
export interface PlayerSpecProps {
|
||||
player: PlayerState;
|
||||
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
|
||||
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"
|
||||
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
|
||||
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",
|
||||
0: "other",
|
||||
1: "spectator",
|
||||
2: "red",
|
||||
3: "blue",
|
||||
}
|
||||
|
||||
export interface PlayersSpecProps {
|
||||
players: PlayerState[];
|
||||
players: PlayerState[];
|
||||
onHover: (userId: number) => void;
|
||||
highlighted: number;
|
||||
}
|
||||
|
||||
function sortPlayer(a, b) {
|
||||
return classSort[a.playerClass] - classSort[b.playerClass];
|
||||
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;
|
||||
const filtered = players.filter((player) => player.team === team);
|
||||
filtered.sort(sortPlayer);
|
||||
return filtered;
|
||||
}
|
||||
|
||||
function medics(players: PlayerState[]): PlayerState[] {
|
||||
return players.filter(player => player.playerClass === 5);
|
||||
return players.filter(player => player.playerClass === 5);
|
||||
}
|
||||
|
||||
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());
|
||||
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) =>
|
||||
<PlayerSpec player={player}/>
|
||||
}</For>
|
||||
<For each={redMedics()}>{(player) =>
|
||||
<UberSpec
|
||||
team={teamMap[player.team]}
|
||||
chargeLevel={player.charge}
|
||||
isDeath={player.health < 1}
|
||||
/>
|
||||
}</For>
|
||||
</div>
|
||||
<div class="blueSpecHolder">
|
||||
<For each={bluePlayers()}>{(player) =>
|
||||
<PlayerSpec player={player}/>
|
||||
}</For>
|
||||
<For each={blueMedics()}>{(player) =>
|
||||
<UberSpec
|
||||
team={teamMap[player.team]}
|
||||
chargeLevel={player.charge}
|
||||
isDeath={player.health < 1}
|
||||
/>
|
||||
}</For>
|
||||
</div>
|
||||
</div>);
|
||||
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.charge}
|
||||
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.charge}
|
||||
isDeath={player.health < 1}
|
||||
/>
|
||||
}</For>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
export function PlayerSpec({player}: PlayerSpecProps) {
|
||||
const healthPercent = Math.min(100, player.health / healthMap[player.playerClass] * 100);
|
||||
const healthStatusClass = (player.health > healthMap[player.playerClass]) ? 'overhealed' : (player.health <= 0 ? 'dead' : '');
|
||||
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
|
||||
class={"playerspec " + teamMap[player.team] + " webp " + healthStatusClass}>
|
||||
{getPlayerIcon(player)}
|
||||
<div class="health-container">
|
||||
<div class="healthbar"
|
||||
style={{width: healthPercent + '%'}}/>
|
||||
<span class="player-name">{player.info.name}</span>
|
||||
<span class="health">{player.health}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
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]) {
|
||||
return <div class={classMap[player.playerClass] + " class-icon"}/>
|
||||
} else {
|
||||
return <div class={"class-icon"}/>
|
||||
}
|
||||
if (classMap[player.playerClass]) {
|
||||
return <div class={classMap[player.playerClass] + " class-icon"}/>
|
||||
} else {
|
||||
return <div class={"class-icon"}/>
|
||||
}
|
||||
}
|
||||
|
||||
export interface UberSpecProps {
|
||||
chargeLevel: number;
|
||||
team: string;
|
||||
isDeath: boolean;
|
||||
chargeLevel: number;
|
||||
team: string;
|
||||
isDeath: boolean;
|
||||
}
|
||||
|
||||
export function UberSpec({chargeLevel, team, isDeath}: UberSpecProps) {
|
||||
const healthStatusClass = (isDeath) ? 'dead' : '';
|
||||
return (
|
||||
<div class={`playerspec uber ${team} ${healthStatusClass}`}>
|
||||
<div class={"uber class-icon"}/>
|
||||
<div class="health-container">
|
||||
<div class="healthbar"
|
||||
style={{width: chargeLevel + '%'}}/>
|
||||
<span class="player-name">Charge</span>
|
||||
<span class="health">{Math.round(chargeLevel)}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
const healthStatusClass = (isDeath) ? 'dead' : '';
|
||||
return (
|
||||
<div class={`playerspec uber ${team} ${healthStatusClass}`}>
|
||||
<div class={"uber class-icon"}/>
|
||||
<div class="health-container">
|
||||
<div class="healthbar"
|
||||
style={{width: chargeLevel + '%'}}/>
|
||||
<span class="player-name">Charge</span>
|
||||
<span class="health">{Math.round(chargeLevel)}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,15 @@ export interface SpecHUDProps {
|
|||
tick: number;
|
||||
parser: AsyncParser;
|
||||
players: PlayerState[];
|
||||
events: Event[]
|
||||
events: Event[];
|
||||
onHover: (userId: number) => void;
|
||||
highlighted: number | null;
|
||||
}
|
||||
|
||||
export function SpecHUD(props: SpecHUDProps) {
|
||||
return (<div class="spechud">
|
||||
<KillFeed tick={props.tick} events={props.events} players={props.players}/>
|
||||
<PlayersSpec players={props.players}/>
|
||||
<PlayersSpec players={props.players} onHover={props.onHover} highlighted={props.highlighted}/>
|
||||
</div>)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue