Explanation of why Krugal Trapper (ll073)'s ability seek does not reveal the trap card
… still in v4.981
Code Summary and Detailed Code
FILE REFERENCES IN THE GAME |
TERMS TO LOCATE SEEK REFERENCE
|
- SpecificCard.cs: Contains the logic related to specific cards and abilities such as:
`OnUseAbility()`, `CanUseAbility()`, `StartTargetingForSeek()`, `GetAbilityTargets()`, and `DoSeek()`.
- GameModel.cs: Manages the core game functions, such as:
`RemoveDeck()`, `ShowCardForPlayer()`, `AddHand()`, and `ShuffleDeck()`.
|
- OnSeek
- DoSeek
- Seek
- StartTargetingForSeek
- GetAbilityTargets
- RemoveDeck
- ShowCardForPlayer
- AddHand
|
SUMMARY OF THE SEEK PROCESS:
|
- `OnUseAbility()`: Handles the activation of the seek ability.
- `CanUseAbility()`: Checks if the seek ability can be used.
- `StartTargetingForSeek()`: Initiates the targeting process for the seek.
- `GetAbilityTargets()`: Retrieves valid targets for the seek.
- `IsValidAbilityTarget()`: Check valid target.
- `DoSeek()`: Executes the seek action:
- `GameModel.RemoveDeck(ShadowEraCard card)`: Removes the card from the deck.
- `GameModel.ShowCardForPlayer(ShadowEraCard card)`: Displays the card to the opponent.
- `GameModel.AddHand(ShadowEraCard card)`: Adds the card to the player's hand.
- `OnSeek()`: May handle additional effects after the card is added to the hand.
- `ShuffleOurDeck()`: Shuffles the deck after the seek is completed.
|
DETAILED CODE
|
This code is a collection of all the functions involved in the Seek mechanic, though it doesn't exist as a single block in any one file.
|
public override void OnUseAbility()
{
if (!isPartTwo)
{
if (!parent.IsDead())
{
MoveToCastPosition();
GameModel.QueuePart2(parent);
isPartTwo = true;
}
}
else
{
isPartTwo = false;
DoSeek(usedShadowEnergy: true);
}
// Handles the activation of the seek ability
}
public override bool CanUseAbility()
{
if (GameModel.isSimulating)
{
return false;
}
if (GameModel.DeckCount() == 0)
{
return false;
}
if (GameModel.HandCount() == GameModel.MaxHandSize())
{
return false;
}
return true;
// Checks if the seek ability can be used
}
public void StartTargetingForSeek()
{
ClearTargets();
MoveToCastPosition();
GameModel.UnhighlightCards();
GameModel.SetGameState(GameState.GameStateType.target);
List<ShadowEraCard> abilityTargets = GetAbilityTargets();
for (int i = 0; i < GameModel.DeckCount(); i++)
{
ShadowEraCard deck = GameModel.GetDeck(i);
if (abilityTargets.Contains(deck))
{
GameModel.RemoveDeck(deck);
i--;
}
}
for (int j = 0; j < abilityTargets.Count; j++)
{
GameModel.AddDeck(abilityTargets[j]);
}
GameModel.HighlightCards(GetAbilityTargets());
DeckListDisplay.abilityCard = parent;
DeckListDisplay.ShowDeck(GameModel.CurSide());
// Initiates the targeting process for the seek
}
public override List<ShadowEraCard> GetAbilityTargets()
{
List<ShadowEraCard> list = new List<ShadowEraCard>();
for (int i = 0; i < GameModel.DeckCount(); i++)
{
ShadowEraCard deck = GameModel.GetDeck(i);
if (IsValidAbilityTarget(deck))
{
list.Add(deck);
}
}
return list;
// Retrieves valid targets for the seek.
}
private static bool IsValidAbilityTarget(ShadowEraCard check)
{
return check.cardType == CardTypeEnum.Ally && check.cardSubType == CardSubTypeEnum.Aldmor;
// Check valid targets for ll041's ability example.
}
public void DoSeek(bool usedShadowEnergy)
{
DeckListDisplay.CloseDeck();
if (targets.Count > 0 && GameModel.HandCount() < GameModel.MaxHandSize())
{
GameModel.RemoveDeck(targets[0]);
GameModel.ShowCardForPlayer(targets[0]);
GameModel.AddHand(targets[0]);
GameModel.OnSeek(targets[0]);
}
else
{
GameModel.OnSeek(null);
}
ShuffleOurDeck();
targets.Clear();
// Executes the seek action
}
public static void RemoveDeck(ShadowEraCard card)
{
// Code that handles removing a card from the deck
}
public static void ShowCardForPlayer(ShadowEraCard card)
{
if (!isSimulating && Gameplay.Instance != null)
{
Gameplay.Instance.UpdateHand(forceUpdate: true);
Gameplay.Instance.ShowCard(card);
Gameplay.Instance.BlockInput(2f);
if (card.gameObject != null)
{
CoroutineManager.Start(_ShowCardForPlayer(card));
}
}
}
public static void AddHand(ShadowEraCard card)
{
// Code that handles adding a card to the player's hand
}
public static void OnSeek(ShadowEraCard card)
{
// Handles additional effects or actions after the card is added to the hand
}
public void ShuffleOurDeck()
{
GameModel.ShuffleDeck();
// Shuffles the deck after the seek is completed
}
|
English Explanation
Alan said: "Card effects take precedence over the game rules".
- This concept Alan said in english is the C# function
`AttachCard(ShadowEraCard card, bool doCallbacks = true):`
- `AttachCard()`: When a card is played or attached, the game makes it "linked" to a player, hero, or ally.
- During this pocress, if `doCallbacks = true`, additional logic, such as the card’s effects, is executed.
- `Callbacks` = Card effects: The `callbacks` trigger specific card effects, such as Rapid Fire allowing a hero to attack twice, or Net Trap disabling an enemy ally for several turns. These effects override general game rules.
- Effects > General rules: Once the `callbacks` are executed, the card effects modify or bypass the standard game rules. For example, the rule "one attack per turn" can be changed by the effect of Rapid Fire.
- Thus, `AttachCard()` and its `callbacks` manage these exceptions to the game’s general rules, allowing card-specific effects to take precedence when triggered.
- As such, the sentence "Card effects take precedence over the game rules" should be understood as: Card effects take precedence over the game rules, as well as over any previous effects that have already modified those rules.
- schema: Game Rules < Card Effect 1 `(doCallbacks = true)` -> Modified Game Rules < Card Effect 2 `(doCallbacks = true)` -> Further Modified Game Rules < Card Effect 3 `(doCallbacks = true)` -> ...
- Relation to Traps and Why They Are Not Revealed
- The global mechanism for Traps, that they must remain face-down, is integrated into the steps of the Seek process. This mechanism takes priority over other rules, such as revealing a card that has been Seeked.
- When a Trap is Seeked, the face-down rule `(PlayFaceDown())` inherent to Traps is triggered before any reveal function `(ShowCardForPlayer())` can be called. This ensures that the Trap stays hidden, overriding the normal rule that states Seeked cards must be revealed.
- This behavior highlights how card effects take precedence over standard game rules. The face-down condition bypasses the normal `ShowCardForPlayer()` function, ensuring that Traps remain hidden in compliance with their unique mechanics.
- Therefore, while the Seek process normally requires cards to be revealed, the Trap mechanic ensures that this reveal is skipped. The handling of Traps shows how `AttachCard()` triggers card-specific logic (via `callbacks`) that overrides the default rules, allowing Traps to stay face-down as intended.
- Intentional or not?
Yes we may say that the behavior of Traps not revealed after Seek function is intentionally coded by the developers, and here is why:
- Traps have specific mechanics that are fundamental to their function: they are played facedown and only revealed when triggered. There is no exception; if a Trap is revealed faceup in the graveyard it is because cards are placed faceup in the graveyard process; if a trap is returned to hand, nothing says in the returned to hand process that it should be revealed.
- The fact that Traps aren’t revealed during a Seek mechanism follows the logic of the game. The code appears to be structured to ensure this rule is confirmed by preventing the `ShowCardForPlayer()` function from being triggered for Traps.
- Functions like `PlayFaceDown()` and specific conditions in the code show that the developers have built these special rules for Traps, and they take effect before the standard rules and the standard rules modified by other effects apply.
- Now, the following example code would essentially stop `PlayFaceDown()` from bypassing the reveal process for Seeked cards.
- So, if the developpers of the game wanted to modify the `PlayFaceDown()` behavior as not that explicitly stated in the rulebook, but as the players would like it to be, they would likely handle the situation easily. It would only require a global phase test.
|void PlayFaceDown(ShadowEraCard card, bool isSeeked)
{
if (isSeeked)
{
// Allow ShowCardForPlayer() to be invoked for Seeked cards
ShowCardForPlayer(card);
}
else
{
// Keep the card face-down as usual (normal Trap behavior)
KeepCardFaceDown(card);
}
}
|