// @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",
/// "allOf": [
/// {}
/// ],
/// "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"
/// ]
/// }
/// },
/// "$comment": "When `type` is `re-roll`, `modifier` must carry `roll` (string) and `subset` (`ones` | `all-failures`). Rerolls always target failures; the subset decides whether only 1s are rerolled or every failed die. The constraint is enforced by AJV at validation time and stripped from the codegen bundle (typify can't model if/then/else) — the generated TS/Rust types therefore see `modifier` as an open object, matching its other-`type` callers. When `type` is `feel-no-pain`, `modifier` carries `threshold` (the FNP save target) and optionally `scope` ∈ {`all`, `mortal`}; an absent scope defaults to `all` (fires on every unsaved wound). The two scopes compose independently against the mortal-wound stream."
///}
/// ```
/// </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": {
/// "description": "References into the weapon-keyword catalog. Each entry names the catalog id and supplies parameter values (e.g. `Sustained Hits 1` → `{keyword_id: 'sustained-hits', parameters: {value: 1}}`).",
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "keyword_id"
/// ],
/// "properties": {
/// "keyword_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "parameters": {
/// "description": "Reference-site parameters conforming to the catalog entry's required_parameters. Only the three documented keys are accepted; any other key is invalid.",
/// "type": "object",
/// "properties": {
/// "target_keyword": {
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "threshold": {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// "value": {
/// "$ref": "#/$defs/stat-value"
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "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,
}
///Catalog entry for a weapon keyword (Lethal Hits, Sustained Hits N, Anti-X N+, etc.). Each weapon profile references entries here via {keyword_id, parameters?} instead of carrying free-text strings. The optional `effect` describes the keyword's game mechanic in the Ability DSL; null when the behaviour is faction-specific flavour not yet modelled.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Weapon Keyword",
/// "description": "Catalog entry for a weapon keyword (Lethal Hits, Sustained Hits N, Anti-X N+, etc.). Each weapon profile references entries here via {keyword_id, parameters?} instead of carrying free-text strings. The optional `effect` describes the keyword's game mechanic in the Ability DSL; null when the behaviour is faction-specific flavour not yet modelled.",
/// "type": "object",
/// "required": [
/// "effect",
/// "game_version",
/// "id",
/// "name",
/// "required_parameters"
/// ],
/// "properties": {
/// "effect": {
/// "description": "Mechanical effect of this keyword. Null when the behaviour is faction-specific flavour not yet expressible in the DSL — engines treat such references as no-op buffs and may surface them as 'cannot auto-apply'.",
/// "oneOf": [
/// {
/// "$ref": "#/$defs/effect"
/// },
/// {
/// "type": "null"
/// }
/// ]
/// },
/// "game_version": {
/// "$ref": "#/$defs/game-version-ref"
/// },
/// "id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "name": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "required_parameters": {
/// "description": "Parameter keys that must be supplied at each reference site, in the order they would appear in a printed datasheet (e.g. Anti-INFANTRY 4+ → ['target_keyword', 'threshold']).",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "enum": [
/// "value",
/// "target_keyword",
/// "threshold"
/// ]
/// },
/// "maxItems": 3,
/// "uniqueItems": true
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct WeaponKeyword {
///Mechanical effect of this keyword. Null when the behaviour is faction-specific flavour not yet expressible in the DSL — engines treat such references as no-op buffs and may surface them as 'cannot auto-apply'.
pub effect: ::std::option::Option<Effect>,
pub game_version: GameVersionRef,
pub id: EntityId,
pub name: WeaponKeywordName,
///Parameter keys that must be supplied at each reference site, in the order they would appear in a printed datasheet (e.g. Anti-INFANTRY 4+ → ['target_keyword', 'threshold']).
pub required_parameters: Vec<WeaponKeywordRequiredParametersItem>,
}
///`WeaponKeywordName`
///
/// <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 WeaponKeywordName(::std::string::String);
impl ::std::ops::Deref for WeaponKeywordName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<WeaponKeywordName> for ::std::string::String {
fn from(value: WeaponKeywordName) -> Self {
value.0
}
}
impl ::std::str::FromStr for WeaponKeywordName {
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 WeaponKeywordName {
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 WeaponKeywordName {
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 WeaponKeywordName {
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 WeaponKeywordName {
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())
})
}
}
///`WeaponKeywordRequiredParametersItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "value",
/// "target_keyword",
/// "threshold"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd
)]
pub enum WeaponKeywordRequiredParametersItem {
#[serde(rename = "value")]
Value,
#[serde(rename = "target_keyword")]
TargetKeyword,
#[serde(rename = "threshold")]
Threshold,
}
impl ::std::fmt::Display for WeaponKeywordRequiredParametersItem {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Value => f.write_str("value"),
Self::TargetKeyword => f.write_str("target_keyword"),
Self::Threshold => f.write_str("threshold"),
}
}
}
impl ::std::str::FromStr for WeaponKeywordRequiredParametersItem {
type Err = self::error::ConversionError;
fn from_str(
value: &str,
) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"value" => Ok(Self::Value),
"target_keyword" => Ok(Self::TargetKeyword),
"threshold" => Ok(Self::Threshold),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for WeaponKeywordRequiredParametersItem {
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 WeaponKeywordRequiredParametersItem {
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 WeaponKeywordRequiredParametersItem {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`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": {
/// "description": "References into the weapon-keyword catalog. Each entry names the catalog id and supplies parameter values (e.g. `Sustained Hits 1` → `{keyword_id: 'sustained-hits', parameters: {value: 1}}`).",
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "keyword_id"
/// ],
/// "properties": {
/// "keyword_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "parameters": {
/// "description": "Reference-site parameters conforming to the catalog entry's required_parameters. Only the three documented keys are accepted; any other key is invalid.",
/// "type": "object",
/// "properties": {
/// "target_keyword": {
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "threshold": {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// "value": {
/// "$ref": "#/$defs/stat-value"
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "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 {
///References into the weapon-keyword catalog. Each entry names the catalog id and supplies parameter values (e.g. `Sustained Hits 1` → `{keyword_id: 'sustained-hits', parameters: {value: 1}}`).
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub keywords: ::std::vec::Vec<WeaponProfilesItemKeywordsItem>,
pub name: WeaponProfilesItemName,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub range: ::std::option::Option<WeaponProfilesItemRange>,
pub stats: WeaponProfilesItemStats,
}
///`WeaponProfilesItemKeywordsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "keyword_id"
/// ],
/// "properties": {
/// "keyword_id": {
/// "$ref": "#/$defs/entity-id"
/// },
/// "parameters": {
/// "description": "Reference-site parameters conforming to the catalog entry's required_parameters. Only the three documented keys are accepted; any other key is invalid.",
/// "type": "object",
/// "properties": {
/// "target_keyword": {
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "threshold": {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// "value": {
/// "$ref": "#/$defs/stat-value"
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct WeaponProfilesItemKeywordsItem {
pub keyword_id: EntityId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub parameters: ::std::option::Option<WeaponProfilesItemKeywordsItemParameters>,
}
///Reference-site parameters conforming to the catalog entry's required_parameters. Only the three documented keys are accepted; any other key is invalid.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Reference-site parameters conforming to the catalog entry's required_parameters. Only the three documented keys are accepted; any other key is invalid.",
/// "type": "object",
/// "properties": {
/// "target_keyword": {
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "threshold": {
/// "type": "integer",
/// "maximum": 6.0,
/// "minimum": 2.0
/// },
/// "value": {
/// "$ref": "#/$defs/stat-value"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct WeaponProfilesItemKeywordsItemParameters {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub target_keyword: ::std::option::Option<
WeaponProfilesItemKeywordsItemParametersTargetKeyword,
>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub threshold: ::std::option::Option<i64>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub value: ::std::option::Option<StatValue>,
}
impl ::std::default::Default for WeaponProfilesItemKeywordsItemParameters {
fn default() -> Self {
Self {
target_keyword: Default::default(),
threshold: Default::default(),
value: Default::default(),
}
}
}
///`WeaponProfilesItemKeywordsItemParametersTargetKeyword`
///
/// <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 WeaponProfilesItemKeywordsItemParametersTargetKeyword(::std::string::String);
impl ::std::ops::Deref for WeaponProfilesItemKeywordsItemParametersTargetKeyword {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<WeaponProfilesItemKeywordsItemParametersTargetKeyword>
for ::std::string::String {
fn from(value: WeaponProfilesItemKeywordsItemParametersTargetKeyword) -> Self {
value.0
}
}
impl ::std::str::FromStr for WeaponProfilesItemKeywordsItemParametersTargetKeyword {
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 WeaponProfilesItemKeywordsItemParametersTargetKeyword {
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 WeaponProfilesItemKeywordsItemParametersTargetKeyword {
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 WeaponProfilesItemKeywordsItemParametersTargetKeyword {
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 WeaponProfilesItemKeywordsItemParametersTargetKeyword {
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())
})
}
}
///`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
}
}