Skip to content

Commit

Permalink
Merge branch 'master' into slow
Browse files Browse the repository at this point in the history
  • Loading branch information
Northmoc authored Jan 28, 2025
2 parents c993bb0 + 53e5f2b commit 2eb644d
Show file tree
Hide file tree
Showing 85 changed files with 665 additions and 388 deletions.
1 change: 1 addition & 0 deletions forge-ai/src/main/java/forge/ai/simulation/GameCopier.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public Game makeCopy(PhaseType advanceToPhase, Player aiPlayer) {
GameRules currentRules = origGame.getRules();
Match newMatch = new Match(currentRules, newPlayers, origGame.getView().getTitle());
Game newGame = new Game(newPlayers, currentRules, newMatch);
newGame.dangerouslySetTimestamp(origGame.getTimestamp());

for (int i = 0; i < origGame.getPlayers().size(); i++) {
Player origPlayer = origGame.getPlayers().get(i);
Expand Down
8 changes: 7 additions & 1 deletion forge-game/pom.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

Expand Down Expand Up @@ -34,5 +35,10 @@
<artifactId>sentry-logback</artifactId>
<version>7.15.0</version>
</dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
<version>1.5.2</version>
</dependency>
</dependencies>
</project>
317 changes: 238 additions & 79 deletions forge-game/src/main/java/forge/game/GameAction.java

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion forge-game/src/main/java/forge/game/GameActionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.SpellAbilityEffect;
import forge.game.ability.effects.DetachedCardEffect;
import forge.game.card.*;
import forge.game.card.CardPlayOption.PayManaCost;
import forge.game.cost.Cost;
Expand All @@ -34,6 +35,7 @@
import forge.game.player.Player;
import forge.game.player.PlayerCollection;
import forge.game.player.PlayerController;
import forge.game.player.PlayerController.FullControlFlag;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementLayer;
Expand Down Expand Up @@ -835,9 +837,11 @@ public static String generatedMana(final SpellAbility sa) {
}

public static CardCollectionView orderCardsByTheirOwners(Game game, CardCollectionView list, ZoneType dest, SpellAbility sa) {
if (list.size() <= 1) {
if (list.size() <= 1 &&
(sa == null || !sa.getActivatingPlayer().getController().isFullControl(FullControlFlag.LayerTimestampOrder))) {
return list;
}
Card eff = null;
CardCollection completeList = new CardCollection();
// CR 613.7m use APNAP
PlayerCollection players = game.getPlayersInTurnOrder(game.getPhaseHandler().getPlayerTurn());
Expand All @@ -853,12 +857,28 @@ public static CardCollectionView orderCardsByTheirOwners(Game game, CardCollecti
subList.add(c);
}
}
if (sa != null && sa.getActivatingPlayer() == p && sa.hasParam("StaticEffect")) {
// create helper card for ordering
eff = new DetachedCardEffect(sa.getHostCard(), "Static Effect of " + sa.getHostCard());
subList.add(eff);
}
CardCollectionView subListView = subList;
if (subList.size() > 1) {
subListView = p.getController().orderMoveToZoneList(subList, dest, sa);
}
completeList.addAll(subListView);
}
if (eff != null) {
int idx = completeList.indexOf(eff);
if (idx < completeList.size() - 1) {
// effects with this param have the responsibility to realign it when later cards are reached
sa.setSVar("StaticEffectUntilCardID", String.valueOf(completeList.get(idx + 1).getId()));
// add generous offset to timestamp, to ensure it applies last compared to cards that were ordered to ETB before it
idx += completeList.size() * 2;
}
sa.setSVar("StaticEffectTimestamp", String.valueOf(game.getNextTimestamp() + idx));
completeList.remove(eff);
}
return completeList;
}

Expand Down
204 changes: 111 additions & 93 deletions forge-game/src/main/java/forge/game/StaticEffect.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import forge.game.card.CardCollectionView;
import forge.game.player.Player;
import forge.game.staticability.StaticAbility;
import forge.game.staticability.StaticAbilityLayer;

/**
* <p>
Expand All @@ -52,7 +53,7 @@ public class StaticEffect {
}

StaticEffect(final StaticAbility ability) {
this(ability.getHostCard());
this(ability.getHostCard());
this.ability = ability;
}

Expand Down Expand Up @@ -171,128 +172,145 @@ public String getParam(final String key) {
* @return a {@link CardCollectionView} of all affected cards.
*/
final CardCollectionView remove() {
return remove(StaticAbilityLayer.CONTINUOUS_LAYERS);
}
final CardCollectionView remove(List<StaticAbilityLayer> layers) {
final CardCollectionView affectedCards = getAffectedCards();
final List<Player> affectedPlayers = getAffectedPlayers();

boolean removeMayPlay = false;

if (hasParam("MayPlay")) {
removeMayPlay = true;
}

if (hasParam("IgnoreEffectCost")) {
getSource().removeChangedCardTraits(getTimestamp(), ability.getId());
if (layers.contains(StaticAbilityLayer.RULES)) {
if (hasParam("IgnoreEffectCost")) {
getSource().removeChangedCardTraits(getTimestamp(), ability.getId());
}
}

// modify players
for (final Player p : affectedPlayers) {
p.setUnlimitedHandSize(false);
p.setMaxHandSize(p.getStartingHandSize());
p.removeChangedKeywords(getTimestamp(), ability.getId());

p.removeMaxLandPlays(getTimestamp());
p.removeMaxLandPlaysInfinite(getTimestamp());
if (layers.contains(StaticAbilityLayer.RULES)) {
p.setUnlimitedHandSize(false);
p.setMaxHandSize(p.getStartingHandSize());

p.removeControlledWhileSearching(getTimestamp());
p.removeControlVote(getTimestamp());
p.removeAdditionalVote(getTimestamp());
p.removeAdditionalOptionalVote(getTimestamp());
p.removeAdditionalVillainousChoices(getTimestamp());
p.removeMaxLandPlays(getTimestamp());
p.removeMaxLandPlaysInfinite(getTimestamp());

p.removeDeclaresAttackers(getTimestamp());
p.removeDeclaresBlockers(getTimestamp());
}
p.removeControlledWhileSearching(getTimestamp());
p.removeControlVote(getTimestamp());
p.removeAdditionalVote(getTimestamp());
p.removeAdditionalOptionalVote(getTimestamp());
p.removeAdditionalVillainousChoices(getTimestamp());

// modify the affected card
for (final Card affectedCard : affectedCards) {
// Gain control
if (hasParam("GainControl")) {
affectedCard.removeTempController(getTimestamp());
p.removeDeclaresAttackers(getTimestamp());
p.removeDeclaresBlockers(getTimestamp());
}

// Revert changed color words
affectedCard.removeChangedTextColorWord(getTimestamp(), ability.getId());

// remove set P/T
if (hasParam("SetPower") || hasParam("SetToughness")) {
affectedCard.removeNewPT(getTimestamp(), ability.getId());
if (layers.contains(StaticAbilityLayer.ABILITIES)) {
p.removeChangedKeywords(getTimestamp(), ability.getId());
}

// remove P/T bonus
affectedCard.removePTBoost(getTimestamp(), ability.getId());

// remove keywords
// (Although nothing uses it at this time)
if (hasParam("AddKeyword") || hasParam("RemoveKeyword") || hasParam("RemoveLandTypes")
|| hasParam("ShareRememberedKeywords") || hasParam("RemoveAllAbilities")) {
affectedCard.removeChangedCardKeywords(getTimestamp(), ability.getId(), false);
}

if (hasParam("CantHaveKeyword")) {
affectedCard.removeCantHaveKeyword(getTimestamp());
}

if (hasParam("AddHiddenKeyword")) {
affectedCard.removeHiddenExtrinsicKeywords(timestamp, ability.getId());
}
}

// remove abilities
if (hasParam("AddAbility") || hasParam("GainsAbilitiesOf")
|| hasParam("GainsAbilitiesOfDefined") || hasParam("GainsTriggerAbsOf")
|| hasParam("AddTrigger") || hasParam("AddStaticAbility")
|| hasParam("AddReplacementEffects") || hasParam("RemoveAllAbilities")
|| hasParam("RemoveLandTypes")) {
affectedCard.removeChangedCardTraits(getTimestamp(), ability.getId());
// modify the affected card
for (final Card affectedCard : affectedCards) {
if (layers.contains(StaticAbilityLayer.CONTROL)) {
if (hasParam("GainControl")) {
affectedCard.removeTempController(getTimestamp());
}
}

// remove Types
if (hasParam("AddType") || hasParam("AddAllCreatureTypes") || hasParam("RemoveType") || hasParam("RemoveLandTypes")) {
// the view is updated in GameAction#checkStaticAbilities to avoid flickering
affectedCard.removeChangedCardTypes(getTimestamp(), ability.getId(), false);
if (layers.contains(StaticAbilityLayer.TEXT)) {
// Revert changed color words
affectedCard.removeChangedTextColorWord(getTimestamp(), ability.getId());

// remove changed name
if (hasParam("SetName") || hasParam("AddNames")) {
affectedCard.removeChangedName(timestamp, ability.getId());
}

if (hasParam("GainTextOf")) {
affectedCard.removeChangedName(getTimestamp(), ability.getId());
affectedCard.removeChangedManaCost(getTimestamp(), ability.getId());
affectedCard.removeColor(getTimestamp(), ability.getId());
affectedCard.removeChangedCardTypes(getTimestamp(), ability.getId());
affectedCard.removeChangedCardTraits(getTimestamp(), ability.getId());
affectedCard.removeChangedCardKeywords(getTimestamp(), ability.getId());
affectedCard.removeNewPT(getTimestamp(), ability.getId());

affectedCard.updateChangedText();
}
}

// remove colors
if (hasParam("AddColor") || hasParam("SetColor")) {
affectedCard.removeColor(getTimestamp(), ability.getId());
if (layers.contains(StaticAbilityLayer.TYPE)) {
// remove Types
if (hasParam("AddType") || hasParam("AddAllCreatureTypes") || hasParam("RemoveType") || hasParam("RemoveLandTypes")) {
// the view is updated in GameAction#checkStaticAbilities to avoid flickering
affectedCard.removeChangedCardTypes(getTimestamp(), ability.getId(), false);
}
}

// remove changed name
if (hasParam("SetName") || hasParam("AddNames")) {
affectedCard.removeChangedName(timestamp, ability.getId());
if (layers.contains(StaticAbilityLayer.COLOR)) {
// remove colors
if (hasParam("AddColor") || hasParam("SetColor")) {
affectedCard.removeColor(getTimestamp(), ability.getId());
}
}

// remove may look at
if (hasParam("MayLookAt")) {
affectedCard.removeMayLookAt(getTimestamp());
}
if (removeMayPlay) {
affectedCard.removeMayPlay(ability);
if (layers.contains(StaticAbilityLayer.ABILITIES)) {
// remove keywords
if (hasParam("AddKeyword") || hasParam("RemoveKeyword") || hasParam("RemoveLandTypes")
|| hasParam("ShareRememberedKeywords") || hasParam("RemoveAllAbilities")) {
affectedCard.removeChangedCardKeywords(getTimestamp(), ability.getId(), false);
}

// remove abilities
if (hasParam("AddAbility") || hasParam("GainsAbilitiesOf")
|| hasParam("GainsAbilitiesOfDefined") || hasParam("GainsTriggerAbsOf")
|| hasParam("AddTrigger") || hasParam("AddStaticAbility")
|| hasParam("AddReplacementEffects") || hasParam("RemoveAllAbilities")
|| hasParam("RemoveLandTypes")) {
affectedCard.removeChangedCardTraits(getTimestamp(), ability.getId());
}

if (hasParam("CantHaveKeyword")) {
affectedCard.removeCantHaveKeyword(getTimestamp());
}

affectedCard.removeChangedSVars(getTimestamp(), ability.getId());
}

if (hasParam("GainTextOf")) {
affectedCard.removeChangedName(getTimestamp(), ability.getId());
affectedCard.removeChangedManaCost(getTimestamp(), ability.getId());
affectedCard.removeColor(getTimestamp(), ability.getId());
affectedCard.removeChangedCardTypes(getTimestamp(), ability.getId());
affectedCard.removeChangedCardTraits(getTimestamp(), ability.getId());
affectedCard.removeChangedCardKeywords(getTimestamp(), ability.getId());
affectedCard.removeNewPT(getTimestamp(), ability.getId());

affectedCard.updateChangedText();
if (layers.contains(StaticAbilityLayer.SETPT)) {
if (hasParam("SetPower") || hasParam("SetToughness")) {
affectedCard.removeNewPT(getTimestamp(), ability.getId());
}
}

if (hasParam("Goad")) {
affectedCard.removeGoad(getTimestamp());
if (layers.contains(StaticAbilityLayer.MODIFYPT)) {
affectedCard.removePTBoost(getTimestamp(), ability.getId());
}

if (hasParam("CanBlockAny")) {
affectedCard.removeCanBlockAny(getTimestamp());
if (layers.contains(StaticAbilityLayer.RULES)) {
if (hasParam("AddHiddenKeyword")) {
affectedCard.removeHiddenExtrinsicKeywords(timestamp, ability.getId());
}

// remove may look at
if (hasParam("MayLookAt")) {
affectedCard.removeMayLookAt(getTimestamp());
}
if (hasParam("MayPlay")) {
affectedCard.removeMayPlay(ability);
}

if (hasParam("Goad")) {
affectedCard.removeGoad(getTimestamp());
}

if (hasParam("CanBlockAny")) {
affectedCard.removeCanBlockAny(getTimestamp());
}
if (hasParam("CanBlockAmount")) {
affectedCard.removeCanBlockAdditional(getTimestamp());
}
}
if (hasParam("CanBlockAmount")) {
affectedCard.removeCanBlockAdditional(getTimestamp());
}

affectedCard.removeChangedSVars(getTimestamp(), ability.getId());

affectedCard.updateAbilityTextForView(); // need to update keyword cache for clean reapply
}
Expand Down
13 changes: 10 additions & 3 deletions forge-game/src/main/java/forge/game/StaticEffects.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
import java.util.Map;
import java.util.Set;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import forge.game.card.Card;
import forge.game.staticability.StaticAbility;
import forge.game.staticability.StaticAbilityLayer;

/**
* <p>
Expand Down Expand Up @@ -67,12 +69,17 @@ public Iterable<StaticEffect> getEffects() {
return staticEffects.values();
}

public boolean removeStaticEffect(final StaticAbility staticAbility) {
final StaticEffect currentEffect = staticEffects.remove(staticAbility);
public boolean removeStaticEffect(final StaticAbility staticAbility, final StaticAbilityLayer layer, final boolean removeFull) {
final StaticEffect currentEffect;
if (removeFull) {
currentEffect = staticEffects.remove(staticAbility);
} else {
currentEffect = staticEffects.get(staticAbility);
}
if (currentEffect == null) {
return false;
}
currentEffect.remove();
currentEffect.remove(Lists.newArrayList(layer));
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ public final class AbilityFactory {
"FallbackAbility", // Complex Unless costs which can be unpayable
"ChooseSubAbility", // Can choose a player via ChoosePlayer
"CantChooseSubAbility", // Can't choose a player via ChoosePlayer
"AnimateSubAbility", // For ChangeZone Effects to Animate before ETB
"RegenerationAbility", // for Regeneration Effect
"ReturnAbility", // for Delayed Trigger on Magpie
"GiftAbility" // for Promise Gift
Expand Down
Loading

0 comments on commit 2eb644d

Please sign in to comment.