mirror of
https://github.com/magefree/mage.git
synced 2025-12-28 22:42:03 -08:00
Refactor batch events (#11995)
* create new abstract class for batch event framework * adjust CardUtil.getEventTargets to support new framework * update TappedBatchEvent to new framework * update UntappedBatchEvent to new framework * slight cleanup * update LifeLostBatchEvent to new framework * update ZoneChangeBatchEvent to new framework * complete refactor by moving damage events to new framework * remove old code no longer used * clean up some nonsense code in star wars card * fix watcher checking id before event type * fix wrong id usage * fix missed wrong id usage
This commit is contained in:
parent
8869d282b2
commit
cb28fb5a56
39 changed files with 308 additions and 635 deletions
|
|
@ -40,7 +40,7 @@ public class BecomesTappedOneOrMoreTriggeredAbility extends TriggeredAbilityImpl
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
TappedBatchEvent batchEvent = (TappedBatchEvent) event;
|
||||
return batchEvent
|
||||
.getTargets()
|
||||
.getTargetIds()
|
||||
.stream()
|
||||
.map(game::getPermanent)
|
||||
.anyMatch(p -> filter.match(p, getControllerId(), this, game));
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import mage.abilities.TriggeredAbilityImpl;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedBatchEvent;
|
||||
import mage.game.events.DamagedBatchAllEvent;
|
||||
import mage.game.events.DamagedEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
|
@ -14,21 +14,17 @@ import mage.game.permanent.Permanent;
|
|||
*/
|
||||
public class DealsCombatDamageEquippedTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private boolean usedThisStep;
|
||||
|
||||
public DealsCombatDamageEquippedTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public DealsCombatDamageEquippedTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.usedThisStep = false;
|
||||
setTriggerPhrase("Whenever equipped creature deals combat damage, ");
|
||||
}
|
||||
|
||||
protected DealsCombatDamageEquippedTriggeredAbility(final DealsCombatDamageEquippedTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.usedThisStep = ability.usedThisStep;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -38,23 +34,16 @@ public class DealsCombatDamageEquippedTriggeredAbility extends TriggeredAbilityI
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event instanceof DamagedBatchEvent || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRE;
|
||||
return event.getType() == GameEvent.EventType.DAMAGED_BATCH_FOR_ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRE) {
|
||||
usedThisStep = false; // clear before damage
|
||||
return false;
|
||||
}
|
||||
if (usedThisStep || !(event instanceof DamagedBatchEvent)) {
|
||||
return false; // trigger only on DamagedEvent and if not yet triggered this step
|
||||
}
|
||||
Permanent sourcePermanent = getSourcePermanentOrLKI(game);
|
||||
if (sourcePermanent == null || sourcePermanent.getAttachedTo() == null) {
|
||||
return false;
|
||||
}
|
||||
int amount = ((DamagedBatchEvent) event)
|
||||
int amount = ((DamagedBatchAllEvent) event)
|
||||
.getEvents()
|
||||
.stream()
|
||||
.filter(DamagedEvent::isCombatDamage)
|
||||
|
|
@ -64,11 +53,7 @@ public class DealsCombatDamageEquippedTriggeredAbility extends TriggeredAbilityI
|
|||
if (amount < 1) {
|
||||
return false;
|
||||
}
|
||||
usedThisStep = true;
|
||||
this.getEffects().setValue("damage", amount);
|
||||
// TODO: this value saved will not be correct if both permanent and player damaged by a single creature
|
||||
// Need to rework engine logic to fire a single DamagedBatchEvent including both permanents and players
|
||||
// Only Sword of Hours is currently affected.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import mage.abilities.TriggeredAbilityImpl;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedBatchEvent;
|
||||
import mage.game.events.DamagedBatchAllEvent;
|
||||
import mage.game.events.DamagedEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
|
|
@ -17,18 +17,14 @@ import mage.game.events.GameEvent;
|
|||
*/
|
||||
public class DealsCombatDamageTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private boolean usedThisStep;
|
||||
|
||||
public DealsCombatDamageTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.usedThisStep = false;
|
||||
setTriggerPhrase(getWhen() + "{this} deals combat damage, ");
|
||||
this.replaceRuleText = true;
|
||||
}
|
||||
|
||||
protected DealsCombatDamageTriggeredAbility(final DealsCombatDamageTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.usedThisStep = ability.usedThisStep;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -38,33 +34,22 @@ public class DealsCombatDamageTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event instanceof DamagedBatchEvent || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRE;
|
||||
return event.getType() == GameEvent.EventType.DAMAGED_BATCH_FOR_ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRE) {
|
||||
usedThisStep = false; // clear before damage
|
||||
return false;
|
||||
}
|
||||
if (usedThisStep || !(event instanceof DamagedBatchEvent)) {
|
||||
return false; // trigger only on DamagedEvent and if not yet triggered this step
|
||||
}
|
||||
int amount = ((DamagedBatchEvent) event)
|
||||
int amount = ((DamagedBatchAllEvent) event)
|
||||
.getEvents()
|
||||
.stream()
|
||||
.filter(DamagedEvent::isCombatDamage)
|
||||
.filter(e -> e.getAttackerId().equals(this.sourceId))
|
||||
.filter(e -> e.getAttackerId().equals(getSourceId()))
|
||||
.mapToInt(GameEvent::getAmount)
|
||||
.sum();
|
||||
if (amount < 1) {
|
||||
return false;
|
||||
}
|
||||
usedThisStep = true;
|
||||
this.getEffects().setValue("damage", amount);
|
||||
// TODO: this value saved will not be correct if both permanent and player damaged by a single creature
|
||||
// Need to rework engine logic to fire a single DamagedBatchEvent including both permanents and players
|
||||
// Only Aisha of Sparks and Smoke is currently affected.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import mage.constants.SetTargetPointer;
|
|||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedBatchEvent;
|
||||
import mage.game.events.DamagedBatchForOnePlayerEvent;
|
||||
import mage.game.events.DamagedEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
|
@ -60,7 +60,7 @@ public class OneOrMoreDealDamageTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
DamagedBatchEvent dEvent = (DamagedBatchEvent) event;
|
||||
DamagedBatchForOnePlayerEvent dEvent = (DamagedBatchForOnePlayerEvent) event;
|
||||
if (onlyCombat && !dEvent.isCombatDamage()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ public class OneOrMoreDealDamageTriggeredAbility extends TriggeredAbilityImpl {
|
|||
this.getAllEffects().setValue("damage", events.stream().mapToInt(DamagedEvent::getAmount).sum());
|
||||
switch (setTargetPointer) {
|
||||
case PLAYER:
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -808,7 +808,80 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
return !simultaneousEvents.isEmpty();
|
||||
}
|
||||
|
||||
public void addSimultaneousLifeLossEventToBatches(LifeLostEvent lifeLossEvent, Game game) {
|
||||
public void addSimultaneousDamage(DamagedEvent damagedEvent, Game game) {
|
||||
// Combine multiple damage events in the single event (batch)
|
||||
// Note: one event can be stored in multiple batches
|
||||
if (damagedEvent instanceof DamagedPlayerEvent) {
|
||||
// DAMAGED_BATCH_FOR_PLAYERS + DAMAGED_BATCH_FOR_ONE_PLAYER
|
||||
addSimultaneousDamageToPlayerBatches((DamagedPlayerEvent) damagedEvent, game);
|
||||
} else if (damagedEvent instanceof DamagedPermanentEvent) {
|
||||
// DAMAGED_BATCH_FOR_PERMANENTS + DAMAGED_BATCH_FOR_ONE_PERMANENT
|
||||
addSimultaneousDamageToPermanentBatches((DamagedPermanentEvent) damagedEvent, game);
|
||||
}
|
||||
// DAMAGED_BATCH_FOR_ALL
|
||||
addSimultaneousDamageToBatchForAll(damagedEvent, game);
|
||||
}
|
||||
|
||||
public void addSimultaneousDamageToPlayerBatches(DamagedPlayerEvent damagedPlayerEvent, Game game) {
|
||||
// find existing batches first
|
||||
boolean isTotalBatchUsed = false;
|
||||
boolean isPlayerBatchUsed = false;
|
||||
for (GameEvent event : simultaneousEvents) {
|
||||
if (event instanceof DamagedBatchForPlayersEvent) {
|
||||
((DamagedBatchForPlayersEvent) event).addEvent(damagedPlayerEvent);
|
||||
isTotalBatchUsed = true;
|
||||
} else if (event instanceof DamagedBatchForOnePlayerEvent
|
||||
&& damagedPlayerEvent.getTargetId().equals(event.getTargetId())) {
|
||||
((DamagedBatchForOnePlayerEvent) event).addEvent(damagedPlayerEvent);
|
||||
isPlayerBatchUsed = true;
|
||||
}
|
||||
}
|
||||
// new batches if necessary
|
||||
if (!isTotalBatchUsed) {
|
||||
addSimultaneousEvent(new DamagedBatchForPlayersEvent(damagedPlayerEvent), game);
|
||||
}
|
||||
if (!isPlayerBatchUsed) {
|
||||
addSimultaneousEvent(new DamagedBatchForOnePlayerEvent(damagedPlayerEvent), game);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSimultaneousDamageToPermanentBatches(DamagedPermanentEvent damagedPermanentEvent, Game game) {
|
||||
// find existing batches first
|
||||
boolean isTotalBatchUsed = false;
|
||||
boolean isSingleBatchUsed = false;
|
||||
for (GameEvent event : simultaneousEvents) {
|
||||
if (event instanceof DamagedBatchForPermanentsEvent) {
|
||||
((DamagedBatchForPermanentsEvent) event).addEvent(damagedPermanentEvent);
|
||||
isTotalBatchUsed = true;
|
||||
} else if (event instanceof DamagedBatchForOnePermanentEvent
|
||||
&& damagedPermanentEvent.getTargetId().equals(event.getTargetId())) {
|
||||
((DamagedBatchForOnePermanentEvent) event).addEvent(damagedPermanentEvent);
|
||||
isSingleBatchUsed = true;
|
||||
}
|
||||
}
|
||||
// new batches if necessary
|
||||
if (!isTotalBatchUsed) {
|
||||
addSimultaneousEvent(new DamagedBatchForPermanentsEvent(damagedPermanentEvent), game);
|
||||
}
|
||||
if (!isSingleBatchUsed) {
|
||||
addSimultaneousEvent(new DamagedBatchForOnePermanentEvent(damagedPermanentEvent), game);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSimultaneousDamageToBatchForAll(DamagedEvent damagedEvent, Game game) {
|
||||
boolean isBatchUsed = false;
|
||||
for (GameEvent event : simultaneousEvents) {
|
||||
if (event instanceof DamagedBatchAllEvent) {
|
||||
((DamagedBatchAllEvent) event).addEvent(damagedEvent);
|
||||
isBatchUsed = true;
|
||||
}
|
||||
}
|
||||
if (!isBatchUsed) {
|
||||
addSimultaneousEvent(new DamagedBatchAllEvent(damagedEvent), game);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSimultaneousLifeLossToBatch(LifeLostEvent lifeLossEvent, Game game) {
|
||||
// Combine multiple life loss events in the single event (batch)
|
||||
// see GameEvent.LOST_LIFE_BATCH
|
||||
|
||||
|
|
@ -827,69 +900,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
}
|
||||
}
|
||||
|
||||
public void addSimultaneousDamage(DamagedEvent damagedEvent, Game game) {
|
||||
// Combine multiple damage events in the single event (batch)
|
||||
// * per damage type (see GameEvent.DAMAGED_BATCH_FOR_PERMANENTS, GameEvent.DAMAGED_BATCH_FOR_PLAYERS)
|
||||
// * per player (see GameEvent.DAMAGED_BATCH_FOR_ONE_PLAYER)
|
||||
// * per permanent (see GameEvent.DAMAGED_BATCH_FOR_ONE_PERMANENT)
|
||||
//
|
||||
// Warning, one event can be stored in multiple batches,
|
||||
// example: DAMAGED_BATCH_FOR_PLAYERS + DAMAGED_BATCH_FOR_ONE_PLAYER
|
||||
|
||||
boolean isPlayerDamage = damagedEvent instanceof DamagedPlayerEvent;
|
||||
boolean isPermanentDamage = damagedEvent instanceof DamagedPermanentEvent;
|
||||
|
||||
// existing batch
|
||||
boolean isDamageBatchUsed = false;
|
||||
boolean isPlayerBatchUsed = false;
|
||||
boolean isPermanentBatchUsed = false;
|
||||
for (GameEvent event : simultaneousEvents) {
|
||||
|
||||
if (isPlayerDamage && event instanceof DamagedBatchForOnePlayerEvent) {
|
||||
// per player
|
||||
DamagedBatchForOnePlayerEvent oldPlayerBatch = (DamagedBatchForOnePlayerEvent) event;
|
||||
if (oldPlayerBatch.getDamageClazz().isInstance(damagedEvent)
|
||||
&& event.getPlayerId().equals(damagedEvent.getTargetId())) {
|
||||
oldPlayerBatch.addEvent(damagedEvent);
|
||||
isPlayerBatchUsed = true;
|
||||
}
|
||||
} else if (isPermanentDamage && event instanceof DamagedBatchForOnePermanentEvent) {
|
||||
// per permanent
|
||||
DamagedBatchForOnePermanentEvent oldPermanentBatch = (DamagedBatchForOnePermanentEvent) event;
|
||||
if (oldPermanentBatch.getDamageClazz().isInstance(damagedEvent)
|
||||
&& CardUtil.getEventTargets(event).contains(damagedEvent.getTargetId())) {
|
||||
oldPermanentBatch.addEvent(damagedEvent);
|
||||
isPermanentBatchUsed = true;
|
||||
}
|
||||
} else if ((event instanceof DamagedBatchEvent)
|
||||
&& ((DamagedBatchEvent) event).getDamageClazz().isInstance(damagedEvent)) {
|
||||
// per damage type
|
||||
// If the batch event isn't DAMAGED_BATCH_FOR_ONE_PLAYER, the targetIDs need not match,
|
||||
// since "event" is a generic batch in this case
|
||||
// (either DAMAGED_BATCH_FOR_PERMANENTS or DAMAGED_BATCH_FOR_PLAYERS)
|
||||
// Just needs to be a permanent-damaging event for DAMAGED_BATCH_FOR_PERMANENTS,
|
||||
// or a player-damaging event for DAMAGED_BATCH_FOR_PLAYERS
|
||||
((DamagedBatchEvent) event).addEvent(damagedEvent);
|
||||
isDamageBatchUsed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// new batch
|
||||
if (!isDamageBatchUsed) {
|
||||
addSimultaneousEvent(DamagedBatchEvent.makeEvent(damagedEvent), game);
|
||||
}
|
||||
if (!isPlayerBatchUsed && isPlayerDamage) {
|
||||
DamagedBatchEvent event = new DamagedBatchForOnePlayerEvent(damagedEvent);
|
||||
addSimultaneousEvent(event, game);
|
||||
}
|
||||
if (!isPermanentBatchUsed && isPermanentDamage) {
|
||||
DamagedBatchEvent event = new DamagedBatchForOnePermanentEvent(damagedEvent);
|
||||
addSimultaneousEvent(event, game);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSimultaneousTapped(TappedEvent tappedEvent, Game game) {
|
||||
public void addSimultaneousTappedToBatch(TappedEvent tappedEvent, Game game) {
|
||||
// Combine multiple tapped events in the single event (batch)
|
||||
|
||||
boolean isTappedBatchUsed = false;
|
||||
|
|
@ -904,13 +915,11 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
|
||||
// new batch
|
||||
if (!isTappedBatchUsed) {
|
||||
TappedBatchEvent batch = new TappedBatchEvent();
|
||||
batch.addEvent(tappedEvent);
|
||||
addSimultaneousEvent(batch, game);
|
||||
addSimultaneousEvent(new TappedBatchEvent(tappedEvent), game);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSimultaneousUntapped(UntappedEvent untappedEvent, Game game) {
|
||||
public void addSimultaneousUntappedToBatch(UntappedEvent untappedEvent, Game game) {
|
||||
// Combine multiple untapped events in the single event (batch)
|
||||
|
||||
boolean isUntappedBatchUsed = false;
|
||||
|
|
@ -925,9 +934,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
|
||||
// new batch
|
||||
if (!isUntappedBatchUsed) {
|
||||
UntappedBatchEvent batch = new UntappedBatchEvent();
|
||||
batch.addEvent(untappedEvent);
|
||||
addSimultaneousEvent(batch, game);
|
||||
addSimultaneousEvent(new UntappedBatchEvent(untappedEvent), game);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
101
Mage/src/main/java/mage/game/events/BatchEvent.java
Normal file
101
Mage/src/main/java/mage/game/events/BatchEvent.java
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
package mage.game.events;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Special events created by game engine to track batches of events that occur simultaneously,
|
||||
* for triggers that need such information
|
||||
* @author xenohedron
|
||||
*/
|
||||
public abstract class BatchEvent<T extends GameEvent> extends GameEvent {
|
||||
|
||||
private final Set<T> events = new HashSet<>();
|
||||
private final boolean singleTargetId;
|
||||
|
||||
/**
|
||||
* @param eventType specific type of event
|
||||
* @param singleTargetId if true, all included events must have same target id
|
||||
* @param firstEvent added to initialize the batch (batch is never empty)
|
||||
*/
|
||||
protected BatchEvent(EventType eventType, boolean singleTargetId, T firstEvent) {
|
||||
super(eventType, (singleTargetId ? firstEvent.getTargetId() : null), null, null);
|
||||
this.singleTargetId = singleTargetId;
|
||||
if (firstEvent instanceof BatchEvent) { // sanity check, if you need it then think twice and research carefully
|
||||
throw new UnsupportedOperationException("Wrong code usage: nesting batch events not supported");
|
||||
}
|
||||
this.addEvent(firstEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* For alternate event structure logic used by ZoneChangeBatchEvent, list of events starts empty.
|
||||
*/
|
||||
protected BatchEvent(EventType eventType) {
|
||||
super(eventType, null, null, null);
|
||||
this.singleTargetId = false;
|
||||
}
|
||||
|
||||
public void addEvent(T event) {
|
||||
if (singleTargetId && !getTargetId().equals(event.getTargetId())) {
|
||||
throw new IllegalStateException("Wrong code usage. Batch event initiated with single target id, but trying to add event with different target id");
|
||||
}
|
||||
this.events.add(event);
|
||||
}
|
||||
|
||||
public Set<T> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
public Set<UUID> getTargetIds() {
|
||||
return events.stream()
|
||||
.map(GameEvent::getTargetId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<UUID> getSourceIds() {
|
||||
return events.stream()
|
||||
.map(GameEvent::getSourceId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<UUID> getPlayerIds() {
|
||||
return events.stream()
|
||||
.map(GameEvent::getPlayerId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount() {
|
||||
return events
|
||||
.stream()
|
||||
.mapToInt(GameEvent::getAmount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
@Override // events can store a diff value, so search it from events list instead
|
||||
public UUID getTargetId() {
|
||||
if (singleTargetId) {
|
||||
return super.getTargetId();
|
||||
}
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list or use CardUtil.getEventTargets(event)");
|
||||
}
|
||||
|
||||
@Override // events can store a diff value, so search it from events list instead
|
||||
@Deprecated // no use case currently supported
|
||||
public UUID getSourceId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list");
|
||||
}
|
||||
|
||||
@Override // events can store a diff value, so search it from events list instead
|
||||
@Deprecated // no use case currently supported
|
||||
public UUID getPlayerId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package mage.game.events;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Game event with batch support (batch is an event that can contain multiple events, example: DAMAGED_BATCH_FOR_PLAYERS)
|
||||
* <p>
|
||||
* Used by game engine to support event lifecycle for triggers
|
||||
*
|
||||
* @author JayDi85
|
||||
*/
|
||||
public interface BatchGameEvent<T extends GameEvent> {
|
||||
|
||||
Set<T> getEvents();
|
||||
|
||||
Set<UUID> getTargets();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package mage.game.events;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class DamagedBatchAllEvent extends BatchEvent<DamagedEvent> {
|
||||
|
||||
public DamagedBatchAllEvent(DamagedEvent firstEvent) {
|
||||
super(EventType.DAMAGED_BATCH_FOR_ALL, false, firstEvent);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
package mage.game.events;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public abstract class DamagedBatchEvent extends GameEvent implements BatchGameEvent<DamagedEvent> {
|
||||
|
||||
private final Class<? extends DamagedEvent> damageClazz;
|
||||
private final Set<DamagedEvent> events = new HashSet<>();
|
||||
|
||||
protected DamagedBatchEvent(EventType type, Class<? extends DamagedEvent> damageClazz) {
|
||||
super(type, null, null, null);
|
||||
this.damageClazz = damageClazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<DamagedEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getTargets() {
|
||||
return events.stream()
|
||||
.map(GameEvent::getTargetId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount() {
|
||||
return events
|
||||
.stream()
|
||||
.mapToInt(GameEvent::getAmount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
public boolean isCombatDamage() {
|
||||
return events.stream().anyMatch(DamagedEvent::isCombatDamage);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getTargetId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list or use CardUtil.getEventTargets(event)");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getSourceId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list.");
|
||||
}
|
||||
|
||||
public void addEvent(DamagedEvent event) {
|
||||
this.events.add(event);
|
||||
}
|
||||
|
||||
public Class<? extends DamagedEvent> getDamageClazz() {
|
||||
return damageClazz;
|
||||
}
|
||||
|
||||
public static DamagedBatchEvent makeEvent(DamagedEvent damagedEvent) {
|
||||
DamagedBatchEvent event;
|
||||
if (damagedEvent instanceof DamagedPlayerEvent) {
|
||||
event = new DamagedBatchForPlayersEvent(damagedEvent);
|
||||
} else if (damagedEvent instanceof DamagedPermanentEvent) {
|
||||
event = new DamagedBatchForPermanentsEvent(damagedEvent);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Wrong code usage. Unknown damage event for a new batch: " + damagedEvent.getClass().getName());
|
||||
}
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
package mage.game.events;
|
||||
|
||||
public class DamagedBatchForOnePermanentEvent extends DamagedBatchEvent {
|
||||
public class DamagedBatchForOnePermanentEvent extends BatchEvent<DamagedPermanentEvent> {
|
||||
|
||||
public DamagedBatchForOnePermanentEvent(DamagedEvent firstEvent) {
|
||||
super(GameEvent.EventType.DAMAGED_BATCH_FOR_ONE_PERMANENT, DamagedPermanentEvent.class);
|
||||
addEvent(firstEvent);
|
||||
setTargetId(firstEvent.getTargetId());
|
||||
public DamagedBatchForOnePermanentEvent(DamagedPermanentEvent firstEvent) {
|
||||
super(GameEvent.EventType.DAMAGED_BATCH_FOR_ONE_PERMANENT, true, firstEvent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,15 @@ package mage.game.events;
|
|||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class DamagedBatchForOnePlayerEvent extends DamagedBatchEvent {
|
||||
public class DamagedBatchForOnePlayerEvent extends BatchEvent<DamagedPlayerEvent> {
|
||||
|
||||
public DamagedBatchForOnePlayerEvent(DamagedEvent firstEvent) {
|
||||
super(EventType.DAMAGED_BATCH_FOR_ONE_PLAYER, DamagedPlayerEvent.class);
|
||||
setPlayerId(firstEvent.getPlayerId());
|
||||
addEvent(firstEvent);
|
||||
public DamagedBatchForOnePlayerEvent(DamagedPlayerEvent firstEvent) {
|
||||
super(EventType.DAMAGED_BATCH_FOR_ONE_PLAYER, true, firstEvent);
|
||||
}
|
||||
|
||||
public boolean isCombatDamage() {
|
||||
return getEvents()
|
||||
.stream()
|
||||
.anyMatch(DamagedEvent::isCombatDamage);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ package mage.game.events;
|
|||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class DamagedBatchForPermanentsEvent extends DamagedBatchEvent {
|
||||
public class DamagedBatchForPermanentsEvent extends BatchEvent<DamagedPermanentEvent> {
|
||||
|
||||
public DamagedBatchForPermanentsEvent(DamagedEvent firstEvent) {
|
||||
super(EventType.DAMAGED_BATCH_FOR_PERMANENTS, DamagedPermanentEvent.class);
|
||||
addEvent(firstEvent);
|
||||
public DamagedBatchForPermanentsEvent(DamagedPermanentEvent firstEvent) {
|
||||
super(EventType.DAMAGED_BATCH_FOR_PERMANENTS, false, firstEvent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ package mage.game.events;
|
|||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class DamagedBatchForPlayersEvent extends DamagedBatchEvent {
|
||||
public class DamagedBatchForPlayersEvent extends BatchEvent<DamagedPlayerEvent> {
|
||||
|
||||
public DamagedBatchForPlayersEvent(DamagedEvent firstEvent) {
|
||||
super(GameEvent.EventType.DAMAGED_BATCH_FOR_PLAYERS, DamagedPlayerEvent.class);
|
||||
addEvent(firstEvent);
|
||||
public DamagedBatchForPlayersEvent(DamagedPlayerEvent firstEvent) {
|
||||
super(GameEvent.EventType.DAMAGED_BATCH_FOR_PLAYERS, false, firstEvent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,10 +120,15 @@ public class GameEvent implements Serializable {
|
|||
|
||||
/* DAMAGED_BATCH_FOR_ONE_PLAYER
|
||||
combines all player damage events to a single batch (event) and split it per damaged player
|
||||
playerId the id of the damaged player
|
||||
targetId the id of the damaged player (playerId won't work for batch)
|
||||
*/
|
||||
DAMAGED_BATCH_FOR_ONE_PLAYER,
|
||||
|
||||
/* DAMAGED_BATCH_FOR_ALL
|
||||
includes all damage events, both permanent damage and player damage, in single batch event
|
||||
*/
|
||||
DAMAGED_BATCH_FOR_ALL,
|
||||
|
||||
/* 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
|
||||
|
|
|
|||
|
|
@ -1,69 +1,22 @@
|
|||
package mage.game.events;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author jimga150
|
||||
*/
|
||||
public class LifeLostBatchEvent extends GameEvent implements BatchGameEvent<LifeLostEvent> {
|
||||
public class LifeLostBatchEvent extends BatchEvent<LifeLostEvent> {
|
||||
|
||||
private final Set<LifeLostEvent> events = new HashSet<>();
|
||||
|
||||
public LifeLostBatchEvent(LifeLostEvent event) {
|
||||
super(EventType.LOST_LIFE_BATCH, null, null, null);
|
||||
addEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<LifeLostEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getTargets() {
|
||||
return events.stream()
|
||||
.map(GameEvent::getTargetId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount() {
|
||||
return events
|
||||
.stream()
|
||||
.mapToInt(GameEvent::getAmount)
|
||||
.sum();
|
||||
public LifeLostBatchEvent(LifeLostEvent firstEvent) {
|
||||
super(EventType.LOST_LIFE_BATCH, false, firstEvent);
|
||||
}
|
||||
|
||||
public int getLifeLostByPlayer(UUID playerID) {
|
||||
return events
|
||||
return getEvents()
|
||||
.stream()
|
||||
.filter(ev -> ev.getTargetId().equals(playerID))
|
||||
.mapToInt(GameEvent::getAmount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
public boolean isLifeLostByCombatDamage() {
|
||||
return events.stream().anyMatch(LifeLostEvent::isLifeLostByCombatDamage);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getTargetId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list or use CardUtil.getEventTargets(event)");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getSourceId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list.");
|
||||
}
|
||||
|
||||
public void addEvent(LifeLostEvent event) {
|
||||
this.events.add(event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,10 @@ import java.util.UUID;
|
|||
/**
|
||||
* @author jimga150
|
||||
*/
|
||||
public class LifeLostEvent extends GameEvent{
|
||||
public class LifeLostEvent extends GameEvent {
|
||||
|
||||
public LifeLostEvent(UUID playerId, Ability source, int amount, boolean atCombat){
|
||||
super(GameEvent.EventType.LOST_LIFE,
|
||||
playerId, source, playerId, amount, atCombat);
|
||||
super(GameEvent.EventType.LOST_LIFE, playerId, source, playerId, amount, atCombat);
|
||||
}
|
||||
|
||||
public boolean isLifeLostByCombatDamage() {
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +1,12 @@
|
|||
package mage.game.events;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class TappedBatchEvent extends GameEvent implements BatchGameEvent<TappedEvent> {
|
||||
public class TappedBatchEvent extends BatchEvent<TappedEvent> {
|
||||
|
||||
private final Set<TappedEvent> events = new HashSet<>();
|
||||
|
||||
public TappedBatchEvent() {
|
||||
super(EventType.TAPPED_BATCH, null, null, null);
|
||||
public TappedBatchEvent(TappedEvent firstEvent) {
|
||||
super(EventType.TAPPED_BATCH, false, firstEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TappedEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getTargets() {
|
||||
return events.stream()
|
||||
.map(GameEvent::getTargetId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount() {
|
||||
return events
|
||||
.stream()
|
||||
.mapToInt(GameEvent::getAmount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getTargetId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list or use CardUtil.getEventTargets(event)");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getSourceId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list.");
|
||||
}
|
||||
|
||||
public void addEvent(TappedEvent event) {
|
||||
this.events.add(event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +1,12 @@
|
|||
package mage.game.events;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class UntappedBatchEvent extends GameEvent implements BatchGameEvent<UntappedEvent> {
|
||||
public class UntappedBatchEvent extends BatchEvent<UntappedEvent> {
|
||||
|
||||
private final Set<UntappedEvent> events = new HashSet<>();
|
||||
|
||||
public UntappedBatchEvent() {
|
||||
super(EventType.UNTAPPED_BATCH, null, null, null);
|
||||
public UntappedBatchEvent(UntappedEvent firstEvent) {
|
||||
super(EventType.UNTAPPED_BATCH, false, firstEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UntappedEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getTargets() {
|
||||
return events.stream()
|
||||
.map(GameEvent::getTargetId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount() {
|
||||
return events
|
||||
.stream()
|
||||
.mapToInt(GameEvent::getAmount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getTargetId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list or use CardUtil.getEventTargets(event)");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getSourceId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list.");
|
||||
}
|
||||
|
||||
public void addEvent(UntappedEvent event) {
|
||||
this.events.add(event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import java.util.UUID;
|
|||
* @author Susucr
|
||||
*/
|
||||
public class UntappedEvent extends GameEvent {
|
||||
|
||||
public UntappedEvent(UUID targetId, UUID playerId, boolean duringUntapPhase) {
|
||||
super(EventType.UNTAPPED, targetId, null, playerId, 0, duringUntapPhase);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +1,8 @@
|
|||
package mage.game.events;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZoneChangeBatchEvent extends GameEvent implements BatchGameEvent<ZoneChangeEvent> {
|
||||
|
||||
private final Set<ZoneChangeEvent> events = new HashSet<>();
|
||||
public class ZoneChangeBatchEvent extends BatchEvent<ZoneChangeEvent> {
|
||||
|
||||
public ZoneChangeBatchEvent() {
|
||||
super(EventType.ZONE_CHANGE_BATCH, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ZoneChangeEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getTargets() {
|
||||
return events
|
||||
.stream()
|
||||
.map(GameEvent::getTargetId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount() {
|
||||
return events
|
||||
.stream()
|
||||
.mapToInt(GameEvent::getAmount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getTargetId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list or use CardUtil.getEventTargets(event)");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated // events can store a diff value, so search it from events list instead
|
||||
public UUID getSourceId() {
|
||||
throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list.");
|
||||
}
|
||||
|
||||
public void addEvent(ZoneChangeEvent event) {
|
||||
this.events.add(event);
|
||||
super(EventType.ZONE_CHANGE_BATCH);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -599,7 +599,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
game.getTurnStepType() == PhaseStep.UNTAP
|
||||
);
|
||||
game.fireEvent(event);
|
||||
game.getState().addSimultaneousUntapped(event, game);
|
||||
game.getState().addSimultaneousUntappedToBatch(event, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -617,7 +617,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
this.tapped = true;
|
||||
TappedEvent event = new TappedEvent(objectId, source, source == null ? null : source.getControllerId(), forCombat);
|
||||
game.fireEvent(event);
|
||||
game.getState().addSimultaneousTapped(event, game);
|
||||
game.getState().addSimultaneousTappedToBatch(event, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -2177,7 +2177,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (event.getAmount() > 0) {
|
||||
LifeLostEvent lifeLostEvent = new LifeLostEvent(playerId, source, event.getAmount(), atCombat);
|
||||
game.fireEvent(lifeLostEvent);
|
||||
game.getState().addSimultaneousLifeLossEventToBatches(lifeLostEvent, game);
|
||||
game.getState().addSimultaneousLifeLossToBatch(lifeLostEvent, game);
|
||||
}
|
||||
return event.getAmount();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import mage.game.CardState;
|
|||
import mage.game.Game;
|
||||
import mage.game.GameState;
|
||||
import mage.game.command.Commander;
|
||||
import mage.game.events.BatchGameEvent;
|
||||
import mage.game.events.BatchEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
|
|
@ -2203,14 +2203,11 @@ public final class CardUtil {
|
|||
|
||||
/**
|
||||
* One single event can be a batch (contain multiple events)
|
||||
*
|
||||
* @param event
|
||||
* @return
|
||||
*/
|
||||
public static Set<UUID> getEventTargets(GameEvent event) {
|
||||
Set<UUID> res = new HashSet<>();
|
||||
if (event instanceof BatchGameEvent) {
|
||||
res.addAll(((BatchGameEvent<?>) event).getTargets());
|
||||
if (event instanceof BatchEvent) {
|
||||
res.addAll(((BatchEvent<?>) event).getTargetIds());
|
||||
} else if (event != null && event.getTargetId() != null) {
|
||||
res.add(event.getTargetId());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue