defmodule Odinsea.Game.Events do @moduledoc """ Event type definitions and map IDs. Ported from Java `server.events.MapleEventType`. Each event type has associated map IDs where the event takes place. """ @typedoc "Event type atom" @type t :: :coconut | :coke_play | :fitness | :ola_ola | :ox_quiz | :survival | :snowball # ============================================================================ # Event Map IDs # ============================================================================ @event_maps %{ # Coconut event - team-based coconut hitting coconut: [109080000], # Coke Play event (similar to coconut) coke_play: [109080010], # Fitness event - 4 stage obstacle course fitness: [109040000, 109040001, 109040002, 109040003, 109040004], # Ola Ola event - 3 stage portal guessing game ola_ola: [109030001, 109030002, 109030003], # OX Quiz event - True/False quiz ox_quiz: [109020001], # Survival event - Last man standing (2 maps) survival: [809040000, 809040100], # Snowball event - Team snowball rolling competition snowball: [109060000] } @doc """ Returns all event types. """ def all do Map.keys(@event_maps) end @doc """ Returns the map IDs for a given event type. ## Examples iex> Odinsea.Game.Events.map_ids(:coconut) [109080000] iex> Odinsea.Game.Events.map_ids(:fitness) [109040000, 109040001, 109040002, 109040003, 109040004] """ def map_ids(event_type) do Map.get(@event_maps, event_type, []) end @doc """ Returns the entry map ID (first map) for an event type. """ def entry_map_id(event_type) do case map_ids(event_type) do [first | _] -> first [] -> nil end end @doc """ Gets an event type by string name (case-insensitive). ## Examples iex> Odinsea.Game.Events.get_by_string("coconut") :coconut iex> Odinsea.Game.Events.get_by_string("OX_QUIZ") :ox_quiz iex> Odinsea.Game.Events.get_by_string("invalid") nil """ def get_by_string(str) when is_binary(str) do str = String.downcase(str) Enum.find(all(), fn type -> Atom.to_string(type) == str or String.replace(Atom.to_string(type), "_", "") == str end) end def get_by_string(_), do: nil @doc """ Returns a human-readable name for the event type. ## Examples iex> Odinsea.Game.Events.display_name(:coconut) "Coconut" iex> Odinsea.Game.Events.display_name(:ola_ola) "Ola Ola" """ def display_name(event_type) do event_type |> Atom.to_string() |> String.replace("_", " ") |> String.split() |> Enum.map(&String.capitalize/1) |> Enum.join(" ") end @doc """ Returns the number of stages/maps for an event. """ def stage_count(event_type) do length(map_ids(event_type)) end @doc """ Checks if a map ID belongs to any event. Returns the event type if found, nil otherwise. """ def event_for_map(map_id) when is_integer(map_id) do Enum.find(all(), fn type -> map_id in map_ids(type) end) end def event_for_map(_), do: nil @doc """ Checks if a map ID is the finish map (109050000). """ def finish_map?(109050000), do: true def finish_map?(_), do: false @doc """ Returns true if the event is a race-type event (timed). """ def race_event?(:fitness), do: true def race_event?(:ola_ola), do: true def race_event?(:survival), do: true def race_event?(_), do: false @doc """ Returns true if the event is team-based. """ def team_event?(:coconut), do: true def team_event?(:snowball), do: true def team_event?(_), do: false @doc """ Returns true if the event has multiple stages. """ def multi_stage?(event_type) do stage_count(event_type) > 1 end @doc """ Returns the stage index for a map ID within an event. Returns 0-based index or nil if not part of event. """ def stage_index(event_type, map_id) do map_ids(event_type) |> Enum.find_index(&(&1 == map_id)) end @doc """ Returns all event data as a map. """ def all_event_data do @event_maps end end