Files
knifer/frontend/src/demo/perround.rs
2024-10-15 23:45:00 +02:00

200 lines
7.7 KiB
Rust

use leptos::*;
fn to_coloumn(idx: usize) -> usize {
if idx < 12 {
2 + idx
} else if idx < 24 {
2 + idx + 1
} else if idx < 27 {
2 + idx + 2
} else {
2 + idx + 3
}
}
#[leptos::component]
pub fn per_round() -> impl leptos::IntoView {
let perround_resource =
create_resource(leptos_router::use_params_map(), |params| async move {
let id = params.get("id").unwrap();
let res =
reqwasm::http::Request::get(&format!("/api/demos/{}/analysis/perround", id))
.send()
.await
.unwrap();
res.json::<common::demo_analysis::PerRoundResult>()
.await
.unwrap()
});
let style = stylers::style! {
"PerRound",
.round_overview {
display: inline-grid;
width: 90vw;
grid-template-columns: auto repeat(12, 1fr) 5px repeat(12, 1fr) 5px repeat(3, 1fr) 5px repeat(3, 1fr);
grid-template-rows: repeat(3, auto);
}
.round_entry {
display: inline-block;
border-left: 1px solid #101010;
border-right: 1px solid #101010;
padding-left: 2px;
padding-right: 2px;
}
.round_number {
border-top: 1px solid #101010;
border-bottom: 1px solid #101010;
}
p.round_entry {
margin: 0px;
}
.won.ct_won, .ct_player {
background-color: #1111ff77;
}
.won.t_won, .t_player {
background-color: #dd111177;
}
.lose {
background-color: #22222277;
}
};
let (round, set_round) = create_signal(0);
let events_list = move || {
let round_index = round();
let data = perround_resource.get();
let current_round = data.as_ref().map(|rs| rs.rounds.get(round_index).cloned()).flatten();
let teams = data.as_ref().map(|rs| rs.teams.clone());
match (current_round, teams) {
(Some(round), Some(teams)) => {
round.events.iter().map(|event| {
match event {
common::demo_analysis::RoundEvent::BombPlanted => view! { <li>Bomb has been planted</li> }.into_view(),
common::demo_analysis::RoundEvent::BombDefused => view! { <li>Bomb has been defused</li> }.into_view(),
common::demo_analysis::RoundEvent::Killed { attacker, died } => {
let mut attacker_t = teams.iter().find(|t| t.players.contains(attacker)).map(|t| t.name == "TERRORIST").unwrap_or(false);
let mut died_t = teams.iter().find(|t| t.players.contains(died)).map(|t| t.name == "TERRORIST").unwrap_or(false);
if (12..27).contains(&round_index) {
attacker_t = !attacker_t;
died_t = !died_t;
}
view! {
class=style,
<li>{"'"}
<span class:t_player=move || attacker_t class:ct_player=move || !attacker_t>{ attacker }</span>{"'"} killed {"'"}
<span class:t_player=move || died_t class:ct_player=move || !died_t>{ died }</span>{"'"}
</li>
}.into_view()
},
}
}).collect::<Vec<_>>().into_view()
}
_ => view! {}.into_view(),
}
};
let round_overview = move || {
(0..30).map(|r| {
let set_round = move |_| {
set_round.set(r);
};
let round = perround_resource.get().map(|rs| rs.rounds.get(r).cloned()).flatten();
let reason = round.map(|r| r.reason);
let (ct_won, t_won) = match &reason {
Some(common::demo_analysis::RoundWinReason::TKilled) => (true, false),
Some(common::demo_analysis::RoundWinReason::BombDefused) => (true, false),
Some(common::demo_analysis::RoundWinReason::TimeRanOut) => (true, false),
Some(common::demo_analysis::RoundWinReason::CTKilled) => (false, true),
Some(common::demo_analysis::RoundWinReason::BombExploded) => (false, true),
_ => (false, false)
};
// Upper is CT by default and lower is T by default
let (mut upper_symbol, mut upper_won) = match &reason {
Some(common::demo_analysis::RoundWinReason::TKilled) => (view! { <span>Killed Ts</span> }.into_view(), true),
Some(common::demo_analysis::RoundWinReason::BombDefused) => (view! { <span>Defused</span> }.into_view(), true),
Some(common::demo_analysis::RoundWinReason::TimeRanOut) => (view! { <span>Out of Time</span> }.into_view(), true),
_ => (view! {}.into_view(), false),
};
let (mut lower_symbol, mut lower_won) = match &reason {
Some(common::demo_analysis::RoundWinReason::CTKilled) => (view! { <span>Killed CTs</span> }.into_view(), true),
Some(common::demo_analysis::RoundWinReason::BombExploded) => (view! { <span>Exploded</span> }.into_view(), true),
_ => (view! {}.into_view(), false),
};
if (12..27).contains(&r) {
core::mem::swap(&mut upper_symbol, &mut lower_symbol);
core::mem::swap(&mut upper_won, &mut lower_won);
}
view! {
class=style,
<div
class="round_entry"
style=format!("grid-column: {}; grid-row: 1", to_coloumn(r))
class:ct_won=move || ct_won
class:t_won=move || t_won
class:won=move || upper_won
class:lose=move || !upper_won
>{ upper_symbol } </div>
<p on:click=set_round class="round_entry round_number" style=format!("grid-column: {}; grid-row: 2", to_coloumn(r))>{ r + 1 }</p>
<div
class="round_entry"
style=format!("grid-column: {}; grid-row: 3", to_coloumn(r))
class:ct_won=move || ct_won
class:t_won=move || t_won
class:won=move || lower_won
class:lose=move || !lower_won
> { lower_symbol } </div>
}
}).collect::<Vec<_>>()
};
let team_names = move || {
let perround_teams = match perround_resource.get().map(|p| p.teams) {
Some(t) => t,
None => return view! {}.into_view(),
};
let upper = perround_teams.iter().find(|t| t.name == "CT").map(|t| t.number).unwrap_or(0);
let lower = perround_teams.iter().find(|t| t.name == "TERRORIST").map(|t| t.number).unwrap_or(0);
view! {
<span style="grid-column: 1; grid-row: 1">Team { upper }</span>
<span style="grid-column: 1; grid-row: 3">Team { lower }</span>
}.into_view()
};
view! {
class=style,
<h3>Per Round</h3>
<div class="round_overview">
{ team_names }
{ round_overview }
</div>
<div>
<h3> Round { move || round.get() + 1 } </h3>
<div>
<ul> { events_list } </ul>
</div>
</div>
}
}