// @generated by `cargo run -p xtask -- codegen` — do not edit by hand.
// Source of truth: crates/wh40kdc/schemas/bundled.schema.json
// (regenerate that first via `cd tools && npm run bundle:schemas`).
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(
&self,
f: &mut ::std::fmt::Formatter<'_>,
) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(
&self,
f: &mut ::std::fmt::Formatter<'_>,
) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
///Community-authored structured representation of what a game ability does. NOT GW text.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ability DSL Entry",
/// "description": "Community-authored structured representation of what a game ability does. NOT GW text.",
/// "type": "object",
/// "required": [
/// "ability_id",
/// "authored_by",
/// "effect",
/// "game_version",
/// "name",
/// "scope"
/// ],
/// "properties": {
/// "ability_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "ability_type": {
/// "type": "string",
/// "enum": [
/// "core",
/// "faction",
/// "detachment",
/// "unit",
/// "enhancement",
/// "stratagem"
/// ]
/// },
/// "authored_by": {
/// "$ref": "#/$defs/contributor-ref"
/// },
/// "behavior": {
/// "description": "How this ability interacts with the game flow — not a runtime predicate",
/// "type": "string",
/// "enum": [
/// "passive",
/// "activated",
/// "reactive",
/// "aura"
/// ]
/// },
/// "community_notes": {
/// "type": "string"
/// },
/// "detachment_id": {
/// "description": "For detachment/enhancement/stratagem-type abilities, the associated detachment",
/// "oneOf": [
/// {
/// "$ref": "#/$defs/entity-id"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "dispute_notes": {
/// "type": "string"
/// },
/// "disputed": {
/// "default": false,
/// "type": "boolean"
/// },
/// "effect": {
/// "$ref": "#/$defs/effect"
/// },
/// "faction_id": {
/// "description": "For faction-type abilities, the faction this rule belongs to",
/// "oneOf": [
/// {
/// "$ref": "#/$defs/entity-id"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "interactions": {
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "ability_ref",
/// "type"
/// ],
/// "properties": {
/// "ability_ref": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "notes": {
/// "type": "string"
/// },
/// "type": {
/// "type": "string",
/// "enum": [
/// "conflicts-with",
/// "combos-with",
/// "superseded-by",
/// "requires",
/// "replaces"
/// ]
/// }
/// }
/// }
/// },
/// "name": {
/// "type": "string"
/// },
/// "scope": {
/// "$ref": "#/$defs/scope"
/// },
/// "supersedes": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/dataslate-version"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "unit_ids": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// }
/// },
/// "version": {
/// "$ref": "#/$defs/dataslate-version"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Ability {
pub ability_id: EntityId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ability_type: ::std::option::Option<AbilityAbilityType>,
pub authored_by: ContributorRef,
///How this ability interacts with the game flow — not a runtime predicate
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub behavior: ::std::option::Option<AbilityBehavior>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub community_notes: ::std::option::Option<::std::string::String>,
///For detachment/enhancement/stratagem-type abilities, the associated detachment
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub detachment_id: ::std::option::Option<EntityId>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub dispute_notes: ::std::option::Option<::std::string::String>,
#[serde(default)]
pub disputed: bool,
pub effect: Effect,
///For faction-type abilities, the faction this rule belongs to
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub faction_id: ::std::option::Option<EntityId>,
pub game_version: GameVersionRef,
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub interactions: ::std::vec::Vec<AbilityInteractionsItem>,
pub name: ::std::string::String,
pub scope: Scope,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub supersedes: ::std::option::Option<DataslateVersion>,
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub unit_ids: ::std::vec::Vec<EntityId>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub version: ::std::option::Option<DataslateVersion>,
}
///`AbilityAbilityType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "core",
/// "faction",
/// "detachment",
/// "unit",
/// "enhancement",
/// "stratagem"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum AbilityAbilityType {
#[serde(rename = "core")]
Core,
#[serde(rename = "faction")]
Faction,
#[serde(rename = "detachment")]
Detachment,
#[serde(rename = "unit")]
Unit,
#[serde(rename = "enhancement")]
Enhancement,
#[serde(rename = "stratagem")]
Stratagem,
}
impl ::std::fmt::Display for AbilityAbilityType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Core => f.write_str("core"),
Self::Faction => f.write_str("faction"),
Self::Detachment => f.write_str("detachment"),
Self::Unit => f.write_str("unit"),
Self::Enhancement => f.write_str("enhancement"),
Self::Stratagem => f.write_str("stratagem"),
}
}
}
impl ::std::str::FromStr for AbilityAbilityType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"core" => Ok(Self::Core),
"faction" => Ok(Self::Faction),
"detachment" => Ok(Self::Detachment),
"unit" => Ok(Self::Unit),
"enhancement" => Ok(Self::Enhancement),
"stratagem" => Ok(Self::Stratagem),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for AbilityAbilityType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for AbilityAbilityType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for AbilityAbilityType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///How this ability interacts with the game flow — not a runtime predicate
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "How this ability interacts with the game flow — not a runtime predicate",
/// "type": "string",
/// "enum": [
/// "passive",
/// "activated",
/// "reactive",
/// "aura"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum AbilityBehavior {
#[serde(rename = "passive")]
Passive,
#[serde(rename = "activated")]
Activated,
#[serde(rename = "reactive")]
Reactive,
#[serde(rename = "aura")]
Aura,
}
impl ::std::fmt::Display for AbilityBehavior {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Passive => f.write_str("passive"),
Self::Activated => f.write_str("activated"),
Self::Reactive => f.write_str("reactive"),
Self::Aura => f.write_str("aura"),
}
}
}
impl ::std::str::FromStr for AbilityBehavior {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"passive" => Ok(Self::Passive),
"activated" => Ok(Self::Activated),
"reactive" => Ok(Self::Reactive),
"aura" => Ok(Self::Aura),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for AbilityBehavior {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for AbilityBehavior {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for AbilityBehavior {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`AbilityInteractionsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "ability_ref",
/// "type"
/// ],
/// "properties": {
/// "ability_ref": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "notes": {
/// "type": "string"
/// },
/// "type": {
/// "type": "string",
/// "enum": [
/// "conflicts-with",
/// "combos-with",
/// "superseded-by",
/// "requires",
/// "replaces"
/// ]
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct AbilityInteractionsItem {
pub ability_ref: EntityId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub notes: ::std::option::Option<::std::string::String>,
#[serde(rename = "type")]
pub type_: AbilityInteractionsItemType,
}
///`AbilityInteractionsItemType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "conflicts-with",
/// "combos-with",
/// "superseded-by",
/// "requires",
/// "replaces"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum AbilityInteractionsItemType {
#[serde(rename = "conflicts-with")]
ConflictsWith,
#[serde(rename = "combos-with")]
CombosWith,
#[serde(rename = "superseded-by")]
SupersededBy,
#[serde(rename = "requires")]
Requires,
#[serde(rename = "replaces")]
Replaces,
}
impl ::std::fmt::Display for AbilityInteractionsItemType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::ConflictsWith => f.write_str("conflicts-with"),
Self::CombosWith => f.write_str("combos-with"),
Self::SupersededBy => f.write_str("superseded-by"),
Self::Requires => f.write_str("requires"),
Self::Replaces => f.write_str("replaces"),
}
}
}
impl ::std::str::FromStr for AbilityInteractionsItemType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"conflicts-with" => Ok(Self::ConflictsWith),
"combos-with" => Ok(Self::CombosWith),
"superseded-by" => Ok(Self::SupersededBy),
"requires" => Ok(Self::Requires),
"replaces" => Ok(Self::Replaces),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for AbilityInteractionsItemType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for AbilityInteractionsItemType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for AbilityInteractionsItemType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///A draw-time predicate over an army list (not runtime board state, so deliberately NOT the Ability DSL condition). Used to gate when_drawn operations such as redraws. Example: a card that is void unless the opponent fields a large unit (10e 'Cull the Horde' redrew when the opponent had no unit of 14+ models) is { subject: 'opponent', quantifier: 'none', unit_filter: { model_count_min: 14 } } with operation 'redraw'.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A draw-time predicate over an army list (not runtime board state, so deliberately NOT the Ability DSL condition). Used to gate when_drawn operations such as redraws. Example: a card that is void unless the opponent fields a large unit (10e 'Cull the Horde' redrew when the opponent had no unit of 14+ models) is { subject: 'opponent', quantifier: 'none', unit_filter: { model_count_min: 14 } } with operation 'redraw'.",
/// "type": "object",
/// "required": [
/// "quantifier",
/// "subject",
/// "unit_filter"
/// ],
/// "properties": {
/// "quantifier": {
/// "description": "Whether the army must contain ('any') or lack ('none') a unit matching unit_filter for the predicate to hold.",
/// "type": "string",
/// "enum": [
/// "any",
/// "none"
/// ]
/// },
/// "subject": {
/// "description": "Whose army list the predicate inspects.",
/// "type": "string",
/// "enum": [
/// "self",
/// "opponent"
/// ]
/// },
/// "unit_filter": {
/// "description": "Criteria a unit in the army must satisfy to match. All present criteria must hold (logical AND).",
/// "type": "object",
/// "minProperties": 1,
/// "properties": {
/// "keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "model_count_max": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "model_count_min": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "wounds_min": {
/// "type": "integer",
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ArmyCompositionPredicate {
///Whether the army must contain ('any') or lack ('none') a unit matching unit_filter for the predicate to hold.
pub quantifier: ArmyCompositionPredicateQuantifier,
///Whose army list the predicate inspects.
pub subject: ArmyCompositionPredicateSubject,
pub unit_filter: ArmyCompositionPredicateUnitFilter,
}
///Whether the army must contain ('any') or lack ('none') a unit matching unit_filter for the predicate to hold.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Whether the army must contain ('any') or lack ('none') a unit matching unit_filter for the predicate to hold.",
/// "type": "string",
/// "enum": [
/// "any",
/// "none"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum ArmyCompositionPredicateQuantifier {
#[serde(rename = "any")]
Any,
#[serde(rename = "none")]
None,
}
impl ::std::fmt::Display for ArmyCompositionPredicateQuantifier {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Any => f.write_str("any"),
Self::None => f.write_str("none"),
}
}
}
impl ::std::str::FromStr for ArmyCompositionPredicateQuantifier {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"any" => Ok(Self::Any),
"none" => Ok(Self::None),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ArmyCompositionPredicateQuantifier {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String>
for ArmyCompositionPredicateQuantifier {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String>
for ArmyCompositionPredicateQuantifier {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Whose army list the predicate inspects.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Whose army list the predicate inspects.",
/// "type": "string",
/// "enum": [
/// "self",
/// "opponent"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum ArmyCompositionPredicateSubject {
#[serde(rename = "self")]
Self_,
#[serde(rename = "opponent")]
Opponent,
}
impl ::std::fmt::Display for ArmyCompositionPredicateSubject {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Self_ => f.write_str("self"),
Self::Opponent => f.write_str("opponent"),
}
}
}
impl ::std::str::FromStr for ArmyCompositionPredicateSubject {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"self" => Ok(Self::Self_),
"opponent" => Ok(Self::Opponent),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ArmyCompositionPredicateSubject {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String>
for ArmyCompositionPredicateSubject {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ArmyCompositionPredicateSubject {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Criteria a unit in the army must satisfy to match. All present criteria must hold (logical AND).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Criteria a unit in the army must satisfy to match. All present criteria must hold (logical AND).",
/// "type": "object",
/// "minProperties": 1,
/// "properties": {
/// "keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "model_count_max": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "model_count_min": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "wounds_min": {
/// "type": "integer",
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ArmyCompositionPredicateUnitFilter {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub keywords: ::std::option::Option<KeywordList>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub model_count_max: ::std::option::Option<::std::num::NonZeroU64>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub model_count_min: ::std::option::Option<::std::num::NonZeroU64>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub wounds_min: ::std::option::Option<::std::num::NonZeroU64>,
}
impl ::std::default::Default for ArmyCompositionPredicateUnitFilter {
fn default() -> Self {
Self {
keywords: Default::default(),
model_count_max: Default::default(),
model_count_min: Default::default(),
wounds_min: Default::default(),
}
}
}
///11e battle size, which sets the army's points limit and detachment-point budget: 'incursion' = 1000 pts / 2 detachment points; 'strike-force' = 2000 pts / 3 detachment points.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "11e battle size, which sets the army's points limit and detachment-point budget: 'incursion' = 1000 pts / 2 detachment points; 'strike-force' = 2000 pts / 3 detachment points.",
/// "type": "string",
/// "enum": [
/// "incursion",
/// "strike-force"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum BattleSize {
#[serde(rename = "incursion")]
Incursion,
#[serde(rename = "strike-force")]
StrikeForce,
}
impl ::std::fmt::Display for BattleSize {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Incursion => f.write_str("incursion"),
Self::StrikeForce => f.write_str("strike-force"),
}
}
}
impl ::std::str::FromStr for BattleSize {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"incursion" => Ok(Self::Incursion),
"strike-force" => Ok(Self::StrikeForce),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for BattleSize {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for BattleSize {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for BattleSize {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`ChoiceEffect`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "options",
/// "type"
/// ],
/// "properties": {
/// "choice_label": {
/// "type": "string"
/// },
/// "options": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/effect-node"
/// },
/// "minItems": 2
/// },
/// "type": {
/// "const": "choice"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct ChoiceEffect {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub choice_label: ::std::option::Option<::std::string::String>,
pub options: ::std::vec::Vec<EffectNode>,
#[serde(rename = "type")]
pub type_: ::serde_json::Value,
}
///`CompoundCondition`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "operands",
/// "operator"
/// ],
/// "properties": {
/// "operands": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/condition-node"
/// },
/// "minItems": 1
/// },
/// "operator": {
/// "type": "string",
/// "enum": [
/// "and",
/// "or",
/// "not"
/// ]
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct CompoundCondition {
pub operands: ::std::vec::Vec<ConditionNode>,
pub operator: CompoundConditionOperator,
}
///`CompoundConditionOperator`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "and",
/// "or",
/// "not"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum CompoundConditionOperator {
#[serde(rename = "and")]
And,
#[serde(rename = "or")]
Or,
#[serde(rename = "not")]
Not,
}
impl ::std::fmt::Display for CompoundConditionOperator {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::And => f.write_str("and"),
Self::Or => f.write_str("or"),
Self::Not => f.write_str("not"),
}
}
}
impl ::std::str::FromStr for CompoundConditionOperator {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"and" => Ok(Self::And),
"or" => Ok(Self::Or),
"not" => Ok(Self::Not),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for CompoundConditionOperator {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for CompoundConditionOperator {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for CompoundConditionOperator {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`Condition`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ability Condition",
/// "$ref": "#/$defs/condition-node"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(transparent)]
pub struct Condition(pub ConditionNode);
impl ::std::ops::Deref for Condition {
type Target = ConditionNode;
fn deref(&self) -> &ConditionNode {
&self.0
}
}
impl ::std::convert::From<Condition> for ConditionNode {
fn from(value: Condition) -> Self {
value.0
}
}
impl ::std::convert::From<ConditionNode> for Condition {
fn from(value: ConditionNode) -> Self {
Self(value)
}
}
///`ConditionNode`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "oneOf": [
/// {
/// "$ref": "#/$defs/simple-condition"
/// },
/// {
/// "$ref": "#/$defs/compound-condition"
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum ConditionNode {
SimpleCondition(SimpleCondition),
CompoundCondition(CompoundCondition),
}
impl ::std::convert::From<SimpleCondition> for ConditionNode {
fn from(value: SimpleCondition) -> Self {
Self::SimpleCondition(value)
}
}
impl ::std::convert::From<CompoundCondition> for ConditionNode {
fn from(value: CompoundCondition) -> Self {
Self::CompoundCondition(value)
}
}
///`ConditionalEffect`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "condition",
/// "effect",
/// "type"
/// ],
/// "properties": {
/// "condition": {
/// "$ref": "#/$defs/condition"
/// },
/// "effect": {
/// "$ref": "#/$defs/effect-node"
/// },
/// "type": {
/// "const": "conditional"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct ConditionalEffect {
pub condition: Condition,
pub effect: ::std::boxed::Box<EffectNode>,
#[serde(rename = "type")]
pub type_: ::serde_json::Value,
}
///GitHub handle or '40kdc-community'
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "GitHub handle or '40kdc-community'",
/// "type": "string"
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
#[serde(transparent)]
pub struct ContributorRef(pub ::std::string::String);
impl ::std::ops::Deref for ContributorRef {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ContributorRef> for ::std::string::String {
fn from(value: ContributorRef) -> Self {
value.0
}
}
impl ::std::convert::From<::std::string::String> for ContributorRef {
fn from(value: ::std::string::String) -> Self {
Self(value)
}
}
impl ::std::str::FromStr for ContributorRef {
type Err = ::std::convert::Infallible;
fn from_str(value: &str) -> ::std::result::Result<Self, Self::Err> {
Ok(Self(value.to_string()))
}
}
impl ::std::fmt::Display for ContributorRef {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
self.0.fmt(f)
}
}
///Dataslate version: a quarterly tag (e.g. '2025-q3') or a named kebab-case slug for non-quarterly slates (e.g. 'pre-launch-provisional')
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Dataslate version: a quarterly tag (e.g. '2025-q3') or a named kebab-case slug for non-quarterly slates (e.g. 'pre-launch-provisional')",
/// "type": "string",
/// "pattern": "^(\\d{4}-q[1-4]|[a-z0-9][a-z0-9-]*[a-z0-9])$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DataslateVersion(::std::string::String);
impl ::std::ops::Deref for DataslateVersion {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DataslateVersion> for ::std::string::String {
fn from(value: DataslateVersion) -> Self {
value.0
}
}
impl ::std::str::FromStr for DataslateVersion {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(||
{
::regress::Regex::new("^(\\d{4}-q[1-4]|[a-z0-9][a-z0-9-]*[a-z0-9])$")
.unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^(\\d{4}-q[1-4]|[a-z0-9][a-z0-9-]*[a-z0-9])$\""
.into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DataslateVersion {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DataslateVersion {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DataslateVersion {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for DataslateVersion {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A deployment map: per-side deployment zones, objective positions, and (11e) per-side territory polygons. Pattern geometry carries forward unchanged from 10th edition; downstream tooling (e.g. bevy-deploy-helper) consumes this as the canonical encoding.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Deployment Pattern",
/// "description": "A deployment map: per-side deployment zones, objective positions, and (11e) per-side territory polygons. Pattern geometry carries forward unchanged from 10th edition; downstream tooling (e.g. bevy-deploy-helper) consumes this as the canonical encoding.",
/// "type": "object",
/// "required": [
/// "game_version",
/// "id",
/// "name",
/// "zones"
/// ],
/// "properties": {
/// "description": {
/// "type": "string"
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "objectives": {
/// "description": "Objective-marker positions on the board.",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/vec2"
/// }
/// },
/// "recommended_terrain_layout_ids": {
/// "description": "Ids of recommended terrain-layout entities (resolved once terrain-layout data is authored).",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "uniqueItems": true
/// },
/// "source": {
/// "description": "Mission pack or source the pattern originates from (e.g. 'leviathan').",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "territories": {
/// "description": "11e per-side territory polygons, mirroring the deployment-zone shape (e.g. the band between a deployment zone and the midline). Empty until authored.",
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "player",
/// "position",
/// "shape"
/// ],
/// "properties": {
/// "player": {
/// "$ref": "#/$defs/side"
/// },
/// "position": {
/// "$ref": "#/$defs/vec2"
/// },
/// "shape": {
/// "$ref": "#/$defs/zone-shape"
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "zones": {
/// "description": "Per-side deployment zones.",
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "player",
/// "position",
/// "shape"
/// ],
/// "properties": {
/// "color": {
/// "description": "Hex render color for the zone overlay.",
/// "type": "string",
/// "pattern": "^#[0-9a-fA-F]{6}$"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "player": {
/// "$ref": "#/$defs/side"
/// },
/// "position": {
/// "$ref": "#/$defs/vec2"
/// },
/// "shape": {
/// "$ref": "#/$defs/zone-shape"
/// }
/// },
/// "additionalProperties": false
/// },
/// "minItems": 1
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct DeploymentPattern {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub description: ::std::option::Option<::std::string::String>,
pub game_version: GameVersionRef,
pub id: EntityId,
pub name: DeploymentPatternName,
///Objective-marker positions on the board.
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub objectives: ::std::vec::Vec<Vec2>,
///Ids of recommended terrain-layout entities (resolved once terrain-layout data is authored).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub recommended_terrain_layout_ids: ::std::option::Option<Vec<EntityId>>,
///Mission pack or source the pattern originates from (e.g. 'leviathan').
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub source: ::std::option::Option<DeploymentPatternSource>,
///11e per-side territory polygons, mirroring the deployment-zone shape (e.g. the band between a deployment zone and the midline). Empty until authored.
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub territories: ::std::vec::Vec<DeploymentPatternTerritoriesItem>,
///Per-side deployment zones.
pub zones: ::std::vec::Vec<DeploymentPatternZonesItem>,
}
///`DeploymentPatternName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DeploymentPatternName(::std::string::String);
impl ::std::ops::Deref for DeploymentPatternName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DeploymentPatternName> for ::std::string::String {
fn from(value: DeploymentPatternName) -> Self {
value.0
}
}
impl ::std::str::FromStr for DeploymentPatternName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DeploymentPatternName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DeploymentPatternName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DeploymentPatternName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for DeploymentPatternName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Mission pack or source the pattern originates from (e.g. 'leviathan').
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Mission pack or source the pattern originates from (e.g. 'leviathan').",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DeploymentPatternSource(::std::string::String);
impl ::std::ops::Deref for DeploymentPatternSource {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DeploymentPatternSource> for ::std::string::String {
fn from(value: DeploymentPatternSource) -> Self {
value.0
}
}
impl ::std::str::FromStr for DeploymentPatternSource {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DeploymentPatternSource {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DeploymentPatternSource {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DeploymentPatternSource {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for DeploymentPatternSource {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`DeploymentPatternTerritoriesItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "player",
/// "position",
/// "shape"
/// ],
/// "properties": {
/// "player": {
/// "$ref": "#/$defs/side"
/// },
/// "position": {
/// "$ref": "#/$defs/vec2"
/// },
/// "shape": {
/// "$ref": "#/$defs/zone-shape"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct DeploymentPatternTerritoriesItem {
pub player: Side,
pub position: Vec2,
pub shape: ZoneShape,
}
///`DeploymentPatternZonesItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "player",
/// "position",
/// "shape"
/// ],
/// "properties": {
/// "color": {
/// "description": "Hex render color for the zone overlay.",
/// "type": "string",
/// "pattern": "^#[0-9a-fA-F]{6}$"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "player": {
/// "$ref": "#/$defs/side"
/// },
/// "position": {
/// "$ref": "#/$defs/vec2"
/// },
/// "shape": {
/// "$ref": "#/$defs/zone-shape"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct DeploymentPatternZonesItem {
///Hex render color for the zone overlay.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub color: ::std::option::Option<DeploymentPatternZonesItemColor>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub name: ::std::option::Option<DeploymentPatternZonesItemName>,
pub player: Side,
pub position: Vec2,
pub shape: ZoneShape,
}
///Hex render color for the zone overlay.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Hex render color for the zone overlay.",
/// "type": "string",
/// "pattern": "^#[0-9a-fA-F]{6}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DeploymentPatternZonesItemColor(::std::string::String);
impl ::std::ops::Deref for DeploymentPatternZonesItemColor {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DeploymentPatternZonesItemColor> for ::std::string::String {
fn from(value: DeploymentPatternZonesItemColor) -> Self {
value.0
}
}
impl ::std::str::FromStr for DeploymentPatternZonesItemColor {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(||
{ ::regress::Regex::new("^#[0-9a-fA-F]{6}$").unwrap() });
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^#[0-9a-fA-F]{6}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DeploymentPatternZonesItemColor {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String>
for DeploymentPatternZonesItemColor {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DeploymentPatternZonesItemColor {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for DeploymentPatternZonesItemColor {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`DeploymentPatternZonesItemName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DeploymentPatternZonesItemName(::std::string::String);
impl ::std::ops::Deref for DeploymentPatternZonesItemName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DeploymentPatternZonesItemName> for ::std::string::String {
fn from(value: DeploymentPatternZonesItemName) -> Self {
value.0
}
}
impl ::std::str::FromStr for DeploymentPatternZonesItemName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DeploymentPatternZonesItemName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DeploymentPatternZonesItemName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DeploymentPatternZonesItemName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for DeploymentPatternZonesItemName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A detachment option within a faction, providing a detachment rule, enhancements, and stratagems.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Detachment",
/// "description": "A detachment option within a faction, providing a detachment rule, enhancements, and stratagems.",
/// "type": "object",
/// "required": [
/// "faction_id",
/// "game_version",
/// "id",
/// "name"
/// ],
/// "properties": {
/// "detachment_points": {
/// "description": "11e: the detachment-point cost (1–3) charged against the army's detachment-point budget. null when not yet assigned.",
/// "oneOf": [
/// {
/// "type": "integer",
/// "maximum": 3.0,
/// "minimum": 1.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "detachment_rule_id": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/entity-id"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "enhancement_ids": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// }
/// },
/// "faction_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "force_dispositions": {
/// "description": "11e: ids of the Force Disposition entities this detachment grants. Empty until assigned.",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "uniqueItems": true
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "restrictions": {
/// "oneOf": [
/// {
/// "type": "object",
/// "properties": {
/// "excluded_keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "notes": {
/// "type": "string"
/// },
/// "required_keywords": {
/// "$ref": "#/$defs/keyword-list"
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "stratagem_ids": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// }
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Detachment {
///11e: the detachment-point cost (1–3) charged against the army's detachment-point budget. null when not yet assigned.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub detachment_points: ::std::option::Option<::std::num::NonZeroU64>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub detachment_rule_id: ::std::option::Option<EntityId>,
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub enhancement_ids: ::std::vec::Vec<EntityId>,
pub faction_id: EntityId,
///11e: ids of the Force Disposition entities this detachment grants. Empty until assigned.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub force_dispositions: ::std::option::Option<Vec<EntityId>>,
pub game_version: GameVersionRef,
pub id: EntityId,
pub name: DetachmentName,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub restrictions: ::std::option::Option<DetachmentRestrictions>,
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub stratagem_ids: ::std::vec::Vec<EntityId>,
}
///`DetachmentName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DetachmentName(::std::string::String);
impl ::std::ops::Deref for DetachmentName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DetachmentName> for ::std::string::String {
fn from(value: DetachmentName) -> Self {
value.0
}
}
impl ::std::str::FromStr for DetachmentName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DetachmentName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DetachmentName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DetachmentName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for DetachmentName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`DetachmentRestrictions`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "properties": {
/// "excluded_keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "notes": {
/// "type": "string"
/// },
/// "required_keywords": {
/// "$ref": "#/$defs/keyword-list"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct DetachmentRestrictions {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub excluded_keywords: ::std::option::Option<KeywordList>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub notes: ::std::option::Option<::std::string::String>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub required_keywords: ::std::option::Option<KeywordList>,
}
impl ::std::default::Default for DetachmentRestrictions {
fn default() -> Self {
Self {
excluded_keywords: Default::default(),
notes: Default::default(),
required_keywords: Default::default(),
}
}
}
///`DiceGatedEffect`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "dice",
/// "threshold",
/// "type"
/// ],
/// "properties": {
/// "comparison": {
/// "default": "gte",
/// "type": "string",
/// "enum": [
/// "gte",
/// "lte",
/// "gt",
/// "lt",
/// "eq"
/// ]
/// },
/// "dice": {
/// "description": "Dice expression, e.g. 'D6', '2D6'",
/// "type": "string"
/// },
/// "on_fail": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/effect-node"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "on_success": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/effect-node"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "threshold": {
/// "description": "Fixed threshold or model characteristic to compare against",
/// "oneOf": [
/// {
/// "type": "integer"
/// },
/// {
/// "type": "string",
/// "enum": [
/// "leadership",
/// "toughness",
/// "save"
/// ]
/// }
/// ]
/// },
/// "type": {
/// "const": "dice-gated"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct DiceGatedEffect {
#[serde(default = "defaults::dice_gated_effect_comparison")]
pub comparison: DiceGatedEffectComparison,
///Dice expression, e.g. 'D6', '2D6'
pub dice: ::std::string::String,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub on_fail: ::std::option::Option<::std::boxed::Box<EffectNode>>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub on_success: ::std::option::Option<::std::boxed::Box<EffectNode>>,
///Fixed threshold or model characteristic to compare against
pub threshold: DiceGatedEffectThreshold,
#[serde(rename = "type")]
pub type_: ::serde_json::Value,
}
///`DiceGatedEffectComparison`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "default": "gte",
/// "type": "string",
/// "enum": [
/// "gte",
/// "lte",
/// "gt",
/// "lt",
/// "eq"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum DiceGatedEffectComparison {
#[serde(rename = "gte")]
Gte,
#[serde(rename = "lte")]
Lte,
#[serde(rename = "gt")]
Gt,
#[serde(rename = "lt")]
Lt,
#[serde(rename = "eq")]
Eq,
}
impl ::std::fmt::Display for DiceGatedEffectComparison {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Gte => f.write_str("gte"),
Self::Lte => f.write_str("lte"),
Self::Gt => f.write_str("gt"),
Self::Lt => f.write_str("lt"),
Self::Eq => f.write_str("eq"),
}
}
}
impl ::std::str::FromStr for DiceGatedEffectComparison {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"gte" => Ok(Self::Gte),
"lte" => Ok(Self::Lte),
"gt" => Ok(Self::Gt),
"lt" => Ok(Self::Lt),
"eq" => Ok(Self::Eq),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for DiceGatedEffectComparison {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DiceGatedEffectComparison {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DiceGatedEffectComparison {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::default::Default for DiceGatedEffectComparison {
fn default() -> Self {
DiceGatedEffectComparison::Gte
}
}
///Fixed threshold or model characteristic to compare against
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Fixed threshold or model characteristic to compare against",
/// "oneOf": [
/// {
/// "type": "integer"
/// },
/// {
/// "type": "string",
/// "enum": [
/// "leadership",
/// "toughness",
/// "save"
/// ]
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum DiceGatedEffectThreshold {
Integer(i64),
String(DiceGatedEffectThresholdString),
}
impl ::std::str::FromStr for DiceGatedEffectThreshold {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if let Ok(v) = value.parse() {
Ok(Self::Integer(v))
} else if let Ok(v) = value.parse() {
Ok(Self::String(v))
} else {
Err("string conversion failed for all variants".into())
}
}
}
impl ::std::convert::TryFrom<&str> for DiceGatedEffectThreshold {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DiceGatedEffectThreshold {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DiceGatedEffectThreshold {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::fmt::Display for DiceGatedEffectThreshold {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match self {
Self::Integer(x) => x.fmt(f),
Self::String(x) => x.fmt(f),
}
}
}
impl ::std::convert::From<i64> for DiceGatedEffectThreshold {
fn from(value: i64) -> Self {
Self::Integer(value)
}
}
impl ::std::convert::From<DiceGatedEffectThresholdString> for DiceGatedEffectThreshold {
fn from(value: DiceGatedEffectThresholdString) -> Self {
Self::String(value)
}
}
///`DiceGatedEffectThresholdString`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "leadership",
/// "toughness",
/// "save"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum DiceGatedEffectThresholdString {
#[serde(rename = "leadership")]
Leadership,
#[serde(rename = "toughness")]
Toughness,
#[serde(rename = "save")]
Save,
}
impl ::std::fmt::Display for DiceGatedEffectThresholdString {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Leadership => f.write_str("leadership"),
Self::Toughness => f.write_str("toughness"),
Self::Save => f.write_str("save"),
}
}
}
impl ::std::str::FromStr for DiceGatedEffectThresholdString {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"leadership" => Ok(Self::Leadership),
"toughness" => Ok(Self::Toughness),
"save" => Ok(Self::Save),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for DiceGatedEffectThresholdString {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DiceGatedEffectThresholdString {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DiceGatedEffectThresholdString {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`DicePoolAllocationEffect`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "max_activations",
/// "options",
/// "pool",
/// "type"
/// ],
/// "properties": {
/// "max_activations": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "options": {
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "effect",
/// "name",
/// "requirement"
/// ],
/// "properties": {
/// "effect": {
/// "$ref": "#/$defs/effect-node"
/// },
/// "name": {
/// "type": "string"
/// },
/// "requirement": {
/// "type": "object",
/// "required": [
/// "min_value",
/// "type"
/// ],
/// "properties": {
/// "min_value": {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 1.0
/// },
/// "type": {
/// "type": "string",
/// "enum": [
/// "pair",
/// "triple",
/// "single",
/// "run"
/// ]
/// }
/// }
/// }
/// }
/// },
/// "minItems": 1
/// },
/// "pool": {
/// "type": "object",
/// "required": [
/// "count",
/// "die"
/// ],
/// "properties": {
/// "count": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "die": {
/// "type": "string"
/// }
/// }
/// },
/// "type": {
/// "const": "dice-pool-allocation"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct DicePoolAllocationEffect {
pub max_activations: ::std::num::NonZeroU64,
pub options: ::std::vec::Vec<DicePoolAllocationEffectOptionsItem>,
pub pool: DicePoolAllocationEffectPool,
#[serde(rename = "type")]
pub type_: ::serde_json::Value,
}
///`DicePoolAllocationEffectOptionsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "effect",
/// "name",
/// "requirement"
/// ],
/// "properties": {
/// "effect": {
/// "$ref": "#/$defs/effect-node"
/// },
/// "name": {
/// "type": "string"
/// },
/// "requirement": {
/// "type": "object",
/// "required": [
/// "min_value",
/// "type"
/// ],
/// "properties": {
/// "min_value": {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 1.0
/// },
/// "type": {
/// "type": "string",
/// "enum": [
/// "pair",
/// "triple",
/// "single",
/// "run"
/// ]
/// }
/// }
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct DicePoolAllocationEffectOptionsItem {
pub effect: EffectNode,
pub name: ::std::string::String,
pub requirement: DicePoolAllocationEffectOptionsItemRequirement,
}
///`DicePoolAllocationEffectOptionsItemRequirement`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "min_value",
/// "type"
/// ],
/// "properties": {
/// "min_value": {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 1.0
/// },
/// "type": {
/// "type": "string",
/// "enum": [
/// "pair",
/// "triple",
/// "single",
/// "run"
/// ]
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct DicePoolAllocationEffectOptionsItemRequirement {
pub min_value: ::std::num::NonZeroU64,
#[serde(rename = "type")]
pub type_: DicePoolAllocationEffectOptionsItemRequirementType,
}
///`DicePoolAllocationEffectOptionsItemRequirementType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "pair",
/// "triple",
/// "single",
/// "run"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum DicePoolAllocationEffectOptionsItemRequirementType {
#[serde(rename = "pair")]
Pair,
#[serde(rename = "triple")]
Triple,
#[serde(rename = "single")]
Single,
#[serde(rename = "run")]
Run,
}
impl ::std::fmt::Display for DicePoolAllocationEffectOptionsItemRequirementType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Pair => f.write_str("pair"),
Self::Triple => f.write_str("triple"),
Self::Single => f.write_str("single"),
Self::Run => f.write_str("run"),
}
}
}
impl ::std::str::FromStr for DicePoolAllocationEffectOptionsItemRequirementType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"pair" => Ok(Self::Pair),
"triple" => Ok(Self::Triple),
"single" => Ok(Self::Single),
"run" => Ok(Self::Run),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str>
for DicePoolAllocationEffectOptionsItemRequirementType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String>
for DicePoolAllocationEffectOptionsItemRequirementType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String>
for DicePoolAllocationEffectOptionsItemRequirementType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`DicePoolAllocationEffectPool`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "count",
/// "die"
/// ],
/// "properties": {
/// "count": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "die": {
/// "type": "string"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct DicePoolAllocationEffectPool {
pub count: ::std::num::NonZeroU64,
pub die: ::std::string::String,
}
///Game edition, e.g. '10th' or '11'
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Game edition, e.g. '10th' or '11'",
/// "type": "string",
/// "pattern": "^\\d{1,2}(th)?$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct Edition(::std::string::String);
impl ::std::ops::Deref for Edition {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<Edition> for ::std::string::String {
fn from(value: Edition) -> Self {
value.0
}
}
impl ::std::str::FromStr for Edition {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(||
{ ::regress::Regex::new("^\\d{1,2}(th)?$").unwrap() });
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^\\d{1,2}(th)?$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for Edition {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for Edition {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for Edition {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for Edition {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`Effect`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ability Effect",
/// "$ref": "#/$defs/effect-node"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(transparent)]
pub struct Effect(pub EffectNode);
impl ::std::ops::Deref for Effect {
type Target = EffectNode;
fn deref(&self) -> &EffectNode {
&self.0
}
}
impl ::std::convert::From<Effect> for EffectNode {
fn from(value: Effect) -> Self {
value.0
}
}
impl ::std::convert::From<EffectNode> for Effect {
fn from(value: EffectNode) -> Self {
Self(value)
}
}
///`EffectNode`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "oneOf": [
/// {
/// "$ref": "#/$defs/single-effect"
/// },
/// {
/// "$ref": "#/$defs/choice-effect"
/// },
/// {
/// "$ref": "#/$defs/sequence-effect"
/// },
/// {
/// "$ref": "#/$defs/dice-gated-effect"
/// },
/// {
/// "$ref": "#/$defs/conditional-effect"
/// },
/// {
/// "$ref": "#/$defs/dice-pool-allocation-effect"
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum EffectNode {
SingleEffect(SingleEffect),
ChoiceEffect(ChoiceEffect),
SequenceEffect(SequenceEffect),
DiceGatedEffect(DiceGatedEffect),
ConditionalEffect(ConditionalEffect),
DicePoolAllocationEffect(DicePoolAllocationEffect),
}
impl ::std::convert::From<SingleEffect> for EffectNode {
fn from(value: SingleEffect) -> Self {
Self::SingleEffect(value)
}
}
impl ::std::convert::From<ChoiceEffect> for EffectNode {
fn from(value: ChoiceEffect) -> Self {
Self::ChoiceEffect(value)
}
}
impl ::std::convert::From<SequenceEffect> for EffectNode {
fn from(value: SequenceEffect) -> Self {
Self::SequenceEffect(value)
}
}
impl ::std::convert::From<DiceGatedEffect> for EffectNode {
fn from(value: DiceGatedEffect) -> Self {
Self::DiceGatedEffect(value)
}
}
impl ::std::convert::From<ConditionalEffect> for EffectNode {
fn from(value: ConditionalEffect) -> Self {
Self::ConditionalEffect(value)
}
}
impl ::std::convert::From<DicePoolAllocationEffect> for EffectNode {
fn from(value: DicePoolAllocationEffect) -> Self {
Self::DicePoolAllocationEffect(value)
}
}
///A purchasable upgrade for a character unit, provided by a detachment.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Enhancement",
/// "description": "A purchasable upgrade for a character unit, provided by a detachment.",
/// "type": "object",
/// "required": [
/// "cost",
/// "detachment_id",
/// "game_version",
/// "id",
/// "name"
/// ],
/// "properties": {
/// "ability_id": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/entity-id"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "cost": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "detachment_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "exclusion_keywords": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/keyword-list"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "is_unique": {
/// "default": true,
/// "type": "boolean"
/// },
/// "keyword_restrictions": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "max_targets": {
/// "description": "Number of units this enhancement may be applied to. Only meaningful when `upgrade_tag` is true; defaults to 1.",
/// "default": 1,
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "points_provisional": {
/// "description": "True when the cost is carried over provisionally (e.g. seeded from a prior edition during migration) and not yet confirmed against the current dataslate.",
/// "default": false,
/// "type": "boolean"
/// },
/// "upgrade_tag": {
/// "description": "11e: when true, this enhancement applies to up to `max_targets` non-character units while counting as a single Enhancement choice.",
/// "default": false,
/// "type": "boolean"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Enhancement {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ability_id: ::std::option::Option<EntityId>,
pub cost: u64,
pub detachment_id: EntityId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub exclusion_keywords: ::std::option::Option<KeywordList>,
pub game_version: GameVersionRef,
pub id: EntityId,
#[serde(default = "defaults::default_bool::<true>")]
pub is_unique: bool,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub keyword_restrictions: ::std::option::Option<KeywordList>,
///Number of units this enhancement may be applied to. Only meaningful when `upgrade_tag` is true; defaults to 1.
#[serde(default = "defaults::default_nzu64::<::std::num::NonZeroU64, 1>")]
pub max_targets: ::std::num::NonZeroU64,
pub name: EnhancementName,
///True when the cost is carried over provisionally (e.g. seeded from a prior edition during migration) and not yet confirmed against the current dataslate.
#[serde(default)]
pub points_provisional: bool,
///11e: when true, this enhancement applies to up to `max_targets` non-character units while counting as a single Enhancement choice.
#[serde(default)]
pub upgrade_tag: bool,
}
///`EnhancementName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EnhancementName(::std::string::String);
impl ::std::ops::Deref for EnhancementName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EnhancementName> for ::std::string::String {
fn from(value: EnhancementName) -> Self {
value.0
}
}
impl ::std::str::FromStr for EnhancementName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for EnhancementName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for EnhancementName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for EnhancementName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for EnhancementName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Kebab-case identifier
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Kebab-case identifier",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 2,
/// "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EntityId(::std::string::String);
impl ::std::ops::Deref for EntityId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EntityId> for ::std::string::String {
fn from(value: EntityId) -> Self {
value.0
}
}
impl ::std::str::FromStr for EntityId {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 2usize {
return Err("shorter than 2 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(||
{ ::regress::Regex::new("^[a-z0-9][a-z0-9-]*[a-z0-9]$").unwrap() });
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z0-9][a-z0-9-]*[a-z0-9]$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for EntityId {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for EntityId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for EntityId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for EntityId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A playable faction or sub-faction.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Faction",
/// "description": "A playable faction or sub-faction.",
/// "type": "object",
/// "required": [
/// "game_version",
/// "id",
/// "name"
/// ],
/// "properties": {
/// "aliases": {
/// "type": "array",
/// "items": {
/// "type": "string"
/// }
/// },
/// "faction_rule_id": {
/// "description": "Reference to the faction-wide ability (e.g., Oath of Moment)",
/// "oneOf": [
/// {
/// "$ref": "#/$defs/entity-id"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "parent_faction_id": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/entity-id"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Faction {
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub aliases: ::std::vec::Vec<::std::string::String>,
///Reference to the faction-wide ability (e.g., Oath of Moment)
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub faction_rule_id: ::std::option::Option<EntityId>,
pub game_version: GameVersionRef,
pub id: EntityId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub keywords: ::std::option::Option<KeywordList>,
pub name: FactionName,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub parent_faction_id: ::std::option::Option<EntityId>,
}
///`FactionName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct FactionName(::std::string::String);
impl ::std::ops::Deref for FactionName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<FactionName> for ::std::string::String {
fn from(value: FactionName) -> Self {
value.0
}
}
impl ::std::str::FromStr for FactionName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for FactionName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for FactionName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for FactionName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for FactionName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A terrain piece's 2D footprint, relative to the piece's `position`. Axis-aligned rectangle, right triangle (right angle at the local origin, legs along +x/+y), or an explicit polygon. GW's standard templates (e.g. 7"×11.5" rectangles, 8"×11.5" right triangles, 6"×4" rectangles, 10"×2.5" and 6"×2" lines) are all expressible here; lines are thin rectangles.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A terrain piece's 2D footprint, relative to the piece's `position`. Axis-aligned rectangle, right triangle (right angle at the local origin, legs along +x/+y), or an explicit polygon. GW's standard templates (e.g. 7\"×11.5\" rectangles, 8\"×11.5\" right triangles, 6\"×4\" rectangles, 10\"×2.5\" and 6\"×2\" lines) are all expressible here; lines are thin rectangles.",
/// "oneOf": [
/// {
/// "type": "object",
/// "required": [
/// "height",
/// "type",
/// "width"
/// ],
/// "properties": {
/// "height": {
/// "type": "number",
/// "exclusiveMinimum": 0.0
/// },
/// "type": {
/// "const": "rectangle"
/// },
/// "width": {
/// "type": "number",
/// "exclusiveMinimum": 0.0
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "object",
/// "required": [
/// "height",
/// "type",
/// "width"
/// ],
/// "properties": {
/// "height": {
/// "type": "number",
/// "exclusiveMinimum": 0.0
/// },
/// "type": {
/// "const": "right-triangle"
/// },
/// "width": {
/// "type": "number",
/// "exclusiveMinimum": 0.0
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "object",
/// "required": [
/// "points",
/// "type"
/// ],
/// "properties": {
/// "points": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/vec2"
/// },
/// "minItems": 3
/// },
/// "type": {
/// "const": "polygon"
/// }
/// },
/// "additionalProperties": false
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(tag = "type", deny_unknown_fields)]
pub enum Footprint {
#[serde(rename = "rectangle")]
Rectangle { height: f64, width: f64 },
#[serde(rename = "right-triangle")]
RightTriangle { height: f64, width: f64 },
#[serde(rename = "polygon")]
Polygon { points: ::std::vec::Vec<Vec2> },
}
///A 11e strategic-intent tag granted by detachments. Players compare dispositions at game start to determine the shared mission; asymmetric primary objectives result.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Force Disposition",
/// "description": "A 11e strategic-intent tag granted by detachments. Players compare dispositions at game start to determine the shared mission; asymmetric primary objectives result.",
/// "type": "object",
/// "required": [
/// "game_version",
/// "id",
/// "name"
/// ],
/// "properties": {
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "description": "One of the five confirmed launch Force Dispositions.",
/// "$ref": "#/$defs/force-disposition-id"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "text": {
/// "description": "Community-authored description of the disposition's effect (original prose only — no reproduced rules text).",
/// "type": "string",
/// "minLength": 1
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ForceDisposition {
pub game_version: GameVersionRef,
///One of the five confirmed launch Force Dispositions.
pub id: ForceDispositionId,
pub name: ForceDispositionName,
///Community-authored description of the disposition's effect (original prose only — no reproduced rules text).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub text: ::std::option::Option<ForceDispositionText>,
}
///One of the five confirmed 11e launch Force Dispositions. Shared by force-disposition entities and the mission-matchup matrix.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "One of the five confirmed 11e launch Force Dispositions. Shared by force-disposition entities and the mission-matchup matrix.",
/// "type": "string",
/// "enum": [
/// "take-and-hold",
/// "disruption",
/// "purge-the-foe",
/// "priority-assets",
/// "reconnaissance"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum ForceDispositionId {
#[serde(rename = "take-and-hold")]
TakeAndHold,
#[serde(rename = "disruption")]
Disruption,
#[serde(rename = "purge-the-foe")]
PurgeTheFoe,
#[serde(rename = "priority-assets")]
PriorityAssets,
#[serde(rename = "reconnaissance")]
Reconnaissance,
}
impl ::std::fmt::Display for ForceDispositionId {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::TakeAndHold => f.write_str("take-and-hold"),
Self::Disruption => f.write_str("disruption"),
Self::PurgeTheFoe => f.write_str("purge-the-foe"),
Self::PriorityAssets => f.write_str("priority-assets"),
Self::Reconnaissance => f.write_str("reconnaissance"),
}
}
}
impl ::std::str::FromStr for ForceDispositionId {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"take-and-hold" => Ok(Self::TakeAndHold),
"disruption" => Ok(Self::Disruption),
"purge-the-foe" => Ok(Self::PurgeTheFoe),
"priority-assets" => Ok(Self::PriorityAssets),
"reconnaissance" => Ok(Self::Reconnaissance),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ForceDispositionId {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ForceDispositionId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ForceDispositionId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`ForceDispositionName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ForceDispositionName(::std::string::String);
impl ::std::ops::Deref for ForceDispositionName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ForceDispositionName> for ::std::string::String {
fn from(value: ForceDispositionName) -> Self {
value.0
}
}
impl ::std::str::FromStr for ForceDispositionName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ForceDispositionName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ForceDispositionName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ForceDispositionName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ForceDispositionName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Community-authored description of the disposition's effect (original prose only — no reproduced rules text).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Community-authored description of the disposition's effect (original prose only — no reproduced rules text).",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ForceDispositionText(::std::string::String);
impl ::std::ops::Deref for ForceDispositionText {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ForceDispositionText> for ::std::string::String {
fn from(value: ForceDispositionText) -> Self {
value.0
}
}
impl ::std::str::FromStr for ForceDispositionText {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ForceDispositionText {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ForceDispositionText {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ForceDispositionText {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ForceDispositionText {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`GameVersion`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Game Version",
/// "type": "object",
/// "required": [
/// "dataslate",
/// "edition",
/// "effective_date"
/// ],
/// "properties": {
/// "dataslate": {
/// "$ref": "#/$defs/dataslate-version"
/// },
/// "edition": {
/// "$ref": "#/$defs/edition"
/// },
/// "effective_date": {
/// "type": "string",
/// "format": "date"
/// },
/// "label": {
/// "type": "string"
/// },
/// "supersedes": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/dataslate-version"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct GameVersion {
pub dataslate: DataslateVersion,
pub edition: Edition,
pub effective_date: ::chrono::naive::NaiveDate,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub label: ::std::option::Option<::std::string::String>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub supersedes: ::std::option::Option<DataslateVersion>,
}
///`GameVersionRef`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Game Version Reference",
/// "type": "object",
/// "required": [
/// "dataslate",
/// "edition"
/// ],
/// "properties": {
/// "dataslate": {
/// "$ref": "#/$defs/dataslate-version"
/// },
/// "edition": {
/// "$ref": "#/$defs/edition"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct GameVersionRef {
pub dataslate: DataslateVersion,
pub edition: Edition,
}
///`InteractionFlag`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Interaction Flag",
/// "type": "object",
/// "required": [
/// "ability_a",
/// "ability_b",
/// "game_version",
/// "interaction_type"
/// ],
/// "properties": {
/// "ability_a": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "ability_b": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "authored_by": {
/// "$ref": "#/$defs/contributor-ref"
/// },
/// "disputed": {
/// "default": false,
/// "type": "boolean"
/// },
/// "faq_reference": {
/// "type": "string"
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "interaction_type": {
/// "type": "string",
/// "enum": [
/// "conflicts",
/// "combos",
/// "sequencing-dependent",
/// "stacks",
/// "does-not-stack",
/// "replaces"
/// ]
/// },
/// "resolution": {
/// "type": "string"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct InteractionFlag {
pub ability_a: EntityId,
pub ability_b: EntityId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub authored_by: ::std::option::Option<ContributorRef>,
#[serde(default)]
pub disputed: bool,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub faq_reference: ::std::option::Option<::std::string::String>,
pub game_version: GameVersionRef,
pub interaction_type: InteractionFlagInteractionType,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub resolution: ::std::option::Option<::std::string::String>,
}
///`InteractionFlagInteractionType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "conflicts",
/// "combos",
/// "sequencing-dependent",
/// "stacks",
/// "does-not-stack",
/// "replaces"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum InteractionFlagInteractionType {
#[serde(rename = "conflicts")]
Conflicts,
#[serde(rename = "combos")]
Combos,
#[serde(rename = "sequencing-dependent")]
SequencingDependent,
#[serde(rename = "stacks")]
Stacks,
#[serde(rename = "does-not-stack")]
DoesNotStack,
#[serde(rename = "replaces")]
Replaces,
}
impl ::std::fmt::Display for InteractionFlagInteractionType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Conflicts => f.write_str("conflicts"),
Self::Combos => f.write_str("combos"),
Self::SequencingDependent => f.write_str("sequencing-dependent"),
Self::Stacks => f.write_str("stacks"),
Self::DoesNotStack => f.write_str("does-not-stack"),
Self::Replaces => f.write_str("replaces"),
}
}
}
impl ::std::str::FromStr for InteractionFlagInteractionType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"conflicts" => Ok(Self::Conflicts),
"combos" => Ok(Self::Combos),
"sequencing-dependent" => Ok(Self::SequencingDependent),
"stacks" => Ok(Self::Stacks),
"does-not-stack" => Ok(Self::DoesNotStack),
"replaces" => Ok(Self::Replaces),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for InteractionFlagInteractionType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for InteractionFlagInteractionType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for InteractionFlagInteractionType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`Keyword`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct Keyword(::std::string::String);
impl ::std::ops::Deref for Keyword {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<Keyword> for ::std::string::String {
fn from(value: Keyword) -> Self {
value.0
}
}
impl ::std::str::FromStr for Keyword {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for Keyword {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for Keyword {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for Keyword {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for Keyword {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`KeywordList`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/keyword"
/// },
/// "uniqueItems": true
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(transparent)]
pub struct KeywordList(pub Vec<Keyword>);
impl ::std::ops::Deref for KeywordList {
type Target = Vec<Keyword>;
fn deref(&self) -> &Vec<Keyword> {
&self.0
}
}
impl ::std::convert::From<KeywordList> for Vec<Keyword> {
fn from(value: KeywordList) -> Self {
value.0
}
}
impl ::std::convert::From<Vec<Keyword>> for KeywordList {
fn from(value: Vec<Keyword>) -> Self {
Self(value)
}
}
///Defines which character units can attach to which bodyguard units.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Leader Attachment",
/// "description": "Defines which character units can attach to which bodyguard units.",
/// "type": "object",
/// "required": [
/// "eligible_bodyguard_ids",
/// "game_version",
/// "leader_id"
/// ],
/// "properties": {
/// "eligible_bodyguard_ids": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "minItems": 1
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "leader_id": {
/// "$ref": "#/$defs/entity-id"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct LeaderAttachment {
pub eligible_bodyguard_ids: ::std::vec::Vec<EntityId>,
pub game_version: GameVersionRef,
pub leader_id: EntityId,
}
///An 11e primary mission (the objective a player scores). Which mission a player plays is selected by the Force Disposition matchup matrix (see mission-matchup), keyed on the player's own disposition and their opponent's. Victory points are capped per game and per battle round.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Mission",
/// "description": "An 11e primary mission (the objective a player scores). Which mission a player plays is selected by the Force Disposition matchup matrix (see mission-matchup), keyed on the player's own disposition and their opponent's. Victory points are capped per game and per battle round.",
/// "type": "object",
/// "required": [
/// "game_version",
/// "id",
/// "name"
/// ],
/// "properties": {
/// "deployment_pattern_ids": {
/// "description": "Ids of the deployment-pattern entities (maps) this mission can be played on. Empty until the per-mission maps are confirmed.",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "uniqueItems": true
/// },
/// "description": {
/// "description": "Community-authored mission/objective summary (original prose only — no reproduced rules text).",
/// "type": "string"
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "source": {
/// "description": "Mission pack or source the mission originates from.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "vp_per_game_cap": {
/// "description": "Maximum primary VP scorable across the whole game. 11e default is 45.",
/// "default": 45,
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "vp_per_round_cap": {
/// "description": "Maximum primary VP scorable in a single battle round. 11e default is 15.",
/// "default": 15,
/// "type": "integer",
/// "minimum": 0.0
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Mission {
///Ids of the deployment-pattern entities (maps) this mission can be played on. Empty until the per-mission maps are confirmed.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub deployment_pattern_ids: ::std::option::Option<Vec<EntityId>>,
///Community-authored mission/objective summary (original prose only — no reproduced rules text).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub description: ::std::option::Option<::std::string::String>,
pub game_version: GameVersionRef,
pub id: EntityId,
pub name: MissionName,
///Mission pack or source the mission originates from.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub source: ::std::option::Option<MissionSource>,
///Maximum primary VP scorable across the whole game. 11e default is 45.
#[serde(default = "defaults::default_u64::<u64, 45>")]
pub vp_per_game_cap: u64,
///Maximum primary VP scorable in a single battle round. 11e default is 15.
#[serde(default = "defaults::default_u64::<u64, 15>")]
pub vp_per_round_cap: u64,
}
///One cell of the 11e Force Disposition matrix: given the player's own Force Disposition and their opponent's, the mission that player plays. Mirrors a single row on a physical Force Disposition card. The (disposition, opponent_disposition) pair is the conceptual key; compound uniqueness across entries is a data convention, not enforced by this schema.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Mission Matchup",
/// "description": "One cell of the 11e Force Disposition matrix: given the player's own Force Disposition and their opponent's, the mission that player plays. Mirrors a single row on a physical Force Disposition card. The (disposition, opponent_disposition) pair is the conceptual key; compound uniqueness across entries is a data convention, not enforced by this schema.",
/// "type": "object",
/// "required": [
/// "disposition",
/// "game_version",
/// "id",
/// "mission_id",
/// "opponent_disposition"
/// ],
/// "properties": {
/// "disposition": {
/// "description": "The player's own Force Disposition.",
/// "$ref": "#/$defs/force-disposition-id"
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "mission_id": {
/// "description": "Id of the mission entity the player plays for this disposition pairing.",
/// "$ref": "#/$defs/entity-id"
/// },
/// "opponent_disposition": {
/// "description": "The opponent's Force Disposition.",
/// "$ref": "#/$defs/force-disposition-id"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct MissionMatchup {
///The player's own Force Disposition.
pub disposition: ForceDispositionId,
pub game_version: GameVersionRef,
pub id: EntityId,
///Id of the mission entity the player plays for this disposition pairing.
pub mission_id: EntityId,
///The opponent's Force Disposition.
pub opponent_disposition: ForceDispositionId,
}
///`MissionName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct MissionName(::std::string::String);
impl ::std::ops::Deref for MissionName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<MissionName> for ::std::string::String {
fn from(value: MissionName) -> Self {
value.0
}
}
impl ::std::str::FromStr for MissionName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for MissionName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for MissionName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for MissionName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for MissionName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Mission pack or source the mission originates from.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Mission pack or source the mission originates from.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct MissionSource(::std::string::String);
impl ::std::ops::Deref for MissionSource {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<MissionSource> for ::std::string::String {
fn from(value: MissionSource) -> Self {
value.0
}
}
impl ::std::str::FromStr for MissionSource {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for MissionSource {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for MissionSource {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for MissionSource {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for MissionSource {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The five official game phases. Unchanged between 10th and 11th edition — 11e reorders Pile In timing within the Fight phase but adds no top-level phase.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The five official game phases. Unchanged between 10th and 11th edition — 11e reorders Pile In timing within the Fight phase but adds no top-level phase.",
/// "type": "string",
/// "enum": [
/// "command",
/// "movement",
/// "shooting",
/// "charge",
/// "fight"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum Phase {
#[serde(rename = "command")]
Command,
#[serde(rename = "movement")]
Movement,
#[serde(rename = "shooting")]
Shooting,
#[serde(rename = "charge")]
Charge,
#[serde(rename = "fight")]
Fight,
}
impl ::std::fmt::Display for Phase {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Command => f.write_str("command"),
Self::Movement => f.write_str("movement"),
Self::Shooting => f.write_str("shooting"),
Self::Charge => f.write_str("charge"),
Self::Fight => f.write_str("fight"),
}
}
}
impl ::std::str::FromStr for Phase {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"command" => Ok(Self::Command),
"movement" => Ok(Self::Movement),
"shooting" => Ok(Self::Shooting),
"charge" => Ok(Self::Charge),
"fight" => Ok(Self::Fight),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for Phase {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for Phase {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for Phase {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`PhaseList`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/phase"
/// },
/// "minItems": 1,
/// "uniqueItems": true
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(transparent)]
pub struct PhaseList(pub Vec<Phase>);
impl ::std::ops::Deref for PhaseList {
type Target = Vec<Phase>;
fn deref(&self) -> &Vec<Phase> {
&self.0
}
}
impl ::std::convert::From<PhaseList> for Vec<Phase> {
fn from(value: PhaseList) -> Self {
value.0
}
}
impl ::std::convert::From<Vec<Phase>> for PhaseList {
fn from(value: Vec<Phase>) -> Self {
Self(value)
}
}
///`PhaseMapping`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Phase Mapping",
/// "type": "object",
/// "required": [
/// "game_version",
/// "phases",
/// "source_id",
/// "source_type"
/// ],
/// "properties": {
/// "authored_by": {
/// "$ref": "#/$defs/contributor-ref"
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "phases": {
/// "$ref": "#/$defs/phase-list"
/// },
/// "source_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "source_type": {
/// "$ref": "#/$defs/source-type"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct PhaseMapping {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub authored_by: ::std::option::Option<ContributorRef>,
pub game_version: GameVersionRef,
pub phases: PhaseList,
pub source_id: EntityId,
pub source_type: SourceType,
}
///One terrain feature placed on the board.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "One terrain feature placed on the board.",
/// "type": "object",
/// "required": [
/// "footprint",
/// "position"
/// ],
/// "properties": {
/// "footprint": {
/// "$ref": "#/$defs/footprint"
/// },
/// "height_inches": {
/// "description": "Height of the piece in inches. Gates Plunging Fire (a piece 3\" or taller confers +1 BS on ground-level targets).",
/// "type": "number",
/// "minimum": 0.0
/// },
/// "is_objective": {
/// "description": "Whether this piece carries an objective marker.",
/// "default": false,
/// "type": "boolean"
/// },
/// "link_group": {
/// "description": "Pieces sharing a `link_group` value are linked terrain — treated as a single terrain feature (and, where an objective sits among them, a single objective).",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "objective": {
/// "description": "Objective-marker metadata. Only meaningful when `is_objective` is true.",
/// "type": "object",
/// "properties": {
/// "control_range_inches": {
/// "description": "Range from the marker within which models contribute to control.",
/// "type": "number",
/// "exclusiveMinimum": 0.0
/// },
/// "position": {
/// "description": "Board-inch position of the marker. Absent means the piece's `position`.",
/// "$ref": "#/$defs/vec2"
/// }
/// },
/// "additionalProperties": false
/// },
/// "position": {
/// "description": "Board-inch placement of the footprint's local origin.",
/// "$ref": "#/$defs/vec2"
/// },
/// "rotation_degrees": {
/// "description": "Clockwise rotation of the footprint about `position`. Absent or 0 means axis-aligned.",
/// "type": "number",
/// "exclusiveMaximum": 360.0,
/// "minimum": 0.0
/// },
/// "template": {
/// "description": "Optional descriptive label for the GW standard template this piece uses (e.g. 'large-ruin', 'long-wall'). Free-form, not enum-locked — the geometry in `footprint` is authoritative.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "terrain_area_keywords": {
/// "description": "Terrain-area keywords this piece's area carries.",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/terrain-area-keyword"
/// },
/// "uniqueItems": true
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Piece {
pub footprint: Footprint,
///Height of the piece in inches. Gates Plunging Fire (a piece 3" or taller confers +1 BS on ground-level targets).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub height_inches: ::std::option::Option<f64>,
///Whether this piece carries an objective marker.
#[serde(default)]
pub is_objective: bool,
///Pieces sharing a `link_group` value are linked terrain — treated as a single terrain feature (and, where an objective sits among them, a single objective).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub link_group: ::std::option::Option<PieceLinkGroup>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub name: ::std::option::Option<PieceName>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub objective: ::std::option::Option<PieceObjective>,
///Board-inch placement of the footprint's local origin.
pub position: Vec2,
///Clockwise rotation of the footprint about `position`. Absent or 0 means axis-aligned.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub rotation_degrees: ::std::option::Option<f64>,
///Optional descriptive label for the GW standard template this piece uses (e.g. 'large-ruin', 'long-wall'). Free-form, not enum-locked — the geometry in `footprint` is authoritative.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub template: ::std::option::Option<PieceTemplate>,
///Terrain-area keywords this piece's area carries.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub terrain_area_keywords: ::std::option::Option<Vec<TerrainAreaKeyword>>,
}
///Pieces sharing a `link_group` value are linked terrain — treated as a single terrain feature (and, where an objective sits among them, a single objective).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Pieces sharing a `link_group` value are linked terrain — treated as a single terrain feature (and, where an objective sits among them, a single objective).",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PieceLinkGroup(::std::string::String);
impl ::std::ops::Deref for PieceLinkGroup {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PieceLinkGroup> for ::std::string::String {
fn from(value: PieceLinkGroup) -> Self {
value.0
}
}
impl ::std::str::FromStr for PieceLinkGroup {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PieceLinkGroup {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PieceLinkGroup {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PieceLinkGroup {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PieceLinkGroup {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`PieceName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PieceName(::std::string::String);
impl ::std::ops::Deref for PieceName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PieceName> for ::std::string::String {
fn from(value: PieceName) -> Self {
value.0
}
}
impl ::std::str::FromStr for PieceName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PieceName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PieceName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PieceName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PieceName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Objective-marker metadata. Only meaningful when `is_objective` is true.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Objective-marker metadata. Only meaningful when `is_objective` is true.",
/// "type": "object",
/// "properties": {
/// "control_range_inches": {
/// "description": "Range from the marker within which models contribute to control.",
/// "type": "number",
/// "exclusiveMinimum": 0.0
/// },
/// "position": {
/// "description": "Board-inch position of the marker. Absent means the piece's `position`.",
/// "$ref": "#/$defs/vec2"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct PieceObjective {
///Range from the marker within which models contribute to control.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub control_range_inches: ::std::option::Option<f64>,
///Board-inch position of the marker. Absent means the piece's `position`.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub position: ::std::option::Option<Vec2>,
}
impl ::std::default::Default for PieceObjective {
fn default() -> Self {
Self {
control_range_inches: Default::default(),
position: Default::default(),
}
}
}
///Optional descriptive label for the GW standard template this piece uses (e.g. 'large-ruin', 'long-wall'). Free-form, not enum-locked — the geometry in `footprint` is authoritative.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Optional descriptive label for the GW standard template this piece uses (e.g. 'large-ruin', 'long-wall'). Free-form, not enum-locked — the geometry in `footprint` is authoritative.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PieceTemplate(::std::string::String);
impl ::std::ops::Deref for PieceTemplate {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PieceTemplate> for ::std::string::String {
fn from(value: PieceTemplate) -> Self {
value.0
}
}
impl ::std::str::FromStr for PieceTemplate {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PieceTemplate {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PieceTemplate {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PieceTemplate {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PieceTemplate {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Which player's turn this applies during
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Which player's turn this applies during",
/// "type": "string",
/// "enum": [
/// "your-turn",
/// "opponent-turn",
/// "either"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum PlayerTurn {
#[serde(rename = "your-turn")]
YourTurn,
#[serde(rename = "opponent-turn")]
OpponentTurn,
#[serde(rename = "either")]
Either,
}
impl ::std::fmt::Display for PlayerTurn {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::YourTurn => f.write_str("your-turn"),
Self::OpponentTurn => f.write_str("opponent-turn"),
Self::Either => f.write_str("either"),
}
}
}
impl ::std::str::FromStr for PlayerTurn {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"your-turn" => Ok(Self::YourTurn),
"opponent-turn" => Ok(Self::OpponentTurn),
"either" => Ok(Self::Either),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for PlayerTurn {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PlayerTurn {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PlayerTurn {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///A faction's resource system (Miracle Dice, Pain tokens, Blessings dice pool, etc.).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Resource Pool",
/// "description": "A faction's resource system (Miracle Dice, Pain tokens, Blessings dice pool, etc.).",
/// "type": "object",
/// "required": [
/// "faction_id",
/// "game_version",
/// "id",
/// "name",
/// "pool_type"
/// ],
/// "properties": {
/// "faction_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "generation": {
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "amount",
/// "condition"
/// ],
/// "properties": {
/// "amount": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "condition": {
/// "$ref": "#/$defs/condition"
/// }
/// }
/// }
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "max_size": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "pool_type": {
/// "type": "string",
/// "enum": [
/// "token",
/// "dice-pool",
/// "counter"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ResourcePool {
pub faction_id: EntityId,
pub game_version: GameVersionRef,
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub generation: ::std::vec::Vec<ResourcePoolGenerationItem>,
pub id: EntityId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub max_size: ::std::option::Option<::std::num::NonZeroU64>,
pub name: ResourcePoolName,
pub pool_type: ResourcePoolPoolType,
}
///`ResourcePoolGenerationItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "amount",
/// "condition"
/// ],
/// "properties": {
/// "amount": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "condition": {
/// "$ref": "#/$defs/condition"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct ResourcePoolGenerationItem {
pub amount: StatValue,
pub condition: Condition,
}
///`ResourcePoolName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResourcePoolName(::std::string::String);
impl ::std::ops::Deref for ResourcePoolName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResourcePoolName> for ::std::string::String {
fn from(value: ResourcePoolName) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResourcePoolName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResourcePoolName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResourcePoolName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResourcePoolName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ResourcePoolName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`ResourcePoolPoolType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "token",
/// "dice-pool",
/// "counter"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum ResourcePoolPoolType {
#[serde(rename = "token")]
Token,
#[serde(rename = "dice-pool")]
DicePool,
#[serde(rename = "counter")]
Counter,
}
impl ::std::fmt::Display for ResourcePoolPoolType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Token => f.write_str("token"),
Self::DicePool => f.write_str("dice-pool"),
Self::Counter => f.write_str("counter"),
}
}
}
impl ::std::str::FromStr for ResourcePoolPoolType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"token" => Ok(Self::Token),
"dice-pool" => Ok(Self::DicePool),
"counter" => Ok(Self::Counter),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ResourcePoolPoolType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResourcePoolPoolType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResourcePoolPoolType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`Scope`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ability Scope",
/// "type": "object",
/// "required": [
/// "duration",
/// "range"
/// ],
/// "properties": {
/// "duration": {
/// "type": "string",
/// "enum": [
/// "phase",
/// "turn",
/// "battle-round",
/// "battle",
/// "until-next-command-phase",
/// "one-use",
/// "permanent"
/// ]
/// },
/// "range": {
/// "type": "string",
/// "enum": [
/// "self",
/// "unit",
/// "attached",
/// "aura-6",
/// "aura-9",
/// "aura-12",
/// "aura-custom",
/// "engagement-range",
/// "any-visible",
/// "any-on-battlefield",
/// "terrain-within-range"
/// ]
/// },
/// "range_inches": {
/// "type": "number"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct Scope {
pub duration: ScopeDuration,
pub range: ScopeRange,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub range_inches: ::std::option::Option<f64>,
}
///`ScopeDuration`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "phase",
/// "turn",
/// "battle-round",
/// "battle",
/// "until-next-command-phase",
/// "one-use",
/// "permanent"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum ScopeDuration {
#[serde(rename = "phase")]
Phase,
#[serde(rename = "turn")]
Turn,
#[serde(rename = "battle-round")]
BattleRound,
#[serde(rename = "battle")]
Battle,
#[serde(rename = "until-next-command-phase")]
UntilNextCommandPhase,
#[serde(rename = "one-use")]
OneUse,
#[serde(rename = "permanent")]
Permanent,
}
impl ::std::fmt::Display for ScopeDuration {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Phase => f.write_str("phase"),
Self::Turn => f.write_str("turn"),
Self::BattleRound => f.write_str("battle-round"),
Self::Battle => f.write_str("battle"),
Self::UntilNextCommandPhase => f.write_str("until-next-command-phase"),
Self::OneUse => f.write_str("one-use"),
Self::Permanent => f.write_str("permanent"),
}
}
}
impl ::std::str::FromStr for ScopeDuration {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"phase" => Ok(Self::Phase),
"turn" => Ok(Self::Turn),
"battle-round" => Ok(Self::BattleRound),
"battle" => Ok(Self::Battle),
"until-next-command-phase" => Ok(Self::UntilNextCommandPhase),
"one-use" => Ok(Self::OneUse),
"permanent" => Ok(Self::Permanent),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ScopeDuration {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ScopeDuration {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ScopeDuration {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`ScopeRange`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "self",
/// "unit",
/// "attached",
/// "aura-6",
/// "aura-9",
/// "aura-12",
/// "aura-custom",
/// "engagement-range",
/// "any-visible",
/// "any-on-battlefield",
/// "terrain-within-range"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum ScopeRange {
#[serde(rename = "self")]
Self_,
#[serde(rename = "unit")]
Unit,
#[serde(rename = "attached")]
Attached,
#[serde(rename = "aura-6")]
Aura6,
#[serde(rename = "aura-9")]
Aura9,
#[serde(rename = "aura-12")]
Aura12,
#[serde(rename = "aura-custom")]
AuraCustom,
#[serde(rename = "engagement-range")]
EngagementRange,
#[serde(rename = "any-visible")]
AnyVisible,
#[serde(rename = "any-on-battlefield")]
AnyOnBattlefield,
#[serde(rename = "terrain-within-range")]
TerrainWithinRange,
}
impl ::std::fmt::Display for ScopeRange {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Self_ => f.write_str("self"),
Self::Unit => f.write_str("unit"),
Self::Attached => f.write_str("attached"),
Self::Aura6 => f.write_str("aura-6"),
Self::Aura9 => f.write_str("aura-9"),
Self::Aura12 => f.write_str("aura-12"),
Self::AuraCustom => f.write_str("aura-custom"),
Self::EngagementRange => f.write_str("engagement-range"),
Self::AnyVisible => f.write_str("any-visible"),
Self::AnyOnBattlefield => f.write_str("any-on-battlefield"),
Self::TerrainWithinRange => f.write_str("terrain-within-range"),
}
}
}
impl ::std::str::FromStr for ScopeRange {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"self" => Ok(Self::Self_),
"unit" => Ok(Self::Unit),
"attached" => Ok(Self::Attached),
"aura-6" => Ok(Self::Aura6),
"aura-9" => Ok(Self::Aura9),
"aura-12" => Ok(Self::Aura12),
"aura-custom" => Ok(Self::AuraCustom),
"engagement-range" => Ok(Self::EngagementRange),
"any-visible" => Ok(Self::AnyVisible),
"any-on-battlefield" => Ok(Self::AnyOnBattlefield),
"terrain-within-range" => Ok(Self::TerrainWithinRange),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ScopeRange {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ScopeRange {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ScopeRange {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///When a VP award is evaluated. A bare `phase` is the legacy shorthand for 'during this phase'; richer triggers add `timing` (the moment within a phase/turn/game), `player_turn`, and a `battle_round` window. A card's section headers map onto these: 'ANY BATTLE ROUND' omits `battle_round`; 'SECOND BATTLE ROUND ONWARDS' is { min: 2 }; 'END OF THE BATTLE' is timing: end-of-battle.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "When a VP award is evaluated. A bare `phase` is the legacy shorthand for 'during this phase'; richer triggers add `timing` (the moment within a phase/turn/game), `player_turn`, and a `battle_round` window. A card's section headers map onto these: 'ANY BATTLE ROUND' omits `battle_round`; 'SECOND BATTLE ROUND ONWARDS' is { min: 2 }; 'END OF THE BATTLE' is timing: end-of-battle.",
/// "type": "object",
/// "allOf": [
/// {}
/// ],
/// "minProperties": 1,
/// "properties": {
/// "battle_round": {
/// "description": "Battle-round window in which the trigger is active. Absent means any battle round (1-5). 'Second battle round onwards' is { min: 2 }.",
/// "type": "object",
/// "minProperties": 1,
/// "properties": {
/// "max": {
/// "type": "integer",
/// "maximum": 5.0,
/// "minimum": 1.0
/// },
/// "min": {
/// "type": "integer",
/// "maximum": 5.0,
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
/// },
/// "phase": {
/// "description": "The phase the trigger is relative to. Required when `timing` is start-of-phase or end-of-phase; omitted for turn- or battle-level timings.",
/// "$ref": "#/$defs/phase"
/// },
/// "player_turn": {
/// "$ref": "#/$defs/player-turn"
/// },
/// "timing": {
/// "description": "The moment the award is checked. 'End of your turn' = end-of-turn; 'End of your Command phase' = end-of-phase with phase: command; 'End of the battle' = end-of-battle.",
/// "type": "string",
/// "enum": [
/// "start-of-turn",
/// "end-of-turn",
/// "start-of-phase",
/// "end-of-phase",
/// "end-of-battle"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ScoringTrigger {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub battle_round: ::std::option::Option<ScoringTriggerBattleRound>,
///The phase the trigger is relative to. Required when `timing` is start-of-phase or end-of-phase; omitted for turn- or battle-level timings.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub phase: ::std::option::Option<Phase>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub player_turn: ::std::option::Option<PlayerTurn>,
///The moment the award is checked. 'End of your turn' = end-of-turn; 'End of your Command phase' = end-of-phase with phase: command; 'End of the battle' = end-of-battle.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub timing: ::std::option::Option<ScoringTriggerTiming>,
}
impl ::std::default::Default for ScoringTrigger {
fn default() -> Self {
Self {
battle_round: Default::default(),
phase: Default::default(),
player_turn: Default::default(),
timing: Default::default(),
}
}
}
///Battle-round window in which the trigger is active. Absent means any battle round (1-5). 'Second battle round onwards' is { min: 2 }.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Battle-round window in which the trigger is active. Absent means any battle round (1-5). 'Second battle round onwards' is { min: 2 }.",
/// "type": "object",
/// "minProperties": 1,
/// "properties": {
/// "max": {
/// "type": "integer",
/// "maximum": 5.0,
/// "minimum": 1.0
/// },
/// "min": {
/// "type": "integer",
/// "maximum": 5.0,
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ScoringTriggerBattleRound {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub max: ::std::option::Option<::std::num::NonZeroU64>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub min: ::std::option::Option<::std::num::NonZeroU64>,
}
impl ::std::default::Default for ScoringTriggerBattleRound {
fn default() -> Self {
Self {
max: Default::default(),
min: Default::default(),
}
}
}
///The moment the award is checked. 'End of your turn' = end-of-turn; 'End of your Command phase' = end-of-phase with phase: command; 'End of the battle' = end-of-battle.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The moment the award is checked. 'End of your turn' = end-of-turn; 'End of your Command phase' = end-of-phase with phase: command; 'End of the battle' = end-of-battle.",
/// "type": "string",
/// "enum": [
/// "start-of-turn",
/// "end-of-turn",
/// "start-of-phase",
/// "end-of-phase",
/// "end-of-battle"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum ScoringTriggerTiming {
#[serde(rename = "start-of-turn")]
StartOfTurn,
#[serde(rename = "end-of-turn")]
EndOfTurn,
#[serde(rename = "start-of-phase")]
StartOfPhase,
#[serde(rename = "end-of-phase")]
EndOfPhase,
#[serde(rename = "end-of-battle")]
EndOfBattle,
}
impl ::std::fmt::Display for ScoringTriggerTiming {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::StartOfTurn => f.write_str("start-of-turn"),
Self::EndOfTurn => f.write_str("end-of-turn"),
Self::StartOfPhase => f.write_str("start-of-phase"),
Self::EndOfPhase => f.write_str("end-of-phase"),
Self::EndOfBattle => f.write_str("end-of-battle"),
}
}
}
impl ::std::str::FromStr for ScoringTriggerTiming {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"start-of-turn" => Ok(Self::StartOfTurn),
"end-of-turn" => Ok(Self::EndOfTurn),
"start-of-phase" => Ok(Self::StartOfPhase),
"end-of-phase" => Ok(Self::EndOfPhase),
"end-of-battle" => Ok(Self::EndOfBattle),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ScoringTriggerTiming {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ScoringTriggerTiming {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ScoringTriggerTiming {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///An 11e mission card. The deck-level rule (draw 2 per turn, keep unscored cards) is separate and not modelled here. This is the per-card shape: an optional on-draw deck operation, an optional player action, and zero or more VP-award blocks. Primary mission cards reuse this shape via card_type. Mechanic blocks reference the Ability DSL; prose is community-authored (no reproduced rules text).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Secondary Card",
/// "description": "An 11e mission card. The deck-level rule (draw 2 per turn, keep unscored cards) is separate and not modelled here. This is the per-card shape: an optional on-draw deck operation, an optional player action, and zero or more VP-award blocks. Primary mission cards reuse this shape via card_type. Mechanic blocks reference the Ability DSL; prose is community-authored (no reproduced rules text).",
/// "type": "object",
/// "required": [
/// "game_version",
/// "id",
/// "name"
/// ],
/// "properties": {
/// "action": {
/// "description": "Optional player action the card enables.",
/// "type": "object",
/// "properties": {
/// "completes": {
/// "description": "Predicate for when the action is considered complete.",
/// "$ref": "#/$defs/condition"
/// },
/// "effect": {
/// "description": "Effect applied when the action completes (e.g. terrain-area-tag to mark transient state on a terrain piece).",
/// "$ref": "#/$defs/effect"
/// },
/// "player_turn": {
/// "$ref": "#/$defs/player-turn"
/// },
/// "starts": {
/// "description": "Phase in which the action can be started.",
/// "$ref": "#/$defs/phase"
/// },
/// "units": {
/// "description": "Eligibility predicate for which units may perform the action.",
/// "$ref": "#/$defs/condition"
/// },
/// "use_limit": {
/// "description": "Maximum number of times the action may be performed.",
/// "type": "integer",
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
/// },
/// "awards": {
/// "description": "VP-award blocks: each scores when `trigger` fires and the optional `when` condition holds. An award scores either a flat `vp` or a count-scaled `vp_per` (VP per instance of the thing named by `per`). Awards accrue independently and sum; a card's '+ ... CUMULATIVE' rows are modelled as separate awards flagged `cumulative` for faithful round-trip.",
/// "type": "array",
/// "items": {
/// "type": "object",
/// "oneOf": [
/// {
/// "required": [
/// "vp"
/// ]
/// },
/// {
/// "required": [
/// "per",
/// "vp_per"
/// ]
/// }
/// ],
/// "required": [
/// "trigger"
/// ],
/// "properties": {
/// "cumulative": {
/// "description": "Marks an award the card shows as an additive '+' bonus to the preceding award in the same trigger block (the card's CUMULATIVE rows). Purely descriptive — all awards accrue independently and are summed.",
/// "default": false,
/// "type": "boolean"
/// },
/// "per": {
/// "description": "What `vp_per` counts, as a kebab-case descriptor (e.g. 'operation-marker-within-range-of-controlled-central-objective'). Required when `vp_per` is present.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "per_max": {
/// "description": "Optional cap on how many instances `vp_per` counts.",
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "trigger": {
/// "$ref": "#/$defs/scoring-trigger"
/// },
/// "vp": {
/// "description": "Flat VP scored when the award fires.",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "vp_per": {
/// "description": "VP scored per instance of the thing named by `per` (e.g. 1 VP per operation marker within range of a controlled objective).",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "when": {
/// "$ref": "#/$defs/condition"
/// }
/// },
/// "additionalProperties": false
/// },
/// "minItems": 1
/// },
/// "card_type": {
/// "description": "Whether this is a secondary card or a primary mission card (which reuses this shape).",
/// "default": "secondary",
/// "type": "string",
/// "enum": [
/// "secondary",
/// "primary"
/// ]
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "subtype": {
/// "description": "Finer classification within the deck (e.g. a category or tactical/fixed split). Free-form — not enum-locked until 11e categories are confirmed.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "text": {
/// "description": "Community-authored card description (original prose only — no reproduced rules text).",
/// "type": "string"
/// },
/// "when_drawn": {
/// "description": "Optional deck operation performed when this card is drawn (e.g. redraw, swap). Distinct from combat effects — deck operations have no combat target, so they are not modelled via the Ability DSL effect language. If `condition` is present, the operation fires only when the predicate holds.",
/// "type": "object",
/// "required": [
/// "operation"
/// ],
/// "properties": {
/// "card_ids": {
/// "description": "Other cards this operation references, by id.",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "uniqueItems": true
/// },
/// "condition": {
/// "description": "Draw-time army-composition predicate gating the operation (e.g. redraw when the opponent lacks a qualifying unit).",
/// "$ref": "#/$defs/army-composition-predicate"
/// },
/// "operation": {
/// "description": "The deck manipulation this card triggers on draw.",
/// "type": "string",
/// "enum": [
/// "reshuffle",
/// "replace",
/// "redraw",
/// "draw-extra",
/// "swap"
/// ]
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct SecondaryCard {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub action: ::std::option::Option<SecondaryCardAction>,
///VP-award blocks: each scores when `trigger` fires and the optional `when` condition holds. An award scores either a flat `vp` or a count-scaled `vp_per` (VP per instance of the thing named by `per`). Awards accrue independently and sum; a card's '+ ... CUMULATIVE' rows are modelled as separate awards flagged `cumulative` for faithful round-trip.
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub awards: ::std::vec::Vec<SecondaryCardAwardsItem>,
///Whether this is a secondary card or a primary mission card (which reuses this shape).
#[serde(default = "defaults::secondary_card_card_type")]
pub card_type: SecondaryCardCardType,
pub game_version: GameVersionRef,
pub id: EntityId,
pub name: SecondaryCardName,
///Finer classification within the deck (e.g. a category or tactical/fixed split). Free-form — not enum-locked until 11e categories are confirmed.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub subtype: ::std::option::Option<SecondaryCardSubtype>,
///Community-authored card description (original prose only — no reproduced rules text).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub text: ::std::option::Option<::std::string::String>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub when_drawn: ::std::option::Option<SecondaryCardWhenDrawn>,
}
///Optional player action the card enables.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Optional player action the card enables.",
/// "type": "object",
/// "properties": {
/// "completes": {
/// "description": "Predicate for when the action is considered complete.",
/// "$ref": "#/$defs/condition"
/// },
/// "effect": {
/// "description": "Effect applied when the action completes (e.g. terrain-area-tag to mark transient state on a terrain piece).",
/// "$ref": "#/$defs/effect"
/// },
/// "player_turn": {
/// "$ref": "#/$defs/player-turn"
/// },
/// "starts": {
/// "description": "Phase in which the action can be started.",
/// "$ref": "#/$defs/phase"
/// },
/// "units": {
/// "description": "Eligibility predicate for which units may perform the action.",
/// "$ref": "#/$defs/condition"
/// },
/// "use_limit": {
/// "description": "Maximum number of times the action may be performed.",
/// "type": "integer",
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct SecondaryCardAction {
///Predicate for when the action is considered complete.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub completes: ::std::option::Option<Condition>,
///Effect applied when the action completes (e.g. terrain-area-tag to mark transient state on a terrain piece).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub effect: ::std::option::Option<Effect>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub player_turn: ::std::option::Option<PlayerTurn>,
///Phase in which the action can be started.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub starts: ::std::option::Option<Phase>,
///Eligibility predicate for which units may perform the action.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub units: ::std::option::Option<Condition>,
///Maximum number of times the action may be performed.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub use_limit: ::std::option::Option<::std::num::NonZeroU64>,
}
impl ::std::default::Default for SecondaryCardAction {
fn default() -> Self {
Self {
completes: Default::default(),
effect: Default::default(),
player_turn: Default::default(),
starts: Default::default(),
units: Default::default(),
use_limit: Default::default(),
}
}
}
///`SecondaryCardAwardsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "oneOf": [
/// {
/// "required": [
/// "vp"
/// ]
/// },
/// {
/// "required": [
/// "per",
/// "vp_per"
/// ]
/// }
/// ],
/// "required": [
/// "trigger"
/// ],
/// "properties": {
/// "cumulative": {
/// "description": "Marks an award the card shows as an additive '+' bonus to the preceding award in the same trigger block (the card's CUMULATIVE rows). Purely descriptive — all awards accrue independently and are summed.",
/// "default": false,
/// "type": "boolean"
/// },
/// "per": {
/// "description": "What `vp_per` counts, as a kebab-case descriptor (e.g. 'operation-marker-within-range-of-controlled-central-objective'). Required when `vp_per` is present.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "per_max": {
/// "description": "Optional cap on how many instances `vp_per` counts.",
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "trigger": {
/// "$ref": "#/$defs/scoring-trigger"
/// },
/// "vp": {
/// "description": "Flat VP scored when the award fires.",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "vp_per": {
/// "description": "VP scored per instance of the thing named by `per` (e.g. 1 VP per operation marker within range of a controlled objective).",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "when": {
/// "$ref": "#/$defs/condition"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(untagged, deny_unknown_fields)]
pub enum SecondaryCardAwardsItem {
Variant0 {
///Marks an award the card shows as an additive '+' bonus to the preceding award in the same trigger block (the card's CUMULATIVE rows). Purely descriptive — all awards accrue independently and are summed.
#[serde(default)]
cumulative: bool,
///Optional cap on how many instances `vp_per` counts.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
per_max: ::std::option::Option<::std::num::NonZeroU64>,
trigger: ScoringTrigger,
///Flat VP scored when the award fires.
vp: u64,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
when: ::std::option::Option<Condition>,
},
Variant1 {
///Marks an award the card shows as an additive '+' bonus to the preceding award in the same trigger block (the card's CUMULATIVE rows). Purely descriptive — all awards accrue independently and are summed.
#[serde(default)]
cumulative: bool,
///What `vp_per` counts, as a kebab-case descriptor (e.g. 'operation-marker-within-range-of-controlled-central-objective'). Required when `vp_per` is present.
per: SecondaryCardAwardsItemVariant1Per,
///Optional cap on how many instances `vp_per` counts.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
per_max: ::std::option::Option<::std::num::NonZeroU64>,
trigger: ScoringTrigger,
///VP scored per instance of the thing named by `per` (e.g. 1 VP per operation marker within range of a controlled objective).
vp_per: u64,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
when: ::std::option::Option<Condition>,
},
}
///What `vp_per` counts, as a kebab-case descriptor (e.g. 'operation-marker-within-range-of-controlled-central-objective'). Required when `vp_per` is present.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "What `vp_per` counts, as a kebab-case descriptor (e.g. 'operation-marker-within-range-of-controlled-central-objective'). Required when `vp_per` is present.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct SecondaryCardAwardsItemVariant1Per(::std::string::String);
impl ::std::ops::Deref for SecondaryCardAwardsItemVariant1Per {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<SecondaryCardAwardsItemVariant1Per> for ::std::string::String {
fn from(value: SecondaryCardAwardsItemVariant1Per) -> Self {
value.0
}
}
impl ::std::str::FromStr for SecondaryCardAwardsItemVariant1Per {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for SecondaryCardAwardsItemVariant1Per {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String>
for SecondaryCardAwardsItemVariant1Per {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String>
for SecondaryCardAwardsItemVariant1Per {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for SecondaryCardAwardsItemVariant1Per {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Whether this is a secondary card or a primary mission card (which reuses this shape).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Whether this is a secondary card or a primary mission card (which reuses this shape).",
/// "default": "secondary",
/// "type": "string",
/// "enum": [
/// "secondary",
/// "primary"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum SecondaryCardCardType {
#[serde(rename = "secondary")]
Secondary,
#[serde(rename = "primary")]
Primary,
}
impl ::std::fmt::Display for SecondaryCardCardType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Secondary => f.write_str("secondary"),
Self::Primary => f.write_str("primary"),
}
}
}
impl ::std::str::FromStr for SecondaryCardCardType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"secondary" => Ok(Self::Secondary),
"primary" => Ok(Self::Primary),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for SecondaryCardCardType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for SecondaryCardCardType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for SecondaryCardCardType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::default::Default for SecondaryCardCardType {
fn default() -> Self {
SecondaryCardCardType::Secondary
}
}
///`SecondaryCardName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct SecondaryCardName(::std::string::String);
impl ::std::ops::Deref for SecondaryCardName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<SecondaryCardName> for ::std::string::String {
fn from(value: SecondaryCardName) -> Self {
value.0
}
}
impl ::std::str::FromStr for SecondaryCardName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for SecondaryCardName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for SecondaryCardName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for SecondaryCardName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for SecondaryCardName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Finer classification within the deck (e.g. a category or tactical/fixed split). Free-form — not enum-locked until 11e categories are confirmed.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Finer classification within the deck (e.g. a category or tactical/fixed split). Free-form — not enum-locked until 11e categories are confirmed.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct SecondaryCardSubtype(::std::string::String);
impl ::std::ops::Deref for SecondaryCardSubtype {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<SecondaryCardSubtype> for ::std::string::String {
fn from(value: SecondaryCardSubtype) -> Self {
value.0
}
}
impl ::std::str::FromStr for SecondaryCardSubtype {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for SecondaryCardSubtype {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for SecondaryCardSubtype {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for SecondaryCardSubtype {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for SecondaryCardSubtype {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Optional deck operation performed when this card is drawn (e.g. redraw, swap). Distinct from combat effects — deck operations have no combat target, so they are not modelled via the Ability DSL effect language. If `condition` is present, the operation fires only when the predicate holds.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Optional deck operation performed when this card is drawn (e.g. redraw, swap). Distinct from combat effects — deck operations have no combat target, so they are not modelled via the Ability DSL effect language. If `condition` is present, the operation fires only when the predicate holds.",
/// "type": "object",
/// "required": [
/// "operation"
/// ],
/// "properties": {
/// "card_ids": {
/// "description": "Other cards this operation references, by id.",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "uniqueItems": true
/// },
/// "condition": {
/// "description": "Draw-time army-composition predicate gating the operation (e.g. redraw when the opponent lacks a qualifying unit).",
/// "$ref": "#/$defs/army-composition-predicate"
/// },
/// "operation": {
/// "description": "The deck manipulation this card triggers on draw.",
/// "type": "string",
/// "enum": [
/// "reshuffle",
/// "replace",
/// "redraw",
/// "draw-extra",
/// "swap"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct SecondaryCardWhenDrawn {
///Other cards this operation references, by id.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub card_ids: ::std::option::Option<Vec<EntityId>>,
///Draw-time army-composition predicate gating the operation (e.g. redraw when the opponent lacks a qualifying unit).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub condition: ::std::option::Option<ArmyCompositionPredicate>,
///The deck manipulation this card triggers on draw.
pub operation: SecondaryCardWhenDrawnOperation,
}
///The deck manipulation this card triggers on draw.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The deck manipulation this card triggers on draw.",
/// "type": "string",
/// "enum": [
/// "reshuffle",
/// "replace",
/// "redraw",
/// "draw-extra",
/// "swap"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum SecondaryCardWhenDrawnOperation {
#[serde(rename = "reshuffle")]
Reshuffle,
#[serde(rename = "replace")]
Replace,
#[serde(rename = "redraw")]
Redraw,
#[serde(rename = "draw-extra")]
DrawExtra,
#[serde(rename = "swap")]
Swap,
}
impl ::std::fmt::Display for SecondaryCardWhenDrawnOperation {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Reshuffle => f.write_str("reshuffle"),
Self::Replace => f.write_str("replace"),
Self::Redraw => f.write_str("redraw"),
Self::DrawExtra => f.write_str("draw-extra"),
Self::Swap => f.write_str("swap"),
}
}
}
impl ::std::str::FromStr for SecondaryCardWhenDrawnOperation {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"reshuffle" => Ok(Self::Reshuffle),
"replace" => Ok(Self::Replace),
"redraw" => Ok(Self::Redraw),
"draw-extra" => Ok(Self::DrawExtra),
"swap" => Ok(Self::Swap),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for SecondaryCardWhenDrawnOperation {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String>
for SecondaryCardWhenDrawnOperation {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for SecondaryCardWhenDrawnOperation {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`SequenceEffect`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "steps",
/// "type"
/// ],
/// "properties": {
/// "steps": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/effect-node"
/// },
/// "minItems": 1
/// },
/// "type": {
/// "const": "sequence"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct SequenceEffect {
pub steps: ::std::vec::Vec<EffectNode>,
#[serde(rename = "type")]
pub type_: ::serde_json::Value,
}
///Which player a zone or territory belongs to.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Which player a zone or territory belongs to.",
/// "type": "string",
/// "enum": [
/// "attacker",
/// "defender"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum Side {
#[serde(rename = "attacker")]
Attacker,
#[serde(rename = "defender")]
Defender,
}
impl ::std::fmt::Display for Side {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Attacker => f.write_str("attacker"),
Self::Defender => f.write_str("defender"),
}
}
}
impl ::std::str::FromStr for Side {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"attacker" => Ok(Self::Attacker),
"defender" => Ok(Self::Defender),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for Side {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for Side {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for Side {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`SimpleCondition`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "type"
/// ],
/// "properties": {
/// "negated": {
/// "default": false,
/// "type": "boolean"
/// },
/// "parameters": {
/// "type": "object",
/// "additionalProperties": true
/// },
/// "type": {
/// "type": "string",
/// "enum": [
/// "phase-is",
/// "timing-is",
/// "player-turn-is",
/// "unit-below-starting-strength",
/// "unit-below-half-strength",
/// "unit-has-keyword",
/// "unit-within-range-of",
/// "model-is-leader",
/// "target-has-keyword",
/// "charged-this-turn",
/// "advanced-this-turn",
/// "remained-stationary",
/// "is-battle-shocked",
/// "has-lost-wounds",
/// "opponent-unit-within-range",
/// "within-range-of-objective",
/// "attack-is-type",
/// "has-fought-this-phase",
/// "destroyed-by-attack-type",
/// "controls-objective",
/// "is-attached",
/// "terrain-area-control",
/// "engagement-state",
/// "territory-control",
/// "fights-first",
/// "disposition-matches",
/// "units-destroyed",
/// "units-destroyed-comparison",
/// "objective-majority"
/// ]
/// }
/// },
/// "$comment": "Board/meta-state and scoring predicates. `parameters` is intentionally open (additionalProperties: true); each type documents its own param convention. Scoring predicates added for mission cards: `units-destroyed` { side: 'enemy'|'friendly', window: 'this-turn'|'previous-turn', count_min: int } — at least count_min units of `side` were destroyed in `window`. `units-destroyed-comparison` { subject: {side, window}, comparator: 'greater-than'|'greater-or-equal', reference: {side, window} } — compares two destruction tallies (e.g. more enemy units destroyed this turn than friendly last turn). `objective-majority` { relative_to: 'opponent' } — you control more objectives than the named party. `controls-objective` params: { count_min: int, objective_role?: 'central', exclude?: 'home', objective?: 'opponent-home' }."
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct SimpleCondition {
#[serde(default)]
pub negated: bool,
#[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")]
pub parameters: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
#[serde(rename = "type")]
pub type_: SimpleConditionType,
}
///`SimpleConditionType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "phase-is",
/// "timing-is",
/// "player-turn-is",
/// "unit-below-starting-strength",
/// "unit-below-half-strength",
/// "unit-has-keyword",
/// "unit-within-range-of",
/// "model-is-leader",
/// "target-has-keyword",
/// "charged-this-turn",
/// "advanced-this-turn",
/// "remained-stationary",
/// "is-battle-shocked",
/// "has-lost-wounds",
/// "opponent-unit-within-range",
/// "within-range-of-objective",
/// "attack-is-type",
/// "has-fought-this-phase",
/// "destroyed-by-attack-type",
/// "controls-objective",
/// "is-attached",
/// "terrain-area-control",
/// "engagement-state",
/// "territory-control",
/// "fights-first",
/// "disposition-matches",
/// "units-destroyed",
/// "units-destroyed-comparison",
/// "objective-majority"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum SimpleConditionType {
#[serde(rename = "phase-is")]
PhaseIs,
#[serde(rename = "timing-is")]
TimingIs,
#[serde(rename = "player-turn-is")]
PlayerTurnIs,
#[serde(rename = "unit-below-starting-strength")]
UnitBelowStartingStrength,
#[serde(rename = "unit-below-half-strength")]
UnitBelowHalfStrength,
#[serde(rename = "unit-has-keyword")]
UnitHasKeyword,
#[serde(rename = "unit-within-range-of")]
UnitWithinRangeOf,
#[serde(rename = "model-is-leader")]
ModelIsLeader,
#[serde(rename = "target-has-keyword")]
TargetHasKeyword,
#[serde(rename = "charged-this-turn")]
ChargedThisTurn,
#[serde(rename = "advanced-this-turn")]
AdvancedThisTurn,
#[serde(rename = "remained-stationary")]
RemainedStationary,
#[serde(rename = "is-battle-shocked")]
IsBattleShocked,
#[serde(rename = "has-lost-wounds")]
HasLostWounds,
#[serde(rename = "opponent-unit-within-range")]
OpponentUnitWithinRange,
#[serde(rename = "within-range-of-objective")]
WithinRangeOfObjective,
#[serde(rename = "attack-is-type")]
AttackIsType,
#[serde(rename = "has-fought-this-phase")]
HasFoughtThisPhase,
#[serde(rename = "destroyed-by-attack-type")]
DestroyedByAttackType,
#[serde(rename = "controls-objective")]
ControlsObjective,
#[serde(rename = "is-attached")]
IsAttached,
#[serde(rename = "terrain-area-control")]
TerrainAreaControl,
#[serde(rename = "engagement-state")]
EngagementState,
#[serde(rename = "territory-control")]
TerritoryControl,
#[serde(rename = "fights-first")]
FightsFirst,
#[serde(rename = "disposition-matches")]
DispositionMatches,
#[serde(rename = "units-destroyed")]
UnitsDestroyed,
#[serde(rename = "units-destroyed-comparison")]
UnitsDestroyedComparison,
#[serde(rename = "objective-majority")]
ObjectiveMajority,
}
impl ::std::fmt::Display for SimpleConditionType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::PhaseIs => f.write_str("phase-is"),
Self::TimingIs => f.write_str("timing-is"),
Self::PlayerTurnIs => f.write_str("player-turn-is"),
Self::UnitBelowStartingStrength => {
f.write_str("unit-below-starting-strength")
}
Self::UnitBelowHalfStrength => f.write_str("unit-below-half-strength"),
Self::UnitHasKeyword => f.write_str("unit-has-keyword"),
Self::UnitWithinRangeOf => f.write_str("unit-within-range-of"),
Self::ModelIsLeader => f.write_str("model-is-leader"),
Self::TargetHasKeyword => f.write_str("target-has-keyword"),
Self::ChargedThisTurn => f.write_str("charged-this-turn"),
Self::AdvancedThisTurn => f.write_str("advanced-this-turn"),
Self::RemainedStationary => f.write_str("remained-stationary"),
Self::IsBattleShocked => f.write_str("is-battle-shocked"),
Self::HasLostWounds => f.write_str("has-lost-wounds"),
Self::OpponentUnitWithinRange => f.write_str("opponent-unit-within-range"),
Self::WithinRangeOfObjective => f.write_str("within-range-of-objective"),
Self::AttackIsType => f.write_str("attack-is-type"),
Self::HasFoughtThisPhase => f.write_str("has-fought-this-phase"),
Self::DestroyedByAttackType => f.write_str("destroyed-by-attack-type"),
Self::ControlsObjective => f.write_str("controls-objective"),
Self::IsAttached => f.write_str("is-attached"),
Self::TerrainAreaControl => f.write_str("terrain-area-control"),
Self::EngagementState => f.write_str("engagement-state"),
Self::TerritoryControl => f.write_str("territory-control"),
Self::FightsFirst => f.write_str("fights-first"),
Self::DispositionMatches => f.write_str("disposition-matches"),
Self::UnitsDestroyed => f.write_str("units-destroyed"),
Self::UnitsDestroyedComparison => f.write_str("units-destroyed-comparison"),
Self::ObjectiveMajority => f.write_str("objective-majority"),
}
}
}
impl ::std::str::FromStr for SimpleConditionType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"phase-is" => Ok(Self::PhaseIs),
"timing-is" => Ok(Self::TimingIs),
"player-turn-is" => Ok(Self::PlayerTurnIs),
"unit-below-starting-strength" => Ok(Self::UnitBelowStartingStrength),
"unit-below-half-strength" => Ok(Self::UnitBelowHalfStrength),
"unit-has-keyword" => Ok(Self::UnitHasKeyword),
"unit-within-range-of" => Ok(Self::UnitWithinRangeOf),
"model-is-leader" => Ok(Self::ModelIsLeader),
"target-has-keyword" => Ok(Self::TargetHasKeyword),
"charged-this-turn" => Ok(Self::ChargedThisTurn),
"advanced-this-turn" => Ok(Self::AdvancedThisTurn),
"remained-stationary" => Ok(Self::RemainedStationary),
"is-battle-shocked" => Ok(Self::IsBattleShocked),
"has-lost-wounds" => Ok(Self::HasLostWounds),
"opponent-unit-within-range" => Ok(Self::OpponentUnitWithinRange),
"within-range-of-objective" => Ok(Self::WithinRangeOfObjective),
"attack-is-type" => Ok(Self::AttackIsType),
"has-fought-this-phase" => Ok(Self::HasFoughtThisPhase),
"destroyed-by-attack-type" => Ok(Self::DestroyedByAttackType),
"controls-objective" => Ok(Self::ControlsObjective),
"is-attached" => Ok(Self::IsAttached),
"terrain-area-control" => Ok(Self::TerrainAreaControl),
"engagement-state" => Ok(Self::EngagementState),
"territory-control" => Ok(Self::TerritoryControl),
"fights-first" => Ok(Self::FightsFirst),
"disposition-matches" => Ok(Self::DispositionMatches),
"units-destroyed" => Ok(Self::UnitsDestroyed),
"units-destroyed-comparison" => Ok(Self::UnitsDestroyedComparison),
"objective-majority" => Ok(Self::ObjectiveMajority),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for SimpleConditionType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for SimpleConditionType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for SimpleConditionType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`SingleEffect`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "target",
/// "type"
/// ],
/// "properties": {
/// "modifier": {
/// "type": "object",
/// "additionalProperties": true
/// },
/// "target": {
/// "type": "string",
/// "enum": [
/// "self",
/// "bearer",
/// "unit",
/// "attached-unit",
/// "attacker",
/// "defender",
/// "friendly-within-aura",
/// "enemy-within-aura",
/// "all-friendly",
/// "all-enemy"
/// ]
/// },
/// "type": {
/// "type": "string",
/// "enum": [
/// "stat-modifier",
/// "roll-modifier",
/// "re-roll",
/// "mortal-wounds",
/// "feel-no-pain",
/// "invulnerable-save",
/// "ward",
/// "keyword-grant",
/// "movement-modifier",
/// "deep-strike",
/// "fallback-and-act",
/// "fight-first",
/// "fight-last",
/// "shoot-on-death",
/// "fight-on-death",
/// "objective-control-modifier",
/// "leadership-modifier",
/// "damage-reduction",
/// "attack-restriction",
/// "ability-grant",
/// "cp-gain",
/// "cp-refund",
/// "model-destruction",
/// "resurrection",
/// "resource-gain",
/// "resource-spend",
/// "charge-roll-modifier",
/// "terrain-area-tag",
/// "bs-modifier",
/// "engagement-passthrough"
/// ]
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct SingleEffect {
#[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")]
pub modifier: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
pub target: SingleEffectTarget,
#[serde(rename = "type")]
pub type_: SingleEffectType,
}
///`SingleEffectTarget`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "self",
/// "bearer",
/// "unit",
/// "attached-unit",
/// "attacker",
/// "defender",
/// "friendly-within-aura",
/// "enemy-within-aura",
/// "all-friendly",
/// "all-enemy"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum SingleEffectTarget {
#[serde(rename = "self")]
Self_,
#[serde(rename = "bearer")]
Bearer,
#[serde(rename = "unit")]
Unit,
#[serde(rename = "attached-unit")]
AttachedUnit,
#[serde(rename = "attacker")]
Attacker,
#[serde(rename = "defender")]
Defender,
#[serde(rename = "friendly-within-aura")]
FriendlyWithinAura,
#[serde(rename = "enemy-within-aura")]
EnemyWithinAura,
#[serde(rename = "all-friendly")]
AllFriendly,
#[serde(rename = "all-enemy")]
AllEnemy,
}
impl ::std::fmt::Display for SingleEffectTarget {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Self_ => f.write_str("self"),
Self::Bearer => f.write_str("bearer"),
Self::Unit => f.write_str("unit"),
Self::AttachedUnit => f.write_str("attached-unit"),
Self::Attacker => f.write_str("attacker"),
Self::Defender => f.write_str("defender"),
Self::FriendlyWithinAura => f.write_str("friendly-within-aura"),
Self::EnemyWithinAura => f.write_str("enemy-within-aura"),
Self::AllFriendly => f.write_str("all-friendly"),
Self::AllEnemy => f.write_str("all-enemy"),
}
}
}
impl ::std::str::FromStr for SingleEffectTarget {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"self" => Ok(Self::Self_),
"bearer" => Ok(Self::Bearer),
"unit" => Ok(Self::Unit),
"attached-unit" => Ok(Self::AttachedUnit),
"attacker" => Ok(Self::Attacker),
"defender" => Ok(Self::Defender),
"friendly-within-aura" => Ok(Self::FriendlyWithinAura),
"enemy-within-aura" => Ok(Self::EnemyWithinAura),
"all-friendly" => Ok(Self::AllFriendly),
"all-enemy" => Ok(Self::AllEnemy),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for SingleEffectTarget {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for SingleEffectTarget {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for SingleEffectTarget {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`SingleEffectType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "stat-modifier",
/// "roll-modifier",
/// "re-roll",
/// "mortal-wounds",
/// "feel-no-pain",
/// "invulnerable-save",
/// "ward",
/// "keyword-grant",
/// "movement-modifier",
/// "deep-strike",
/// "fallback-and-act",
/// "fight-first",
/// "fight-last",
/// "shoot-on-death",
/// "fight-on-death",
/// "objective-control-modifier",
/// "leadership-modifier",
/// "damage-reduction",
/// "attack-restriction",
/// "ability-grant",
/// "cp-gain",
/// "cp-refund",
/// "model-destruction",
/// "resurrection",
/// "resource-gain",
/// "resource-spend",
/// "charge-roll-modifier",
/// "terrain-area-tag",
/// "bs-modifier",
/// "engagement-passthrough"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum SingleEffectType {
#[serde(rename = "stat-modifier")]
StatModifier,
#[serde(rename = "roll-modifier")]
RollModifier,
#[serde(rename = "re-roll")]
ReRoll,
#[serde(rename = "mortal-wounds")]
MortalWounds,
#[serde(rename = "feel-no-pain")]
FeelNoPain,
#[serde(rename = "invulnerable-save")]
InvulnerableSave,
#[serde(rename = "ward")]
Ward,
#[serde(rename = "keyword-grant")]
KeywordGrant,
#[serde(rename = "movement-modifier")]
MovementModifier,
#[serde(rename = "deep-strike")]
DeepStrike,
#[serde(rename = "fallback-and-act")]
FallbackAndAct,
#[serde(rename = "fight-first")]
FightFirst,
#[serde(rename = "fight-last")]
FightLast,
#[serde(rename = "shoot-on-death")]
ShootOnDeath,
#[serde(rename = "fight-on-death")]
FightOnDeath,
#[serde(rename = "objective-control-modifier")]
ObjectiveControlModifier,
#[serde(rename = "leadership-modifier")]
LeadershipModifier,
#[serde(rename = "damage-reduction")]
DamageReduction,
#[serde(rename = "attack-restriction")]
AttackRestriction,
#[serde(rename = "ability-grant")]
AbilityGrant,
#[serde(rename = "cp-gain")]
CpGain,
#[serde(rename = "cp-refund")]
CpRefund,
#[serde(rename = "model-destruction")]
ModelDestruction,
#[serde(rename = "resurrection")]
Resurrection,
#[serde(rename = "resource-gain")]
ResourceGain,
#[serde(rename = "resource-spend")]
ResourceSpend,
#[serde(rename = "charge-roll-modifier")]
ChargeRollModifier,
#[serde(rename = "terrain-area-tag")]
TerrainAreaTag,
#[serde(rename = "bs-modifier")]
BsModifier,
#[serde(rename = "engagement-passthrough")]
EngagementPassthrough,
}
impl ::std::fmt::Display for SingleEffectType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::StatModifier => f.write_str("stat-modifier"),
Self::RollModifier => f.write_str("roll-modifier"),
Self::ReRoll => f.write_str("re-roll"),
Self::MortalWounds => f.write_str("mortal-wounds"),
Self::FeelNoPain => f.write_str("feel-no-pain"),
Self::InvulnerableSave => f.write_str("invulnerable-save"),
Self::Ward => f.write_str("ward"),
Self::KeywordGrant => f.write_str("keyword-grant"),
Self::MovementModifier => f.write_str("movement-modifier"),
Self::DeepStrike => f.write_str("deep-strike"),
Self::FallbackAndAct => f.write_str("fallback-and-act"),
Self::FightFirst => f.write_str("fight-first"),
Self::FightLast => f.write_str("fight-last"),
Self::ShootOnDeath => f.write_str("shoot-on-death"),
Self::FightOnDeath => f.write_str("fight-on-death"),
Self::ObjectiveControlModifier => f.write_str("objective-control-modifier"),
Self::LeadershipModifier => f.write_str("leadership-modifier"),
Self::DamageReduction => f.write_str("damage-reduction"),
Self::AttackRestriction => f.write_str("attack-restriction"),
Self::AbilityGrant => f.write_str("ability-grant"),
Self::CpGain => f.write_str("cp-gain"),
Self::CpRefund => f.write_str("cp-refund"),
Self::ModelDestruction => f.write_str("model-destruction"),
Self::Resurrection => f.write_str("resurrection"),
Self::ResourceGain => f.write_str("resource-gain"),
Self::ResourceSpend => f.write_str("resource-spend"),
Self::ChargeRollModifier => f.write_str("charge-roll-modifier"),
Self::TerrainAreaTag => f.write_str("terrain-area-tag"),
Self::BsModifier => f.write_str("bs-modifier"),
Self::EngagementPassthrough => f.write_str("engagement-passthrough"),
}
}
}
impl ::std::str::FromStr for SingleEffectType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"stat-modifier" => Ok(Self::StatModifier),
"roll-modifier" => Ok(Self::RollModifier),
"re-roll" => Ok(Self::ReRoll),
"mortal-wounds" => Ok(Self::MortalWounds),
"feel-no-pain" => Ok(Self::FeelNoPain),
"invulnerable-save" => Ok(Self::InvulnerableSave),
"ward" => Ok(Self::Ward),
"keyword-grant" => Ok(Self::KeywordGrant),
"movement-modifier" => Ok(Self::MovementModifier),
"deep-strike" => Ok(Self::DeepStrike),
"fallback-and-act" => Ok(Self::FallbackAndAct),
"fight-first" => Ok(Self::FightFirst),
"fight-last" => Ok(Self::FightLast),
"shoot-on-death" => Ok(Self::ShootOnDeath),
"fight-on-death" => Ok(Self::FightOnDeath),
"objective-control-modifier" => Ok(Self::ObjectiveControlModifier),
"leadership-modifier" => Ok(Self::LeadershipModifier),
"damage-reduction" => Ok(Self::DamageReduction),
"attack-restriction" => Ok(Self::AttackRestriction),
"ability-grant" => Ok(Self::AbilityGrant),
"cp-gain" => Ok(Self::CpGain),
"cp-refund" => Ok(Self::CpRefund),
"model-destruction" => Ok(Self::ModelDestruction),
"resurrection" => Ok(Self::Resurrection),
"resource-gain" => Ok(Self::ResourceGain),
"resource-spend" => Ok(Self::ResourceSpend),
"charge-roll-modifier" => Ok(Self::ChargeRollModifier),
"terrain-area-tag" => Ok(Self::TerrainAreaTag),
"bs-modifier" => Ok(Self::BsModifier),
"engagement-passthrough" => Ok(Self::EngagementPassthrough),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for SingleEffectType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for SingleEffectType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for SingleEffectType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Type of game element that is the source of an enrichment entry
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Type of game element that is the source of an enrichment entry",
/// "type": "string",
/// "enum": [
/// "ability",
/// "stratagem",
/// "enhancement",
/// "detachment-rule",
/// "faction-rule"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum SourceType {
#[serde(rename = "ability")]
Ability,
#[serde(rename = "stratagem")]
Stratagem,
#[serde(rename = "enhancement")]
Enhancement,
#[serde(rename = "detachment-rule")]
DetachmentRule,
#[serde(rename = "faction-rule")]
FactionRule,
}
impl ::std::fmt::Display for SourceType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Ability => f.write_str("ability"),
Self::Stratagem => f.write_str("stratagem"),
Self::Enhancement => f.write_str("enhancement"),
Self::DetachmentRule => f.write_str("detachment-rule"),
Self::FactionRule => f.write_str("faction-rule"),
}
}
}
impl ::std::str::FromStr for SourceType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"ability" => Ok(Self::Ability),
"stratagem" => Ok(Self::Stratagem),
"enhancement" => Ok(Self::Enhancement),
"detachment-rule" => Ok(Self::DetachmentRule),
"faction-rule" => Ok(Self::FactionRule),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for SourceType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for SourceType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for SourceType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///A stat that can be a fixed number or a dice expression
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A stat that can be a fixed number or a dice expression",
/// "oneOf": [
/// {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// {
/// "type": "string",
/// "pattern": "^\\d*[Dd]\\d+(\\+\\d+)?$"
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum StatValue {
Integer(u64),
String(StatValueString),
}
impl ::std::str::FromStr for StatValue {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if let Ok(v) = value.parse() {
Ok(Self::Integer(v))
} else if let Ok(v) = value.parse() {
Ok(Self::String(v))
} else {
Err("string conversion failed for all variants".into())
}
}
}
impl ::std::convert::TryFrom<&str> for StatValue {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for StatValue {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for StatValue {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::fmt::Display for StatValue {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match self {
Self::Integer(x) => x.fmt(f),
Self::String(x) => x.fmt(f),
}
}
}
impl ::std::convert::From<u64> for StatValue {
fn from(value: u64) -> Self {
Self::Integer(value)
}
}
impl ::std::convert::From<StatValueString> for StatValue {
fn from(value: StatValueString) -> Self {
Self::String(value)
}
}
///`StatValueString`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^\\d*[Dd]\\d+(\\+\\d+)?$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct StatValueString(::std::string::String);
impl ::std::ops::Deref for StatValueString {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<StatValueString> for ::std::string::String {
fn from(value: StatValueString) -> Self {
value.0
}
}
impl ::std::str::FromStr for StatValueString {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(||
{ ::regress::Regex::new("^\\d*[Dd]\\d+(\\+\\d+)?$").unwrap() });
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^\\d*[Dd]\\d+(\\+\\d+)?$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for StatValueString {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for StatValueString {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for StatValueString {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for StatValueString {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A CP-costed ability usable during specific game phases.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Stratagem",
/// "description": "A CP-costed ability usable during specific game phases.",
/// "type": "object",
/// "required": [
/// "category",
/// "cp_cost",
/// "game_version",
/// "id",
/// "name",
/// "phases",
/// "player_turn",
/// "timing",
/// "type"
/// ],
/// "properties": {
/// "ability_id": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/entity-id"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "category": {
/// "description": "Whether this is a universal core stratagem or tied to a specific detachment",
/// "type": "string",
/// "enum": [
/// "core",
/// "detachment"
/// ]
/// },
/// "cp_cost": {
/// "type": "integer",
/// "maximum": 4.0,
/// "minimum": 0.0
/// },
/// "detachment_id": {
/// "description": "Null for core stratagems",
/// "oneOf": [
/// {
/// "$ref": "#/$defs/entity-id"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "phases": {
/// "$ref": "#/$defs/phase-list"
/// },
/// "player_turn": {
/// "$ref": "#/$defs/player-turn"
/// },
/// "target_restrictions": {
/// "oneOf": [
/// {
/// "type": "object",
/// "properties": {
/// "excluded_keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "notes": {
/// "type": "string"
/// },
/// "required_keywords": {
/// "$ref": "#/$defs/keyword-list"
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "timing": {
/// "type": "string",
/// "enum": [
/// "once-per-phase",
/// "once-per-turn",
/// "once-per-battle",
/// "unlimited"
/// ]
/// },
/// "type": {
/// "description": "GW-printed stratagem category from the card",
/// "type": "string",
/// "enum": [
/// "battle-tactic",
/// "strategic-ploy",
/// "epic-deed",
/// "wargear"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Stratagem {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ability_id: ::std::option::Option<EntityId>,
///Whether this is a universal core stratagem or tied to a specific detachment
pub category: StratagemCategory,
pub cp_cost: i64,
///Null for core stratagems
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub detachment_id: ::std::option::Option<EntityId>,
pub game_version: GameVersionRef,
pub id: EntityId,
pub name: StratagemName,
pub phases: PhaseList,
pub player_turn: PlayerTurn,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub target_restrictions: ::std::option::Option<StratagemTargetRestrictions>,
pub timing: StratagemTiming,
///GW-printed stratagem category from the card
#[serde(rename = "type")]
pub type_: StratagemType,
}
///Whether this is a universal core stratagem or tied to a specific detachment
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Whether this is a universal core stratagem or tied to a specific detachment",
/// "type": "string",
/// "enum": [
/// "core",
/// "detachment"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum StratagemCategory {
#[serde(rename = "core")]
Core,
#[serde(rename = "detachment")]
Detachment,
}
impl ::std::fmt::Display for StratagemCategory {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Core => f.write_str("core"),
Self::Detachment => f.write_str("detachment"),
}
}
}
impl ::std::str::FromStr for StratagemCategory {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"core" => Ok(Self::Core),
"detachment" => Ok(Self::Detachment),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for StratagemCategory {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for StratagemCategory {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for StratagemCategory {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`StratagemName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct StratagemName(::std::string::String);
impl ::std::ops::Deref for StratagemName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<StratagemName> for ::std::string::String {
fn from(value: StratagemName) -> Self {
value.0
}
}
impl ::std::str::FromStr for StratagemName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for StratagemName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for StratagemName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for StratagemName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for StratagemName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`StratagemTargetRestrictions`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "properties": {
/// "excluded_keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "notes": {
/// "type": "string"
/// },
/// "required_keywords": {
/// "$ref": "#/$defs/keyword-list"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct StratagemTargetRestrictions {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub excluded_keywords: ::std::option::Option<KeywordList>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub notes: ::std::option::Option<::std::string::String>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub required_keywords: ::std::option::Option<KeywordList>,
}
impl ::std::default::Default for StratagemTargetRestrictions {
fn default() -> Self {
Self {
excluded_keywords: Default::default(),
notes: Default::default(),
required_keywords: Default::default(),
}
}
}
///`StratagemTiming`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "once-per-phase",
/// "once-per-turn",
/// "once-per-battle",
/// "unlimited"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum StratagemTiming {
#[serde(rename = "once-per-phase")]
OncePerPhase,
#[serde(rename = "once-per-turn")]
OncePerTurn,
#[serde(rename = "once-per-battle")]
OncePerBattle,
#[serde(rename = "unlimited")]
Unlimited,
}
impl ::std::fmt::Display for StratagemTiming {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::OncePerPhase => f.write_str("once-per-phase"),
Self::OncePerTurn => f.write_str("once-per-turn"),
Self::OncePerBattle => f.write_str("once-per-battle"),
Self::Unlimited => f.write_str("unlimited"),
}
}
}
impl ::std::str::FromStr for StratagemTiming {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"once-per-phase" => Ok(Self::OncePerPhase),
"once-per-turn" => Ok(Self::OncePerTurn),
"once-per-battle" => Ok(Self::OncePerBattle),
"unlimited" => Ok(Self::Unlimited),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for StratagemTiming {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for StratagemTiming {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for StratagemTiming {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///GW-printed stratagem category from the card
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "GW-printed stratagem category from the card",
/// "type": "string",
/// "enum": [
/// "battle-tactic",
/// "strategic-ploy",
/// "epic-deed",
/// "wargear"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum StratagemType {
#[serde(rename = "battle-tactic")]
BattleTactic,
#[serde(rename = "strategic-ploy")]
StrategicPloy,
#[serde(rename = "epic-deed")]
EpicDeed,
#[serde(rename = "wargear")]
Wargear,
}
impl ::std::fmt::Display for StratagemType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::BattleTactic => f.write_str("battle-tactic"),
Self::StrategicPloy => f.write_str("strategic-ploy"),
Self::EpicDeed => f.write_str("epic-deed"),
Self::Wargear => f.write_str("wargear"),
}
}
}
impl ::std::str::FromStr for StratagemType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"battle-tactic" => Ok(Self::BattleTactic),
"strategic-ploy" => Ok(Self::StrategicPloy),
"epic-deed" => Ok(Self::EpicDeed),
"wargear" => Ok(Self::Wargear),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for StratagemType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for StratagemType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for StratagemType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///An 11e terrain-area keyword. Confirmed launch set; extend as further keywords publish on dataslate.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "An 11e terrain-area keyword. Confirmed launch set; extend as further keywords publish on dataslate.",
/// "type": "string",
/// "enum": [
/// "obscuring",
/// "hidden",
/// "plunging-fire"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum TerrainAreaKeyword {
#[serde(rename = "obscuring")]
Obscuring,
#[serde(rename = "hidden")]
Hidden,
#[serde(rename = "plunging-fire")]
PlungingFire,
}
impl ::std::fmt::Display for TerrainAreaKeyword {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Obscuring => f.write_str("obscuring"),
Self::Hidden => f.write_str("hidden"),
Self::PlungingFire => f.write_str("plunging-fire"),
}
}
}
impl ::std::str::FromStr for TerrainAreaKeyword {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"obscuring" => Ok(Self::Obscuring),
"hidden" => Ok(Self::Hidden),
"plunging-fire" => Ok(Self::PlungingFire),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for TerrainAreaKeyword {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for TerrainAreaKeyword {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for TerrainAreaKeyword {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///A recommended arrangement of terrain pieces on the board, independent of the deployment map (a deployment-pattern references the layouts it recommends via recommended_terrain_layout_ids). Geometry is the source of truth; the GW standard piece templates are expressed as explicit footprints, with an optional descriptive `template` label. Footprints are deliberately open (not enum-locked) — the launch catalog and its size are unconfirmed, so this models any shape rather than a fixed set. No layout data is authored yet.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Terrain Layout",
/// "description": "A recommended arrangement of terrain pieces on the board, independent of the deployment map (a deployment-pattern references the layouts it recommends via recommended_terrain_layout_ids). Geometry is the source of truth; the GW standard piece templates are expressed as explicit footprints, with an optional descriptive `template` label. Footprints are deliberately open (not enum-locked) — the launch catalog and its size are unconfirmed, so this models any shape rather than a fixed set. No layout data is authored yet.",
/// "type": "object",
/// "required": [
/// "game_version",
/// "id",
/// "name"
/// ],
/// "properties": {
/// "description": {
/// "type": "string"
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "pieces": {
/// "description": "Terrain pieces composing the layout. May be empty while a layout is registered by name ahead of its confirmed geometry.",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/piece"
/// }
/// },
/// "source": {
/// "description": "Mission pack or source the layout originates from.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct TerrainLayout {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub description: ::std::option::Option<::std::string::String>,
pub game_version: GameVersionRef,
pub id: EntityId,
pub name: TerrainLayoutName,
///Terrain pieces composing the layout. May be empty while a layout is registered by name ahead of its confirmed geometry.
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub pieces: ::std::vec::Vec<Piece>,
///Mission pack or source the layout originates from.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub source: ::std::option::Option<TerrainLayoutSource>,
}
///`TerrainLayoutName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct TerrainLayoutName(::std::string::String);
impl ::std::ops::Deref for TerrainLayoutName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<TerrainLayoutName> for ::std::string::String {
fn from(value: TerrainLayoutName) -> Self {
value.0
}
}
impl ::std::str::FromStr for TerrainLayoutName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for TerrainLayoutName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for TerrainLayoutName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for TerrainLayoutName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for TerrainLayoutName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Mission pack or source the layout originates from.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Mission pack or source the layout originates from.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct TerrainLayoutSource(::std::string::String);
impl ::std::ops::Deref for TerrainLayoutSource {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<TerrainLayoutSource> for ::std::string::String {
fn from(value: TerrainLayoutSource) -> Self {
value.0
}
}
impl ::std::str::FromStr for TerrainLayoutSource {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for TerrainLayoutSource {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for TerrainLayoutSource {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for TerrainLayoutSource {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for TerrainLayoutSource {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`TimingFlag`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Timing Flag",
/// "type": "object",
/// "required": [
/// "game_version",
/// "source_id",
/// "source_type",
/// "timing"
/// ],
/// "properties": {
/// "authored_by": {
/// "$ref": "#/$defs/contributor-ref"
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "source_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "source_type": {
/// "$ref": "#/$defs/source-type"
/// },
/// "timing": {
/// "type": "string",
/// "enum": [
/// "start-of-phase",
/// "end-of-phase",
/// "before-hit-roll",
/// "after-hit-roll",
/// "before-wound-roll",
/// "after-wound-roll",
/// "before-save-roll",
/// "after-save-roll",
/// "before-damage-roll",
/// "after-damage-roll",
/// "before-charge-roll",
/// "after-charge-roll",
/// "before-advance-roll",
/// "after-advance-roll",
/// "before-battle-shock",
/// "after-battle-shock",
/// "on-unit-selected",
/// "on-unit-destroyed",
/// "on-model-destroyed",
/// "on-damage-allocated"
/// ]
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct TimingFlag {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub authored_by: ::std::option::Option<ContributorRef>,
pub game_version: GameVersionRef,
pub source_id: EntityId,
pub source_type: SourceType,
pub timing: TimingFlagTiming,
}
///`TimingFlagTiming`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "start-of-phase",
/// "end-of-phase",
/// "before-hit-roll",
/// "after-hit-roll",
/// "before-wound-roll",
/// "after-wound-roll",
/// "before-save-roll",
/// "after-save-roll",
/// "before-damage-roll",
/// "after-damage-roll",
/// "before-charge-roll",
/// "after-charge-roll",
/// "before-advance-roll",
/// "after-advance-roll",
/// "before-battle-shock",
/// "after-battle-shock",
/// "on-unit-selected",
/// "on-unit-destroyed",
/// "on-model-destroyed",
/// "on-damage-allocated"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum TimingFlagTiming {
#[serde(rename = "start-of-phase")]
StartOfPhase,
#[serde(rename = "end-of-phase")]
EndOfPhase,
#[serde(rename = "before-hit-roll")]
BeforeHitRoll,
#[serde(rename = "after-hit-roll")]
AfterHitRoll,
#[serde(rename = "before-wound-roll")]
BeforeWoundRoll,
#[serde(rename = "after-wound-roll")]
AfterWoundRoll,
#[serde(rename = "before-save-roll")]
BeforeSaveRoll,
#[serde(rename = "after-save-roll")]
AfterSaveRoll,
#[serde(rename = "before-damage-roll")]
BeforeDamageRoll,
#[serde(rename = "after-damage-roll")]
AfterDamageRoll,
#[serde(rename = "before-charge-roll")]
BeforeChargeRoll,
#[serde(rename = "after-charge-roll")]
AfterChargeRoll,
#[serde(rename = "before-advance-roll")]
BeforeAdvanceRoll,
#[serde(rename = "after-advance-roll")]
AfterAdvanceRoll,
#[serde(rename = "before-battle-shock")]
BeforeBattleShock,
#[serde(rename = "after-battle-shock")]
AfterBattleShock,
#[serde(rename = "on-unit-selected")]
OnUnitSelected,
#[serde(rename = "on-unit-destroyed")]
OnUnitDestroyed,
#[serde(rename = "on-model-destroyed")]
OnModelDestroyed,
#[serde(rename = "on-damage-allocated")]
OnDamageAllocated,
}
impl ::std::fmt::Display for TimingFlagTiming {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::StartOfPhase => f.write_str("start-of-phase"),
Self::EndOfPhase => f.write_str("end-of-phase"),
Self::BeforeHitRoll => f.write_str("before-hit-roll"),
Self::AfterHitRoll => f.write_str("after-hit-roll"),
Self::BeforeWoundRoll => f.write_str("before-wound-roll"),
Self::AfterWoundRoll => f.write_str("after-wound-roll"),
Self::BeforeSaveRoll => f.write_str("before-save-roll"),
Self::AfterSaveRoll => f.write_str("after-save-roll"),
Self::BeforeDamageRoll => f.write_str("before-damage-roll"),
Self::AfterDamageRoll => f.write_str("after-damage-roll"),
Self::BeforeChargeRoll => f.write_str("before-charge-roll"),
Self::AfterChargeRoll => f.write_str("after-charge-roll"),
Self::BeforeAdvanceRoll => f.write_str("before-advance-roll"),
Self::AfterAdvanceRoll => f.write_str("after-advance-roll"),
Self::BeforeBattleShock => f.write_str("before-battle-shock"),
Self::AfterBattleShock => f.write_str("after-battle-shock"),
Self::OnUnitSelected => f.write_str("on-unit-selected"),
Self::OnUnitDestroyed => f.write_str("on-unit-destroyed"),
Self::OnModelDestroyed => f.write_str("on-model-destroyed"),
Self::OnDamageAllocated => f.write_str("on-damage-allocated"),
}
}
}
impl ::std::str::FromStr for TimingFlagTiming {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"start-of-phase" => Ok(Self::StartOfPhase),
"end-of-phase" => Ok(Self::EndOfPhase),
"before-hit-roll" => Ok(Self::BeforeHitRoll),
"after-hit-roll" => Ok(Self::AfterHitRoll),
"before-wound-roll" => Ok(Self::BeforeWoundRoll),
"after-wound-roll" => Ok(Self::AfterWoundRoll),
"before-save-roll" => Ok(Self::BeforeSaveRoll),
"after-save-roll" => Ok(Self::AfterSaveRoll),
"before-damage-roll" => Ok(Self::BeforeDamageRoll),
"after-damage-roll" => Ok(Self::AfterDamageRoll),
"before-charge-roll" => Ok(Self::BeforeChargeRoll),
"after-charge-roll" => Ok(Self::AfterChargeRoll),
"before-advance-roll" => Ok(Self::BeforeAdvanceRoll),
"after-advance-roll" => Ok(Self::AfterAdvanceRoll),
"before-battle-shock" => Ok(Self::BeforeBattleShock),
"after-battle-shock" => Ok(Self::AfterBattleShock),
"on-unit-selected" => Ok(Self::OnUnitSelected),
"on-unit-destroyed" => Ok(Self::OnUnitDestroyed),
"on-model-destroyed" => Ok(Self::OnModelDestroyed),
"on-damage-allocated" => Ok(Self::OnDamageAllocated),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for TimingFlagTiming {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for TimingFlagTiming {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for TimingFlagTiming {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///A unit datasheet entry with stat profiles and point costs.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Unit",
/// "description": "A unit datasheet entry with stat profiles and point costs.",
/// "type": "object",
/// "required": [
/// "faction_id",
/// "game_version",
/// "id",
/// "name",
/// "profiles"
/// ],
/// "properties": {
/// "ability_ids": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// }
/// },
/// "attachment_role": {
/// "description": "Character attachment role (11e). 'support' implies the unit is only legal when attached to a host unit (cannot be taken solo); 'leader' is valid as a standalone list entry. null/absent for non-attaching units.",
/// "oneOf": [
/// {
/// "enum": [
/// "leader",
/// "support"
/// ]
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "base_size_mm": {
/// "oneOf": [
/// {
/// "type": "object",
/// "required": [
/// "shape"
/// ],
/// "properties": {
/// "diameter": {
/// "type": "number"
/// },
/// "length": {
/// "type": "number"
/// },
/// "shape": {
/// "enum": [
/// "round",
/// "oval"
/// ]
/// },
/// "width": {
/// "type": "number"
/// }
/// }
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "faction_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "faction_keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "is_legend": {
/// "default": false,
/// "type": "boolean"
/// },
/// "keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "model_count": {
/// "type": "object",
/// "required": [
/// "max",
/// "min"
/// ],
/// "properties": {
/// "max": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "min": {
/// "type": "integer",
/// "minimum": 1.0
/// }
/// }
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "points": {
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "cost",
/// "models"
/// ],
/// "properties": {
/// "cost": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "models": {
/// "type": "integer",
/// "minimum": 1.0
/// }
/// }
/// }
/// },
/// "points_provisional": {
/// "description": "True when point costs are carried over provisionally (e.g. seeded from a prior edition during migration) and not yet confirmed against the current dataslate.",
/// "default": false,
/// "type": "boolean"
/// },
/// "profiles": {
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "Ld",
/// "M",
/// "OC",
/// "Sv",
/// "T",
/// "W"
/// ],
/// "properties": {
/// "Ld": {
/// "type": "integer",
/// "maximum": 10.0,
/// "minimum": 2.0
/// },
/// "M": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "OC": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "Sv": {
/// "type": "integer",
/// "maximum": 7.0,
/// "minimum": 2.0
/// },
/// "T": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "W": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "invuln_sv": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "name": {
/// "description": "Profile name (e.g., 'Wounded' for degrading)",
/// "type": "string"
/// }
/// }
/// },
/// "minItems": 1
/// },
/// "role": {
/// "description": "Battlefield role from the datasheet header. Unit types (Infantry, Vehicle, etc.) belong in keywords.",
/// "type": "string",
/// "enum": [
/// "character",
/// "battleline",
/// "dedicated-transport",
/// "fortification",
/// "allied",
/// "epic-hero"
/// ]
/// },
/// "transport_capacity": {
/// "oneOf": [
/// {
/// "type": "object",
/// "required": [
/// "capacity"
/// ],
/// "properties": {
/// "capacity": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "exclusion_keywords": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/keyword-list"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "keyword_restrictions": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/keyword-list"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "weapon_ids": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// }
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Unit {
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub ability_ids: ::std::vec::Vec<EntityId>,
///Character attachment role (11e). 'support' implies the unit is only legal when attached to a host unit (cannot be taken solo); 'leader' is valid as a standalone list entry. null/absent for non-attaching units.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub attachment_role: ::std::option::Option<UnitAttachmentRole>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub base_size_mm: ::std::option::Option<UnitBaseSizeMm>,
pub faction_id: EntityId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub faction_keywords: ::std::option::Option<KeywordList>,
pub game_version: GameVersionRef,
pub id: EntityId,
#[serde(default)]
pub is_legend: bool,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub keywords: ::std::option::Option<KeywordList>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub model_count: ::std::option::Option<UnitModelCount>,
pub name: UnitName,
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub points: ::std::vec::Vec<UnitPointsItem>,
///True when point costs are carried over provisionally (e.g. seeded from a prior edition during migration) and not yet confirmed against the current dataslate.
#[serde(default)]
pub points_provisional: bool,
pub profiles: ::std::vec::Vec<UnitProfilesItem>,
///Battlefield role from the datasheet header. Unit types (Infantry, Vehicle, etc.) belong in keywords.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub role: ::std::option::Option<UnitRole>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub transport_capacity: ::std::option::Option<UnitTransportCapacity>,
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub weapon_ids: ::std::vec::Vec<EntityId>,
}
///`UnitAttachmentRole`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "enum": [
/// "leader",
/// "support"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum UnitAttachmentRole {
#[serde(rename = "leader")]
Leader,
#[serde(rename = "support")]
Support,
}
impl ::std::fmt::Display for UnitAttachmentRole {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Leader => f.write_str("leader"),
Self::Support => f.write_str("support"),
}
}
}
impl ::std::str::FromStr for UnitAttachmentRole {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"leader" => Ok(Self::Leader),
"support" => Ok(Self::Support),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for UnitAttachmentRole {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for UnitAttachmentRole {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for UnitAttachmentRole {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`UnitBaseSizeMm`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "shape"
/// ],
/// "properties": {
/// "diameter": {
/// "type": "number"
/// },
/// "length": {
/// "type": "number"
/// },
/// "shape": {
/// "enum": [
/// "round",
/// "oval"
/// ]
/// },
/// "width": {
/// "type": "number"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct UnitBaseSizeMm {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub diameter: ::std::option::Option<f64>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub length: ::std::option::Option<f64>,
pub shape: UnitBaseSizeMmShape,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub width: ::std::option::Option<f64>,
}
///`UnitBaseSizeMmShape`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "enum": [
/// "round",
/// "oval"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum UnitBaseSizeMmShape {
#[serde(rename = "round")]
Round,
#[serde(rename = "oval")]
Oval,
}
impl ::std::fmt::Display for UnitBaseSizeMmShape {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Round => f.write_str("round"),
Self::Oval => f.write_str("oval"),
}
}
}
impl ::std::str::FromStr for UnitBaseSizeMmShape {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"round" => Ok(Self::Round),
"oval" => Ok(Self::Oval),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for UnitBaseSizeMmShape {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for UnitBaseSizeMmShape {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for UnitBaseSizeMmShape {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Describes the internal model-type breakdown of a unit.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Unit Composition",
/// "description": "Describes the internal model-type breakdown of a unit.",
/// "type": "object",
/// "required": [
/// "game_version",
/// "models",
/// "unit_id"
/// ],
/// "properties": {
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "models": {
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "max",
/// "min",
/// "name"
/// ],
/// "properties": {
/// "default_weapon_ids": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// }
/// },
/// "is_leader_model": {
/// "default": false,
/// "type": "boolean"
/// },
/// "max": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "min": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "name": {
/// "type": "string",
/// "minLength": 1
/// },
/// "profile_name": {
/// "oneOf": [
/// {
/// "type": "string",
/// "minLength": 1
/// },
/// {
/// "type": "null"
/// }
/// ]
/// }
/// },
/// "additionalProperties": false
/// },
/// "minItems": 1
/// },
/// "unit_id": {
/// "$ref": "#/$defs/entity-id"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct UnitComposition {
pub game_version: GameVersionRef,
pub models: ::std::vec::Vec<UnitCompositionModelsItem>,
pub unit_id: EntityId,
}
///`UnitCompositionModelsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "max",
/// "min",
/// "name"
/// ],
/// "properties": {
/// "default_weapon_ids": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// }
/// },
/// "is_leader_model": {
/// "default": false,
/// "type": "boolean"
/// },
/// "max": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "min": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "name": {
/// "type": "string",
/// "minLength": 1
/// },
/// "profile_name": {
/// "oneOf": [
/// {
/// "type": "string",
/// "minLength": 1
/// },
/// {
/// "type": "null"
/// }
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct UnitCompositionModelsItem {
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub default_weapon_ids: ::std::vec::Vec<EntityId>,
#[serde(default)]
pub is_leader_model: bool,
pub max: ::std::num::NonZeroU64,
pub min: u64,
pub name: UnitCompositionModelsItemName,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub profile_name: ::std::option::Option<UnitCompositionModelsItemProfileName>,
}
///`UnitCompositionModelsItemName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct UnitCompositionModelsItemName(::std::string::String);
impl ::std::ops::Deref for UnitCompositionModelsItemName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<UnitCompositionModelsItemName> for ::std::string::String {
fn from(value: UnitCompositionModelsItemName) -> Self {
value.0
}
}
impl ::std::str::FromStr for UnitCompositionModelsItemName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for UnitCompositionModelsItemName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for UnitCompositionModelsItemName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for UnitCompositionModelsItemName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for UnitCompositionModelsItemName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`UnitCompositionModelsItemProfileName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct UnitCompositionModelsItemProfileName(::std::string::String);
impl ::std::ops::Deref for UnitCompositionModelsItemProfileName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<UnitCompositionModelsItemProfileName>
for ::std::string::String {
fn from(value: UnitCompositionModelsItemProfileName) -> Self {
value.0
}
}
impl ::std::str::FromStr for UnitCompositionModelsItemProfileName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for UnitCompositionModelsItemProfileName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String>
for UnitCompositionModelsItemProfileName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String>
for UnitCompositionModelsItemProfileName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for UnitCompositionModelsItemProfileName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`UnitModelCount`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "max",
/// "min"
/// ],
/// "properties": {
/// "max": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "min": {
/// "type": "integer",
/// "minimum": 1.0
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct UnitModelCount {
pub max: ::std::num::NonZeroU64,
pub min: ::std::num::NonZeroU64,
}
///`UnitName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct UnitName(::std::string::String);
impl ::std::ops::Deref for UnitName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<UnitName> for ::std::string::String {
fn from(value: UnitName) -> Self {
value.0
}
}
impl ::std::str::FromStr for UnitName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for UnitName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for UnitName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for UnitName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for UnitName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`UnitPointsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "cost",
/// "models"
/// ],
/// "properties": {
/// "cost": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "models": {
/// "type": "integer",
/// "minimum": 1.0
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct UnitPointsItem {
pub cost: u64,
pub models: ::std::num::NonZeroU64,
}
///`UnitProfilesItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "Ld",
/// "M",
/// "OC",
/// "Sv",
/// "T",
/// "W"
/// ],
/// "properties": {
/// "Ld": {
/// "type": "integer",
/// "maximum": 10.0,
/// "minimum": 2.0
/// },
/// "M": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "OC": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "Sv": {
/// "type": "integer",
/// "maximum": 7.0,
/// "minimum": 2.0
/// },
/// "T": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "W": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "invuln_sv": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "name": {
/// "description": "Profile name (e.g., 'Wounded' for degrading)",
/// "type": "string"
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct UnitProfilesItem {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub invuln_sv: ::std::option::Option<i64>,
#[serde(rename = "Ld")]
pub ld: i64,
#[serde(rename = "M")]
pub m: StatValue,
///Profile name (e.g., 'Wounded' for degrading)
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub name: ::std::option::Option<::std::string::String>,
#[serde(rename = "OC")]
pub oc: u64,
#[serde(rename = "Sv")]
pub sv: i64,
#[serde(rename = "T")]
pub t: ::std::num::NonZeroU64,
#[serde(rename = "W")]
pub w: ::std::num::NonZeroU64,
}
///Battlefield role from the datasheet header. Unit types (Infantry, Vehicle, etc.) belong in keywords.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Battlefield role from the datasheet header. Unit types (Infantry, Vehicle, etc.) belong in keywords.",
/// "type": "string",
/// "enum": [
/// "character",
/// "battleline",
/// "dedicated-transport",
/// "fortification",
/// "allied",
/// "epic-hero"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum UnitRole {
#[serde(rename = "character")]
Character,
#[serde(rename = "battleline")]
Battleline,
#[serde(rename = "dedicated-transport")]
DedicatedTransport,
#[serde(rename = "fortification")]
Fortification,
#[serde(rename = "allied")]
Allied,
#[serde(rename = "epic-hero")]
EpicHero,
}
impl ::std::fmt::Display for UnitRole {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Character => f.write_str("character"),
Self::Battleline => f.write_str("battleline"),
Self::DedicatedTransport => f.write_str("dedicated-transport"),
Self::Fortification => f.write_str("fortification"),
Self::Allied => f.write_str("allied"),
Self::EpicHero => f.write_str("epic-hero"),
}
}
}
impl ::std::str::FromStr for UnitRole {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"character" => Ok(Self::Character),
"battleline" => Ok(Self::Battleline),
"dedicated-transport" => Ok(Self::DedicatedTransport),
"fortification" => Ok(Self::Fortification),
"allied" => Ok(Self::Allied),
"epic-hero" => Ok(Self::EpicHero),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for UnitRole {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for UnitRole {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for UnitRole {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`UnitTransportCapacity`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "capacity"
/// ],
/// "properties": {
/// "capacity": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "exclusion_keywords": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/keyword-list"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "keyword_restrictions": {
/// "oneOf": [
/// {
/// "$ref": "#/$defs/keyword-list"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct UnitTransportCapacity {
pub capacity: ::std::num::NonZeroU64,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub exclusion_keywords: ::std::option::Option<KeywordList>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub keyword_restrictions: ::std::option::Option<KeywordList>,
}
///A 2D point in board inches. Origin at a board corner; JSON uses y-down (downstream renderers may flip to y-up).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A 2D point in board inches. Origin at a board corner; JSON uses y-down (downstream renderers may flip to y-up).",
/// "type": "object",
/// "required": [
/// "x",
/// "y"
/// ],
/// "properties": {
/// "x": {
/// "type": "number"
/// },
/// "y": {
/// "type": "number"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Vec2 {
pub x: f64,
pub y: f64,
}
///A weapon substitution option available to models within a unit.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Wargear Option",
/// "description": "A weapon substitution option available to models within a unit.",
/// "type": "object",
/// "required": [
/// "game_version",
/// "id",
/// "replacement",
/// "replaces",
/// "unit_id"
/// ],
/// "properties": {
/// "additional_cost": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "is_free": {
/// "default": true,
/// "type": "boolean"
/// },
/// "model_constraint": {
/// "oneOf": [
/// {
/// "type": "object",
/// "properties": {
/// "max_count": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "model_name": {
/// "type": "string",
/// "minLength": 1
/// },
/// "per_n_models": {
/// "type": "integer",
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "replacement": {
/// "description": "Weapon IDs being added",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "minItems": 1
/// },
/// "replaces": {
/// "description": "Weapon IDs being removed",
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "minItems": 1
/// },
/// "unit_id": {
/// "$ref": "#/$defs/entity-id"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct WargearOption {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub additional_cost: ::std::option::Option<u64>,
pub game_version: GameVersionRef,
pub id: EntityId,
#[serde(default = "defaults::default_bool::<true>")]
pub is_free: bool,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub model_constraint: ::std::option::Option<WargearOptionModelConstraint>,
///Weapon IDs being added
pub replacement: ::std::vec::Vec<EntityId>,
///Weapon IDs being removed
pub replaces: ::std::vec::Vec<EntityId>,
pub unit_id: EntityId,
}
///`WargearOptionModelConstraint`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "properties": {
/// "max_count": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "model_name": {
/// "type": "string",
/// "minLength": 1
/// },
/// "per_n_models": {
/// "type": "integer",
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct WargearOptionModelConstraint {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub max_count: ::std::option::Option<::std::num::NonZeroU64>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub model_name: ::std::option::Option<WargearOptionModelConstraintModelName>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub per_n_models: ::std::option::Option<::std::num::NonZeroU64>,
}
impl ::std::default::Default for WargearOptionModelConstraint {
fn default() -> Self {
Self {
max_count: Default::default(),
model_name: Default::default(),
per_n_models: Default::default(),
}
}
}
///`WargearOptionModelConstraintModelName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct WargearOptionModelConstraintModelName(::std::string::String);
impl ::std::ops::Deref for WargearOptionModelConstraintModelName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<WargearOptionModelConstraintModelName>
for ::std::string::String {
fn from(value: WargearOptionModelConstraintModelName) -> Self {
value.0
}
}
impl ::std::str::FromStr for WargearOptionModelConstraintModelName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for WargearOptionModelConstraintModelName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String>
for WargearOptionModelConstraintModelName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String>
for WargearOptionModelConstraintModelName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for WargearOptionModelConstraintModelName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A weapon entry with one or more stat profiles (e.g., standard and overcharge modes).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Weapon",
/// "description": "A weapon entry with one or more stat profiles (e.g., standard and overcharge modes).",
/// "type": "object",
/// "required": [
/// "game_version",
/// "id",
/// "name",
/// "profiles",
/// "type"
/// ],
/// "properties": {
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "profiles": {
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "name",
/// "stats"
/// ],
/// "properties": {
/// "keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "range": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// {
/// "type": "string",
/// "const": "Melee"
/// }
/// ]
/// },
/// "stats": {
/// "type": "object",
/// "required": [
/// "A",
/// "AP",
/// "D",
/// "S"
/// ],
/// "properties": {
/// "A": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "AP": {
/// "type": "integer"
/// },
/// "BS": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "D": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "S": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "WS": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// }
/// }
/// }
/// },
/// "additionalProperties": false
/// },
/// "minItems": 1
/// },
/// "type": {
/// "enum": [
/// "ranged",
/// "melee"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Weapon {
pub game_version: GameVersionRef,
pub id: EntityId,
pub name: WeaponName,
pub profiles: ::std::vec::Vec<WeaponProfilesItem>,
#[serde(rename = "type")]
pub type_: WeaponType,
}
///`WeaponName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct WeaponName(::std::string::String);
impl ::std::ops::Deref for WeaponName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<WeaponName> for ::std::string::String {
fn from(value: WeaponName) -> Self {
value.0
}
}
impl ::std::str::FromStr for WeaponName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for WeaponName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for WeaponName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for WeaponName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for WeaponName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`WeaponProfilesItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "name",
/// "stats"
/// ],
/// "properties": {
/// "keywords": {
/// "$ref": "#/$defs/keyword-list"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "range": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// {
/// "type": "string",
/// "const": "Melee"
/// }
/// ]
/// },
/// "stats": {
/// "type": "object",
/// "required": [
/// "A",
/// "AP",
/// "D",
/// "S"
/// ],
/// "properties": {
/// "A": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "AP": {
/// "type": "integer"
/// },
/// "BS": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "D": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "S": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "WS": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// }
/// }
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct WeaponProfilesItem {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub keywords: ::std::option::Option<KeywordList>,
pub name: WeaponProfilesItemName,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub range: ::std::option::Option<WeaponProfilesItemRange>,
pub stats: WeaponProfilesItemStats,
}
///`WeaponProfilesItemName`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct WeaponProfilesItemName(::std::string::String);
impl ::std::ops::Deref for WeaponProfilesItemName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<WeaponProfilesItemName> for ::std::string::String {
fn from(value: WeaponProfilesItemName) -> Self {
value.0
}
}
impl ::std::str::FromStr for WeaponProfilesItemName {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for WeaponProfilesItemName {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for WeaponProfilesItemName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for WeaponProfilesItemName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for WeaponProfilesItemName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`WeaponProfilesItemRange`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "oneOf": [
/// {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// {
/// "type": "string",
/// "const": "Melee"
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum WeaponProfilesItemRange {
Integer(u64),
String(::std::string::String),
}
impl ::std::fmt::Display for WeaponProfilesItemRange {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match self {
Self::Integer(x) => x.fmt(f),
Self::String(x) => x.fmt(f),
}
}
}
impl ::std::convert::From<u64> for WeaponProfilesItemRange {
fn from(value: u64) -> Self {
Self::Integer(value)
}
}
///`WeaponProfilesItemStats`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "A",
/// "AP",
/// "D",
/// "S"
/// ],
/// "properties": {
/// "A": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "AP": {
/// "type": "integer"
/// },
/// "BS": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "D": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "S": {
/// "$ref": "#/$defs/stat-value"
/// },
/// "WS": {
/// "oneOf": [
/// {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// {
/// "type": "null"
/// }
/// ]
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
pub struct WeaponProfilesItemStats {
#[serde(rename = "A")]
pub a: StatValue,
#[serde(rename = "AP")]
pub ap: i64,
#[serde(
rename = "BS",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub bs: ::std::option::Option<i64>,
#[serde(rename = "D")]
pub d: StatValue,
#[serde(rename = "S")]
pub s: StatValue,
#[serde(
rename = "WS",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub ws: ::std::option::Option<i64>,
}
///`WeaponType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "enum": [
/// "ranged",
/// "melee"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum WeaponType {
#[serde(rename = "ranged")]
Ranged,
#[serde(rename = "melee")]
Melee,
}
impl ::std::fmt::Display for WeaponType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Ranged => f.write_str("ranged"),
Self::Melee => f.write_str("melee"),
}
}
}
impl ::std::str::FromStr for WeaponType {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"ranged" => Ok(Self::Ranged),
"melee" => Ok(Self::Melee),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for WeaponType {
type Error = self::error::ConversionError;
fn try_from(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for WeaponType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for WeaponType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Auto-generated by tools/src/bundle-schemas.ts. Single self-contained schema for Rust codegen — do not edit by hand.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://40kdc.dev/schemas/bundled.schema.json",
/// "title": "40kdc Bundled Schemas",
/// "description": "Auto-generated by tools/src/bundle-schemas.ts. Single self-contained schema for Rust codegen — do not edit by hand."
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(transparent)]
pub struct X40kdcBundledSchemas(pub ::serde_json::Value);
impl ::std::ops::Deref for X40kdcBundledSchemas {
type Target = ::serde_json::Value;
fn deref(&self) -> &::serde_json::Value {
&self.0
}
}
impl ::std::convert::From<X40kdcBundledSchemas> for ::serde_json::Value {
fn from(value: X40kdcBundledSchemas) -> Self {
value.0
}
}
impl ::std::convert::From<::serde_json::Value> for X40kdcBundledSchemas {
fn from(value: ::serde_json::Value) -> Self {
Self(value)
}
}
///A zone footprint, expressed as an axis-aligned rectangle or an explicit polygon. Vertices/extent are relative to the owning element's position.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A zone footprint, expressed as an axis-aligned rectangle or an explicit polygon. Vertices/extent are relative to the owning element's position.",
/// "oneOf": [
/// {
/// "type": "object",
/// "required": [
/// "height",
/// "type",
/// "width"
/// ],
/// "properties": {
/// "height": {
/// "type": "number",
/// "exclusiveMinimum": 0.0
/// },
/// "type": {
/// "const": "rectangle"
/// },
/// "width": {
/// "type": "number",
/// "exclusiveMinimum": 0.0
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "object",
/// "required": [
/// "points",
/// "type"
/// ],
/// "properties": {
/// "points": {
/// "type": "array",
/// "items": {
/// "$ref": "#/$defs/vec2"
/// },
/// "minItems": 3
/// },
/// "type": {
/// "const": "polygon"
/// }
/// },
/// "additionalProperties": false
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(tag = "type", deny_unknown_fields)]
pub enum ZoneShape {
#[serde(rename = "rectangle")]
Rectangle { height: f64, width: f64 },
#[serde(rename = "polygon")]
Polygon { points: ::std::vec::Vec<Vec2> },
}
/// Generation of default values for serde.
pub mod defaults {
pub(super) fn default_bool<const V: bool>() -> bool {
V
}
pub(super) fn default_u64<T, const V: u64>() -> T
where
T: ::std::convert::TryFrom<u64>,
<T as ::std::convert::TryFrom<u64>>::Error: ::std::fmt::Debug,
{
T::try_from(V).unwrap()
}
pub(super) fn default_nzu64<T, const V: u64>() -> T
where
T: ::std::convert::TryFrom<::std::num::NonZeroU64>,
<T as ::std::convert::TryFrom<::std::num::NonZeroU64>>::Error: ::std::fmt::Debug,
{
T::try_from(::std::num::NonZeroU64::try_from(V).unwrap()).unwrap()
}
pub(super) fn dice_gated_effect_comparison() -> super::DiceGatedEffectComparison {
super::DiceGatedEffectComparison::Gte
}
pub(super) fn secondary_card_card_type() -> super::SecondaryCardCardType {
super::SecondaryCardCardType::Secondary
}
}