Packages

Easier creation of the Visual Novel-like games or presentations.

Current section

Files

Jump to
dev_joy lib dev_joy character.ex
Raw

lib/dev_joy/character.ex

defmodule DevJoy.Character do
@moduledoc """
A character is an NPC acting in a game.
## Data module
A data module is supposed to fetch character basic information like avatar and full name
which could be entered in your code or fetched from some API or site.
Such module needs to implement `c:get_character/1` callback.
config :dev_joy, DevJoy.Character, data_module: MyApp.DataModule
## Extra module
An extra module is supposed to fetch character extra information stored in data field
which could be entered in your code or fetched from some API or site.
Such module needs to implement `c:get_character_data/1` callback.
config :dev_joy, DevJoy.Character, extra_module: MyApp.ExtraModule
## Fetching data
All data is fetched at compile time for every dialog and question.
It's recommended to cache all external data in order to avoid long compilation time.
"""
alias DevJoy.Character
alias DevJoy.ForumData
alias DevJoy.Scene
defstruct [:avatar, :full_name, :id, data: []]
@typedoc "Character struct"
@type t :: %__MODULE__{avatar: avatar, data: data, full_name: full_name, id: id}
@typedoc "External url or ralative path within project"
@type avatar :: String.t()
@typedoc "Additional data"
@type data :: Keyword.t()
@typedoc "Full name"
@type full_name :: String.t()
@typedoc "Identifier"
@type id :: atom
@doc "Retrieves information about a character using it's id."
@callback get_character(id) :: Scene.struct_fields()
@doc "Retrieves information about a character using it's id."
@callback get_character_data(id) :: data
@optional_callbacks get_character: 1, get_character_data: 1
@doc """
Gets a data and extra module from configuration.
Using a data module it retrieves information about a character using their id.
Using an extra module it retrieves additional data for a character using their id.
"""
@spec get_fields!(id) :: data | no_return
def get_fields!(id) do
:dev_joy
|> Application.get_env(Character, data_module: ForumData)
|> with_character!(id)
|> then(fn {config, fields} -> {config, Keyword.put(fields, :id, id)} end)
|> then(fn {config, character} ->
config
|> Keyword.get(:extra_module)
|> then(fn
nil -> character
extra_module -> Keyword.put(character, :data, extra_module.get_character_data(id))
end)
end)
end
@spec with_character!(term, id) :: {term, Scene.struct_fields()} | no_return
defp with_character!(config, id) do
config
|> Keyword.get(:data_module)
|> then(fn
nil -> raise "missing data_module configuration"
data_module -> {config, data_module.get_character(id)}
end)
end
end