use std::collections::HashMap;
use std::ops::Index;
use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
use crate::devs::Developer;
use crate::roletypes::{RoleType, Team};
use crate::locales::Language;
#[pyclass(frozen)]
#[derive(Clone, PartialEq, Debug)]
pub struct Role {
_id: usize,
pub name: String,
role_type: Option<RoleType>,
localized_name: HashMap<Language, String>,
original_author: Developer,
current_author: Developer,
available: bool
}
impl Role {
pub fn new(
id: usize,
role_name: &str,
role_type: Option<RoleType>,
local_names: HashMap<Language, String>,
orig_author: Developer,
current_author: Option<Developer>,
available: bool
) -> Self{
Role{
_id: id,
name: role_name.to_string(),
role_type,
localized_name: local_names,
original_author: orig_author,
current_author: if current_author.is_none() {orig_author} else {current_author.unwrap()},
available: available
}
}
pub fn get_index(&self) -> usize {
return self._id
}
pub fn get_team(&self) -> Team {
if self.name != "Random" {
return self.role_type.unwrap().get_team().clone();
} else {
panic!("Random does not have a team");
}
}
pub fn get_role_type(&self) -> Option<RoleType> {
return self.role_type
}
pub fn get_name(&self, locale: Language) -> String {
return self.localized_name[&locale].clone();
}
pub fn get_english_name(&self) -> String {
return self.localized_name[&Language::English].clone();
}
pub fn get_original_author(&self) -> Developer {
return self.original_author;
}
pub fn get_current_author(&self) -> Developer {
return self.current_author;
}
pub fn is_available(&self) -> bool {
return self.available;
}
}
macro_rules! define_roles {
($($key:ident => $id:expr),* $(,)?) => {
#[pyclass(frozen)]
#[derive(Clone)]
pub struct Roles {
$(#[pyo3(get)]
pub $key: Role,)*
_roles: HashMap<String, Role>,
_raw_list: Vec<Role>
}
impl Roles {
pub fn new() -> Self {
let mut map = HashMap::new();
let mut list = Vec::new();
$(
let role = $id;
map.insert(stringify!($key).to_string(), role.clone());
list.push(role);
)*
Self { $($key: map[stringify!($key)].clone(),)* _roles: map, _raw_list: list }
}
pub fn from_index(&self, index: usize) -> &Role{
&self._raw_list[index]
}
}
#[pymethods]
impl Roles {
#[new]
pub fn py_new() -> Self {
Roles::new()
}
fn __iter__(slf: PyRef<Self>) -> PyRolesIter {
PyRolesIter {
inner: slf.clone().into_iter(),
}
}
}
}
}
define_roles!(
Kerrigan => Role::new(0, "Kerrigan", Some(RoleType::Hunter), HashMap::from([(Language::English, "Kerrigan".to_string())]), Developer::Geo, Some(Developer::Luminous), true),
Scientist => Role::new(1, "Scientist", Some(RoleType::Builder), HashMap::from([(Language::English, "Scientist".to_string())]), Developer::Geo, Some(Developer::Luminous), true),
Dark_Templar => Role::new(2, "Dark_Templar", Some(RoleType::Builder), HashMap::from([(Language::English, "Dark Templar".to_string())]), Developer::Geo, Some(Developer::Luminous), true),
Ascendant => Role::new(3, "Ascendant", Some(RoleType::Builder), HashMap::from([(Language::English, "Ascendant".to_string())]), Developer::Luminous, None, true),
Spirit => Role::new(4, "Spirit", Some(RoleType::Builder), HashMap::from([(Language::English, "Spirit".to_string())]), Developer::Luminous, None, true),
Ares => Role::new(5, "Ares", Some(RoleType::Builder), HashMap::from([(Language::English, "Ares".to_string())]), Developer::Luminous, None, true),
Prophet => Role::new(6, "Prophet", Some(RoleType::Support), HashMap::from([(Language::English, "Prophet".to_string())]), Developer::Luminous, None, true),
Stukov => Role::new(7, "Stukov", Some(RoleType::Builder), HashMap::from([(Language::English, "Stukov".to_string())]), Developer::Luminous, None, true),
Artanis => Role::new(8, "Artanis", Some(RoleType::Builder), HashMap::from([(Language::English, "Artanis".to_string())]), Developer::Luminous, None, true),
Zagara => Role::new(9, "Zagara", Some(RoleType::Defender), HashMap::from([(Language::English, "Zagara".to_string())]), Developer::Luminous, None, true),
Engineer => Role::new(10, "Engineer", Some(RoleType::Builder), HashMap::from([(Language::English, "Engineer".to_string())]), Developer::Luminous, None, true),
Team_Nova => Role::new(11, "Team_Nova", Some(RoleType::Support), HashMap::from([(Language::English, "Team Nova".to_string())]), Developer::Luminous, None, true),
Nomad => Role::new(12, "Nomad", Some(RoleType::Builder), HashMap::from([(Language::English, "Nomad".to_string())]), Developer::Luminous, None, true),
Dehaka => Role::new(13, "Dehaka", Some(RoleType::Hunter), HashMap::from([(Language::English, "Dehaka".to_string())]), Developer::Luminous, None, true),
Helios => Role::new(14, "Helios", Some(RoleType::Builder), HashMap::from([(Language::English, "Helios".to_string())]), Developer::Luminous, None, true),
Random => Role::new(15, "Random", None, HashMap::from([(Language::English, "Random".to_string())]), Developer::Luminous, None, true),
Thakras => Role::new(16, "Thakras", Some(RoleType::Hunter), HashMap::from([(Language::English, "Thakras".to_string())]), Developer::Luminous, None, true),
Swann => Role::new(17, "Swann", Some(RoleType::Builder), HashMap::from([(Language::English, "Swann".to_string())]), Developer::Luminous, None, true),
Warden => Role::new(18, "Warden", Some(RoleType::Support), HashMap::from([(Language::English, "Warden".to_string())]), Developer::Luminous, None, true),
Selendis => Role::new(19, "Selendis", Some(RoleType::Builder), HashMap::from([(Language::English, "Selendis".to_string())]), Developer::Hex, None, true),
Niadra => Role::new(20, "Niadra", Some(RoleType::Defender), HashMap::from([(Language::English, "Niadra".to_string())]), Developer::Luminous, None, true),
Mira => Role::new(21, "Mira", Some(RoleType::Builder), HashMap::from([(Language::English, "Mira".to_string())]), Developer::Luminous, None, true),
Scion => Role::new(22, "Scion", Some(RoleType::Support), HashMap::from([(Language::English, "Scion".to_string())]), Developer::Luminous, None, true),
Technician => Role::new(23, "Technician", Some(RoleType::Builder), HashMap::from([(Language::English, "Technician".to_string())]), Developer::Fatline, Some(Developer::Gcloud), true),
Warfield => Role::new(24, "Warfield", Some(RoleType::Builder), HashMap::from([(Language::English, "Warfield".to_string())]), Developer::Fatline, Some(Developer::Understudy), true),
Champion => Role::new(25, "Champion", Some(RoleType::Builder), HashMap::from([(Language::English, "Champion".to_string())]), Developer::Luminous, None, true),
Elementalist => Role::new(26, "Elementalist", Some(RoleType::Support), HashMap::from([(Language::English, "Elementalist".to_string())]), Developer::Fatline, Some(Developer::Sox), true),
Brakk => Role::new(27, "Brakk", Some(RoleType::Hunter), HashMap::from([(Language::English, "Brakk".to_string())]), Developer::Fatline, Some(Developer::Gcloud), true),
Glevig => Role::new(28, "Glevig", Some(RoleType::Defender), HashMap::from([(Language::English, "Glevig".to_string())]), Developer::Fatline, Some(Developer::Understudy), true),
Delta_Squad => Role::new(29, "Delta_Squad", Some(RoleType::Support), HashMap::from([(Language::English, "Delta Squad".to_string())]), Developer::Luminous, None, true),
Phaegore => Role::new(30, "Phaegore", Some(RoleType::Defender), HashMap::from([(Language::English, "Phaegore".to_string())]), Developer::Templar, Some(Developer::Andrene), true),
Alarak => Role::new(31, "Alarak", Some(RoleType::Builder), HashMap::from([(Language::English, "Alarak".to_string())]), Developer::Luminous, None, true),
Izsha => Role::new(32, "Izsha", Some(RoleType::Defender), HashMap::from([(Language::English, "Izsha".to_string())]), Developer::Susu, None, true),
Malus => Role::new(33, "Malus", Some(RoleType::Hunter), HashMap::from([(Language::English, "Malus".to_string())]), Developer::Susu, None, true),
Kraith => Role::new(34, "Kraith", Some(RoleType::Hunter), HashMap::from([(Language::English, "Kraith".to_string())]), Developer::Templar, None, true),
Energizer => Role::new(35, "Energizer", Some(RoleType::Builder), HashMap::from([(Language::English, "Energizer".to_string())]), Developer::Fatline, Some(Developer::Sox), true),
Andor => Role::new(36, "Andor", Some(RoleType::Builder), HashMap::from([(Language::English, "Andor".to_string())]), Developer::Korneel, None, true),
DJ => Role::new(37, "DJ", Some(RoleType::Builder), HashMap::from([(Language::English, "DJ".to_string())]), Developer::Sox, None, true),
Rattlesnake => Role::new(38, "Rattlesnake", Some(RoleType::Support), HashMap::from([(Language::English, "Rattlesnake".to_string())]), Developer::Legacy, Some(Developer::Andrene), true),
SgtHammer => Role::new(39, "SgtHammer", Some(RoleType::Builder), HashMap::from([(Language::English, "SgtHammer".to_string())]), Developer::Archlei, Some(Developer::Hex), true),
Chew => Role::new(40, "Chew", Some(RoleType::Support), HashMap::from([(Language::English, "Chew".to_string())]), Developer::Sox, None, true),
Aewyn => Role::new(41, "Aewyn", Some(RoleType::Builder), HashMap::from([(Language::English, "Aewyn".to_string())]), Developer::Luminous, None, true),
Critter_Lord => Role::new(42, "Critter_Lord", Some(RoleType::Builder), HashMap::from([(Language::English, "Critter Lord".to_string())]), Developer::Korneel, None, true),
Nightingale => Role::new(43, "Nightingale", Some(RoleType::Support), HashMap::from([(Language::English, "Nightingale".to_string())]), Developer::Luminous, None, true),
Sjlerk => Role::new(44, "Sjlerk", Some(RoleType::Support), HashMap::from([(Language::English, "Sjlerk".to_string())]), Developer::Korneel, None, true),
Sophia => Role::new(45, "Sophia", Some(RoleType::Builder), HashMap::from([(Language::English, "Sophia".to_string())]), Developer::Korneel, Some(Developer::TheePotatoLord), true),
Jinara => Role::new(46, "Jinara", Some(RoleType::Builder), HashMap::from([(Language::English, "Jinara".to_string())]), Developer::Fern, None, true),
Sir_Roachington => Role::new(47, "Sir_Roachington", Some(RoleType::Defender), HashMap::from([(Language::English, "Sir Roachington".to_string())]), Developer::TheePotatoLord, None, true),
Raszagal => Role::new(48, "Raszagal", Some(RoleType::Builder), HashMap::from([(Language::English, "Raszagal".to_string())]), Developer::Understudy, None, false),
);
impl Index<&str> for Roles {
type Output = Role;
fn index(&self, index: &str) -> &Self::Output {
&self._roles[index]
}
}
impl IntoIterator for Roles {
type IntoIter = RolesIntoIter;
type Item = Role;
fn into_iter(self) -> Self::IntoIter {
RolesIntoIter {
roles: self,
index: 0
}
}
}
pub struct RolesIntoIter {
roles: Roles,
index: usize
}
impl Iterator for RolesIntoIter {
type Item = Role;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.roles._raw_list.len() {
return None;
}
let res = self.roles._raw_list[self.index].clone();
self.index +=1;
Some(res)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_iter_order() {
let roles = Roles::new();
let roles2 = Roles::new();
let mut i = 0;
for role in roles {
assert!(role == roles2._raw_list[i]);
i += 1;
}
}
#[test]
fn select_role_by_name_validate_order() {
let roles = Roles::new();
let roles2 = Roles::new();
for role in roles {
assert!(&roles2[&role.name] == roles2.from_index(role._id));
}
}
#[test]
fn select_role_direct() {
let roles = Roles::new();
assert!(&roles.Scientist == &roles["Scientist"]);
assert!(&roles.Warfield == &roles["Warfield"]);
}
}
#[pyclass]
struct PyRolesIter {
inner: RolesIntoIter,
}
#[pymethods]
impl PyRolesIter {
fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
slf
}
fn __next__(mut slf: PyRefMut<Self>) -> Option<Role> {
slf.inner.next()
}
}
#[pymethods]
impl Role {
#[pyo3(name = "get_index")]
pub fn py_get_index(&self) -> PyResult<usize> {
Ok(self.get_index())
}
#[pyo3(name = "get_team")]
pub fn py_get_team(&self) -> PyResult<Team> {
if self.name != "Random" {
Ok(self.get_team())
} else {
Err(PyErr::new::<PyTypeError, _>("Role Random does not have a team."))
}
}
#[pyo3(name = "get_role_type")]
pub fn py_get_role_type(&self) -> PyResult<Option<RoleType>> {
Ok(self.get_role_type())
}
#[pyo3(name = "get_name", signature = (language=None))]
pub fn py_get_name(&self, language: Option<Language>) -> PyResult<String> {
match language {
Some(lang) => Ok(self.get_name(lang)),
None => Ok(self.get_english_name()),
}
}
#[pyo3(name = "get_original_author")]
pub fn py_get_original_author(&self) -> PyResult<Developer> {
Ok(self.get_original_author())
}
#[pyo3(name = "get_current_author")]
pub fn py_get_current_author(&self) -> PyResult<Developer> {
Ok(self.get_current_author())
}
#[pyo3(name = "is_available")]
pub fn py_is_available(&self) -> PyResult<bool> {
Ok(self.is_available())
}
}