forked from External/mage
- Adds Room + Room half card types - Adds Room unlock ability - Adds Room special functionality (locking halves, unlocking, changing names, changing mana values) - Adjusts name predicate handling for Room name handling (Rooms have between 0 and 2 names on the battlefield depending on their state. They have 1 name on the stack as a normal split card does). Allows cards to match these names properly - Adds Room game events (Unlock, Fully Unlock) and unlock triggers - Updates Split card constructor to allow a single type line as with Rooms - Adds empty name constant for fully unlocked rooms - Updates Permanent to include the door unlock states (that all permanents have) that are relevant when a permanent is or becomes a Room. - Updates ZonesHandler to properly move Room card parts onto and off of the battlefield. - Updated Eerie ability to function properly with Rooms - Implemented Bottomless Pool // Locker Room - Implemented Surgical Suite // Hospital Room - Added Room card tests
919 lines
35 KiB
Java
919 lines
35 KiB
Java
package mage.game.events;
|
||
|
||
import mage.ApprovingObject;
|
||
import mage.MageIdentifier;
|
||
import mage.abilities.Ability;
|
||
import mage.constants.Zone;
|
||
|
||
import java.io.Serializable;
|
||
import java.util.ArrayList;
|
||
import java.util.List;
|
||
import java.util.UUID;
|
||
|
||
/**
|
||
* @author BetaSteward_at_googlemail.com
|
||
*/
|
||
public class GameEvent implements Serializable {
|
||
|
||
protected EventType type;
|
||
protected UUID id;
|
||
protected UUID targetId;
|
||
protected UUID sourceId; // TODO: check sourceId usage in all events, it must gets sourceId from source ability only, not other values
|
||
protected UUID playerId;
|
||
protected int amount;
|
||
// flags:
|
||
// for counters: event is result of effect (+1 from planeswalkers is cost, not effect)
|
||
// for combat damage: event is preventable damage
|
||
// for discard: event is result of effect (1) or result of cost (0)
|
||
// for prevent damage: try to prevent combat damage (1) or other damage (0)
|
||
// for tapped: is it tapped for combat (1) or for another reason (0)
|
||
protected boolean flag;
|
||
protected String data;
|
||
protected Zone zone;
|
||
protected List<UUID> appliedEffects = new ArrayList<>();
|
||
protected ApprovingObject approvingObject; // e.g. the approving object for casting a spell from non hand zone
|
||
|
||
public enum EventType {
|
||
|
||
//Game events
|
||
BEGINNING,
|
||
PREVENT_DAMAGE, PREVENTED_DAMAGE,
|
||
//Turn-based events
|
||
PLAY_TURN, EXTRA_TURN,
|
||
BEGIN_TURN, // event fired on actual begin of turn.
|
||
CHANGE_PHASE, PHASE_CHANGED,
|
||
CHANGE_STEP, STEP_CHANGED,
|
||
BEGINNING_PHASE, BEGINNING_PHASE_PRE, BEGINNING_PHASE_POST, // The normal beginning phase -- at the beginning of turn
|
||
BEGINNING_PHASE_EXTRA, BEGINNING_PHASE_PRE_EXTRA, BEGINNING_PHASE_POST_EXTRA, // Extra beginning phase, 'as turn begun' watchers don't want to react on thoses.
|
||
UNTAP_STEP_PRE, UNTAP_STEP, UNTAP_STEP_POST,
|
||
UPKEEP_STEP_PRE, UPKEEP_STEP, UPKEEP_STEP_POST,
|
||
DRAW_STEP_PRE, DRAW_STEP, DRAW_STEP_POST,
|
||
PRECOMBAT_MAIN_PHASE, PRECOMBAT_MAIN_PHASE_PRE, PRECOMBAT_MAIN_PHASE_POST,
|
||
PRECOMBAT_MAIN_STEP_PRE, PRECOMBAT_MAIN_STEP, PRECOMBAT_MAIN_STEP_POST,
|
||
COMBAT_PHASE, COMBAT_PHASE_PRE, COMBAT_PHASE_POST,
|
||
BEGIN_COMBAT_STEP_PRE, BEGIN_COMBAT_STEP, BEGIN_COMBAT_STEP_POST,
|
||
DECLARE_ATTACKERS_STEP_PRE, DECLARE_ATTACKERS_STEP, DECLARE_ATTACKERS_STEP_POST,
|
||
DECLARE_BLOCKERS_STEP_PRE, DECLARE_BLOCKERS_STEP, DECLARE_BLOCKERS_STEP_POST,
|
||
COMBAT_DAMAGE_STEP, COMBAT_DAMAGE_STEP_PRE, COMBAT_DAMAGE_STEP_PRIORITY, COMBAT_DAMAGE_STEP_POST,
|
||
END_COMBAT_STEP_PRE, END_COMBAT_STEP, END_COMBAT_STEP_POST,
|
||
POSTCOMBAT_MAIN_PHASE, POSTCOMBAT_MAIN_PHASE_PRE, POSTCOMBAT_MAIN_PHASE_POST,
|
||
POSTCOMBAT_MAIN_STEP_PRE, POSTCOMBAT_MAIN_STEP, POSTCOMBAT_MAIN_STEP_POST,
|
||
END_PHASE, END_PHASE_PRE, END_PHASE_POST,
|
||
END_TURN_STEP_PRE, END_TURN_STEP, END_TURN_STEP_POST,
|
||
CLEANUP_STEP_PRE, CLEANUP_STEP, CLEANUP_STEP_POST,
|
||
EMPTY_MANA_POOL,
|
||
AT_END_OF_TURN,
|
||
//player events
|
||
/* ZONE_CHANGE
|
||
targetId id of the zone changing object
|
||
sourceId sourceId of the ability with the object moving effect
|
||
WARNING: can be null if moved by game rules (e.g. draw in draw step, discard in cleanup step, fizzled spell)
|
||
playerId controller of the moved object
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
ZONE_CHANGE,
|
||
ZONE_CHANGE_GROUP, // between two specific zones only; TODO: rework all usages to ZONE_CHANGE_BATCH instead, see #11895
|
||
ZONE_CHANGE_BATCH(true), // all zone changes that occurred from a single effect
|
||
DRAW_TWO_OR_MORE_CARDS, // event calls for multi draws only (if player draws 2+ cards at once)
|
||
DRAW_CARD, DREW_CARD,
|
||
EXPLORE, EXPLORED, // targetId is exploring permanent, playerId is its controller
|
||
ECHO_PAID,
|
||
MIRACLE_CARD_REVEALED,
|
||
/* MADNESS_CARD_EXILED,
|
||
targetId id of the card with madness
|
||
sourceId original id of the madness ability
|
||
playerId controller of the card
|
||
*/
|
||
MADNESS_CARD_EXILED,
|
||
INVESTIGATED, // playerId is the player who investigated
|
||
KICKED,
|
||
/* DISCARD_CARD
|
||
flag event is result of effect (1) or result of cost (0)
|
||
*/
|
||
DISCARD_CARD,
|
||
DISCARDED_CARD,
|
||
DISCARDED_CARDS,
|
||
CYCLE_CARD, CYCLED_CARD, CYCLE_DRAW,
|
||
/* CLASHED (one event fired for each player involved)
|
||
playerId the id of the clashing player
|
||
flag true = playerId won the clash
|
||
targetId the id of the other player in the clash
|
||
*/
|
||
CLASH, CLASHED,
|
||
DAMAGE_PLAYER,
|
||
|
||
/* MILL_CARDS
|
||
playerId the id of the player milling the card (not the source's controller)
|
||
targetId the id of the card milled
|
||
*/
|
||
MILL_CARDS,
|
||
/* MILLED_CARDS
|
||
playerId the id of the player milling the card (not the source's controller)
|
||
targetId the id of the card milled
|
||
*/
|
||
MILLED_CARD,
|
||
/* MILLED_CARDS_BATCH_FOR_ONE_PLAYER,
|
||
combines all MILLED_CARD events for a player milling card at the same time in a single batch
|
||
playerId the id of the player whose batch it is
|
||
*/
|
||
MILLED_CARDS_BATCH_FOR_ONE_PLAYER(true),
|
||
/* MILLED_CARDS_BATCH_FOR_ALL,
|
||
combines all MILLED_CARD events for any player in a single batch
|
||
*/
|
||
MILLED_CARDS_BATCH_FOR_ALL(true),
|
||
|
||
/* DAMAGED_PLAYER
|
||
targetId the id of the damaged player
|
||
sourceId sourceId of the ability which caused the damage
|
||
playerId the id of the damaged player
|
||
amount amount of damage
|
||
flag true = combat damage - other damage = false
|
||
*/
|
||
DAMAGED_PLAYER,
|
||
|
||
/* DAMAGED_BATCH_FOR_PLAYERS,
|
||
combines all player damage events to a single batch (event)
|
||
*/
|
||
DAMAGED_BATCH_FOR_PLAYERS(true),
|
||
|
||
/* DAMAGED_BATCH_FOR_ONE_PLAYER
|
||
combines all player damage events to a single batch (event) and split it per damaged player
|
||
targetId the id of the damaged player (playerId won't work for batch)
|
||
*/
|
||
DAMAGED_BATCH_FOR_ONE_PLAYER(true),
|
||
/* DAMAGED_BATCH_BY_SOURCE
|
||
combine all damage events from a single source to a single batch (event)
|
||
*/
|
||
DAMAGED_BATCH_BY_SOURCE(true),
|
||
/* DAMAGED_BATCH_FOR_ALL
|
||
includes all damage events, both permanent damage and player damage, in single batch event
|
||
*/
|
||
DAMAGED_BATCH_FOR_ALL(true),
|
||
/* DAMAGED_BATCH_FIRED
|
||
* Does not contain any info on damage events, and can fire even when all damage is prevented.
|
||
* Fire any time a DAMAGED_BATCH_FOR_ALL could have fired (combat & noncombat).
|
||
* It is not a batch event (doesn't contain sub events), the name is a little ambiguous.
|
||
*/
|
||
DAMAGED_BATCH_COULD_HAVE_FIRED,
|
||
|
||
/* DAMAGE_CAUSES_LIFE_LOSS,
|
||
targetId the id of the damaged player
|
||
sourceId sourceId of the ability which caused the damage, can be null for default events like combat
|
||
playerId the id of the damaged player
|
||
amount amount of damage
|
||
flag is it combat damage
|
||
*/
|
||
DAMAGE_CAUSES_LIFE_LOSS,
|
||
PLAYER_LIFE_CHANGE,
|
||
GAIN_LIFE, GAINED_LIFE,
|
||
/* LOSE_LIFE + LOST_LIFE
|
||
targetId the id of the player loosing life
|
||
sourceId sourceId of the ability which caused the lose
|
||
playerId the id of the player loosing life
|
||
amount amount of life loss
|
||
flag true = from combat damage - other from non combat damage
|
||
*/
|
||
|
||
LOSE_LIFE, LOST_LIFE,
|
||
/* LOST_LIFE_BATCH_FOR_ONE_PLAYER
|
||
combines all life lost events for a player to a single batch (event)
|
||
*/
|
||
LOST_LIFE_BATCH_FOR_ONE_PLAYER(true),
|
||
/* LOST_LIFE_BATCH
|
||
combines all player life lost events to a single batch (event)
|
||
*/
|
||
LOST_LIFE_BATCH(true),
|
||
|
||
PLAY_LAND, LAND_PLAYED,
|
||
CREATURE_CHAMPIONED,
|
||
/* CREATURE_CHAMPIONED
|
||
targetId the id of the creature that was championed
|
||
sourceId sourceId of the creature using the champion ability
|
||
playerId the id of the controlling player
|
||
*/
|
||
CREW_VEHICLE,
|
||
/* CREW_VEHICLE
|
||
targetId the id of the creature that will crew a vehicle
|
||
sourceId sourceId of the vehicle
|
||
playerId the id of the controlling player
|
||
*/
|
||
CREWED_VEHICLE,
|
||
/* CREWED_VEHICLE
|
||
targetId the id of the creature that crewed a vehicle
|
||
sourceId sourceId of the vehicle
|
||
playerId the id of the controlling player
|
||
*/
|
||
VEHICLE_CREWED,
|
||
/* VEHICLE_CREWED
|
||
targetId the id of the vehicle
|
||
sourceId sourceId of the vehicle
|
||
playerId the id of the controlling player
|
||
*/
|
||
SADDLE_MOUNT,
|
||
/* SADDLE_MOUNT
|
||
targetId the id of the creature that will saddle a mount
|
||
sourceId sourceId of the mount
|
||
playerId the id of the controlling player
|
||
*/
|
||
SADDLED_MOUNT,
|
||
/* SADDLED_MOUNT
|
||
targetId the id of the creature that saddled a mount
|
||
sourceId sourceId of the mount
|
||
playerId the id of the controlling player
|
||
*/
|
||
MOUNT_SADDLED,
|
||
/* MOUNT_SADDLED
|
||
targetId the id of the mount
|
||
sourceId sourceId of the mount
|
||
playerId the id of the controlling player
|
||
*/
|
||
STATION_PERMANENT,
|
||
/* STATION_PERMANENT
|
||
targetId the id of the creature stationing
|
||
sourceId sourceId of the spaceship or planet
|
||
playerId the id of the controlling player
|
||
amount how many counters are being added
|
||
*/
|
||
CAST_SPELL,
|
||
CAST_SPELL_LATE,
|
||
/* SPELL_CAST, CAST_SPELL_LATE
|
||
targetId id of the spell that's try to cast
|
||
sourceId sourceId of the spell that's try to cast
|
||
playerId player that try to cast the spell
|
||
amount not used for this event
|
||
flag not used for this event
|
||
zone zone the spell is cast from (main card)
|
||
*/
|
||
SPELL_CAST,
|
||
/* SPELL_CAST
|
||
targetId id of the spell that's cast
|
||
sourceId sourceId of the spell that's cast
|
||
playerId player that casts the spell
|
||
amount not used for this event
|
||
flag not used for this event
|
||
zone zone the spell is cast from
|
||
*/
|
||
ACTIVATE_ABILITY, ACTIVATED_ABILITY,
|
||
/* ACTIVATE_ABILITY, ACTIVATED_ABILITY,
|
||
WARNING, do not use choose dialogs inside, can be calls multiple types, e.g. on playable checking
|
||
targetId id of the ability to activate / use
|
||
sourceId sourceId of the object with that ability
|
||
playerId player that tries to use this ability
|
||
*/
|
||
TAKE_SPECIAL_ACTION, TAKEN_SPECIAL_ACTION,
|
||
/* TAKE_SPECIAL_ACTION, TAKEN_SPECIAL_ACTION,
|
||
targetId id of the ability to activate / use
|
||
sourceId sourceId of the object with that ability
|
||
playerId player that tries to use this ability
|
||
*/
|
||
TAKE_SPECIAL_MANA_PAYMENT, TAKEN_SPECIAL_MANA_PAYMENT,
|
||
/* TAKE_SPECIAL_MANA_PAYMENT, TAKEN_SPECIAL_MANA_PAYMENT
|
||
targetId id of the ability to activate / use
|
||
sourceId sourceId of the object with that ability
|
||
playerId player that tries to use this ability
|
||
*/
|
||
TRIGGERED_ABILITY,
|
||
RESOLVING_ABILITY,
|
||
/* COPY_STACKOBJECT
|
||
targetId id of the spell/ability to copy
|
||
sourceId id of the object with copy ability
|
||
playerId id of the player who will be control new copied spell/ability
|
||
amount number on copies
|
||
*/
|
||
COPY_STACKOBJECT,
|
||
/* COPIED_STACKOBJECT, TODO: make same logic in params for COPY_STACKOBJECT and COPIED_STACKOBJECT
|
||
targetId id of the new copied spell/ability
|
||
sourceId id of the spell/ability to copy
|
||
playerId id of the player who will be control new copied spell/ability
|
||
*/
|
||
COPIED_STACKOBJECT,
|
||
/* ADD_MANA
|
||
targetId id of the ability that added the mana
|
||
sourceId sourceId of the ability that added the mana
|
||
playerId player the mana is added to the mana pool for
|
||
mana the mana added
|
||
*/
|
||
ADD_MANA,
|
||
/* MANA_ADDED
|
||
targetId id of the ability that added the mana
|
||
sourceId sourceId of the ability that added the mana
|
||
playerId player the mana is added to the mana pool for
|
||
mana the mana added
|
||
*/
|
||
MANA_ADDED,
|
||
/* MANA_PAID
|
||
targetId id if the ability the mana was paid for (not the sourceId)
|
||
sourceId sourceId of the mana source
|
||
playerId controller of the ability the mana was paid for
|
||
amount not used for this event
|
||
flag indicates a special condition of mana
|
||
data originalId of the mana producing ability as string (converted from UUID)
|
||
*/
|
||
MANA_PAID,
|
||
LOSES, LOST, WINS, DRAW_PLAYER,
|
||
/* TARGET
|
||
targetId id of the targeting card
|
||
sourceId id of the ability's object that try to targeting
|
||
playerId player who try to targeting (can be different from source ability's controller)
|
||
TODO: BUT there is isLegal(Ability source, Game game) code and it uses only source ability's controller,
|
||
so some abilities can be fizzled on resolve cause no legal targets?
|
||
amount not used for this event
|
||
*/
|
||
TARGET, TARGETED,
|
||
/* TARGETS_VALID
|
||
targetId id of the spell or id of stack ability the targets were set to
|
||
sourceId = targetId
|
||
playerId controller of the spell or stack ability
|
||
amount not used for this event
|
||
*/
|
||
TARGETS_VALID,
|
||
/* COUNTER
|
||
targetId id of the spell or id of stack ability
|
||
sourceId sourceId of the ability countering the spell or stack ability
|
||
playerId controller of the countered spell or stack ability
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
COUNTER,
|
||
COUNTERED,
|
||
DECLARING_ATTACKERS, DECLARED_ATTACKERS,
|
||
/* DECLARE_ATTACKER
|
||
REPLACE EVENT - can be used to replace attack declaration
|
||
targetId id of the defending player or planeswalker attacked
|
||
sourceId id of the attacking creature
|
||
playerId player defining the attacking creatures
|
||
*/
|
||
DECLARE_ATTACKER,
|
||
/* ATTACKER_DECLARED
|
||
targetId id of the defending player or planeswalker attacked
|
||
sourceId id of the attacking creature
|
||
playerId player defining the attacking creatures
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
ATTACKER_DECLARED,
|
||
/* DECLARING_BLOCKERS
|
||
targetId attackerId
|
||
sourceId not used for this event
|
||
playerId attackerId
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
DEFENDER_ATTACKED,
|
||
DECLARING_BLOCKERS,
|
||
DECLARED_BLOCKERS,
|
||
DECLARE_BLOCKER,
|
||
|
||
/* BLOCKER_DECLARED
|
||
raise one time for each declared blocker (e.g. multiple events per attacker allows)
|
||
|
||
warning, must use for rules: becomes blocked by a creature
|
||
|
||
rules ref:
|
||
Acolyte of the Inferno’s last ability will trigger once for each creature that blocks it.
|
||
Each of those creatures will be dealt 2 damage.
|
||
(2015-06-22)
|
||
|
||
targetId attacker id
|
||
sourceId blocker id
|
||
playerId blocker controller id
|
||
*/
|
||
BLOCKER_DECLARED,
|
||
|
||
/* CREATURE_BLOCKED
|
||
raise one time per attacker (e.g. only one event per attacker allows)
|
||
|
||
warning, must use for rules: xxx becomes blocked,
|
||
|
||
rules ref:
|
||
Rakdos Roustabout
|
||
An ability that triggers when a creature becomes blocked triggers only once
|
||
if two or more creatures block it.
|
||
(2019-01-25)
|
||
|
||
targetId attacker id
|
||
sourceId not used for this event
|
||
playerId not used for this event
|
||
*/
|
||
CREATURE_BLOCKED,
|
||
|
||
CREATURE_BLOCKS,
|
||
BATCH_BLOCK_NONCOMBAT,
|
||
UNBLOCKED_ATTACKER,
|
||
SEARCH_LIBRARY, LIBRARY_SEARCHED,
|
||
SHUFFLE_LIBRARY, LIBRARY_SHUFFLED,
|
||
ENCHANT_PLAYER, ENCHANTED_PLAYER,
|
||
CAN_TAKE_MULLIGAN,
|
||
SCRY, SCRIED, SCRY_TO_BOTTOM,
|
||
SURVEIL, SURVEILED,
|
||
PROLIFERATE, PROLIFERATED,
|
||
FATESEALED,
|
||
FLIP_COIN, FLIP_COINS, COIN_FLIPPED,
|
||
REPLACE_ROLLED_DIE, // for Clam-I-Am workaround only
|
||
ROLL_DIE, DIE_ROLLED,
|
||
ROLL_DICE, DICE_ROLLED,
|
||
PLANESWALK, PLANESWALKED,
|
||
PAID_CUMULATIVE_UPKEEP,
|
||
DIDNT_PAY_CUMULATIVE_UPKEEP,
|
||
PAY_LIFE, LIFE_PAID,
|
||
CASCADE_LAND,
|
||
LEARN,
|
||
//permanent events
|
||
ENTERS_THE_BATTLEFIELD_SELF, /* 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15),
|
||
one of them must be chosen. If not, proceed to rule 616.1b. */
|
||
ENTERS_THE_BATTLEFIELD_CONTROL, // 616.1b
|
||
ENTERS_THE_BATTLEFIELD_COPY, // 616.1c
|
||
ENTERS_THE_BATTLEFIELD, // 616.1d
|
||
TAP,
|
||
/* TAPPED,
|
||
targetId tapped permanent
|
||
sourceId id of the ability's source (can be null for standard tap actions like combat)
|
||
playerId source's controller, null if no source
|
||
amount not used for this event
|
||
flag is it tapped for combat
|
||
*/
|
||
TAPPED,
|
||
/* TAPPED_FOR_MANA
|
||
During calculation of the available mana for a player the "TappedForMana" event is fired to simulate triggered mana production.
|
||
By checking the inCheckPlayableState these events are handled to give back only the available mana of instead really producing mana.
|
||
IMPORTANT: Triggered non mana abilities have to ignore the event if game.inCheckPlayableState is true.
|
||
*/
|
||
TAPPED_FOR_MANA,
|
||
/* TAPPED_BATCH
|
||
combine all TAPPED events occuring at the same time in a single event
|
||
*/
|
||
TAPPED_BATCH(true),
|
||
UNTAP,
|
||
/* UNTAPPED,
|
||
targetId untapped permanent
|
||
sourceId not used for this event // TODO: add source for untap?
|
||
playerId controller of permanent // TODO: replace by source controller of untap? need to check every usage if so.
|
||
amount not used for this event
|
||
flag true if untapped during untap step (event is checked at upkeep so can't trust the current Phase)
|
||
*/
|
||
UNTAPPED,
|
||
/* UNTAPPED_BATCH
|
||
combine all UNTAPPED events occuring at the same time in a single event
|
||
*/
|
||
UNTAPPED_BATCH(true),
|
||
FLIP, FLIPPED,
|
||
TRANSFORMING, TRANSFORMED,
|
||
ADAPT,
|
||
BECOMES_MONSTROUS,
|
||
/* BECOMES_EXERTED
|
||
targetId id of the exerted creature
|
||
sourceId sourceId of the ability that triggered the event (do exert)
|
||
playerId player who makes the exert (can be different from permanent's controller)
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
BECOMES_EXERTED,
|
||
BECOMES_RENOWNED,
|
||
GAINS_CLASS_LEVEL,
|
||
/* CREATURE_ENLISTED
|
||
targetId id of the enlisted creature
|
||
sourceId id of the creature that enlisted
|
||
playerId player who controls the creatures
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
CREATURE_ENLISTED,
|
||
/* BECOMES_MONARCH
|
||
targetId playerId of the player that becomes the monarch
|
||
sourceId id of the source object that created that effect, if no effect exist it's null
|
||
playerId playerId of the player that becomes the monarch
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
BECOME_MONARCH,
|
||
BECOMES_MONARCH,
|
||
TOOK_INITIATIVE,
|
||
BECOMES_DAY_NIGHT,
|
||
MEDITATED,
|
||
PHASE_OUT, PHASED_OUT,
|
||
PHASE_IN, PHASED_IN,
|
||
TURN_FACE_UP, TURNED_FACE_UP,
|
||
TURN_FACE_DOWN, TURNED_FACE_DOWN,
|
||
MANIFESTED_DREAD,
|
||
/* OPTION_USED
|
||
targetId originalId of the ability that triggered the event
|
||
sourceId sourceId of the ability that triggered the event
|
||
playerId controller of the ability
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
OPTION_USED,
|
||
|
||
DAMAGE_PERMANENT,
|
||
DAMAGED_PERMANENT,
|
||
|
||
/* DAMAGED_BATCH_FOR_PERMANENTS
|
||
combine all permanent damage events to a single batch (event)
|
||
*/
|
||
DAMAGED_BATCH_FOR_PERMANENTS(true),
|
||
|
||
/* DAMAGED_BATCH_FOR_ONE_PERMANENT
|
||
combines all permanent damage events to a single batch (event) and split it per damaged permanent
|
||
*/
|
||
DAMAGED_BATCH_FOR_ONE_PERMANENT(true),
|
||
REMOVE_DAMAGE_EOT,
|
||
|
||
DESTROY_PERMANENT,
|
||
/* DESTROYED_PERMANENT
|
||
targetId id of the destroyed creature
|
||
sourceId sourceId of the ability with the destroy effect
|
||
playerId controller of the creature
|
||
amount not used for this event
|
||
flag true if no regeneration is allowed
|
||
*/
|
||
DESTROYED_PERMANENT,
|
||
SACRIFICE_PERMANENT, SACRIFICED_PERMANENT, SACRIFICED_PERMANENT_BATCH(true),
|
||
FIGHTED_PERMANENT,
|
||
BATCH_FIGHT,
|
||
EXPLOITED_CREATURE,
|
||
EVOLVED_CREATURE,
|
||
EMBALMED_CREATURE,
|
||
ETERNALIZED_CREATURE,
|
||
ATTACH, ATTACHED,
|
||
UNATTACH, UNATTACHED,
|
||
/* ATTACH, ATTACHED,
|
||
UNATTACH, UNATTACHED,
|
||
targetId id of the permanent who get/lose attachment
|
||
sourceId id of the attachment
|
||
playerId player who control the attachment
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
STAY_ATTACHED,
|
||
ADD_COUNTER, COUNTER_ADDED,
|
||
ADD_COUNTERS, COUNTERS_ADDED,
|
||
/* REMOVE_COUNTER, REMOVE_COUNTERS, COUNTER_REMOVED, COUNTERS_REMOVED
|
||
targetId id of the permanent or player losing counter(s)
|
||
sourceId id of the ability removing them
|
||
playerId player who controls the ability removing the counters
|
||
amount number of counters being removed
|
||
data name of the counter(s) being removed
|
||
*/
|
||
REMOVE_COUNTER, COUNTER_REMOVED,
|
||
REMOVE_COUNTERS, COUNTERS_REMOVED,
|
||
LOSE_CONTROL,
|
||
/* LOST_CONTROL
|
||
targetId id of the creature that lost control
|
||
sourceId null
|
||
playerId player that controls the creature before
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
LOST_CONTROL,
|
||
/* GAIN_CONTROL
|
||
targetId id of the permanent that trying to get control
|
||
sourceId null
|
||
playerId new player that try to get control of permanent
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
GAIN_CONTROL,
|
||
/* GAINED_CONTROL
|
||
targetId id of the permanent that got control
|
||
sourceId null
|
||
playerId new player that got control of permanent
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
GAINED_CONTROL,
|
||
CREATE_TOKEN, CREATED_TOKEN, CREATED_TOKENS,
|
||
/* REGENERATE
|
||
targetId id of the creature to regenerate
|
||
sourceId sourceId of the effect doing the regeneration
|
||
playerId controller of the creature
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
REGENERATE,
|
||
REGENERATED,
|
||
CHANGE_COLOR, COLOR_CHANGED,
|
||
NUMBER_OF_TRIGGERS,
|
||
//combat events
|
||
COMBAT_DAMAGE_APPLIED,
|
||
SELECTED_ATTACKER, SELECTED_BLOCKER,
|
||
/* voting
|
||
targetId player who voting
|
||
sourceId sourceId of the effect doing the voting
|
||
playerId player who deciding about voting, can be changed by replace events
|
||
amount not used for this event
|
||
flag not used for this event
|
||
*/
|
||
VOTE, VOTED,
|
||
/* dungeons
|
||
targetId id of the room
|
||
sourceId sourceId of the ability causing player to venture
|
||
playerId player in the dungeon
|
||
*/
|
||
ROOM_ENTERED,
|
||
VENTURE, VENTURED,
|
||
DUNGEON_COMPLETED,
|
||
TEMPTED_BY_RING, RING_BEARER_CHOSEN,
|
||
REMOVED_FROM_COMBAT, // targetId id of permanent removed from combat
|
||
/* card foretold
|
||
targetId id of card foretold
|
||
playerId id of player foretelling card
|
||
flag true if player did foretell, false if became foretold without foretell
|
||
*/
|
||
CARD_FORETOLD,
|
||
/* villainous choice
|
||
targetId player making the choice
|
||
sourceId sourceId of the ability forcing the choice
|
||
playerId controller of the ability forcing the choice
|
||
amount number of times choice is repeated
|
||
flag not used for this event
|
||
*/
|
||
FACE_VILLAINOUS_CHOICE,
|
||
/* DISCOVER
|
||
targetId not used for this event
|
||
sourceId sourceId of the ability discovering
|
||
playerId controller of the ability
|
||
amount discover value
|
||
flag not used for this event
|
||
*/
|
||
DISCOVERED,
|
||
/* Exiled while crafting (see Market Gnome)
|
||
targetId the permanent exiled
|
||
sourceId of the craft ability
|
||
playerId the player crafting
|
||
*/
|
||
EXILED_WHILE_CRAFTING,
|
||
/* Solving a Case
|
||
targetId the permanent being solved
|
||
sourceId of the ability solving
|
||
playerId the player solving
|
||
*/
|
||
SOLVE_CASE, CASE_SOLVED,
|
||
/* Become suspected
|
||
targetId the permanent being suspected
|
||
sourceId of the ability suspecting
|
||
playerId the player suspecting
|
||
*/
|
||
BECOME_SUSPECTED,
|
||
/* Evidence collected
|
||
targetId same as sourceId
|
||
sourceId of the ability for the cost
|
||
playerId the player paying the cost
|
||
*/
|
||
EVIDENCE_COLLECTED,
|
||
/* Mentored Creature
|
||
targetId creature that was mentored
|
||
sourceId of the mentor ability
|
||
playerId controller of the creature mentoring
|
||
*/
|
||
MENTORED_CREATURE,
|
||
/* the card becomes plotted
|
||
targetId card that was plotted
|
||
sourceId of the plotting ability (may be the card itself or another one)
|
||
playerId owner of the plotted card (the one able to cast the card)
|
||
*/
|
||
BECOME_PLOTTED,
|
||
/* the player foraged
|
||
targetId same as sourceId
|
||
sourceId of the ability
|
||
playerId player who foraged
|
||
*/
|
||
FORAGED,
|
||
/* gave a gift
|
||
targetId the player who received the gift
|
||
sourceId of the ability
|
||
playerId player who gave the gift
|
||
*/
|
||
GAVE_GIFT,
|
||
/* rad counter life loss/gain effect
|
||
*/
|
||
RADIATION_GAIN_LIFE,
|
||
/* for checking sacrifice as a cost
|
||
targetId the permanent to be sacrificed
|
||
sourceId of the ability
|
||
playerId controller of ability
|
||
data id of the ability being paid for
|
||
*/
|
||
PAY_SACRIFICE_COST,
|
||
EARTHBENDED,
|
||
AIRBENDED,
|
||
FIREBENDED,
|
||
WATERBENDED,
|
||
/* A room permanent has a door unlocked.
|
||
targetId the room permanent
|
||
sourceId the unlock ability
|
||
playerId the room permanent's controller
|
||
flag true = left door unlocked false = right door unlocked
|
||
*/
|
||
DOOR_UNLOCKED,
|
||
/* A room permanent has a door unlocked.
|
||
targetId the room permanent
|
||
sourceId the unlock ability
|
||
playerId the room permanent's controller
|
||
*/
|
||
ROOM_FULLY_UNLOCKED,
|
||
// custom events - must store some unique data to track
|
||
CUSTOM_EVENT;
|
||
|
||
private final boolean isBatch;
|
||
|
||
EventType() {
|
||
this(false);
|
||
}
|
||
|
||
EventType(boolean isBatch) {
|
||
this.isBatch = isBatch;
|
||
}
|
||
|
||
public boolean isBatch() {
|
||
return isBatch;
|
||
}
|
||
}
|
||
|
||
public GameEvent(EventType type, UUID targetId, Ability source, UUID playerId) {
|
||
this(type, targetId, source, playerId, 0, false, null);
|
||
}
|
||
|
||
public GameEvent(EventType type, UUID targetId, Ability source, UUID playerId, ApprovingObject approvingObject) {
|
||
this(type, targetId, source, playerId, 0, false, approvingObject);
|
||
}
|
||
|
||
public GameEvent(EventType type, UUID targetId, Ability source, UUID playerId, int amount, boolean flag) {
|
||
this(type, targetId, source, playerId, amount, flag, null);
|
||
}
|
||
|
||
public static GameEvent getEvent(EventType type, UUID targetId, Ability source, UUID playerId, int amount) {
|
||
return new GameEvent(type, targetId, source, playerId, amount, false);
|
||
}
|
||
|
||
public static GameEvent getEvent(EventType type, UUID targetId, Ability source, UUID playerId) {
|
||
return new GameEvent(type, targetId, source, playerId);
|
||
}
|
||
|
||
public static GameEvent getEvent(EventType type, UUID targetId, Ability source, UUID playerId, ApprovingObject approvingObject) {
|
||
return new GameEvent(type, targetId, source, playerId, approvingObject);
|
||
}
|
||
|
||
@Deprecated // usage must be replaced by getEvent with source ability
|
||
public static GameEvent getEvent(EventType type, UUID targetId, UUID playerId) {
|
||
return new GameEvent(type, targetId, null, playerId);
|
||
}
|
||
|
||
public static GameEvent getEvent(EventType type, UUID targetId, Ability source, UUID playerId, String data, int amount) {
|
||
GameEvent event = getEvent(type, targetId, source, playerId);
|
||
event.setAmount(amount);
|
||
event.setData(data);
|
||
return event;
|
||
}
|
||
|
||
private GameEvent(EventType type, UUID targetId, Ability source, UUID playerId,
|
||
int amount, boolean flag, ApprovingObject approvingObject
|
||
) {
|
||
this.type = type;
|
||
this.targetId = targetId;
|
||
this.sourceId = source == null ? null : source.getSourceId(); // We only keep the sourceId from the whole source.
|
||
this.amount = amount;
|
||
this.playerId = playerId;
|
||
this.flag = flag;
|
||
this.approvingObject = approvingObject;
|
||
this.id = UUID.randomUUID();
|
||
}
|
||
|
||
public EventType getType() {
|
||
return type;
|
||
}
|
||
|
||
public UUID getId() {
|
||
return id;
|
||
}
|
||
|
||
/**
|
||
* Some batch events can contain multiple events list, see BatchGameEvent for usage
|
||
*/
|
||
public UUID getTargetId() {
|
||
return targetId;
|
||
}
|
||
|
||
public void setTargetId(UUID targetId) {
|
||
this.targetId = targetId;
|
||
}
|
||
|
||
public UUID getSourceId() {
|
||
return sourceId;
|
||
}
|
||
|
||
public void setPlayerId(UUID playerId) {
|
||
this.playerId = playerId;
|
||
}
|
||
|
||
public UUID getPlayerId() {
|
||
return playerId;
|
||
}
|
||
|
||
public int getAmount() {
|
||
return amount;
|
||
}
|
||
|
||
public void setAmount(int amount) {
|
||
this.amount = amount;
|
||
}
|
||
|
||
public void setAmountForCounters(int amount, boolean isEffect) {
|
||
this.amount = amount;
|
||
|
||
// cost event must be "transformed" to effect event, as example:
|
||
// planeswalker's +1 cost will be affected by Pir, Imaginative Rascal (1 + 1) and applied as effect by Doubling Season (2 * 2)
|
||
// https://github.com/magefree/mage/issues/5802
|
||
if (isEffect) {
|
||
setFlag(true);
|
||
}
|
||
}
|
||
|
||
public boolean getFlag() {
|
||
return flag;
|
||
}
|
||
|
||
public void setFlag(boolean flag) {
|
||
this.flag = flag;
|
||
}
|
||
|
||
public String getData() {
|
||
return data;
|
||
}
|
||
|
||
public void setData(String data) {
|
||
this.data = data;
|
||
}
|
||
|
||
public Zone getZone() {
|
||
return zone;
|
||
}
|
||
|
||
public void setZone(Zone zone) {
|
||
this.zone = zone;
|
||
}
|
||
|
||
/**
|
||
* Returns possibly approving object that allowed the creation of the event. Used for cast spell and play land events.
|
||
*/
|
||
public ApprovingObject getApprovingObject() {
|
||
return approvingObject;
|
||
}
|
||
|
||
/**
|
||
* used to store which replacement effects were already applied to an event
|
||
* or any modified events that may replace it
|
||
* <p>
|
||
* 614.5. A replacement effect doesn't invoke itself repeatedly; it gets
|
||
* only one opportunity to affect an event or any modified events that may
|
||
* replace it. Example: A player controls two permanents, each with an
|
||
* ability that reads "If a creature you control would deal damage to a
|
||
* creature or player, it deals double that damage to that creature or
|
||
* player instead." A creature that normally deals 2 damage will deal 8
|
||
* damage--not just 4, and not an infinite amount.
|
||
*/
|
||
public List<UUID> getAppliedEffects() {
|
||
return appliedEffects;
|
||
}
|
||
|
||
public void addAppliedEffects(List<UUID> appliedEffects) {
|
||
if (appliedEffects != null) {
|
||
this.appliedEffects.addAll(appliedEffects);
|
||
}
|
||
}
|
||
|
||
public void setAppliedEffects(List<UUID> appliedEffects) {
|
||
if (appliedEffects != null) {
|
||
if (this.appliedEffects.isEmpty()) {
|
||
this.appliedEffects = appliedEffects; // Use object reference to handle that an replacement effect can only be once applied to an event
|
||
} else {
|
||
this.appliedEffects.addAll(appliedEffects);
|
||
}
|
||
}
|
||
}
|
||
|
||
public boolean hasApprovingIdentifier(MageIdentifier identifier) {
|
||
if (approvingObject == null) {
|
||
return false;
|
||
}
|
||
if (identifier.equals(MageIdentifier.Default)) {
|
||
return false;
|
||
}
|
||
return identifier.equals(approvingObject.getApprovingAbility().getIdentifier());
|
||
}
|
||
|
||
/**
|
||
* Custom sourceId setup for some events (use it in constructor).
|
||
* TODO: replace all custom sourceId to normal event classes
|
||
* for now, having the setter helps find all that do not provide an Ability source,
|
||
* so keeping it is worthwhile until a thoughtful cleanup.
|
||
*/
|
||
protected void setSourceId(UUID sourceId) {
|
||
this.sourceId = sourceId;
|
||
}
|
||
|
||
@Override
|
||
public String toString() {
|
||
return this.type.toString();
|
||
}
|
||
}
|