#[cfg(test)]
#[path = "../../tests/tf2/objectives/objective_resource.rs"]
mod tests;
use super::{Objective, ObjectiveError, RoundTimer};
use crate::Server;
use crate::entities::Entity;
use crate::math::Vector;
use crate::tf2::scoreboard::ScoringTeam;
use sdk_raw::inputs::MAX_CONTROL_POINTS;
use std::ffi::{CStr, c_int};
#[doc(alias(
"tf_objective_resource",
"CTFObjectiveResource",
"CBaseTeamObjectiveResource"
))]
#[derive(Debug, Clone, Copy)]
pub struct ObjectiveResource<'s>(Objective<'s>);
impl<'s> ObjectiveResource<'s> {
pub fn new(server: Server<'s>, entity: Entity<'s>) -> Result<Self, ObjectiveError> {
Objective::new(
server,
entity,
c"CBaseTeamObjectiveResource",
"tf_objective_resource",
)
.map(Self)
}
pub fn find(server: Server<'s>) -> Result<Option<Self>, ObjectiveError> {
super::find_by_class(server, c"tf_objective_resource", Self::new)
}
#[doc(alias("m_iNumTeamMembers", "GetNumPlayersInArea"))]
pub fn cappers_in_zone(self, point: usize, team: ScoringTeam) -> Result<c_int, ObjectiveError> {
self.0
.element(c"m_iNumTeamMembers", team_index(point, team)?)
}
#[doc(alias("m_iCappingTeam", "GetCappingTeam"))]
pub fn capping_team(self, point: usize) -> Result<Option<ScoringTeam>, ObjectiveError> {
let team = self.0.element(c"m_iCappingTeam", point_index(point)?)?;
Ok(ScoringTeam::from_raw(team))
}
#[doc(alias("m_flCapPercentages", "GetCPCapPercentage"))]
pub fn capture_left(self, point: usize) -> Result<f32, ObjectiveError> {
self.0.float_element(
c"CBaseTeamObjectiveResource",
c"m_flCapPercentages",
point_index(point)?,
)
}
#[doc(alias("m_flTeamCapTime", "GetCPCapTime"))]
pub fn capture_time(self, point: usize, team: ScoringTeam) -> Result<f32, ObjectiveError> {
self.0.element(c"m_flTeamCapTime", team_index(point, team)?)
}
pub fn entity(self) -> Entity<'s> {
self.0.entity()
}
#[doc(alias("m_iCPGroup", "GetCPGroup", "point_group"))]
pub fn group(self, point: usize) -> Result<c_int, ObjectiveError> {
self.0.element(c"m_iCPGroup", point_index(point)?)
}
#[doc(alias("m_iTimerToShowInHUD", "GetTimerToShowInHUD"))]
pub fn hud_timer(self) -> Result<Option<RoundTimer<'s>>, ObjectiveError> {
self.timer(c"m_iTimerToShowInHUD")
}
#[doc(alias("m_bBlocked", "CapIsBlocked"))]
pub fn is_blocked(self, point: usize) -> Result<bool, ObjectiveError> {
self.0.flag_element(c"m_bBlocked", point_index(point)?)
}
#[doc(alias("m_bInMiniRound", "IsInMiniRound"))]
pub fn is_in_mini_round(self, point: usize) -> Result<bool, ObjectiveError> {
self.0.flag_element(c"m_bInMiniRound", point_index(point)?)
}
#[doc(alias("m_bCPLocked", "GetCPLocked"))]
pub fn is_locked(self, point: usize) -> Result<bool, ObjectiveError> {
self.0.flag_element(c"m_bCPLocked", point_index(point)?)
}
#[doc(alias("m_bCPIsVisible", "IsCPVisible"))]
pub fn is_visible(self, point: usize) -> Result<bool, ObjectiveError> {
self.0.flag_element(c"m_bCPIsVisible", point_index(point)?)
}
#[doc(alias("m_flLazyCapPerc"))]
pub fn lazy_capture_left(self, point: usize) -> Result<f32, ObjectiveError> {
self.0.element(c"m_flLazyCapPerc", point_index(point)?)
}
#[doc(alias("m_iOwner", "GetOwningTeam"))]
pub fn owner(self, point: usize) -> Result<Option<ScoringTeam>, ObjectiveError> {
let team = self.0.element(c"m_iOwner", point_index(point)?)?;
Ok(ScoringTeam::from_raw(team))
}
#[doc(alias("m_flPathDistance", "GetPathDistance"))]
pub fn path_distance(self, point: usize) -> Result<f32, ObjectiveError> {
self.0.element(c"m_flPathDistance", point_index(point)?)
}
#[doc(alias("m_bPlayingMiniRounds", "PlayingMiniRounds"))]
pub fn plays_mini_rounds(self) -> Result<bool, ObjectiveError> {
self.0.flag(c"m_bPlayingMiniRounds")
}
#[doc(alias("m_iNumControlPoints", "GetNumControlPoints"))]
pub fn point_count(self) -> Result<usize, ObjectiveError> {
let count: c_int = self.0.get(c"m_iNumControlPoints")?;
Ok(usize::try_from(count.clamp(0, MAX_CONTROL_POINTS)).unwrap_or(0))
}
#[doc(alias("m_vCPPositions", "GetCPPosition"))]
pub fn position(self, point: usize) -> Result<Vector, ObjectiveError> {
self.0.element(c"m_vCPPositions", point_index(point)?)
}
#[doc(alias("m_iTeamReqCappers", "GetRequiredCappers"))]
pub fn required_cappers(
self,
point: usize,
team: ScoringTeam,
) -> Result<c_int, ObjectiveError> {
self.0
.element(c"m_iTeamReqCappers", team_index(point, team)?)
}
#[doc(alias("m_iStopWatchTimer", "GetStopWatchTimer"))]
pub fn stopwatch_timer(self) -> Result<Option<RoundTimer<'s>>, ObjectiveError> {
self.timer(c"m_iStopWatchTimer")
}
#[doc(alias("m_bTeamCanCap", "TeamCanCapPoint"))]
pub fn team_can_capture(self, point: usize, team: ScoringTeam) -> Result<bool, ObjectiveError> {
self.0
.flag_element(c"m_bTeamCanCap", team_index(point, team)?)
}
#[doc(alias("m_iTeamInZone", "GetTeamInZone"))]
pub fn team_in_zone(self, point: usize) -> Result<Option<ScoringTeam>, ObjectiveError> {
let team = self.0.element(c"m_iTeamInZone", point_index(point)?)?;
Ok(ScoringTeam::from_raw(team))
}
fn timer(self, name: &CStr) -> Result<Option<RoundTimer<'s>>, ObjectiveError> {
let index: c_int = self.0.get(name)?;
if index <= 0 {
return Ok(None);
}
let server = self.0.server();
Ok(server
.server_tools()?
.entity_by_index(index)
.and_then(|entity| RoundTimer::new(server, entity).ok()))
}
#[doc(alias("m_flCPTimerTimes", "GetCPTimerTime"))]
pub fn timer_end(self, point: usize) -> Result<f32, ObjectiveError> {
self.0.element(c"m_flCPTimerTimes", point_index(point)?)
}
#[doc(alias("m_flUnlockTimes", "GetCPUnlockTime"))]
pub fn unlock_time(self, point: usize) -> Result<f32, ObjectiveError> {
self.0.element(c"m_flUnlockTimes", point_index(point)?)
}
}
fn point_index(point: usize) -> Result<usize, ObjectiveError> {
if point < MAX_CONTROL_POINTS as usize {
Ok(point)
} else {
Err(ObjectiveError::PointOutOfRange { index: point })
}
}
fn team_index(point: usize, team: ScoringTeam) -> Result<usize, ObjectiveError> {
let team = usize::try_from(team.to_raw()).expect("TF2's teams are positive");
Ok(point_index(point)? + team * MAX_CONTROL_POINTS as usize)
}