using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; using ICSharpCode.SharpZipLib.Zip; using DominionBase.Utilities; namespace Dominion.NET_WPF { delegate void player_ChooseDelegate(DominionBase.Players.Player player, DominionBase.Choice choice); /// /// Interaction logic for wMain.xaml /// public partial class wMain : Window { private static Settings _Settings = null; public static Settings Settings { get { return _Settings; } private set { _Settings = value; } } private DominionBase.Game game = null; private DominionBase.Players.Player _Player = null; private VersionInfo latestVersionInfo = null; private Dictionary _MatEventHandlers = new Dictionary(); private Thread gameThread = null; public AutoResetEvent WaitEvent = new AutoResetEvent(false); private Label _TradeRouteLabel = null; private int _CurrentPlayDepth = 0; private Boolean _StartingNewGame = false; private Statistics _Statistics = null; public wMain() { InitializeComponent(); bTurnDone.IsEnabled = false; bPlayTreasures.IsEnabled = false; bBuyPhase.IsEnabled = false; cardTrash.PileName = "Trash"; _Statistics = Statistics.Load(); } private void Window_Initialized(object sender, EventArgs e) { wMain.Settings = Settings.Load(); #if DEBUG #else try { CheckForUpdates(false); } catch { } #endif glMain.LogFile = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "game.log"); if (_Settings.WindowSize.Width > 0) this.Width = _Settings.WindowSize.Width; if (_Settings.WindowSize.Height > 0) this.Height = _Settings.WindowSize.Height; this.WindowState = _Settings.WindowState; } private void EnqueueGameMessageAndWait(DominionBase.GameMessage message) { lock (game.MessageRequestQueue) game.MessageRequestQueue.Enqueue(message); game.WaitEvent.Set(); while (game.MessageResponseQueue.Count == 0) Thread.Sleep(100); } private void ReleaseEvents() { if (game == null) return; game.GameEndedEvent -= new DominionBase.Game.GameEndedEventHandler(game_GameEndedEvent); game.GameMessage -= new DominionBase.Game.GameMessageEventHandler(game_GameMessage); if (game.Table != null) { if (game.Table.TokenPiles != null) game.Table.TokenPiles.TokenCollectionsChanged -= new DominionBase.TokenCollections.TokenCollectionsChangedEventHandler(TokenPiles_TokenCollectionsChanged); if (game.Table.Trash != null) game.Table.Trash.PileChanged -= new DominionBase.Piles.Pile.PileChangedEventHandler(Trash_PileChanged); if (game.Table.SpecialPiles.ContainsKey(DominionBase.Cards.Promotional.TypeClass.BlackMarketSupply)) game.Table.SpecialPiles[DominionBase.Cards.Promotional.TypeClass.BlackMarketSupply].PileChanged -= _MatEventHandlers[DominionBase.Cards.Promotional.TypeClass.BlackMarketSupply]; if (game.Table.SpecialPiles.ContainsKey(DominionBase.Cards.Cornucopia.TypeClass.PrizeSupply)) game.Table.SpecialPiles[DominionBase.Cards.Cornucopia.TypeClass.PrizeSupply].PileChanged -= _MatEventHandlers[DominionBase.Cards.Cornucopia.TypeClass.PrizeSupply]; if (game.Table.SpecialPiles.ContainsKey(DominionBase.Cards.DarkAges.TypeClass.Madman)) game.Table.SpecialPiles[DominionBase.Cards.DarkAges.TypeClass.Madman].PileChanged -= _MatEventHandlers[DominionBase.Cards.DarkAges.TypeClass.Madman]; if (game.Table.SpecialPiles.ContainsKey(DominionBase.Cards.DarkAges.TypeClass.Mercenary)) game.Table.SpecialPiles[DominionBase.Cards.DarkAges.TypeClass.Mercenary].PileChanged -= _MatEventHandlers[DominionBase.Cards.DarkAges.TypeClass.Mercenary]; if (game.Table.SpecialPiles.ContainsKey(DominionBase.Cards.DarkAges.TypeClass.Spoils)) game.Table.SpecialPiles[DominionBase.Cards.DarkAges.TypeClass.Spoils].PileChanged -= _MatEventHandlers[DominionBase.Cards.DarkAges.TypeClass.Spoils]; } if (game.Players != null) { foreach (DominionBase.Players.Player player in game.Players) { player.Choose = null; player.Revealed.PileChanged -= new DominionBase.Piles.Pile.PileChangedEventHandler(Revealed_PileChanged); player.BenefitReceiving -= new DominionBase.Players.Player.BenefitReceivingEventHandler(player_BenefitReceiving); player.CardPlaying -= new DominionBase.Players.Player.CardPlayingEventHandler(player_CardPlaying); player.CardPlayed -= new DominionBase.Players.Player.CardPlayedEventHandler(player_CardPlayed); player.CardBuying -= new DominionBase.Players.Player.CardBuyingEventHandler(player_CardBuying); player.CardBought -= new DominionBase.Players.Player.CardBoughtEventHandler(player_CardBought); player.CardBuyFinished -= new DominionBase.Players.Player.CardBuyFinishedEventHandler(player_CardBuyFinished); player.CardGaining -= new DominionBase.Players.Player.CardGainingEventHandler(player_CardGaining); player.CardGainedInto -= new DominionBase.Players.Player.CardGainedIntoEventHandler(player_CardGainedInto); player.CardGainFinished -= new DominionBase.Players.Player.CardGainFinishedEventHandler(player_CardGainFinished); player.Trashing -= new DominionBase.Players.Player.TrashingEventHandler(player_Trashing); player.TrashedFinished -= new DominionBase.Players.Player.TrashedFinishedEventHandler(player_Trashed); player.PhaseChanged -= new DominionBase.Players.Player.PhaseChangedEventHandler(player_PhaseChangedEvent); player.CardsDrawn -= new DominionBase.Players.Player.CardsDrawnEventHandler(player_CardsDrawn); player.TurnStarting -= new DominionBase.Players.Player.TurnStartingEventHandler(player_TurnStarting); player.Shuffling -= new DominionBase.Players.Player.ShufflingEventHandler(player_Shuffle); player.CardsAddedToDeck -= new DominionBase.Players.Player.CardsAddedToDeckEventHandler(player_CardsAddedToDeck); player.CardsAddedToHand -= new DominionBase.Players.Player.CardsAddedToHandEventHandler(player_CardsAddedToHand); player.CardsDiscarded -= new DominionBase.Players.Player.CardsDiscardedEventHandler(player_CardsDiscarded); player.PlayerMats.CardMatsChanged -= new DominionBase.Piles.CardMats.CardMatsChangedEventHandler(PlayerMats_DecksChanged); player.TokenPiles.TokenCollectionsChanged -= new DominionBase.TokenCollections.TokenCollectionsChangedEventHandler(PlayerTokenPiles_TokenCollectionsChanged); player.BenefitsChanged -= new DominionBase.Players.Player.BenefitsChangedEventHandler(player_BenefitsChanged); if (player == _Player) { player.CardReceived -= new DominionBase.Players.Player.CardReceivedEventHandler(player_CardReceived); } } } } private void ReleaseGame() { _Player = null; uccChooser.IsReady = false; cardTrash.Pile = null; foreach (TabItem ti in tcAreas.Items) { if (ti.Content is Controls.ucPlayerDisplay) { (ti.Content as Controls.ucPlayerDisplay).TearDown(); (((ti.Header as DockPanel).ToolTip as ToolTip).Content as Controls.ucPlayerOverview).TearDown(); } } foreach (StackPanel sp in stackPanelSupplyPiles.Children.OfType()) { foreach (SupplyControl sc in sp.Children.OfType()) { sc.Supply = null; } } if (game == null) return; ReleaseEvents(); game.Clear(); game = null; GC.Collect(); GC.Collect(1); GC.Collect(2); GC.Collect(3); GC.WaitForPendingFinalizers(); GC.Collect(); } private void StartGame(DominionBase.GameSettings settings) { _StartingNewGame = false; ReleaseGame(); wMain.Settings = Settings.Load(); // Clean out the Image Repository before starting a new game -- // so we don't allocate too much memory for cards we're not even using Caching.ImageRepository.Reset(); glMain.TearDown(); glMain.Clear(); while (tcAreas.Items.Count > 1) tcAreas.Items.RemoveAt(1); dpMatsandPiles.Children.Clear(); dpGameStuff.Children.Clear(); _TradeRouteLabel = null; // Try to force garbage collection to save some memory GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); try { game = new DominionBase.Game( _Settings.NumberOfHumanPlayers, _Settings.PlayerSettings.Take(_Settings.NumberOfPlayers).Select(ps => ps.Name), _Settings.PlayerSettings.Take(_Settings.NumberOfPlayers).Select(ps => ps.AIClassType), settings); } catch (DominionBase.Cards.ConstraintException ce) { MessageBox.Show(ce.Message, "Constraint exception!", MessageBoxButton.OK, MessageBoxImage.Exclamation); return; } catch (DominionBase.GameCreationException gce) { MessageBox.Show(gce.Message, "Game creation exception!", MessageBoxButton.OK, MessageBoxImage.Exclamation); return; } game.GameEndedEvent += new DominionBase.Game.GameEndedEventHandler(game_GameEndedEvent); glMain.NewSection(String.Format("Game started with {0} players", game.Players.Count)); game.Table.TokenPiles.TokenCollectionsChanged += new DominionBase.TokenCollections.TokenCollectionsChangedEventHandler(TokenPiles_TokenCollectionsChanged); game.Table.Trash.PileChanged += new DominionBase.Piles.Pile.PileChangedEventHandler(Trash_PileChanged); Trash_PileChanged(game.Table.Trash, new DominionBase.Piles.PileChangedEventArgs(DominionBase.Piles.PileChangedEventArgs.Operation.Reset)); game.GameMessage += new DominionBase.Game.GameMessageEventHandler(game_GameMessage); foreach (DominionBase.Players.Player player in game.Players.FindAll(p => p.PlayerType == DominionBase.Players.PlayerType.Human)) player.Choose = player_Choose; if (game.Players.Any(player => player.PlayerType == DominionBase.Players.PlayerType.Human)) _Player = game.Players.OfType().First(); else _Player = null; glMain.Log("Using the following cards: "); IEnumerable kingdomSupplies = game.Table.Supplies.Where(kvp => kvp.Value.Randomizer.Location == DominionBase.Cards.Location.Kingdom).Select(kvp => kvp.Value).OrderBy(s => s.Name); glMain.Log(" ", kingdomSupplies.Take(5)); glMain.Log(" ", kingdomSupplies.Skip(5)); int prosperityPiles = game.Table.Supplies.Count(kvp => kvp.Value.Location == DominionBase.Cards.Location.Kingdom && kvp.Value.Source == DominionBase.Cards.Source.Prosperity); int darkAgesPiles = game.Table.Supplies.Count(kvp => kvp.Value.Location == DominionBase.Cards.Location.Kingdom && kvp.Value.Source == DominionBase.Cards.Source.DarkAges); int kingdomPiles = game.Table.Supplies.Count(kvp => kvp.Value.Location == DominionBase.Cards.Location.Kingdom && kvp.Value.Tokens.Count(t => t.GetType() == DominionBase.Cards.Cornucopia.TypeClass.BaneToken) == 0); glMain.Log(String.Format("Prosperity Kingdom card ratio is {0}/{1} = {2:P0}", prosperityPiles, kingdomPiles, ((float)prosperityPiles) / kingdomPiles )); glMain.Log(String.Format(" Colony / Platinum {0}selected", game.Settings.ColonyPlatinumUsage == DominionBase.ColonyPlatinumUsage.Used ? "" : "not " )); glMain.Log(String.Format("Dark Ages Kingdom card ratio is {0}/{1} = {2:P0}", darkAgesPiles, kingdomPiles, ((float)darkAgesPiles) / kingdomPiles )); glMain.Log(String.Format(" Shelters {0}selected", game.Settings.ShelterUsage == DominionBase.ShelterUsage.Used ? "" : "not " )); glMain.Log("Turn order is: ", String.Join(", ", game.Players.Select(p => p == _Player ? String.Format("{0} (You)", p.Name) : p.Name))); Type[] specialTypes = new Type[] { DominionBase.Cards.Promotional.TypeClass.BlackMarketSupply, DominionBase.Cards.Cornucopia.TypeClass.PrizeSupply, DominionBase.Cards.DarkAges.TypeClass.Madman, DominionBase.Cards.DarkAges.TypeClass.Mercenary, DominionBase.Cards.DarkAges.TypeClass.Spoils }; foreach (Type specialType in specialTypes) { if (game.Table.SpecialPiles.ContainsKey(specialType)) { _MatEventHandlers[specialType] = new DominionBase.Piles.Pile.PileChangedEventHandler(GamePile_PileChanged); game.Table.SpecialPiles[specialType].PileChanged += _MatEventHandlers[specialType]; GamePile_PileChanged(game.Table.SpecialPiles[specialType], new DominionBase.Piles.PileChangedEventArgs(DominionBase.Piles.PileChangedEventArgs.Operation.Reset)); } } if (game.Table.Supplies.ContainsKey(DominionBase.Cards.Prosperity.TypeClass.TradeRoute)) { if (dpGameStuff.Children.Count > 0) { Border bDiv = new Border(); bDiv.BorderThickness = new Thickness(2); bDiv.BorderBrush = Brushes.Black; Panel.SetZIndex(bDiv, 1); DockPanel.SetDock(bDiv, Dock.Left); dpGameStuff.Children.Add(bDiv); } Label lTradeRoute = new Label(); lTradeRoute.Content = "Trade Route Tokens:"; lTradeRoute.FontSize = 16d; lTradeRoute.FontWeight = FontWeights.Bold; lTradeRoute.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Right; lTradeRoute.Background = Caching.BrushRepository.GetBrush(DominionBase.Cards.Category.Treasure); DockPanel.SetDock(lTradeRoute, Dock.Left); dpGameStuff.Children.Add(lTradeRoute); _TradeRouteLabel = new Label(); _TradeRouteLabel.Content = "0"; _TradeRouteLabel.FontWeight = FontWeights.Bold; _TradeRouteLabel.VerticalAlignment = System.Windows.VerticalAlignment.Stretch; _TradeRouteLabel.VerticalContentAlignment = System.Windows.VerticalAlignment.Center; _TradeRouteLabel.Background = Caching.BrushRepository.GetBrush(DominionBase.Cards.Category.Treasure); _TradeRouteLabel.Padding = new Thickness(0, 0, 5, 0); _TradeRouteLabel.BorderThickness = new Thickness(0, 0, 1, 0); DockPanel.SetDock(_TradeRouteLabel, Dock.Left); dpGameStuff.Children.Add(_TradeRouteLabel); } if (dpGameStuff.Children.Count > 0) bStuffDivider.Visibility = System.Windows.Visibility.Visible; else bStuffDivider.Visibility = System.Windows.Visibility.Collapsed; foreach (DominionBase.Players.Player player in game.Players) { TabItem tiPlayer = new TabItem(); DockPanel dpHeader = new DockPanel(); Image iHeader = new Image(); iHeader.Stretch = Stretch.None; iHeader.Margin = new Thickness(0, 0, 5, 0); DockPanel.SetDock(iHeader, Dock.Left); switch (player.PlayerType) { case DominionBase.Players.PlayerType.Human: iHeader.Source = (BitmapImage)this.Resources["imHuman"]; break; case DominionBase.Players.PlayerType.Computer: iHeader.Source = (BitmapImage)this.Resources["imComputer"]; break; } dpHeader.Children.Add(iHeader); TextBlock tbHeader = new TextBlock(); tbHeader.Text = player.Name; dpHeader.Children.Add(tbHeader); tiPlayer.Header = dpHeader; tcAreas.Items.Add(tiPlayer); Controls.ucPlayerDisplay ucpdPlayer = new Controls.ucPlayerDisplay(); tiPlayer.Content = ucpdPlayer; ucpdPlayer.IsUIPlayer = (player == _Player); ucpdPlayer.Player = player; PlayerSettings playerSettings = _Settings.PlayerSettings.FirstOrDefault(ps => ps.Name == player.Name); if (playerSettings != null) { tiPlayer.Background = new SolidColorBrush(playerSettings.UIColor); ucpdPlayer.ColorFocus = playerSettings.UIColor; } ToolTip tt = new System.Windows.Controls.ToolTip(); Controls.ucPlayerOverview ucpo = new Controls.ucPlayerOverview(); ucpo.Player = player; tt.Content = ucpo; ToolTipService.SetToolTip(dpHeader, tt); if (Settings.ToolTipShowDuration == ToolTipShowDuration.Off) ToolTipService.SetIsEnabled(dpHeader, false); else { ToolTipService.SetIsEnabled(dpHeader, true); ToolTipService.SetShowDuration(dpHeader, (int)Settings.ToolTipShowDuration); } dpHeader.MouseDown += new MouseButtonEventHandler(tiPlayer_MouseDown); dpHeader.MouseUp += new MouseButtonEventHandler(tiPlayer_MouseUp); player.Revealed.PileChanged += new DominionBase.Piles.Pile.PileChangedEventHandler(Revealed_PileChanged); player.BenefitReceiving += new DominionBase.Players.Player.BenefitReceivingEventHandler(player_BenefitReceiving); //player.DiscardPile.PileChanged += new DominionBase.Pile.PileChangedEventHandler(DiscardPile_PileChanged); player.CardPlaying += new DominionBase.Players.Player.CardPlayingEventHandler(player_CardPlaying); player.CardPlayed += new DominionBase.Players.Player.CardPlayedEventHandler(player_CardPlayed); player.CardBuying += new DominionBase.Players.Player.CardBuyingEventHandler(player_CardBuying); player.CardBought += new DominionBase.Players.Player.CardBoughtEventHandler(player_CardBought); player.CardBuyFinished += new DominionBase.Players.Player.CardBuyFinishedEventHandler(player_CardBuyFinished); player.CardGaining += new DominionBase.Players.Player.CardGainingEventHandler(player_CardGaining); player.CardGainedInto += new DominionBase.Players.Player.CardGainedIntoEventHandler(player_CardGainedInto); player.CardGainFinished += new DominionBase.Players.Player.CardGainFinishedEventHandler(player_CardGainFinished); player.Trashing += new DominionBase.Players.Player.TrashingEventHandler(player_Trashing); player.TrashedFinished += new DominionBase.Players.Player.TrashedFinishedEventHandler(player_Trashed); player.PhaseChanged += new DominionBase.Players.Player.PhaseChangedEventHandler(player_PhaseChangedEvent); player.CardsDrawn += new DominionBase.Players.Player.CardsDrawnEventHandler(player_CardsDrawn); player.TurnStarting += new DominionBase.Players.Player.TurnStartingEventHandler(player_TurnStarting); player.Shuffling += new DominionBase.Players.Player.ShufflingEventHandler(player_Shuffle); player.CardsAddedToDeck += new DominionBase.Players.Player.CardsAddedToDeckEventHandler(player_CardsAddedToDeck); player.CardsAddedToHand += new DominionBase.Players.Player.CardsAddedToHandEventHandler(player_CardsAddedToHand); player.CardsDiscarded += new DominionBase.Players.Player.CardsDiscardedEventHandler(player_CardsDiscarded); player.PlayerMats.CardMatsChanged += new DominionBase.Piles.CardMats.CardMatsChangedEventHandler(PlayerMats_DecksChanged); player.TokenPiles.TokenCollectionsChanged += new DominionBase.TokenCollections.TokenCollectionsChangedEventHandler(PlayerTokenPiles_TokenCollectionsChanged); player.BenefitsChanged += new DominionBase.Players.Player.BenefitsChangedEventHandler(player_BenefitsChanged); if (player == _Player) { tcAreas.SelectedItem = tiPlayer; player.CardReceived += new DominionBase.Players.Player.CardReceivedEventHandler(player_CardReceived); } } LayoutSupplyPiles(); miNewGame.IsEnabled = false; miEndGame.IsEnabled = true; gameThread = new Thread(game.StartAsync); gameThread.Start(); UpdateDisplay(); } private void LayoutSupplyPiles() { if (game == null) return; stackPanelSupplyPiles.Children.Clear(); int pilesPerColumn = 0; switch (_Settings.LayoutStyle) { case LayoutStyle.Supply2Columns: pilesPerColumn = Math.Max( game.Table.Supplies.Count(skv => skv.Value.Location == DominionBase.Cards.Location.Kingdom), game.Table.Supplies.Count(skv => skv.Value.Location == DominionBase.Cards.Location.General)); break; case LayoutStyle.Supply4Columns: pilesPerColumn = Math.Max( (game.Table.Supplies.Count(skv => skv.Value.Location == DominionBase.Cards.Location.Kingdom) + 1) / 2, (game.Table.Supplies.Count(skv => skv.Value.Location == DominionBase.Cards.Location.General) + 1) / 2); break; } StackPanel spFirstAction = new StackPanel(); spFirstAction.FlowDirection = System.Windows.FlowDirection.LeftToRight; spFirstAction.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; spFirstAction.Margin = new Thickness(0, 0, 4, 0); stackPanelSupplyPiles.Children.Add(spFirstAction); Border borderSupply = new Border(); borderSupply.BorderThickness = new Thickness(1); borderSupply.BorderBrush = Brushes.DarkSlateBlue; stackPanelSupplyPiles.Children.Add(borderSupply); StackPanel spFirstGeneral = new StackPanel(); spFirstGeneral.FlowDirection = System.Windows.FlowDirection.LeftToRight; spFirstGeneral.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; spFirstGeneral.Margin = new Thickness(0, 0, 4, 0); stackPanelSupplyPiles.Children.Add(spFirstGeneral); StackPanel spCurrentAction = spFirstAction; StackPanel spCurrentGeneral = spFirstGeneral; foreach (Type supplyType in game.Table.SupplyKeysOrdered) { StackPanel sp = null; switch (game.Table.Supplies[supplyType].Location) { case DominionBase.Cards.Location.General: sp = spCurrentGeneral; if (_Settings.LayoutStyle == LayoutStyle.Supply4Columns && sp.Children.Count > 0 && sp.Children.OfType().Last().Supply.Category == DominionBase.Cards.Category.Curse) { sp = new StackPanel(); sp.FlowDirection = System.Windows.FlowDirection.LeftToRight; sp.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; sp.Margin = new Thickness(0, 0, 4, 0); borderSupply = new Border(); borderSupply.BorderThickness = new Thickness(1); borderSupply.BorderBrush = Brushes.DarkSlateBlue; stackPanelSupplyPiles.Children.Add(borderSupply); stackPanelSupplyPiles.Children.Add(sp); spCurrentGeneral = sp; } break; case DominionBase.Cards.Location.Kingdom: sp = spCurrentAction; if (sp.Children.OfType().Count() >= pilesPerColumn) { sp = new StackPanel(); sp.FlowDirection = System.Windows.FlowDirection.LeftToRight; sp.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; sp.Margin = new Thickness(0, 0, 4, 0); borderSupply = new Border(); borderSupply.BorderThickness = new Thickness(1); borderSupply.BorderBrush = Brushes.DarkSlateBlue; stackPanelSupplyPiles.Children.Insert(stackPanelSupplyPiles.Children.IndexOf(spFirstGeneral), sp); stackPanelSupplyPiles.Children.Insert(stackPanelSupplyPiles.Children.IndexOf(spFirstGeneral), borderSupply); spCurrentAction = sp; } break; default: continue; } SupplyControl newSC = new SupplyControl(); sp.Children.Add(newSC); int previousSCIndex = sp.Children.Count - 1; while (previousSCIndex >= 0 && !(sp.Children[previousSCIndex--] is SupplyControl)) ; newSC.HorizontalAlignment = HorizontalAlignment.Stretch; newSC.Width = sp.Width; newSC.Supply = game.Table.Supplies[supplyType]; if (previousSCIndex >= 0) { if ((game.Table.Supplies[supplyType].Location == DominionBase.Cards.Location.General && ((SupplyControl)sp.Children[previousSCIndex]).Supply.Category != newSC.Supply.Category) || (game.Table.Supplies[supplyType].Location == DominionBase.Cards.Location.Kingdom && ((SupplyControl)sp.Children[previousSCIndex]).Supply.Randomizer.BaseCost != newSC.Supply.Randomizer.BaseCost)) { borderSupply = new Border(); borderSupply.Margin = new Thickness(15, 0, 15, 0); borderSupply.BorderThickness = new Thickness(1); borderSupply.BorderBrush = Brushes.LightSkyBlue; sp.Children.Insert(sp.Children.Count - 1, borderSupply); } } } CheckBuyable(game.ActivePlayer); stackPanelSupplyPiles.InvalidateVisual(); rdGrid0.Height = new GridLength(stackPanelSupplyPiles.ActualHeight + 5); rdGrid0.Height = GridLength.Auto; } void tiPlayer_MouseDown(object sender, MouseButtonEventArgs e) { if (Settings != null && Settings.ShowToolTipOnRightClick && e.ChangedButton == MouseButton.Right && e.ButtonState == MouseButtonState.Pressed) { (sender as UIElement).CaptureMouse(); FrameworkElement element = sender as FrameworkElement; ToolTip tt = element.ToolTip as ToolTip; Controls.ucPlayerOverview ucpo = (tt.Content as Controls.ucPlayerOverview); ucpo.Turn = game.TurnsTaken.LastOrDefault(t => t.Player == ((element.Parent as ContentControl).Content as Controls.ucPlayerDisplay).Player && t != game.CurrentTurn); tt.IsOpen = true; } } void tiPlayer_MouseUp(object sender, MouseButtonEventArgs e) { if (Settings != null && Settings.ShowToolTipOnRightClick && e.ChangedButton == MouseButton.Right && e.ButtonState == MouseButtonState.Released) { (sender as UIElement).ReleaseMouseCapture(); ToolTip tt = (sender as FrameworkElement).ToolTip as ToolTip; tt.IsOpen = false; } } void game_GameMessage(object sender, DominionBase.GameMessageEventArgs e) { if (this.Dispatcher.CheckAccess()) { Type cardType = e.SourceCard.CardType; if (cardType == DominionBase.Cards.Base.TypeClass.Chancellor || cardType == DominionBase.Cards.Cornucopia.TypeClass.TrustySteed || cardType == DominionBase.Cards.DarkAges.TypeClass.Scavenger) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" put{0} deck into discard pile", e.Player == _Player ? "" : "s") ); } else if (cardType == DominionBase.Cards.Intrigue.TypeClass.Masquerade) { String postText = String.Format(" to the left ({0})", e.AffectedPlayer); if (e.Player == _Player) glMain.Log(e.Player, "You pass ", e.Card1, postText); else glMain.Log(e.Player, e.Player, " passes a card", postText); } else if (cardType == DominionBase.Cards.Intrigue.TypeClass.WishingWell || cardType == DominionBase.Cards.DarkAges.TypeClass.Mystic || cardType == DominionBase.Cards.DarkAges.TypeClass.Rebuild) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" name{0} ", e.Player == _Player ? "" : "s"), e.Card1); } else if (cardType == DominionBase.Cards.Seaside.TypeClass.Ambassador) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" return{0} {1} to the ", e.Player == _Player ? "" : "s", StringUtility.Plural("card", e.Count)), e.Card1, " supply pile"); } else if (cardType == DominionBase.Cards.Seaside.TypeClass.Embargo) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" put{0} {1} token on ", e.Player == _Player ? "" : "s", e.SourceCard.Name), e.Card1); } else if (cardType == DominionBase.Cards.Seaside.TypeClass.Haven) { if (e.Player == _Player) glMain.Log(e.Player, "You set aside ", e.Card1); else glMain.Log(e.Player, e.Player, " sets aside a card"); } else if (cardType == DominionBase.Cards.Seaside.TypeClass.Lighthouse) { glMain.Log( e.Player, e.Player == _Player ? (Object)"Your" : (Object)e.Player, e.Player == _Player ? " " : "'s ", e.SourceCard, " provides immunity to the attack."); } else if (cardType == DominionBase.Cards.Prosperity.TypeClass.Contraband) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" name{0} ", e.Player == _Player ? "" : "s"), e.Card1); } else if (cardType == DominionBase.Cards.Hinterlands.TypeClass.Trader) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" gain{0} ", e.Player == _Player ? "" : "s"), e.Card2, " instead of ", e.Card1); } else if (cardType == DominionBase.Cards.DarkAges.TypeClass.Madman || cardType == DominionBase.Cards.DarkAges.TypeClass.Spoils) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, " return ", e.Card1, " to the ", e.Card1, " pile"); } } else { this.Dispatcher.BeginInvoke(new EventHandler(game_GameMessage), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } internal String DepthPrefix() { StringBuilder sb = new StringBuilder(); for (int c = 0; c < _CurrentPlayDepth; c++) sb.Append("... "); return sb.ToString(); } void PlayerTokenPiles_TokenCollectionsChanged(object sender, DominionBase.TokenCollectionsChangedEventArgs e) { if (this.Dispatcher.CheckAccess()) { if (e.OperationPerformed == DominionBase.TokenCollectionsChangedEventArgs.Operation.Added) { if (e.AddedTokens[0].GetType() == DominionBase.Cards.Seaside.TypeClass.PirateShipToken) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" gain{0} a Pirate Ship token", e.Player == _Player ? "" : "s") ); } } } else { this.Dispatcher.BeginInvoke(new EventHandler(PlayerTokenPiles_TokenCollectionsChanged), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void PlayerMats_DecksChanged(object sender, DominionBase.Piles.CardMatsChangedEventArgs e) { if (this.Dispatcher.CheckAccess()) { if (e.CardMat.GetType() == DominionBase.Cards.Seaside.TypeClass.IslandMat) { if (e.OperationPerformed == DominionBase.Piles.CardMatsChangedEventArgs.Operation.Added) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" set{0} aside ", e.Player == _Player ? "" : "s"), e.AddedCards, " on Island Mat"); } } else if (e.CardMat.GetType() == DominionBase.Cards.Seaside.TypeClass.NativeVillageMat) { if (e.OperationPerformed == DominionBase.Piles.CardMatsChangedEventArgs.Operation.Added) { if (e.Player == _Player) glMain.Log(e.Player, "You put ", e.AddedCards, " on Native Village Mat"); else glMain.Log( e.Player, e.Player, String.Format(" puts {0} on Native Village Mat", DominionBase.Utilities.StringUtility.Plural("card", e.AddedCards.Count) )); } else if (e.OperationPerformed == DominionBase.Piles.CardMatsChangedEventArgs.Operation.Removed && e.Player.Phase != DominionBase.Players.PhaseEnum.Endgame) { if (e.Player == _Player) glMain.Log(e.Player, "You take ", e.RemovedCards, " from Native Village Mat"); else glMain.Log( e.Player, e.Player, String.Format(" takes {0} from Native Village Mat", DominionBase.Utilities.StringUtility.Plural("card", e.RemovedCards.Count) )); } } } else { this.Dispatcher.BeginInvoke(new EventHandler(PlayerMats_DecksChanged), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardsAddedToDeck(object sender, DominionBase.Players.CardsAddedToDeckEventArgs e) { if (this.Dispatcher.CheckAccess()) { String locationMod = String.Empty; if (e.DeckPosition == DominionBase.Piles.DeckPosition.Bottom) locationMod = "the "; if (e.Cards.Count == 0) return; if (sender == _Player) glMain.Log( sender as DominionBase.Players.Player, "You put ", e.Cards, String.Format(" on {0}{1} of your deck", locationMod, e.DeckPosition.ToString().ToLower()) ); else glMain.Log( sender as DominionBase.Players.Player, sender, String.Format(" puts {0} on {2}{1} of their deck", StringUtility.Plural("card", e.Cards.Count), e.DeckPosition.ToString().ToLower(), locationMod )); } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardsAddedToDeck), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardsAddedToHand(object sender, DominionBase.Players.CardsAddedToHandEventArgs e) { if (this.Dispatcher.CheckAccess()) { if (e.Cards.Count == 0) return; if (sender == _Player) glMain.Log( sender as DominionBase.Players.Player, "You put ", e.Cards, " into your hand"); else glMain.Log(sender as DominionBase.Players.Player, sender, String.Format(" puts {0} into their hand", StringUtility.Plural("card", e.Cards.Count))); } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardsAddedToHand), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardsDiscarded(object sender, DominionBase.Players.CardsDiscardEventArgs e) { if (this.Dispatcher.CheckAccess()) { if (e.Cards.Count == 0 || e.HandledBy.Contains(this)) return; e.HandledBy.Add(this); String location = String.Empty; switch (e.FromLocation) { case DominionBase.Players.DeckLocation.Tableau: case DominionBase.Players.DeckLocation.PreviousTableau: return; case DominionBase.Players.DeckLocation.Hand: case DominionBase.Players.DeckLocation.Deck: location = String.Format(" from {0} {1}", sender == _Player ? "your" : "their", e.FromLocation.ToString().ToLower()); break; } Object name = (sender == _Player ? (Object)"You" : (Object)sender); String verb = String.Format(" discard{0} ", sender == _Player ? "" : "s"); if (e.Cards.Count == 1) glMain.Log(sender as DominionBase.Players.Player, name, verb, e.Cards, location); else glMain.Log(sender as DominionBase.Players.Player, name, verb, String.Format("{0}{1}", StringUtility.Plural("card", e.Cards.Count), location)); } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardsDiscarded), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_Shuffle(object sender, DominionBase.Players.ShuffleEventArgs e) { if (this.Dispatcher.CheckAccess()) { glMain.Log( e.Player, "(", e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" shuffle{0}...)", e.Player == _Player ? "" : "s") ); } else { this.Dispatcher.BeginInvoke(new EventHandler(player_Shuffle), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_BenefitReceiving(object sender, DominionBase.Players.BenefitReceivingEventArgs e) { if (this.Dispatcher.CheckAccess()) { StringBuilder sb = new StringBuilder(); sb.AppendFormat(" get{0}", e.Player == _Player ? "" : "s"); if (e.Benefit.Cards > 0) sb.AppendFormat(" +{0} card{1}", e.Benefit.Cards, e.Benefit.Cards == 1 ? "" : "s"); if (e.Benefit.Actions > 0) sb.AppendFormat(" +{0} action{1}", e.Benefit.Actions, e.Benefit.Actions == 1 ? "" : "s"); if (e.Benefit.Buys > 0) sb.AppendFormat(" +{0} buy{1}", e.Benefit.Buys, e.Benefit.Buys == 1 ? "" : "s"); if (e.Benefit.Currency > new DominionBase.Currency()) sb.AppendFormat(" +{0}", Utilities.RenderText(e.Benefit.Currency.ToString())); else if (e.Benefit.Currency < new DominionBase.Currency()) sb.AppendFormat(" {0}", Utilities.RenderText(e.Benefit.Currency.ToString())); if (e.Benefit.VictoryPoints > 0) sb.Append(Utilities.RenderText(String.Format(" +{0}", e.Benefit.VictoryPoints))); sb.Append(e.Benefit.FlavorText); if (e.Phase == DominionBase.Players.PhaseEnum.Starting) { sb.Append(" from "); glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, sb.ToString(), sender); } else glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, sb.ToString()); } else { this.Dispatcher.BeginInvoke(new EventHandler(player_BenefitReceiving), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_TurnStarting(object sender, DominionBase.Players.TurnStartingEventArgs e) { if (this.Dispatcher.CheckAccess()) { if (e.Player == _Player) dpStuff.Visibility = System.Windows.Visibility.Visible; else dpStuff.Visibility = System.Windows.Visibility.Collapsed; // Just in case _CurrentPlayDepth = 0; if (game.Players[0] == e.Player && e.GrantedBy == null) glMain.NewTurn(game.TurnsTaken.TurnNumber(e.Player)); glMain.NewTurn(e.Player, e.GrantedBy); } else { this.Dispatcher.BeginInvoke(new EventHandler(player_TurnStarting), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardsDrawn(object sender, DominionBase.Players.CardsDrawnEventArgs e) { if (this.Dispatcher.CheckAccess()) { if (e.Cards.Count > 0) { String from = String.Empty; if (e.FromDeckPosition == DominionBase.Piles.DeckPosition.Bottom) from = String.Format(" from the bottom of {0} deck", sender == _Player ? "your" : "their"); if (sender == _Player) glMain.Log( sender as DominionBase.Players.Player, "You draw ", e.Cards, from); else glMain.Log( sender as DominionBase.Players.Player, sender, String.Format(" draws {0}{1}", StringUtility.Plural("card", e.Cards.Count), from)); } } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardsDrawn), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void game_GameEndedEvent(object sender, DominionBase.GameEndedEventArgs e) { if (this.Dispatcher.CheckAccess()) { //_Statistics.Add(game, _Player); //_Statistics.Save(); miNewGame.IsEnabled = true; miEndGame.IsEnabled = false; miReplay.IsEnabled = true; //svGame.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled; if (_StartingNewGame) { glMain.TearDown(); glMain.Clear(); } glMain.NewSection("Game ended"); foreach (DominionBase.Players.Player player in game.Players) glMain.Log(String.Empty, player, String.Format(": {0} point{1} in {2} turns", player.VictoryPoints, player.VictoryPoints == 1 ? "" : "s", game.TurnsTaken.Count(t => t.Player == player && !t.ModifiedTurn))); if (game.Winners.Count > 0) glMain.Log(String.Format("Winner{0}: {1} with {2} point{3}", game.Winners.Count == 1 ? "" : "s", game.Winners, game.Winners[0].VictoryPoints, game.Winners[0].VictoryPoints == 1 ? "" : "s")); UpdateDisplay(); ReleaseEvents(); if (_StartingNewGame) Game_NewGame_Click(null, null); } else { this.Dispatcher.BeginInvoke(new EventHandler(game_GameEndedEvent), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_BenefitsChanged(object sender, DominionBase.Players.BenefitsChangedEventArgs e) { if (this.Dispatcher.CheckAccess()) { if (e.Player == game.ActivePlayer) { tbActions.Inlines.Clear(); tbActions.Inlines.Add(((TextBlock)Utilities.RenderText(String.Format("{1}{0}{2}", e.Actions, e.Actions > 0 ? "" : "", e.Actions > 0 ? "" : ""), NET_WPF.RenderSize.Tiny, true)[0]).Inlines.ElementAt(0)); tbBuys.Inlines.Clear(); tbBuys.Inlines.Add(((TextBlock)Utilities.RenderText(String.Format("{1}{0}{2}", e.Buys, e.Buys > 0 ? "" : "", e.Buys > 0 ? "" : ""), NET_WPF.RenderSize.Tiny, true)[0]).Inlines.ElementAt(0)); tbCurrency.Inlines.Clear(); TextBlock tbTemp = (TextBlock)Utilities.RenderText(e.Player.Currency.ToString(), NET_WPF.RenderSize.Tiny, false)[0]; while (tbTemp.Inlines.Count > 0) tbCurrency.Inlines.Add(tbTemp.Inlines.ElementAt(0)); } } else { this.Dispatcher.BeginInvoke(new EventHandler(player_BenefitsChanged), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_PhaseChangedEvent(object sender, DominionBase.Players.PhaseChangedEventArgs e) { if (this.Dispatcher.CheckAccess()) { if (e.CurrentPlayer == game.ActivePlayer) { //System.Diagnostics.Trace.WriteLine(String.Format("{2} Phase changed: {0} to {1}", e.OldPhase, e.NewPhase, DateTime.Now.ToString("o"))); if (e.NewPhase == DominionBase.Players.PhaseEnum.Starting || e.NewPhase == DominionBase.Players.PhaseEnum.Buy || e.NewPhase == DominionBase.Players.PhaseEnum.Waiting) CheckBuyable(e.CurrentPlayer); else ClearBuyable(); } if (e.CurrentPlayer != _Player) return; if (e.NewPhase == DominionBase.Players.PhaseEnum.Starting || e.NewPhase == DominionBase.Players.PhaseEnum.Endgame) miSettings.IsEnabled = true; else if (e.NewPhase == DominionBase.Players.PhaseEnum.Waiting) miSettings.IsEnabled = false; UpdateDisplay(); if (_Settings.AutoPlayTreasures && e.NewPhase == DominionBase.Players.PhaseEnum.Treasure) { // Ugly hack, but it mostly works -- just a slight delay between the end of the PhaseChangedEvent and the AutoPlay BackgroundWorker autoplayInvoker = new BackgroundWorker(); autoplayInvoker.DoWork += delegate { Thread.Sleep(TimeSpan.FromMilliseconds(50)); AutoPlayTreasures(); }; autoplayInvoker.RunWorkerAsync(); } } else { this.Dispatcher.BeginInvoke(new EventHandler(player_PhaseChangedEvent), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } private void AutoPlayTreasures() { WaitCallback wcb = new WaitCallback(UpdateDisplayTarget); DominionBase.GamePlayMessage gpm = null; // Always play Contraband first DominionBase.Cards.CardCollection contrabandTreasures = _Player.Hand[DominionBase.Cards.Prosperity.TypeClass.Contraband]; foreach (DominionBase.Cards.Card card in contrabandTreasures) { if (_Player.Phase != DominionBase.Players.PhaseEnum.Treasure) break; while (game.MessageResponseQueue.Count > 0) game.MessageResponseQueue.Dequeue(); gpm = new DominionBase.GamePlayMessage(wcb, _Player, card); gpm.Message = String.Format("{0} playing {1}", _Player, card); EnqueueGameMessageAndWait(gpm); } // Play "normal" Treasure cards next DominionBase.Cards.CardCollection tNormal = _Player.Hand[c => (c.Category & DominionBase.Cards.Category.Treasure) == DominionBase.Cards.Category.Treasure && c.CardType != DominionBase.Cards.Prosperity.TypeClass.Bank && c.CardType != DominionBase.Cards.Prosperity.TypeClass.Contraband && c.CardType != DominionBase.Cards.Prosperity.TypeClass.Loan && c.CardType != DominionBase.Cards.Prosperity.TypeClass.Venture && c.CardType != DominionBase.Cards.Cornucopia.TypeClass.HornOfPlenty]; if (tNormal.Count > 0) _Player.PlayCards(tNormal); // Only play Loan & Venture after cards like Philosopher's Stone that work better with more cards // There are some very specific situations where playing Horn Of Plenty before Philospher's Stone // or Venture is the right way to play things, but that's so incredibly rare. DominionBase.Cards.CardCollection tLoanVenture = _Player.Hand[DominionBase.Cards.Prosperity.TypeClass.Venture]; if (_Settings.AutoPlayTreasures_IncludingLoan) { if (_Settings.AutoPlayTreasures_LoanFirst) tLoanVenture.InsertRange(0, _Player.Hand[DominionBase.Cards.Prosperity.TypeClass.Loan]); else tLoanVenture.AddRange(_Player.Hand[DominionBase.Cards.Prosperity.TypeClass.Loan]); } foreach (DominionBase.Cards.Card card in tLoanVenture) { if (_Player.Phase != DominionBase.Players.PhaseEnum.Treasure) break; gpm = new DominionBase.GamePlayMessage(wcb, _Player, card); gpm.Message = String.Format("{0} playing {1}", _Player, card); EnqueueGameMessageAndWait(gpm); return; } // Always play Bank & Horn of Plenty last DominionBase.Cards.CardCollection tBankHornofPlenty = _Player.Hand[DominionBase.Cards.Prosperity.TypeClass.Bank]; if (_Settings.AutoPlayTreasures_IncludingHornOfPlenty) { // If Horn Of Plenty is to be played first, play ALL Horn Of Plenty cards first if (_Settings.AutoPlayTreasures_HornOfPlentyFirst) tBankHornofPlenty.InsertRange(0, _Player.Hand[DominionBase.Cards.Cornucopia.TypeClass.HornOfPlenty]); // Otherwise, play a SINGLE Bank card, then ALL Horn of Plenty cards, then all remaining Bank cards else tBankHornofPlenty.InsertRange(tBankHornofPlenty.Count == 0 ? 0 : 1, _Player.Hand[DominionBase.Cards.Cornucopia.TypeClass.HornOfPlenty]); } foreach (DominionBase.Cards.Card card in tBankHornofPlenty) { if (_Player.Phase != DominionBase.Players.PhaseEnum.Treasure) break; gpm = new DominionBase.GamePlayMessage(wcb, _Player, card); gpm.Message = String.Format("{0} playing {1}", _Player, card); EnqueueGameMessageAndWait(gpm); } } private void ClearBuyable() { foreach (StackPanel sp in stackPanelSupplyPiles.Children.OfType()) { foreach (SupplyControl sc in sp.Children.OfType()) { sc.SupplyClick -= SupplyControl_SupplyClick; sc.Clickability = sc.Clickability; } } } private void CheckBuyable(DominionBase.Players.Player player) { Boolean buyablePhase = player != null && (player.Phase == DominionBase.Players.PhaseEnum.Action || player.Phase == DominionBase.Players.PhaseEnum.Treasure || player.Phase == DominionBase.Players.PhaseEnum.Buy); foreach (StackPanel sp in stackPanelSupplyPiles.Children.OfType()) { foreach (SupplyControl sc in sp.Children.OfType()) { sc.SupplyClick -= SupplyControl_SupplyClick; if (_Player != player) sc.Clickability = SupplyVisibility.Plain; else if (buyablePhase && _Player == player && sc.Supply.CanBuy(player)) { sc.Clickability = SupplyVisibility.Gainable; sc.SupplyClick += SupplyControl_SupplyClick; } else sc.Clickability = SupplyVisibility.NotClickable; } } } void player_Trashing(object sender, DominionBase.Players.TrashEventArgs e) { if (this.Dispatcher.CheckAccess()) { e.TrashedCards.Sort(); glMain.Log( sender as DominionBase.Players.Player, sender == _Player ? (Object)"You" : (Object)sender, String.Format(" trash{0} ", sender == _Player ? "" : "es"), e.TrashedCards); glMain.Push(); _CurrentPlayDepth++; } else { this.Dispatcher.BeginInvoke(new EventHandler(player_Trashing), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_Trashed(object sender, DominionBase.Players.TrashEventArgs e) { if (this.Dispatcher.CheckAccess()) { glMain.Pop(); _CurrentPlayDepth--; } else { this.Dispatcher.BeginInvoke(new EventHandler(player_Trashed), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardReceived(object sender, DominionBase.Players.CardReceivedEventArgs e) { if (this.Dispatcher.CheckAccess()) { DominionBase.Players.Player player = sender as DominionBase.Players.Player; StringBuilder extra = new StringBuilder(); switch (e.Location) { case DominionBase.Players.DeckLocation.Deck: String locationMod = String.Empty; DominionBase.Piles.DeckPosition dp = player.ResolveDeckPosition(e.Location, e.Position); if (dp == DominionBase.Piles.DeckPosition.Bottom) locationMod = "the "; extra.AppendFormat(", putting it on {1}{0} of your {2}", dp.ToString().ToLower(), locationMod, e.Location.ToString().ToLower()); break; case DominionBase.Players.DeckLocation.Hand: case DominionBase.Players.DeckLocation.Tableau: case DominionBase.Players.DeckLocation.PreviousTableau: extra.AppendFormat(", putting it into your {0}", e.Location.ToString().ToLower()); break; } glMain.Log( player, player == _Player ? (Object)"You" : (Object)player, String.Format(" receive{0} ", player == _Player ? "" : "s"), e.Card, " from ", e.FromPlayer, extra); UpdateDisplay(); } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardReceived), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardGaining(object sender, DominionBase.Players.CardGainEventArgs e) { if (this.Dispatcher.CheckAccess()) { if (!e.Bought) { glMain.Log( sender as DominionBase.Players.Player, sender == _Player ? (Object)"You" : (Object)sender, String.Format(" gain{0} ", sender == _Player ? "" : "s"), e.Card); glMain.Push(); _CurrentPlayDepth++; } } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardGaining), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardGainedInto(object sender, DominionBase.Players.CardGainEventArgs e) { if (this.Dispatcher.CheckAccess()) { // the CardBought event will have already handled this, so we can just skip printing any message if (e.Location == DominionBase.Players.DeckLocation.Discard) return; StringBuilder extra = new StringBuilder(); String pronoun = "their"; if (sender as DominionBase.Players.Player == _Player) pronoun = "your"; switch (e.Location) { case DominionBase.Players.DeckLocation.Deck: String locationMod = String.Empty; if ((sender as DominionBase.Players.Player).ResolveDeckPosition(e.Location, e.Position) == DominionBase.Piles.DeckPosition.Bottom) locationMod = "the bottom of "; extra.AppendFormat("on {0}{2} {1}", locationMod, e.Location.ToString().ToLower(), pronoun); break; case DominionBase.Players.DeckLocation.Hand: case DominionBase.Players.DeckLocation.Tableau: case DominionBase.Players.DeckLocation.PreviousTableau: extra.AppendFormat("into {1} {0}", e.Location.ToString().ToLower(), pronoun); break; } glMain.Log( sender as DominionBase.Players.Player, sender == _Player ? (Object)"You" : (Object)sender, String.Format(" put{0} ", sender == _Player ? "" : "s"), e.Card, extra.ToString()); UpdateDisplay(); } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardGainedInto), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardGainFinished(object sender, DominionBase.Players.CardGainEventArgs e) { if (this.Dispatcher.CheckAccess()) { glMain.Pop(); _CurrentPlayDepth--; } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardGainFinished), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardBuying(object sender, DominionBase.Players.CardBuyEventArgs e) { if (this.Dispatcher.CheckAccess()) { glMain.Log( sender as DominionBase.Players.Player, sender == _Player ? (Object)"You" : (Object)sender, String.Format(" buy{0} ", sender == _Player ? "" : "s"), e.Card); glMain.Push(); _CurrentPlayDepth++; } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardBuying), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardBought(object sender, DominionBase.Players.CardBuyEventArgs e) { if (this.Dispatcher.CheckAccess()) { } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardBought), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardBuyFinished(object sender, DominionBase.Players.CardBuyEventArgs e) { if (this.Dispatcher.CheckAccess()) { glMain.Pop(); _CurrentPlayDepth--; if (sender == _Player) CheckBuyable((DominionBase.Players.Player)sender); } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardBuyFinished), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardPlaying(object sender, DominionBase.Players.CardPlayingEventArgs e) { if (this.Dispatcher.CheckAccess()) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" play{0} ", e.Player == _Player ? "" : "s"), e.Cards == null ? (Object)"nothing" : (Object)e.Cards, String.Format(" {0}", e.Modifier)); glMain.Push(); _CurrentPlayDepth++; } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardPlaying), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void player_CardPlayed(object sender, DominionBase.Players.CardPlayedEventArgs e) { if (this.Dispatcher.CheckAccess()) { glMain.Pop(); _CurrentPlayDepth--; } else { this.Dispatcher.BeginInvoke(new EventHandler(player_CardPlayed), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void Revealed_PileChanged(object sender, DominionBase.Piles.PileChangedEventArgs e) { if (e.OperationPerformed == DominionBase.Piles.PileChangedEventArgs.Operation.Added) { if (this.Dispatcher.CheckAccess()) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" reveal{0}: ", e.Player == _Player ? "" : "s"), //String.Format("{0} reveal{1}: ", e.Player == _Player ? "You" : e.Player.ToString(), e.Player == _Player ? "" : "s"), e.AddedCards); } else { this.Dispatcher.BeginInvoke(new EventHandler(Revealed_PileChanged), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } } void DiscardPile_PileChanged(object sender, DominionBase.Piles.PileChangedEventArgs e) { if (e.OperationPerformed == DominionBase.Piles.PileChangedEventArgs.Operation.Added) { if (this.Dispatcher.CheckAccess()) { glMain.Log( e.Player, e.Player == _Player ? (Object)"You" : (Object)e.Player, String.Format(" discard{0}: {1}", e.Player == _Player ? "" : "s", StringUtility.Plural("card", e.AddedCards.Count)) ); } else { this.Dispatcher.BeginInvoke(new EventHandler(DiscardPile_PileChanged), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } } void Trash_PileChanged(object sender, DominionBase.Piles.PileChangedEventArgs e) { if (cardTrash.Dispatcher.CheckAccess()) { cardTrash.ExactCount = true; cardTrash.IsCardsVisible = true; cardTrash.Phase = DominionBase.Players.PhaseEnum.Waiting; cardTrash.CardSize = CardSize.Text; cardTrash.Pile = game.Table.Trash; } else { cardTrash.Dispatcher.BeginInvoke(new EventHandler(Trash_PileChanged), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } void TokenPiles_TokenCollectionsChanged(object sender, DominionBase.TokenCollectionsChangedEventArgs e) { if (_TradeRouteLabel == null) return; if (_TradeRouteLabel.Dispatcher.CheckAccess()) { _TradeRouteLabel.Content = e.Count.ToString(); } else { _TradeRouteLabel.Dispatcher.BeginInvoke(new EventHandler(TokenPiles_TokenCollectionsChanged), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } private void player_Choose(DominionBase.Players.Player player, DominionBase.Choice choice) { if (this.Dispatcher.CheckAccess()) { UpdateDisplay(); uccChooser.Player = player; uccChooser.Choice = choice; uccChooser.Visibility = System.Windows.Visibility.Visible; List supplyControls = new List(); foreach (StackPanel sp in stackPanelSupplyPiles.Children.OfType()) supplyControls.AddRange(sp.Children.OfType()); uccChooser.SupplyControls = supplyControls; uccChooser.IsReady = true; } else { this.Dispatcher.BeginInvoke(new player_ChooseDelegate(player_Choose), System.Windows.Threading.DispatcherPriority.Normal, player, choice); } } private void uccChooser_ChooserOKClick(object sender, RoutedEventArgs e) { uccChooser.Visibility = System.Windows.Visibility.Collapsed; Controls.ucChooser chooser = sender as Controls.ucChooser; DominionBase.Players.PlayerChoiceMessage pcm = new DominionBase.Players.PlayerChoiceMessage(WaitEvent, chooser.Player, chooser.ChoiceResult); pcm.Message = String.Format("{0} chooses", chooser.Player); lock (chooser.Player.MessageRequestQueue) chooser.Player.MessageRequestQueue.Enqueue(pcm); chooser.Player.WaitEvent.Set(); while (WaitEvent.WaitOne(250)) ; lock (chooser.Player.MessageResponseQueue) if (chooser.Player.MessageResponseQueue.Count > 0) chooser.Player.MessageResponseQueue.Dequeue(); UpdateDisplay(); CheckBuyable(chooser.Player); } private void UpdateDisplayTarget(object target) { if (this.Dispatcher.CheckAccess()) { UpdateDisplay(); } else { WaitCallback wcb = new WaitCallback(UpdateDisplayTarget); this.Dispatcher.BeginInvoke(wcb, System.Windows.Threading.DispatcherPriority.Normal, target); } } private void UpdateDisplay() { miReplay.IsEnabled = (game.State == DominionBase.GameState.Ended || game.State == DominionBase.GameState.Aborted); UpdateDisplayPlayer(game.ActivePlayer); } private void UpdateDisplayPlayer(DominionBase.Players.Player player) { bPlayTreasures.IsEnabled = false; bBuyPhase.IsEnabled = false; bTurnDone.IsEnabled = false; if (player == null) { return; } if (player == _Player) { dpButtons.Visibility = System.Windows.Visibility.Visible; switch (player.Phase) { case DominionBase.Players.PhaseEnum.Action: bPlayTreasures.IsEnabled = player.Hand[DominionBase.Cards.Category.Treasure].Count > 0; bBuyPhase.IsEnabled = true; bTurnDone.IsEnabled = true; break; case DominionBase.Players.PhaseEnum.Treasure: bPlayTreasures.IsEnabled = player.Hand[DominionBase.Cards.Category.Treasure].Count > 0; bBuyPhase.IsEnabled = true; bTurnDone.IsEnabled = true; break; case DominionBase.Players.PhaseEnum.Buy: bTurnDone.IsEnabled = true; break; case DominionBase.Players.PhaseEnum.Cleanup: case DominionBase.Players.PhaseEnum.Playing: case DominionBase.Players.PhaseEnum.Choosing: case DominionBase.Players.PhaseEnum.Waiting: case DominionBase.Players.PhaseEnum.Endgame: break; } } else { dpButtons.Visibility = System.Windows.Visibility.Hidden; } } private void bPlayTreasures_Click(object sender, RoutedEventArgs e) { if (_Settings.PromptUnplayedActions && game.ActivePlayer.Phase == DominionBase.Players.PhaseEnum.Action && game.ActivePlayer.Actions > 0) { if (MessageBox.Show("You have unplayed actions left. Are you sure you want to do this?", "Please confirm", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel) return; } (sender as Button).IsEnabled = false; WaitCallback wcb = new WaitCallback(UpdateDisplayTarget); DominionBase.GamePlayTreasuresMessage gptm = new DominionBase.GamePlayTreasuresMessage(wcb, game.ActivePlayer); gptm.Message = String.Format("{0} playing treasures", game.ActivePlayer); EnqueueGameMessageAndWait(gptm); } private void SupplyControl_SupplyClick(object sender, RoutedEventArgs e) { DominionBase.Piles.Supply supply = (e.Source as SupplyControl).Supply; WaitCallback wcb = new WaitCallback(Bought); DominionBase.GameBuyMessage gbm = new DominionBase.GameBuyMessage(wcb, game.ActivePlayer, supply); gbm.Message = String.Format("{0} buying {1}", game.ActivePlayer, supply); EnqueueGameMessageAndWait(gbm); } private void Bought(object target) { if (this.Dispatcher.CheckAccess()) { if (game.ActivePlayer == null) return; if (game.ActivePlayer.Buys == 0) bTurnDone_Click(bTurnDone, null); // If the only cards we can buy are Copper & Curse and there are no Goons in play // and the proper setting is enabled, it will automatically skip the remaining buys else if (_Settings.NeverBuyCopperOrCurseExceptWhenGoonsIsInPlay && game.ActivePlayer.Tableau[DominionBase.Cards.Prosperity.TypeClass.Goons].Count == 0 && game.Table.Supplies.Values.Count(supply => supply.SupplyCardType != DominionBase.Cards.Universal.TypeClass.Copper && supply.SupplyCardType != DominionBase.Cards.Universal.TypeClass.Curse && supply.CanBuy(game.ActivePlayer)) == 0) { bTurnDone_Click(bTurnDone, null); } UpdateDisplay(); } else { WaitCallback wcb = new WaitCallback(Bought); this.Dispatcher.BeginInvoke(wcb, System.Windows.Threading.DispatcherPriority.Normal, target); } } private void CardCollectionControl_CardCollectionControlClick(object sender, RoutedEventArgs e) { Controls.CardStackControl csc = e.OriginalSource as Controls.CardStackControl; if (game == null || game.ActivePlayer == null || csc == null) return; if ((game.ActivePlayer.Phase == DominionBase.Players.PhaseEnum.Action && ((csc.ClickedCard.Category & DominionBase.Cards.Category.Action) == DominionBase.Cards.Category.Action || (csc.ClickedCard.Category & DominionBase.Cards.Category.Treasure) == DominionBase.Cards.Category.Treasure)) || (game.ActivePlayer.Phase == DominionBase.Players.PhaseEnum.Treasure && (csc.ClickedCard.Category & DominionBase.Cards.Category.Treasure) == DominionBase.Cards.Category.Treasure)) { if (_Settings.PromptUnplayedActions && game.ActivePlayer.Phase == DominionBase.Players.PhaseEnum.Action && game.ActivePlayer.Actions > 0 && ((csc.ClickedCard.Category & DominionBase.Cards.Category.Action) != DominionBase.Cards.Category.Action)) { if (MessageBox.Show("You have unplayed actions left. Are you sure you want to do this?", "Please confirm", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel) return; } WaitCallback wcb = new WaitCallback(UpdateDisplayTarget); DominionBase.GamePlayMessage gpm = new DominionBase.GamePlayMessage(wcb, game.ActivePlayer, csc.ClickedCard); gpm.Message = String.Format("{0} playing {1}", game.ActivePlayer, csc.ClickedCard); EnqueueGameMessageAndWait(gpm); } } private void bTurnDone_Click(object sender, RoutedEventArgs e) { (sender as Button).IsEnabled = false; if (_Settings.PromptUnspentBuysTreasure && game.ActivePlayer.Buys > 0 && game.ActivePlayer.Currency > new DominionBase.Currency()) { if (MessageBox.Show("You have unused coins and buys left. Are you sure you want to do this?", "Please confirm", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel) { (sender as Button).IsEnabled = true; return; } } WaitCallback wcb = new WaitCallback(UpdateDisplayTarget); DominionBase.GameEndTurnMessage getm = new DominionBase.GameEndTurnMessage(wcb, game.ActivePlayer); getm.Message = String.Format("{0} ending turn", game.ActivePlayer); EnqueueGameMessageAndWait(getm); } private void Game_Exit_Click(object sender, RoutedEventArgs e) { this.Close(); } private void Game_Settings_Click(object sender, RoutedEventArgs e) { wSettings settingsDialogBox = new wSettings(ref _Settings); settingsDialogBox.Owner = this; if (settingsDialogBox.ShowDialog() == true) { _Settings.Save(); LayoutSupplyPiles(); } } private void Game_NewGame_Click(object sender, RoutedEventArgs e) { if (game != null && game.State == DominionBase.GameState.Running) { _StartingNewGame = true; if (!IsEndGameOK()) return; } else { DominionBase.GameSettings settings = new DominionBase.GameSettings(); settings.IdenticalStartingHands = _Settings.IdenticalStartingHands; settings.Constraints.AddRange(_Settings.Constraints); if (_Settings.UsePreset) { settings.Constraints.Clear(); try { settings.Preset = _Settings.Presets.SingleOrDefault(p => p.Name == _Settings.PresetName); } catch { } if (settings.Preset == null) { MessageBox.Show(String.Format("Cannot find preset named \"{0}\"!{1}Please check your presets.txt file.", _Settings.PresetName, System.Environment.NewLine), "Cannot find preset", MessageBoxButton.OK, MessageBoxImage.Exclamation); return; } } settings.CardSettings.AddRange(_Settings.CardSettings); StartGame(settings); } } void GamePile_PileChanged(object sender, DominionBase.Piles.PileChangedEventArgs e) { if (this.Dispatcher.CheckAccess()) { DominionBase.Piles.Supply supply = sender as DominionBase.Piles.Supply; String wpName = String.Format("wp{0}", supply.SupplyCardType.Name); String cccName = String.Format("card{0}", supply.SupplyCardType.Name); String cccPileName = supply.SupplyCardType.Name; if (supply.SupplyCardType == DominionBase.Cards.Promotional.TypeClass.BlackMarketSupply) { cccPileName = "Black Market cards"; } else if (supply.SupplyCardType == DominionBase.Cards.Cornucopia.TypeClass.PrizeSupply) { cccPileName = "Prizes"; } WrapPanel wpSpecialPile = dpMatsandPiles.Children.OfType().SingleOrDefault(wp => wp.Name == wpName); CardCollectionControl cccSpecialPile = null; if (wpSpecialPile == null) { if (dpMatsandPiles.Children.Count > 0) { Border bDiv = new Border(); bDiv.BorderThickness = new Thickness(2); bDiv.BorderBrush = Brushes.Black; DockPanel.SetDock(bDiv, Dock.Top); dpMatsandPiles.Children.Add(bDiv); } wpSpecialPile = new WrapPanel(); wpSpecialPile.Name = wpName; wpSpecialPile.Orientation = Orientation.Horizontal; DockPanel.SetDock(wpSpecialPile, Dock.Top); cccSpecialPile = new CardCollectionControl(); cccSpecialPile.Name = cccName; cccSpecialPile.Padding = new Thickness(0); cccSpecialPile.PileName = cccPileName; cccSpecialPile.CardSize = CardSize.Text; cccSpecialPile.ExactCount = true; cccSpecialPile.IsCardsVisible = true; cccSpecialPile.IsDisplaySorted = true; cccSpecialPile.Phase = DominionBase.Players.PhaseEnum.Waiting; wpSpecialPile.Children.Add(cccSpecialPile); dpMatsandPiles.Children.Add(wpSpecialPile); } else cccSpecialPile = wpSpecialPile.Children.OfType().FirstOrDefault(); cccSpecialPile.Pile = supply; } else { this.Dispatcher.BeginInvoke(new EventHandler(GamePile_PileChanged), System.Windows.Threading.DispatcherPriority.Normal, sender, e); } } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if (game != null) { if (!IsEndGameOK()) { e.Cancel = true; return; } if (uccChooser.Visibility == System.Windows.Visibility.Visible) uccChooser.Player.WaitEvent.Set(); } if (gameThread != null) gameThread.Join(); _Settings.WindowSize = new Size(this.Width, this.Height); _Settings.WindowState = this.WindowState; _Settings.Save(); } private void bBuyPhase_Click(object sender, RoutedEventArgs e) { if (_Settings.PromptUnplayedActions && game.ActivePlayer.Phase == DominionBase.Players.PhaseEnum.Action && game.ActivePlayer.Actions > 0) { if (MessageBox.Show("You have unplayed actions left. Are you sure you want to do this?", "Please confirm", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel) return; } (sender as Button).IsEnabled = false; WaitCallback wcb = new WaitCallback(UpdateDisplayTarget); DominionBase.GameGoToBuyPhaseMessage ggtbpm = new DominionBase.GameGoToBuyPhaseMessage(wcb, game.ActivePlayer); ggtbpm.Message = String.Format("{0} going to Buy phase", game.ActivePlayer); EnqueueGameMessageAndWait(ggtbpm); } private void tcAreas_SelectionChanged(object sender, SelectionChangedEventArgs e) { foreach (TabItem removedTab in e.RemovedItems.OfType()) { if ((removedTab.Content as Controls.ucPlayerDisplay) == null) continue; (removedTab.Content as Controls.ucPlayerDisplay).IsActive = false; } foreach (TabItem addedTab in e.AddedItems.OfType()) { if ((addedTab.Content as Controls.ucPlayerDisplay) == null) continue; (addedTab.Content as Controls.ucPlayerDisplay).IsActive = true; addedTab.InvalidateVisual(); } } private void OpenUrl(String target) { try { System.Diagnostics.Process.Start(target); } catch (System.ComponentModel.Win32Exception noBrowser) { if (noBrowser.ErrorCode == -2147467259) MessageBox.Show(noBrowser.Message); } catch (System.Exception other) { MessageBox.Show(other.Message); } } private void Help_OfficialSite_Click(object sender, RoutedEventArgs e) { OpenUrl("http://www.riograndegames.com/games.html?id=278"); } private void Help_DeveloperSite_Click(object sender, RoutedEventArgs e) { OpenUrl("http://dominion.technowall.net/"); } private void Help_CheckForUpdates_Click(object sender, RoutedEventArgs e) { try { CheckForUpdates(true); } catch { } } private void Help_CardViewer_Click(object sender, RoutedEventArgs e) { wCardViewer wcv = new wCardViewer(); wcv.Show(); } private void svGame_ScrollChanged(object sender, ScrollChangedEventArgs e) { ScrollViewer sv = sender as ScrollViewer; if (sv.ExtentHeight == 0 || sv.ExtentWidth == 0) return; bGameHorizontal.Width = sv.ViewportWidth * sv.ViewportWidth / sv.ExtentWidth; bGameVertical.Height = sv.ViewportHeight * sv.ViewportHeight / sv.ExtentHeight; bGameHorizontal.Margin = new Thickness(sv.ViewportWidth * sv.HorizontalOffset / sv.ExtentWidth, 0, 0, 0); bGameVertical.Margin = new Thickness(0, sv.ViewportHeight * sv.VerticalOffset / sv.ExtentHeight, 0, 0); } private void CheckForUpdates(Boolean forceCheck) { Assembly a = Assembly.GetExecutingAssembly(); // If this isn't null, we're trying to update to a version if (!forceCheck && Application.Current.Properties["Update"] != null) { System.Net.WebClient wClient = new System.Net.WebClient(); cpStatus.Content = String.Format("Downloading {0}...", Application.Current.Properties["Update"]); wClient.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(wClient_DownloadFileCompleted); wClient.DownloadProgressChanged += new System.Net.DownloadProgressChangedEventHandler(wClient_DownloadProgressChanged); wClient.DownloadFileAsync(new Uri(Application.Current.Properties["Update"].ToString()), System.IO.Path.Combine(System.IO.Path.GetDirectoryName(a.Location), "update.zip")); } else { if (Application.Current.Properties["Updated"] != null && (Boolean)Application.Current.Properties["Updated"]) { MessageBox.Show(String.Format("Successfully updated to latest version {0}!", a.GetName().Version), "Update complete!", MessageBoxButton.OK, MessageBoxImage.Information); _Settings.UpdateAvailable = false; _Settings.Save(); } String tempPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(a.Location), "update"); // Blow away any existing files if (System.IO.Directory.Exists(tempPath)) System.IO.Directory.Delete(tempPath, true); iUpdate.Visibility = miDownload.Visibility = System.Windows.Visibility.Collapsed; // Only check for an update if we haven't checked in the last 24 hours // Or if we're forcing a check if (forceCheck || DateTime.Now - TimeSpan.FromHours(24) > _Settings.LastUpdateCheck) { this.latestVersionInfo = VersionChecker.GetLatestVersion(); _Settings.LastUpdateCheck = DateTime.Now; Version currentVersion = a.GetName().Version; if (latestVersionInfo.IsVersionValid && latestVersionInfo.IsNewerThan(currentVersion)) _Settings.UpdateAvailable = true; if (forceCheck) MessageBox.Show(String.Format("Your version: {0}{2}Latest version: {1}", currentVersion, latestVersionInfo.Version, System.Environment.NewLine), "Version info", MessageBoxButton.OK, MessageBoxImage.Information); _Settings.Save(); } if (_Settings.UpdateAvailable) { iUpdate.Visibility = miDownload.Visibility = System.Windows.Visibility.Visible; iUpdate.ToolTip = miDownload.ToolTip = "Update available"; } } } void wClient_DownloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e) { pbStatus.Visibility = System.Windows.Visibility.Visible; pbStatus.Minimum = 0; pbStatus.Value = 0; pbStatus.Maximum = e.TotalBytesToReceive; pbStatus.Value = e.BytesReceived; pbStatus.ToolTip = String.Format("{0:0.00}KB / {1:0.00}KB ({2}%)", e.BytesReceived / 1024.0, e.TotalBytesToReceive / 1024.0, e.ProgressPercentage); } void wClient_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { cpStatus.Content = String.Empty; // "Hi!"; pbStatus.Visibility = System.Windows.Visibility.Collapsed; Assembly a = Assembly.GetExecutingAssembly(); System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(System.IO.Path.GetDirectoryName(a.Location)); String zipFile = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(a.Location), "update.zip"); try { using (System.IO.FileStream fileStreamIn = System.IO.File.OpenRead(zipFile)) { using (ZipInputStream zipInStream = new ZipInputStream(fileStreamIn)) { ZipEntry zEntry; while ((zEntry = zipInStream.GetNextEntry()) != null) { byte[] buffer = new byte[4096]; String fullZipToPath = System.IO.Path.Combine(di.Parent.FullName, zEntry.Name); String directoryName = System.IO.Path.GetDirectoryName(zEntry.Name); if (!String.IsNullOrWhiteSpace(directoryName) && !System.IO.Directory.Exists(directoryName)) System.IO.Directory.CreateDirectory(directoryName); if (String.IsNullOrWhiteSpace(System.IO.Path.GetFileName(fullZipToPath))) continue; using (System.IO.FileStream streamWriter = System.IO.File.Create(fullZipToPath)) { ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(zipInStream, streamWriter, buffer); } } } } } catch (Exception ex) { MessageBox.Show(ex.Message); MessageBox.Show(ex.StackTrace); throw; } String tempFile = System.IO.Path.Combine(di.Parent.FullName, System.IO.Path.GetFileName(a.Location)); System.Diagnostics.Process.Start(tempFile, "-U"); this.Close(); } private void Help_DownloadLatest_Click(object sender, RoutedEventArgs e) { if (!_Settings.UpdateAvailable) return; Assembly a = Assembly.GetExecutingAssembly(); String tempPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(a.Location), "update"); // Blow away any existing files if (System.IO.Directory.Exists(tempPath)) System.IO.Directory.Delete(tempPath, true); System.IO.Directory.CreateDirectory(tempPath); // Copy all DLLs to the temp Update directory -- these are the only ones that can't be overwritten foreach (String file in System.IO.Directory.GetFiles(System.IO.Path.GetDirectoryName(a.Location), "*", System.IO.SearchOption.TopDirectoryOnly)) { if (file.ToLower().EndsWith(".dll") || file == a.Location) System.IO.File.Copy(file, System.IO.Path.Combine(tempPath, System.IO.Path.GetFileName(file))); } String tempFile = System.IO.Path.Combine(tempPath, System.IO.Path.GetFileName(a.Location)); System.Diagnostics.Process.Start(tempFile, String.Format("-u \"{0}\"", latestVersionInfo.FileUrl)); this.Close(); } private void Game_EndGame_Click(object sender, RoutedEventArgs e) { IsEndGameOK(); } private Boolean IsEndGameOK() { if (game != null) { if (game.State == DominionBase.GameState.Running && game.Players.Contains(_Player)) { MessageBoxResult mbr = MessageBox.Show("Do you want to abort the current game? This will count as a loss in your statistics.", "Please confirm", MessageBoxButton.OKCancel); if (mbr == MessageBoxResult.Cancel) return false; } if (uccChooser.Visibility == System.Windows.Visibility.Visible) { game.Abort(); uccChooser.Player.WaitEvent.Set(); uccChooser.Player = null; uccChooser.Choice = null; uccChooser.IsReady = false; uccChooser.Visibility = System.Windows.Visibility.Collapsed; } DominionBase.GameEndMessage gem = new DominionBase.GameEndMessage(_Player); gem.Message = String.Format("{0} ending game", _Player); EnqueueGameMessageAndWait(gem); bTurnDone.IsEnabled = false; bPlayTreasures.IsEnabled = false; bBuyPhase.IsEnabled = false; } return true; } private void Game_Replay_Click(object sender, RoutedEventArgs e) { if (game == null || game.State == DominionBase.GameState.Running || game.State == DominionBase.GameState.NotStarted) { miReplay.IsEnabled = false; return; } DominionBase.GameSettings settings = new DominionBase.GameSettings(); settings.IdenticalStartingHands = game.Settings.IdenticalStartingHands; settings.ColonyPlatinumUsage = DominionBase.ColonyPlatinumUsage.Never; settings.ShelterUsage = DominionBase.ShelterUsage.Never; Dictionary cardDictMap = new Dictionary(); settings.Preset = new DominionBase.Cards.Preset("Replay"); foreach (DominionBase.Piles.Supply supply in game.Table.Supplies.Values) { if (supply.Location == DominionBase.Cards.Location.Kingdom) { settings.Preset.Cards.Add(DominionBase.Cards.Card.CreateInstance(supply.CardType)); } //if (supply.CardType == DominionBase.Cards.Prosperity.TypeClass.Colony || supply.CardType == DominionBase.Cards.Prosperity.TypeClass.Platinum) // settings.ColonyPlatinumUsage = DominionBase.ColonyPlatinumUsage.Always; } if (game.Settings.ColonyPlatinumUsage == DominionBase.ColonyPlatinumUsage.Used) settings.ColonyPlatinumUsage = DominionBase.ColonyPlatinumUsage.Always; if (game.Settings.ShelterUsage == DominionBase.ShelterUsage.Used) settings.ShelterUsage = DominionBase.ShelterUsage.Always; List copyOfPresetCards = new List(settings.Preset.Cards); foreach (DominionBase.Cards.Card presetCard in copyOfPresetCards) presetCard.CheckSetup(settings.Preset, game.Table); StartGame(settings); } } }