mirror of
https://github.com/lexogrine/cs2-react-hud.git
synced 2025-12-10 03:52:48 +01:00
204 lines
5.8 KiB
TypeScript
204 lines
5.8 KiB
TypeScript
import React from "react";
|
|
import * as I from "csgogsi-socket";
|
|
import "./matchbar.scss";
|
|
import TeamScore from "./TeamScore";
|
|
import Bomb from "./../Timers/BombTimer";
|
|
import Countdown from "./../Timers/Countdown";
|
|
import { GSI } from "../../App";
|
|
import { Match } from "../../api/interfaces";
|
|
|
|
function stringToClock(time: string | number, pad = true) {
|
|
if (typeof time === "string") {
|
|
time = parseFloat(time);
|
|
}
|
|
const countdown = Math.abs(Math.ceil(time));
|
|
const minutes = Math.floor(countdown / 60);
|
|
const seconds = countdown - minutes * 60;
|
|
if (pad && seconds < 10) {
|
|
return `${minutes}:0${seconds}`;
|
|
}
|
|
return `${minutes}:${seconds}`;
|
|
}
|
|
|
|
interface IProps {
|
|
match: Match | null;
|
|
map: I.Map;
|
|
phase: I.PhaseRaw,
|
|
bomb: I.Bomb | null,
|
|
}
|
|
|
|
export interface Timer {
|
|
width: number;
|
|
active: boolean;
|
|
countdown: number;
|
|
side: "left"|"right";
|
|
type: "defusing" | "planting";
|
|
player: I.Player | null;
|
|
}
|
|
|
|
interface IState {
|
|
defusing: Timer,
|
|
planting: Timer,
|
|
winState: {
|
|
side: "left"|"right",
|
|
show: boolean
|
|
}
|
|
}
|
|
|
|
export default class TeamBox extends React.Component<IProps, IState> {
|
|
constructor(props: IProps){
|
|
super(props);
|
|
this.state = {
|
|
defusing: {
|
|
width: 0,
|
|
active: false,
|
|
countdown: 10,
|
|
side: "left",
|
|
type: "defusing",
|
|
player: null
|
|
},
|
|
planting: {
|
|
width: 0,
|
|
active: false,
|
|
countdown: 10, // Fake
|
|
side: "right",
|
|
type: "planting",
|
|
player: null
|
|
},
|
|
winState: {
|
|
side: 'left',
|
|
show: false
|
|
}
|
|
}
|
|
}
|
|
plantStop = () => this.setState(state => {
|
|
state.planting.active = false;
|
|
return state;
|
|
});
|
|
|
|
setWidth = (type: 'defusing' | 'planting', width: number) => {
|
|
this.setState(state => {
|
|
state[type].width = width;
|
|
return state;
|
|
})
|
|
}
|
|
|
|
initPlantTimer = () => {
|
|
const bomb = new Countdown(time => {
|
|
let width = time * 100;
|
|
this.setWidth("planting", width/3);
|
|
});
|
|
GSI.on("bombPlantStart", player => {
|
|
if(!player || !player.team) return;
|
|
this.setState(state => {
|
|
state.planting.active = true;
|
|
state.planting.side = player.team.orientation;
|
|
state.planting.player = player;
|
|
})
|
|
})
|
|
GSI.on("data", data => {
|
|
if(!data.bomb || !data.bomb.countdown || data.bomb.state !== "planting") return this.plantStop();
|
|
this.setState(state => {
|
|
state.planting.active = true;
|
|
})
|
|
return bomb.go(data.bomb.countdown);
|
|
});
|
|
}
|
|
|
|
defuseStop = () => this.setState(state => {
|
|
state.defusing.active = false;
|
|
state.defusing.countdown = 10;
|
|
return state;
|
|
});
|
|
|
|
initDefuseTimer = () => {
|
|
const bomb = new Countdown(time => {
|
|
let width = time > this.state.defusing.countdown ? this.state.defusing.countdown*100 : time * 100;
|
|
this.setWidth("defusing", width/this.state.defusing.countdown);
|
|
});
|
|
GSI.on("defuseStart", player => {
|
|
if(!player || !player.team) return;
|
|
this.setState(state => {
|
|
state.defusing.active = true;
|
|
state.defusing.countdown = !Boolean(player.state.defusekit) ? 10 : 5;
|
|
state.defusing.side = player.team.orientation;
|
|
state.defusing.player = player;
|
|
return state;
|
|
})
|
|
})
|
|
GSI.on("data", data => {
|
|
if(!data.bomb || !data.bomb.countdown || data.bomb.state !== "defusing") return this.defuseStop();
|
|
this.setState(state => {
|
|
state.defusing.active = true;
|
|
return state;
|
|
})
|
|
return bomb.go(data.bomb.countdown);
|
|
});
|
|
}
|
|
|
|
resetWin = () => {
|
|
setTimeout(() => {
|
|
this.setState(state => {
|
|
state.winState.show = false;
|
|
return state;
|
|
})
|
|
}, 6000);
|
|
}
|
|
|
|
componentDidMount(){
|
|
this.initDefuseTimer();
|
|
this.initPlantTimer();
|
|
GSI.on("roundEnd", score => {
|
|
this.setState(state => {
|
|
state.winState.show = true;
|
|
state.winState.side = score.winner.orientation;
|
|
return state;
|
|
}, this.resetWin);
|
|
});
|
|
}
|
|
getRoundLabel = () => {
|
|
const { map } = this.props;
|
|
const round = map.round + 1;
|
|
if (round <= 24) {
|
|
return `Round ${round}/24`;
|
|
}
|
|
const additionalRounds = round - 24;
|
|
const OT = Math.ceil(additionalRounds/6);
|
|
return `OT ${OT} (${additionalRounds - (OT - 1)*6}/6)`;
|
|
}
|
|
render() {
|
|
const { defusing, planting, winState } = this.state;
|
|
const { bomb, match, map, phase } = this.props;
|
|
const time = stringToClock(phase.phase_ends_in);
|
|
const left = map.team_ct.orientation === "left" ? map.team_ct : map.team_t;
|
|
const right = map.team_ct.orientation === "left" ? map.team_t : map.team_ct;
|
|
const isPlanted = bomb && (bomb.state === "defusing" || bomb.state === "planted");
|
|
const bo = (match && Number(match.matchType.substr(-1))) || 0;
|
|
let leftTimer: Timer | null = null, rightTimer: Timer | null = null;
|
|
if(defusing.active || planting.active){
|
|
if(defusing.active){
|
|
if(defusing.side === "left") leftTimer = defusing;
|
|
else rightTimer = defusing;
|
|
} else {
|
|
if(planting.side === "left") leftTimer = planting;
|
|
else rightTimer = planting;
|
|
}
|
|
}
|
|
return (
|
|
<>
|
|
<div id={`matchbar`}>
|
|
<TeamScore team={left} orientation={"left"} timer={leftTimer} showWin={winState.show && winState.side === "left"} />
|
|
<div className={`score left ${left.side}`}>{left.score}</div>
|
|
<div id="timer" className={bo === 0 ? 'no-bo' : ''}>
|
|
<div id={`round_timer_text`} className={isPlanted ? "hide":""}>{time}</div>
|
|
<div id="round_now" className={isPlanted ? "hide":""}>{this.getRoundLabel()}</div>
|
|
<Bomb />
|
|
</div>
|
|
<div className={`score right ${right.side}`}>{right.score}</div>
|
|
<TeamScore team={right} orientation={"right"} timer={rightTimer} showWin={winState.show && winState.side === "right"} />
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
}
|