mirror of
https://github.com/magefree/mage.git
synced 2025-12-26 05:22:02 -08:00
Reworking effects that allow controlling combat (WIP) (#8159)
* reworked effects that allow controlling combat * [AFC] Implemented Berserker's Frenzy * [AFC] updated Berserker's Frenzy to roll correctly
This commit is contained in:
parent
f5177097cd
commit
f7e821be2f
12 changed files with 366 additions and 492 deletions
|
|
@ -27,6 +27,7 @@ public class RollDieWithResultTableEffect extends OneShotEffect {
|
|||
private final String prefixText;
|
||||
private final List<TableEntry> resultsTable = new ArrayList<>();
|
||||
private final DynamicValue modifier;
|
||||
private final int toIgnore;
|
||||
|
||||
public RollDieWithResultTableEffect() {
|
||||
this(20);
|
||||
|
|
@ -37,14 +38,15 @@ public class RollDieWithResultTableEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
public RollDieWithResultTableEffect(int sides, String prefixText) {
|
||||
this(sides, prefixText, StaticValue.get(0));
|
||||
this(sides, prefixText, StaticValue.get(0), 0);
|
||||
}
|
||||
|
||||
public RollDieWithResultTableEffect(int sides, String prefixText, DynamicValue modifier) {
|
||||
public RollDieWithResultTableEffect(int sides, String prefixText, DynamicValue modifier, int toIgnore) {
|
||||
super(Outcome.Benefit);
|
||||
this.sides = sides;
|
||||
this.prefixText = prefixText;
|
||||
this.modifier = modifier;
|
||||
this.toIgnore = toIgnore;
|
||||
}
|
||||
|
||||
protected RollDieWithResultTableEffect(final RollDieWithResultTableEffect effect) {
|
||||
|
|
@ -55,6 +57,7 @@ public class RollDieWithResultTableEffect extends OneShotEffect {
|
|||
this.resultsTable.add(tableEntry.copy());
|
||||
}
|
||||
this.modifier = effect.modifier.copy();
|
||||
this.toIgnore = effect.toIgnore;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -68,7 +71,9 @@ public class RollDieWithResultTableEffect extends OneShotEffect {
|
|||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
int result = player.rollDice(outcome, source, game, sides) + modifier.calculate(game, source, this);
|
||||
int result = player.rollDice(
|
||||
outcome, source, game, sides, 1 + toIgnore, toIgnore
|
||||
).get(0) + modifier.calculate(game, source, this);
|
||||
this.applyResult(result, game, source);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.ControlCombatRedundancyWatcher;
|
||||
|
||||
/**
|
||||
* @author L_J, TheElk801
|
||||
*/
|
||||
public class ChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
|
||||
|
||||
public ChooseBlockersEffect(Duration duration) {
|
||||
super(duration, Outcome.Benefit, false, false);
|
||||
}
|
||||
|
||||
private ChooseBlockersEffect(final ChooseBlockersEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChooseBlockersEffect copy() {
|
||||
return new ChooseBlockersEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
ControlCombatRedundancyWatcher.addBlockingController(source.getControllerId(), this.duration, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (!ControlCombatRedundancyWatcher.checkBlockingController(source.getControllerId(), game)) {
|
||||
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
|
||||
return false;
|
||||
}
|
||||
Player blockController = game.getPlayer(source.getControllerId());
|
||||
if (blockController != null) {
|
||||
game.getCombat().selectBlockers(blockController, source, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
if (staticText != null && !staticText.isEmpty()) {
|
||||
return staticText;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder("you choose which creatures block this ");
|
||||
switch (duration) {
|
||||
case EndOfTurn:
|
||||
sb.append("turn");
|
||||
break;
|
||||
case EndOfCombat:
|
||||
sb.append("combat");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("duration type not supported");
|
||||
}
|
||||
sb.append(" and how those creatures block");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package mage.watchers.common;
|
||||
|
||||
import mage.constants.WatcherScope;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
/**
|
||||
* @author L_J
|
||||
*/
|
||||
|
||||
public class ChooseBlockersRedundancyWatcher extends Watcher { // workaround for solving timestamp issues regarding "you choose which creatures block and how those creatures block" effects
|
||||
|
||||
public int copyCount = 0;
|
||||
public int copyCountApply = 0;
|
||||
|
||||
public ChooseBlockersRedundancyWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
copyCount = 0;
|
||||
copyCountApply = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
copyCount++;
|
||||
copyCountApply = copyCount;
|
||||
}
|
||||
|
||||
public void decrement() {
|
||||
if (copyCountApply > 0) {
|
||||
copyCountApply--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package mage.watchers.common;
|
||||
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.WatcherScope;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author L_J
|
||||
*/
|
||||
public class ControlCombatRedundancyWatcher extends Watcher { // workaround for solving timestamp issues regarding "you choose which creatures block and how those creatures block" effects
|
||||
|
||||
private static final class PlayerDuration {
|
||||
|
||||
private final Duration duration;
|
||||
private final UUID playerId;
|
||||
|
||||
private PlayerDuration(Duration duration, UUID playerId) {
|
||||
this.duration = duration;
|
||||
this.playerId = playerId;
|
||||
}
|
||||
|
||||
private boolean isCombat() {
|
||||
return duration == Duration.EndOfCombat;
|
||||
}
|
||||
|
||||
private boolean isPlayer(UUID playerId) {
|
||||
return playerId.equals(this.playerId);
|
||||
}
|
||||
}
|
||||
|
||||
private final List<PlayerDuration> attackingControllers = new ArrayList<>();
|
||||
private final List<PlayerDuration> blockingControllers = new ArrayList<>();
|
||||
|
||||
public ControlCombatRedundancyWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
attackingControllers.clear();
|
||||
blockingControllers.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST) {
|
||||
attackingControllers.removeIf(PlayerDuration::isCombat);
|
||||
blockingControllers.removeIf(PlayerDuration::isCombat);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addAttackingController(UUID playerId, Duration duration, Game game) {
|
||||
ControlCombatRedundancyWatcher watcher = game.getState().getWatcher(ControlCombatRedundancyWatcher.class);
|
||||
watcher.attackingControllers.add(0, new PlayerDuration(duration, playerId));
|
||||
}
|
||||
|
||||
public static void addBlockingController(UUID playerId, Duration duration, Game game) {
|
||||
ControlCombatRedundancyWatcher watcher = game.getState().getWatcher(ControlCombatRedundancyWatcher.class);
|
||||
watcher.blockingControllers.add(0, new PlayerDuration(duration, playerId));
|
||||
}
|
||||
|
||||
public static boolean checkAttackingController(UUID playerId, Game game) {
|
||||
ControlCombatRedundancyWatcher watcher = game.getState().getWatcher(ControlCombatRedundancyWatcher.class);
|
||||
return !watcher.attackingControllers.isEmpty() && watcher.attackingControllers.get(0).isPlayer(playerId);
|
||||
}
|
||||
|
||||
public static boolean checkBlockingController(UUID playerId, Game game) {
|
||||
ControlCombatRedundancyWatcher watcher = game.getState().getWatcher(ControlCombatRedundancyWatcher.class);
|
||||
return !watcher.blockingControllers.isEmpty() && watcher.blockingControllers.get(0).isPlayer(playerId);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue