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]]
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]]
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]]
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)
handle_leader(event: PhaseChangeAction.Pre)
reset_on_phase(event: EPostPhaseChange)
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.