Skip to content

Built-In Classes

This is the code reference for the built-in, but non-core classes.

open_mafia_engine.built_in.auxiliary

CounterAux

Int-valued aux object, with a default value of 0.

get_or_create(/, game: Game, key: str, value: int = 0, **kwargs) -> CounterAux classmethod

Finds the AuxObject by key or, if there is no object, creates it.

Source code in built_in/auxiliary.py
@classmethod
def get_or_create(
    cls, game: Game, /, key: str, value: int = 0, **kwargs
) -> CounterAux:
    return super().get_or_create(game, key=key, value=value, **kwargs)

increment(self)

Increments this counter by one (e.g. self.value += 1)

Source code in built_in/auxiliary.py
def increment(self):
    """Increments this counter by one (e.g. `self.value += 1`)"""
    self.value += 1

CounterPerPhaseAux

CounterAux that resets after every phase ends.

reset_every_phase(event: EPostPhaseChange) -> None

TempPhaseAux

Aux object that removes itself after the phase.

remove_self(event: EPostPhaseChange) -> Optional[List[RemoveAuxAction]]

ValueAux

Aux object that represents a key-value pair.

get_or_create(/, game: Game, key: str, value: Any, **kwargs) -> ValueAux classmethod

Finds the AuxObject by key or, if there is no object, creates it.

Source code in built_in/auxiliary.py
@classmethod
def get_or_create(cls, game: Game, /, key: str, value: Any, **kwargs) -> ValueAux:
    return super().get_or_create(game, key=key, value=value, **kwargs)

open_mafia_engine.built_in.constraints

ConstraintNoSelfFactionTarget

Any targets for the action, if they are Actors, must be from other factions.

check(self, action: Action) -> Optional[open_mafia_engine.core.event_system.Constraint.Violation]

Checks whether the action is allowed.

If allowed, return None. If not allowed, return a Constraint.Violation

Source code in built_in/constraints.py
def check(self, action: Action) -> Optional[Constraint.Violation]:
    ai = ActionInspector(action)
    p2a: Dict[str, Actor] = ai.values_of_type(Actor)
    bads = []
    for p, a in p2a.items():
        if any(f in self.owner.factions for f in a.factions):
            bads.append(f"{p!r} ({a.name!r})")
    s = "" if len(self.owner.factions) == 1 else "s"
    if len(bads) > 0:
        return self.Violation(f"Targets in own faction{s}: " + ", ".join(bads))

ConstraintNoSelfTarget

Any targets for the action, if they are Actors, must not be the owner.

check(self, action: Action) -> Optional[open_mafia_engine.core.event_system.Constraint.Violation]

Checks whether the action is allowed.

If allowed, return None. If not allowed, return a Constraint.Violation

Source code in built_in/constraints.py
def check(self, action: Action) -> Optional[Constraint.Violation]:
    ai = ActionInspector(action)
    p2a: Dict[str, Actor] = ai.values_of_type(Actor)
    bads = []
    for p, a in p2a.items():
        if a == self.owner:
            bads.append(f"{p!r}")
    if len(bads) > 0:
        return self.Violation("Self-targeting not allowed: " + ", ".join(bads))

LimitPerPhaseActorConstraint

Allow only N uses per phase for this actor.

Attributes

game : Game parent : ATBase limit : int The maximum number of actions per phase. Default is 1. only_successful : bool Whether to count only successful tries towards the limit. Default is False (i.e. even attempts are counted).

owner: Actor property readonly

The owner of this constraint's parent.

LimitPerPhaseKeyConstraint

Allow only N uses per phase, given a key.

Attributes

game : Game parent : Subscriber key : str They key to use for the aux object. limit : int The maximum number of actions per phase. Default is 1. only_successful : bool Whether to count only successful tries towards the limit. Default is False (i.e. even attempts are counted).

check(self, action: Action) -> Optional[open_mafia_engine.core.event_system.Constraint.Violation]

Checks whether the action is allowed.

If allowed, return None. If not allowed, return a Constraint.Violation

Source code in built_in/constraints.py
def check(self, action: Action) -> Optional[Constraint.Violation]:
    v = self.counter.value
    if v >= self.limit:
        return self.Violation(
            f"Reached limit of {self.limit} (found {v}) for key {self.key!r}"
        )

hook_post_action(self, action: Action) -> Optional[List[open_mafia_engine.core.event_system.Action]]

Hook called when parent successfully actioned.

Source code in built_in/constraints.py
def hook_post_action(self, action: Action) -> Optional[List[Action]]:
    if self.only_successful:
        self.counter.increment()

hook_pre_action(self, action: Action) -> Optional[List[open_mafia_engine.core.event_system.Action]]

Hook called when parent is trying to action & no violation for self.

Source code in built_in/constraints.py
def hook_pre_action(self, action: Action) -> Optional[List[Action]]:
    if not self.only_successful:
        self.counter.increment()

PhaseConstraint

Allow only using in a particular phase.

prefix_tags: List[str] property readonly

These are tags used for descriptions, as a prefix.

check(self, action: Action) -> Optional[open_mafia_engine.core.event_system.Constraint.Violation]

Checks whether the action is allowed.

If allowed, return None. If not allowed, return a Constraint.Violation

Source code in built_in/constraints.py
def check(self, action: Action) -> Optional[Constraint.Violation]:
    cp = self.game.current_phase
    if cp != self.phase:
        return self.Violation(
            f"Wrong phase: currently {cp.name!r}, need {self.phase.name!r}."
        )

open_mafia_engine.built_in.information

BaseInformationAction

Action that gives information to a player.

Only ATBase (e.g. Ability or Trigger) may create this action, so we always know the "owner" (who to inform).

Inherit from this action.

inform(self, msg: str)

Helper function to inform the user.

This will trigger EStatusChanged.

Source code in built_in/information.py
def inform(self, msg: str):
    """Helper function to inform the user.

    This will trigger `EStatusChanged`.
    """
    msg = str(msg)

    key = self.status_key()
    st = self.owner.status
    old = st.get(key)
    if old is None:
        st[key] = [msg]
    elif isinstance(old, list):
        st[key] = old + [msg]
    else:
        raise TypeError(f"Expected previous status to be list, but got: {old!r}")

status_key() -> str classmethod

Returns the key where results will be stored.

Source code in built_in/information.py
@classmethod
def status_key(self) -> str:
    """Returns the key where results will be stored."""
    return "info_results"

BaseInspectAction

Action that inspects an Actor.

Inherit from this action.

InspectFactionAction

Inspect the factions of a player.

doit(self)

Performs the action.

Source code in built_in/information.py
def doit(self):
    found = [f.name for f in self.target.factions]
    msg = "Your target is part of these factions: " + ", ".join(found)
    self.inform(msg)

open_mafia_engine.built_in.kills

DeathCausingAction

Action that causes an Actor to die.

Note that KillAction and LynchAction, which are subclasses, are not subclasses of each other. This is to differentiate "kills" and "lynches" and other action types that cause death.

doit(self)

Performs the action.

Source code in built_in/kills.py
def doit(self):
    self.target.status["dead"] = True

KillAction

Action that kills the target.

LynchAction

Action that lynches the target.

open_mafia_engine.built_in.lynch_tally

LynchTally

Vote tally that lynches the vote leader.

respond_leader(self, leader: GameObject) -> Optional[List[open_mafia_engine.built_in.kills.LynchAction]]

Override this for particular behavior.

Source code in built_in/lynch_tally.py
def respond_leader(self, leader: GameObject) -> Optional[List[LynchAction]]:
    """Override this for particular behavior."""
    if isinstance(leader, Actor):
        return [LynchAction(self.game, self, target=leader)]

open_mafia_engine.built_in.notify

EFactionNotify

Event that causes a message to be sent to a faction.

EFActorNotify

Event that causes a message to be sent to an Actor.

ENotify

Base event purely for notifications.

open_mafia_engine.built_in.outcome

OCLastFactionStanding

Win if your faction is last alive. Lose if all members die.

check_deaths(event: EStatusChange)

open_mafia_engine.built_in.phases

open_mafia_engine.built_in.protect

ProtectFromKillAction

Action that protects the tarte from kills until the end of the phase.

doit(self)

Performs the action.

Source code in built_in/protect.py
def doit(self):
    ProtectorFromKillAux(self.game, target=self.target)

ProtectorFromKillAux

Aux object that protects the target from kills.

handle_to_save(event: EPreAction) -> Optional[List[open_mafia_engine.core.event_system.ConditionalCancelAction]]

Cancels the action if it came from the target.

open_mafia_engine.built_in.redirect

ActorRedirectAction

Redirects actions to

ActorRedirectorAux

Aux object that redirects actions made by the target to another actor.

It removes itself after the end of the phase.

Attributes

game : Game target : Actor The target to redirect. new_target : Actor The resulting target. field_name : str The field name to search for. key : None or str Safely ignore this (?). only_abilities : bool If True, only blocks Ability activations, and lets Triggers through. Default is True.

handle_to_cancel(event: EPreAction) -> Optional[List[open_mafia_engine.built_in.redirect.ActorRedirectAction]]

Cancels the action if it came from the target.

BaseRedirectAction

Action that redirects another action to a new target.

Note that actions can have multiple targets. This redirects the one closest to field_name

doit(self)

Performs the action.

Source code in built_in/redirect.py
def doit(self):
    action = self.target
    ai = ActionInspector(action)

    # Look for name match, with high confidence
    p1 = {p: p for p in ai.param_names}
    found = FuzzyMatcher(p1, score_cutoff=80).get(self.field_name, None)

    if found is None:
        # If not, check for exact type matches
        type_matches = ai.params_of_type(type(self.new_target))
        p2 = {p: p for p in type_matches}
        found = FuzzyMatcher(p2, score_cutoff=0).get(self.field_name, None)

    if found is None:
        # Meh - we failed, lets set it anyways for history.
        warnings.warn(
            f"Could not redirect. Field name: {self.field_name!r}."
            f" Action: {action!r}. New target: {self.new_target!r}."
        )
        found = self.field_name

    ai.set_value(found, self.new_target)

CreateRedirectAction

Action that redirects all actions from the target to new_target.

doit(self)

Performs the action.

Source code in built_in/redirect.py
def doit(self):
    ActorRedirectorAux(
        self.game,
        target=self.target,
        new_target=self.new_target,
        field_name=self.field_name,
        only_abilities=True,
    )

open_mafia_engine.built_in.roleblock

RoleBlockAction

Action that prevents the target from actioning until the end of the phase.

doit(self)

Performs the action.

Source code in built_in/roleblock.py
def doit(self):
    RoleBlockerAux(self.game, target=self.target, only_abilities=True)

RoleBlockerAux

Aux object that blocks actions made by the target.

It removes itself after the end of the phase.

Attributes

game : Game target : Actor The target to block. key : None or str Safely ignore this (?). only_abilities : bool If True, only blocks Ability activations, and lets Triggers through. Default is True.

handle_to_cancel(event: EPreAction) -> Optional[List[open_mafia_engine.core.event_system.CancelAction]]

Cancels the action if it came from the target.

open_mafia_engine.built_in.startup

ECreateFactionChat

Event that signals creating a faction chat.

FactionChatCreatorAux

Base class to create the faction chat for some faction.

handle_startup(event: EPrePhaseChange)

open_mafia_engine.built_in.triggers

UnkillableTrigger

Cancels kill actions against the owner.

cancel_self_kills(event: EPreAction)

UnlynchableTrigger

Cancels lynch actions against the owner.

cancel_self_kills(event: EPreAction)

open_mafia_engine.built_in.voting

AbstractVoteTarget

A target for voting. Don't use directly.

apply(self, vr: VotingResults, voter: Actor)

Apply self on the voting results.

Source code in built_in/voting.py
@abstractmethod
def apply(self, vr: VotingResults, voter: Actor):
    """Apply self on the voting results."""

ActorTarget

Normal voting for a single Actor.

apply(self, vr: VotingResults, voter: Actor)

Apply self on the voting results.

Source code in built_in/voting.py
def apply(self, vr: VotingResults, voter: Actor):
    vr._reset(voter)
    vr._set(voter, self.actor)

ActorTargets

Voting for multiple actors.

apply(self, vr: VotingResults, voter: Actor)

Apply self on the voting results.

Source code in built_in/voting.py
def apply(self, vr: VotingResults, voter: Actor):
    vr._reset(voter)
    for a in self.actors:
        vr._set(voter, a)

Tally

Voting tally.

Tallies select the leader before each phase end. Override respond_leader(). Tallies reset after each phase end.

results: VotingResults property readonly

Applies vote history to get current results.

add_vote(self, vote: Vote)

Adds the vote to history.

Source code in built_in/voting.py
def add_vote(self, vote: Vote):
    """Adds the vote to history."""
    if not isinstance(vote, Vote):
        raise TypeError(f"Can only add a Vote, got {vote!r}")
    self._vote_history.append(vote)

check_hammer(event: VoteAction.Post)

TODO: Hammers.

handle_leader(event: PhaseChangeAction.Pre)

reset_on_phase(event: EPostPhaseChange)

Resets votes every phase change.

respond_leader(self, leader: GameObject) -> Optional[List[Action]]

Override this for particular behavior.

Source code in built_in/voting.py
@abstractmethod
def respond_leader(self, leader: GameObject) -> Optional[List[Action]]:
    """Override this for particular behavior."""
    return None

UnvoteAll

Symbolic class for unvoting.

apply(self, vr: VotingResults, voter: Actor)

Removes all votes made by voter.

Source code in built_in/voting.py
def apply(self, vr: VotingResults, voter: Actor):
    """Removes all votes made by `voter`."""
    if not vr.options.allow_unvote:
        # Warn?
        return
    vr._reset(voter)

Vote

A vote on a Tally.

Attributes

voter : Actor The actor who is voting. target : AbstractVoteTarget The target, or targets, or UnvoteAll...

VoteAbility

Voting ability.

activate(self, target: AbstractVoteTarget) -> Optional[List[VoteAction]]

Creates the action.

Source code in built_in/voting.py
def activate(self, target: AbstractVoteTarget) -> Optional[List[VoteAction]]:
    """Creates the action."""

    # TODO: Constraints!

    try:
        return [
            VoteAction(
                self.game, self, voter=self.owner, target=target, tally=self.tally
            )
        ]
    except Exception:
        logger.exception("Error executing action:")
        if False:  # True, if debugging?
            raise
        return None

VoteAction

Votes for someone.

Post

We have voted.

Pre

We are about to vote.

doit(self)

Performs the action.

Source code in built_in/voting.py
def doit(self):
    self.tally.add_vote(Vote(self.game, voter=self.voter, target=self.target))

VoteAgainstAll

Symbolic class for voting against all options.

apply(self, vr: VotingResults, voter: Actor)

Unvotes-all, then votes for VoteAgainstAll object.

Source code in built_in/voting.py
def apply(self, vr: VotingResults, voter: Actor):
    """Unvotes-all, then votes for `VoteAgainstAll` object."""
    if not vr.options.allow_against_all:
        # Warn?
        return
    vr._reset(voter)
    vr._set(
        voter,
        VoteAgainstAll(self.game),
    )

VotingOptions

Voting options.

Attributes

game : Game allow_unvote : bool Whether unvotes are allowed at all. Default is True. allow_against_all : bool Whether a "VoteAgainstAll" (e.g. "no lynch") is allowed. Default is True.

TODO: Hammers? Tiebreaks?

VotingResults

Voting results object.

vote_counts: List[Tuple[GameObject, float]] property readonly

Gets the vote counts, sorted in descending order.

vote_leaders: List[GameObject] property readonly

Gets the current vote leaders, if any.

vote_map: List[Tuple[GameObject, float, List[Actor]]] property readonly

Gets the vote counts, along with Actors who vote for them.

get_default_tally(game: Game, obj: NoneType) -> Tally

Selects the default vote tally.

Source code in built_in/voting.py
@converter.register
def get_default_tally(game: Game, obj: NoneType) -> Tally:
    """Selects the default vote tally."""
    tallies: List[Tally] = game.aux.filter_by_type(Tally)
    if len(tallies) == 0:
        raise TypeError(f"No tallies found!")
    elif len(tallies) > 1:
        raise TypeError(f"Multiple tallies found: {tallies!r}")
    return tallies[0]

get_vote_target_multi(game: Game, obj: list) -> AbstractVoteTarget

Parses a list of strings (or Actors) as a complex vote target.

Source code in built_in/voting.py
@converter.register
def get_vote_target_multi(game: Game, obj: list) -> AbstractVoteTarget:
    """Parses a list of strings (or Actors) as a complex vote target."""
    # TODO: What if there are unvotes inside?...
    actors = [get_actor_by_name(game, x) for x in obj]
    return ActorTargets(game, actors=actors)

get_vote_target_single(game: Game, obj: str) -> AbstractVoteTarget

Parses a string as a vote target.

Source code in built_in/voting.py
@converter.register
def get_vote_target_single(game: Game, obj: str) -> AbstractVoteTarget:
    """Parses a string as a vote target."""
    # TODO: Set phrases as game-specific options?
    if obj.lower() == "unvote":
        return UnvoteAll(game)
    elif obj.lower() == "no lynch":
        return VoteAgainstAll(game)
    return ActorTarget(game, actor=obj)  # will auto-convert the str, or fail.