/// <summary>Unalias some Cards, e.g. before a shuffle</summary> /// <param name="card">An array containing the Card ids to unalias.</param> /// <param name="type">An array containing the corresponding revealed CardIdentity ids.</param> public void Unalias(int[] card, ulong[] type) { if (card.Length != type.Length) { Program.TraceWarning("[Unalias] Card and type lengths don't match."); return; } Pile g = null; List <int> cards = new List <int>(card.Length); List <ulong> types = new List <ulong>(card.Length); for (int i = 0; i < card.Length; i++) { Card c = Card.Find(card[i]); if (c == null) { Program.TraceWarning("[Unalias] Card not found."); continue; } if (g == null) { g = c.Group as Pile; } else if (g != c.Group) { Program.TraceWarning("[Unalias] Not all cards belong to the same group!"); continue; } // Check nobody cheated if (!c.Type.MySecret) { if (c.Type.Key != Crypto.ModExp(type[i])) { Program.TraceWarning("[Unalias] Card identity doesn't match."); } } // Substitue the card's identity CardIdentity ci = CardIdentity.Find((int)type[i]); if (ci == null) { Program.TraceWarning("[Unalias] Card identity not found."); continue; } CardIdentity.Delete(c.Type.Id); c.Type = ci; // Propagate unaliasing if (ci.Alias && ci.MySecret) { cards.Add(c.Id); } types.Add(ci.Key); } if (cards.Count > 0) { Program.Client.Rpc.Unalias(cards.ToArray(), types.ToArray()); } if (g == null) { return; } if (!g.PreparingShuffle) { Program.TraceWarning("[Unalias] Cards revealed are not in a group prepared for shuffle."); return; } // If all cards are now revealed, one can proceed to shuffling if (!g.WantToShuffle) { return; } bool done = false; for (int i = 0; !done && i < g.Count; i++) { done = g[i].Type.Alias; } if (!done) { g.DoShuffle(); } }
/// <summary>Reveal one card's identity</summary> /// <param name="card">The card, whose identity is revealed</param> /// <param name="revealed">Either the salted CardIdentity id (in the case of an alias), or the salted, condensed Card GUID.</param> /// <param name="guid"> </param> public void Reveal(Card card, ulong revealed, Guid guid) { // Save old id CardIdentity oldType = card.Type; // Check if the card is rightfully revealed if (!card.Type.Revealing) { Program.Trace.TraceEvent(TraceEventType.Warning, EventIds.Event, "Someone tries to reveal a card which is not visible to everybody."); } // Check if we can trust other clients if (!card.Type.MySecret) { if (guid != Guid.Empty && (uint)revealed != guid.Condense()) { Program.Trace.TraceEvent(TraceEventType.Warning, EventIds.Event, "[Reveal] Alias and id aren't the same. One client is buggy or tries to cheat."); } if (Crypto.ModExp(revealed) != card.Type.Key) { Program.Trace.TraceEvent(TraceEventType.Warning, EventIds.Event, "[Reveal] Card identity doesn't match. One client is buggy or tries to cheat."); } } else { card.Type.MySecret = false; } // Reveal an alias if (guid == Guid.Empty) { // Find the new type CardIdentity newId = CardIdentity.Find((int)revealed); // HACK: it is unclear to me how the CardIdentity could not be found and newId ends up null // see this bug report: https://octgn.16bugs.com/projects/3602/bugs/192070 // for now I'm just doing nothing (supposing that it means the type was already revealed). if (newId == null) { card.Reveal(); return; } // Possibly copy the model, if it was known and isn't anymore // (possible when the alias has beeen locally revealed) if (newId.Model == null) { newId.Model = card.Type.Model; } // Set the new type card.Type = newId; // Delete the old identity CardIdentity.Delete(oldType.Id); // Possibly reveal the alias further card.Reveal(); // Raise a notification oldType.OnRevealed(newId); } // Reveal a card's type else if (card.Type.Model == null) { card.SetModel(Program.GameEngine.Definition.GetCardById(guid)); // Raise a notification oldType.OnRevealed(oldType); } }