Packages

Pure-Elixir tabletop RPG game support and rules modeled on the System Reference Document (SRD) 5.2 with opt-in support for some 5.1 rules.

Current section

Files

Jump to
srd_5e lib srd content weapon.ex
Raw

lib/srd/content/weapon.ex

defmodule Srd.Content.Weapon do
@moduledoc """
An SRD weapon.
"""
alias Srd.Dice.Expr
alias Srd.Rules.Damage
@masteries ~w(cleave graze nick push sap slow topple vex)a
@enforce_keys [:slug, :name, :category, :kind, :damage, :damage_type, :mastery]
defstruct [
:slug,
:name,
:category,
:kind,
:damage,
:damage_type,
:mastery,
:versatile,
properties: []
]
@type category :: :simple | :martial
@type kind :: :melee | :ranged
@type property ::
:ammunition
| :finesse
| :heavy
| :light
| :loading
| :reach
| :special
| :thrown
| :two_handed
| :versatile
@typedoc "A 2024 SRD weapon mastery property."
@type mastery :: :cleave | :graze | :nick | :push | :sap | :slow | :topple | :vex
@typedoc """
An SRD weapon:
* `:slug` - stable identifier used for lookup
* `:name` - display name
* `:category` - simple or martial
* `:kind` - melee or ranged
* `:damage` - the damage dice
* `:damage_type` - the damage type dealt
* `:mastery` - the weapon's mastery property
* `:versatile` - the two-handed damage dice, present when the weapon is versatile
* `:properties` - the weapon's properties
"""
@type t :: %__MODULE__{
slug: String.t(),
name: String.t(),
category: category(),
kind: kind(),
damage: Expr.t(),
damage_type: Damage.damage_type(),
mastery: mastery(),
versatile: Expr.t() | nil,
properties: [property()]
}
@doc false
@spec new(map()) :: t()
def new(data) do
%__MODULE__{
slug: data.slug,
name: data.name,
category: data.category,
kind: data.kind,
damage: Expr.parse!(data.damage),
damage_type: validate_type!(data.damage_type),
mastery: validate_mastery!(data.mastery),
versatile: parse_optional(data[:versatile]),
properties: data[:properties] || []
}
end
defp validate_type!(type) do
if type in Damage.types() do
type
else
raise ArgumentError, "unknown damage type: #{inspect(type)}"
end
end
defp validate_mastery!(mastery) when mastery in @masteries, do: mastery
defp validate_mastery!(mastery),
do: raise(ArgumentError, "unknown weapon mastery: #{inspect(mastery)}")
defp parse_optional(nil), do: nil
defp parse_optional(die), do: Expr.parse!(die)
end