mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
Turn under control reworked:
- game: fixed game freezes when computer try to take control over another computer or human (added game logs, related to #12878); - cheats: improved take and give control commands, now you can give control under yourself to another player; - cheats: improved take and give control commands, now you can return control to computer in the same priority; - cheats: deleted useless and unused command to activate opponent's ability;
This commit is contained in:
parent
a5c354f960
commit
1f1d1088a1
6 changed files with 50 additions and 73 deletions
|
|
@ -1,8 +1,6 @@
|
|||
package mage.utils;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
|
|
@ -26,6 +24,7 @@ import mage.game.permanent.token.Token;
|
|||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetPlayer;
|
||||
import mage.target.common.TargetOpponent;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.MultiAmountMessage;
|
||||
import mage.util.RandomUtil;
|
||||
|
|
@ -68,15 +67,14 @@ public final class SystemUtil {
|
|||
// [@mana add] -> MANA ADD
|
||||
private static final String COMMAND_CARDS_ADD_TO_HAND = "@card add to hand";
|
||||
private static final String COMMAND_LANDS_ADD_TO_BATTLEFIELD = "@lands add";
|
||||
private static final String COMMAND_OPPONENT_UNDER_CONTROL_START = "@opponent under control start";
|
||||
private static final String COMMAND_OPPONENT_UNDER_CONTROL_END = "@opponent under control end";
|
||||
private static final String COMMAND_UNDER_CONTROL_TAKE = "@under control take";
|
||||
private static final String COMMAND_UNDER_CONTROL_GIVE = "@under control give";
|
||||
private static final String COMMAND_MANA_ADD = "@mana add"; // TODO: not implemented
|
||||
private static final String COMMAND_RUN_CUSTOM_CODE = "@run custom code"; // TODO: not implemented
|
||||
private static final String COMMAND_SHOW_OPPONENT_HAND = "@show opponent hand";
|
||||
private static final String COMMAND_SHOW_OPPONENT_LIBRARY = "@show opponent library";
|
||||
private static final String COMMAND_SHOW_MY_HAND = "@show my hand";
|
||||
private static final String COMMAND_SHOW_MY_LIBRARY = "@show my library";
|
||||
private static final String COMMAND_ACTIVATE_OPPONENT_ABILITY = "@activate opponent ability";
|
||||
private static final Map<String, String> supportedCommands = new HashMap<>();
|
||||
|
||||
static {
|
||||
|
|
@ -84,14 +82,13 @@ public final class SystemUtil {
|
|||
supportedCommands.put(COMMAND_CARDS_ADD_TO_HAND, "CARDS: ADD TO HAND");
|
||||
supportedCommands.put(COMMAND_MANA_ADD, "MANA ADD");
|
||||
supportedCommands.put(COMMAND_LANDS_ADD_TO_BATTLEFIELD, "LANDS: ADD TO BATTLEFIELD");
|
||||
supportedCommands.put(COMMAND_OPPONENT_UNDER_CONTROL_START, "OPPONENT CONTROL: ENABLE");
|
||||
supportedCommands.put(COMMAND_OPPONENT_UNDER_CONTROL_END, "OPPONENT CONTROL: DISABLE");
|
||||
supportedCommands.put(COMMAND_UNDER_CONTROL_TAKE, "UNDER CONTROL: TAKE");
|
||||
supportedCommands.put(COMMAND_UNDER_CONTROL_GIVE, "UNDER CONTROL: GIVE");
|
||||
supportedCommands.put(COMMAND_RUN_CUSTOM_CODE, "RUN CUSTOM CODE");
|
||||
supportedCommands.put(COMMAND_SHOW_OPPONENT_HAND, "SHOW OPPONENT HAND");
|
||||
supportedCommands.put(COMMAND_SHOW_OPPONENT_LIBRARY, "SHOW OPPONENT LIBRARY");
|
||||
supportedCommands.put(COMMAND_SHOW_MY_HAND, "SHOW MY HAND");
|
||||
supportedCommands.put(COMMAND_SHOW_MY_LIBRARY, "SHOW MY LIBRARY");
|
||||
supportedCommands.put(COMMAND_ACTIVATE_OPPONENT_ABILITY, "ACTIVATE OPPONENT ABILITY");
|
||||
}
|
||||
|
||||
private static final Pattern patternGroup = Pattern.compile("\\[(.+)\\]"); // [test new card]
|
||||
|
|
@ -307,8 +304,8 @@ public final class SystemUtil {
|
|||
// add default commands
|
||||
initLines.add(0, String.format("[%s]", COMMAND_LANDS_ADD_TO_BATTLEFIELD));
|
||||
initLines.add(1, String.format("[%s]", COMMAND_CARDS_ADD_TO_HAND));
|
||||
initLines.add(2, String.format("[%s]", COMMAND_OPPONENT_UNDER_CONTROL_START));
|
||||
initLines.add(3, String.format("[%s]", COMMAND_OPPONENT_UNDER_CONTROL_END));
|
||||
initLines.add(2, String.format("[%s]", COMMAND_UNDER_CONTROL_TAKE));
|
||||
initLines.add(3, String.format("[%s]", COMMAND_UNDER_CONTROL_GIVE));
|
||||
|
||||
// collect all commands
|
||||
CommandGroup currentGroup = null;
|
||||
|
|
@ -427,53 +424,6 @@ public final class SystemUtil {
|
|||
break;
|
||||
}
|
||||
|
||||
case COMMAND_ACTIVATE_OPPONENT_ABILITY: {
|
||||
// WARNING, maybe very bugged if called in wrong priority
|
||||
// uses choose triggered ability dialog to select it
|
||||
UUID savedPriorityPlayer = null;
|
||||
if (game.getActivePlayerId() != opponent.getId()) {
|
||||
savedPriorityPlayer = game.getActivePlayerId();
|
||||
}
|
||||
|
||||
// change active player to find and play selected abilities (it's danger and buggy code)
|
||||
if (savedPriorityPlayer != null) {
|
||||
game.getState().setPriorityPlayerId(opponent.getId());
|
||||
game.firePriorityEvent(opponent.getId());
|
||||
}
|
||||
|
||||
List<ActivatedAbility> abilities = opponent.getPlayable(game, true);
|
||||
Map<String, String> choices = new HashMap<>();
|
||||
abilities.forEach(ability -> {
|
||||
MageObject object = ability.getSourceObject(game);
|
||||
choices.put(ability.getId().toString(), object.getName() + ": " + ability.toString());
|
||||
});
|
||||
// TODO: set priority for us?
|
||||
Choice choice = new ChoiceImpl(false);
|
||||
choice.setMessage("Choose playable ability to activate by opponent " + opponent.getName());
|
||||
choice.setKeyChoices(choices);
|
||||
if (feedbackPlayer.choose(Outcome.Detriment, choice, game) && choice.getChoiceKey() != null) {
|
||||
String needId = choice.getChoiceKey();
|
||||
Optional<ActivatedAbility> ability = abilities.stream().filter(a -> a.getId().toString().equals(needId)).findFirst();
|
||||
if (ability.isPresent()) {
|
||||
// TODO: set priority for player?
|
||||
ActivatedAbility activatedAbility = ability.get();
|
||||
game.informPlayers(feedbackPlayer.getLogName() + " as another player " + opponent.getLogName()
|
||||
+ " trying to force an activate ability: " + activatedAbility.getGameLogMessage(game));
|
||||
if (opponent.activateAbility(activatedAbility, game)) {
|
||||
game.informPlayers("Force to activate ability: DONE");
|
||||
} else {
|
||||
game.informPlayers("Force to activate ability: FAIL");
|
||||
}
|
||||
}
|
||||
}
|
||||
// restore original priority player
|
||||
if (savedPriorityPlayer != null) {
|
||||
game.getState().setPriorityPlayerId(savedPriorityPlayer);
|
||||
game.firePriorityEvent(savedPriorityPlayer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case COMMAND_CARDS_ADD_TO_HAND: {
|
||||
|
||||
// card
|
||||
|
|
@ -552,12 +502,12 @@ public final class SystemUtil {
|
|||
break;
|
||||
}
|
||||
|
||||
case COMMAND_OPPONENT_UNDER_CONTROL_START: {
|
||||
Target target = new TargetPlayer().withNotTarget(true).withChooseHint("to take under your control");
|
||||
case COMMAND_UNDER_CONTROL_TAKE: {
|
||||
Target target = new TargetOpponent().withNotTarget(true).withChooseHint("to take under your control");
|
||||
Ability fakeSourceAbility = fakeSourceAbilityTemplate.copy();
|
||||
if (feedbackPlayer.chooseTarget(Outcome.GainControl, target, fakeSourceAbility, game)) {
|
||||
Player targetPlayer = game.getPlayer(target.getFirstTarget());
|
||||
if (targetPlayer != null && targetPlayer != feedbackPlayer) {
|
||||
if (!targetPlayer.getId().equals(feedbackPlayer.getId())) {
|
||||
CardUtil.takeControlUnderPlayerStart(game, fakeSourceAbility, feedbackPlayer, targetPlayer, false);
|
||||
// allow priority play again in same step (for better cheat UX)
|
||||
targetPlayer.resetPassed();
|
||||
|
|
@ -568,14 +518,20 @@ public final class SystemUtil {
|
|||
break;
|
||||
}
|
||||
|
||||
case COMMAND_OPPONENT_UNDER_CONTROL_END: {
|
||||
Target target = new TargetPlayer().withNotTarget(true).withChooseHint("to free from your control");
|
||||
case COMMAND_UNDER_CONTROL_GIVE: {
|
||||
Target target = new TargetPlayer().withNotTarget(true).withChooseHint("to give control of your player");
|
||||
Ability fakeSourceAbility = fakeSourceAbilityTemplate.copy();
|
||||
if (feedbackPlayer.chooseTarget(Outcome.GainControl, target, fakeSourceAbility, game)) {
|
||||
Player targetPlayer = game.getPlayer(target.getFirstTarget());
|
||||
if (targetPlayer != null && targetPlayer != feedbackPlayer && !targetPlayer.isGameUnderControl()) {
|
||||
if (targetPlayer != null) {
|
||||
if (!targetPlayer.getId().equals(feedbackPlayer.getId())) {
|
||||
// give control to another player
|
||||
CardUtil.takeControlUnderPlayerStart(game, fakeSourceAbility, targetPlayer, feedbackPlayer, false);
|
||||
} else {
|
||||
// return control to itself
|
||||
CardUtil.takeControlUnderPlayerEnd(game, fakeSourceAbility, feedbackPlayer, targetPlayer);
|
||||
}
|
||||
}
|
||||
// workaround for refresh priority dialog like avatar click (cheats called from priority in 99%)
|
||||
game.firePriorityEvent(feedbackPlayer.getId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -360,9 +360,14 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
// async command: cheat by current player
|
||||
if (response.getAsyncWantCheat()) {
|
||||
// execute cheats and continue
|
||||
// run cheats
|
||||
SystemUtil.executeCheatCommands(game, null, this);
|
||||
game.fireUpdatePlayersEvent(); // need force to game update for new possible data
|
||||
// force to game update for new possible data
|
||||
game.fireUpdatePlayersEvent();
|
||||
// must stop current dialog on changed control, so game can give priority to actual player
|
||||
if (this.isGameUnderControl() != game.getPlayer(this.getId()).isGameUnderControl()) {
|
||||
return;
|
||||
}
|
||||
// wait another answer
|
||||
if (canRespond()) {
|
||||
loop = true;
|
||||
|
|
|
|||
|
|
@ -3080,8 +3080,8 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void controlPlayersTurn(Game game, UUID playerUnderControlId, String info) {
|
||||
computerPlayer.controlPlayersTurn(game, playerUnderControlId, info);
|
||||
public boolean controlPlayersTurn(Game game, UUID playerUnderControlId, String info) {
|
||||
return computerPlayer.controlPlayersTurn(game, playerUnderControlId, info);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -341,8 +341,9 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
* @param game
|
||||
* @param playerUnderControlId
|
||||
* @param info additional info to show in game logs like source
|
||||
* @return false on failed taken control, e.g. on unsupported player type
|
||||
*/
|
||||
void controlPlayersTurn(Game game, UUID playerUnderControlId, String info);
|
||||
boolean controlPlayersTurn(Game game, UUID playerUnderControlId, String info);
|
||||
|
||||
/**
|
||||
* Sets player {@link UUID} who controls this player's turn.
|
||||
|
|
|
|||
|
|
@ -598,8 +598,17 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void controlPlayersTurn(Game game, UUID playerUnderControlId, String info) {
|
||||
public boolean controlPlayersTurn(Game game, UUID playerUnderControlId, String info) {
|
||||
Player playerUnderControl = game.getPlayer(playerUnderControlId);
|
||||
|
||||
// TODO: add support computer over computer
|
||||
// TODO: add support computer over human
|
||||
if (this.isComputer()) {
|
||||
// not supported yet
|
||||
game.informPlayers(getLogName() + " is AI and can't take control over " + playerUnderControl.getLogName() + info);
|
||||
return false;
|
||||
}
|
||||
|
||||
playerUnderControl.setTurnControlledBy(this.getId());
|
||||
game.informPlayers(getLogName() + " taken turn control of " + playerUnderControl.getLogName() + info);
|
||||
if (!playerUnderControlId.equals(this.getId())) {
|
||||
|
|
@ -609,6 +618,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
// control will reset on start of the turn
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1358,7 +1358,11 @@ public final class CardUtil {
|
|||
*/
|
||||
public static void takeControlUnderPlayerStart(Game game, Ability source, Player controller, Player playerUnderControl, boolean givePauseForResponse) {
|
||||
// game logs added in child's call
|
||||
controller.controlPlayersTurn(game, playerUnderControl.getId(), CardUtil.getSourceLogName(game, source));
|
||||
if (!controller.controlPlayersTurn(game, playerUnderControl.getId(), CardUtil.getSourceLogName(game, source))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// give pause, so new controller can look around battlefield and hands before finish controlling choose dialog
|
||||
if (givePauseForResponse) {
|
||||
while (controller.canRespond()) {
|
||||
if (controller.chooseUse(Outcome.Benefit, "You got control of " + playerUnderControl.getLogName()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue