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 extends GameEvent { private final Set events = new HashSet<>(); private final boolean singleTargetId; private final boolean singleSourceId; private final boolean singlePlayerId; /** * @param eventType specific type of event * @param singleSourceId if true, all included events must have same source id * @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, boolean singleSourceId, T firstEvent) { this(eventType, singleTargetId, singleSourceId, false, firstEvent); } /** * @param eventType specific type of event * @param singleSourceId if true, all included events must have same source id * @param singleTargetId if true, all included events must have same target id * @param singlePlayerId if true, all included events must have same player id * @param firstEvent added to initialize the batch (batch is never empty) */ protected BatchEvent(EventType eventType, boolean singleTargetId, boolean singleSourceId, boolean singlePlayerId, T firstEvent) { super(eventType, (singleTargetId ? firstEvent.getTargetId() : null), null, (singlePlayerId ? firstEvent.getPlayerId() : null) ); this.singleTargetId = singleTargetId; this.singleSourceId = singleSourceId; this.singlePlayerId = singlePlayerId; this.setSourceId(singleSourceId ? firstEvent.getSourceId() : null); 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; this.singleSourceId = false; this.singlePlayerId = 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"); } if (singleSourceId && !getSourceId().equals(event.getSourceId())) { throw new IllegalStateException("Wrong code usage. Batch event initiated with single source id, but trying to add event with different target id"); } this.events.add(event); } public Set getEvents() { return events; } public Set getTargetIds() { return events.stream() .map(GameEvent::getTargetId) .filter(Objects::nonNull) .collect(Collectors.toSet()); } public Set getSourceIds() { return events.stream() .map(GameEvent::getSourceId) .filter(Objects::nonNull) .collect(Collectors.toSet()); } public Set 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 public UUID getSourceId() { if (singleSourceId) { return super.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 public UUID getPlayerId() { if (singlePlayerId) { return super.getPlayerId(); } throw new IllegalStateException("Wrong code usage. Must search value from a getEvents list"); } }