m (code and content added) |
m |
||
(31 intermediate revisions by one user not shown) | |||
Line 1: | Line 1: | ||
− | <center><big>Explanation of why [[Krugal Trapper]] (ll073)'s ability does not reveal the trap card</big><br /> | + | __TOC__ |
+ | <center><img src="https://www.shadowera.com/landing/img/blog-separator-2.png" ></center> | ||
+ | <center><big>Explanation of why [[Krugal Trapper]] (ll073)'s ability '''[[:Category:Seek|seek]]''' does not reveal the trap card</big><br /> | ||
… still in v4.981</center> | … still in v4.981</center> | ||
<center><img src="https://www.shadowera.com/landing/img/blog-separator-2.png" ></center><br /> | <center><img src="https://www.shadowera.com/landing/img/blog-separator-2.png" ></center><br /> | ||
− | <span style="color:orange;">Alan said: "Card effects take precedence over the game rules | + | == Code Summary and Detailed Code == |
+ | {| class="wikitable" code-table" | ||
+ | |- | ||
+ | ! <center>FILE REFERENCES IN THE GAME</center> || <center>TERMS TO LOCATE SEEK REFERENCE</center> | ||
+ | |- | ||
+ | | style="vertical-align: top;" | | ||
+ | * <span style="color: violet;">SpecificCard.cs</span>: Contains the logic related to specific cards and abilities such as:<br /> `OnUseAbility()`, `CanUseAbility()`, `StartTargetingForSeek()`, `GetAbilityTargets()`, and `DoSeek()`.<br /><br /> | ||
+ | * <span style="color: violet;">GameModel.cs</span>: Manages the core game functions, such as:<br /> `RemoveDeck()`, `ShowCardForPlayer()`, `AddHand()`, and `ShuffleDeck()`. | ||
+ | | style="vertical-align: top;" | | ||
+ | * OnSeek | ||
+ | * DoSeek | ||
+ | * Seek | ||
+ | * StartTargetingForSeek | ||
+ | * GetAbilityTargets | ||
+ | * RemoveDeck | ||
+ | * ShowCardForPlayer | ||
+ | * AddHand | ||
+ | |- | ||
+ | ! colspan="2" | <center>SUMMARY OF THE SEEK PROCESS:</center> | ||
+ | |- | ||
+ | | colspan="2" | | ||
+ | # `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. | ||
+ | |- | ||
+ | ! colspan="2" | <center>DETAILED CODE</center> | ||
+ | |- | ||
+ | | colspan="2" | 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. | ||
+ | |- | ||
+ | | colspan="2" | | ||
+ | <small><syntaxhighlight lang="csharp"> | ||
+ | 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 | ||
+ | } | ||
+ | </syntaxhighlight></small> | ||
+ | |} | ||
+ | |||
+ | == English Explanation == | ||
+ | |||
+ | <span style="color:orange;">Alan said: "Card effects take precedence over the game rules".<br /><br /> | ||
− | * This concept Alan said in english is the function < | + | * This concept Alan said in english is the C# function<br /> `AttachCard(ShadowEraCard card, bool doCallbacks = true):`<div style="height: 10px;"></div> |
− | *# | + | *# `AttachCard()`: When a card is played or attached, the game makes it "linked" to a player, hero, or ally. |
− | *# During this pocress, if | + | *# 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. | + | *# '''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, | + | *# Thus, `AttachCard()` and its `callbacks` manage these exceptions to the game’s general rules, allowing card-specific effects to take precedence when triggered.<br /> |
+ | **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'''.<br /> | ||
+ | *** 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)` -> ...<div style="height: 20px;"></div> | ||
* Relation to Traps and Why They Are Not Revealed<div style="height: 10px;"></div> | * Relation to Traps and Why They Are Not Revealed<div style="height: 10px;"></div> | ||
*# 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 '''Seek'''ed.<br /> | *# 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 '''Seek'''ed.<br /> | ||
− | *# When a Trap is '''Seek'''ed, the face-down rule | + | *# When a Trap is '''Seek'''ed, 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 '''Seek'''ed cards must be revealed. |
− | *# This behavior highlights how card effects take precedence over standard game rules. The face-down condition bypasses the normal | + | *# 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 | + | *# 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.<div style="height: 20px;"></div> |
* Intentional or not?<br />Yes we may say that the behavior of Traps not revealed after '''Seek''' function is intentionally coded by the developers, and here is why:<br /> | * Intentional or not?<br />Yes we may say that the behavior of Traps not revealed after '''Seek''' function is intentionally coded by the developers, and here is why:<br /> | ||
− | *# Traps have specific mechanics that are fundamental | + | *# 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 | + | *# 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 | + | *# 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 | + | *# Now, the following example code would essentially stop `PlayFaceDown()` from bypassing the reveal process for '''Seek'''ed cards. |
− | *# So, if the | + | *# 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. |
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
− | |void PlayFaceDown(ShadowEraCard card, bool isSeeked) | + | | |
+ | <syntaxhighlight lang="csharp">|void PlayFaceDown(ShadowEraCard card, bool isSeeked) | ||
{ | { | ||
if (isSeeked) | if (isSeeked) | ||
{ | { | ||
− | // Allow | + | // Allow ShowCardForPlayer() to be invoked for Seeked cards |
− | + | ShowCardForPlayer(card); | |
} | } | ||
else | else | ||
Line 35: | Line 221: | ||
KeepCardFaceDown(card); | KeepCardFaceDown(card); | ||
} | } | ||
− | } | + | }</syntaxhighlight> |
|} | |} | ||
− | + | <br /><br /> | |
− | + | ||
− | + | ||
[[Category:Seek]] | [[Category:Seek]] |
|
|
---|---|
|
|
| |
| |
| |
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 } |
Alan said: "Card effects take precedence over the game rules".
|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); } } |