Click here to Skip to main content
15,885,782 members
Articles / Artificial Intelligence

The Game of Clue (C# 2010)

Rate me:
Please Sign up or sign in to vote.
4.93/5 (55 votes)
13 Aug 2010CPOL29 min read 132.3K   3K   102  
You are a suspect!
  • clue_c_2010.zip
    • Clue CS2010
      • Clue CS2010.sln
      • Clue CS2010
        • About.rtf
        • Arranging The Cards.rtf
        • classPicTray_V2.cs
        • classSprite.cs
        • cLibPicBoxViewer.cs
        • Clue CS2010.csproj
        • Clue CS2010.csproj.user
        • Clue_Icon.ico
        • Dealing the cards.rtf
        • Equipment.rtf
        • formClue.cs
        • formClue.Designer.cs
        • formClue.resx
        • formInstructions.cs
        • formInstructions.Designer.cs
        • formInstructions.resx
        • Getting out of a room.rtf
        • Interesting notes and hints.rtf
        • Introduction.rtf
        • JESSICA_RABBIT.SP2
        • Movement of tokens.rtf
        • Moving into a room.rtf
        • Notes.bfs
        • Preparation.rtf
        • Program.cs
        • Properties
        • Proving the suggestion true or false.rtf
        • PulseButton.cs
        • PulseButton.designer.cs
        • PulseButton.dll
        • RATPROTESTER.SP2
        • Resources
          • baize.png
          • bars.bmp
          • Board Under Lense.jpg
          • CanShowACard.bmp
          • cardback.Jpeg
          • CardBilliardRoom.Jpeg
          • CardRoomBallroom.Jpeg
          • CardRoomConservatory.Jpeg
          • CardRoomDiningRoom.Jpeg
          • CardRoomHall.Jpeg
          • CardRoomKitchen.Jpeg
          • CardRoomLibrary.Jpeg
          • CardRoomLounge.Jpeg
          • CardRoomStudy.Jpeg
          • CardSuspectColMustard.Jpeg
          • CardSuspectMissScarlet.Jpeg
          • CardSuspectMrsPeacock.jpg
          • CardSuspectMrsWhite.Jpeg
          • CardSuspectProfPlum.Jpeg
          • CardSuspectRevGreen.Jpeg
          • CardWeaponCandleStick.Jpeg
          • CardWeaponKnife.Jpeg
          • CardWeaponLeadPipe.Jpeg
          • CardWeaponRevolver.Jpeg
          • CardWeaponRope.Jpeg
          • CardWeaponWrench.Jpeg
          • Clue logo mask.bmp
          • clue logo.bmp
          • ClueBoardMarble.Jpeg
          • ClueFloor.bmp
          • CrimeSceneBallRoom.bmp
          • CrimeSceneBilliardRoom.bmp
          • CrimeSceneConservatory.bmp
          • CrimeSceneDiningRoom.bmp
          • CrimeSceneHall.bmp
          • CrimeSceneKitchen.bmp
          • CrimeSceneLibrary.bmp
          • CrimeSceneLounge.bmp
          • CrimeSceneStudy.bmp
          • die1.bmp
          • die2.bmp
          • die3.bmp
          • die4.bmp
          • die5.bmp
          • die6.bmp
          • magnifying_glass.bmp
          • magnifying_handle.png
          • mainblock.bmp
          • Mouse00.bmp
          • Mouse01.bmp
          • Mouse02.bmp
          • newsprint.jpg
          • NoCardsToShow.bmp
          • notebook.jpg
          • noteBox_blank.bmp
          • noteBox_check.bmp
          • noteBox_ColMustard.bmp
          • noteBox_highlight.bmp
          • noteBox_MissScarlet.bmp
          • noteBox_MrsPeacock.bmp
          • noteBox_MrsWhite.bmp
          • noteBox_ProfPlum.bmp
          • noteBox_questionMark.bmp
          • noteBox_RevGreen.bmp
          • noteBox_X.bmp
          • picture frame oval.bmp
          • Piece_ColMustard.bmp
          • Piece_MissScarlet.bmp
          • Piece_MrsPeacock.bmp
          • Piece_MrsWhite.bmp
          • Piece_ProfPlum.bmp
          • Piece_RevGreen.bmp
          • prison bars large.bmp
          • setAI.bmp
          • SuggestionBubble.bmp
          • SuspectColMustard.bmp
          • SuspectMissScarlet.bmp
          • SuspectMrsPeacock.bmp
          • SuspectMrsWhite.bmp
          • SuspectProfPlum.bmp
          • SuspectRevGreen.bmp
          • WeaponBoard_Candlestick.bmp
          • WeaponBoard_Knife.bmp
          • WeaponBoard_LeadPipe.bmp
          • WeaponBoard_Revolver.bmp
          • WeaponBoard_Rope.bmp
          • WeaponBoard_Wrench.bmp
          • WeaponCandlestick.bmp
          • WeaponKnife.bmp
          • WeaponLeadPipe.bmp
          • WeaponRevolver.bmp
          • WeaponRope.bmp
          • WeaponWrench.bmp
          • Winner.bmp
        • Scream.aiff
        • Secret Passages.rtf
        • The accusation.rtf
        • The Suggestion.rtf
        • To Begin.rtf
        • User Interface.rtf
        • WALDO.SP2
        • Winning the game.rtf
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;
using Sprite;
using PicTray;

/// todo
/// - intro animation
namespace Clue_CS2010
{
	#region "enumerated types"

	public enum enuAccuseAnimationMode
	{
		endAccusation,
		drawAccusation,
		prepareToShowCards,
		showCards,
		hideCards,
		retractCards,
		withdrawAccusingSuspect,
		showNewspaper
	}

	public enum enuAILevel { stupid, dull, average, bright, genius, _numAILevels };
	public enum enuButtons { MakeSuggestion_Cancel, MakeSuggestion_Ok, RespondToSuggestion_Ok, MouseOver, _numButtons };
	public enum enuCards
	{
		MissScarlet = 0, ColMustard, MrsWhite, RevGreen, MrsPeacock, ProfPlum,
		Knife, Candlestick, Revolver, Rope, LeadPipe, Wrench,
		Study, Hall, Lounge, DiningRoom, Kitchen, BallRoom, Conservatory, BilliardRoom, Library,
		_numCards, Unknown, NoCardShown
	};
	public enum enuCardType { weapon = 0, room, Suspect, _numCardTypes };
	public enum enuDealCardsMode
	{
		getReady,
		SortCardsIntotypes,
		gatherTypes,

		spreadWeaponCardsFaceUp,
		flipWeaponcards,
		shuffleWeaponCards,
		gatherFaceDownWeapons,
		spreadWeapondsCardsFaceDown,
		selectWeapon,
		gatherFaceDownWeapons_LessMurderWeapon,

		spreadSuspectCardsFaceUp,
		flipSuspectcards,
		shuffleSuspectCards,
		gatherFaceDownSuspects,
		spreadSuspectdsCardsFaceDown,
		selectSuspect,
		gatherFaceDownSuspects_LessMurderSuspect,

		spreadRoomCardsFaceUp,
		flipRoomcards,
		shuffleRoomCards,
		gatherFaceDownRooms,
		spreadRoomdsCardsFaceDown,
		selectRoom,
		gatherFaceDownRooms_LessMurderRoom,

		shuffleCards,
		joinCardsAfterShuffle,
		dealToPlayers,
		moveMurderCardsToCenter,
		endDealCardsAnimation
	};
	public enum enuDir { north = 0, east, south, west, secretPassage };
	public enum enuFloor { tile = 0, room, door, invalid };

	public enum enuIntroAnimationMode 
	{ 
		moveToBawdyMansion,
		moveToRat, 
		movetoCKLovesVP,
		moveToBritneyWasHere,
		moveToSpider,
		moveToCheese,
		moveToCat,
		moveToWaldo,	
		moveToJessicaRabbit,
		moveToWrittenBy, 
		moveToChristKennedy,
		moveToYear, 
		moveToEnd, 
		_numIntroMode 
	};

	public enum enuIntroAnimationSprites
	{
		waldo,
		Jessica_Rabbit,
		RatProtester,
		_NumIntroAnimationSprites
	};

	public enum enuMode
	{
		idle,
		dealCards,
		Accuse,
		Accuse_Animation,
		chooseCharacter,
		warnPlayerNextTurn,
		beginTurn,
		gameOver,
		rollDie_begin,
		rollDie_animate,
		rollDie_end,
		showAllowableMoves,
		animateMove,
		Suggest,
		AISuggestionComplete,
		animateIntroduction,
		animateSummonSuspect,
		animateSummonWeapon,
		animateSecretPassage,
		respondToSuggestion,
		playerChoosesCardToShow,
		playerTurnIdle,
		endTurn,
		any
	};
	public enum enuNote { blank, X, check, question, _numNotes, shown };
	public enum enuRooms { Study, Hall, Lounge, DiningRoom, Kitchen, BallRoom, Conservatory, BilliardRoom, Library, _numRooms, start, tiles };
	public enum enuSuspects { MissScarlet = 0, ColMustard, MrsWhite, RevGreen, MrsPeacock, ProfPlum, _numSuspects };
	public enum enuWeapons { Knife = 0, Candlestick, Revolver, Rope, LeadPipe, Wrench, _numWeapons };

	#endregion

	#region "structures"
	public struct udtMurder
	{
		public enuSuspects eSuspect;
		public enuRooms eRoom;
		public enuWeapons eWeapon;
	}

	public struct udtAnimationSummons
	{
		public Point ptStart;
		public Point ptEnd;
		public Point ptMidway;
		public int intStepCounter;
		public int intMaxSteps;
		public double dblAngleBetweenPoints;
		public double dblDistanceBetweenPoints;

		public bool bolMoveToCenterOfScreen;
	}

	public struct udtAnimationSecretPassge
	{
		public Point ptStart;
		public Point ptEnd;
		public Point ptMidway;
		public int intStepCounter;
		public int intMaxSteps;
		public double dblAngleBetweenPoints;
		public double dblDistanceBetweenPoints;

		public bool bolMoveToCenterOfScreen;
		public enuRooms eRoom_Start;
		public enuRooms eRoom_End;
	}

	public struct udtSuggestionAnimation
	{
		public int intProveSuggestionCycleCounter;
	}

	public struct udtAnimationInfo
	{
		public Point ptStart;
		public Point ptEnd;
		public Point ptPos;
		public int intStep;
		public int intMaxSteps;

		public double dblTravelAngle;
		public double dblTravelDistance;
		public double dblTravelInitialVelocity;
		public double dblTravelAcceleration;
		public Point velTravel;

		public double dblAngleFacing;
		public double dblAngleTurning;
		public double dblAngleTurningAttenuation;

		public double dblSizeFactor;

		public Bitmap bmpGray;
		public Bitmap bmp;
	}

	public struct udtAccusation_Animation
	{
		public classCard[] cAnimatedCards;
		public int intAnimationStep;
		public bool bolInit;
		public Bitmap bmpAccusationBoard;
		public Bitmap bmpShadedAccusationBoard;
		public Bitmap bmpAccusationForegroundGray;
		public Bitmap bmpAccusationForeground;
		public enuAccuseAnimationMode _eMode;
		public udtMurder udrAccusation;
		public udtAnimationInfo[] udrElements;
		public udtAnimationInfo[] udrFloodlights;
		public udtAccusation_Animation_RotatingNewspaper udrNewspaper;
		public enuMode eRestoreMode;
	}

	public struct udtIntro_Animation
	{
		public int intAnimationStep;
		public bool bolInit;
		public enuIntroAnimationMode eMode;
		//public udtAnimationInfo[] udrMice;
		public udtIntro_Animation_Board udrBoardUnderLense;
		public Bitmap bmpBoard;
		public udtIntro_MagnifyingGlass udrMagnifyingGlass;
		public classRotatedImage[] cBmpMice;
		public udtIntro_Animation_Sprites[] sprites;
	}

	public struct udtIntro_Animation_Sprites
	{
		public classSprite cSprite;
		public int intConfiguration;
		public int intConfigurationStep;
		public int intMaxSteps;
		public int intStepCounter;
		public Sprite.enuMirror eMirror;
		public udtAnimationInfo udrAniInfo;
	}
	
	public struct udtIntro_Animation_Board
	{
		public udtIntro_Animation_BoardParcel[,] udrParcels;
		public Size szArray;
		public Size szParcels;
	}

	public struct udtIntro_Animation_BoardParcel
	{
		public Bitmap bmp;
		public Rectangle rec;
	}

	public struct udtIntro_MagnifyingGlass
	{
		public Point ptStart;
		public Point ptEnd;
		public Point ptPos;
		public int intStep;
		public int intMaxSteps;

		public int intHoverStep;
		public int intHoverMax;

		public double dblTravelAngle;
		public double dblTravelDistance;
		public Point velTravel;

		public double dblSizeFactor;
		public double dblSizeFactor_Start;
		public double dblSizeFactor_End;

		public Bitmap bmpLense;
		public Bitmap bmpHandle;
		public Color clrBackground;
		public Color clrLense;
		public Point ptCenterLense;
	}

	public struct udtAccusation_Animation_RotatingNewspaper
	{
		public classRotatedImage cBmp;
		public int intImage;
		public Point ptPos;
		public double dblSizeFactor;
	}

	public struct udtMoveAnimationInfo
	{
		public string strPath;
		public int intAnimationStep;

		public Bitmap bmpAnimationBoard;
		public Point ptMouseTile;
		public Point ptAnimationMove;
		public Point ptImage;
		public Rectangle recPiece;

		public classSuspect cSus;
	}

	public struct udtRollDieInfo
	{
		public int intDieValue;
		public int intDieWidth;
		public int intMaxVel;
		public int intVelFactor;
		public int intImageIndex;
		public Bitmap bmpCurrent;
		public double dblVelocityAttenuationFactor;
		public int intRightMost;
		public int intLowerMost;
		public double dblVel;
		public double dblAngle;
		public double dblXVel;
		public double dblYVel;
		public int intRollCount;
		public int intRollAnimation;
		public Point ptDie;
	}

	/// <summary>
	/// used to track sequence of suspects that follow me in order of play
	/// </summary> 
	public struct udtSuggestionAI_perSuspect
	{
		public enuSuspects eSuspect;
		public udtSuggestionAI_frequenCards[] udrRoomsMystery;			// list of mystery Rooms which this suspect may have
		public udtSuggestionAI_frequenCards[] udrWeaponCardsMystery;		// list of mystery Weapons which this suspect may have
		public udtSuggestionAI_frequenCards[] udrSuspectCardsMystery;		// list of mystery Suspects which this suspect may have
	}

	/// <summary>
	/// number of suspects who may have any given card
	/// </summary>
	public struct udtSuggestionAI_frequenCards
	{
		public enuCards eCards;
		public int intNumMystery;
	}

	/// <summary>
	/// information used to make a more informed suggestion
	/// </summary>
	public struct udtSuggestionAI
	{
		public udtSuggestionAI_perSuspect[] suspectMysteryInfo;				// sequence of suspects that follow me in order of play 
		// suspect's name, list of rooms cards suspect may have, list of weapons cards (ibid), list of suspect cards (ibid)
		public udtSuggestionAI_frequenCards[] udrRoomCardsMysteryFrequency;		// array of room cards ordered in number of suspects which may have these cards
		public udtSuggestionAI_frequenCards[] udrWeaponMysteryFrequency;		//     same :   weapon cards  
		public udtSuggestionAI_frequenCards[] udrSuspectMysteryFrequency;		//		same : Suspect cards

	}
	
		public struct udtTypeOrder
		{
			public classCard[] cWeapons;
			public classCard[] cSuspects;
			public classCard[] cRooms;
		}

		public struct udtAnimateDealCards
		{
			public enuDealCardsMode _eMode;
			public classCard[] cCardsCurrentAnimation;
			public udtTypeOrder udrTypeOrder;
			public int intAnimationCounter;
			public string strCards;
			public bool bolInit;
			public bool bolQuitAnimation;
			public udtAnimateDealCards_Shuffle udrShuffle;
		}

		public struct udtAnimateDealCards_Shuffle
		{
			public Point ptCentralShufflePos;
			public int intMaxDistance;
			public int intTimeShuffled;
			public int intMaxShuffle;
		}

	#endregion

	public partial class formClue : Form
	{
		#region "constants"
		public const double dblTwoPi = Math.PI * 2.0;
		#endregion

		#region "debug variables"
		//public string strDebugFilename;
		
		///// <summary>
		///// when true : load sprites from c:\sprites\ 
		///// when false : search for sprite files by going to parent until(but not including) root of drive starting for current-directory
		///// </summary>
		//public bool bolDebug = true; 

		#endregion

		#region "objects"
		public classMath cLibMath = new classMath();
		public classSpriteMaker spriteMaker = new classSpriteMaker();

		public PictureBox picBoard = new PictureBox();
		Button[] btnPlayerResponse = new Button[3];
		public ProgressBar proBar = new ProgressBar();

		MenuStrip mnu = new MenuStrip();

		public classButton[] cButtons;
				
		public Size sz;
		public Label lblSizer = new Label();

		public classPicTray_V2 cLibPicTraySuspects = new classPicTray_V2();
		public classPicTray_V2 cLibPicTrayWeapons = new classPicTray_V2();
		public classPicTray_V2 cLibPicTrayRooms = new classPicTray_V2();

		public System.Windows.Forms.Timer tmrDelay = new System.Windows.Forms.Timer();
		public System.Windows.Forms.Timer tmrAutoProceed = new System.Windows.Forms.Timer();
		public System.Windows.Forms.Timer tmrNextPlayer = new System.Windows.Forms.Timer();

		public Random rnd = new Random();
		Label lblInitializing = new Label();
		System.Windows.Forms.Timer tmrInit = new System.Windows.Forms.Timer();
		#endregion

		#region "Variables"
		public Bitmap bmpBoard, bmpSuggestionBoard, bmpGameBoard, bmpDealAnimationBoard, bmpDealAnimationBoard_Base;
		Bitmap bmpBaize = Clue_CS2010.Properties.Resources.baize;
		Bitmap bmpSuggestionBubble = Clue_CS2010.Properties.Resources.SuggestionBubble;
		Bitmap bmpCardBack = Clue_CS2010.Properties.Resources.cardback;
		Bitmap bmpBannerNoCard = Clue_CS2010.Properties.Resources.NoCardsToShow;
		Bitmap bmpBannerCardToShow = Clue_CS2010.Properties.Resources.CanShowACard;

		formInstructions frmInstructions;

		Bitmap bmpResponseBubble;
		public Bitmap bmpNotebook;

		public Bitmap[] bmpPieces = new Bitmap[(int)enuSuspects._numSuspects];
		public Bitmap[] bmpSuspects = new Bitmap[(int)enuSuspects._numSuspects];
		public Bitmap[] bmpWeapons_PicTray = new Bitmap[(int)enuWeapons._numWeapons];
		public Bitmap[] bmpWeapons_Board = new Bitmap[(int)enuWeapons._numWeapons];
		public Bitmap[] bmpRooms = new Bitmap[(int)enuRooms._numRooms];
				
		public classCard cCardUnknown;
		public classCard[] cCards;

		public classSuspect[] cSuspects;
		public classRoom[] cRooms;
		public classWeapon[] cWeapons;

		public Color[] clrSuspects;

		public enuCards[] eValidPlayerResponseCards;

		Rectangle recBannerButton;
		
		classNote[,] cPlayerNotes = new classNote[(int)enuSuspects._numSuspects, (int)enuCards._numCards];
		classNote cMouseOverNote;
		
		enuMode _eMode = enuMode.chooseCharacter;

		udtMoveAnimationInfo udrMoveAnimationInfo;
		string strCardsDealt;
		
		Point[] ptAnimationTypeStackPos;
		Point ptMouseTile;
		Point ptMousePos;
		public Point ptBoardTL = new Point(26, 7);
		Point[] ptSetAI;
		Point[] ptRoomCenters;
		Point ptSuggestionBubbleTL, ptResponseBubbleTL;

		bool _bolDisableMouseClickBoard = false;
		bool bolHideOptions = false;
		public bool bolAutoProceed = false;

		public int intSuspectTurn;
		public int intNumTurns = 0;
		int intBaseAutoProceedInterval = 3500;

		double dblSpeedFactor = 1.0;
				
		public classRotatedImage[] cBmpDie;
		public udtRollDieInfo udrRollDieInfo;
		public udtSuggestionAnimation udrSuggestionAnimation;
		public udtAnimationSummons udrAniSummWeapon;
		public udtAnimationSummons udrAniSummSuspect;
		public udtAnimationSecretPassge udrAniSecretPassage;
		public udtIntro_Animation udrAniIntro;
		public udtMurder udrMurder = new udtMurder();
		public udtMurder udrSuggestion = new udtMurder();

		public udtAnimateDealCards udrAnimateDealCards;
		public udtAccusation_Animation udrAniAccusation;

		/// flood-lights accusation animation variables
		Bitmap bmpFloodlights;
		Color clrFloordlights = Color.Red;
		Color clrField = Color.Blue;
		Brush br;
		bool bolInit = false;

		#endregion
		
		public formClue()
		{
			InitializeComponent();
			bmpNotebook = new Bitmap(Clue_CS2010.Properties.Resources.notebook);
			bmpBoard = new Bitmap(Clue_CS2010.Properties.Resources.ClueBoardMarble);
			sz = new Size(Clue_CS2010.Properties.Resources.ClueFloor.Width, Clue_CS2010.Properties.Resources.ClueFloor.Height);

			picBoard.Image = bmpBoard;
			picBoard.Refresh();
			PlaceControls();
			proBar.Visible = true; proBar.Maximum = 210;

			tmrInit.Interval = 5;
			tmrInit.Tick += new EventHandler(tmrInit_Tick);
			tmrInit.Enabled = true;
		}

		public bool bolDisableMouseClickBoard
		{
			get { return _bolDisableMouseClickBoard; }
			set 
			{
				_bolDisableMouseClickBoard = value;
			}
		}

		public void advanceProBar()
		{
			proBar.Value = (proBar.Value + 1) % proBar.Maximum;
		}

		void tmrInit_Tick(object sender, EventArgs e)
		{
			tmrInit.Enabled = false;
			Location = new Point(0, 0);
			Size = Screen.PrimaryScreen.WorkingArea.Size;
			Refresh();

			//initIntroMice(); advanceProBar();
			initMenu(); advanceProBar();
			initDieImages(); advanceProBar();
			initPieces(); advanceProBar();
			initSuspects(); advanceProBar();
			initWeapons(); advanceProBar();
			initColors(); advanceProBar();
			initRooms(); advanceProBar();
			resetPlayerNotes(); advanceProBar();
			initSetAIGroupBox(); advanceProBar();
			initCards(); advanceProBar();
			initAnimationIntroBehindTheLenseImages();
			eMode = (enuMode)0;
			initResponseBubble(); advanceProBar();

			bmpSuggestionBubble.MakeTransparent();
			bmpBannerCardToShow.MakeTransparent();
			bmpBannerNoCard.MakeTransparent();

			cButtons = new classButton[(int)enuButtons._numButtons];
			tmrNextPlayer.Interval = 5;
			tmrNextPlayer.Tick += new EventHandler(tmrNextPlayer_Tick);
			advanceProBar();
			ptAnimationTypeStackPos = new Point[3];
			ptAnimationTypeStackPos[(int)enuCardType.room] = new Point((int)(bmpBoard.Width * .1), (int)(bmpBoard.Height * .25));
			ptAnimationTypeStackPos[(int)enuCardType.Suspect] = new Point((int)(bmpBoard.Width * .1), (int)(bmpBoard.Height * .5));
			ptAnimationTypeStackPos[(int)enuCardType.weapon] = new Point((int)(bmpBoard.Width * .1), (int)(bmpBoard.Height * .75));

			tmrDelay.Tick += new EventHandler(tmrDelay_Tick);

			//strDebugFilename = System.IO.Directory.GetCurrentDirectory() + "\\AI test results.txt";

			FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
			Size = Screen.PrimaryScreen.WorkingArea.Size;
			Activated += new EventHandler(formClue_Activated);
			advanceProBar();
			resetPlayerNotes(); resetSuspects(enuSuspects.MissScarlet);

			advanceProBar();
			#region "init tray : cLibPicTrayRooms"
			{
				picBoard.Controls.Add(cLibPicTrayRooms);
				cLibPicTrayRooms.BackColor = Color.Transparent;

				cLibPicTrayRooms.tmrRotate.Tick += new EventHandler(cLibPicTraySuspectTmrRotate_Tick);

				for (enuRooms eRoomCounter = (enuRooms)0; eRoomCounter < enuRooms._numRooms; eRoomCounter++)
					cLibPicTrayRooms.addImageToTray(new Bitmap(cCards[(int)classCard.getECardFromERoom(eRoomCounter)].cBmp.getImage(0)), eRoomCounter.ToString());
				cLibPicTrayRooms.Visible = false;
			}
			#endregion
			advanceProBar();
			#region "init tray : cLibPicTraySuspects"
			{
				picBoard.Controls.Add(cLibPicTraySuspects);
				cLibPicTraySuspects.Options.BackColor = Color.Transparent;
				cLibPicTraySuspects.RoundImages = true;

				cLibPicTraySuspects.tmrRotate.Tick += new EventHandler(cLibPicTraySuspectTmrRotate_Tick);

				for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
					cLibPicTraySuspects.addImageToTray(bmpSuspects[(int)eSuspectCounter], eSuspectCounter.ToString());
				cLibPicTraySuspects.Visible = false;
			}
			#endregion
			advanceProBar();
			#region "init tray : cLibPicTrayWeapons"
			{
				picBoard.Controls.Add(cLibPicTrayWeapons);
				cLibPicTrayWeapons.Options.BackColor = Color.Transparent;
				cLibPicTrayWeapons.Location = new Point(355, 0);
				cLibPicTrayWeapons.RoundImages = true;

				cLibPicTrayWeapons.tmrRotate.Tick += new EventHandler(cLibPicTrayWeaponTmrRotate_Tick);

				for (enuWeapons eSuspectCounter = (enuWeapons)0; eSuspectCounter < enuWeapons._numWeapons; eSuspectCounter++)
					cLibPicTrayWeapons.addImageToTray(new Bitmap(bmpWeapons_PicTray[(int)eSuspectCounter]), eSuspectCounter.ToString());
				cLibPicTrayWeapons.Visible = false;
			}
			#endregion

			// init accusation animation variables
			bmpFloodlights = new Bitmap(bmpBoard.Width, bmpBoard.Height);
			using (Graphics g = Graphics.FromImage(bmpFloodlights))
				g.FillRectangle(new SolidBrush(clrField), new Rectangle(0, 0, bmpBoard.Width, bmpBoard.Height));
			bmpFloodlights.MakeTransparent(clrFloordlights);
			br = new SolidBrush(clrFloordlights);
			advanceProBar();
			commitMurder(); dealCards();
			eMode = enuMode.idle; eDealMode = enuDealCardsMode.SortCardsIntotypes;

			lblInitializing.Visible =
				proBar.Visible = false;
			bolInit = true;
			eMode = enuMode.animateIntroduction;
		}

		void formClue_Activated(object sender, EventArgs e)
		{
			Location = new Point(0, 0);
		}

		#region "timers"
		public void setDelayTimer(int intMilliseconds)
		{
			int intNewInterval = (int)(intMilliseconds * dblSpeedFactor);
			if (intNewInterval < 1)
				intNewInterval = 1;
			tmrDelay.Interval = intNewInterval;
			tmrDelay.Enabled = false;
			tmrDelay.Enabled = true;
		}

		void tmrAutoProceed_Tick(object sender, EventArgs e)
		{
			autoProceedEnabled = false;

			switch (eMode)
			{
				case enuMode.playerChoosesCardToShow:
					if (eValidPlayerResponseCards.Length == 1)
						btnPlayerResponse_Click((object)btnPlayerResponse[0], new MouseEventArgs(System.Windows.Forms.MouseButtons.Left, 1, 1, 1, 1));
					else
						PlayerChoosesCardToShowBannerClick();
					break;

				default:
					btnRespondSuggestion_OK_click();
					break;
			}
		}

		void tmrDelay_Tick(object sender, EventArgs e)
		{
			tmrDelay.Enabled = false;
		
			switch (eMode)
			{	
				case enuMode.warnPlayerNextTurn:
					eMode = enuMode.beginTurn;
					break;

				case enuMode.animateMove:
					moveStep();
					break;

				case enuMode.showAllowableMoves:
					cSuspects[intSuspectTurn].endShowAllowableMoves();
					break;

				case enuMode.rollDie_animate:
					rollDie_animate();
					break;

				case enuMode.animateIntroduction:
					animateIntroduction();
					break;

				case enuMode.animateSummonSuspect:
					animateSummonSuspect();
					break;

				case enuMode.animateSummonWeapon:
					animateSummonWeapon();
					break;

				case enuMode.Accuse_Animation:
				case enuMode.Accuse:
					animateAccusation();
					break;

				case enuMode.animateSecretPassage:
					AnimateSecretPassage();
					break;

				case enuMode.gameOver:
					eMode = enuMode.animateIntroduction;
					break;

				case enuMode.idle:
				case enuMode.dealCards:
					animateDealCards();
					break;
			}


		}
		void cLibPicTraySuspectTmrRotate_Tick(object sender, EventArgs e)
		{
			switch (eMode)
			{
				case enuMode.Accuse:
					setAccusation();
					break;

				case enuMode.Suggest:
					setSuggestion();
					break;

				case enuMode.chooseCharacter:
					setBtnChooseSuspectColorAndText();
					break;
			}
		}

		void cLibPicTrayWeaponTmrRotate_Tick(object sender, EventArgs e)
		{
			switch (eMode)
			{
				case enuMode.Accuse:
					setAccusation();
					break;

				case enuMode.Suggest:
					setSuggestion();
					break;
			}
		}

		#endregion		

		#region "animate intro"
		enuIntroAnimationMode eIntroMode
		{
			get { return udrAniIntro.eMode; }
			set
			{
				udrAniIntro.eMode = value;
				udrAniIntro.bolInit = false;
			}
		}

		void initAnimationIntroBehindTheLenseImages()
		{
			Bitmap bmpMegaBoard = new Bitmap(Clue_CS2010.Properties.Resources.Board_Under_Lense);

			udrAniIntro.udrMagnifyingGlass.bmpLense = new Bitmap(Clue_CS2010.Properties.Resources.magnifying_glass);
			udrAniIntro.udrMagnifyingGlass.bmpHandle = new Bitmap(Clue_CS2010.Properties.Resources.magnifying_handle);
			udrAniIntro.udrMagnifyingGlass.bmpHandle.MakeTransparent(udrAniIntro.udrMagnifyingGlass.bmpHandle.GetPixel(0, 0));


			int intMaxFitHorizontally = (int)(Math.Floor((double)bmpMegaBoard.Width / (2.0 * (double)Clue_CS2010.Properties.Resources.magnifying_glass.Width)));
			int intMaxFitVertically = (int)(Math.Floor((double)bmpMegaBoard.Height / (2.0 * (double)Clue_CS2010.Properties.Resources.magnifying_glass.Height)));

			udrAniIntro.udrBoardUnderLense.szArray = new System.Drawing.Size(2 * intMaxFitHorizontally - 1,
																			 2 * intMaxFitVertically - 1);
			udrAniIntro.udrBoardUnderLense.udrParcels =new udtIntro_Animation_BoardParcel[udrAniIntro.udrBoardUnderLense.szArray.Width, udrAniIntro.udrBoardUnderLense.szArray.Height];
			udrAniIntro.udrBoardUnderLense.szParcels  = new Size(bmpMegaBoard.Width / intMaxFitHorizontally, bmpMegaBoard.Height / intMaxFitVertically);
			Rectangle recDest = new Rectangle(0, 0, udrAniIntro.udrBoardUnderLense.szParcels.Width, udrAniIntro.udrBoardUnderLense.szParcels.Height);

			for (int intX = 0; intX < udrAniIntro.udrBoardUnderLense.szArray.Width; intX++)
			{
				for (int intY = 0; intY < udrAniIntro.udrBoardUnderLense.szArray.Height; intY++)
				{
					udrAniIntro.udrBoardUnderLense.udrParcels[intX, intY].bmp = new Bitmap(udrAniIntro.udrBoardUnderLense.szParcels.Width, udrAniIntro.udrBoardUnderLense.szParcels.Height);
					udrAniIntro.udrBoardUnderLense.udrParcels[intX, intY].rec = new Rectangle(intX * udrAniIntro.udrBoardUnderLense.szParcels.Width / 2, intY * udrAniIntro.udrBoardUnderLense.szParcels.Height / 2, udrAniIntro.udrBoardUnderLense.szParcels.Width, udrAniIntro.udrBoardUnderLense.szParcels.Height);
					using (Graphics g = Graphics.FromImage(udrAniIntro.udrBoardUnderLense.udrParcels[intX, intY].bmp))
						g.DrawImage(bmpMegaBoard, recDest, udrAniIntro.udrBoardUnderLense.udrParcels[intX, intY].rec, GraphicsUnit.Pixel);
					advanceProBar();
				}
			}
		}

		void initAnimateIntroduction()
		{
			//bolGameOver = false;
			Bitmap bmpTemp = new Bitmap(bmpBoard.Width + bmpNotebook.Width +5, bmpBoard.Height);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				g.DrawImage(bmpBoard, new Point(0, 0));
				g.DrawImage(bmpNotebook, new Point(bmpBoard.Width+5, 0));
				Bitmap bmpLogo = new Bitmap(Clue_CS2010.Properties.Resources.clue_logo);
				bmpLogo.MakeTransparent();
				g.DrawImage(bmpLogo, (bmpTemp.Width - bmpLogo.Width) / 2, (bmpTemp.Height - bmpLogo.Height) / 2);
			}
			picBoard.Size = bmpTemp.Size;
			picBoard.Image = bmpTemp;
			picBoard.BringToFront();
			udrAniIntro.bmpBoard = bmpTemp;
			
			udrAniIntro.udrMagnifyingGlass.ptCenterLense = new Point(udrAniIntro.udrMagnifyingGlass.bmpLense.Width / 2, udrAniIntro.udrMagnifyingGlass.bmpLense.Height / 2);
			udrAniIntro.udrMagnifyingGlass.clrBackground = udrAniIntro.udrMagnifyingGlass.bmpLense.GetPixel(0, 0);
			udrAniIntro.udrMagnifyingGlass.clrLense = udrAniIntro.udrMagnifyingGlass.bmpLense.GetPixel(udrAniIntro.udrMagnifyingGlass.ptCenterLense.X, udrAniIntro.udrMagnifyingGlass.ptCenterLense.Y);
			
			// initialize intro animation sprites
			udrAniIntro.sprites = new udtIntro_Animation_Sprites[(int)enuIntroAnimationSprites._NumIntroAnimationSprites];
			udrAniIntro.sprites[(int)enuIntroAnimationSprites.waldo].cSprite = spriteMaker.loadSprite(getSpriteFilename(enuIntroAnimationSprites.waldo.ToString()));
			udrAniIntro.sprites[(int)enuIntroAnimationSprites.waldo].udrAniInfo.ptPos = new Point(336, 1784);

			udrAniIntro.sprites[(int)enuIntroAnimationSprites.Jessica_Rabbit].cSprite = spriteMaker.loadSprite(getSpriteFilename(enuIntroAnimationSprites.Jessica_Rabbit.ToString()));
			udrAniIntro.sprites[(int)enuIntroAnimationSprites.Jessica_Rabbit].udrAniInfo.ptPos = new Point(420, 708);

			udrAniIntro.sprites[(int)enuIntroAnimationSprites.RatProtester].cSprite = spriteMaker.loadSprite(getSpriteFilename(enuIntroAnimationSprites.RatProtester.ToString()));
			udrAniIntro.sprites[(int)enuIntroAnimationSprites.RatProtester].udrAniInfo.ptPos = new Point(1100, 418);
			udrAniIntro.sprites[(int)enuIntroAnimationSprites.RatProtester].eMirror = Sprite.enuMirror.none;

			eIntroMode = (enuIntroAnimationMode)0;
			setDelayTimer(10);
		}

		string getSpriteFilename(string strFilename)
		{
			//if (bolDebug)
			//    return "c:\\sprites\\" + strFilename + "\\" + strFilename + ".sp2";

			string strDirectory = System.IO.Directory.GetCurrentDirectory();
			string strFilenameAndDirectory = strDirectory + "\\" + strFilename + ".sp2";
			while (strFilenameAndDirectory.Length > 0 && !System.IO.File.Exists(strFilenameAndDirectory))
			{
				int intIndex = strDirectory.LastIndexOf("\\");
				if (intIndex > 0)
				{
					strDirectory = strDirectory.Substring(0, intIndex);
					strFilenameAndDirectory = strDirectory +"\\" + strFilename + ".sp2";
				}
				else
					strFilenameAndDirectory = "";
			}
			return strFilenameAndDirectory;
		}

		void animateIntroduction()
		{
			if (!udrAniIntro.bolInit)
			{
				switch (udrAniIntro.eMode)
				{
					case enuIntroAnimationMode.moveToBawdyMansion:
						udrAniIntro.udrMagnifyingGlass.ptStart = new Point(-550, 50);
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(1092, 60);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 8;
						break;

					case enuIntroAnimationMode.moveToRat:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(1119, 418);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 12;
						break;

					case enuIntroAnimationMode.movetoCKLovesVP:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(2740, 236);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 6;
						break;

					case enuIntroAnimationMode.moveToBritneyWasHere:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(2732, 1404);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 6;
						break;

					case enuIntroAnimationMode.moveToSpider:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(1904, 1687);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 3;
						break;

					case enuIntroAnimationMode.moveToCheese:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(2076, 2020);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 3;
						break;

					case enuIntroAnimationMode.moveToCat:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(1100, 2044);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 1;
						break;

					case enuIntroAnimationMode.moveToWaldo:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(336, 1784);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 15;
						break;

					case enuIntroAnimationMode.moveToJessicaRabbit:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(420, 738);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 15;
						break;

					case enuIntroAnimationMode.moveToWrittenBy:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(884, 952);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 5;
						break;

					case enuIntroAnimationMode.moveToChristKennedy:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(2299, 1265);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 20;
						break;

					case enuIntroAnimationMode.moveToYear:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(289, 1429);
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 4;
						break;

					case enuIntroAnimationMode.moveToEnd:
						udrAniIntro.udrMagnifyingGlass.ptStart = udrAniIntro.udrMagnifyingGlass.ptPos;
						udrAniIntro.udrMagnifyingGlass.ptEnd = new Point(-550, (Clue_CS2010.Properties.Resources.Board_Under_Lense.Height) - 50);
						udrAniIntro.udrMagnifyingGlass.intHoverMax = 0;
						udrAniIntro.udrMagnifyingGlass.intHoverStep = 0;
						break;
				}

				udrAniIntro.udrMagnifyingGlass.intStep = 0;

				udrAniIntro.udrMagnifyingGlass.dblTravelAngle = classMath.arcTan(udrAniIntro.udrMagnifyingGlass.ptEnd, udrAniIntro.udrMagnifyingGlass.ptStart);
				udrAniIntro.udrMagnifyingGlass.dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniIntro.udrMagnifyingGlass.ptEnd, udrAniIntro.udrMagnifyingGlass.ptStart);

				udrAniIntro.udrMagnifyingGlass.intMaxSteps = (int)(Math.Ceiling(udrAniIntro.udrMagnifyingGlass.dblTravelDistance / 60));

				udrAniIntro.bolInit = true;
			}

			// animate sprites
			for (enuIntroAnimationSprites eSpriteCounter = (enuIntroAnimationSprites)0; eSpriteCounter < enuIntroAnimationSprites._NumIntroAnimationSprites; eSpriteCounter++)
			{
				switch (eSpriteCounter)
				{
					case enuIntroAnimationSprites.RatProtester:
						udrAniIntro.sprites[(int)eSpriteCounter].intConfigurationStep = (udrAniIntro.sprites[(int)eSpriteCounter].intConfigurationStep + 1) % udrAniIntro.sprites[(int)eSpriteCounter].cSprite.Configurations[udrAniIntro.sprites[(int)eSpriteCounter].intConfiguration].steps.Length;
						if (udrAniIntro.sprites[(int)eSpriteCounter].intConfigurationStep == 0)
						{
							if (udrAniIntro.sprites[(int)eSpriteCounter].eMirror == Sprite.enuMirror.none)
								udrAniIntro.sprites[(int)eSpriteCounter].eMirror = Sprite.enuMirror.horizontal;
							else
								udrAniIntro.sprites[(int)eSpriteCounter].eMirror = Sprite.enuMirror.none;
						}
						int intStepSize = 20;
						udrAniIntro.sprites[(int)eSpriteCounter].udrAniInfo.ptPos.X += (udrAniIntro.sprites[(int)eSpriteCounter].eMirror == Sprite.enuMirror.none ? 1 : -1) * intStepSize;
						break;

					default:
						udrAniIntro.sprites[(int)eSpriteCounter].intConfigurationStep = (udrAniIntro.sprites[(int)eSpriteCounter].intConfigurationStep + 1) % udrAniIntro.sprites[(int)eSpriteCounter].cSprite.Configurations[udrAniIntro.sprites[(int)eSpriteCounter].intConfiguration].steps.Length;
						if (udrAniIntro.sprites[(int)eSpriteCounter].intConfigurationStep == 0)
							udrAniIntro.sprites[(int)eSpriteCounter].intConfiguration = (int)(rnd.NextDouble() * 10000 * udrAniIntro.sprites[(int)eSpriteCounter].cSprite.Configurations.Length) % udrAniIntro.sprites[(int)eSpriteCounter].cSprite.Configurations.Length;
						break;
				}
			}

			// move magnifying glass over mega board
			if (udrAniIntro.udrMagnifyingGlass.intStep < udrAniIntro.udrMagnifyingGlass.intMaxSteps)
			{
				udrAniIntro.udrMagnifyingGlass.intStep++;
				double dblPercentDistanceTravelled = ((double)udrAniIntro.udrMagnifyingGlass.intStep / (double)udrAniIntro.udrMagnifyingGlass.intMaxSteps);
				udrAniIntro.udrMagnifyingGlass.ptPos.X = (int)(udrAniIntro.udrMagnifyingGlass.ptStart.X + dblPercentDistanceTravelled * udrAniIntro.udrMagnifyingGlass.dblTravelDistance * Math.Cos(udrAniIntro.udrMagnifyingGlass.dblTravelAngle));
				udrAniIntro.udrMagnifyingGlass.ptPos.Y = (int)(udrAniIntro.udrMagnifyingGlass.ptStart.Y + dblPercentDistanceTravelled * udrAniIntro.udrMagnifyingGlass.dblTravelDistance * Math.Sin(udrAniIntro.udrMagnifyingGlass.dblTravelAngle));
			}

			// create image of lense
			Bitmap bmpTempLense = new Bitmap(udrAniIntro.udrMagnifyingGlass.bmpLense.Width, udrAniIntro.udrMagnifyingGlass.bmpLense.Height);
			Rectangle recSrcMegaParcel;
			Rectangle recDestMegaBoard = new Rectangle(0, 0, bmpTempLense.Width, bmpTempLense.Height);
			Rectangle recSrcMegaBoard = new Rectangle(getMagnifyingLenseTLOnMegaBoard(udrAniIntro.udrMagnifyingGlass.ptPos), bmpTempLense.Size);
			using (Graphics g = Graphics.FromImage(bmpTempLense))
			{
				// copy mega board image onto temp bmp

				Point ptIndex = new Point(udrAniIntro.udrBoardUnderLense.szArray.Width - 1, udrAniIntro.udrBoardUnderLense.szArray.Height - 1);
				while (ptIndex.X > 0 && udrAniIntro.udrBoardUnderLense.udrParcels[ptIndex.X, ptIndex.Y].rec.Left > recSrcMegaBoard.Left)
					ptIndex.X--;
				while (ptIndex.Y > 0 && udrAniIntro.udrBoardUnderLense.udrParcels[ptIndex.X, ptIndex.Y].rec.Top > recSrcMegaBoard.Top)
					ptIndex.Y--;
			
				recSrcMegaParcel = new Rectangle(recSrcMegaBoard.Left - udrAniIntro.udrBoardUnderLense.udrParcels[ptIndex.X, ptIndex.Y].rec.Left,
														   recSrcMegaBoard.Top - udrAniIntro.udrBoardUnderLense.udrParcels[ptIndex.X, ptIndex.Y].rec.Top,
														   recSrcMegaBoard.Width,
														   recSrcMegaBoard.Height);

				g.DrawImage(udrAniIntro.udrBoardUnderLense.udrParcels[ptIndex.X, ptIndex.Y].bmp, recDestMegaBoard, recSrcMegaParcel, GraphicsUnit.Pixel);


				Point ptLenseCenter = udrAniIntro.udrMagnifyingGlass.ptPos;
				for (int intSpriteCounter = 0; intSpriteCounter < udrAniIntro.sprites.Length; intSpriteCounter++)
				{
					double dblDistance = classMath.distanceBetweenTwoPoints(ptLenseCenter, udrAniIntro.sprites[intSpriteCounter].udrAniInfo.ptPos);
					if (dblDistance < 200)
					{ // draw this sprite
						Point ptSprite = new Point(udrAniIntro.sprites[intSpriteCounter].udrAniInfo.ptPos.X - recSrcMegaBoard.Left,
												   udrAniIntro.sprites[intSpriteCounter].udrAniInfo.ptPos.Y - recSrcMegaBoard.Top);

						udrAniIntro.sprites[intSpriteCounter].cSprite.putConfigurationOnScreen(ref bmpTempLense,
																								   udrAniIntro.sprites[intSpriteCounter].intConfiguration,
																								   udrAniIntro.sprites[intSpriteCounter].intConfigurationStep,
																								   ptSprite,
																								   0,
																								   1.0,
																								   udrAniIntro.sprites[intSpriteCounter].eMirror,
																								   false);
					}
				}


				udrAniIntro.udrMagnifyingGlass.bmpLense.MakeTransparent(udrAniIntro.udrMagnifyingGlass.clrLense);
				g.DrawImage(udrAniIntro.udrMagnifyingGlass.bmpLense, new Point(0, 0));
			}

			// make temp lense background transparent then draw onto regular board
			bmpTempLense.MakeTransparent(udrAniIntro.udrMagnifyingGlass.clrBackground);

			Bitmap bmpNewBoard = new Bitmap(udrAniIntro.bmpBoard);
			using (Graphics g = Graphics.FromImage(bmpNewBoard))
			{
				Point ptTLLense = getMagnifyingLenseTLOnRegularBoard(udrAniIntro.udrMagnifyingGlass.ptPos);
				g.DrawImage(bmpTempLense, ptTLLense);
				g.DrawImage(udrAniIntro.udrMagnifyingGlass.bmpHandle, new Point(ptTLLense.X - 198, ptTLLense.Y + 229));
			}

			picBoard.Image = bmpNewBoard; picBoard.Refresh();

			if (udrAniIntro.udrMagnifyingGlass.intStep >= udrAniIntro.udrMagnifyingGlass.intMaxSteps)
			{
				if (udrAniIntro.udrMagnifyingGlass.intHoverStep < udrAniIntro.udrMagnifyingGlass.intHoverMax)
				{
					udrAniIntro.udrMagnifyingGlass.intHoverStep++;
				}
				else
					eIntroMode = (enuIntroAnimationMode)(((int)eIntroMode + 1) % (int)enuIntroAnimationMode._numIntroMode);
			}

			setDelayTimer(100);
		}

		Point getMagnifyingLenseTLOnRegularBoard(Point ptLenseCenterOnMegaBoard)
		{
			Point ptLenseCenterOnRegularBoard = new Point(ptLenseCenterOnMegaBoard.X / 3, ptLenseCenterOnMegaBoard.Y / 3);
			return new Point(ptLenseCenterOnRegularBoard.X - udrAniIntro.udrMagnifyingGlass.ptCenterLense.X, ptLenseCenterOnRegularBoard.Y - udrAniIntro.udrMagnifyingGlass.ptCenterLense.Y);
		}

		Point getMagnifyingLenseTLOnMegaBoard(Point ptLenseCenterOnMegaBoard)
		{
			return new Point(ptLenseCenterOnMegaBoard.X - udrAniIntro.udrMagnifyingGlass.ptCenterLense.X, ptLenseCenterOnMegaBoard.Y - udrAniIntro.udrMagnifyingGlass.ptCenterLense.Y);
		}

		#endregion

		#region "animate Deal Cards"
		enuDealCardsMode eDealMode
		{
			get { return udrAnimateDealCards._eMode; }
			set
			{
				int intHalfCardWidth = cCards[0].cBmp.getImage(0).Width / 2;
				int intHalfCardHeight = cCards[0].cBmp.getImage(0).Height / 2;
				if (udrAnimateDealCards._eMode != value)
				{
					udrAnimateDealCards._eMode = value;

					// initialize animation for each mode
					switch (eDealMode)
					{
						case enuDealCardsMode.SortCardsIntotypes:
							udrAnimateDealCards.strCards = shuffleCards(false);
							udrAnimateDealCards.intAnimationCounter = 0;
							udrAnimateDealCards.cCardsCurrentAnimation = new classCard[0];
							setDelayTimer(100);
							break;

						case enuDealCardsMode.gatherTypes:
							udrAnimateDealCards.intAnimationCounter = 0;
							break;

						/// shuffle, select & hide weapons
						case enuDealCardsMode.spreadWeaponCardsFaceUp:
							bmpDealAnimationBoard_Base = AnimateDealCards_getBlankDealCardsImage();

							using (Graphics g = Graphics.FromImage(bmpDealAnimationBoard_Base))
							{
								classCard cThisCard = udrAnimateDealCards.udrTypeOrder.cSuspects[udrAnimateDealCards.udrTypeOrder.cSuspects.Length - 1];
								Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - intHalfCardWidth, cThisCard.udrAnimationInfo.ptPos.Y - intHalfCardHeight);
								g.DrawImage(cThisCard.cBmp.getImage(0), ptTL);

								cThisCard = udrAnimateDealCards.udrTypeOrder.cRooms[udrAnimateDealCards.udrTypeOrder.cRooms.Length - 1];
								ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - intHalfCardWidth, cThisCard.udrAnimationInfo.ptPos.Y - intHalfCardHeight);
								g.DrawImage(cThisCard.cBmp.getImage(0), ptTL);
							}

							udrAnimateDealCards.intAnimationCounter = 0;
							break;

						case enuDealCardsMode.flipWeaponcards:
							udrAnimateDealCards.bolInit = false;
							udrAnimateDealCards.intAnimationCounter = 0;
							break;

						case enuDealCardsMode.shuffleWeaponCards:
							udrAnimateDealCards.bolInit = false;
							udrAnimateDealCards.intAnimationCounter = 0;
							break;

						case enuDealCardsMode.gatherFaceDownWeapons:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.spreadWeapondsCardsFaceDown:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.selectWeapon:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.gatherFaceDownWeapons_LessMurderWeapon:
							udrAnimateDealCards.bolInit = false;
							break;


						/// shuffle, select & hide suspects
						case enuDealCardsMode.spreadSuspectCardsFaceUp:
							udrAnimateDealCards.intAnimationCounter = 0;

							bmpDealAnimationBoard_Base = AnimateDealCards_getBlankDealCardsImage();

							using (Graphics g = Graphics.FromImage(bmpDealAnimationBoard_Base))
							{
								// draw back weapon card stack
								classCard cThisCard = udrAnimateDealCards.udrTypeOrder.cSuspects[udrAnimateDealCards.udrTypeOrder.cSuspects.Length - 1];
								Point ptTL = new Point(ptAnimationTypeStackPos[(int)enuCardType.weapon].X - intHalfCardWidth, ptAnimationTypeStackPos[(int)enuCardType.weapon].Y - intHalfCardHeight);
								g.DrawImage(cCardUnknown.cBmp.getImage(0), ptTL);

								// draw front room stack
								cThisCard = udrAnimateDealCards.udrTypeOrder.cRooms[udrAnimateDealCards.udrTypeOrder.cRooms.Length - 1];
								ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - intHalfCardWidth, cThisCard.udrAnimationInfo.ptPos.Y - intHalfCardHeight);
								g.DrawImage(cThisCard.cBmp.getImage(0), ptTL);
							}
							break;

						case enuDealCardsMode.flipSuspectcards:
							udrAnimateDealCards.bolInit = false;
							udrAnimateDealCards.intAnimationCounter = 0;
							break;

						case enuDealCardsMode.shuffleSuspectCards:
							udrAnimateDealCards.bolInit = false;
							udrAnimateDealCards.intAnimationCounter = 0;
							break;

						case enuDealCardsMode.gatherFaceDownSuspects:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.spreadSuspectdsCardsFaceDown:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.selectSuspect:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.gatherFaceDownSuspects_LessMurderSuspect:
							udrAnimateDealCards.bolInit = false;
							break;


						/// shuffle, select & hide Rooms
						case enuDealCardsMode.spreadRoomCardsFaceUp:
							udrAnimateDealCards.intAnimationCounter = 0;
							bmpDealAnimationBoard_Base = AnimateDealCards_getBlankDealCardsImage();

							using (Graphics g = Graphics.FromImage(bmpDealAnimationBoard_Base))
							{
								// draw back weapon card stack
								Point ptTL = new Point(ptAnimationTypeStackPos[(int)enuCardType.weapon].X - intHalfCardWidth, ptAnimationTypeStackPos[(int)enuCardType.weapon].Y - intHalfCardHeight);
								g.DrawImage(cCardUnknown.cBmp.getImage(0), ptTL);

								// draw back suspect stack
								ptTL = new Point(ptAnimationTypeStackPos[(int)enuCardType.Suspect].X - intHalfCardWidth, ptAnimationTypeStackPos[(int)enuCardType.Suspect].Y - intHalfCardHeight);
								g.DrawImage(cCardUnknown.cBmp.getImage(0), ptTL);
							}
							break;

						case enuDealCardsMode.flipRoomcards:
							udrAnimateDealCards.bolInit = false;
							udrAnimateDealCards.intAnimationCounter = 0;
							break;

						case enuDealCardsMode.shuffleRoomCards:
							udrAnimateDealCards.bolInit = false;
							udrAnimateDealCards.intAnimationCounter = 0;
							break;

						case enuDealCardsMode.gatherFaceDownRooms:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.spreadRoomdsCardsFaceDown:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.selectRoom:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.gatherFaceDownRooms_LessMurderRoom:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.shuffleCards:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.joinCardsAfterShuffle:
							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.dealToPlayers:
							udrAnimateDealCards.bolInit = false;
							int intCardIndex = (int)classCard.getECardFromEWeapon(udrMurder.eWeapon);
							cCards[intCardIndex].udrAnimationInfo.intStep = cCards[intCardIndex].udrAnimationInfo.intMaxSteps;

							intCardIndex = (int)classCard.getECardFromERoom(udrMurder.eRoom);
							cCards[intCardIndex].udrAnimationInfo.intStep = cCards[intCardIndex].udrAnimationInfo.intMaxSteps;

							intCardIndex = (int)classCard.getECardFromESuspect(udrMurder.eSuspect);
							cCards[intCardIndex].udrAnimationInfo.intStep = cCards[intCardIndex].udrAnimationInfo.intMaxSteps;

							udrAnimateDealCards.strCards = strCardsDealt;
							break;

						case enuDealCardsMode.moveMurderCardsToCenter:
							bmpDealAnimationBoard_Base = AnimateDealCards_getBlankDealCardsImage();
							udrAnimateDealCards.cCardsCurrentAnimation = new classCard[3];
							udrAnimateDealCards.cCardsCurrentAnimation[0] = cCards[(int)classCard.getECardFromESuspect ( udrMurder.eSuspect)];
							udrAnimateDealCards.cCardsCurrentAnimation[1] = cCards[(int)classCard.getECardFromERoom ( udrMurder.eRoom)];
							udrAnimateDealCards.cCardsCurrentAnimation[2] = cCards[(int)classCard.getECardFromEWeapon ( udrMurder.eWeapon)];

							enuCards eWeapon = classCard.getECardFromEWeapon(udrMurder.eWeapon);
							enuCards eSuspect = classCard.getECardFromESuspect(udrMurder.eSuspect);
							enuCards eRoom = classCard.getECardFromERoom(udrMurder.eRoom);

							using (Graphics g = Graphics.FromImage(bmpDealAnimationBoard_Base))
							{
								for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
									for (int intCardCounter = 0; intCardCounter < cSuspects[(int)eSuspectCounter].cCards.Length; intCardCounter++)
									{
										classCard cThisCard = cSuspects[(int)eSuspectCounter].cCards[intCardCounter];

										int intImageIndex = getImageIndex(cThisCard.udrAnimationInfo.dblAngleFacing);

										Bitmap bmp = cThisCard.cSuspect.bolPlayerControlled ? cThisCard.cBmp.getImage(intImageIndex) : cCardUnknown.cBmp.getImage(intImageIndex);
										Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - bmp.Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - bmp.Height / 2);
										g.DrawImage(bmp, ptTL);

										cThisCard.udrAnimationInfo.intStep++;
									}
							}

							udrAnimateDealCards.bolInit = false;
							break;

						case enuDealCardsMode.endDealCardsAnimation:
							if (eMode == enuMode.idle)
							{
								eDealMode  = enuDealCardsMode.SortCardsIntotypes;
								return;
							}
							break;
					}
				}
			}
		}

		Bitmap AnimateDealCards_getBlankDealCardsImage()
		{
			Bitmap bmpTemp = new Bitmap(pnlNotebook.Left + 240, picBoard.Height);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				g.DrawImage(bmpBoard, 0, 0);
				g.DrawImage((Bitmap)Clue_CS2010.Properties.Resources.notebook, pnlNotebook.Left, 0);
			}
			return bmpTemp;
		}

		void animateDealCards()
		{
			if (udrAnimateDealCards.bolQuitAnimation)
			{
				if (eMode == enuMode.idle)
					NewGame((object)this, new EventArgs());
				else
					eDealMode = enuDealCardsMode.endDealCardsAnimation;
			}
			switch (eDealMode)
			{
				case enuDealCardsMode.SortCardsIntotypes:
					bmpDealAnimationBoard_Base = AnimateDealCards_getBlankDealCardsImage();
					picBoard.Image = bmpDealAnimationBoard_Base;
					picBoard.BringToFront();
					AnimateDealCards_SortCardsIntoTypes();
					break;

				case enuDealCardsMode.gatherTypes:
					AnimateDealCards_GatherTypes();
					break;

				/// shuffle, select & hide weapons
				case enuDealCardsMode.spreadWeaponCardsFaceUp:
					AnimateDealCards_SpreadCards(enuCardType.weapon, true);
					break;

				case enuDealCardsMode.flipWeaponcards:
					AnimateDealCards_FlipCardsUtoD_DirR(enuCardType.weapon);
					break;

				case enuDealCardsMode.shuffleWeaponCards:
					AnimateDealCards_Shuffle(enuCardType.weapon);
					break;

				case enuDealCardsMode.gatherFaceDownWeapons:
					AnimateDealCards_GatherType(ptAnimationTypeStackPos[(int)enuCardType.weapon], enuCardType.weapon, false);
					break;

				case enuDealCardsMode.spreadWeapondsCardsFaceDown:
					AnimateDealCards_SpreadCards(enuCardType.weapon, false);
					break;

				case enuDealCardsMode.selectWeapon:
					AnimateDealCards_SelectCard(enuCardType.weapon);
					break;

				case enuDealCardsMode.gatherFaceDownWeapons_LessMurderWeapon:
					AnimateDealCards_GatherType(ptAnimationTypeStackPos[(int)enuCardType.weapon], enuCardType.weapon, false);
					break;


				/// shuffle, select & hide Suspects
				case enuDealCardsMode.spreadSuspectCardsFaceUp:
					AnimateDealCards_SpreadCards(enuCardType.Suspect, true);
					break;

				case enuDealCardsMode.flipSuspectcards:
					AnimateDealCards_FlipCardsUtoD_DirR(enuCardType.Suspect);
					break;

				case enuDealCardsMode.shuffleSuspectCards:
					AnimateDealCards_Shuffle(enuCardType.Suspect);
					break;

				case enuDealCardsMode.gatherFaceDownSuspects:
					AnimateDealCards_GatherType(ptAnimationTypeStackPos[(int)enuCardType.Suspect], enuCardType.Suspect, false);
					break;

				case enuDealCardsMode.spreadSuspectdsCardsFaceDown:
					AnimateDealCards_SpreadCards(enuCardType.Suspect, false);
					break;

				case enuDealCardsMode.selectSuspect:
					AnimateDealCards_SelectCard(enuCardType.Suspect);
					break;

				case enuDealCardsMode.gatherFaceDownSuspects_LessMurderSuspect:
					AnimateDealCards_GatherType(ptAnimationTypeStackPos[(int)enuCardType.Suspect], enuCardType.Suspect, false);
					break;


				/// shuffle, select & hide Rooms
				case enuDealCardsMode.spreadRoomCardsFaceUp:
					AnimateDealCards_SpreadCards(enuCardType.room, true);
					break;

				case enuDealCardsMode.flipRoomcards:
					AnimateDealCards_FlipCardsUtoD_DirR(enuCardType.room);
					break;

				case enuDealCardsMode.shuffleRoomCards:
					AnimateDealCards_Shuffle(enuCardType.room);
					break;

				case enuDealCardsMode.gatherFaceDownRooms:
					AnimateDealCards_GatherType(ptAnimationTypeStackPos[(int)enuCardType.room], enuCardType.room, false);
					break;

				case enuDealCardsMode.spreadRoomdsCardsFaceDown:
					AnimateDealCards_SpreadCards(enuCardType.room, false);
					break;

				case enuDealCardsMode.selectRoom:
					AnimateDealCards_SelectCard(enuCardType.room);
					break;

				case enuDealCardsMode.gatherFaceDownRooms_LessMurderRoom:
					AnimateDealCards_GatherType(ptAnimationTypeStackPos[(int)enuCardType.room], enuCardType.room, false);
					break;

				case enuDealCardsMode.shuffleCards:
					bmpDealAnimationBoard_Base = AnimateDealCards_getBlankDealCardsImage();
					AnimateDealCards_ShuffleCards();
					break;

				case enuDealCardsMode.joinCardsAfterShuffle:
					AnimateDealCards_JoinCards();
					break;

				case enuDealCardsMode.dealToPlayers:
					AnimateDealCards_DealToPlayers();
					break;

				case enuDealCardsMode.moveMurderCardsToCenter:
					
					AnimateDealCards_MoveMurderCardsToCenter();
					break;

				case enuDealCardsMode.endDealCardsAnimation:
					if (eMode == enuMode.idle)
					{
						eDealMode = enuDealCardsMode.SortCardsIntotypes;
					}
					else
					{
						setPlayerNoteBook();
						drawPlayerCards();
						setSuspectsAI();

						grbControls.Enabled = grbControls.Visible = true;
						intSuspectTurn = 0;

						eMode = enuMode.warnPlayerNextTurn;
					}
					break;
			}
		}

		void AnimateDealCards_MoveMurderCardsToCenter()
		{
			if (!udrAnimateDealCards.bolInit)
			{
				udrAnimateDealCards.bolInit = true;
				

				for (int intCardCounter = 0; intCardCounter < udrAnimateDealCards.cCardsCurrentAnimation.Length; intCardCounter++)
				{
					classCard cThisCard = udrAnimateDealCards.cCardsCurrentAnimation[intCardCounter];
					cThisCard.udrAnimationInfo.ptStart = getRoomCenter(enuRooms.Kitchen);
					cThisCard.udrAnimationInfo.ptEnd = getRoomCenter(enuRooms._numRooms);

					cThisCard.udrAnimationInfo.dblTravelAngle = classMath.arcTan(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
					cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);

					cThisCard.udrAnimationInfo.intMaxSteps = intCardCounter * 10 + 10;
					cThisCard.udrAnimationInfo.intStep =0;

					cThisCard.udrAnimationInfo.velTravel.X  = (int)(cThisCard.udrAnimationInfo.dblTravelDistance / (double) cThisCard.udrAnimationInfo.intMaxSteps * Math.Cos(cThisCard.udrAnimationInfo.dblTravelAngle));
					cThisCard.udrAnimationInfo.velTravel.Y = (int)(cThisCard.udrAnimationInfo.dblTravelDistance / (double)cThisCard.udrAnimationInfo.intMaxSteps * Math.Sin(cThisCard.udrAnimationInfo.dblTravelAngle));

					double dblNumRotations = intCardCounter;
					cThisCard.udrAnimationInfo.dblAngleTurning = (dblNumRotations * 2.0 * Math.PI) / (double)cThisCard.udrAnimationInfo.intMaxSteps * ((int)(rnd.NextDouble() * 1000) % 2 == 0 ? 1 : -1);
				}
			}
			Bitmap bmpTemp = new Bitmap(bmpDealAnimationBoard_Base);
			bool bolQuit = true;
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{				 
				for (int intCardCounter = 0; intCardCounter < udrAnimateDealCards.cCardsCurrentAnimation.Length; intCardCounter++)
				{
					classCard cThisCard = udrAnimateDealCards.cCardsCurrentAnimation[intCardCounter];

					if (cThisCard.udrAnimationInfo.intStep < cThisCard.udrAnimationInfo.intMaxSteps)
					{
						bolQuit = false;
						// move this card along 
						cThisCard.udrAnimationInfo.ptPos.X += cThisCard.udrAnimationInfo.velTravel.X;
						cThisCard.udrAnimationInfo.ptPos.Y += cThisCard.udrAnimationInfo.velTravel.Y;

						cThisCard.udrAnimationInfo.dblAngleFacing += cThisCard.udrAnimationInfo.dblAngleTurning;

						while (cThisCard.udrAnimationInfo.dblAngleFacing >= dblTwoPi)
							cThisCard.udrAnimationInfo.dblAngleFacing -= dblTwoPi;
						while (cThisCard.udrAnimationInfo.dblAngleFacing < 0)
							cThisCard.udrAnimationInfo.dblAngleFacing += dblTwoPi;
					}

					int intImageIndex = getImageIndex(cThisCard.udrAnimationInfo.dblAngleFacing);
					Bitmap bmp = cCardUnknown.cBmp.getImage(intImageIndex);
					Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - bmp.Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - bmp.Height / 2);
					g.DrawImage(bmp, ptTL);

					cThisCard.udrAnimationInfo.intStep++;
					if (cThisCard.udrAnimationInfo.intStep == cThisCard.udrAnimationInfo.intMaxSteps)
					{
						cThisCard.udrAnimationInfo.ptPos = cThisCard.udrAnimationInfo.ptEnd;
						cThisCard.udrAnimationInfo.dblAngleFacing = 0;
					}
				}

				
			}
			picBoard.Image = bmpTemp; picBoard.Refresh();

			if (bolQuit)
			{
				eDealMode = (enuDealCardsMode)((int)eDealMode + 1);
			}
			setDelayTimer(10);
		}

		void AnimateDealCards_JoinCards()
		{
			enuCards eWeapon = classCard.getECardFromEWeapon(udrMurder.eWeapon);
			enuCards eSuspect = classCard.getECardFromESuspect(udrMurder.eSuspect);
			enuCards eRoom = classCard.getECardFromERoom(udrMurder.eRoom);

			if (!udrAnimateDealCards.bolInit)
			{
				udrAnimateDealCards.bolInit = true;

				for (int intCardCounter = 0; intCardCounter < cCards.Length; intCardCounter++)
				{
					classCard cThisCard = cCards[intCardCounter];

					cThisCard.udrAnimationInfo.intMaxSteps = (int)(rnd.NextDouble() * 1000) % 15 + 10;
					cThisCard.udrAnimationInfo.intStep = 0;

					cThisCard.udrAnimationInfo.ptStart = cThisCard.udrAnimationInfo.ptPos;
					cThisCard.udrAnimationInfo.ptEnd = getRoomCenter(enuRooms._numRooms);

					cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
					cThisCard.udrAnimationInfo.dblTravelInitialVelocity = cThisCard.udrAnimationInfo.dblTravelDistance / cThisCard.udrAnimationInfo.intMaxSteps;

					cThisCard.udrAnimationInfo.dblTravelAngle = classMath.arcTan(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
					cThisCard.udrAnimationInfo.velTravel.X = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Cos(cThisCard.udrAnimationInfo.dblTravelAngle));
					cThisCard.udrAnimationInfo.velTravel.Y = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Sin(cThisCard.udrAnimationInfo.dblTravelAngle));


					if (cThisCard.udrAnimationInfo.dblAngleFacing > Math.PI)
						cThisCard.udrAnimationInfo.dblAngleTurning = (dblTwoPi - cThisCard.udrAnimationInfo.dblAngleFacing) / cThisCard.udrAnimationInfo.intMaxSteps;
					else
						cThisCard.udrAnimationInfo.dblAngleTurning = -cThisCard.udrAnimationInfo.dblAngleFacing / cThisCard.udrAnimationInfo.intMaxSteps;

					if (Math.Abs(cThisCard.udrAnimationInfo.dblAngleTurning) < (Math.PI / 32.0))
					{
						cThisCard.udrAnimationInfo.dblAngleTurning = 0;
						cThisCard.udrAnimationInfo.dblAngleFacing = 0;
					}
				}
			}

			Bitmap bmpTemp = new Bitmap(bmpDealAnimationBoard_Base);
			bool bolQuit = true;
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{

				for (int intCardCounter = 0; intCardCounter < cCards.Length; intCardCounter++)
				{
					classCard cThisCard = cCards[intCardCounter];

					if (cThisCard.eCardName != eWeapon
						&& cThisCard.eCardName != eSuspect
						&& cThisCard.eCardName != eRoom)
					{
						if (cThisCard.udrAnimationInfo.intStep < cThisCard.udrAnimationInfo.intMaxSteps)
						{
							bolQuit = false;
							// move this card along 
							cThisCard.udrAnimationInfo.ptPos.X += cThisCard.udrAnimationInfo.velTravel.X;
							cThisCard.udrAnimationInfo.ptPos.Y += cThisCard.udrAnimationInfo.velTravel.Y;

							cThisCard.udrAnimationInfo.dblAngleFacing += cThisCard.udrAnimationInfo.dblAngleTurning;

							while (cThisCard.udrAnimationInfo.dblAngleFacing >= dblTwoPi)
								cThisCard.udrAnimationInfo.dblAngleFacing -= dblTwoPi;
							while (cThisCard.udrAnimationInfo.dblAngleFacing < 0)
								cThisCard.udrAnimationInfo.dblAngleFacing += dblTwoPi;
						}

						int intImageIndex = getImageIndex(cThisCard.udrAnimationInfo.dblAngleFacing );
						Bitmap bmp = cCardUnknown.cBmp.getImage(intImageIndex);
						Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - bmp.Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - bmp.Height / 2);
						g.DrawImage(bmp, ptTL);

						cThisCard.udrAnimationInfo.intStep++;
						if (cThisCard.udrAnimationInfo.intStep == cThisCard.udrAnimationInfo.intMaxSteps)
						{
							cThisCard.udrAnimationInfo.ptPos = cThisCard.udrAnimationInfo.ptEnd;
							cThisCard.udrAnimationInfo.dblAngleFacing = 0;
						}
					}
				}

				AnimateDealCards_drawMurderCards(g);
			}
			picBoard.Image = bmpTemp; picBoard.Refresh();
			
			if (bolQuit)
			{
				eDealMode = (enuDealCardsMode)((int)eDealMode + 1);
			}
			setDelayTimer(100);
		}

		int getImageIndex(double dblAngle) {return  (int)(dblAngle/ (Math.PI / 8.0)) % 16; }

		void AnimateDealCards_ShuffleCards()
		{
			if (!udrAnimateDealCards.bolInit)
			{
				udrAnimateDealCards.bolInit = true;

				for (int intCardCounter = 0; intCardCounter < cCards.Length; intCardCounter++)
				{
					cCards[intCardCounter].udrAnimationInfo.intStep = cCards[intCardCounter].udrAnimationInfo.intMaxSteps;
					cCards[intCardCounter].udrAnimationInfo.ptStart = cCards[intCardCounter].udrAnimationInfo.ptPos;
				}

				udrAnimateDealCards.udrShuffle.ptCentralShufflePos = getRoomCenter(enuRooms._numRooms);
				udrAnimateDealCards.udrShuffle.intMaxDistance = (int)(bmpBoard.Width * .4);
				udrAnimateDealCards.udrShuffle.intTimeShuffled = 0;
				udrAnimateDealCards.udrShuffle.intMaxShuffle = 50;
			}

			Bitmap bmpTemp = new Bitmap(bmpDealAnimationBoard_Base);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				enuCards eWeapon = classCard.getECardFromEWeapon(udrMurder.eWeapon);
				enuCards eSuspect = classCard.getECardFromESuspect(udrMurder.eSuspect);
				enuCards eRoom = classCard.getECardFromERoom(udrMurder.eRoom);

				AnimateDealCards_drawMurderCards(g);

				for (int intCardCounter = 0; intCardCounter < cCards.Length; intCardCounter++)
				{
					classCard cThisCard = cCards[intCardCounter];

					if (cThisCard.eCardName != eWeapon
						&& cThisCard.eCardName != eSuspect
						&& cThisCard.eCardName != eRoom)
					{
						// prepare this card for next move
						if (cThisCard.udrAnimationInfo.intStep >= cThisCard.udrAnimationInfo.intMaxSteps)
						{
							int intRndDistance = (int)(rnd.NextDouble() * 10000) % udrAnimateDealCards.udrShuffle.intMaxDistance;
							double dblRndRad = rnd.NextDouble() * Math.PI * 2.0;
							cThisCard.udrAnimationInfo.intMaxSteps = (int)(rnd.NextDouble() * 1000) % 5 + 5;
							cThisCard.udrAnimationInfo.intStep = 0;

							cThisCard.udrAnimationInfo.ptStart = cThisCard.udrAnimationInfo.ptPos;
							cThisCard.udrAnimationInfo.ptEnd
								= new Point(udrAnimateDealCards.udrShuffle.ptCentralShufflePos.X + (int)(intRndDistance * Math.Cos(dblRndRad)),
											udrAnimateDealCards.udrShuffle.ptCentralShufflePos.Y + (int)(intRndDistance * Math.Sin(dblRndRad)));

							cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
							cThisCard.udrAnimationInfo.dblTravelInitialVelocity = cThisCard.udrAnimationInfo.dblTravelDistance / cThisCard.udrAnimationInfo.intMaxSteps;

							cThisCard.udrAnimationInfo.dblTravelAngle = classMath.arcTan(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
							cThisCard.udrAnimationInfo.velTravel.X = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Cos(cThisCard.udrAnimationInfo.dblTravelAngle));
							cThisCard.udrAnimationInfo.velTravel.Y = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Sin(cThisCard.udrAnimationInfo.dblTravelAngle));

							double dblMaxAngularVelocity = Math.PI * .2;
							cThisCard.udrAnimationInfo.dblAngleTurning = rnd.NextDouble() * 2.0 * dblMaxAngularVelocity - dblMaxAngularVelocity;
						}

						// move this card along 
						cThisCard.udrAnimationInfo.ptPos.X += cThisCard.udrAnimationInfo.velTravel.X;
						cThisCard.udrAnimationInfo.ptPos.Y += cThisCard.udrAnimationInfo.velTravel.Y;

						cThisCard.udrAnimationInfo.dblAngleFacing += cThisCard.udrAnimationInfo.dblAngleTurning;

						while (cThisCard.udrAnimationInfo.dblAngleFacing >= dblTwoPi)
							cThisCard.udrAnimationInfo.dblAngleFacing -= dblTwoPi;
						while (cThisCard.udrAnimationInfo.dblAngleFacing < 0)
							cThisCard.udrAnimationInfo.dblAngleFacing += dblTwoPi;

						int intImageIndex = getImageIndex(cThisCard.udrAnimationInfo.dblAngleFacing);
						Bitmap bmp = cCardUnknown.cBmp.getImage(intImageIndex);
						Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - bmp.Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - bmp.Height / 2);
						g.DrawImage(bmp, ptTL);

						cThisCard.udrAnimationInfo.intStep++;
					}
				}

			}
			picBoard.Image = bmpTemp; picBoard.Refresh();

			udrAnimateDealCards.udrShuffle.intTimeShuffled++;
			if (udrAnimateDealCards.udrShuffle.intTimeShuffled > udrAnimateDealCards.udrShuffle.intMaxShuffle)
			{
				eDealMode = (enuDealCardsMode)((int)eDealMode + 1);
			}
			setDelayTimer(100);
		}

		void AnimateDealCards_DealToPlayers()
		{
			if (udrAnimateDealCards.intAnimationCounter % 8 == 0 && udrAnimateDealCards.strCards.Length > 0)
			{
				// throw new card across the table				
				int intNumCardsLeft = udrAnimateDealCards.strCards.Length / 2;

				/// first card out is 6 + 6 + 9 = 21 - 3 = 18
				enuSuspects eSuspectReceivingCard = (enuSuspects)((18 - intNumCardsLeft)%(int)enuSuspects._numSuspects);

				string strThisCard = udrAnimateDealCards.strCards.Substring(0, 2);
				udrAnimateDealCards.strCards = udrAnimateDealCards.strCards.Substring(2);
				enuCards eCard = (enuCards)Convert.ToInt16(strThisCard);
				Array.Resize<classCard>(ref udrAnimateDealCards.cCardsCurrentAnimation, udrAnimateDealCards.cCardsCurrentAnimation.Length + 1);
				udrAnimateDealCards.cCardsCurrentAnimation[udrAnimateDealCards.cCardsCurrentAnimation.Length - 1] = cCards[(int)eCard];
				classCard cThisCard = udrAnimateDealCards.cCardsCurrentAnimation[udrAnimateDealCards.cCardsCurrentAnimation.Length - 1];
				cSuspects[(int)eSuspectReceivingCard].receiveCard(ref cThisCard);
				Point ptEnd = new Point(1, 1);
				int intEdge = 20;
				switch (eSuspectReceivingCard)
				{
					case enuSuspects.MissScarlet:
						ptEnd = new Point((int)(bmpBoard.Width * .6), intEdge );
						break;

					case enuSuspects.ColMustard:
						ptEnd = new Point((int)(bmpBoard.Width - intEdge ), (int)(bmpBoard.Height *.3));
						break;

					case enuSuspects.MrsWhite:
						ptEnd = new Point((int)(bmpBoard.Width *.7 ), (int)(bmpBoard.Height - intEdge));
						break;

					case enuSuspects.RevGreen:
						ptEnd = new Point((int)(bmpBoard.Width * .3), (int)(bmpBoard.Height - intEdge));
						break;

					case enuSuspects.MrsPeacock:
						ptEnd = new Point(intEdge, (int)(bmpBoard.Height *.7));
						break;

					case enuSuspects.ProfPlum:
						ptEnd = new Point(intEdge, (int)(bmpBoard.Height * .3));
						break;
				}

				cThisCard.cSuspect = cSuspects[(int)eSuspectReceivingCard];

				int intRangeError = (int)(bmpBoard.Height * .04);
				ptEnd = new Point((int)(ptEnd.X + (int)(rnd.NextDouble() * 1000) % intRangeError * Math.Cos(rnd.NextDouble() * Math.PI * 2)),
								  (int)(ptEnd.Y + (int)(rnd.NextDouble() * 1000) % intRangeError * Math.Sin(rnd.NextDouble() * Math.PI * 2)));

				cThisCard.udrAnimationInfo.ptStart = cThisCard.udrAnimationInfo.ptPos;
				cThisCard.udrAnimationInfo.ptEnd = ptEnd;
				cThisCard.udrAnimationInfo.dblTravelAcceleration = -5;
				cThisCard.udrAnimationInfo.dblTravelAngle = classMath.arcTan(ptEnd, cThisCard.udrAnimationInfo.ptStart);
				cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(ptEnd, cThisCard.udrAnimationInfo.ptStart);
				cThisCard.udrAnimationInfo.intMaxSteps = (int)Math.Ceiling(Math.Sqrt(-2.0 * cThisCard.udrAnimationInfo.dblTravelDistance / cThisCard.udrAnimationInfo.dblTravelAcceleration));
				cThisCard.udrAnimationInfo.dblTravelInitialVelocity = -cThisCard.udrAnimationInfo.dblTravelAcceleration * cThisCard.udrAnimationInfo.intMaxSteps;
				cThisCard.udrAnimationInfo.dblAngleTurning = rnd.NextDouble() * Math.PI * (1.0 / 8.0);
				cThisCard.udrAnimationInfo.intStep = 0;
				cThisCard.udrAnimationInfo.dblAngleTurningAttenuation = 0.95;
			}

			udrAnimateDealCards.intAnimationCounter++;

			bmpDealAnimationBoard = new Bitmap(bmpDealAnimationBoard_Base);
			bool bolEndSortCards = true;

			using (Graphics g = Graphics.FromImage(bmpDealAnimationBoard))
			{
				if (udrAnimateDealCards.strCards.Length > 0)
				{ // if there are still cards left in the center stack -> draw center stack
					Bitmap bmp = cCardUnknown.cBmp.getImage(0);
					Point ptTL = new Point(getRoomCenter(enuRooms._numRooms).X - bmp.Width / 2, getRoomCenter(enuRooms._numRooms).Y - bmp.Height / 2);
					g.DrawImage(bmp, ptTL);
				}
				
				// draw murder cards
				Bitmap bmpMurderCards = cCardUnknown.cBmp.getImage(0);
				Point ptTLMurderCards = new Point(getRoomCenter(enuRooms.Kitchen).X - bmpMurderCards.Width / 2, getRoomCenter(enuRooms.Kitchen).Y - bmpMurderCards.Height / 2);
				g.DrawImage(bmpMurderCards, ptTLMurderCards);


				for (int intCardCounter = 0; intCardCounter < udrAnimateDealCards.cCardsCurrentAnimation.Length; intCardCounter++)
				{
					classCard cThisCard = udrAnimateDealCards.cCardsCurrentAnimation[intCardCounter];
					if (cThisCard.udrAnimationInfo.intStep < cThisCard.udrAnimationInfo.intMaxSteps)
					{
						bolEndSortCards = false;

						cThisCard.udrAnimationInfo.intStep++;

						double dblDistanceTravelled = cThisCard.udrAnimationInfo.dblTravelInitialVelocity * cThisCard.udrAnimationInfo.intStep + .5 * cThisCard.udrAnimationInfo.dblTravelAcceleration * cThisCard.udrAnimationInfo.intStep * cThisCard.udrAnimationInfo.intStep;
						cThisCard.udrAnimationInfo.ptPos = new Point(cThisCard.udrAnimationInfo.ptStart.X + (int)(dblDistanceTravelled * Math.Cos(cThisCard.udrAnimationInfo.dblTravelAngle)),
																	 cThisCard.udrAnimationInfo.ptStart.Y + (int)(dblDistanceTravelled * Math.Sin(cThisCard.udrAnimationInfo.dblTravelAngle)));

						cThisCard.udrAnimationInfo.dblAngleFacing += cThisCard.udrAnimationInfo.dblAngleTurning;

						while (cThisCard.udrAnimationInfo.dblAngleFacing >= dblTwoPi)
							cThisCard.udrAnimationInfo.dblAngleFacing -= dblTwoPi;
						while (cThisCard.udrAnimationInfo.dblAngleFacing < 0)
							cThisCard.udrAnimationInfo.dblAngleFacing += dblTwoPi;

						cThisCard.udrAnimationInfo.dblAngleTurning *= cThisCard.udrAnimationInfo.dblAngleTurningAttenuation;
					}

					int intImageIndex = getImageIndex(cThisCard.udrAnimationInfo.dblAngleFacing);
					Bitmap bmp = cThisCard.cSuspect.bolPlayerControlled ? cThisCard.cBmp.getImage (intImageIndex): cCardUnknown.cBmp.getImage(intImageIndex);
					Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - bmp.Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - bmp.Height / 2);
					g.DrawImage(bmp, ptTL);
				}

				
			}

			picBoard.Image = bmpDealAnimationBoard; picBoard.Refresh();
			if (bolEndSortCards && udrAnimateDealCards.strCards.Length == 0)
			{
				eDealMode  = (enuDealCardsMode)((int)eDealMode + 1);
				udrAnimateDealCards.intAnimationCounter = 0;
			}
			setDelayTimer(10);
		}

		void AnimateDealCards_SelectCard(enuCardType eTypeCard)
		{
			classCard cThisCard = cCards[(int)classCard.getECardFromERoom(udrMurder.eRoom)];
			classCard[] cCardsArray = udrAnimateDealCards.udrTypeOrder.cRooms;

			switch (eTypeCard)
			{
				case enuCardType.Suspect:
					cCardsArray = udrAnimateDealCards.udrTypeOrder.cSuspects;
					cThisCard = cCards[(int)classCard.getECardFromESuspect(udrMurder.eSuspect)];
					break;

				case enuCardType.weapon:
					cCardsArray = udrAnimateDealCards.udrTypeOrder.cWeapons;
					cThisCard = cCards[(int)classCard.getECardFromEWeapon(udrMurder.eWeapon)];
					break;
			}

			if (!udrAnimateDealCards.bolInit)
			{
				for (int intCardCounter = 0; intCardCounter < cCardsArray.Length; intCardCounter++)
				{
					cCardsArray[intCardCounter].udrAnimationInfo.ptStart = cCardsArray[intCardCounter].udrAnimationInfo.ptPos;
					cCardsArray[intCardCounter].udrAnimationInfo.ptEnd = cCardsArray[intCardCounter].udrAnimationInfo.ptPos;
					cCardsArray[intCardCounter].udrAnimationInfo.dblAngleFacing = 0;
				}

				udrAnimateDealCards.bolInit = true;
				cThisCard.udrAnimationInfo.ptStart = cThisCard.udrAnimationInfo.ptPos;
				cThisCard.udrAnimationInfo.ptEnd = getRoomCenter(enuRooms.Kitchen);

				cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
				
				cThisCard.udrAnimationInfo.intMaxSteps = (int)(cThisCard.udrAnimationInfo.dblTravelDistance / 40);
				cThisCard.udrAnimationInfo.intStep = 0;

				cThisCard.udrAnimationInfo.dblTravelInitialVelocity = cThisCard.udrAnimationInfo.dblTravelDistance / cThisCard.udrAnimationInfo.intMaxSteps;

				cThisCard.udrAnimationInfo.dblTravelAngle = classMath.arcTan(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
				cThisCard.udrAnimationInfo.velTravel.X = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Cos(cThisCard.udrAnimationInfo.dblTravelAngle));
				cThisCard.udrAnimationInfo.velTravel.Y = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Sin(cThisCard.udrAnimationInfo.dblTravelAngle));

			}

			Bitmap bmpTemp = new Bitmap(bmpDealAnimationBoard_Base);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				if (eDealMode > enuDealCardsMode.selectWeapon)
					AnimateDealCards_drawMurderCards(g);
				
				// move this card along 
				cThisCard.udrAnimationInfo.ptPos.X += cThisCard.udrAnimationInfo.velTravel.X;
				cThisCard.udrAnimationInfo.ptPos.Y += cThisCard.udrAnimationInfo.velTravel.Y;

				cThisCard.udrAnimationInfo.intStep++;

				for (int intCardCounter = 0; intCardCounter < cCardsArray.Length; intCardCounter++)
				{
					int intImageIndex = getImageIndex(cCardsArray[intCardCounter].udrAnimationInfo.dblAngleFacing);
					Bitmap bmp = cCardUnknown.cBmp.getImage(intImageIndex);
					Point ptTL = new Point(cCardsArray[intCardCounter].udrAnimationInfo.ptPos.X - bmp.Width / 2, cCardsArray[intCardCounter].udrAnimationInfo.ptPos.Y - bmp.Height / 2);
					g.DrawImage(bmp, ptTL);
				}
				
			}

			picBoard.Image = bmpTemp; picBoard.Refresh();

			if (cThisCard.udrAnimationInfo.intStep >= cThisCard.udrAnimationInfo.intMaxSteps)
			{
				eDealMode = (enuDealCardsMode)((int)eDealMode + 1);
			}
			setDelayTimer(10);
		}

		void AnimateDealCards_drawMurderCards(Graphics g)
		{
			Point ptKitchen = getRoomCenter(enuRooms.Kitchen);
			Bitmap bmpCard = cCardUnknown.cBmp.getImage(0);
			Point ptTL = new Point(ptKitchen.X - bmpCard.Width / 2, ptKitchen.Y - bmpCard.Height / 2);
			g.DrawImage(bmpCard, ptTL);
		}

		void AnimateDealCards_Shuffle(enuCardType eTypeCard)
		{
			if (!udrAnimateDealCards.bolInit)
			{
				udrAnimateDealCards.bolInit = true;
				udrAnimateDealCards.intAnimationCounter = 0;

				classCard[] cCardsInitArray = udrAnimateDealCards.udrTypeOrder.cRooms;
				switch (eTypeCard)
				{
					case enuCardType.Suspect:
						cCardsInitArray = udrAnimateDealCards.udrTypeOrder.cSuspects;
						break;

					case enuCardType.weapon:
						cCardsInitArray = udrAnimateDealCards.udrTypeOrder.cWeapons;
						break;
				}

				for (int intCardCounter = 0; intCardCounter < cCardsInitArray.Length; intCardCounter++)
				{
					cCardsInitArray[intCardCounter].udrAnimationInfo.intStep = cCardsInitArray[intCardCounter].udrAnimationInfo.intMaxSteps;
					cCardsInitArray[intCardCounter].udrAnimationInfo.ptStart = cCardsInitArray[intCardCounter].udrAnimationInfo.ptPos;
					cCardsInitArray[intCardCounter].udrAnimationInfo.dblAngleFacing = 0;
				}

				udrAnimateDealCards.udrShuffle.ptCentralShufflePos = cCardsInitArray[cCardsInitArray.Length / 2].udrAnimationInfo.ptPos;
				udrAnimateDealCards.udrShuffle.intMaxDistance = (int)(bmpBoard.Width * .3);
				udrAnimateDealCards.udrShuffle.intTimeShuffled = 0;
				udrAnimateDealCards.udrShuffle.intMaxShuffle = 40;
			}

			classCard[] cCardsArray = udrAnimateDealCards.udrTypeOrder.cRooms;
			switch (eTypeCard)
			{
				case enuCardType.Suspect:
					cCardsArray = udrAnimateDealCards.udrTypeOrder.cSuspects;
					break;

				case enuCardType.weapon:
					cCardsArray = udrAnimateDealCards.udrTypeOrder.cWeapons;
					break;
			}

			Bitmap bmpTemp = new Bitmap(bmpDealAnimationBoard_Base);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				if (eDealMode > enuDealCardsMode.selectWeapon)
					AnimateDealCards_drawMurderCards(g);
				
				for (int intCardCounter = 0; intCardCounter < cCardsArray.Length; intCardCounter++)
				{
					classCard cThisCard = cCardsArray[intCardCounter];

					// prepare this card for next move
					if (cThisCard.udrAnimationInfo.intStep >= cThisCard.udrAnimationInfo.intMaxSteps)
					{
						int intRndDistance = (int)(rnd.NextDouble() * 10000) % udrAnimateDealCards.udrShuffle.intMaxDistance;
						double dblRndRad = rnd.NextDouble() * Math.PI * 2.0;
						cThisCard.udrAnimationInfo.intMaxSteps = (int)(rnd.NextDouble() * 1000) % 10 + 5;
						cThisCard.udrAnimationInfo.intStep = 0;

						cThisCard.udrAnimationInfo.ptStart = cThisCard.udrAnimationInfo.ptPos;
						cThisCard.udrAnimationInfo.ptEnd
							= new Point(udrAnimateDealCards.udrShuffle.ptCentralShufflePos.X + (int)(intRndDistance * Math.Cos(dblRndRad)),
										udrAnimateDealCards.udrShuffle.ptCentralShufflePos.Y + (int)(intRndDistance * Math.Sin(dblRndRad)));

						cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
						cThisCard.udrAnimationInfo.dblTravelInitialVelocity = cThisCard.udrAnimationInfo.dblTravelDistance / cThisCard.udrAnimationInfo.intMaxSteps;

						cThisCard.udrAnimationInfo.dblTravelAngle = classMath.arcTan(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
						cThisCard.udrAnimationInfo.velTravel.X = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Cos(cThisCard.udrAnimationInfo.dblTravelAngle));
						cThisCard.udrAnimationInfo.velTravel.Y = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Sin(cThisCard.udrAnimationInfo.dblTravelAngle));

						double dblMaxAngularVelocity = Math.PI * .02;
						cThisCard.udrAnimationInfo.dblAngleTurning = rnd.NextDouble() * 2.0 * dblMaxAngularVelocity - dblMaxAngularVelocity;
						cThisCard.udrAnimationInfo.dblAngleFacing = 0;
					}

					// move this card along 
					cThisCard.udrAnimationInfo.ptPos.X += cThisCard.udrAnimationInfo.velTravel.X;
					cThisCard.udrAnimationInfo.ptPos.Y += cThisCard.udrAnimationInfo.velTravel.Y;

					cThisCard.udrAnimationInfo.dblAngleFacing += cThisCard.udrAnimationInfo.dblAngleTurning;

					while (cThisCard.udrAnimationInfo.dblAngleFacing >= dblTwoPi)
						cThisCard.udrAnimationInfo.dblAngleFacing -= dblTwoPi;
					while (cThisCard.udrAnimationInfo.dblAngleFacing < 0)
						cThisCard.udrAnimationInfo.dblAngleFacing += dblTwoPi;

					int intImageIndex = getImageIndex(cThisCard.udrAnimationInfo.dblAngleFacing);
					Bitmap bmp = cCardUnknown.cBmp.getImage(intImageIndex);
					Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - bmp.Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - bmp.Height / 2);
					g.DrawImage(bmp, ptTL);

					cThisCard.udrAnimationInfo.intStep++;
				}
				
			}
			picBoard.Image = bmpTemp; picBoard.Refresh();

			// randomly swap two cards

			if (udrAnimateDealCards.udrShuffle.intTimeShuffled > 10)
			{
				int intRndA = 0, intRndB = 0;
				while (intRndA == intRndB)
				{
					intRndB = (int)(rnd.NextDouble() * 1000) % cCardsArray.Length;
					intRndA = (int)(rnd.NextDouble() * 1000) % cCardsArray.Length;
				}

				classCard cTemp = cCardsArray[intRndA];
				cCardsArray[intRndA] = cCardsArray[intRndB];
				cCardsArray[intRndB] = cTemp;
			}

			udrAnimateDealCards.udrShuffle.intTimeShuffled++;
			if (udrAnimateDealCards.udrShuffle.intTimeShuffled > udrAnimateDealCards.udrShuffle.intMaxShuffle)
			{
				eDealMode = (enuDealCardsMode)((int)eDealMode + 1);
			}
			setDelayTimer(10);
		}

		void AnimateDealCards_GatherType(Point ptDestination, enuCardType eCardType, bool bolFaceUp)
		{
			classCard[] cCardsArray = udrAnimateDealCards.udrTypeOrder.cRooms;
			classCard cCardException = null;

			switch (eCardType)
			{
				case enuCardType.room:
					if (eDealMode > enuDealCardsMode.selectRoom)
						cCardException = cCards[(int)classCard.getECardFromERoom(udrMurder.eRoom)];
					break;

				case enuCardType.Suspect:
					cCardsArray = udrAnimateDealCards.udrTypeOrder.cSuspects;
					if (eDealMode > enuDealCardsMode.selectSuspect)
						cCardException = cCards[(int)classCard.getECardFromESuspect(udrMurder.eSuspect)];
					break;

				case enuCardType.weapon:
					cCardsArray = udrAnimateDealCards.udrTypeOrder.cWeapons;
					if (eDealMode > enuDealCardsMode.selectWeapon)
						cCardException = cCards[(int)classCard.getECardFromEWeapon(udrMurder.eWeapon)];
					break;
			}

			if (!udrAnimateDealCards.bolInit)
			{
				udrAnimateDealCards.bolInit = true;

				for (int intCardCounter = 0; intCardCounter < cCardsArray.Length; intCardCounter++)
				{
					classCard cThisCard = cCardsArray[intCardCounter];
					if (cThisCard != cCardException)
					{
						cThisCard.udrAnimationInfo.ptStart = cThisCard.udrAnimationInfo.ptPos;
						cThisCard.udrAnimationInfo.ptEnd = ptDestination;
						int intMaxSteps = (int)(rnd.NextDouble() * 1000) % 7 + 7;
						cThisCard.udrAnimationInfo.intMaxSteps = intMaxSteps;
						cThisCard.udrAnimationInfo.intStep = 0;

						if (cThisCard.udrAnimationInfo.dblAngleFacing > Math.PI)
							cThisCard.udrAnimationInfo.dblAngleTurning = (dblTwoPi - cThisCard.udrAnimationInfo.dblAngleFacing) / cThisCard.udrAnimationInfo.intMaxSteps;
						else
							cThisCard.udrAnimationInfo.dblAngleTurning = -cThisCard.udrAnimationInfo.dblAngleFacing / cThisCard.udrAnimationInfo.intMaxSteps;

						if (Math.Abs(cThisCard.udrAnimationInfo.dblAngleTurning) < (Math.PI / 32.0))
						{
							cThisCard.udrAnimationInfo.dblAngleTurning = 0;
							cThisCard.udrAnimationInfo.dblAngleFacing = 0;
						}

						cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
						cThisCard.udrAnimationInfo.dblTravelAngle = classMath.arcTan(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
						cThisCard.udrAnimationInfo.dblTravelInitialVelocity = cThisCard.udrAnimationInfo.dblTravelDistance / cThisCard.udrAnimationInfo.intMaxSteps;
						cThisCard.udrAnimationInfo.velTravel.X = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Cos(cThisCard.udrAnimationInfo.dblTravelAngle));
						cThisCard.udrAnimationInfo.velTravel.Y = (int)(cThisCard.udrAnimationInfo.dblTravelInitialVelocity * Math.Sin(cThisCard.udrAnimationInfo.dblTravelAngle));
					}
				}
			}

			Bitmap bmpTemp = new Bitmap(bmpDealAnimationBoard_Base);
			bool bolQuit = true;
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				for (int intCardCounter = 0; intCardCounter < cCardsArray.Length; intCardCounter++)
				{
					classCard cThisCard = cCardsArray[intCardCounter];
					if (cThisCard != cCardException)
					{
						cThisCard.udrAnimationInfo.ptPos.X += cThisCard.udrAnimationInfo.velTravel.X;
						cThisCard.udrAnimationInfo.ptPos.Y += cThisCard.udrAnimationInfo.velTravel.Y;

						cThisCard.udrAnimationInfo.dblAngleFacing += cThisCard.udrAnimationInfo.dblAngleTurning;

						while (cThisCard.udrAnimationInfo.dblAngleFacing >= dblTwoPi)
							cThisCard.udrAnimationInfo.dblAngleFacing -= dblTwoPi;
						while (cThisCard.udrAnimationInfo.dblAngleFacing < 0)
							cThisCard.udrAnimationInfo.dblAngleFacing += dblTwoPi;

						cThisCard.udrAnimationInfo.intStep++;
						int intImageIndex = getImageIndex(cThisCard.udrAnimationInfo.dblAngleFacing);

						if (cThisCard.udrAnimationInfo.intStep >= cThisCard.udrAnimationInfo.intMaxSteps)
						{
							cThisCard.udrAnimationInfo.ptPos = cThisCard.udrAnimationInfo.ptEnd;
							intImageIndex = 0;
						}
						else
							bolQuit = false;

						Bitmap bmp = cThisCard.cBmp.getImage(intImageIndex);

						if (!bolFaceUp)
							bmp = cCardUnknown.cBmp.getImage(intImageIndex);

						Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - bmp.Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - bmp.Height / 2);
						g.DrawImage(bmp, ptTL);
					}
				}
				if (eDealMode > enuDealCardsMode.selectWeapon)
					AnimateDealCards_drawMurderCards(g);
			}
			picBoard.Image = bmpTemp; picBoard.Refresh();

			if (bolQuit)
				eDealMode = (enuDealCardsMode)((int)eDealMode + 1);

			setDelayTimer(100);
		}

		/// <summary>
		/// flip the weapon cards from a face up state to a face down one, moving from left-to-right
		/// </summary>
		void AnimateDealCards_FlipCardsUtoD_DirR(enuCardType eTypeCard)
		{
			classCard[] cAnimate = udrAnimateDealCards.udrTypeOrder.cRooms;

			switch (eTypeCard)
			{
				case enuCardType.Suspect:
					cAnimate = udrAnimateDealCards.udrTypeOrder.cSuspects;
					break;

				case enuCardType.weapon:
					cAnimate = udrAnimateDealCards.udrTypeOrder.cWeapons;
					break;
			}

			int intHalfCardWidth = cCards[0].cBmp.getImage(0).Width / 2;
			int intCardHeight = cCards[0].cBmp.getImage(0).Height;
			double dblCardWidth = cCards[0].cBmp.getImage(0).Width;
			double dblK = 0;

			if (!udrAnimateDealCards.bolInit)
			{
				for (int intCardCounter = 0; intCardCounter < cAnimate.Length; intCardCounter++)
				{
					classCard cThisCard = cAnimate[intCardCounter];
					// record the edge of the card which remains in contact with the table in ptStart
					cThisCard.udrAnimationInfo.ptStart = new Point(cThisCard.udrAnimationInfo.ptPos.X + intHalfCardWidth, cThisCard.udrAnimationInfo.ptPos.Y);
					cThisCard.udrAnimationInfo.ptEnd = new Point(cThisCard.udrAnimationInfo.ptStart.X + cThisCard.cBmp.getImage(0).Width, cThisCard.udrAnimationInfo.ptStart.Y);
				}

				udrAnimateDealCards.intAnimationCounter = 0;
				udrAnimateDealCards.bolInit = true;
				setDelayTimer(100);
				return;
			}

			int intMaxSteps = 30;
			udrAnimateDealCards.intAnimationCounter++;
			if (udrAnimateDealCards.intAnimationCounter >= intMaxSteps)
			{
				for (int intCardCounter = 0; intCardCounter < cAnimate.Length; intCardCounter++)
				{
					classCard cThisCard = cAnimate[intCardCounter];
					// record the edge of the card which remains in contact with the table in ptStart
					cThisCard.udrAnimationInfo.ptPos.X += (int)dblCardWidth;
				}


				udrAnimateDealCards.intAnimationCounter = 0;
				eDealMode = (enuDealCardsMode)((int)eDealMode + 1);
				setDelayTimer(100);
				return;
			}

			double dblTotalDistance = 2 * dblCardWidth + cAnimate[cAnimate.Length - 1].udrAnimationInfo.ptStart.X - cAnimate[0].udrAnimationInfo.ptStart.X;
			double dblMPivot = 0;
			int intPivotPoint = (int)(((double)(udrAnimateDealCards.intAnimationCounter) / (double)(intMaxSteps)) * dblTotalDistance);
			int intLeftMostPoint = cAnimate[0].udrAnimationInfo.ptStart.X - (int)dblCardWidth;
			int intPivotCardIndex = cAnimate.Length;
			Point ptTLImage;
			Point ptTLPivotCard = new Point(0, 0);

			// select Pivot Card
			for (int intCardCounter = 0; intCardCounter < cAnimate.Length; intCardCounter++)
			{
				if (intLeftMostPoint + intPivotPoint < cAnimate[intCardCounter].udrAnimationInfo.ptStart.X)
				{
					intPivotCardIndex = intCardCounter;
					break;
				}
			}

			Bitmap bmpTemp = new Bitmap(bmpDealAnimationBoard_Base);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				if (intPivotCardIndex < cAnimate.Length)
				{
					// calculate size and draw location of pivot card
					int intLeftPivotCard = intPivotPoint;
					classCard cPivotCard = cAnimate[intPivotCardIndex];
					int intRightPivotCard = cPivotCard.udrAnimationInfo.ptStart.X;
					ptTLImage = new Point(intLeftPivotCard + intLeftMostPoint, cPivotCard.udrAnimationInfo.ptPos.Y - cPivotCard.cBmp.getImage(0).Height / 2);
					int intImageWidth = cPivotCard.udrAnimationInfo.ptStart.X - ptTLImage.X;

					Bitmap bmpPivotCard = new Bitmap(cPivotCard.cBmp.getImage(0), intImageWidth, intCardHeight);
					g.DrawImage(bmpPivotCard, ptTLImage);

					if (intPivotCardIndex < cAnimate.Length - 1)
					{
						// calculate contact point with card to the right
						/// view cards side-ways for calculations
						/// form two lines of bottom edge of pivot card and card to the right of it (pivot cards leans towards the left w/ right-neighbor card pressed onto it)
						/// where card to the right is leaning on pivot card
						/// both lines are of equal lengths and share a common fixed y-value for their lowest points(table)
						/// TL point of pivot card must be calculated given width of card (hypotenuse) & width of image (distance on x-plane away from pivot card's base point)
						/// set common Y value = 0(table top)
						/// set pivot card's known base point x value = 0(pivot card is in contact with that table in the system's origin)
						/// forming a right-angle triangle with X-axis, Card's edge & imaginary vertical line
						/// TL point of pivot card can be found
						/// c^2 = a^2 + b^2 -> a = sqrt(c^2-b^2), 
						/// here Y point of TL is sqrt(CardWidth^2 - CardImageWidth^2)
						/// and  X point of TL is -CardImageWidth
						ptTLPivotCard = new Point(-bmpPivotCard.Width, (int)Math.Sqrt(Math.Pow(dblCardWidth, 2) - Math.Pow(bmpPivotCard.Width, 2)));
						dblMPivot = (double)ptTLPivotCard.Y / (double)ptTLPivotCard.X;

						/// using the line equation y = Mx + B for both lines 
						/// we can calculate the point where both lines are in contact (x, y)
						/// by using the two line equations separately
						/// y = M1x + B1 and also y = M2x + B2 
						/// where (x,y) is common to both lines 
						/// we can drop an imaginary vertical line and form a right-angled triangle 
						/// knowing the hypotenuse is equal to C = card width
						/// and the adjacent side alone the x-axis = (x - k) where K is the distance between cards
						/// then solving the pythagorean triangle C^2 = A^2 + B^2 = (x-k)^2 + y^2 for y
						/// we get	y = sqrt(c^2 + 2xk - x^2 -k^2) 
						///			y = M1x + B1
						/// putting these two equations together gives us the quadratic
						/// x^2(M1^2 + 1) + x(-2k) + (K^2 - C^2) = 0						

						// constant distance between cards K
						Point ptTLPreviousCard = ptTLPivotCard;

						// calculate size and draw locations of all cards to the right of pivot card
						for (int intCardCounter = intPivotCardIndex + 1; intCardCounter < cAnimate.Length; intCardCounter++)
						{
							classCard cThisCard = cAnimate[intCardCounter];
							// solve for slope of pivot-card = dY/dX
							double dblM1 = (double)ptTLPreviousCard.Y / (double)ptTLPreviousCard.X;
							dblK = (cAnimate[intCardCounter].udrAnimationInfo.ptStart.X - cAnimate[intCardCounter - 1].udrAnimationInfo.ptStart.X);

							// variables of quadratic equation
							double dbl_A = (dblM1 * dblM1 + 1.0);
							double dbl_B = -2 * dblK;
							double dbl_C = dblK * dblK - dblCardWidth * dblCardWidth;

							double dblX_Plus = (-dbl_B + Math.Sqrt(dbl_B * dbl_B - 4 * dbl_A * dbl_C)) / (2 * dbl_A);
							double dblX_Minus = (-dbl_B - Math.Sqrt(dbl_B * dbl_B - 4 * dbl_A * dbl_C)) / (2 * dbl_A);

							Point ptCommon = new Point(0, 0);
							int intWidthImage = (int)dblCardWidth;

							if (dblX_Minus > ptTLPreviousCard.X - 1 && dblX_Minus < 0)
							{
								double dblX = dblX_Minus - dblK;
								ptCommon = new Point((int)dblX, (int)(dblX_Minus * dblM1));
								intWidthImage = (int)(dblK - dblX_Minus);
							}
							else if (dblX_Plus > ptTLPreviousCard.X - 1 && dblX_Plus < 0)
							{
								double dblX = dblX_Plus - dblK;
								ptCommon = new Point((int)dblX, (int)(dblX_Plus * dblM1));
								intWidthImage = (int)(dblK - dblX_Plus);
							}
							else
							{
								ptCommon = new Point(cThisCard.udrAnimationInfo.ptStart.X - (int)dblCardWidth, 0);
							}

							/// previous card's base edge (ptStart.x + intHalfCard) is on the origin
							if (ptCommon.X == 0)
								ptCommon.X = 1;

							Bitmap bmpThisCardImage = new Bitmap(cThisCard.cBmp.getImage(0), intWidthImage, intCardHeight);
							ptTLImage = new Point(cThisCard.udrAnimationInfo.ptStart.X - intWidthImage, cThisCard.udrAnimationInfo.ptStart.Y - intCardHeight / 2);
							g.DrawImage(bmpThisCardImage, ptTLImage);

							ptTLPreviousCard = ptCommon;
						}
					}
				}

				if (intPivotCardIndex > 0)
				{ // calculate size and draw locations of all cards to the left of pivot card
					Point ptTRPreviousCard = new Point(0, 0);
					Bitmap bmpCardUnknown;
					int intWidthImage;

					for (int intCardCounter = intPivotCardIndex - 1; intCardCounter >= 0; intCardCounter--)
					{
						classCard cThisCard = cAnimate[intCardCounter];

						if (intCardCounter == cAnimate.Length - 1)
						{
							// all cards are faced down -> use Pivot point as x of TR corner for this right-most card
							intWidthImage = intLeftMostPoint + intPivotPoint - (cThisCard.udrAnimationInfo.ptStart.X);
							ptTLImage = new Point(cThisCard.udrAnimationInfo.ptStart.X, cThisCard.udrAnimationInfo.ptStart.Y - intCardHeight / 2);
							bmpCardUnknown = new Bitmap(bmpCardBack, intWidthImage, intCardHeight);
							g.DrawImage(bmpCardUnknown, ptTLImage);

							ptTRPreviousCard = new Point(bmpCardUnknown.Width, (int)Math.Sqrt(Math.Pow(dblCardWidth, 2) - Math.Pow(bmpCardUnknown.Width, 2)));
						}
						else if (intCardCounter == intPivotCardIndex - 1)
						{  // one or more cards are face down and this is the first card to the left of the pivot card
							dblK = (cAnimate[intCardCounter + 1].udrAnimationInfo.ptStart.X - cAnimate[intCardCounter].udrAnimationInfo.ptStart.X);
							intWidthImage = intLeftMostPoint + intPivotPoint - cAnimate[intCardCounter].udrAnimationInfo.ptStart.X;

							ptTRPreviousCard = new Point(intWidthImage,
														 (int)(Math.Sqrt(dblCardWidth * dblCardWidth - intWidthImage * intWidthImage)));
							ptTLImage = new Point(cThisCard.udrAnimationInfo.ptStart.X, cThisCard.udrAnimationInfo.ptStart.Y - intCardHeight / 2);
							if (intWidthImage == 0)
							{
								intWidthImage = 1;
								ptTRPreviousCard.X = 1;
							}
							bmpCardUnknown = new Bitmap(bmpCardBack, intWidthImage, intCardHeight);

							g.DrawImage(bmpCardUnknown, ptTLImage);
						}
						else
						{
							dblK = (cAnimate[intCardCounter + 1].udrAnimationInfo.ptStart.X - cAnimate[intCardCounter].udrAnimationInfo.ptStart.X);
							// this is one of the cards to the left of the pivot card
							// calculate slope of the card on which this card is leaning
							double dblM1 = (double)ptTRPreviousCard.Y / (double)ptTRPreviousCard.X;

							/// we know the TR point of the previous card
							/// both this card and card to the right lean towards the right with this card falling onto its right-neaghbor
							/// drop an imaginary line from the point of contact(x,y) to form a right-angle triangle 
							/// using the previous card's base point as the origin
							/// solve for y, set equal to y = M1x eq'n, drop the y's
							/// get identical quadratic as previous case above

							// variables of quadratic equation
							double dbl_A = (dblM1 * dblM1 + 1);
							double dbl_B = 2 * dblK;
							double dbl_C = dblK * dblK - dblCardWidth * dblCardWidth;

							double dblX_Plus = (-dbl_B + Math.Sqrt(dbl_B * dbl_B - 4 * dbl_A * dbl_C)) / (2 * dbl_A);
							double dblX_Minus = (-dbl_B - Math.Sqrt(dbl_B * dbl_B - 4 * dbl_A * dbl_C)) / (2 * dbl_A);

							int intImageWidth = (int)dblCardWidth;
							if (dblX_Plus > 0 && dblX_Plus < ptTRPreviousCard.X)
							{
								intImageWidth = (int)(dblX_Plus + dblK);
								ptTRPreviousCard = new Point((int)(dblK - dblX_Plus), (int)(dblM1 * (double)dblX_Plus));
							}
							else if (dblX_Minus > 0 && dblX_Minus < ptTRPreviousCard.X)
							{
								intImageWidth = (int)(dblX_Minus + dblK);
								ptTRPreviousCard = new Point((int)(dblK - dblX_Plus), (int)(dblM1 * (double)dblX_Plus));
							}
							else
							{
								ptTRPreviousCard = new Point(cThisCard.udrAnimationInfo.ptStart.X + (int)dblCardWidth, 0);
							}

							ptTLImage = new Point(cThisCard.udrAnimationInfo.ptStart.X, cThisCard.udrAnimationInfo.ptStart.Y - intCardHeight / 2);
							bmpCardUnknown = new Bitmap(bmpCardBack, intImageWidth, intCardHeight);
							g.DrawImage(bmpCardUnknown, ptTLImage);
						}
					}
				}
				if (eDealMode > enuDealCardsMode.selectWeapon)
					AnimateDealCards_drawMurderCards(g);
			}
			picBoard.Image = bmpTemp; picBoard.Refresh();

			setDelayTimer(100);
			udrAnimateDealCards.intAnimationCounter++;
		}

		void AnimateDealCards_SpreadCards(enuCardType eCardType, bool bolFaceUp)
		{
			classCard[] cAnimate = udrAnimateDealCards.udrTypeOrder.cRooms;
			int intHGap = (int)(cCards[0].cBmp.getImage(0).Width * .45);
			switch (eCardType)
			{
				case enuCardType.Suspect:
					cAnimate = udrAnimateDealCards.udrTypeOrder.cSuspects;
					intHGap = (int)(cCards[0].cBmp.getImage(0).Width * .65);
					break;

				case enuCardType.weapon:
					cAnimate = udrAnimateDealCards.udrTypeOrder.cWeapons;
					intHGap = (int)(cCards[0].cBmp.getImage(0).Width * .65);
					break;
			}

			switch (udrAnimateDealCards.intAnimationCounter)
			{
				case 0: // init spread out top facing  cards
					Point ptBase = cAnimate[0].udrAnimationInfo.ptPos;
					int intMaxSteps = 30;
					for (int intCardCounter = 0; intCardCounter < cAnimate.Length; intCardCounter++)
					{
						classCard cThisCard = cAnimate[intCardCounter];
						cThisCard.udrAnimationInfo.ptStart = cThisCard.udrAnimationInfo.ptPos;
						cThisCard.udrAnimationInfo.ptEnd = new Point(ptBase.X + intCardCounter * intHGap, ptBase.Y);
						cThisCard.udrAnimationInfo.intMaxSteps = intMaxSteps;
						cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
						cThisCard.udrAnimationInfo.dblTravelInitialVelocity = cThisCard.udrAnimationInfo.dblTravelDistance / cThisCard.udrAnimationInfo.intMaxSteps;
						cThisCard.udrAnimationInfo.intStep = 0;
					}
					udrAnimateDealCards.intAnimationCounter++;
					break;

				case 1: // spread out cards
					bool bolStartFlipCards = false;
					Bitmap bmpTemp = new Bitmap(bmpDealAnimationBoard_Base);
					using (Graphics g = Graphics.FromImage(bmpTemp))
					{
						for (int intCardCounter = 0; intCardCounter < cAnimate.Length; intCardCounter++)
						{
							classCard cThisCard = cAnimate[intCardCounter];
							cThisCard.udrAnimationInfo.ptPos = new Point(cThisCard.udrAnimationInfo.ptPos.X + (int)cThisCard.udrAnimationInfo.dblTravelInitialVelocity, cThisCard.udrAnimationInfo.ptPos.Y);
							cThisCard.udrAnimationInfo.intStep++;
							if (cThisCard.udrAnimationInfo.intStep >= cThisCard.udrAnimationInfo.intMaxSteps)
								bolStartFlipCards = true;
							Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - cThisCard.cBmp.getImage(0).Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - cThisCard.cBmp.getImage(0).Height / 2);
							if (bolFaceUp)
								g.DrawImage(cThisCard.cBmp.getImage(0), ptTL);
							else
								g.DrawImage(cCardUnknown.cBmp.getImage(0), ptTL);
						}
						if (eDealMode > enuDealCardsMode.selectWeapon)
							AnimateDealCards_drawMurderCards(g);
					}
					if (bolStartFlipCards)
						eDealMode = (enuDealCardsMode)((int)eDealMode + 1);
					picBoard.Image = bmpTemp; picBoard.Refresh();
					break;
			}
			setDelayTimer(10);
		}

		void AnimateDealCards_GatherTypes()
		{
			switch (udrAnimateDealCards.intAnimationCounter)
			{
				case 0:					// initialize card animations
					int intMaxSteps = 10;

					for (int intCardCounter = 0; intCardCounter < udrAnimateDealCards.cCardsCurrentAnimation.Length; intCardCounter++)
					{
						classCard cThisCard = udrAnimateDealCards.cCardsCurrentAnimation[intCardCounter];
						cThisCard.udrAnimationInfo.ptStart = cThisCard.udrAnimationInfo.ptPos;
						cThisCard.udrAnimationInfo.ptEnd = ptAnimationTypeStackPos[(int)cThisCard.eType];
						cThisCard.udrAnimationInfo.intMaxSteps = intMaxSteps;
						cThisCard.udrAnimationInfo.intStep = 0;

						if (cThisCard.udrAnimationInfo.dblAngleFacing > Math.PI)
							cThisCard.udrAnimationInfo.dblAngleTurning = (dblTwoPi - cThisCard.udrAnimationInfo.dblAngleFacing) / cThisCard.udrAnimationInfo.intMaxSteps;
						else
							cThisCard.udrAnimationInfo.dblAngleTurning = -cThisCard.udrAnimationInfo.dblAngleFacing / cThisCard.udrAnimationInfo.intMaxSteps;

						cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
						cThisCard.udrAnimationInfo.dblTravelAngle = classMath.arcTan(cThisCard.udrAnimationInfo.ptEnd, cThisCard.udrAnimationInfo.ptStart);
						cThisCard.udrAnimationInfo.dblTravelInitialVelocity = cThisCard.udrAnimationInfo.dblTravelDistance / cThisCard.udrAnimationInfo.intMaxSteps;
					}
					udrAnimateDealCards.intAnimationCounter++;

					udrAnimateDealCards.udrTypeOrder.cRooms = new classCard[0];
					udrAnimateDealCards.udrTypeOrder.cSuspects = new classCard[0];
					udrAnimateDealCards.udrTypeOrder.cWeapons = new classCard[0];
					break;

				case 1:				 // animate cards
					bmpDealAnimationBoard = new Bitmap(bmpDealAnimationBoard_Base);
					bool bolGatherTopCardsAndExit = false;
					bool bolInsertIntoTypeOrder = (udrAnimateDealCards.udrTypeOrder.cSuspects.Length == 0);
					using (Graphics g = Graphics.FromImage(bmpDealAnimationBoard))
					{
						for (int intCardCounter = 0; intCardCounter < udrAnimateDealCards.cCardsCurrentAnimation.Length; intCardCounter++)
						{
							classCard cThisCard = udrAnimateDealCards.cCardsCurrentAnimation[intCardCounter];
							if (bolInsertIntoTypeOrder)
							{
								switch (cThisCard.eType)
								{
									case enuCardType.room:
										Array.Resize<classCard>(ref udrAnimateDealCards.udrTypeOrder.cRooms, udrAnimateDealCards.udrTypeOrder.cRooms.Length + 1);
										udrAnimateDealCards.udrTypeOrder.cRooms[udrAnimateDealCards.udrTypeOrder.cRooms.Length - 1] = cThisCard;
										break;

									case enuCardType.weapon:
										Array.Resize<classCard>(ref udrAnimateDealCards.udrTypeOrder.cWeapons, udrAnimateDealCards.udrTypeOrder.cWeapons.Length + 1);
										udrAnimateDealCards.udrTypeOrder.cWeapons[udrAnimateDealCards.udrTypeOrder.cWeapons.Length - 1] = cThisCard;
										break;

									case enuCardType.Suspect:
										Array.Resize<classCard>(ref udrAnimateDealCards.udrTypeOrder.cSuspects, udrAnimateDealCards.udrTypeOrder.cSuspects.Length + 1);
										udrAnimateDealCards.udrTypeOrder.cSuspects[udrAnimateDealCards.udrTypeOrder.cSuspects.Length - 1] = cThisCard;
										break;
								}
							}
							cThisCard.udrAnimationInfo.intStep++;
							if (cThisCard.udrAnimationInfo.intStep == cThisCard.udrAnimationInfo.intMaxSteps)
								bolGatherTopCardsAndExit = true;

							double dblFractionDistanceTravelled = ((double)cThisCard.udrAnimationInfo.intStep / (double)cThisCard.udrAnimationInfo.intMaxSteps) * cThisCard.udrAnimationInfo.dblTravelDistance;
							cThisCard.udrAnimationInfo.ptPos = new Point(cThisCard.udrAnimationInfo.ptStart.X + (int)(dblFractionDistanceTravelled * Math.Cos(cThisCard.udrAnimationInfo.dblTravelAngle)),
																		 cThisCard.udrAnimationInfo.ptStart.Y + (int)(dblFractionDistanceTravelled * Math.Sin(cThisCard.udrAnimationInfo.dblTravelAngle)));
							cThisCard.udrAnimationInfo.dblAngleFacing += cThisCard.udrAnimationInfo.dblAngleTurning;

							while (cThisCard.udrAnimationInfo.dblAngleFacing < 0)
								cThisCard.udrAnimationInfo.dblAngleFacing += dblTwoPi;
							while (cThisCard.udrAnimationInfo.dblAngleFacing >= dblTwoPi)
								cThisCard.udrAnimationInfo.dblAngleFacing -= dblTwoPi;

							int intImageIndex = (bolGatherTopCardsAndExit ? 0 : getImageIndex (cThisCard.udrAnimationInfo.dblAngleFacing));
							Bitmap bmp = cThisCard.cBmp.getImage(intImageIndex);
							Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - bmp.Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - bmp.Height / 2);
							g.DrawImage(bmp, ptTL);
						}
					}
					picBoard.Image = bmpDealAnimationBoard; picBoard.Refresh();
					if (bolGatherTopCardsAndExit)
					{
						udrAnimateDealCards.cCardsCurrentAnimation = new classCard[0];
						eDealMode = (enuDealCardsMode)((int)eDealMode + 1);
					}
					break;

			}
			setDelayTimer(100);
		}

		void AnimateDealCards_SortCardsIntoTypes()
		{
			if (udrAnimateDealCards.intAnimationCounter % 8 == 0 && udrAnimateDealCards.strCards.Length > 0)
			{
				// throw new card across the table
				string strThisCard = udrAnimateDealCards.strCards.Substring(0, 2);
				udrAnimateDealCards.strCards = udrAnimateDealCards.strCards.Substring(2);
				enuCards eCard = (enuCards)Convert.ToInt16(strThisCard);
				Array.Resize<classCard>(ref udrAnimateDealCards.cCardsCurrentAnimation, udrAnimateDealCards.cCardsCurrentAnimation.Length + 1);
				udrAnimateDealCards.cCardsCurrentAnimation[udrAnimateDealCards.cCardsCurrentAnimation.Length - 1] = cCards[(int)eCard];
				classCard cThisCard = udrAnimateDealCards.cCardsCurrentAnimation[udrAnimateDealCards.cCardsCurrentAnimation.Length - 1];
				Point ptStart = new Point(-50, -50);
				Point ptEnd = new Point(1, 1);

				switch (cThisCard.eType)
				{
					case enuCardType.room:
						ptEnd = new Point((int)(bmpBoard.Width * .9), (int)(bmpBoard.Height * .25));
						break;

					case enuCardType.Suspect:
						ptEnd = new Point((int)(bmpBoard.Width * .85), (int)(bmpBoard.Height * .75));
						break;

					case enuCardType.weapon:
						ptEnd = new Point((int)(bmpBoard.Width * .25), (int)(bmpBoard.Height * .75));
						break;
				}
				int intRangeError = (int)(bmpBoard.Height * .1);
				ptEnd = new Point((int)(ptEnd.X + (int)(rnd.NextDouble() * 1000) % intRangeError * Math.Cos(rnd.NextDouble() * Math.PI * 2)),
								  (int)(ptEnd.Y + (int)(rnd.NextDouble() * 1000) % intRangeError * Math.Sin(rnd.NextDouble() * Math.PI * 2)));

				cThisCard.udrAnimationInfo.ptStart = ptStart;
				cThisCard.udrAnimationInfo.ptEnd = ptEnd;
				cThisCard.udrAnimationInfo.dblTravelAcceleration = -15;
				cThisCard.udrAnimationInfo.dblTravelAngle = classMath.arcTan(ptEnd, ptStart);
				cThisCard.udrAnimationInfo.dblTravelDistance = classMath.distanceBetweenTwoPoints(ptEnd, ptStart);
				cThisCard.udrAnimationInfo.intMaxSteps = (int)Math.Ceiling(Math.Sqrt(-2.0 * cThisCard.udrAnimationInfo.dblTravelDistance / cThisCard.udrAnimationInfo.dblTravelAcceleration));
				cThisCard.udrAnimationInfo.dblTravelInitialVelocity = -cThisCard.udrAnimationInfo.dblTravelAcceleration * cThisCard.udrAnimationInfo.intMaxSteps;
				cThisCard.udrAnimationInfo.dblAngleTurning = rnd.NextDouble() * Math.PI * (1.0 / 8.0);
				cThisCard.udrAnimationInfo.intStep = 0;
				cThisCard.udrAnimationInfo.dblAngleTurningAttenuation = 0.95;
			}

			udrAnimateDealCards.intAnimationCounter++;

			bmpDealAnimationBoard = new Bitmap(bmpDealAnimationBoard_Base);
			bool bolEndSortCards = true;

			using (Graphics g = Graphics.FromImage(bmpDealAnimationBoard))
			{
				for (int intCardCounter = 0; intCardCounter < udrAnimateDealCards.cCardsCurrentAnimation.Length; intCardCounter++)
				{
					classCard cThisCard = udrAnimateDealCards.cCardsCurrentAnimation[intCardCounter];
					if (cThisCard.udrAnimationInfo.intStep < cThisCard.udrAnimationInfo.intMaxSteps)
					{
						bolEndSortCards = false;

						cThisCard.udrAnimationInfo.intStep++;

						double dblDistanceTravelled = cThisCard.udrAnimationInfo.dblTravelInitialVelocity * cThisCard.udrAnimationInfo.intStep + .5 * cThisCard.udrAnimationInfo.dblTravelAcceleration * cThisCard.udrAnimationInfo.intStep * cThisCard.udrAnimationInfo.intStep;
						cThisCard.udrAnimationInfo.ptPos = new Point(cThisCard.udrAnimationInfo.ptStart.X + (int)(dblDistanceTravelled * Math.Cos(cThisCard.udrAnimationInfo.dblTravelAngle)),
																	 cThisCard.udrAnimationInfo.ptStart.Y + (int)(dblDistanceTravelled * Math.Sin(cThisCard.udrAnimationInfo.dblTravelAngle)));

						cThisCard.udrAnimationInfo.dblAngleFacing += cThisCard.udrAnimationInfo.dblAngleTurning;

						while (cThisCard.udrAnimationInfo.dblAngleFacing >= dblTwoPi)
							cThisCard.udrAnimationInfo.dblAngleFacing -= dblTwoPi;
						while (cThisCard.udrAnimationInfo.dblAngleFacing < 0)
							cThisCard.udrAnimationInfo.dblAngleFacing += dblTwoPi;

						cThisCard.udrAnimationInfo.dblAngleTurning *= cThisCard.udrAnimationInfo.dblAngleTurningAttenuation;
					}

					int intImageIndex = getImageIndex(cThisCard.udrAnimationInfo.dblAngleFacing);
					Bitmap bmp = cThisCard.cBmp.getImage(intImageIndex);
					Point ptTL = new Point(cThisCard.udrAnimationInfo.ptPos.X - bmp.Width / 2, cThisCard.udrAnimationInfo.ptPos.Y - bmp.Height / 2);
					g.DrawImage(bmp, ptTL);
				}
			}

			picBoard.Image = bmpDealAnimationBoard; picBoard.Refresh();
			if (bolEndSortCards && udrAnimateDealCards.strCards.Length == 0)
			{
				eDealMode = (enuDealCardsMode)((int)eDealMode + 1);
				udrAnimateDealCards.intAnimationCounter = 0;
			}
			setDelayTimer(10);
		}
		#endregion

		#region "animate summonses"
		void initSummonWeapon()
		{
			if (cWeapons[(int)udrSuggestion.eWeapon].eRoom == cSuspects[intSuspectTurn].eRoom)
			{
				cWeapons[(int)udrSuggestion.eWeapon].eRoom = cSuspects[intSuspectTurn].eRoom;
				eMode = enuMode.respondToSuggestion;
				drawBoard();
				DrawSuggestingSuspect(); writeSuggestion();
				ProveSuggestion();
				return;
			}

			udrAniSummWeapon.ptStart = getWeaponGraphicPositionInRoom(udrSuggestion.eWeapon, cWeapons[(int)udrSuggestion.eWeapon].eRoom);
			udrAniSummWeapon.ptEnd = getWeaponGraphicPositionInRoom(udrSuggestion.eWeapon, cSuspects[intSuspectTurn].eRoom);
			udrAniSummWeapon.intStepCounter = 0;
			udrAniSummWeapon.bolMoveToCenterOfScreen = true;
			udrAniSummWeapon.intMaxSteps = 12;
			udrAniSummWeapon.dblAngleBetweenPoints = classMath.arcTan((double)(udrAniSummWeapon.ptEnd.X - udrAniSummWeapon.ptStart.X), (double)(udrAniSummWeapon.ptEnd.Y - udrAniSummWeapon.ptStart.Y));
			udrAniSummWeapon.dblDistanceBetweenPoints = Math.Sqrt(Math.Pow(udrAniSummWeapon.ptEnd.X - udrAniSummWeapon.ptStart.X, 2) + Math.Pow(udrAniSummWeapon.ptEnd.Y - udrAniSummWeapon.ptStart.Y, 2)) / 2;

			udrAniSummWeapon.ptMidway = new Point((int)(udrAniSummWeapon.ptStart.X + udrAniSummWeapon.dblDistanceBetweenPoints * Math.Cos(udrAniSummWeapon.dblAngleBetweenPoints)),
												  (int)(udrAniSummWeapon.ptStart.Y + udrAniSummWeapon.dblDistanceBetweenPoints * Math.Sin(udrAniSummWeapon.dblAngleBetweenPoints)));
			drawBoard();
			bmpGameBoard = (Bitmap)picBoard.Image;
			setDelayTimer(40);
		}

		void animateSummonWeapon()
		{
			udrAniSummWeapon.intStepCounter++;
			if (udrAniSummWeapon.intStepCounter < udrAniSummWeapon.intMaxSteps)
			{
				Bitmap bmpTemp = new Bitmap(bmpGameBoard);

				using (Graphics g = Graphics.FromImage(bmpTemp))
				{
					double dblFractionDistance = ((double)udrAniSummWeapon.intStepCounter / (double)udrAniSummWeapon.intMaxSteps);
					double dblPartDistance = udrAniSummWeapon.dblDistanceBetweenPoints * dblFractionDistance;
					Point pt = new Point((int)(udrAniSummWeapon.ptStart.X + dblPartDistance * Math.Cos(udrAniSummWeapon.dblAngleBetweenPoints)),
										 (int)(udrAniSummWeapon.ptStart.Y + dblPartDistance * Math.Sin(udrAniSummWeapon.dblAngleBetweenPoints)));
					int intTotalSizeDifference = (bmpWeapons_Board[0].Width - 35);
					double dblFractionSize = ((double)udrAniSummWeapon.intStepCounter / (double)udrAniSummWeapon.intMaxSteps);
					if (!udrAniSummWeapon.bolMoveToCenterOfScreen)
					{
						dblFractionSize = ((double)(udrAniSummWeapon.intMaxSteps - udrAniSummWeapon.intStepCounter) / (double)udrAniSummWeapon.intMaxSteps);
					}
					Size sz = new Size((int)(intTotalSizeDifference * dblFractionSize) + 35, (int)(intTotalSizeDifference * dblFractionSize) + 35);

					Point ptTL = new Point(pt.X - sz.Width / 2, pt.Y - sz.Height / 2);

					Rectangle recDest = new Rectangle(ptTL, sz);
					Rectangle recSrc = new Rectangle(0, 0, bmpWeapons_Board[(int)udrSuggestion.eWeapon].Width, bmpWeapons_Board[(int)udrSuggestion.eWeapon].Height);

					g.DrawImage(bmpWeapons_Board[(int)udrSuggestion.eWeapon], recDest, recSrc, GraphicsUnit.Pixel);

				}
				picBoard.Image = bmpTemp; picBoard.Refresh();
				setDelayTimer(40);
			}
			else
			{
				if (udrAniSummWeapon.bolMoveToCenterOfScreen)
				{
					udrAniSummWeapon.ptStart = udrAniSummWeapon.ptMidway;
					udrAniSummWeapon.intStepCounter = 0;
					udrAniSummWeapon.bolMoveToCenterOfScreen = false;
					udrAniSummWeapon.intMaxSteps = 12;
					setDelayTimer(40);
				}
				else
				{
					cWeapons[(int)udrSuggestion.eWeapon].eRoom = cSuspects[intSuspectTurn].eRoom;
					eMode = enuMode.respondToSuggestion;
					drawBoard();
					DrawSuggestingSuspect(); writeSuggestion();
					ProveSuggestion();
				}
			}
		}

		void initSummonSuspect()
		{
			if (cSuspects[(int)udrSuggestion.eSuspect].eRoom == cSuspects[intSuspectTurn].eRoom)
			{
				eMode = enuMode.animateSummonWeapon;
				return;
			}

			// set summoned suspect can suggest
			cSuspects[(int)udrSuggestion.eSuspect].bolCanSuggest = true;
			cSuspects[(int)udrSuggestion.eSuspect].bolHasNotYetMadeASuggestionThisTurn = false;

			if (cSuspects[(int)udrSuggestion.eSuspect].eRoom == enuRooms.tiles)
				udrAniSummSuspect.ptStart = getTileCenter(cSuspects[(int)udrSuggestion.eSuspect].ptTile);
			else if (cSuspects[(int)udrSuggestion.eSuspect].eRoom == enuRooms.start)
				udrAniSummSuspect.ptStart = new Point(cSuspects[(int)udrSuggestion.eSuspect].ptFirstTile.X * 28 + ptBoardTL.X, cSuspects[(int)udrSuggestion.eSuspect].ptFirstTile.Y * 28 + ptBoardTL.Y);
			else
				udrAniSummSuspect.ptStart = getPieceGraphicPositionInRoom(udrSuggestion.eSuspect, cSuspects[(int)udrSuggestion.eSuspect].eRoom);

			udrAniSummSuspect.ptEnd = getPieceGraphicPositionInRoom(udrSuggestion.eSuspect, cSuspects[intSuspectTurn].eRoom);

			udrAniSummSuspect.intStepCounter = 0;
			udrAniSummSuspect.bolMoveToCenterOfScreen = true;
			udrAniSummSuspect.intMaxSteps = 12;
			udrAniSummSuspect.dblAngleBetweenPoints = classMath.arcTan((double)(udrAniSummSuspect.ptEnd.X - udrAniSummSuspect.ptStart.X), (double)(udrAniSummSuspect.ptEnd.Y - udrAniSummSuspect.ptStart.Y));
			udrAniSummSuspect.dblDistanceBetweenPoints = Math.Sqrt(Math.Pow(udrAniSummSuspect.ptEnd.X - udrAniSummSuspect.ptStart.X, 2) + Math.Pow(udrAniSummSuspect.ptEnd.Y - udrAniSummSuspect.ptStart.Y, 2)) / 2;

			udrAniSummSuspect.ptMidway = new Point((int)(udrAniSummSuspect.ptStart.X + udrAniSummSuspect.dblDistanceBetweenPoints * Math.Cos(udrAniSummSuspect.dblAngleBetweenPoints)),
												   (int)(udrAniSummSuspect.ptStart.Y + udrAniSummSuspect.dblDistanceBetweenPoints * Math.Sin(udrAniSummSuspect.dblAngleBetweenPoints)));
			drawBoard();
			setDelayTimer(40);
		}

		void animateSummonSuspect()
		{
			udrAniSummSuspect.intStepCounter++;
			if (udrAniSummSuspect.intStepCounter < udrAniSummSuspect.intMaxSteps)
			{
				Bitmap bmpTemp = new Bitmap(bmpGameBoard);

				using (Graphics g = Graphics.FromImage(bmpTemp))
				{
					double dblFractionDistance = ((double)udrAniSummSuspect.intStepCounter / (double)udrAniSummSuspect.intMaxSteps);
					double dblPartDistance = udrAniSummSuspect.dblDistanceBetweenPoints * dblFractionDistance;
					Point pt = new Point((int)(udrAniSummSuspect.ptStart.X + dblPartDistance * Math.Cos(udrAniSummSuspect.dblAngleBetweenPoints)),
										 (int)(udrAniSummSuspect.ptStart.Y + dblPartDistance * Math.Sin(udrAniSummSuspect.dblAngleBetweenPoints)));
					int intTotalSizeDifference = (bmpSuspects[0].Width - 35);
					double dblFractionSize = ((double)udrAniSummSuspect.intStepCounter / (double)udrAniSummSuspect.intMaxSteps);
					if (!udrAniSummSuspect.bolMoveToCenterOfScreen)
					{
						dblFractionSize = ((double)(udrAniSummSuspect.intMaxSteps - udrAniSummSuspect.intStepCounter) / (double)udrAniSummSuspect.intMaxSteps);
					}
					Size sz = new Size((int)(intTotalSizeDifference * dblFractionSize) + 35, (int)(intTotalSizeDifference * dblFractionSize) + 35);

					Point ptTL = new Point(pt.X - sz.Width / 2, pt.Y - sz.Height / 2);

					Rectangle recDest = new Rectangle(ptTL, sz);
					Rectangle recSrc = new Rectangle(0, 0, bmpSuspects[(int)udrSuggestion.eSuspect].Width, bmpSuspects[(int)udrSuggestion.eSuspect].Height);

					g.DrawImage(bmpSuspects[(int)udrSuggestion.eSuspect], recDest, recSrc, GraphicsUnit.Pixel);

				}
				picBoard.Image = bmpTemp; picBoard.Refresh();
				setDelayTimer(40);
			}
			else
			{
				if (udrAniSummSuspect.bolMoveToCenterOfScreen)
				{
					udrAniSummSuspect.ptStart = udrAniSummSuspect.ptMidway;
					udrAniSummSuspect.intStepCounter = 0;
					udrAniSummSuspect.bolMoveToCenterOfScreen = false;
					udrAniSummSuspect.intMaxSteps = 12;
					setDelayTimer(40);
				}
				else
				{
					cSuspects[(int)udrSuggestion.eSuspect].eRoom = cSuspects[intSuspectTurn].eRoom;
					eMode = enuMode.animateSummonWeapon;
				}
			}
		}
		#endregion
			
		#region "debug"
		//public void clearDebug()
		//{
		//    System.IO.File.WriteAllText(strDebugFilename, "");
		//}

		//public void appendDebug(string strMessage)
		//{
		//    strDebugFilename = strDebugFilename.ToUpper().Replace("DEBUG", "RELEASE");
		//    string strStatistics = "\r\n ----  statistics ---";
		//    string strOriginal = "";
		//    if (System.IO.File.Exists(strDebugFilename))
		//        strOriginal = System.IO.File.ReadAllText(strDebugFilename);
		//    int intCutChr = strOriginal.IndexOf(strStatistics);
		//    if (intCutChr >= 0)
		//        strOriginal = strOriginal.Substring(0, intCutChr - 1);
		//    strOriginal += "\r\n" + strMessage + "(" + DateTime.Now.ToString() + ")";

		//    string strCopy = strOriginal;
		//    string strCorrectlyIn = "Correctly in";
		//    intCutChr = strCopy.IndexOf(strCorrectlyIn);
		//    int[] intTurns = new int[100];
		//    int intNumGames = 0;
		//    while (intCutChr > 0)
		//    {
		//        intNumGames++;
		//        strCopy = strCopy.Substring(intCutChr + strCorrectlyIn.Length).Trim();
		//        intCutChr = strCopy.IndexOf(" ");
		//        if (intCutChr > 0)
		//        {
		//            int intThisNumTurn = Convert.ToInt16(strCopy.Substring(0, intCutChr));
		//            if (intThisNumTurn >= 0 && intThisNumTurn < intTurns.Length)
		//                intTurns[intThisNumTurn]++;
		//        }
		//        intCutChr = strCopy.IndexOf(strCorrectlyIn);
		//    }
		//    strOriginal += strStatistics;
		//    for (int intNumTurnsCounter = 0; intNumTurnsCounter < intTurns.Length; intNumTurnsCounter++)
		//    {
		//        if (intTurns[intNumTurnsCounter] > 0)
		//        {
		//            strOriginal += "\r\nsolved in " + intNumTurnsCounter.ToString() + " turns " + intTurns[intNumTurnsCounter].ToString() + " time" + (intTurns[intNumTurnsCounter] == 1 ? "" : "s") + " out of " + intNumGames.ToString() + " %" + ((double)intTurns[intNumTurnsCounter] / (double)intNumGames * 100.0).ToString("f2");
		//        }
		//    }

		//    System.IO.File.WriteAllText(strDebugFilename, strOriginal);
		//}
		#endregion
				
		#region "helper functions"
		Point getTileCenter(Point ptTile)
		{
			return new Point(ptBoardTL.X + ptTile.X * 28 + 14, ptBoardTL.Y + ptTile.Y * 28 + 14);
		}

		public bool floorTileIsFree(Point pt)
		{
			foreach (classSuspect cS in cSuspects)
				if (cS.eRoom == enuRooms.tiles && cS.ptTile == pt)
					return false;
			return true;
		}

		bool validTile(Point pt)
		{
			return (pt.X >= 0 && pt.Y >= 0 && pt.X < sz.Width && pt.Y < sz.Height);
		}

		Point getPieceGraphicPositionInRoom(enuSuspects eSuspect) { return getPieceGraphicPositionInRoom(eSuspect, cSuspects[(int)eSuspect].eRoom); }
		Point getPieceGraphicPositionInRoom(enuSuspects eSuspect, enuRooms eRoom)
		{
			double dblAlpha = (-Math.PI / 2 + Math.PI / 3.0) - (double)(int)eSuspect * (Math.PI / 3.0);

			Point	ptRoomCenter =getRoomCenter(eRoom);
			double dblRadius = 40;
			Point ptPieceCenter = new Point(ptRoomCenter.X + (int)(dblRadius * Math.Cos(dblAlpha)), ptRoomCenter.Y + (int)(dblRadius * Math.Sin(dblAlpha)));
			return ptPieceCenter;
		}

		Point getWeaponGraphicPositionInRoom(enuWeapons eWeapon) { return getWeaponGraphicPositionInRoom(eWeapon, cWeapons[(int)eWeapon].eRoom); }
		Point getWeaponGraphicPositionInRoom(enuWeapons eWeapon, enuRooms eRoom)
		{
			double dblAlpha = (double)(int)eWeapon * (Math.PI / 3.0);
			Point ptRoomCenter = getRoomCenter(eRoom);
			double dblRadius = 40;
			Point ptWeaponCenter = new Point(ptRoomCenter.X + (int)(dblRadius * Math.Cos(dblAlpha)), ptRoomCenter.Y + (int)(dblRadius * Math.Sin(dblAlpha)));
			return ptWeaponCenter;
		}

		public Bitmap getTextImage(string strText, Font fnt)
		{ return getTextImage(strText, fnt, Color.Black); }
		public Bitmap getTextImage(string strText, Font fnt, Color clr)
		{
			// use lblSize's 'autosize' mode to measure required output bitmap size
			lblSizer.Text = strText;
			lblSizer.Font = fnt;

			Rectangle quoteRect = new Rectangle(0,
												0,
												lblSizer.Width
													+ (fnt.Italic ? (int)(fnt.Height * .3) : 0)
													+ (fnt.Bold ? (int)(fnt.Height * .2) : 0),
												lblSizer.Height + 5);

			// create a new bitmap that contains both the quote and the author text
			Bitmap bmpTemp = new Bitmap(quoteRect.Width, quoteRect.Height);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				// set the text rendering characteristics
				g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
				g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

				// draw the text
				TextRenderer.DrawText(g,
									  strText,
									  fnt,
									  new Point(quoteRect.X + 5,
												quoteRect.Y),
									  clr,
									  Color.White,
									  TextFormatFlags.Default | TextFormatFlags.NoPrefix);
			}
			bmpTemp.MakeTransparent(Color.White);
			int intLeftCut = 7;
			int intWidth = bmpTemp.Width - intLeftCut;
			if (intWidth <= 0)
				intWidth = 1;
			Bitmap bmpRetVal = new Bitmap(intWidth, bmpTemp.Height);
			using (Graphics g = Graphics.FromImage(bmpRetVal))
			{
				Rectangle rectDest = new Rectangle(0, 0, quoteRect.Width, bmpRetVal.Height);
				Rectangle rectSrc = new Rectangle(intLeftCut, 0, quoteRect.Width, bmpRetVal.Height);
				g.DrawImage(bmpTemp, rectDest, rectSrc, GraphicsUnit.Pixel);
			}

			return bmpRetVal;
		}
		Point getRoomCenter(enuRooms eRoom)
		{
			if (ptRoomCenters == null || true)
			{
				ptRoomCenters = new Point[(int)enuRooms._numRooms + 1];

				for (enuRooms eRoomCounter = (enuRooms)0; eRoomCounter <= enuRooms._numRooms; eRoomCounter++)
				{
					switch (eRoomCounter)
					{
						case enuRooms.Study:
							ptRoomCenters[(int)eRoomCounter] = new Point(110, 60);
							break;

						case enuRooms.Hall:
							ptRoomCenters[(int)eRoomCounter] = new Point(358, 100);
							break;

						case enuRooms.Lounge:
							ptRoomCenters[(int)eRoomCounter] = new Point(596, 82);
							break;

						case enuRooms.DiningRoom:
							ptRoomCenters[(int)eRoomCounter] = new Point(591, 332);
							break;

						case enuRooms.Kitchen:
							ptRoomCenters[(int)eRoomCounter] = new Point(610, 580);
							break;

						case enuRooms.BallRoom:
							ptRoomCenters[(int)eRoomCounter] = new Point(367, 564);
							break;

						case enuRooms.Conservatory:
							ptRoomCenters[(int)eRoomCounter] = new Point(103, 611);
							break;

						case enuRooms.BilliardRoom:
							ptRoomCenters[(int)eRoomCounter] = new Point(106, 409);
							break;

						case enuRooms.Library:
							ptRoomCenters[(int)eRoomCounter] = new Point(122, 242);
							break;

						case enuRooms._numRooms:
							ptRoomCenters[(int)eRoomCounter] = new Point(349, 328);
							break;
					}
				}
			}

			return ptRoomCenters[(int)eRoom];
		}

		public enuRooms getERoomFromCard(enuCards eRoomCard)
		{
			try
			{
				if (classCard.eCardIsARoom(eRoomCard))
					return (enuRooms)((int)eRoomCard - (int)enuSuspects._numSuspects - (int)enuWeapons._numWeapons);
			}
			catch (Exception)
			{

			}
			return enuRooms._numRooms;
		}

		public enuCards getCardFromERoom(enuRooms eRoom)
		{
			string strERoom = eRoom.ToString();
			for (enuCards eCardCounter = (enuCards)0; eCardCounter < enuCards._numCards; eCardCounter++)
				if (eCardCounter.ToString() == strERoom)
					return eCardCounter;
			return enuCards._numCards;
		}

		public enuSuspects getESuspectFromCard(enuCards eSuspectCard)
		{
			try
			{
				if (classCard.eCardIsASuspect(eSuspectCard))
					return (enuSuspects)((int)eSuspectCard);
			}
			catch (Exception)
			{

			}
			return enuSuspects._numSuspects;
		}

		public enuCards getCardFromESuspect(enuSuspects eSuspect)
		{
			string streSuspect = eSuspect.ToString();
			for (enuCards eCardCounter = (enuCards)0; eCardCounter < enuCards._numCards; eCardCounter++)
				if (eCardCounter.ToString() == streSuspect)
					return eCardCounter;
			return enuCards._numCards;
		}

		public enuWeapons getEWeaponFromCard(enuCards eWeaponCard)
		{
			try
			{
				if (classCard.eCardIsAWeapon(eWeaponCard))
					return (enuWeapons)((int)eWeaponCard - (int)enuSuspects._numSuspects);
			}
			catch (Exception) { }
			return enuWeapons._numWeapons;
		}

		public enuCards getCardFromEWeapon(enuWeapons eWeapon)
		{
			string streWeapon = eWeapon.ToString();
			for (enuCards eCardCounter = (enuCards)0; eCardCounter < enuCards._numCards; eCardCounter++)
				if (eCardCounter.ToString() == streWeapon)
					return eCardCounter;
			return enuCards._numCards;
		}

		public enuDir getOppDir(enuDir dirIn) { return (enuDir)(((int)dirIn + 2) % 4); }

		void appendCardList(ref enuCards[] eCardList, enuCards eCard)
		{
			if (eCardList == null)
				eCardList = new enuCards[0];

			Array.Resize<enuCards>(ref eCardList, eCardList.Length + 1);
			eCardList[eCardList.Length - 1] = eCard;
		}

		bool eCardIsInListeCards(ref classCard[] cCardList, enuCards eCard)
		{
			for (int intCardCounter = 0; intCardCounter < cCardList.Length; intCardCounter++)
				if (cCardList[intCardCounter].eCardName == eCard)
					return true;
			return false;
		}

		public Point movePoint(Point pt, enuDir dir)
		{
			switch (dir)
			{
				case enuDir.north:
					if (pt.Y < 1)
						return new Point(-1, -1);
					else
						return new Point(pt.X, pt.Y - 1);

				case enuDir.east:
					if (pt.X > sz.Width - 1)
						return new Point(-1, -1);
					else
						return new Point(pt.X + 1, pt.Y);

				case enuDir.south:
					if (pt.Y > sz.Height - 1)
						return new Point(-1, -1);
					else
						return new Point(pt.X, pt.Y + 1);

				case enuDir.west:
					if (pt.X < 1)
						return new Point(-1, -1);
					else
						return new Point(pt.X - 1, pt.Y);
			}
			return new Point(-1, -1);
		}

		bool RoomDoor(ref classRoom cRoom, Point pt)
		{
			for (int intDoorCounter = 0; intDoorCounter < cRoom.ptDoors.Length; intDoorCounter++)
			{
				if (cRoom.ptDoors[intDoorCounter] == pt)
					return true;
			}
			return false;
		}
		void setPtMouseTile(int intX, int intY)
		{
			ptMouseTile = new Point((intX - ptBoardTL.X) / 28, (intY - ptBoardTL.Y) / 28);
		}

		enuSuspects getMouseOverAISuspect(Point pt)
		{
			if (pt.Y > 39 && pt.Y < 64)
			{ // Col.Mustard
				return enuSuspects.ColMustard;
			}
			else if (pt.Y > 65 && pt.Y < 90)
			{ // Prof Plum
				return enuSuspects.ProfPlum;
			}
			else if (pt.Y > 91 && pt.Y < 118)
			{ // Rev.Green
				return enuSuspects.RevGreen;
			}
			else if (pt.Y > 119 && pt.Y < 144)
			{ // Mrs.Peacock
				return enuSuspects.MrsPeacock;
			}
			else if (pt.Y > 145 && pt.Y < 170)
			{ // Miss Scarlet
				return enuSuspects.MissScarlet;
			}
			else if (pt.Y > 171 && pt.Y < 196)
			{ // Mrs.White
				return enuSuspects.MrsWhite;
			}
			else
				return enuSuspects._numSuspects;
		}

		#endregion

		public enuMode eMode
		{
			get { return _eMode; }
			set
			{
				_eMode = value;
				switch (_eMode)
				{
					case enuMode.chooseCharacter:
						pnlControls.Enabled = false;
						cLibPicTrayWeapons.Visible = false;
						break;

					case enuMode.Accuse:
						pnlControls.Enabled = false;
						if (cSuspects[intSuspectTurn].bolPlayerControlled)
							ShowAccuseOptions();
						break;

					case enuMode.Suggest:
						pnlControls.Enabled = false;
						Suggest();
						break;

					case enuMode.animateIntroduction:
						initAnimateIntroduction();
						break;
						
					case enuMode.animateSummonSuspect:
						initSummonSuspect();
						break;

					case enuMode.animateSummonWeapon:
						initSummonWeapon();
						break;

					case enuMode.respondToSuggestion:
						break;

					case enuMode.animateSecretPassage:
						initAnimateSecretPassage();
						break;

					case enuMode.warnPlayerNextTurn:
						btnChooseSuspect.Visible =
							cLibPicTraySuspects.Visible =
							cLibPicTrayWeapons.Visible = false;
						btnEndTurn.Enabled = false;
						btnSuggest.Enabled = cSuspects[intSuspectTurn].bolCanSuggest;
						grbControls.BackColor = clrSuspects[intSuspectTurn]; grbControls.Refresh();
						pnlControls.Enabled = false;
						btnRollDie.PulseColor
							= grbControls.ForeColor = Color.FromArgb((grbControls.BackColor.A + 126) % 255,
																	 (grbControls.BackColor.R + 126) % 255,
																	 (grbControls.BackColor.G + 126) % 255,
																	 (grbControls.BackColor.B + 126) % 255);

						grbControls.Text = cSuspects[intSuspectTurn].eName.ToString();
						picBoard.SendToBack(); picBoard.Refresh();
						drawBoard();
						warnPlayerWhoseTurnItIs();
						break;

					case enuMode.beginTurn:
						btnRollDie.Enabled = true;
						grbControls.Visible = true;
						eraseWarnPlayerWhoseTurnItIs();
						picBoard.SendToBack();
						picNotebook.Refresh();
						pnlControls.Enabled = true;
						cSuspects[intSuspectTurn].allowSecretPassage();
						drawBoard();
						if (!cSuspects[intSuspectTurn].bolPlayerControlled)
						{
							cSuspects[intSuspectTurn].playTurn();
						}
						else
							eMode = enuMode.playerTurnIdle;
						break;

					case enuMode.endTurn:
						cSuspects[intSuspectTurn].bolCanSuggest = false;
						cSuspects[intSuspectTurn].resetAllowableMoves();
						if (!cSuspects[intSuspectTurn].bolPlayerControlled)
						{
							if (eMode != enuMode.respondToSuggestion && eMode != enuMode.Suggest)
							{
								drawBoard();
								nextPlayer();
							}
						}
						else
							nextPlayer();
						break;

					case enuMode.rollDie_animate:
						setDelayTimer(5);
						break;

					case enuMode.rollDie_end:
						rollDie_End();
						break;

					case enuMode.dealCards:
						btnChooseSuspect.Visible =
							cLibPicTraySuspects.Visible =
							cLibPicTrayWeapons.Visible = false;
						udrAnimateDealCards.bolQuitAnimation = false;
						eDealMode = (enuDealCardsMode)0;
						eDealMode = (enuDealCardsMode)1;
						break;						
				}
			}
		}

		void initResponseBubble()
		{
			bmpResponseBubble = new Bitmap(bmpSuggestionBubble, new Size(400, 120));
			bmpResponseBubble.RotateFlip(RotateFlipType.RotateNoneFlipX);
			bmpResponseBubble.MakeTransparent();
		}

		void PlayerChoosesCardToShowBannerClick()
		{
			autoProceedEnabled = false;

			picBoard.Image = bmpSuggestionBoard; picBoard.Refresh();

			eMode = enuMode.respondToSuggestion;
			ProveSuggestion_ReceiveResponse(getPlayerSuspect().eName, enuCards.NoCardShown);
		}

		public void btnMakeSuggestion_OK_click()
		{
			autoProceedEnabled = false;
			cLibPicTraySuspects.Visible = false;
			cLibPicTrayWeapons.Visible = false;
			eMode = enuMode.respondToSuggestion;
			cButtons[(int)enuButtons.MakeSuggestion_Cancel].erase();
			cButtons[(int)enuButtons.MakeSuggestion_Ok].erase();
			eMode = enuMode.animateSummonSuspect;
		}

		void btnMakeSuggestion_Cancel_click()
		{
			cSuspects[intSuspectTurn].bolCanSuggest = true;
			cLibPicTraySuspects.Visible = false;
			cLibPicTrayWeapons.Visible = false;
			btnSuggest.Enabled = pnlControls.Enabled = true;
			eMode = enuMode.playerTurnIdle;
			drawBoard();
		}

		void btnRespondSuggestion_OK_click()
		{
			autoProceedEnabled = false;
			if (udrSuggestionAnimation.intProveSuggestionCycleCounter < (int)enuSuspects._numSuspects)
				ProveSuggestion_CycleThroughSuspects();
			else
			{
				drawBoard();
				pnlControls.Enabled = true;
				if (cSuspects[intSuspectTurn].bolPlayerControlled)
					eMode = enuMode.playerTurnIdle;
				else
				{
					if (cSuspects[intSuspectTurn].bolMustMove)
					{
						eMode = enuMode.AISuggestionComplete;
						cSuspects[intSuspectTurn].playTurn();
					}
					else
						eMode = enuMode.endTurn;
				}
			}
		}

		bool buttonPressed()
		{
			if (eMode == enuMode.playerChoosesCardToShow)
			{
				if (ptMousePos.X > recBannerButton.Left && ptMousePos.X < recBannerButton.Left + recBannerButton.Width)
					if (ptMousePos.Y > recBannerButton.Top && ptMousePos.Y < recBannerButton.Top + recBannerButton.Height)
					{
						if (btnPlayerResponse[0].Visible)
							return false; // there are cards to show ignore this click
						PlayerChoosesCardToShowBannerClick();
						return true;
					}
			}

			if (cButtons[(int)enuButtons.MouseOver] == null)
				return false;

			switch (eMode)
			{
				case enuMode.Suggest:
					if (cButtons[(int)enuButtons.MouseOver] == cButtons[(int)enuButtons.MakeSuggestion_Ok])
					{
						btnMakeSuggestion_OK_click();
						return true;
					}
					else if (cButtons[(int)enuButtons.MouseOver] == cButtons[(int)enuButtons.MakeSuggestion_Cancel]
							 && cSuspects[intSuspectTurn].bolPlayerControlled)
					{
						btnMakeSuggestion_Cancel_click();
						return true;
					}
					break;

				case enuMode.respondToSuggestion:
					if (cButtons[(int)enuButtons.MouseOver] == cButtons[(int)enuButtons.RespondToSuggestion_Ok])
					{
						btnRespondSuggestion_OK_click();
					}
					break;
			}

			return false;
		}		

		void pic_MouseClick(object sender, MouseEventArgs e)
		{ // this is the event-handler called when player clicks picBoard or picNote
			if ((eMode == enuMode.showAllowableMoves && !cSuspects[intSuspectTurn].bolPlayerControlled)
			 || (eMode == enuMode.showAllowableMoves && !validTile(ptMouseTile))
			 || bolDisableMouseClickBoard
				|| !bolInit)
				return;
			picMouseClick(sender, e);
		}

		public void picMouseClick(object sender, MouseEventArgs e)
		{ // this is the function which the AI calls to activate a move
			if (!bolInit)
				return;
			if (eMode == enuMode.dealCards || eMode == enuMode.idle)
			{
				udrAnimateDealCards.bolQuitAnimation = true;
				return;
			}

			if (buttonPressed())
				return;

			setPtMouseTile(e.X, e.Y);

			if (!validTile(ptMouseTile))
				return;

			bolDisableMouseClickBoard = true;
			classSuspect cSus = cSuspects[intSuspectTurn];

			if (cSus.cSEAllowableMoves[ptMouseTile.X, ptMouseTile.Y] != null)
			{
				if (classSuspect.cFloor[ptMouseTile.X, ptMouseTile.Y].eType == enuFloor.door
					&& classSuspect.cFloor[ptMouseTile.X, ptMouseTile.Y].dirDoor == enuDir.secretPassage)
				{
					eMode = enuMode.animateSecretPassage;
					bolDisableMouseClickBoard = false;
					return;
				}
				else
				{
					btnRollDie.Enabled = false;
					btnEndTurn.Enabled = true;
					if (cSus.eRoom == enuRooms.start)
					{
						cSus.eRoom = enuRooms.tiles;
						cSus.ptTile = cSus.ptFirstTile;
					}

					// animate suspect walking
					// calculate path from current tile to clicked-tile by working backwards
					udrMoveAnimationInfo.strPath = "";
					classSearchElement cSE = cSus.cSEAllowableMoves[ptMouseTile.X, ptMouseTile.Y];
					classRoom cRoom = null;
					if (cSus.eRoom < enuRooms._numRooms)
						cRoom = cRooms[(int)cSus.eRoom];
					Point ptNext = cSus.ptTile;
					enuDir dirStep;
					while (cSE != null
						   && ((cSus.eRoom == enuRooms.tiles && cSE != cSus.cSEAllowableMoves[cSus.ptTile.X, cSus.ptTile.Y]) // suspect is on tile and tile has been reached
							  || (cSus.eRoom < enuRooms._numRooms && !RoomDoor(ref cRoom, cSE.pt)))) // suspect is in a room and one of the room's doors has been reached
					{
						dirStep = getOppDir(cSE.SrcDir);
						udrMoveAnimationInfo.strPath = ((int)dirStep).ToString() + udrMoveAnimationInfo.strPath;
						ptNext = movePoint(cSE.pt, cSE.SrcDir);
						cSE = cSus.cSEAllowableMoves[ptNext.X, ptNext.Y];
					}

					if (cSus.eRoom < enuRooms._numRooms) // suspect is in a room -> ptNext points to door (not included in allowable steps)
					{
						cSus.ptTile = ptNext;
						cSus.eRoom = enuRooms.tiles;
					}

					eMode = enuMode.animateMove;

					cSus.resetAllowableMoves(); drawBoard();

					udrMoveAnimationInfo.bmpAnimationBoard = new Bitmap(picBoard.Image);
					udrMoveAnimationInfo.ptImage = new Point(ptBoardTL.X + cSus.ptTile.X * 28 + 2, ptBoardTL.Y + cSus.ptTile.Y * 28 + 2);
					udrMoveAnimationInfo.recPiece = new Rectangle(udrMoveAnimationInfo.ptImage.X, udrMoveAnimationInfo.ptImage.Y, 28, 28);
					udrMoveAnimationInfo.ptMouseTile = ptMouseTile;

					startMoveAnimation();
					return;
				}
				drawBoard();
			}
			bolDisableMouseClickBoard = false;
		}

		void Pic_MouseMove(object sender, MouseEventArgs e)
		{
			if (!bolInit)
				return;
			if (bolDisableMouseClickBoard)
				return;
			ptMousePos = new Point(e.X, e.Y);
			setPtMouseTile(e.X, e.Y);
			cButtons[(int)enuButtons.MouseOver] = getMouseOverButton(new Point(e.X, e.Y));
		}
		void picBoard_MouseEnter(object sender, EventArgs e)
		{
			if (!bolInit)
				return;
			hideOptions();
		}

		#region "animate Move"
		void startMoveAnimation()
		{
			udrMoveAnimationInfo.intAnimationStep = 4;
			udrMoveAnimationInfo.cSus = cSuspects[intSuspectTurn];
			eMode = enuMode.animateMove;
			moveStep();
		}

		void moveStep()
		{
			enuDir dirStep;

		startMoveStep:
			if (udrMoveAnimationInfo.intAnimationStep < 4)
			{
				using (Graphics g = Graphics.FromImage(udrMoveAnimationInfo.bmpAnimationBoard))
				{	// erase old image of suspect off game board	
					g.DrawImage(bmpBoard, udrMoveAnimationInfo.recPiece, udrMoveAnimationInfo.recPiece, GraphicsUnit.Pixel);
					// move ptImage
					udrMoveAnimationInfo.ptImage = new Point(udrMoveAnimationInfo.ptImage.X + udrMoveAnimationInfo.ptAnimationMove.X, udrMoveAnimationInfo.ptImage.Y + udrMoveAnimationInfo.ptAnimationMove.Y);
					// create new rectangle for altered position
					udrMoveAnimationInfo.recPiece = new Rectangle(udrMoveAnimationInfo.ptImage.X, udrMoveAnimationInfo.ptImage.Y, 28, 28);
					// draw new image of suspect onto game board
					g.DrawImage(bmpPieces[intSuspectTurn], udrMoveAnimationInfo.recPiece, new Rectangle(0, 0, 28, 28), GraphicsUnit.Pixel);
					picBoard.Image = udrMoveAnimationInfo.bmpAnimationBoard; picBoard.Refresh();
					udrMoveAnimationInfo.intAnimationStep++;
					setDelayTimer(40);
					return;
				}
			}
			else if (udrMoveAnimationInfo.strPath.Length > 0)
			{
				string strStep = udrMoveAnimationInfo.strPath.Substring(0, 1);
				udrMoveAnimationInfo.strPath = udrMoveAnimationInfo.strPath.Substring(1);
				dirStep = (enuDir)(Convert.ToInt16(strStep));
				switch (dirStep)
				{
					case enuDir.north:
						udrMoveAnimationInfo.ptAnimationMove = new Point(0, -7);
						break;

					case enuDir.east:
						udrMoveAnimationInfo.ptAnimationMove = new Point(7, 0);
						break;

					case enuDir.south:
						udrMoveAnimationInfo.ptAnimationMove = new Point(0, 7);
						break;

					default:
					case enuDir.west:
						udrMoveAnimationInfo.ptAnimationMove = new Point(-7, 0);
						break;
				}
				udrMoveAnimationInfo.intAnimationStep = 0;
				goto startMoveStep;
			}

			udrMoveAnimationInfo.cSus.ptTile = udrMoveAnimationInfo.ptMouseTile;
			if (classSuspect.cFloor[udrMoveAnimationInfo.cSus.ptTile.X, udrMoveAnimationInfo.cSus.ptTile.Y].eType == enuFloor.door)
			{
				udrMoveAnimationInfo.cSus.eRoom = classSuspect.cFloor[udrMoveAnimationInfo.cSus.ptTile.X, udrMoveAnimationInfo.cSus.ptTile.Y].eRoom;
				udrMoveAnimationInfo.cSus.bolCanSuggest = cSuspects[intSuspectTurn].bolHasNotYetMadeASuggestionThisTurn;
				btnSuggest.Enabled = cSuspects[intSuspectTurn].bolHasNotYetMadeASuggestionThisTurn;
			}
			else
			{
				udrMoveAnimationInfo.cSus.eRoom = enuRooms.tiles;
				btnSuggest.Enabled = cSuspects[intSuspectTurn].bolCanSuggest = false;
			}

			drawBoard();

			bolDisableMouseClickBoard = false;
			if (!udrMoveAnimationInfo.cSus.bolPlayerControlled)
				udrMoveAnimationInfo.cSus.playTurnAfterMove();
			else
			{
				pnlControls.Enabled = true;
				btnAccuse.Enabled = btnEndTurn.Enabled = true;
				eMode = enuMode.playerTurnIdle;
			}
		}

		#endregion

		void initAnimateSecretPassage()
		{
			grbControls.Enabled = btnRollDie.Enabled = false;
			udrAniSecretPassage.eRoom_End = cRooms[(int) cSuspects[intSuspectTurn].eRoom].oppositeCornerRoom();
			udrAniSecretPassage.eRoom_Start = cSuspects[intSuspectTurn].eRoom;

			udrAniSecretPassage.ptStart = getPieceGraphicPositionInRoom((enuSuspects)intSuspectTurn, cSuspects[intSuspectTurn].eRoom);
			udrAniSecretPassage.ptEnd = getPieceGraphicPositionInRoom((enuSuspects)intSuspectTurn, udrAniSecretPassage.eRoom_End);

			udrAniSecretPassage.intStepCounter = 0;
			udrAniSecretPassage.bolMoveToCenterOfScreen = true;
			udrAniSecretPassage.intMaxSteps = 12;
			udrAniSecretPassage.dblAngleBetweenPoints = classMath.arcTan((double)(udrAniSecretPassage.ptEnd.X - udrAniSecretPassage.ptStart.X), (double)(udrAniSecretPassage.ptEnd.Y - udrAniSecretPassage.ptStart.Y));
			udrAniSecretPassage.dblDistanceBetweenPoints = Math.Sqrt(Math.Pow(udrAniSecretPassage.ptEnd.X - udrAniSecretPassage.ptStart.X, 2) + Math.Pow(udrAniSecretPassage.ptEnd.Y - udrAniSecretPassage.ptStart.Y, 2)) / 2;

			udrAniSecretPassage.ptMidway = new Point((int)(udrAniSecretPassage.ptStart.X + udrAniSecretPassage.dblDistanceBetweenPoints * Math.Cos(udrAniSecretPassage.dblAngleBetweenPoints)),
												   (int)(udrAniSecretPassage.ptStart.Y + udrAniSecretPassage.dblDistanceBetweenPoints * Math.Sin(udrAniSecretPassage.dblAngleBetweenPoints)));

			cSuspects[intSuspectTurn].resetAllowableMoves(); drawBoard();
			
			setDelayTimer(40);
		}

		void AnimateSecretPassage()
		{
			udrAniSecretPassage.intStepCounter++;
			if (udrAniSecretPassage.intStepCounter < udrAniSecretPassage.intMaxSteps)
			{
				Bitmap bmpTemp = new Bitmap(bmpGameBoard);

				using (Graphics g = Graphics.FromImage(bmpTemp))
				{
					double dblFractionDistance = ((double)udrAniSecretPassage.intStepCounter / (double)udrAniSecretPassage.intMaxSteps);
					double dblPartDistance = udrAniSecretPassage.dblDistanceBetweenPoints * dblFractionDistance;
					Point pt = new Point((int)(udrAniSecretPassage.ptStart.X + dblPartDistance * Math.Cos(udrAniSecretPassage.dblAngleBetweenPoints)),
										 (int)(udrAniSecretPassage.ptStart.Y + dblPartDistance * Math.Sin(udrAniSecretPassage.dblAngleBetweenPoints)));
					int intTotalSizeDifference = (bmpSuspects[0].Width - 35);
					double dblFractionSize = ((double)udrAniSecretPassage.intStepCounter / (double)udrAniSecretPassage.intMaxSteps);
					if (!udrAniSecretPassage.bolMoveToCenterOfScreen)
					{
						dblFractionSize = ((double)(udrAniSecretPassage.intMaxSteps - udrAniSecretPassage.intStepCounter) / (double)udrAniSecretPassage.intMaxSteps);
					}
					Size sz = new Size((int)(intTotalSizeDifference * dblFractionSize) + 35, (int)(intTotalSizeDifference * dblFractionSize) + 35);

					Point ptTL = new Point(pt.X - sz.Width / 2, pt.Y - sz.Height / 2);

					Rectangle recDest = new Rectangle(ptTL, sz);
					Rectangle recSrc = new Rectangle(0, 0, bmpSuspects[(int)intSuspectTurn].Width, bmpSuspects[(int)intSuspectTurn].Height);

					g.DrawImage(bmpSuspects[(int)intSuspectTurn], recDest, recSrc, GraphicsUnit.Pixel);
				}
				picBoard.Image = bmpTemp; picBoard.Refresh();
				setDelayTimer(40);
			}
			else
			{
				if (udrAniSecretPassage.bolMoveToCenterOfScreen)
				{
					udrAniSecretPassage.ptStart = udrAniSecretPassage.ptMidway;
					udrAniSecretPassage.intStepCounter = 0;
					udrAniSecretPassage.bolMoveToCenterOfScreen = false;
					udrAniSecretPassage.intMaxSteps = 12;
					setDelayTimer(40);
				}
				else
				{
					cSuspects[intSuspectTurn].eRoom = udrAniSecretPassage.eRoom_End;
					btnRollDie.Enabled = false;
					grbControls.Enabled
						= btnEndTurn.Enabled
						= btnSuggest.Enabled
						= cSuspects[intSuspectTurn].bolCanSuggest = true;
					bolDisableMouseClickBoard = false;
					eMode = enuMode.playerTurnIdle;
					if (!cSuspects[intSuspectTurn].bolPlayerControlled)
					{
						cSuspects[intSuspectTurn].bolMustMove = false;
						cSuspects[intSuspectTurn].makeSuggestion();
					}
					drawBoard();
				}
			}
		}

		classButton getMouseOverButton(Point ptMouse)
		{
			for (enuButtons eButtonCounter = 0; eButtonCounter < enuButtons._numButtons; eButtonCounter++)
			{
				if (cButtons[(int)eButtonCounter] != null)
				{
					classButton cThisButton = cButtons[(int)eButtonCounter];
					if (ptMouse.X > cThisButton.pt.X && ptMouse.X < cThisButton.pt.X + cThisButton.sz.Width)
						if (ptMouse.Y > cThisButton.pt.Y && ptMouse.Y < cThisButton.pt.Y + cThisButton.sz.Height)
						{
							if (cThisButton.eMode == enuMode.any
								|| cThisButton.eMode == eMode)
							{
								if (cButtons[(int)enuButtons.MouseOver] != cThisButton)
								{
									if (cButtons[(int)enuButtons.MouseOver] != null)
										cButtons[(int)enuButtons.MouseOver].draw();
									cThisButton.highlight();
								}
								return cThisButton;
							}
						}
				}
			}

			if (cButtons[(int)enuButtons.MouseOver] != null)
				cButtons[(int)enuButtons.MouseOver].draw();

			return null;
		}

		void PlaceControls()
		{
			Controls.Add(picBoard);
			picBoard.SizeMode = PictureBoxSizeMode.Normal;
			Bitmap bmpTemp = new Bitmap(bmpBoard.Width + 5 + bmpNotebook.Width, bmpBoard.Height);
			Bitmap bmpLogo = new Bitmap(Clue_CS2010.Properties.Resources.clue_logo);
			bmpLogo.MakeTransparent();
				
			Point ptTLLogo = new Point((bmpTemp.Width - bmpLogo.Width) / 2, (bmpTemp.Height - bmpLogo.Height) / 2);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				g.DrawImage(bmpBoard, new Point(0, 0));
				g.DrawImage(bmpNotebook, new Point(bmpBoard.Width + 5, 0));
				g.DrawImage(bmpLogo, ptTLLogo );
			}
			picBoard.Image = bmpTemp;
			picBoard.Location = new Point(0, 25);
			picBoard.Controls.Add(btnAccuse_Ok);

			pnlNotebook.Left = picBoard.Left + Clue_CS2010.Properties.Resources.ClueBoardMarble.Width + 5;
			pnlNotebook.Top = picBoard.Top;

			grbControls.Location = new Point(pnlNotebook.Left + pnlNotebook.Width + 5, picNotebook.Top);
			grbControls.Width = Screen.PrimaryScreen.WorkingArea.Width - grbControls.Left - 10;
			grbControls.Height = picNotebook.Height;
			grbControls.Top = picBoard.Top;

			picBoard.Width = pnlNotebook.Left + 240;
			picBoard.Height = Screen.PrimaryScreen.WorkingArea.Height;

			picNotebook.BringToFront();
			bringControlsUpFront();

			picDieBox.Left = 5;
			picDieBox.Width = grbControls.Width - 10;			

			pnlControls.Top = 25;
			pnlControls.Left = 5;
			pnlControls.Width = grbControls.Width-10;

			btnEndTurn.Left = btnRollDie.Left = btnAccuse.Left = btnSuggest.Left = 5;
			btnEndTurn.Width = btnRollDie.Width = btnSuggest.Width = pnlControls.Width - 10;

			btnSuggest.Top = 0;
			btnRollDie.Top = btnSuggest.Top + btnSuggest.Height + 5;
			btnEndTurn.Top = btnRollDie.Top + btnRollDie.Height + 5;

			pnlControls.Height = btnEndTurn.Top + btnEndTurn.Height + 5;

			btnAccuse.Top = grbControls.Height - btnAccuse.Height - 5;
			btnAccuse.Width = grbControls.Width - 10;
			btnAccuse.Left = 5;

			picDieBox.Top = pnlControls.Top + pnlControls.Height + 5;
			picDieBox.Height = btnAccuse.Top - picDieBox.Top - 5;
			picDieBox.Visible = true;

			btnChooseSuspect.BackColor = Color.Transparent;
			btnChooseSuspect.Click += new EventHandler(btnChooseSuspect_Click);
			btnChooseSuspect.Visible = false;

			lblSizer.AutoSize = true;
			Controls.Add(lblSizer);
			lblSizer.Top = Screen.PrimaryScreen.WorkingArea.Height + 10;
			lblSizer.Visible = true;

			picBoard.MouseLeave += new EventHandler(picBoard_MouseLeave);
			picBoard.MouseMove += new MouseEventHandler(Pic_MouseMove);
			picBoard.MouseClick += new MouseEventHandler(pic_MouseClick);
			picBoard.MouseEnter += new EventHandler(picBoard_MouseEnter);

			picNotebook.MouseLeave += new EventHandler(picNotebook_MouseLeave);
			picNotebook.MouseMove += new MouseEventHandler(picNotebook_MouseMove);
			picNotebook.MouseClick += new MouseEventHandler(picNotebook_MouseClick);
			picNotebook.MouseWheel += new MouseEventHandler(picNotebook_MouseWheel);

			grbSetAI.Left = (Screen.PrimaryScreen.WorkingArea.Width - grbSetAI.Width) / 2;
			grbSetAI.Top = (Screen.PrimaryScreen.WorkingArea.Height - grbSetAI.Height) / 2;
			grbSetAI.MouseClick += new MouseEventHandler(grbSetAI_MouseClick);
			grbSetAI.MouseEnter += new EventHandler(grbSetAI_MouseEnter);

			grbSpeed.Left = (Screen.PrimaryScreen.WorkingArea.Width - grbSpeed.Width) / 2;
			grbSpeed.Top = (Screen.PrimaryScreen.WorkingArea.Height - grbSpeed.Height) / 2;
			grbSpeed.MouseEnter += new EventHandler(grbSpeed_MouseEnter);
			chkSpeed_AutoProceed.CheckedChanged += new EventHandler(chkSpeed_AutoProceed_CheckedChanged);
			chkSpeed_AutoProceed.Checked = true;
			hsbSpeed.ValueChanged += new EventHandler(hsbSpeed_ValueChanged);

			Controls.Add(proBar);
			proBar.Top = ptTLLogo.Y + bmpLogo.Height + 35;
			proBar.Width = (int)(Screen.PrimaryScreen.WorkingArea.Width * .3);
			proBar.Left = (Screen.PrimaryScreen.WorkingArea.Width - proBar.Width) / 2;
			proBar.BringToFront();
			proBar.Visible = false;

			for (int intPlayerResponseButtonCounter = 0; intPlayerResponseButtonCounter < btnPlayerResponse.Length; intPlayerResponseButtonCounter++)
			{
				btnPlayerResponse[intPlayerResponseButtonCounter] = new Button();
				picBoard.Controls.Add(btnPlayerResponse[intPlayerResponseButtonCounter]);
				btnPlayerResponse[intPlayerResponseButtonCounter].Visible = false;
				btnPlayerResponse[intPlayerResponseButtonCounter].Text = "";
				btnPlayerResponse[intPlayerResponseButtonCounter].FlatStyle = FlatStyle.Flat;
				btnPlayerResponse[intPlayerResponseButtonCounter].MouseClick += new MouseEventHandler(btnPlayerResponse_Click);
			}

			Controls.Add(lblInitializing);
			lblInitializing.Text = "Initializing data";
			lblInitializing.BackColor = Color.Yellow;
			lblInitializing.AutoSize = true;
			lblInitializing.Left = (Screen.PrimaryScreen.WorkingArea.Width - lblInitializing.Width) / 2;
			lblInitializing.Top = proBar.Top + proBar.Height + 5;
			lblInitializing.Visible = true;
			lblInitializing.BringToFront();


			picBoard.BringToFront();
			proBar.BringToFront();
			lblInitializing.BringToFront();

			tmrAutoProceed.Interval = intBaseAutoProceedInterval;
			tmrAutoProceed.Tick += new EventHandler(tmrAutoProceed_Tick);

		
		}

		bool autoProceedEnabled
		{
			get { return tmrAutoProceed.Enabled; }
			set 
			{
				tmrAutoProceed.Enabled = false;
				
				tmrAutoProceed.Enabled = value; 
			}
		}
	
		void grbSpeed_MouseEnter(object sender, EventArgs e)
		{
			bolHideOptions = true;
		}

		void grbSetAI_MouseEnter(object sender, EventArgs e)
		{
			bolHideOptions = true;
		}

		void hsbSpeed_ValueChanged(object sender, EventArgs e)
		{
			double dblMaxFactor = 10;
			double dblMinFactor = 0.1;
			double dblSlope = (dblMaxFactor - dblMinFactor) / (-(double)hsbSpeed.Maximum);
			dblSpeedFactor = dblSlope * (double)hsbSpeed.Value + dblMaxFactor;
			tmrAutoProceed.Interval = (int)((double)intBaseAutoProceedInterval * dblSpeedFactor);
		}

		void chkSpeed_AutoProceed_CheckedChanged(object sender, EventArgs e)
		{
			bolAutoProceed = chkSpeed_AutoProceed.Checked;
		}
		
		void grbSetAI_MouseClick(object sender, MouseEventArgs e)
		{
			enuSuspects eSuspectMouseOver = getMouseOverAISuspect(new Point(e.X, e.Y));
			if (eSuspectMouseOver != enuSuspects._numSuspects)
			{
				classSuspect cSus = cSuspects[(int)eSuspectMouseOver];
				cSus.eAILevel = (enuAILevel)(((int)cSus.eAILevel + 1) % (int)enuAILevel._numAILevels);
				drawSuspectAILevel();
			}
		}
		
		void picNotebook_MouseWheel(object sender, MouseEventArgs e)
		{
			if (!bolInit)
				return;
			if (cButtons[(int)enuButtons.MouseOver] != null)
			{
				if (e.Delta > 0)
					cButtons[(int)enuButtons.MouseOver].cNote.Note = (enuNote)(((int)cButtons[(int)enuButtons.MouseOver].cNote.Note - 1 + (int)enuNote._numNotes) % (int)(enuNote._numNotes));
				else
					cButtons[(int)enuButtons.MouseOver].cNote.Note = (enuNote)(((int)cButtons[(int)enuButtons.MouseOver].cNote.Note + 1) % (int)(enuNote._numNotes));
			}
		}

		void picNotebook_MouseMove(object sender, MouseEventArgs e)
		{
			if (!bolInit)
				return;
			Point ptMouse = new Point(e.X, e.Y);
			for (enuCards eCardCounter = (enuCards)0; eCardCounter < enuCards._numCards; eCardCounter++)
			{
				if (ptMouse.Y > cPlayerNotes[0, (int)eCardCounter].pt.Y && ptMouse.Y < cPlayerNotes[0, (int)eCardCounter].pt.Y + 25)
				{
					for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
					{
						if (ptMouse.X > cPlayerNotes[(int)eSuspectCounter, (int)eCardCounter].pt.X
							&& ptMouse.X < cPlayerNotes[(int)eSuspectCounter, (int)eCardCounter].pt.X + 25)
						{
							classNote cThisNote = cPlayerNotes[(int)eSuspectCounter, (int)eCardCounter];
							if (cMouseOverNote != cThisNote)
							{
								if (cMouseOverNote != null)
									cMouseOverNote.draw();
								cThisNote.highlight();
								cMouseOverNote = cThisNote;
							}
							return;
						}
					}
				}
			}
			if (cMouseOverNote != null)
				cMouseOverNote.draw();
			cMouseOverNote = null;
		}

		void picNotebook_MouseClick(object sender, MouseEventArgs e)
		{
			if (!bolInit)
				return;
			if (cMouseOverNote != null)
			{
				if (e.Button == System.Windows.Forms.MouseButtons.Left)
					cMouseOverNote.Note = (enuNote)(((int)cMouseOverNote.Note + 1) % (int)(enuNote._numNotes));
				else if (e.Button == System.Windows.Forms.MouseButtons.Right)
					cMouseOverNote.Note = (enuNote)(((int)cMouseOverNote.Note - 1 + (int)enuNote._numNotes) % (int)(enuNote._numNotes));
				cMouseOverNote.highlight();
			}
		}

		void picNotebook_MouseLeave(object sender, EventArgs e)
		{
			if (!bolInit)
				return;
			if (cButtons[(int)enuButtons.MouseOver] != null)
				cButtons[(int)enuButtons.MouseOver].draw();
		}

		void picBoard_MouseLeave(object sender, EventArgs e)
		{
			if (!bolInit)
				return;
			if (cButtons[(int)enuButtons.MouseOver] != null)
				cButtons[(int)enuButtons.MouseOver].draw();
		}

		void hideOptions()
		{
			if (bolHideOptions)
			{
				grbSetAI.Visible = grbSpeed.Visible = false;
				bolHideOptions = false;
			}
		}
	
		void drawSuspectAILevel()
		{
			Font fnt = new System.Drawing.Font("Blackadder itc", 18);

			Bitmap bmpTemp = new Bitmap(Clue_CS2010.Properties.Resources.setAI);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
				{
					Bitmap bmpAILevel = getTextImage(cSuspects[(int)eSuspectCounter].eAILevel.ToString(),
													 fnt,
													 Color.Black);
					bmpAILevel.MakeTransparent();
					g.DrawImage(bmpAILevel, ptSetAI[(int)eSuspectCounter]);
				}
			}
			grbSetAI.BackgroundImage = bmpTemp;
		}

		#region "init objects & classes"

		void initSuspects()
		{
			bmpSuspects[(int)enuSuspects.MissScarlet] = new Bitmap(Clue_CS2010.Properties.Resources.SuspectMissScarlet); bmpSuspects[(int)enuSuspects.MissScarlet].MakeTransparent();
			bmpSuspects[(int)enuSuspects.ColMustard] = new Bitmap(Clue_CS2010.Properties.Resources.SuspectColMustard); bmpSuspects[(int)enuSuspects.ColMustard].MakeTransparent();
			bmpSuspects[(int)enuSuspects.MrsWhite] = new Bitmap(Clue_CS2010.Properties.Resources.SuspectMrsWhite); bmpSuspects[(int)enuSuspects.MrsWhite].MakeTransparent();
			bmpSuspects[(int)enuSuspects.RevGreen] = new Bitmap(Clue_CS2010.Properties.Resources.SuspectRevGreen); bmpSuspects[(int)enuSuspects.RevGreen].MakeTransparent();
			bmpSuspects[(int)enuSuspects.MrsPeacock] = new Bitmap(Clue_CS2010.Properties.Resources.SuspectMrsPeacock); bmpSuspects[(int)enuSuspects.MrsPeacock].MakeTransparent();
			bmpSuspects[(int)enuSuspects.ProfPlum] = new Bitmap(Clue_CS2010.Properties.Resources.SuspectProfPlum); bmpSuspects[(int)enuSuspects.ProfPlum].MakeTransparent();

			cSuspects = new classSuspect[(int)enuSuspects._numSuspects];
			for (enuSuspects SuspectCounter = (enuSuspects)0; SuspectCounter < enuSuspects._numSuspects; SuspectCounter++)
				cSuspects[(int)SuspectCounter] = new classSuspect(SuspectCounter, this);
		}

		void initSetAIGroupBox()
		{
			ptSetAI = new Point[(int)enuSuspects._numSuspects];
			ptSetAI[(int)enuSuspects.ColMustard] = new Point(240, 33);
			ptSetAI[(int)enuSuspects.ProfPlum] = new Point(240, 59);
			ptSetAI[(int)enuSuspects.RevGreen] = new Point(240, 85);
			ptSetAI[(int)enuSuspects.MrsPeacock] = new Point(240, 112);
			ptSetAI[(int)enuSuspects.MissScarlet] = new Point(240, 138);
			ptSetAI[(int)enuSuspects.MrsWhite] = new Point(240, 164);
			drawSuspectAILevel();
		}

		void initWeapons()
		{
			bmpWeapons_PicTray[(int)enuWeapons.Candlestick] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponCandlestick);
			bmpWeapons_PicTray[(int)enuWeapons.Knife] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponKnife);
			bmpWeapons_PicTray[(int)enuWeapons.LeadPipe] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponLeadPipe);
			bmpWeapons_PicTray[(int)enuWeapons.Revolver] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponRevolver);
			bmpWeapons_PicTray[(int)enuWeapons.Rope] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponRope);
			bmpWeapons_PicTray[(int)enuWeapons.Wrench] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponWrench);

			cWeapons = new classWeapon[(int)enuWeapons._numWeapons];
			for (enuWeapons eWeaponCounter = (enuWeapons)0; eWeaponCounter < enuWeapons._numWeapons; eWeaponCounter++)
				cWeapons[(int)eWeaponCounter] = new classWeapon(eWeaponCounter);

			bmpWeapons_Board = new Bitmap[(int)enuWeapons._numWeapons];
			bmpWeapons_Board[(int)enuWeapons.Candlestick] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponBoard_Candlestick); bmpWeapons_Board[(int)enuWeapons.Candlestick].MakeTransparent(bmpWeapons_Board[(int)enuWeapons.Candlestick].GetPixel(0, 0));
			bmpWeapons_Board[(int)enuWeapons.Knife] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponBoard_Knife); bmpWeapons_Board[(int)enuWeapons.Knife].MakeTransparent(bmpWeapons_Board[(int)enuWeapons.Knife].GetPixel(0, 0));
			bmpWeapons_Board[(int)enuWeapons.LeadPipe] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponBoard_LeadPipe); bmpWeapons_Board[(int)enuWeapons.LeadPipe].MakeTransparent(bmpWeapons_Board[(int)enuWeapons.LeadPipe].GetPixel(0, 0));
			bmpWeapons_Board[(int)enuWeapons.Revolver] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponBoard_Revolver); bmpWeapons_Board[(int)enuWeapons.Revolver].MakeTransparent(bmpWeapons_Board[(int)enuWeapons.Revolver].GetPixel(0, 0));
			bmpWeapons_Board[(int)enuWeapons.Rope] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponBoard_Rope); bmpWeapons_Board[(int)enuWeapons.Rope].MakeTransparent(bmpWeapons_Board[(int)enuWeapons.Rope].GetPixel(0, 0));
			bmpWeapons_Board[(int)enuWeapons.Wrench] = new Bitmap(Clue_CS2010.Properties.Resources.WeaponBoard_Wrench); bmpWeapons_Board[(int)enuWeapons.Wrench].MakeTransparent(bmpWeapons_Board[(int)enuWeapons.Wrench].GetPixel(0, 0));
		}

		void initRooms()
		{
			cRooms = new classRoom[(int)enuRooms._numRooms];
			for (enuRooms eRoomCounter = (enuRooms)0; eRoomCounter < enuRooms._numRooms; eRoomCounter++)
				cRooms[(int)eRoomCounter] = new classRoom(eRoomCounter, this);

			bmpRooms[(int)enuRooms.BallRoom] = Clue_CS2010.Properties.Resources.CrimeSceneBallRoom;
			bmpRooms[(int)enuRooms.BilliardRoom] = Clue_CS2010.Properties.Resources.CrimeSceneBilliardRoom;
			bmpRooms[(int)enuRooms.Conservatory] = Clue_CS2010.Properties.Resources.CrimeSceneConservatory;
			bmpRooms[(int)enuRooms.DiningRoom] = Clue_CS2010.Properties.Resources.CrimeSceneDiningRoom;
			bmpRooms[(int)enuRooms.Hall] = Clue_CS2010.Properties.Resources.CrimeSceneHall;
			bmpRooms[(int)enuRooms.Kitchen] = Clue_CS2010.Properties.Resources.CrimeSceneKitchen;
			bmpRooms[(int)enuRooms.Library] = Clue_CS2010.Properties.Resources.CrimeSceneLibrary;
			bmpRooms[(int)enuRooms.Lounge] = Clue_CS2010.Properties.Resources.CrimeSceneLounge;
			bmpRooms[(int)enuRooms.Study] = Clue_CS2010.Properties.Resources.CrimeSceneStudy;
		}

		void initColors()
		{
			clrSuspects = new Color[(int)enuSuspects._numSuspects];
			for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
				clrSuspects[(int)eSuspectCounter] = bmpPieces[(int)eSuspectCounter].GetPixel(5, 5);
		}

		void initPieces()
		{
			bmpPieces[(int)enuSuspects.MissScarlet] = new Bitmap(Clue_CS2010.Properties.Resources.Piece_MissScarlet); bmpPieces[(int)enuSuspects.MissScarlet].MakeTransparent();
			bmpPieces[(int)enuSuspects.ColMustard] = new Bitmap(Clue_CS2010.Properties.Resources.Piece_ColMustard); bmpPieces[(int)enuSuspects.ColMustard].MakeTransparent();
			bmpPieces[(int)enuSuspects.MrsWhite] = new Bitmap(Clue_CS2010.Properties.Resources.Piece_MrsWhite); bmpPieces[(int)enuSuspects.MrsWhite].MakeTransparent();
			bmpPieces[(int)enuSuspects.RevGreen] = new Bitmap(Clue_CS2010.Properties.Resources.Piece_RevGreen); bmpPieces[(int)enuSuspects.RevGreen].MakeTransparent();
			bmpPieces[(int)enuSuspects.MrsPeacock] = new Bitmap(Clue_CS2010.Properties.Resources.Piece_MrsPeacock); bmpPieces[(int)enuSuspects.MrsPeacock].MakeTransparent();
			bmpPieces[(int)enuSuspects.ProfPlum] = new Bitmap(Clue_CS2010.Properties.Resources.Piece_ProfPlum); bmpPieces[(int)enuSuspects.ProfPlum].MakeTransparent();
		}

		//void initIntroMice()
		//{
		//    cBmpDie = new classRotatedImage[3];

		//    string strDirectoryAndBaseDieFilename = System.IO.Directory.GetCurrentDirectory() + "\\mouse";
		//    for (int intMouseTailCounter = 0; intMouseTailCounter < 3; intMouseTailCounter++)
		//    {
		//        cBmpDie[intMouseTailCounter] = new classRotatedImage();
		//        string strThisDieFilename = strDirectoryAndBaseDieFilename + intMouseTailCounter.ToString() + ".rBMP";
		//        if (System.IO.File.Exists(strThisDieFilename))
		//        {
		//            cBmpDie[intMouseTailCounter].loadBaseImages(strThisDieFilename);
		//        }
		//        else
		//        {
		//            Pen pWhite = new Pen(Color.White, 2);
		//            Bitmap bmpOriginal = Clue_CS2010.Properties.Resources.Mouse00;

		//            switch (intMouseTailCounter)
		//            {
		//                case 1:
		//                    bmpOriginal = Clue_CS2010.Properties.Resources.Mouse01;
		//                    break;
		//                case 2:
		//                    bmpOriginal = Clue_CS2010.Properties.Resources.Mouse02;
		//                    break;
		//            }

		//            cBmpDie[intMouseTailCounter].createBaseImage(bmpOriginal);
		//            cBmpDie[intMouseTailCounter].saveBaseImages(strThisDieFilename);
		//        }
		//    }
		//}

		void initDieImages()
		{
			cBmpDie = new classRotatedImage[7];

			string strDirectoryAndBaseDieFilename = System.IO.Directory.GetCurrentDirectory() + "\\die";
			for (int intDieValueCounter = 1; intDieValueCounter < 7; intDieValueCounter++)
			{
				cBmpDie[intDieValueCounter] = new classRotatedImage();
				string strThisDieFilename = strDirectoryAndBaseDieFilename + intDieValueCounter.ToString() + ".rBMP";
				if (System.IO.File.Exists(strThisDieFilename))
				{
					cBmpDie[intDieValueCounter].loadBaseImages(strThisDieFilename);
				}
				else
				{
					Pen pWhite = new Pen(Color.White, 2);
					Bitmap bmpOriginal = Clue_CS2010.Properties.Resources.die1;

					switch (intDieValueCounter)
					{
						case 2:
							bmpOriginal = Clue_CS2010.Properties.Resources.die2;
							break;
						case 3:
							bmpOriginal =Clue_CS2010.Properties.Resources.die3;
							break;
						case 4:
							bmpOriginal =Clue_CS2010.Properties.Resources.die4;
							break;
						case 5:
							bmpOriginal =Clue_CS2010.Properties.Resources.die5;
							break;
						case 6:
							bmpOriginal =Clue_CS2010.Properties.Resources.die6;
							break;
					}

				
					cBmpDie[intDieValueCounter].createBaseImage(bmpOriginal);
					cBmpDie[intDieValueCounter].saveBaseImages(strThisDieFilename);
				}
			}
		}

		void initCards()
		{
			cCards = new classCard[(int)enuCards._numCards];
			for (enuCards cardCounter = (enuCards)0; cardCounter < enuCards._numCards; cardCounter++)
			{
				cCards[(int)cardCounter] = new classCard(this, cardCounter);
			}
			cCardUnknown = new classCard(this, enuCards.Unknown);
		}

		void initMenu()
		{
			ToolStripMenuItem mnuFile = new ToolStripMenuItem();
			mnuFile.Text = "&File";
			mnuFile.DropDownItems.Add("&New Game", null, NewGame);
			mnuFile.DropDownItems.Add("E&xit", null, Exit);
			mnu.Items.Add(mnuFile);
			Controls.Add(mnu);

			ToolStripMenuItem mnuOptions = new ToolStripMenuItem();
			mnuOptions.Text = "&Options";
			mnuOptions.DropDownItems.Add("set &AI", null, SetAI);
			mnuOptions.DropDownItems.Add("&Speed", null, SetSpeed);
			mnu.Items.Add(mnuOptions);
			Controls.Add(mnu);

			ToolStripMenuItem mnuHelp = new ToolStripMenuItem();
			mnuHelp.Text = "&Help";
			mnuHelp.Click +=new EventHandler(Instructions);
			mnu.Items.Add(mnuHelp);
			Controls.Add(mnu);

			mnu.BackColor = Color.Black;
			mnu.ForeColor = Color.White;
			mnu.Visible = true;
		}

		#endregion

		void Instructions(object sender, EventArgs e)
		{
			if (frmInstructions == null)
				frmInstructions = new formInstructions();
			frmInstructions.ShowDialog();
			frmInstructions.Width = (int)(Screen.PrimaryScreen.WorkingArea.Width * .7);
			frmInstructions.Height = (int)(Screen.PrimaryScreen.WorkingArea.Height * .7);
			frmInstructions.Left = (Screen.PrimaryScreen.WorkingArea.Width - frmInstructions.Width) / 2;
			frmInstructions.Top = (Screen.PrimaryScreen.WorkingArea.Height - frmInstructions.Height) / 2;
		}

		void SetSpeed(object sender, EventArgs e)
		{
			grbSpeed.Visible = !grbSpeed.Visible;
		}

		void SetAI(object sender, EventArgs e)
		{
			grbSetAI.Visible = !grbSetAI.Visible;
		}

		void Exit(object sender, EventArgs e)
		{
			Dispose();
		}

		public void setUpCLibPicTrayChooseWeapon()
		{			
			setPicTrayBackgroundImage(ref cLibPicTrayWeapons);
			cLibPicTrayWeapons.Visible = true;
			cLibPicTrayWeapons.BringToFront();
			cLibPicTrayWeapons.RefreshTrayImage();
			bringControlsUpFront();
		}

		void bringControlsUpFront()
		{
			grbSetAI.BringToFront();
			grbSpeed.BringToFront();
		}

		void setUpCLibPicTrayChooseSuspect()
		{
			setPicTrayBackgroundImage(ref cLibPicTraySuspects);
			cLibPicTraySuspects.Visible = true;
			cLibPicTraySuspects.BringToFront();
			cLibPicTraySuspects.RefreshTrayImage();
			bringControlsUpFront();
		}

		public void NewGame(object sender, EventArgs e)
		{
			eMode = enuMode.chooseCharacter; eDealMode = (enuDealCardsMode)0;
			btnAccuse.Text = "Accuse";
			btnAccuse.Enabled = false;
			intNumTurns = 1;
			cLibPicTrayRooms.Visible =
				cLibPicTrayWeapons.Visible = false;
			bolDisableMouseClickBoard = false;
			btnChooseSuspect.Location = new Point(260, 530);

			bmpDealAnimationBoard_Base = AnimateDealCards_getBlankDealCardsImage();

			picBoard.Size = bmpDealAnimationBoard_Base.Size;
			picBoard.Image = bmpDealAnimationBoard_Base;
			picBoard.BringToFront();

			Bitmap bmpChooseSuspect = new Bitmap(btnChooseSuspect.Width, btnChooseSuspect.Height);
			using (Graphics g = Graphics.FromImage(bmpChooseSuspect))
			{
				Rectangle recSrc = new Rectangle(btnChooseSuspect.Location.X, btnChooseSuspect.Location.Y - 25, btnChooseSuspect.Size.Width, btnChooseSuspect.Size.Height);
				Rectangle recDest = new Rectangle(0, 0, btnChooseSuspect.Width, btnChooseSuspect.Height);
				g.DrawImage(new Bitmap(bmpBoard), recDest, recSrc, GraphicsUnit.Pixel);
			}
			btnChooseSuspect.BackgroundImage = bmpChooseSuspect;

			#region "cLibPicTraySuspects Choose Player Character"
			cLibPicTraySuspects.Location = new Point(0, 0);
			cLibPicTraySuspects.Options.Mirror = PicTray.enuMirror.none;
			cLibPicTraySuspects.Options.makeImagesTransparent = true;
			cLibPicTraySuspects.Options.PopUpClickPic = false;
			cLibPicTraySuspects.Options.SelectionMode = PicTray.enuSelectionMode.click;
			cLibPicTraySuspects.Options.TrayCenter = new Point(351, 182);
			cLibPicTraySuspects.Options.Width = 711;
			cLibPicTraySuspects.Options.Height = 491;
			cLibPicTraySuspects.Options.Rotation.StepSize = 0.119380520836412;
			cLibPicTraySuspects.Options.Rotation.Interval = 27;
			cLibPicTraySuspects.Options.Rotation.Mode = PicTray.enuRotationMode.toSelected;
			cLibPicTraySuspects.Options.Ellipse.Angle = 0;
			cLibPicTraySuspects.Options.Ellipse.Radius_Height = 124;
			cLibPicTraySuspects.Options.Ellipse.Radius_Width = 280;
			cLibPicTraySuspects.Options.Front.Angle = 1.56765473414131;
			cLibPicTraySuspects.Options.Front.UserSet = PicTray.enuFrontUserSet.none;
			cLibPicTraySuspects.Options.ImageSize.Height_MinMax = new PicTray.classMinMax(35, 343);
			cLibPicTraySuspects.Options.ImageSize.Width_MinMax = new PicTray.classMinMax(35, 300);
			cLibPicTraySuspects.Options.Caption.Show = false;
			cLibPicTraySuspects.Options.Caption.Font = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Regular);
			cLibPicTraySuspects.Options.Caption.ForeColor = Color.FromArgb(255, 255, 255, 0);
			cLibPicTraySuspects.Options.Caption.BackColor = Color.FromArgb(255, 0, 0, 0);

			#endregion

			resetSuspects(enuSuspects.MissScarlet);
			resetPlayerNotes();
			btnWarnPlayerWhoseTurnItIs.Visible = false;
			setBtnChooseSuspectColorAndText();
			setUpCLibPicTrayChooseSuspect();
			btnChooseSuspect.Visible = true;
			btnChooseSuspect.BringToFront();
			bringControlsUpFront();

		}

		void resetPlayerNotes()
		{
			bmpNotebook = new Bitmap(Clue_CS2010.Properties.Resources.notebook);
			for (enuCards eCardCounter = (enuCards)0; eCardCounter < enuCards._numCards; eCardCounter++)
				for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
				{
					if (cPlayerNotes[(int)eSuspectCounter, (int)eCardCounter] == null)
						cPlayerNotes[(int)eSuspectCounter, (int)eCardCounter] = new classNote(	  this,
																							  ref picNotebook,
																								  enuMode.any,
																								  eSuspectCounter,
																								  eCardCounter);
					cPlayerNotes[(int)eSuspectCounter, (int)eCardCounter].Note = enuNote.blank;
					cPlayerNotes[(int)eSuspectCounter, (int)eCardCounter].setMyImages();
				}
			picNotebook.Image = bmpNotebook;
			picNotebook.Refresh();
		}

		void setAccusation()
		{
			udrSuggestion.eRoom = (enuRooms)cLibPicTrayRooms.SelectedImage.Index;
			udrSuggestion.eSuspect = cSuspects[cLibPicTraySuspects.SelectedImage.Index].eName;
			udrSuggestion.eWeapon = (enuWeapons)cLibPicTrayWeapons.SelectedImage.Index;

			btnAccuse_Ok.Text = "I accuse " + udrSuggestion.eSuspect.ToString()
							  + "\r\n" + "    in the " + udrSuggestion.eRoom.ToString()
							  + "\r\n" + "  with the " + udrSuggestion.eWeapon.ToString();			

			Bitmap bmpAccuseButton = new Bitmap(btnAccuse_Ok.Width, btnAccuse_Ok.Height);
			using (Graphics g = Graphics.FromImage(bmpAccuseButton))
			{
				// draw suspects' tray image top-left corner of button
				Rectangle recSrc = new Rectangle(btnAccuse_Ok.Location.X, btnAccuse_Ok.Location.Y, cLibPicTraySuspects.Width - btnAccuse_Ok.Left, cLibPicTraySuspects.Height - btnAccuse_Ok.Top);
				Rectangle recDest = new Rectangle(0, 0, recSrc.Width, recSrc.Height);
				g.DrawImage(new Bitmap(cLibPicTraySuspects.Image), recDest, recSrc, GraphicsUnit.Pixel);

				// draw weapons' tray image top-right corner of button
				recSrc = new Rectangle(0, btnAccuse_Ok.Location.Y, btnAccuse_Ok.Width + btnAccuse_Ok.Left - cLibPicTrayWeapons.Left, cLibPicTrayWeapons.Height - btnAccuse_Ok.Top);
				recDest = new Rectangle(cLibPicTrayWeapons.Left - btnAccuse_Ok.Left, 0, recSrc.Width , recSrc.Height);
				g.DrawImage(new Bitmap(cLibPicTrayWeapons.Image), recDest, recSrc, GraphicsUnit.Pixel);

				// draw rooms' tray image bottom half of button
				recSrc = new Rectangle(btnAccuse_Ok.Left, 0, btnAccuse_Ok.Width, btnAccuse_Ok.Top + btnAccuse_Ok.Height - cLibPicTrayRooms.Top);
				recDest = new Rectangle(0, cLibPicTrayRooms.Top - btnAccuse_Ok.Top, recSrc.Width, recSrc.Height);
				g.DrawImage(new Bitmap(cLibPicTrayRooms.Image), recDest, recSrc, GraphicsUnit.Pixel);
			}
		
			btnAccuse_Ok.BackgroundImage = bmpAccuseButton;
			btnAccuse_Ok.BringToFront();
			btnAccuse_Ok.Visible = true;
		}

		void setSuggestion()
		{
			bool bolRefreshSuggestionImage = false;

			if (udrSuggestion.eRoom != cSuspects[intSuspectTurn].eRoom)
			{
				udrSuggestion.eRoom = cSuspects[intSuspectTurn].eRoom;
				bolRefreshSuggestionImage = true;
			}
			if (udrSuggestion.eSuspect != cSuspects[cLibPicTraySuspects.SelectedImage.Index].eName)
			{
				udrSuggestion.eSuspect = cSuspects[cLibPicTraySuspects.SelectedImage.Index].eName;
				bolRefreshSuggestionImage = true;
			}
			if (udrSuggestion.eWeapon != (enuWeapons)cLibPicTrayWeapons.SelectedImage.Index)
			{
				udrSuggestion.eWeapon = (enuWeapons)cLibPicTrayWeapons.SelectedImage.Index;
				bolRefreshSuggestionImage = true;
			}
			if (bolRefreshSuggestionImage)
				writeSuggestion();
		}

		void writeResponse(enuCards eCard_response, enuSuspects eSuspect_responding)
		{
			Bitmap bmpNewBoard = new Bitmap(picBoard.Image);

			using (Graphics g = Graphics.FromImage(bmpNewBoard))
			{
				g.FillRectangle(new SolidBrush(Color.White), new Rectangle(ptResponseBubbleTL.X + 14, ptResponseBubbleTL.Y + 9, 330, 55));

				Bitmap bmpText;
				Font fnt = new System.Drawing.Font("blackadder itc", 36);
				Rectangle recDest, recSrc;

				if (eCard_response == enuCards.NoCardShown)
				{
					bmpText = getTextImage("Sorry, no card", fnt, Color.Black);
					recDest = new Rectangle(ptResponseBubbleTL.X + 25, ptResponseBubbleTL.Y + 15, bmpText.Width, bmpText.Height);
					recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
					g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);
				}
				else
				{
					bmpText = getTextImage("I have a card", fnt, Color.Black);
					recDest = new Rectangle(ptResponseBubbleTL.X + 25, ptResponseBubbleTL.Y + 15, bmpText.Width, bmpText.Height);
					recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
					g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

					Bitmap bmpCardShow = bmpCardBack;
					if (cSuspects[intSuspectTurn].bolPlayerControlled || eSuspect_responding == getPlayerSuspect().eName)
					{
						bmpCardShow = cCards[(int)eCard_response].cBmp.getImage(0);
					}
					int intWidth = 120;
					recDest = new Rectangle(287, ptResponseBubbleTL.Y + bmpResponseBubble.Height, intWidth, (int)((double)bmpCardShow.Height / (double)bmpCardShow.Width * intWidth));
					recSrc = new Rectangle(0, 0, bmpCardShow.Width, bmpCardShow.Height);
					g.DrawImage(bmpCardShow, recDest, recSrc, GraphicsUnit.Pixel);
				}
			}
			picBoard.Image = bmpNewBoard; picBoard.Refresh();
		}

		void writeSuggestion()
		{
		
			Bitmap bmpNewBoard = new Bitmap(picBoard.Image);
			using (Graphics g = Graphics.FromImage(bmpNewBoard))
			{
				g.FillRectangle(new SolidBrush(Color.White), new Rectangle(ptSuggestionBubbleTL.X + 54, ptSuggestionBubbleTL.Y + 9, 335, 280));

				Bitmap bmpText;
				Font fnt = new System.Drawing.Font("blackadder itc", 36);
				Rectangle recDest, recSrc;

				int intTop = 0;
				int intVLineSpacine = 45;
				int intLeftText = 50;
				int intTabText = 140;

				bmpText = getTextImage("I suggest", fnt);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intLeftText, ptSuggestionBubbleTL.Y + intTop, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage(udrSuggestion.eSuspect.ToString(), fnt, udrSuggestion.eSuspect == enuSuspects.MrsWhite ? Color.Gray : clrSuspects[(int)udrSuggestion.eSuspect]);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intTabText, ptSuggestionBubbleTL.Y + intTop + intVLineSpacine + 10, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage("in the", fnt);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intLeftText, ptSuggestionBubbleTL.Y + intTop + 2 * intVLineSpacine, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage(udrSuggestion.eRoom.ToString(), fnt);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intTabText, ptSuggestionBubbleTL.Y + intTop + 3 * intVLineSpacine, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage("with the", fnt);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intLeftText, ptSuggestionBubbleTL.Y + intTop + 4 * intVLineSpacine, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage(udrSuggestion.eWeapon.ToString(), fnt);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intTabText, ptSuggestionBubbleTL.Y + intTop + 5 * intVLineSpacine, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);
			}
			picBoard.Image = bmpNewBoard;
		}

		void setBtnChooseSuspectColorAndText()
		{
			btnChooseSuspect.PulseColor =
			btnChooseSuspect.ButtonColorTop = clrSuspects[cLibPicTraySuspects.SelectedImage.Index];
			btnChooseSuspect.ButtonColorBottom = Color.FromArgb((btnChooseSuspect.ButtonColorTop.A + 127) % 255,
																(btnChooseSuspect.ButtonColorTop.R + 127) % 255,
																(btnChooseSuspect.ButtonColorTop.G + 127) % 255,
																(btnChooseSuspect.ButtonColorTop.B + 127) % 255);

			btnChooseSuspect.Text = "Play as " + cLibPicTraySuspects.SelectedImage.caption;
		}

		void btnChooseSuspect_Click(object sender, EventArgs e)
		{
			int intPlayerCharacter = cLibPicTraySuspects.SelectedImage.Index;
			resetSuspects(cSuspects[intPlayerCharacter].eName);
			resetWeapons();

			commitMurder();
			dealCards();
			eMode = enuMode.dealCards;
			
		}

		void setSuspectsAI()
		{
			for (int intSuspectCounter = 0; intSuspectCounter < cSuspects.Length; intSuspectCounter++)
			{
				if (!cSuspects[intSuspectCounter].bolPlayerControlled)
				{
					cSuspects[intSuspectCounter].setAI();
				}
			}
		}

		void eraseDie()
		{
			picDieBox.Image = new Bitmap(bmpBaize);
		}

		public void nextPlayer()
		{
			tmrNextPlayer.Enabled = true;
		}

		void tmrNextPlayer_Tick(object sender, EventArgs e)
		{
			tmrNextPlayer.Enabled = false;
			_nextPlayer();
		}

		void _nextPlayer()
		{
			btnEndTurn.Enabled = false;
			btnAccuse.Text = "Accuse";

			eraseDie();

			cSuspects[intSuspectTurn].resetAllowableMoves(); drawBoard();
			do
			{
				intSuspectTurn = (intSuspectTurn + 1) % 6;
			} while (cSuspects[intSuspectTurn].bolEliminated);

			cSuspects[intSuspectTurn].bolMustMove = true;
			
			if (intSuspectTurn == 0)
			{
				intNumTurns++;
			}
			btnRollDie.Enabled = true;
			btnSuggest.Enabled = cSuspects[intSuspectTurn].bolCanSuggest;
			cSuspects[intSuspectTurn].bolHasNotYetMadeASuggestionThisTurn = true;
			cSuspects[intSuspectTurn].resetAllowableMoves();

			eMode = enuMode.warnPlayerNextTurn;
		}

		void eraseWarnPlayerWhoseTurnItIs()
		{
			Bitmap bmpTemp = new Bitmap(picBoard.Width, picBoard.Height);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				g.DrawImage(bmpGameBoard, new Point(0, 0));
				g.DrawImage(new Bitmap(picNotebook.Image), new Point(bmpBoard.Width + 5, 0));
			}
			picBoard.Image = bmpTemp; picBoard.Refresh();
		}

		void warnPlayerWhoseTurnItIs()
		{
			btnAccuse.Enabled = false; 
			
			double dblSizeDifference = 1.5;
			Size szNewPicFrame = new System.Drawing.Size((int)(Clue_CS2010.Properties.Resources.picture_frame_oval.Width * dblSizeDifference),
												 (int)(Clue_CS2010.Properties.Resources.picture_frame_oval.Height * dblSizeDifference));
			Bitmap bmpPicFrame = new Bitmap(Clue_CS2010.Properties.Resources.picture_frame_oval, szNewPicFrame);

			Color clrBack = bmpPicFrame.GetPixel(0, 0);
			Color clrMirror = bmpPicFrame.GetPixel(bmpPicFrame.Width / 2, bmpPicFrame.Height / 2);

			bmpPicFrame.MakeTransparent(clrMirror);

			Bitmap bmpSuspectImage = new Bitmap(bmpPicFrame.Width, bmpPicFrame.Height);

			using (Graphics g = Graphics.FromImage(bmpSuspectImage))
			{
				int intHeight = (int)(.8 * bmpPicFrame.Height); // controls the size of the output image relative to original

				Rectangle recDest = new Rectangle((bmpPicFrame.Width - intHeight) / 2, (int)((bmpPicFrame.Height - intHeight) * .6), intHeight, intHeight);
				Rectangle recSrc = new Rectangle(0, 0, bmpSuspects[intSuspectTurn].Width, bmpSuspects[intSuspectTurn].Height);
				g.DrawImage(bmpSuspects[intSuspectTurn], recDest, recSrc, GraphicsUnit.Pixel);
				g.DrawImage(bmpPicFrame, new Point(0, 0));
			}

			bmpSuspectImage.MakeTransparent(clrBack);

			Bitmap bmpTemp = new Bitmap(picBoard.Width, picBoard.Height);

			Point ptLocPicFrame = new Point((Screen.PrimaryScreen.WorkingArea.Width - bmpSuspectImage.Width) / 2, 100);

			// if screen is so wide that mid-screen off the bitmap, adjust
			if (ptLocPicFrame.X > bmpTemp.Width - bmpSuspectImage.Width / 2)
				ptLocPicFrame.X = bmpTemp.Width - bmpSuspectImage.Width / 2;

			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				g.DrawImage(new Bitmap(picBoard.Image), new Point(0, 0));

				g.DrawImage(new Bitmap(picNotebook.Image), new Point(pnlNotebook.Left, 0));

				g.DrawImage(bmpSuspectImage, new Rectangle(ptLocPicFrame, szNewPicFrame), new Rectangle(new Point(0, 0), new Size(szNewPicFrame.Width - 1, szNewPicFrame.Height - 1)), GraphicsUnit.Pixel);
			}

			picBoard.BringToFront();
			picBoard.Image = bmpTemp; picBoard.Refresh();
			picBoard.Width = ptLocPicFrame.X + szNewPicFrame.Width + 10;

			if (cSuspects[intSuspectTurn].bolPlayerControlled)
			{
				btnWarnPlayerWhoseTurnItIs.AutoSize = true;
				btnWarnPlayerWhoseTurnItIs.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
				btnWarnPlayerWhoseTurnItIs.PulseColor =
					btnWarnPlayerWhoseTurnItIs.ButtonColorTop = clrSuspects[intSuspectTurn];
				btnWarnPlayerWhoseTurnItIs.ButtonColorBottom = Color.FromArgb((btnWarnPlayerWhoseTurnItIs.ButtonColorTop.A + 127) % 255,
																			 (btnWarnPlayerWhoseTurnItIs.ButtonColorTop.R + 127) % 255,
																			 (btnWarnPlayerWhoseTurnItIs.ButtonColorTop.G + 127) % 255,
																			 (btnWarnPlayerWhoseTurnItIs.ButtonColorTop.B + 127) % 255);
				btnWarnPlayerWhoseTurnItIs.Text = "Your turn " + cSuspects[intSuspectTurn].eName.ToString();
				btnWarnPlayerWhoseTurnItIs.Location = new Point(ptLocPicFrame.X + bmpPicFrame.Width / 2 - btnWarnPlayerWhoseTurnItIs.Width / 2,
																ptLocPicFrame.Y + bmpPicFrame.Height + 50);

				Bitmap bmpButton = new Bitmap(btnWarnPlayerWhoseTurnItIs.Width, btnWarnPlayerWhoseTurnItIs.Height);

				using (Graphics g = Graphics.FromImage(bmpButton))
				{
					Rectangle recDest = new Rectangle(0, 0, bmpButton.Width, bmpButton.Height);
					Rectangle recSrc = new Rectangle(btnWarnPlayerWhoseTurnItIs.Left, btnWarnPlayerWhoseTurnItIs.Top - picBoard.Top, bmpButton.Width, bmpButton.Height);
					g.DrawImage(bmpTemp, recDest, recSrc, GraphicsUnit.Pixel);
				}
				btnWarnPlayerWhoseTurnItIs.BackgroundImage = bmpButton;

				btnWarnPlayerWhoseTurnItIs.Visible = true; btnWarnPlayerWhoseTurnItIs.BringToFront();
			}
			else
				setDelayTimer(3000);
			bringControlsUpFront();
		}

		string shuffleCards() { return shuffleCards(true); }

		string shuffleCards(bool bolExcludeMurderCards)
		{
			string strCards = "";
			int intNumSuspects = (int)enuSuspects._numSuspects;			
			int intNumSuspectsAndWeapons = intNumSuspects + (int)enuWeapons._numWeapons;

			enuCards  eWeapon = classCard.getECardFromEWeapon( udrMurder.eWeapon);
			enuCards eSuspect = classCard.getECardFromESuspect(udrMurder.eSuspect);
			enuCards eRoom = classCard.getECardFromERoom(udrMurder.eRoom);

			// gather cards in string
			for (enuCards eCardCounter = 0; eCardCounter < enuCards._numCards; eCardCounter++)
			{
				// Suspects + weapons + rooms

				if (bolExcludeMurderCards
					&& 
					(eCardCounter == eWeapon 
					|| eCardCounter == eSuspect 
					|| eCardCounter == eRoom))
				{
					goto skipAddCard;
				}

				// add card to string
				strCards += ((int)eCardCounter).ToString("d2");

			skipAddCard: ;
			}

			// shuffle cards
			int intNumCards = strCards.Length / 2;
			for (int intShuffleCounter = 0; intShuffleCounter < 10000; intShuffleCounter++)
			{
				int intA = 0, intB = 0;
				while (intA >= intB)
				{
					intA = (int)(rnd.NextDouble() * 1000) % intNumCards;
					intB = (int)(rnd.NextDouble() * 1000) % intNumCards;
				}

				string strA = strCards.Substring(0, intA * 2);
				string strB = strCards.Substring(strA.Length, (intB - intA) * 2);
				string strC = strCards.Substring(strA.Length + strB.Length);

				strCards = strC + strB + strA;
			}
			return strCards;
		}

		void dealCards()
		{
			string strCards = strCardsDealt = shuffleCards();

			// deal cards
			enuSuspects eSuspectCounter = (enuSuspects)0;
			while (strCards.Length > 0)
			{
				string strThisCard = strCards.Substring(0, 2);
				strCards = strCards.Substring(2);
				int intThisCard = Convert.ToInt16(strThisCard);
				classCard thisCard = cCards[intThisCard];
				cSuspects[(int)eSuspectCounter].receiveCard(ref thisCard);
				eSuspectCounter = (enuSuspects)(((int)eSuspectCounter + 1) % (int)enuSuspects._numSuspects);
			}
		}

		void setPlayerNoteBook()
		{
			classSuspect cPlayer = getPlayerSuspect();
			for (int intCardCounter = 0; intCardCounter < cPlayer.cCards.Length; intCardCounter++)
			{
				for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
				{
					enuNote eNewNote = enuNote.X;
					if (cSuspects[(int)eSuspectCounter] == cPlayer)
						eNewNote = enuNote.check;

					if (cPlayerNotes[(int)cSuspects[(int)eSuspectCounter].eName, (int)cPlayer.cCards[intCardCounter].eCardName].Note != eNewNote)
					{
						cPlayerNotes[(int)cSuspects[(int)eSuspectCounter].eName, (int)cPlayer.cCards[intCardCounter].eCardName].Note = eNewNote;
					}
					cPlayerNotes[(int)cSuspects[(int)eSuspectCounter].eName, (int)cPlayer.cCards[intCardCounter].eCardName].draw();
				}
			}

			for (enuCards eCardCounter = (enuCards)0; eCardCounter < enuCards._numCards; eCardCounter++)
			{
				if (cPlayerNotes[(int)cPlayer.eName, (int)eCardCounter].Note != enuNote.check)				
					cPlayerNotes[(int)cPlayer.eName, (int)eCardCounter].Note = enuNote.X;
				cPlayerNotes[(int)cSuspects[(int)cPlayer.eName].eName, (int)eCardCounter].draw();
			}
		}

		void commitMurder()
		{
			udrMurder.eSuspect = (enuSuspects)((int)(rnd.NextDouble() * 10000) % (int)enuSuspects._numSuspects);
			udrMurder.eRoom = (enuRooms)((int)(rnd.NextDouble() * 10000) % (int)enuRooms._numRooms);
			udrMurder.eWeapon = (enuWeapons)((int)(rnd.NextDouble() * 10000) % (int)enuWeapons._numWeapons);
		}

		void resetWeapons()
		{
			for (enuWeapons eWeaponsCounter = (enuWeapons)0; eWeaponsCounter < enuWeapons._numWeapons; eWeaponsCounter++)
				cWeapons[(int)eWeaponsCounter].eRoom = enuRooms._numRooms;
		}

		void resetSuspects(enuSuspects ePlayerCharacter)
		{
			for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
			{
				cSuspects[(int)eSuspectCounter].bolCanSuggest = false;
				cSuspects[(int)eSuspectCounter].bolEliminated = false;
				cSuspects[(int)eSuspectCounter].bolMustMove = true;
				cSuspects[(int)eSuspectCounter].bolPlayerControlled = (eSuspectCounter == ePlayerCharacter);

				cSuspects[(int)eSuspectCounter].cCards = new classCard[0];
				cSuspects[(int)eSuspectCounter].eRoom = enuRooms.start;
				cSuspects[(int)eSuspectCounter].resetAllowableMoves();
				cSuspects[(int)eSuspectCounter].initNotes();
			}
		}
		
		#region "Accusation"

		private void btnAccuse_Click(object sender, EventArgs e)
		{
			if (cSuspects[intSuspectTurn].bolPlayerControlled && !cSuspects[intSuspectTurn].bolEliminated)
			{
				if (eMode != enuMode.Accuse)
				{
					udrAniAccusation.eRestoreMode = eMode;
					eMode = enuMode.Accuse;

					btnAccuse.Text = "cancel Accuse";
				}
				else
				{
					eMode = udrAniAccusation.eRestoreMode;
					btnAccuse_Ok.Visible =
						cLibPicTrayWeapons.Visible =
						cLibPicTrayRooms.Visible =
						cLibPicTraySuspects.Visible = false;
					btnAccuse.Text = "Accuse";
					pnlControls.Enabled = true;
				}
			}
		}

		public void btnAccuse_Ok_Click(object sender, EventArgs e)
		{
			udtMurder udrAccusation;
			udrAccusation.eWeapon = (enuWeapons)cLibPicTrayWeapons.SelectedImage.Index;
			udrAccusation.eSuspect = (enuSuspects)cLibPicTraySuspects.SelectedImage.Index;
			udrAccusation.eRoom = (enuRooms)cLibPicTrayRooms.SelectedImage.Index;

			btnAccuse.Enabled 
				= cLibPicTrayRooms.Visible 
				= cLibPicTrayRooms.tmrRotate.Enabled 
				= cLibPicTrayWeapons.Visible 
				= cLibPicTrayWeapons.tmrRotate.Enabled 
				= cLibPicTraySuspects.Visible 
				= cLibPicTraySuspects.tmrRotate.Enabled 
				= btnAccuse_Ok.Visible 
				= false;

			Accuse(getPlayerSuspect().eName, udrAccusation);
		}
		
		void animateAccusation()
		{			
			switch (udrAniAccusation._eMode)
			{
				case  enuAccuseAnimationMode.drawAccusation:
					AnimateAccusation_drawAccusation();
					break;

				case enuAccuseAnimationMode.prepareToShowCards:
					AnimateAccusation_PrepareToShowCards();
					break;

				case enuAccuseAnimationMode.showCards:
					AnimateAccusation_ShowCards();
					break;

				case enuAccuseAnimationMode.hideCards:
					AnimateAccusation_HideCards();
					break;

				case enuAccuseAnimationMode.retractCards:
					AnimateAccusation_RetractCards();
					break;

				case enuAccuseAnimationMode.withdrawAccusingSuspect:
					AnimateAccusation_WithdrawAccusingSuspect();
					break;

				case enuAccuseAnimationMode.showNewspaper:
					AnimateAccusation_ShowNewspaper();
					break;
			}
		}

		void AnimateAccusation_ShowNewspaper()
		{
			if (!udrAniAccusation.bolInit)
			{
				udrAniAccusation.intAnimationStep = 0;
				
				udrAniAccusation.udrElements = new udtAnimationInfo[2];

				//						Murderer's face (index = 0)
				udrAniAccusation.udrElements[0].bmp = new Bitmap(bmpSuspects[(int)udrMurder.eSuspect].Width, bmpSuspects[(int)udrMurder.eSuspect].Height);

				// need to remove trim color around circular image
				Color clrTransparent = bmpSuspects[(int)udrMurder.eSuspect].GetPixel(bmpSuspects[(int)udrMurder.eSuspect].Width / 2, 0);
				using (Graphics g = Graphics.FromImage(udrAniAccusation.udrElements[0].bmp))
				{
					g.FillRectangle(new SolidBrush(clrTransparent), new Rectangle(0, 0, udrAniAccusation.udrElements[0].bmp.Width, udrAniAccusation.udrElements[0].bmp.Height));
					g.DrawImage(bmpSuspects[(int)udrMurder.eSuspect], new Point(0, 0));
				}

				udrAniAccusation.udrElements[0].bmp.MakeTransparent(udrAniAccusation.udrElements[0].bmp.GetPixel(0,0));

				int intImageSize = 200;
				udrAniAccusation.udrElements[0].dblSizeFactor = (double)intImageSize / (double)udrAniAccusation.udrElements[0].bmp.Width;
				
				int intStartTop = (int)(intImageSize * .55);
				udrAniAccusation.udrElements[0].ptPos=
					udrAniAccusation.udrElements[0].ptStart = new Point((int)(bmpBoard.Width * .5), intStartTop + 20);
				udrAniAccusation.udrElements[0].ptEnd = new Point((int)(bmpBoard.Width *.5), (int)(bmpBoard.Height *.5));

				udrAniAccusation.udrElements[0].intMaxSteps = 30;
				udrAniAccusation.udrElements[0].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[0].ptEnd, udrAniAccusation.udrElements[0].ptStart);
				udrAniAccusation.udrElements[0].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[0].ptEnd, udrAniAccusation.udrElements[0].ptStart);
				udrAniAccusation.udrElements[0].intStep = 0;


				//						prison bars (index = 1)
				udrAniAccusation.udrElements[1].bmp = new Bitmap(Clue_CS2010.Properties.Resources.prison_bars_large);
				udrAniAccusation.udrElements[1].bmp.MakeTransparent(Color.White);
				udrAniAccusation.udrElements[1].ptPos =
					udrAniAccusation.udrElements[1].ptStart = new Point((int)(bmpBoard.Width *.2), (int)(bmpBoard.Height * .5));
				udrAniAccusation.udrElements[1].ptEnd = new Point((int)(bmpBoard.Width * .5), (int)(bmpBoard.Height * .5));
				udrAniAccusation.udrElements[1].intMaxSteps = 30;
				udrAniAccusation.udrElements[1].dblSizeFactor = 17.5;
				udrAniAccusation.udrElements[1].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[1].ptEnd, udrAniAccusation.udrElements[1].ptStart);
				udrAniAccusation.udrElements[1].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[1].ptEnd, udrAniAccusation.udrElements[1].ptStart);
				udrAniAccusation.udrElements[1].intStep = 0;

				udrAniAccusation.bolInit = true;
			}

			switch (udrAniAccusation.intAnimationStep)
			{
				case 0: 
						// move murderer image to center & zoom 
						// AND move large color bars from ultra-zoom into focus
					bool bolQuitUltraZoom = true;
					Bitmap bmpTemp = new Bitmap(udrAniAccusation.bmpAccusationBoard);
					using (Graphics g = Graphics.FromImage(bmpTemp))
					{
						for (int intEleCounter = 0; intEleCounter < udrAniAccusation.udrElements.Length; intEleCounter++)
						{
							if (udrAniAccusation.udrElements[intEleCounter].intStep < udrAniAccusation.udrElements[intEleCounter].intMaxSteps)
							{
								udrAniAccusation.udrElements[intEleCounter].intStep++;
								udrAniAccusation.udrElements[intEleCounter].ptPos.X = udrAniAccusation.udrElements[intEleCounter].ptStart.X + (int)((double)udrAniAccusation.udrElements[intEleCounter].intStep / (double)udrAniAccusation.udrElements[intEleCounter].intMaxSteps * udrAniAccusation.udrElements[intEleCounter].dblTravelDistance * Math.Cos(udrAniAccusation.udrElements[intEleCounter].dblTravelAngle));
								udrAniAccusation.udrElements[intEleCounter].ptPos.Y = udrAniAccusation.udrElements[intEleCounter].ptStart.Y + (int)((double)udrAniAccusation.udrElements[intEleCounter].intStep / (double)udrAniAccusation.udrElements[intEleCounter].intMaxSteps * udrAniAccusation.udrElements[intEleCounter].dblTravelDistance * Math.Sin(udrAniAccusation.udrElements[intEleCounter].dblTravelAngle));
								bolQuitUltraZoom = false;
							}

							switch (intEleCounter)
							{
								case 0:
									double dblSFFace_Start = 1.0;
									double dblSFFace_End = 2;
									udrAniAccusation.udrElements[intEleCounter].dblSizeFactor = dblSFFace_Start + (dblSFFace_End - dblSFFace_Start) * ((double)udrAniAccusation.udrElements[intEleCounter].intStep / (double)udrAniAccusation.udrElements[intEleCounter].intMaxSteps);
									break;

								case 1:
									// set size factor of bars
									double dblSFBars_Start = 17.5;
									double dblSFBars_End = 1.0;
									udrAniAccusation.udrElements[intEleCounter].dblSizeFactor = dblSFBars_Start + (dblSFBars_End - dblSFBars_Start) * ((double)udrAniAccusation.udrElements[intEleCounter].intStep / (double)udrAniAccusation.udrElements[intEleCounter].intMaxSteps);
									break;
							}
							
							Size sz = new Size((int)((double)udrAniAccusation.udrElements[intEleCounter].bmp.Width * udrAniAccusation.udrElements[intEleCounter].dblSizeFactor),
											   (int)((double)udrAniAccusation.udrElements[intEleCounter].bmp.Height * udrAniAccusation.udrElements[intEleCounter].dblSizeFactor));
							Point ptTL = new Point(udrAniAccusation.udrElements[intEleCounter].ptPos.X - sz.Width/2, udrAniAccusation.udrElements[intEleCounter].ptPos.Y - sz.Height / 2);
							g.DrawImage(udrAniAccusation.udrElements[intEleCounter].bmp, new Rectangle(ptTL, sz));
						}
					}
					picBoard.Image = bmpTemp; picBoard.Refresh();
					if (bolQuitUltraZoom)
					{
						// join face & bars into one image
						// convert image to black & white
						// introduce newspaper behind it

						// create b/w prison photo (index 0)
						Bitmap bmpBarsAndFace_Color = new Bitmap(udrAniAccusation.udrElements[1].bmp.Width, udrAniAccusation.udrElements[1].bmp.Height);
						using (Graphics g = Graphics.FromImage(bmpBarsAndFace_Color))
						{
							g.FillRectangle(new SolidBrush(Color.Brown), new Rectangle(0, 0, bmpBarsAndFace_Color.Width, bmpBarsAndFace_Color.Height));
						
							Size szFace = new Size((int)((double)udrAniAccusation.udrElements[0].bmp.Width * udrAniAccusation.udrElements[0].dblSizeFactor),
											   (int)((double)udrAniAccusation.udrElements[0].bmp.Height * udrAniAccusation.udrElements[0].dblSizeFactor));
							Point ptTLFace = new Point((bmpBarsAndFace_Color.Width - szFace.Width) / 2, (bmpBarsAndFace_Color.Height - szFace.Height) / 2);
							g.DrawImage(udrAniAccusation.udrElements[0].bmp, new Rectangle(ptTLFace, szFace));

							Size szBars = new Size((int)((double)udrAniAccusation.udrElements[1].bmp.Width * udrAniAccusation.udrElements[1].dblSizeFactor),
											   (int)((double)udrAniAccusation.udrElements[1].bmp.Height * udrAniAccusation.udrElements[1].dblSizeFactor));
							Point ptTLBars = new Point(0, 0);
							g.DrawImage(udrAniAccusation.udrElements[1].bmp, new Rectangle(ptTLBars, szBars));
						}
						udrAniAccusation.udrElements[1].bmp = MakeGrayscale3(bmpBarsAndFace_Color);
						
						// set up newspaper background
						udrAniAccusation.udrElements[0].bmp = new Bitmap(Clue_CS2010.Properties.Resources.newsprint);
						using (Graphics g = Graphics.FromImage(udrAniAccusation.udrElements[0].bmp))
						{
							Bitmap bmpText;
							Font fnt = new System.Drawing.Font("Franklin Gothic Demi", 12);
							Rectangle recDest, recSrc;
							Point ptTL = new Point(9, 167);

							bmpText = getTextImage(udrMurder.eSuspect.ToString() + " in the " + udrMurder.eRoom.ToString(), fnt);
							recDest = new Rectangle(ptTL.X, ptTL.Y, bmpText.Width / 2, bmpText.Height / 2);
							recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
							g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);


							bmpText = getTextImage("with the " + udrMurder.eWeapon.ToString(), fnt);
							recDest = new Rectangle(ptTL.X, ptTL.Y + 6, bmpText.Width / 2, bmpText.Height / 2);
							recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
							g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);
						}
					
						udrAniAccusation.udrElements[0].ptStart =
							udrAniAccusation.udrElements[0].ptPos =
							udrAniAccusation.udrElements[0].ptEnd = new Point(bmpBoard.Width / 2, bmpBoard.Height / 2);
						udrAniAccusation.udrElements[0].dblSizeFactor = 1.0;
						udrAniAccusation.udrElements[0].intStep =
							udrAniAccusation.udrElements[0].intMaxSteps = 0;

						// set up prison-picture motion
						udrAniAccusation.udrElements[1].ptStart = udrAniAccusation.udrElements[1].ptPos;
						udrAniAccusation.udrElements[1].ptEnd = new Point(udrAniAccusation.udrElements[0].ptEnd.X - udrAniAccusation.udrElements[0].bmp.Width/2 + 9 +75,
																		  udrAniAccusation.udrElements[0].ptEnd.Y - udrAniAccusation.udrElements[0].bmp.Height/2 + 82 + 40);
						udrAniAccusation.udrElements[1].dblSizeFactor = 1.0;
						udrAniAccusation.udrElements[1].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[1].ptEnd, udrAniAccusation.udrElements[1].ptStart);
						udrAniAccusation.udrElements[1].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[1].ptEnd, udrAniAccusation.udrElements[1].ptStart);
						udrAniAccusation.udrElements[1].intStep = 0;
						udrAniAccusation.udrElements[1].intMaxSteps = 20;

						udrAniAccusation.intAnimationStep++;
					}
					break;

				case 1:
						// move b/w face/bars onto newspaper
					bool bolQuitPutToPrint = true;
					Bitmap bmpTempPutToPrint = new Bitmap(udrAniAccusation.bmpAccusationBoard);
					using (Graphics g = Graphics.FromImage(bmpTempPutToPrint))
					{
						for (int intEleCounter = 0; intEleCounter < udrAniAccusation.udrElements.Length; intEleCounter++)
						{
							switch (intEleCounter)
							{
								case 0:
									g.DrawImage(udrAniAccusation.udrElements[intEleCounter].bmp, udrAniAccusation.udrElements[intEleCounter].ptPos.X - udrAniAccusation.udrElements[intEleCounter].bmp.Width / 2, udrAniAccusation.udrElements[intEleCounter].ptPos.Y - udrAniAccusation.udrElements[intEleCounter].bmp.Height / 2);
									break;

								case 1:
									if (udrAniAccusation.udrElements[intEleCounter].intStep < udrAniAccusation.udrElements[1].intMaxSteps)
									{
										udrAniAccusation.udrElements[intEleCounter].intStep++;
										udrAniAccusation.udrElements[intEleCounter].ptPos.X = udrAniAccusation.udrElements[intEleCounter].ptStart.X + (int)((double)udrAniAccusation.udrElements[intEleCounter].intStep / (double)udrAniAccusation.udrElements[intEleCounter].intMaxSteps * udrAniAccusation.udrElements[intEleCounter].dblTravelDistance * Math.Cos(udrAniAccusation.udrElements[intEleCounter].dblTravelAngle));
										udrAniAccusation.udrElements[intEleCounter].ptPos.Y = udrAniAccusation.udrElements[intEleCounter].ptStart.Y + (int)((double)udrAniAccusation.udrElements[intEleCounter].intStep / (double)udrAniAccusation.udrElements[intEleCounter].intMaxSteps * udrAniAccusation.udrElements[intEleCounter].dblTravelDistance * Math.Sin(udrAniAccusation.udrElements[intEleCounter].dblTravelAngle));
										bolQuitPutToPrint = false;
									}

									double dblSFFaceAndBars_Start = 1.0;
									double dblSFFaceAndBars_End = 150.0 / (double)udrAniAccusation.udrElements[intEleCounter].bmp.Width;
									/// = F + (F' - F)(n/N)
									udrAniAccusation.udrElements[intEleCounter].dblSizeFactor = dblSFFaceAndBars_Start + (dblSFFaceAndBars_End - dblSFFaceAndBars_Start) * ((double)udrAniAccusation.udrElements[intEleCounter].intStep / (double)udrAniAccusation.udrElements[intEleCounter].intMaxSteps);
									Size sz = new Size((int)((double)udrAniAccusation.udrElements[intEleCounter].bmp.Width * udrAniAccusation.udrElements[intEleCounter].dblSizeFactor),
														   (int)((double)udrAniAccusation.udrElements[intEleCounter].bmp.Height * udrAniAccusation.udrElements[intEleCounter].dblSizeFactor));
									Point ptTL = new Point(udrAniAccusation.udrElements[intEleCounter].ptPos.X - sz.Width / 2, udrAniAccusation.udrElements[intEleCounter].ptPos.Y - sz.Height / 2);
									g.DrawImage(udrAniAccusation.udrElements[intEleCounter].bmp, new Rectangle(ptTL, sz));
									break;
							}
						}
					}
					picBoard.Image = bmpTempPutToPrint; picBoard.Refresh();
					if (bolQuitPutToPrint)
					{
						// create four base rotated images during pause						
						Bitmap bmpNewsPaper = new Bitmap(udrAniAccusation.udrElements[0].bmp.Width, udrAniAccusation.udrElements[0].bmp.Height);
						using (Graphics g = Graphics.FromImage(bmpNewsPaper))
						{
							g.DrawImage(udrAniAccusation.udrElements[0].bmp, 0, 0);

							double dblSFFaceAndBars_Start = 1.0;
							double dblSFFaceAndBars_End = 150.0 / (double)udrAniAccusation.udrElements[1].bmp.Width;
							/// = F + (F' - F)(n/N)
							udrAniAccusation.udrElements[1].dblSizeFactor = dblSFFaceAndBars_Start + (dblSFFaceAndBars_End - dblSFFaceAndBars_Start) * ((double)udrAniAccusation.udrElements[1].intStep / (double)udrAniAccusation.udrElements[1].intMaxSteps);
							Size sz = new Size((int)((double)udrAniAccusation.udrElements[1].bmp.Width * udrAniAccusation.udrElements[1].dblSizeFactor),
												   (int)((double)udrAniAccusation.udrElements[1].bmp.Height * udrAniAccusation.udrElements[1].dblSizeFactor));
							Point ptTL = new Point(9, 82);
							g.DrawImage(udrAniAccusation.udrElements[1].bmp, new Rectangle(ptTL, sz));
						}
						udrAniAccusation.udrNewspaper.cBmp = new classRotatedImage();

						double dblAspectRatioXOverY = (double)bmpNewsPaper.Width / (double)bmpNewsPaper.Height;
						udrAniAccusation.udrNewspaper.dblSizeFactor = 2.0;
						double dblReducedSizeFactor = 1.0 / udrAniAccusation.udrNewspaper.dblSizeFactor;
						int intNewWidth = (int)((double)bmpNewsPaper.Width * dblReducedSizeFactor);
						int intNewHeight = (int)((double)intNewWidth / dblAspectRatioXOverY);
						udrAniAccusation.udrNewspaper.cBmp.createBaseImage(new Bitmap( bmpNewsPaper, intNewWidth, intNewHeight));
						udrAniAccusation.udrNewspaper.cBmp.getImage(1);
						udrAniAccusation.udrNewspaper.cBmp.getImage(2);
						udrAniAccusation.udrNewspaper.cBmp.getImage(3);

						udrAniAccusation.udrNewspaper.ptPos = new Point(bmpBoard.Width / 2, bmpBoard.Height / 2);
						
						udrAniAccusation.intAnimationStep++;
					}
					break;

				default:
						// zoom out newspaper in quick rotation
					udrAniAccusation.intAnimationStep++;
					Bitmap bmpTempSpinningNewspaper = new Bitmap(udrAniAccusation.bmpAccusationBoard);
					using (Graphics g = Graphics.FromImage(bmpTempSpinningNewspaper))
					{
						udrAniAccusation.udrNewspaper.dblSizeFactor *= 1.1;
						udrAniAccusation.udrNewspaper.intImage = (udrAniAccusation.udrNewspaper.intImage + 1) % 16;

						Bitmap bmpCurrentNewspaper = udrAniAccusation.udrNewspaper.cBmp.getImage(udrAniAccusation.udrNewspaper.intImage);
						Size szCurrentNewspaper = new Size((int)(bmpCurrentNewspaper.Width * udrAniAccusation.udrNewspaper.dblSizeFactor),
														   (int)(bmpCurrentNewspaper.Height * udrAniAccusation.udrNewspaper.dblSizeFactor));
						Point ptTLCurrentNewspaper = new Point(udrAniAccusation.udrNewspaper.ptPos.X - szCurrentNewspaper.Width / 2,
															   udrAniAccusation.udrNewspaper.ptPos.Y - szCurrentNewspaper.Height / 2);
						g.DrawImage(bmpCurrentNewspaper, new Rectangle(ptTLCurrentNewspaper, szCurrentNewspaper));
					}
					picBoard.Image = bmpTempSpinningNewspaper;picBoard.Refresh();

					if (udrAniAccusation.udrNewspaper.dblSizeFactor > 15)
					{
						GameOver();
						return;
					}
					break;
			}
			setDelayTimer(10);
		}

		void AnimateAccusation_WithdrawAccusingSuspect()
		{
			if (!udrAniAccusation.bolInit)
			{
				udrAniAccusation.bolInit = true;

				udrAniAccusation.udrElements = new udtAnimationInfo[1];
				Point ptSuspectTL = new Point(15, 420);

				udrAniAccusation.udrElements[0].dblSizeFactor = 1.3;
			
				udrAniAccusation.udrElements[0].bmp = new Bitmap(bmpSuspects[intSuspectTurn]);
				udrAniAccusation.udrElements[0].ptPos = //Point ptSuspectTL = new Point(15, 420);				
					udrAniAccusation.udrElements[0].ptStart = new Point(15 + udrAniAccusation.udrElements[0].bmp.Width / 2, 420 + udrAniAccusation.udrElements[0].bmp.Height / 2);
				udrAniAccusation.udrElements[0].ptEnd = getRoomCenter(enuRooms._numRooms);

				udrAniAccusation.udrElements[0].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[0].ptEnd, udrAniAccusation.udrElements[0].ptStart);
				udrAniAccusation.udrElements[0].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[0].ptEnd, udrAniAccusation.udrElements[0].ptStart);

				udrAniAccusation.udrElements[0].intMaxSteps = 20;
				udrAniAccusation.udrElements[0].intStep = 0;


				udrAniAccusation.intAnimationStep = 0;
			}

			switch (udrAniAccusation.intAnimationStep)
			{
				case 0: // move suspect head to center of screen
					if (udrAniAccusation.udrElements[0].intStep < udrAniAccusation.udrElements[0].intMaxSteps)
					{
						Bitmap bmpTemp = new Bitmap(bmpGameBoard);
						using (Graphics g = Graphics.FromImage(bmpTemp))
						{
							udrAniAccusation.udrElements[0].intStep++;
							double dblPercentageDistanceTravelled = (double)udrAniAccusation.udrElements[0].intStep / (double)udrAniAccusation.udrElements[0].intMaxSteps;
							udrAniAccusation.udrElements[0].ptPos.X = udrAniAccusation.udrElements[0].ptStart.X + (int)(udrAniAccusation.udrElements[0].dblTravelDistance * dblPercentageDistanceTravelled * Math.Cos(udrAniAccusation.udrElements[0].dblTravelAngle));
							udrAniAccusation.udrElements[0].ptPos.Y = udrAniAccusation.udrElements[0].ptStart.Y + (int)(udrAniAccusation.udrElements[0].dblTravelDistance * dblPercentageDistanceTravelled * Math.Sin(udrAniAccusation.udrElements[0].dblTravelAngle));

							int intImageSize = (int)(udrAniAccusation.udrElements[0].bmp.Width * udrAniAccusation.udrElements[0].dblSizeFactor);
							Rectangle recDest = new Rectangle(udrAniAccusation.udrElements[0].ptPos.X - intImageSize / 2, udrAniAccusation.udrElements[0].ptPos.Y - intImageSize / 2, intImageSize, intImageSize);
							Rectangle recSrc = new Rectangle(0, 0, udrAniAccusation.udrElements[0].bmp.Width, udrAniAccusation.udrElements[0].bmp.Height);
							g.DrawImage(udrAniAccusation.udrElements[0].bmp, recDest, recSrc, GraphicsUnit.Pixel);
							udrAniAccusation.udrElements[0].dblSizeFactor *= 1.05;
						}

						picBoard.Image = bmpTemp; picBoard.Refresh();


					}
					else
					{
						udrAniAccusation.intAnimationStep++;
						udrAniAccusation.bmpAccusationForeground = new Bitmap(bmpBoard.Width, bmpBoard.Height);
						using (Graphics g = Graphics.FromImage(udrAniAccusation.bmpAccusationForeground))
						{
							Rectangle recDest, recSrc;

							g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, udrAniAccusation.bmpAccusationForeground.Width, udrAniAccusation.bmpAccusationForeground.Height));

							Bitmap bmpBubble = new Bitmap(Clue_CS2010.Properties.Resources.SuggestionBubble, 300, 500);

							bmpBubble.MakeTransparent(Color.White);
							bmpBubble.RotateFlip(RotateFlipType.Rotate270FlipY);

							bmpBubble.MakeTransparent(Color.White);
							Point ptTL = new Point((udrAniAccusation.bmpAccusationForeground.Width - bmpBubble.Width) / 2, udrAniAccusation.bmpAccusationForeground.Height - bmpBubble.Height);
							recDest = new Rectangle(ptTL, bmpBubble.Size);
							recSrc = new Rectangle(1, 1, bmpBubble.Width - 2, bmpBubble.Height - 2);
							g.DrawImage(bmpBubble, recDest, recSrc, GraphicsUnit.Pixel);

							Bitmap bmpText;
							Font fnt = new System.Drawing.Font("blackadder itc", 36);

							int intTop = 50;
							int intVLineSpacine = 50;
							int intLeftText = 5;

							bmpText = getTextImage("Forgive my indiscretion", fnt);
							recDest = new Rectangle(ptSuggestionBubbleTL.X + intLeftText, ptSuggestionBubbleTL.Y + intTop, bmpText.Width, bmpText.Height);
							recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
							g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

							bmpText = getTextImage("I shall remove ", fnt);
							recDest = new Rectangle(ptSuggestionBubbleTL.X + intLeftText, ptSuggestionBubbleTL.Y + intTop + 2 * intVLineSpacine, bmpText.Width, bmpText.Height);
							recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
							g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

							bmpText = getTextImage("      myself from the game.", fnt);
							recDest = new Rectangle(ptSuggestionBubbleTL.X + intLeftText, ptSuggestionBubbleTL.Y + intTop + 3 * intVLineSpacine, bmpText.Width, bmpText.Height);
							recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
							g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);
						}

						udrAniAccusation.udrElements[0].intStep = 0;
						udrAniAccusation.udrElements[0].intMaxSteps = 80;

						udrAniAccusation.bmpAccusationForeground.MakeTransparent(Color.White);
					}

					break;

				case 1: // write report that accusing suspect has been eliminated & shrink accusing suspect's image
					Bitmap bmpTemp_WriteReport = new Bitmap(bmpGameBoard);
					using (Graphics g = Graphics.FromImage(bmpTemp_WriteReport))
					{
						udrAniAccusation.udrElements[0].intStep++;
						udrAniAccusation.udrElements[0].dblSizeFactor *= .95;

						int intImageSize = (int)(udrAniAccusation.udrElements[0].bmp.Width * udrAniAccusation.udrElements[0].dblSizeFactor);
						if (intImageSize < 1)
							intImageSize = 1;
						Rectangle recDest = new Rectangle(udrAniAccusation.udrElements[0].ptPos.X - intImageSize / 2, udrAniAccusation.udrElements[0].ptPos.Y - intImageSize / 2, intImageSize, intImageSize);
						Rectangle recSrc = new Rectangle(0, 0, udrAniAccusation.udrElements[0].bmp.Width, udrAniAccusation.udrElements[0].bmp.Height);
						g.DrawImage(udrAniAccusation.udrElements[0].bmp, recDest, recSrc, GraphicsUnit.Pixel);

						g.DrawImage(udrAniAccusation.bmpAccusationForeground, new Point(0, 0));
					}
					picBoard.Image = bmpTemp_WriteReport;

					if (udrAniAccusation.udrElements[0].intStep > udrAniAccusation.udrElements[0].intMaxSteps)
					{
						udrAniAccusation.intAnimationStep++;
					}
					break;

				case 2: // quit
					cSuspects[intSuspectTurn].bolEliminated = true;
					cSuspects[intSuspectTurn].removeSuspectFromDoorways();
					eMode = enuMode.endTurn;
					break;
			}

		

			setDelayTimer(10);
		}

		void AnimateAccusation_RetractCards()
		{
			int intSizeFloodlights = 200;
			int intMaxSteps = 15;

			if (!udrAniAccusation.bolInit)
			{
				/// room
				udrAniAccusation.udrElements[(int)enuCardType.room].bmp = cCards[(int)classCard.getECardFromERoom(udrMurder.eRoom)].cBmp.getImage(0);
				udrAniAccusation.udrElements[(int)enuCardType.room].ptStart = udrAniAccusation.udrElements[(int)enuCardType.room].ptPos;
				udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd = getRoomCenter(enuRooms._numRooms);

				udrAniAccusation.udrElements[(int)enuCardType.room].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.room].intStep = 0;

				udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleTurning =
					udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleFacing =
					udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleTurningAttenuation = 0;

				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAcceleration = 0;
				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.room].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.room].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelInitialVelocity = udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelDistance / udrAniAccusation.udrElements[(int)enuCardType.room].intMaxSteps;

				udrAniAccusation.udrElements[(int)enuCardType.room].velTravel.X = (int)(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle));
				udrAniAccusation.udrElements[(int)enuCardType.room].velTravel.Y = (int)(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle));

				/// weapon
				udrAniAccusation.udrElements[(int)enuCardType.weapon].bmp = cCards[(int)classCard.getECardFromEWeapon(udrMurder.eWeapon)].cBmp.getImage(0);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart = udrAniAccusation.udrElements[(int)enuCardType.weapon].ptPos;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd = getRoomCenter(enuRooms._numRooms);

				udrAniAccusation.udrElements[(int)enuCardType.weapon].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].intStep = 0;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleTurning =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleFacing =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleTurningAttenuation = 0;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAcceleration = 0;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelInitialVelocity = udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelDistance / udrAniAccusation.udrElements[(int)enuCardType.weapon].intMaxSteps;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].velTravel.X = (int)(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle));
				udrAniAccusation.udrElements[(int)enuCardType.weapon].velTravel.Y = (int)(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle));

				/// Suspect
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmp = cCards[(int)classCard.getECardFromESuspect(udrMurder.eSuspect)].cBmp.getImage(0);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart = udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptPos;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd = getRoomCenter(enuRooms._numRooms);

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].intStep = 0;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleTurning =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleFacing =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleTurningAttenuation = 0;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAcceleration = 0;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelInitialVelocity = udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelDistance / udrAniAccusation.udrElements[(int)enuCardType.Suspect].intMaxSteps;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].velTravel.X = (int)(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle));
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].velTravel.Y = (int)(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle));

				udrAniAccusation.intAnimationStep = 0;
				udrAniAccusation.bolInit = true;
			}

			Bitmap bmpCard = cCardUnknown.cBmp.getImage(0);
			Bitmap bmpShadeCard = MakeGrayscale3(new Bitmap(cCardUnknown.cBmp.getImage(0)));
			Bitmap bmpTempShade = new Bitmap(udrAniAccusation.bmpShadedAccusationBoard);
			Bitmap bmpTemp = new Bitmap(udrAniAccusation.bmpAccusationBoard);
			bool bolQuit = true;

			using (Graphics gGray = Graphics.FromImage(bmpTempShade))  // draw everything in gray-scale
			{
				using (Graphics gForeground = Graphics.FromImage(bmpTemp)) // used to draw the animated cards in color onto a foreground image of 3 elements (3 ele + 3 cards in color)
				{
					gForeground.DrawImage(udrAniAccusation.bmpAccusationForeground, new Point(0, 0));
					for (enuCardType eTypeCounter = (enuCardType)0; eTypeCounter < enuCardType._numCardTypes; eTypeCounter++)
					{
						udrAniAccusation.udrElements[(int)eTypeCounter].intStep++;
						if (udrAniAccusation.udrElements[(int)eTypeCounter].intStep >= udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps)
						{
							udrAniAccusation.udrElements[(int)eTypeCounter].ptPos = udrAniAccusation.udrElements[(int)eTypeCounter].ptEnd;
						}
						else
						{
							udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X += udrAniAccusation.udrElements[(int)eTypeCounter].velTravel.X;
							udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y += udrAniAccusation.udrElements[(int)eTypeCounter].velTravel.Y;
							bolQuit = false;
						}

						gGray.DrawImage(bmpShadeCard, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height / 2);
						gForeground.DrawImage(bmpCard, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height / 2);
					}
					gGray.DrawImage(udrAniAccusation.bmpAccusationForegroundGray, new Point(0, 0));
				}

				/// we now have 
				///		- a gray scale foreground drawn onto the gray-scale background (3 gray cards + 3 gray elements)
				///		- a color foreground w/ 3 elements + 3 cards
				///	we need to generate a mask for the floodlights
				Point ptFinalFloodLightPos = getRoomCenter(enuRooms._numRooms);
				Bitmap bmpFloodLights_copy = new Bitmap(bmpFloodlights);
				using (Graphics g = Graphics.FromImage(bmpFloodLights_copy))
				{
					bool bolMoveToEnd = (udrAniAccusation.intAnimationStep > intMaxSteps * 4);
					for (int intFloodlightCounter = 0; intFloodlightCounter < udrAniAccusation.udrFloodlights.Length; intFloodlightCounter++)
					{
						g.FillEllipse(br, new Rectangle(udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos.X - intSizeFloodlights, udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos.Y - intSizeFloodlights, 2 * intSizeFloodlights, 2 * intSizeFloodlights));
					}
				}

			endFloodLight:
				bmpFloodLights_copy.MakeTransparent(clrFloordlights);
				// now we also have a blue image with three red circles
				// make red circles transparent
				// superimpose this blue mask on top of colored foreground
				Bitmap bmpMaskedColouredForeground = new Bitmap(bmpTemp);
				using (Graphics g = Graphics.FromImage(bmpMaskedColouredForeground))
					g.DrawImage(bmpFloodLights_copy, new Point(0, 0));

				// make blue transparent (keep colored image only where the transparent red-circles were)
				bmpMaskedColouredForeground.MakeTransparent(clrField);
				// copy these colored circles on top of final output image
				gGray.DrawImage(bmpMaskedColouredForeground, new Point(0, 0));
			}

			picBoard.Image = bmpTempShade;
			udrAniAccusation.intAnimationStep++;
			if (bolQuit)
			{
				eAccusationMode = enuAccuseAnimationMode.withdrawAccusingSuspect;
			}
			setDelayTimer(10);
		}

		void AnimateAccusation_HideCards()
		{
			int intSizeFloodlights = 200;
			if (!udrAniAccusation.bolInit)
			{
				for (int intCardCounter = 0; intCardCounter < udrAniAccusation.udrElements.Length; intCardCounter++)
					udrAniAccusation.udrElements[intCardCounter].intStep = 0;
				udrAniAccusation.bolInit = true;
			}

			Bitmap bmpCard = cCardUnknown.cBmp.getImage(0);
			Bitmap bmpTemp = new Bitmap(udrAniAccusation.bmpAccusationBoard);
			bool bolQuit = true;

			using (Graphics gForeground = Graphics.FromImage(bmpTemp)) // used to draw the animated cards in color onto a foreground image of 3 elements (3 ele + 3 cards in color)
			{
				gForeground.DrawImage(udrAniAccusation.bmpAccusationForeground, new Point(0, 0));
				for (enuCardType eTypeCounter = (enuCardType)0; eTypeCounter < enuCardType._numCardTypes; eTypeCounter++)
				{
					udrAniAccusation.udrElements[(int)eTypeCounter].intStep++;
					int intMidway = udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps / 2;
					if (udrAniAccusation.udrElements[(int)eTypeCounter].intStep > intMidway)
					{
						int intStepsPastMid = udrAniAccusation.udrElements[(int)eTypeCounter].intStep - intMidway;
						double dblPercentageLeft = ((double)intStepsPastMid / (double)intMidway);
						int intWidth = (int)(dblPercentageLeft * (double)udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Width);
						if (intWidth < 1)
							intWidth = 1;
						Bitmap bmpFacedown = new Bitmap(cCardUnknown.cBmp.getImage(0), intWidth, udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height);
						gForeground.DrawImage(bmpFacedown, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - bmpFacedown.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - bmpFacedown.Height / 2);
					}
					else
					{
						double dblPercentageLeft = ((double)(intMidway - udrAniAccusation.udrElements[(int)eTypeCounter].intStep) / (double)intMidway);
						int intWidth = (int)(dblPercentageLeft * (double)cCardUnknown.cBmp.getImage(0).Width);
						if (intWidth < 1)
							intWidth = 1;
						Bitmap bmpFaceup = new Bitmap(udrAniAccusation.udrElements[(int)eTypeCounter].bmp, intWidth, udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height);
						gForeground.DrawImage(bmpFaceup, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - bmpFaceup.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - bmpFaceup.Height / 2);
					}
					if (udrAniAccusation.udrElements[(int)eTypeCounter].intStep < udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps)
						bolQuit = false;
				}
			}

			/// we now have 
			///		- a gray scale foreground drawn onto the gray-scale background ( 3 gray elements)
			///		- a color foreground w/ 3 elements + 3 cards
			///	we need to generate a mask for the floodlights
			Point ptFinalFloodLightPos = getRoomCenter(enuRooms._numRooms);
			Bitmap bmpFloodLights_copy = new Bitmap(bmpFloodlights);
			using (Graphics g = Graphics.FromImage(bmpFloodLights_copy))
				g.FillEllipse(br, new Rectangle(udrAniAccusation.udrFloodlights[0].ptPos.X - intSizeFloodlights, udrAniAccusation.udrFloodlights[0].ptPos.Y - intSizeFloodlights, 2 * intSizeFloodlights, 2 * intSizeFloodlights));

			bmpFloodLights_copy.MakeTransparent(clrFloordlights);
			// now we also have a blue image with three red circles
			// make red circles transparent
			// superimpose this blue mask on top of colored foreground
			Bitmap bmpMaskedColouredForeground = new Bitmap(bmpTemp);
			using (Graphics g = Graphics.FromImage(bmpMaskedColouredForeground))
				g.DrawImage(bmpFloodLights_copy, new Point(0, 0));

			// make blue transparent (keep colored image only where the transparent red-circles were)
			bmpMaskedColouredForeground.MakeTransparent(clrField);

			// copy the circle of colored image (flood light) on top of final output image
			Bitmap bmpTempShade = new Bitmap(udrAniAccusation.bmpShadedAccusationBoard);
			using (Graphics gGray = Graphics.FromImage(bmpTempShade))  // draw everything in gray-scale
				gGray.DrawImage(bmpMaskedColouredForeground, new Point(0, 0));

			picBoard.Image = bmpTempShade; picBoard.Refresh();
			udrAniAccusation.intAnimationStep++;
			if (bolQuit)
			{
				eAccusationMode = enuAccuseAnimationMode.retractCards;
			}
			setDelayTimer(10);
		}		

		void AnimateAccusation_ShowCards()
		{
			int intSizeFloodlights = 200;
			int intMaxSteps = 30;

			if (!udrAniAccusation.bolInit)
			{
				udrAniAccusation.bolInit = true;
				/// room
				udrAniAccusation.udrElements[(int)enuCardType.room].bmp = cCards[(int)classCard.getECardFromERoom(udrMurder.eRoom)].cBmp.getImage(0);
				udrAniAccusation.udrElements[(int)enuCardType.room].ptStart =
					udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd =
					udrAniAccusation.udrElements[(int)enuCardType.room].ptPos;

				udrAniAccusation.udrElements[(int)enuCardType.room].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.room].intStep = 0;

				udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleTurning =
					udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleFacing =
					udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleTurningAttenuation = 0;

				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAcceleration =
					udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle =
					udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelDistance =
					udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelInitialVelocity = 0;

				udrAniAccusation.udrElements[(int)enuCardType.room].velTravel.X = (int)(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle));
				udrAniAccusation.udrElements[(int)enuCardType.room].velTravel.Y = (int)(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle));

				/// Suspect
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmp = cCards[(int)classCard.getECardFromESuspect(udrMurder.eSuspect)].cBmp.getImage(0);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptPos;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].intStep = 0;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleTurning =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleFacing =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleTurningAttenuation = 0;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAcceleration =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelDistance =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelInitialVelocity = 0;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].velTravel.X = (int)(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle));
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].velTravel.Y = (int)(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle));

				/// weapon
				udrAniAccusation.udrElements[(int)enuCardType.weapon].bmp = cCards[(int)classCard.getECardFromEWeapon(udrMurder.eWeapon)].cBmp.getImage(0);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].ptPos;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].intStep = 0;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleTurning =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleFacing =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleTurningAttenuation = 0;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAcceleration =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelDistance =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelInitialVelocity = 0;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].velTravel.X = (int)(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle));
				udrAniAccusation.udrElements[(int)enuCardType.weapon].velTravel.Y = (int)(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle));

				udrAniAccusation.intAnimationStep = 0;
				udrAniAccusation.bolInit = true;

				// prepare shaded accusation board
				udrAniAccusation.bmpShadedAccusationBoard = MakeGrayscale3(bmpGameBoard);
				using (Graphics g = Graphics.FromImage(udrAniAccusation.bmpShadedAccusationBoard))
				{
					g.DrawImage(udrAniAccusation.bmpAccusationForegroundGray, new Point(0, 0));

					// draw center rectangle w/o cards
					Rectangle recDest = new Rectangle(279, 231, 418 - 279, 426 - 231);
					g.FillRectangle(new SolidBrush(bmpBoard.GetPixel(bmpBoard.Width / 2, bmpBoard.Height / 2)), recDest);

					Bitmap bmpAccusingSuspectAndBubble = getAccusingSuspectAndBubbleImage((enuSuspects)intSuspectTurn, udrAniAccusation.udrAccusation);
					bmpAccusingSuspectAndBubble.MakeTransparent(Color.White);
					g.DrawImage(bmpAccusingSuspectAndBubble, new Point(0, 0));
				}

				// prepare accusation board
				udrAniAccusation.bmpAccusationBoard = new Bitmap (bmpGameBoard);
				using (Graphics g = Graphics.FromImage(udrAniAccusation.bmpAccusationBoard))
				{
					g.DrawImage(udrAniAccusation.bmpAccusationForeground, new Point(0, 0));

					// draw center rectangle w/o cards
					Rectangle recDest = new Rectangle(279, 231, 418 - 279, 426 - 231);
					g.FillRectangle(new SolidBrush(bmpBoard.GetPixel(bmpBoard.Width / 2, bmpBoard.Height / 2)), recDest);

					Bitmap bmpAccusingSuspectAndBubble = getAccusingSuspectAndBubbleImage((enuSuspects)intSuspectTurn, udrAniAccusation.udrAccusation);
					bmpAccusingSuspectAndBubble.MakeTransparent(Color.White);
					g.DrawImage(bmpAccusingSuspectAndBubble, new Point(0, 0));
				}
			}

			Bitmap bmpCard = cCardUnknown.cBmp.getImage(0);
			Bitmap bmpTemp = new Bitmap(udrAniAccusation.bmpAccusationBoard);
			bool bolQuit = true;
			
			using (Graphics gForeground = Graphics.FromImage(bmpTemp)) // used to draw the animated cards in color onto a foreground image of 3 elements (3 ele + 3 cards in color)
			{
				gForeground.DrawImage(udrAniAccusation.bmpAccusationForeground, new Point(0, 0));
				for (enuCardType eTypeCounter = (enuCardType)0; eTypeCounter < enuCardType._numCardTypes; eTypeCounter++)
				{
					udrAniAccusation.udrElements[(int)eTypeCounter].intStep++;
					int intMidway = udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps / 2;
					if (udrAniAccusation.udrElements[(int)eTypeCounter].intStep > intMidway)
					{
						int intStepsPastMid = udrAniAccusation.udrElements[(int)eTypeCounter].intStep - intMidway;
						double dblPercentageLeft = ((double)intStepsPastMid / (double)intMidway);
						int intWidth = (int)(dblPercentageLeft * (double)udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Width);
						if (intWidth<1)
							intWidth = 1;
						Bitmap bmpFaceup = new Bitmap(udrAniAccusation.udrElements[(int)eTypeCounter].bmp, intWidth, udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height);
						gForeground.DrawImage(bmpFaceup, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - bmpFaceup.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - bmpFaceup.Height / 2);
					}
					else
					{
						double dblPercentageLeft = ((double)(intMidway - udrAniAccusation.udrElements[(int)eTypeCounter].intStep) / (double)intMidway);
						int intWidth = (int)(dblPercentageLeft * (double)cCardUnknown.cBmp.getImage(0).Width);
						if (intWidth < 1)
							intWidth = 1;
						Bitmap bmpFacedown = new Bitmap(cCardUnknown.cBmp.getImage(0), intWidth, udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height);
						gForeground.DrawImage(bmpFacedown, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - bmpFacedown.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - bmpFacedown.Height / 2);
					}
					if (udrAniAccusation.udrElements[(int)eTypeCounter].intStep < udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps)
						bolQuit = false;
				}
			}

			/// we now have 
			///		- a gray scale foreground drawn onto the gray-scale background ( 3 gray elements)
			///		- a color foreground w/ 3 elements + 3 cards
			///	we need to generate a mask for the floodlights
			Point ptFinalFloodLightPos = getRoomCenter(enuRooms._numRooms);
			Bitmap bmpFloodLights_copy = new Bitmap(bmpFloodlights);
			using (Graphics g = Graphics.FromImage(bmpFloodLights_copy))
				g.FillEllipse(br, new Rectangle(udrAniAccusation.udrFloodlights[0].ptPos.X - intSizeFloodlights, udrAniAccusation.udrFloodlights[0].ptPos.Y - intSizeFloodlights, 2 * intSizeFloodlights, 2 * intSizeFloodlights));
			
			bmpFloodLights_copy.MakeTransparent(clrFloordlights);
			// now we also have a blue image with three red circles
			// make red circles transparent
			// superimpose this blue mask on top of colored foreground
			Bitmap bmpMaskedColouredForeground = new Bitmap(bmpTemp);
			using (Graphics g = Graphics.FromImage(bmpMaskedColouredForeground))
				g.DrawImage(bmpFloodLights_copy, new Point(0, 0));

			// make blue transparent (keep colored image only where the transparent red-circles were)
			bmpMaskedColouredForeground.MakeTransparent(clrField);

			// copy the circle of colored image (flood light) on top of final output image
			Bitmap bmpTempShade = new Bitmap(udrAniAccusation.bmpShadedAccusationBoard);
			using (Graphics gGray = Graphics.FromImage(bmpTempShade))  // draw everything in gray-scale
				gGray.DrawImage(bmpMaskedColouredForeground, new Point(0, 0));

			picBoard.Image = bmpTempShade; picBoard.Refresh();
			udrAniAccusation.intAnimationStep++;
			if (bolQuit)
			{
				if (compareTwoMurderScenes(udrAniAccusation.udrAccusation, udrMurder))
				{ // accusation is correct
					eAccusationMode = enuAccuseAnimationMode.showNewspaper;
					udrAniAccusation.bmpAccusationBoard = new Bitmap(picBoard.Image);
				}
				else 
				{ // accusation is false
					eAccusationMode = enuAccuseAnimationMode.hideCards;
				}
			}
			setDelayTimer(10);
		}

		bool compareTwoMurderScenes(udtMurder udrMurderA, udtMurder udrMurderB)
		{
			return (udrMurderA.eSuspect == udrMurderB.eSuspect
					&& udrMurderA.eRoom == udrMurderB.eRoom
					&& udrMurderA.eWeapon == udrMurderB.eWeapon);
		}

		void AnimateAccusation_PrepareToShowCards()
		{
			int intSizeFloodlights = 200;
			int intMaxSteps = 15;

			if (!udrAniAccusation.bolInit)
			{
				/// room
				udrAniAccusation.udrElements[(int)enuCardType.room].bmp = cCards[(int)classCard.getECardFromERoom(udrMurder.eRoom)].cBmp.getImage(0);
				udrAniAccusation.udrElements[(int)enuCardType.room].ptPos =
					udrAniAccusation.udrElements[(int)enuCardType.room].ptStart = getRoomCenter(enuRooms._numRooms);
				udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd = new Point(udrAniAccusation.udrElements[(int)enuCardType.room].ptStart.X - udrAniAccusation.udrElements[(int)enuCardType.room].bmp.Width, getRoomCenter(enuRooms._numRooms).Y);

				udrAniAccusation.udrElements[(int)enuCardType.room].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.room].intStep = 0;

				udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleTurning =
					udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleFacing =
					udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleTurningAttenuation = 0;

				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAcceleration = 0;
				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.room].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.room].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelInitialVelocity = udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelDistance / udrAniAccusation.udrElements[(int)enuCardType.room].intMaxSteps;

				udrAniAccusation.udrElements[(int)enuCardType.room].velTravel.X = (int)(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle));
				udrAniAccusation.udrElements[(int)enuCardType.room].velTravel.Y = (int)(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle));

				/// weapon
				udrAniAccusation.udrElements[(int)enuCardType.weapon].bmp = cCards[(int)classCard.getECardFromEWeapon(udrMurder.eWeapon)].cBmp.getImage(0);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].ptPos =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart = getRoomCenter(enuRooms._numRooms);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd = new Point(udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart.X + udrAniAccusation.udrElements[(int)enuCardType.weapon].bmp.Width, getRoomCenter(enuRooms._numRooms).Y);

				udrAniAccusation.udrElements[(int)enuCardType.weapon].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].intStep = 0;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleTurning =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleFacing =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleTurningAttenuation = 0;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAcceleration = 0;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelInitialVelocity = udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelDistance / udrAniAccusation.udrElements[(int)enuCardType.weapon].intMaxSteps;

				udrAniAccusation.udrElements[(int)enuCardType.weapon].velTravel.X = (int)(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle));
				udrAniAccusation.udrElements[(int)enuCardType.weapon].velTravel.Y = (int)(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle));

				/// Suspect
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmp = cCards[(int)classCard.getECardFromESuspect(udrMurder.eSuspect)].cBmp.getImage(0);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptPos =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart = getRoomCenter(enuRooms._numRooms);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd = new Point(udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart.X, getRoomCenter(enuRooms._numRooms).Y);

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].intStep = 0;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleTurning =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleFacing =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleTurningAttenuation = 0;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAcceleration = 0;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelInitialVelocity = udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelDistance / udrAniAccusation.udrElements[(int)enuCardType.Suspect].intMaxSteps;

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].velTravel.X = (int)(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle));
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].velTravel.Y = (int)(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle));

				udrAniAccusation.udrFloodlights = new udtAnimationInfo[1];
				for (int intFloodlightCounter = 0; intFloodlightCounter < udrAniAccusation.udrFloodlights.Length; intFloodlightCounter++)
				{
					udrAniAccusation.udrFloodlights[intFloodlightCounter].ptStart 
						= new Point(((int)rnd.NextDouble() * 1000) % 2 == 0 ? bmpBoard.Width + 50 : -50, 
									 (int)rnd.NextDouble() * bmpBoard.Height);
					udrAniAccusation.udrFloodlights[intFloodlightCounter].intMaxSteps =
						udrAniAccusation.udrFloodlights[intFloodlightCounter].intStep = 0;
				}

				udrAniAccusation.intAnimationStep = 0;
				udrAniAccusation.bolInit = true;	
			}

			Bitmap bmpCard = cCardUnknown.cBmp.getImage(0);
			Bitmap bmpShadeCard = MakeGrayscale3(new Bitmap(cCardUnknown.cBmp.getImage(0)));
			Bitmap bmpTempShade = new Bitmap(udrAniAccusation.bmpShadedAccusationBoard);
			Bitmap bmpTemp = new Bitmap(udrAniAccusation.bmpAccusationBoard);
			bool bolQuit = false;
				
			using (Graphics gGray = Graphics.FromImage(bmpTempShade))  // draw everything in gray-scale
			{
				using (Graphics gForeground = Graphics.FromImage(bmpTemp)) // used to draw the animated cards in color onto a foreground image of 3 elements (3 ele + 3 cards in color)
				{
					gForeground.DrawImage(udrAniAccusation.bmpAccusationForeground, new Point(0, 0));
					for (enuCardType eTypeCounter = (enuCardType)0; eTypeCounter < enuCardType._numCardTypes; eTypeCounter++)
					{
						if (udrAniAccusation.intAnimationStep > 20)
						{
							udrAniAccusation.udrElements[(int)eTypeCounter].intStep++;
							if (udrAniAccusation.udrElements[(int)eTypeCounter].intStep >= udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps)
							{
								udrAniAccusation.udrElements[(int)eTypeCounter].ptPos = udrAniAccusation.udrElements[(int)eTypeCounter].ptEnd;
							}
							else
							{
								udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X += udrAniAccusation.udrElements[(int)eTypeCounter].velTravel.X;
								udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y += udrAniAccusation.udrElements[(int)eTypeCounter].velTravel.Y;
							}
						}

						gGray.DrawImage(bmpShadeCard, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height / 2);
						gForeground.DrawImage(bmpCard, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height / 2);
					}
					gGray.DrawImage(udrAniAccusation.bmpAccusationForegroundGray, new Point(0, 0));
				}

				/// we now have 
				///		- a gray scale foreground drawn onto the gray-scale background (3 gray cards + 3 gray elements)
				///		- a color foreground w/ 3 elements + 3 cards
				///	we need to generate a mask for the floodlights
				Point ptFinalFloodLightPos = getRoomCenter(enuRooms._numRooms);
				Bitmap bmpFloodLights_copy = new Bitmap(bmpFloodlights);
				using (Graphics g = Graphics.FromImage(bmpFloodLights_copy))
				{
					bool bolMoveToEnd = (udrAniAccusation.intAnimationStep > intMaxSteps* 4);
					for (int intFloodlightCounter = 0; intFloodlightCounter < udrAniAccusation.udrFloodlights.Length; intFloodlightCounter++)
					{
						if (udrAniAccusation.udrFloodlights[intFloodlightCounter].intStep >= udrAniAccusation.udrFloodlights[intFloodlightCounter].intMaxSteps)
						{
							udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelDistance = 0;
							udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos = udrAniAccusation.udrFloodlights[intFloodlightCounter].ptEnd;
							if ((bolMoveToEnd && udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos == ptFinalFloodLightPos))
							{
								g.FillEllipse(br, new Rectangle(udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos.X - intSizeFloodlights, udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos.Y - intSizeFloodlights, 2 * intSizeFloodlights, 2 * intSizeFloodlights));
								bolQuit = true;
								goto endFloodLight;
							}
							bool bolLoop = true;
							while (udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelDistance < 200 && bolLoop)
							{
								udrAniAccusation.udrFloodlights[intFloodlightCounter].intStep = 0;
								udrAniAccusation.udrFloodlights[intFloodlightCounter].ptStart = udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos;
								if (bolMoveToEnd)
									udrAniAccusation.udrFloodlights[intFloodlightCounter].ptEnd = ptFinalFloodLightPos;
								else
									udrAniAccusation.udrFloodlights[intFloodlightCounter].ptEnd = new Point((int)(rnd.NextDouble() * 10000) % (int)(bmpBoard.Width*2.0/3.0) + (int)(bmpBaize.Width * 1.0/6.0), (int)(rnd.NextDouble() * 10000) % (int)(bmpBoard.Height * .4) + (int)(bmpBoard.Height * .1));
								udrAniAccusation.udrFloodlights[intFloodlightCounter].dblAngleFacing =
									udrAniAccusation.udrFloodlights[intFloodlightCounter].dblAngleTurning =
									udrAniAccusation.udrFloodlights[intFloodlightCounter].dblAngleTurningAttenuation = 0;
								udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrFloodlights[intFloodlightCounter].ptEnd, udrAniAccusation.udrFloodlights[intFloodlightCounter].ptStart);
								udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrFloodlights[intFloodlightCounter].ptEnd, udrAniAccusation.udrFloodlights[intFloodlightCounter].ptStart);
								int intStepSize = 20;
								if (udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelDistance < intStepSize)
								{
									udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos = udrAniAccusation.udrFloodlights[intFloodlightCounter].ptEnd;
									bolLoop = false;
								}
								else
								{
									udrAniAccusation.udrFloodlights[intFloodlightCounter].intMaxSteps = (int)(udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelDistance / 20);
									udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelInitialVelocity = udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelDistance / udrAniAccusation.udrFloodlights[intFloodlightCounter].intMaxSteps;

									udrAniAccusation.udrFloodlights[intFloodlightCounter].velTravel.X = (int)(udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelInitialVelocity * Math.Cos(udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelAngle));
									udrAniAccusation.udrFloodlights[intFloodlightCounter].velTravel.Y = (int)(udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelInitialVelocity * Math.Sin(udrAniAccusation.udrFloodlights[intFloodlightCounter].dblTravelAngle));
									bolLoop = false;
								}
							}
						}
						udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos.X += udrAniAccusation.udrFloodlights[intFloodlightCounter].velTravel.X;
						udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos.Y += udrAniAccusation.udrFloodlights[intFloodlightCounter].velTravel.Y;
						udrAniAccusation.udrFloodlights[intFloodlightCounter].intStep++;

						g.FillEllipse(br, new Rectangle(udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos.X - intSizeFloodlights, udrAniAccusation.udrFloodlights[intFloodlightCounter].ptPos.Y - intSizeFloodlights, 2 * intSizeFloodlights, 2 * intSizeFloodlights));
					}
				}

			endFloodLight:
				bmpFloodLights_copy.MakeTransparent(clrFloordlights);
				// now we also have a blue image with three red circles
				// make red circles transparent
				// superimpose this blue mask on top of colored foreground
				Bitmap bmpMaskedColouredForeground = new Bitmap(bmpTemp);
				using (Graphics g = Graphics.FromImage(bmpMaskedColouredForeground))
					g.DrawImage(bmpFloodLights_copy, new Point (0,0));

				// make blue transparent (keep colored image only where the transparent red-circles were)
				bmpMaskedColouredForeground.MakeTransparent(clrField);
				// copy these colored circles on top of final output image
				gGray.DrawImage(bmpMaskedColouredForeground, new Point(0, 0));
			}

			picBoard.Image = bmpTempShade;
			udrAniAccusation.intAnimationStep++;
			if (bolQuit)
			{
				if (cSuspects[intSuspectTurn].bolPlayerControlled
					|| compareTwoMurderScenes(udrAniAccusation.udrAccusation, udrMurder))
				{
					eAccusationMode = enuAccuseAnimationMode.showCards;
				}
				else
				{
					eAccusationMode = enuAccuseAnimationMode.withdrawAccusingSuspect;
				}
			}
			setDelayTimer(10);
		}

		/// <summary>
		///  copied from http://www.switchonthecode.com/tutorials/csharp-tutorial-convert-a-color-image-to-grayscale
		/// </summary>
		/// <param name="original"></param>
		/// <returns></returns>
		public Bitmap MakeGrayscale3(Bitmap original)
		{
			//create a blank bitmap the same size as original
			Bitmap newBitmap = new Bitmap(original.Width, original.Height);

			//get a graphics object from the new image
			Graphics g = Graphics.FromImage(newBitmap);

			//create the grayscale ColorMatrix
			ColorMatrix colorMatrix = new ColorMatrix(new float[][] {
																	new float[] {.3f, .3f, .3f, 0, 0},
																	new float[] {.59f, .59f, .59f, 0, 0},
																	new float[] {.11f, .11f, .11f, 0, 0},
																	new float[] {0, 0, 0, 1, 0},
																	new float[] {0, 0, 0, 0, 1}
																	}
													 );

			//create some image attributes
			ImageAttributes attributes = new ImageAttributes();

			//set the color matrix attribute
			attributes.SetColorMatrix(colorMatrix);

			//draw the original image on the new image
			//using the grayscale color matrix
			g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
			   0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);

			//dispose the Graphics object
			g.Dispose();
			return newBitmap;
		}

		void AnimateAccusation_drawAccusation()
		{
			if (!udrAniAccusation.bolInit)
			{
				udrAniAccusation.bolInit = true;

				btnAccuse_Ok.Visible = false;
				cLibPicTrayRooms.Visible =
					cLibPicTrayRooms.tmrRotate.Enabled = false;
				cLibPicTrayWeapons.Visible =
					cLibPicTrayWeapons.tmrRotate.Enabled = false;
				cLibPicTraySuspects.Visible =
					cLibPicTraySuspects.tmrRotate.Enabled = false;

				udrAniAccusation.bmpAccusationBoard = new Bitmap(picBoard.Image);
				udrAniAccusation.bmpShadedAccusationBoard = MakeGrayscale3(udrAniAccusation.bmpAccusationBoard);

				/// draw accusing suspect and bubble onto base image
				Bitmap bmpAccusingSuspectImageAndBubble = getAccusingSuspectAndBubbleImage((enuSuspects)intSuspectTurn, udrAniAccusation.udrAccusation);
				bmpAccusingSuspectImageAndBubble.MakeTransparent(Color.White);

				using (Graphics g = Graphics.FromImage(udrAniAccusation.bmpAccusationBoard))
					g.DrawImage(bmpAccusingSuspectImageAndBubble, new Point(0, 0));

				using (Graphics g = Graphics.FromImage(udrAniAccusation.bmpShadedAccusationBoard))
					g.DrawImage(bmpAccusingSuspectImageAndBubble, new Point(0, 0));

				int intImageSize = 200;
				int intSpaceBetweenRestingImages = (int)(intImageSize * .84);
				int intEndTop = (int)(intImageSize * .55);
				int intMaxSteps = 20;

				
					udrAniAccusation.udrElements = new udtAnimationInfo[3];
				// room
				udrAniAccusation.udrElements[(int)enuCardType.room].ptPos =
					udrAniAccusation.udrElements[(int)enuCardType.room].ptStart = new Point(-50, -50);
				udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd = new Point((int)(bmpBoard.Width * .5) -intSpaceBetweenRestingImages , intEndTop);
				udrAniAccusation.udrElements[(int)enuCardType.room].intMaxSteps = (int)(intMaxSteps*1.5);
				udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleFacing = 0;
				udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleTurning = 0;
				udrAniAccusation.udrElements[(int)enuCardType.room].dblAngleTurningAttenuation = 0;
				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAcceleration = 0;
				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.room].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.room].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[(int)enuCardType.room].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.room].ptStart);
				
				udrAniAccusation.udrElements[(int)enuCardType.room].bmpGray =MakeGrayscale3( new Bitmap(bmpRooms[(int)udrAniAccusation.udrAccusation.eRoom], intImageSize, intImageSize));
				// this rectangle corrects any errors generated in resizing image that would leave a trailing line on the edges
				using (Graphics g = Graphics.FromImage(udrAniAccusation.udrElements[(int)enuCardType.room].bmpGray))
					g.DrawRectangle(new Pen(udrAniAccusation.udrElements[(int)enuCardType.room].bmpGray.GetPixel(0, 0), 2), new Rectangle(0, 0, intImageSize - 1, intImageSize - 1));
				udrAniAccusation.udrElements[(int)enuCardType.room].bmpGray.MakeTransparent(udrAniAccusation.udrElements[(int)enuCardType.room].bmpGray.GetPixel(0, 0));

				udrAniAccusation.udrElements[(int)enuCardType.room].bmp = new Bitmap(bmpRooms[(int)udrAniAccusation.udrAccusation.eRoom], intImageSize, intImageSize);
				// this rectangle corrects any errors generated in resizing image that would leave a trailing line on the edges
				using (Graphics g = Graphics.FromImage(udrAniAccusation.udrElements[(int)enuCardType.room].bmp))
					g.DrawRectangle(new Pen(udrAniAccusation.udrElements[(int)enuCardType.room].bmp.GetPixel(0, 0), 2), new Rectangle(0, 0, intImageSize - 1, intImageSize - 1));
				udrAniAccusation.udrElements[(int)enuCardType.room].bmp.MakeTransparent(udrAniAccusation.udrElements[(int)enuCardType.room].bmp.GetPixel(0, 0));
				
				udrAniAccusation.udrElements[(int)enuCardType.room].intStep = 0;

				// suspect
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptPos =
					udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart = new Point(bmpBoard.Width/2, -50);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd = new Point((int)(bmpBoard.Width * .5), intEndTop+20);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].intMaxSteps = intMaxSteps;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleFacing = 0;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleTurning = 0;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblAngleTurningAttenuation = 0;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAcceleration = 0;
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.Suspect].ptStart);
					
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmpGray =MakeGrayscale3( new Bitmap(bmpSuspects[(int)udrAniAccusation.udrAccusation.eSuspect], intImageSize, intImageSize));
				// this rectangle corrects any errors generated in resizing image that would leave a trailing line on the edges
				using (Graphics g = Graphics.FromImage(udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmpGray))
					g.DrawRectangle(new Pen(udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmpGray.GetPixel(0, 0),2), new Rectangle(0, 0, intImageSize-1, intImageSize-1));
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmpGray.MakeTransparent(udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmpGray.GetPixel(0, 0));

				udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmp = new Bitmap(bmpSuspects[(int)udrAniAccusation.udrAccusation.eSuspect], intImageSize, intImageSize);
				// this rectangle corrects any errors generated in resizing image that would leave a trailing line on the edges
				using (Graphics g = Graphics.FromImage(udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmp))
					g.DrawRectangle(new Pen(udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmp.GetPixel(0, 0), 2), new Rectangle(0, 0, intImageSize - 1, intImageSize - 1));
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmp.MakeTransparent(udrAniAccusation.udrElements[(int)enuCardType.Suspect].bmp.GetPixel(0, 0));
				
				udrAniAccusation.udrElements[(int)enuCardType.Suspect].intStep = 0;

				// weapon
				udrAniAccusation.udrElements[(int)enuCardType.weapon].ptPos =
					udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart = new Point(bmpBoard.Width +50, -50);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd = new Point((int)(bmpBoard.Width * .5) + intSpaceBetweenRestingImages , intEndTop);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].intMaxSteps = (int)(intMaxSteps*1.5);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleFacing = 0;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleTurning = 0;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblAngleTurningAttenuation = 0;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAcceleration = 0;
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelAngle = classMath.arcTan(udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart);
				udrAniAccusation.udrElements[(int)enuCardType.weapon].dblTravelDistance = classMath.distanceBetweenTwoPoints(udrAniAccusation.udrElements[(int)enuCardType.weapon].ptEnd, udrAniAccusation.udrElements[(int)enuCardType.weapon].ptStart);
				
				udrAniAccusation.udrElements[(int)enuCardType.weapon].bmpGray =MakeGrayscale3( new Bitmap(bmpWeapons_PicTray[(int)udrAniAccusation.udrAccusation.eWeapon], intImageSize, intImageSize));
				// this rectangle corrects any errors generated in resizing image that would leave a trailing line on the edges
				using (Graphics g = Graphics.FromImage(udrAniAccusation.udrElements[(int)enuCardType.weapon].bmpGray))
					g.DrawRectangle(new Pen(udrAniAccusation.udrElements[(int)enuCardType.weapon].bmpGray.GetPixel(0, 0), 2), new Rectangle(0, 0, intImageSize - 1, intImageSize - 1));
				udrAniAccusation.udrElements[(int)enuCardType.weapon].bmpGray.MakeTransparent(udrAniAccusation.udrElements[(int)enuCardType.weapon].bmpGray.GetPixel(0, 0));

				udrAniAccusation.udrElements[(int)enuCardType.weapon].bmp = new Bitmap(bmpWeapons_PicTray[(int)udrAniAccusation.udrAccusation.eWeapon], intImageSize, intImageSize);
				// this rectangle corrects any errors generated in resizing image that would leave a trailing line on the edges
				using (Graphics g = Graphics.FromImage(udrAniAccusation.udrElements[(int)enuCardType.weapon].bmp))
					g.DrawRectangle(new Pen(udrAniAccusation.udrElements[(int)enuCardType.weapon].bmp.GetPixel(0, 0), 2), new Rectangle(0, 0, intImageSize - 1, intImageSize - 1));
				udrAniAccusation.udrElements[(int)enuCardType.weapon].bmp.MakeTransparent(udrAniAccusation.udrElements[(int)enuCardType.weapon].bmp.GetPixel(0, 0));
				
				udrAniAccusation.udrElements[(int)enuCardType.weapon].intStep = 0;
			}

			Bitmap bmpTemp = new Bitmap(udrAniAccusation.bmpShadedAccusationBoard);
			bool bolQuitDraw = true;
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				for (enuCardType eTypeCounter = (enuCardType)0; eTypeCounter < enuCardType._numCardTypes; eTypeCounter++)
				{
					udrAniAccusation.udrElements[(int)eTypeCounter].intStep++;
					if (udrAniAccusation.udrElements[(int)eTypeCounter].intStep < udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps)
						bolQuitDraw = false;
					else
						udrAniAccusation.udrElements[(int)eTypeCounter].intStep = udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps;
					udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X = udrAniAccusation.udrElements[(int)eTypeCounter].ptStart.X + (int)(udrAniAccusation.udrElements[(int)eTypeCounter].dblTravelDistance * ((double)udrAniAccusation.udrElements[(int)eTypeCounter].intStep / (double)udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps) * Math.Cos(udrAniAccusation.udrElements[(int)eTypeCounter].dblTravelAngle));
					udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y = udrAniAccusation.udrElements[(int)eTypeCounter].ptStart.Y + (int)(udrAniAccusation.udrElements[(int)eTypeCounter].dblTravelDistance * ((double)udrAniAccusation.udrElements[(int)eTypeCounter].intStep / (double)udrAniAccusation.udrElements[(int)eTypeCounter].intMaxSteps) * Math.Sin(udrAniAccusation.udrElements[(int)eTypeCounter].dblTravelAngle));

					Point ptTL = new Point(udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height / 2);
					g.DrawImage(udrAniAccusation.udrElements[(int)eTypeCounter].bmpGray, ptTL.X, ptTL.Y);
				}
			}

			picBoard.Image = bmpTemp; picBoard.Refresh();

			if (bolQuitDraw)
			{
				// draw the three elements in the foreground (base Accusation image has accusing-suspect & bubble)
				// gray foreground
				udrAniAccusation.bmpAccusationForegroundGray = new Bitmap(udrAniAccusation.bmpAccusationBoard.Width, udrAniAccusation.bmpAccusationBoard.Height);

				using (Graphics g = Graphics.FromImage(udrAniAccusation.bmpAccusationForegroundGray))
				{
					g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, udrAniAccusation.bmpAccusationForegroundGray.Width, udrAniAccusation.bmpAccusationForegroundGray.Height));


					for (enuCardType eTypeCounter = (enuCardType)0; eTypeCounter < enuCardType._numCardTypes; eTypeCounter++)
						g.DrawImage(udrAniAccusation.udrElements[(int)eTypeCounter].bmpGray, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height / 2);
				}

				udrAniAccusation.bmpAccusationForegroundGray.MakeTransparent(Color.White);

				// colored foreground
				udrAniAccusation.bmpAccusationForeground = new Bitmap(udrAniAccusation.bmpAccusationBoard.Width, udrAniAccusation.bmpAccusationBoard.Height);

				using (Graphics g = Graphics.FromImage(udrAniAccusation.bmpAccusationForeground))
				{
					g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, udrAniAccusation.bmpAccusationForeground.Width, udrAniAccusation.bmpAccusationForeground.Height));

					for (enuCardType eTypeCounter = (enuCardType)0; eTypeCounter < enuCardType._numCardTypes; eTypeCounter++)
						g.DrawImage(udrAniAccusation.udrElements[(int)eTypeCounter].bmp, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.X - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Width / 2, udrAniAccusation.udrElements[(int)eTypeCounter].ptPos.Y - udrAniAccusation.udrElements[(int)eTypeCounter].bmp.Height / 2);
				}
				udrAniAccusation.bmpAccusationForeground.MakeTransparent(Color.White);

				eAccusationMode = enuAccuseAnimationMode.prepareToShowCards;
			}
			setDelayTimer(100);
		}

		Bitmap getAccusingSuspectAndBubbleImage(enuSuspects eSuspectMakingAccusation, udtMurder udrAccusation)
		{
			Bitmap bmpRetVal = new Bitmap(udrAniAccusation.bmpAccusationBoard.Width, udrAniAccusation.bmpAccusationBoard.Height);
						
			using (Graphics g = Graphics.FromImage(bmpRetVal))
			{
				g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, bmpRetVal.Width, bmpRetVal.Height));

				Rectangle recDest = new Rectangle(279, 252, 139, 100);
				Rectangle recSrc = new Rectangle(0, 0, 139, 100);
							
				Point ptSuspectTL = new Point(15, 420);
				double dblSuspectImageFactor = 1.3;
				int intSuspectImageSize = (int)(bmpSuspects[(int)eSuspectMakingAccusation].Width * dblSuspectImageFactor);
				ptSuggestionBubbleTL = new Point(ptSuspectTL.X + intSuspectImageSize-50, 405);
				recDest = new Rectangle(ptSuspectTL.X, ptSuspectTL.Y, intSuspectImageSize, intSuspectImageSize);
				recSrc = new Rectangle(0, 0, bmpSuspects[(int)eSuspectMakingAccusation].Width, bmpSuspects[(int)eSuspectMakingAccusation].Height);
				g.DrawImage(bmpSuspects[(int)eSuspectMakingAccusation], recDest, recSrc, GraphicsUnit.Pixel);

				recDest = new Rectangle(ptSuggestionBubbleTL.X, ptSuggestionBubbleTL.Y, bmpSuggestionBubble.Width+50, bmpSuggestionBubble.Height-60);
				recSrc = new Rectangle(0, 0, bmpSuggestionBubble.Width, bmpSuggestionBubble.Height);
				g.DrawImage(bmpSuggestionBubble, recDest, recSrc, GraphicsUnit.Pixel);

				Bitmap bmpText;
				Font fnt = new System.Drawing.Font("blackadder itc", 36);
				
				int intTop = 0;
				int intVLineSpacine = 45;
				int intLeftText = 75;
				int intTabText = 190;

				bmpText = getTextImage("I accuse",fnt);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intLeftText, ptSuggestionBubbleTL.Y + intTop, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage(udrAccusation.eSuspect.ToString(), new Font(fnt.Name, fnt.Size, FontStyle.Italic | FontStyle.Underline), udrAccusation.eSuspect == enuSuspects.MrsWhite ? Color.Gray : clrSuspects[(int)udrAccusation.eSuspect]);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intTabText, ptSuggestionBubbleTL.Y + intTop + intVLineSpacine + 10, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage("in the", fnt);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intLeftText, ptSuggestionBubbleTL.Y + intTop + 2 * intVLineSpacine, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage(udrAccusation.eRoom.ToString(), new Font(fnt.Name, fnt.Size, FontStyle.Italic | FontStyle.Underline));
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intTabText, ptSuggestionBubbleTL.Y + intTop + 3 * intVLineSpacine, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage("with the", fnt);
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intLeftText, ptSuggestionBubbleTL.Y + intTop + 4 * intVLineSpacine, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);

				bmpText = getTextImage(udrAccusation.eWeapon.ToString(), new Font(fnt.Name, fnt.Size, FontStyle.Italic | FontStyle.Underline));
				recDest = new Rectangle(ptSuggestionBubbleTL.X + intTabText, ptSuggestionBubbleTL.Y + intTop + 5 * intVLineSpacine, bmpText.Width, bmpText.Height);
				recSrc = new Rectangle(0, 0, bmpText.Width, bmpText.Height);
				g.DrawImage(bmpText, recDest, recSrc, GraphicsUnit.Pixel);
			}

			return bmpRetVal;
		}

		public void Accuse(enuSuspects eSuspectAccusing, udtMurder udrAccusation)
		{
			if (eMode != enuMode.Accuse)
			{
				udrAniAccusation.eRestoreMode = eMode;
				eMode = enuMode.Accuse;
			}
			btnAccuse.Enabled = pnlControls.Enabled = true;

			udrAniAccusation.udrAccusation.eRoom = udrAccusation.eRoom;
			udrAniAccusation.udrAccusation.eWeapon = udrAccusation.eWeapon;
			udrAniAccusation.udrAccusation.eSuspect= udrAccusation.eSuspect;

			eAccusationMode = enuAccuseAnimationMode.drawAccusation;
		}

		enuAccuseAnimationMode eAccusationMode
		{
			get { return udrAniAccusation._eMode; }
			set
			{
				if (udrAniAccusation._eMode != value)
				{
					udrAniAccusation._eMode = value;
					switch (udrAniAccusation._eMode)
					{
						case enuAccuseAnimationMode.drawAccusation:
							udrAniAccusation.bolInit = false;
							setDelayTimer(10);
							break;

						case enuAccuseAnimationMode.prepareToShowCards:
							udrAniAccusation.bolInit = false;
							setDelayTimer(10);
							break;

						case enuAccuseAnimationMode.showCards:
							udrAniAccusation.bolInit = false;
							break;

						case enuAccuseAnimationMode.hideCards:
							udrAniAccusation.bolInit = false;
							break;

						case enuAccuseAnimationMode.retractCards:
							udrAniAccusation.bolInit = false;
							break;

						case enuAccuseAnimationMode.withdrawAccusingSuspect:
							udrAniAccusation.bolInit = false;
							break;

						case enuAccuseAnimationMode.showNewspaper:
							udrAniAccusation.bolInit = false;
							setDelayTimer(10);
							break;
					}
				}
			}
		}

		void ShowAccuseOptions()
		{
			#region "init tray : cLibPicTraySuspects"
			{
				cLibPicTraySuspects.Options.Mirror = PicTray.enuMirror.none;
				cLibPicTraySuspects.Options.makeImagesTransparent = true;
				cLibPicTraySuspects.Options.PopUpClickPic = false;
				cLibPicTraySuspects.Options.SelectionMode = PicTray.enuSelectionMode.click;
				cLibPicTraySuspects.Options.TrayCenter = new Point(-3, 144);
				cLibPicTraySuspects.Options.Width = 355;
				cLibPicTraySuspects.Options.Height = 422;
				cLibPicTraySuspects.Options.Rotation.StepSize = 0.120951317163207;
				cLibPicTraySuspects.Options.Rotation.Interval = 27;
				cLibPicTraySuspects.Options.Rotation.Mode = PicTray.enuRotationMode.toSelected;
				cLibPicTraySuspects.Options.Ellipse.Angle = 1.77499984927823;
				cLibPicTraySuspects.Options.Ellipse.Radius_Height = 102;
				cLibPicTraySuspects.Options.Ellipse.Radius_Width = 119;
				cLibPicTraySuspects.Options.Front.Angle = 0.0816814089933346;
				cLibPicTraySuspects.Options.Front.UserSet = PicTray.enuFrontUserSet.none;
				cLibPicTraySuspects.Options.ImageSize.Height_MinMax = new PicTray.classMinMax(75, 250);
				cLibPicTraySuspects.Options.ImageSize.Width_MinMax = new PicTray.classMinMax(75, 151);
				cLibPicTraySuspects.Options.ImageSize.Size_Control = enuSizeControl.both;
				cLibPicTraySuspects.Options.Caption.Show = false;
				cLibPicTraySuspects.Options.Caption.Font = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Regular);
				cLibPicTraySuspects.Options.Caption.ForeColor = Color.FromArgb(255, 255, 255, 0);
				cLibPicTraySuspects.Options.Caption.BackColor = Color.FromArgb(255, 0, 0, 0);
			
				cLibPicTraySuspects.Left = picBoard.Left;
				cLibPicTraySuspects.Top = 0;
			}
			#endregion

			#region "init tray : cLibPicTrayWeapons"
			{
				cLibPicTrayWeapons.Options.Mirror = PicTray.enuMirror.horizontal;
				cLibPicTrayWeapons.Options.makeImagesTransparent = true;
				cLibPicTrayWeapons.Options.PopUpClickPic = false;
				cLibPicTrayWeapons.Options.SelectionMode = PicTray.enuSelectionMode.click;
				cLibPicTrayWeapons.Options.TrayCenter = new Point(-3, 144);
				cLibPicTrayWeapons.Options.Width = 355;
				cLibPicTrayWeapons.Options.Height = 422;
				cLibPicTrayWeapons.Options.Rotation.StepSize = 0.120951317163207;
				cLibPicTrayWeapons.Options.Rotation.Interval = 27;
				cLibPicTrayWeapons.Options.Rotation.Mode = PicTray.enuRotationMode.toSelected;
				cLibPicTrayWeapons.Options.Ellipse.Angle = 1.77499984927823;
				cLibPicTrayWeapons.Options.Ellipse.Radius_Height = 102;
				cLibPicTrayWeapons.Options.Ellipse.Radius_Width = 119;
				cLibPicTrayWeapons.Options.Front.Angle = 0.0816814089933346;
				cLibPicTrayWeapons.Options.Front.UserSet = PicTray.enuFrontUserSet.none;
				cLibPicTrayWeapons.Options.ImageSize.Height_MinMax = new PicTray.classMinMax(75, 250);
				cLibPicTrayWeapons.Options.ImageSize.Width_MinMax = new PicTray.classMinMax(75, 151);
				cLibPicTrayWeapons.Options.ImageSize.Size_Control = enuSizeControl.both;
				cLibPicTrayWeapons.Options.Caption.Show = false;
				cLibPicTrayWeapons.Options.Caption.Font = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Regular);
				cLibPicTrayWeapons.Options.Caption.ForeColor = Color.FromArgb(255, 255, 255, 0);
				cLibPicTrayWeapons.Options.Caption.BackColor = Color.FromArgb(255, 0, 0, 0);

				cLibPicTrayWeapons.Left = cLibPicTraySuspects.Left + cLibPicTraySuspects.Width;
				cLibPicTrayWeapons.Top = 0;
			}
			#endregion
			#region "init tray : cLibPicTrayRooms"
			
			cLibPicTrayRooms.Options.Mirror = PicTray.enuMirror.vertical;
			cLibPicTrayRooms.Options.makeImagesTransparent = false;
			cLibPicTrayRooms.Options.PopUpClickPic = false;
			cLibPicTrayRooms.Options.SelectionMode = PicTray.enuSelectionMode.click;
			cLibPicTrayRooms.Options.TrayCenter = new Point(350, 100);
			cLibPicTrayRooms.Options.Width = 705;
			cLibPicTrayRooms.Options.Height = 289;
			cLibPicTrayRooms.Options.Rotation.StepSize = 0.117809724509617;
			cLibPicTrayRooms.Options.Rotation.Interval = 27;
			cLibPicTrayRooms.Options.Rotation.Mode = PicTray.enuRotationMode.toSelected;
			cLibPicTrayRooms.Options.Ellipse.Angle = 0;
			cLibPicTrayRooms.Options.Ellipse.Radius_Height = 66;
			cLibPicTrayRooms.Options.Ellipse.Radius_Width = 290;
			cLibPicTrayRooms.Options.Front.Angle = 1.49225651045515;
			cLibPicTrayRooms.Options.Front.UserSet = PicTray.enuFrontUserSet.none;
			cLibPicTrayRooms.Options.ImageSize.Height_MinMax = new PicTray.classMinMax(50, 250);
			cLibPicTrayRooms.Options.ImageSize.Width_MinMax = new PicTray.classMinMax(50, 150);
			cLibPicTrayRooms.SizeControl = enuSizeControl.both;
			cLibPicTrayRooms.Options.Caption.Show = false;
			cLibPicTrayRooms.Options.Caption.Font = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Regular);
			cLibPicTrayRooms.Options.Caption.ForeColor = Color.FromArgb(255, 255, 255, 0);
			cLibPicTrayRooms.Options.Caption.BackColor = Color.FromArgb(255, 0, 0, 0);
			
			cLibPicTrayRooms.Top = cLibPicTraySuspects.Top + cLibPicTraySuspects.Height;
			cLibPicTrayRooms.Left = 0;
			#endregion
		
			cLibPicTrayRooms.SendToBack();
			cLibPicTraySuspects.SendToBack();
			cLibPicTrayWeapons.SendToBack();
			
			cLibPicTrayRooms.Visible = true;	
			cLibPicTraySuspects.Visible = true;
			cLibPicTrayWeapons.Visible = true;

			setPicTrayBackgroundImage(ref cLibPicTrayRooms);
			setPicTrayBackgroundImage(ref cLibPicTraySuspects);
			setPicTrayBackgroundImage(ref cLibPicTrayWeapons); 
			
			cLibPicTrayRooms.BringToFront();
			cLibPicTraySuspects.BringToFront();
			cLibPicTrayWeapons.BringToFront(); 

			btnAccuse_Ok.Top = cLibPicTrayRooms.Top - btnAccuse_Ok.Height + 40;
			btnAccuse_Ok.Left = (bmpBoard.Width - btnAccuse_Ok.Width) / 2;
			btnAccuse_Ok.Visible = true;
		}
		#endregion

		void setPicTrayBackgroundImage(ref classPicTray_V2 cLibTray)
		{
			Bitmap bmpTempTwo = new Bitmap(cLibTray.Width, cLibTray.Height);

			using (Graphics g = Graphics.FromImage(bmpTempTwo))
			{
				Rectangle recSrc = new Rectangle(cLibTray.Location, cLibTray.Size);
				Rectangle recDest = new Rectangle(0, 0, cLibTray.Width, cLibTray.Height);
				g.DrawImage((Bitmap)picBoard.Image, recDest, recSrc, GraphicsUnit.Pixel);
			}
		
			cLibTray.BackgroundImage = bmpTempTwo;
			cLibTray.RefreshTrayImage();
			cLibTray.Refresh();
		}

		public void GameOver()
		{
			eMode = enuMode.gameOver;
			grbControls.Enabled = false;
			Bitmap bmpGameOver = new Bitmap(bmpGameBoard);			
			Bitmap bmpBanner =new Bitmap( Clue_CS2010.Properties.Resources.Winner);
			bmpBanner.MakeTransparent();

			Bitmap bmpFace = new Bitmap((int)(bmpSuspects[intSuspectTurn].Width), (int)(bmpSuspects[intSuspectTurn].Height));
			using (Graphics g = Graphics.FromImage(bmpFace))
			{
				g.FillRectangle(new SolidBrush(bmpSuspects[intSuspectTurn].GetPixel(bmpSuspects[intSuspectTurn].Width / 2, 0)), new Rectangle(0, 0, bmpFace.Width, bmpFace.Height));
				g.DrawImage(bmpSuspects[intSuspectTurn], new Rectangle (0,0, bmpFace.Width, bmpFace.Height), new Rectangle(0,0, bmpSuspects[intSuspectTurn].Width, bmpSuspects[intSuspectTurn].Height), GraphicsUnit.Pixel);
			}
			bmpFace.MakeTransparent(bmpFace.GetPixel(0, 0));

			using (Graphics g = Graphics.FromImage(bmpGameOver))
			{
				// draw face
				double dblSizeFactor = 2.1;
				Size  szFace= new System.Drawing.Size((int)(bmpFace.Width *dblSizeFactor), (int)(bmpFace.Height *dblSizeFactor));
				Rectangle recDest = new Rectangle((bmpGameOver.Width - szFace.Width) / 2, (bmpGameOver.Height - szFace.Height)/2, szFace.Width, szFace.Height);
				Rectangle recSrc = new Rectangle(0, 0, bmpFace.Width, bmpFace.Height);
				g.DrawImage(bmpFace, recDest, recSrc, GraphicsUnit.Pixel);

				// draw banner
				recDest = new Rectangle((bmpGameOver.Width - bmpBanner.Width) / 2, (int)(bmpGameOver.Height *.6), bmpBanner.Width, bmpBanner.Height);
				recSrc = new Rectangle(0, 0, bmpBanner.Width, bmpBanner.Height);
				g.DrawImage(bmpBanner, recDest, recSrc, GraphicsUnit.Pixel);
			}
			setDelayTimer(20000);
			pnlNotebook.BringToFront();
			picBoard.Image = bmpGameOver; picBoard.Refresh();

		}

		public void showAllowableMoves()
		{
			eMode = enuMode.showAllowableMoves;

			pnlControls.Enabled = btnEndTurn.Enabled = cSuspects[intSuspectTurn].setAllowableMoves();

			drawBoard();
		}
		
		void drawBoard()
		{
			bmpGameBoard = new Bitmap(bmpBoard);
			classSuspect cS = cSuspects[intSuspectTurn];

			Pen pTrim = new Pen(clrSuspects[intSuspectTurn], 4);
			Pen pWhite = new Pen(Color.White, 1);
			using (Graphics g = Graphics.FromImage(bmpGameBoard))
			{
				// draw allowable moves
				for (int intX = 0; intX < sz.Width; intX++)
				{
					for (int intY = 0; intY < sz.Height; intY++)
					{
						if (cS.cSEAllowableMoves[intX, intY] != null)
						{
							g.DrawRectangle(pWhite, new Rectangle(ptBoardTL.X + intX * 28 + 3, ptBoardTL.Y + intY * 28 + 3, 22, 22));
							g.DrawRectangle(pTrim, new Rectangle(ptBoardTL.X + intX * 28 + 6, ptBoardTL.Y + intY * 28 + 6, 17, 17));
							g.DrawRectangle(pWhite, new Rectangle(ptBoardTL.X + intX * 28 + 8, ptBoardTL.Y + intY * 28 + 8, 12, 12));
						}
					}
				}

				// draw center back of card				
				Point ptCenter = getRoomCenter(enuRooms._numRooms);
				Point ptTLCard = new Point(ptCenter.X - cCardUnknown.cBmp.getImage(0).Width / 2, ptCenter.Y - cCardUnknown.cBmp.getImage(0).Height / 2);
				Rectangle recDestCard = new Rectangle(ptTLCard, cCardUnknown.cBmp.getImage(0).Size);
				Rectangle recSrcCard = new Rectangle(0, 0, cCardUnknown.cBmp.getImage(0).Width, cCardUnknown.cBmp.getImage(0).Height);
				g.DrawImage(cCardUnknown.cBmp.getImage(0), recDestCard, recSrcCard, GraphicsUnit.Pixel);				

				// draw weapons
				Size szWeapon = new System.Drawing.Size(35, 35);
				Rectangle recSrc = new Rectangle(0, 0, bmpWeapons_Board[0].Width, bmpWeapons_Board[0].Height);
				for (enuWeapons eWeaponCounter = (enuWeapons)0; eWeaponCounter < enuWeapons._numWeapons; eWeaponCounter++)
				{
					if (cWeapons[(int)eWeaponCounter].eRoom != enuRooms.start
						&& !(eMode == enuMode.animateSummonWeapon && eWeaponCounter == udrSuggestion.eWeapon)) // do not draw the weapon if it is being animated in 'summon weapon' mode
					{ // in a room
						Point ptPieceCenter = getWeaponGraphicPositionInRoom(eWeaponCounter);
						Point ptPieceTL = new Point(ptPieceCenter.X - szWeapon.Width / 2, ptPieceCenter.Y - szWeapon.Height / 2);
						Rectangle recDest = new Rectangle(ptPieceTL, szWeapon);

						g.DrawImage(new Bitmap(bmpWeapons_Board[(int)eWeaponCounter]), recDest, recSrc, GraphicsUnit.Pixel);
					}
				}

				// draw pieces
				for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
				{
					if (!(eMode == enuMode.animateSummonSuspect && eSuspectCounter == udrSuggestion.eSuspect)// do not draw the suspect if it is being animated in 'summon suspect' mode
						&& !(eMode == enuMode.animateSecretPassage && eSuspectCounter == (enuSuspects)intSuspectTurn)) // do not draw the suspect if it is being animated in 'secret passage' mode
					{
						if (cSuspects[(int)eSuspectCounter].eRoom == enuRooms.tiles)
						{ // on a tile
							g.DrawImage(bmpPieces[(int)eSuspectCounter], new Point(ptBoardTL.X + cSuspects[(int)eSuspectCounter].ptTile.X * 28 + 2, ptBoardTL.Y + cSuspects[(int)eSuspectCounter].ptTile.Y * 28 + 2));
						}
						else if (cSuspects[(int)eSuspectCounter].eRoom != enuRooms.start)
						{ // in a room
							Point ptPieceCenter = getPieceGraphicPositionInRoom(eSuspectCounter);
							Point ptPieceTL = new Point(ptPieceCenter.X - bmpPieces[(int)eSuspectCounter].Width / 2, ptPieceCenter.Y - bmpPieces[(int)eSuspectCounter].Height / 2);
							g.DrawImage(bmpPieces[(int)eSuspectCounter], ptPieceTL);
						}
					}
				}
			}

			picBoard.Image = bmpGameBoard; picBoard.Refresh();
		}	

		private void btnSuggestion_Click(object sender, EventArgs e)
		{
			if (cSuspects[intSuspectTurn].bolPlayerControlled && !cSuspects[intSuspectTurn].bolEliminated)
				eMode = enuMode.Suggest;
		}

		public void Suggest()
		{
		 	btnSuggest.Enabled = false;
			pnlControls.Enabled = false;
			drawBoard();

			#region "cLibPicTraySuspects make suggestion"
			cLibPicTraySuspects.Location = new Point(0, 0);
			cLibPicTraySuspects.Options.Mirror = PicTray.enuMirror.none;
			cLibPicTraySuspects.Options.makeImagesTransparent = true;
			cLibPicTraySuspects.Options.PopUpClickPic = false;
			cLibPicTraySuspects.Options.SelectionMode = PicTray.enuSelectionMode.click;
			cLibPicTraySuspects.Options.TrayCenter = new Point(47, 193);
			cLibPicTraySuspects.Options.Width = 355;
			cLibPicTraySuspects.Options.Height = 385;
			cLibPicTraySuspects.Options.Rotation.StepSize = 0.119380520836412;
			cLibPicTraySuspects.Options.Rotation.Interval = 27;
			cLibPicTraySuspects.Options.Rotation.Mode = PicTray.enuRotationMode.toSelected;
			cLibPicTraySuspects.Options.Ellipse.Angle = 1.21579635693925;
			cLibPicTraySuspects.Options.Ellipse.Radius_Height = 67;
			cLibPicTraySuspects.Options.Ellipse.Radius_Width = 126;
			cLibPicTraySuspects.Options.Front.Angle = 0;
			cLibPicTraySuspects.Options.Front.UserSet = PicTray.enuFrontUserSet.none;
			cLibPicTraySuspects.Options.ImageSize.Height_MinMax = new PicTray.classMinMax(50, 150);
			cLibPicTraySuspects.Options.ImageSize.Width_MinMax = new PicTray.classMinMax(50, 150);
			cLibPicTraySuspects.Options.Caption.Show = false;
			cLibPicTraySuspects.Options.Caption.Font = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Regular);
			cLibPicTraySuspects.Options.Caption.ForeColor = Color.FromArgb(255, 255, 255, 0);
			cLibPicTraySuspects.Options.Caption.BackColor = Color.FromArgb(255, 0, 0, 0);

			cLibPicTraySuspects.tmrRotate.Enabled = true;
			#endregion

			#region "cLibPicTrayWeapons make suggestion"
			cLibPicTrayWeapons.Options.BackColor = Color.Transparent;
			cLibPicTrayWeapons.Options.Mirror = PicTray.enuMirror.horizontal;
			cLibPicTrayWeapons.Options.makeImagesTransparent = true;
			cLibPicTrayWeapons.Options.PopUpClickPic = false;
			cLibPicTrayWeapons.Options.SelectionMode = PicTray.enuSelectionMode.click;
			cLibPicTrayWeapons.Options.TrayCenter = new Point(60, 210);
			cLibPicTrayWeapons.Options.Width = 355;
			cLibPicTrayWeapons.Options.Height = 385;
			cLibPicTrayWeapons.Options.Rotation.StepSize = 0.119380520836412;
			cLibPicTrayWeapons.Options.Rotation.Interval = 27;
			cLibPicTrayWeapons.Options.Rotation.Mode = PicTray.enuRotationMode.toSelected;
			cLibPicTrayWeapons.Options.Ellipse.Angle = 1.01579635693925;// 1.21579635693925;
			cLibPicTrayWeapons.Options.Ellipse.Radius_Height = 67;
			cLibPicTrayWeapons.Options.Ellipse.Radius_Width = 126;
			cLibPicTrayWeapons.Options.Front.Angle = 0;
			cLibPicTrayWeapons.Options.Front.UserSet = PicTray.enuFrontUserSet.none;
			cLibPicTrayWeapons.Options.ImageSize.Height_MinMax = new PicTray.classMinMax(50, 150);
			cLibPicTrayWeapons.Options.ImageSize.Width_MinMax = new PicTray.classMinMax(50, 150);
			cLibPicTrayWeapons.Options.Caption.Show = false;
			cLibPicTrayWeapons.Options.Caption.Font = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Regular);
			cLibPicTrayWeapons.Options.Caption.ForeColor = Color.FromArgb(255, 255, 255, 0);
			cLibPicTrayWeapons.Options.Caption.BackColor = Color.FromArgb(255, 0, 0, 0);

			cLibPicTrayWeapons.tmrRotate.Enabled = true;
			#endregion

			DrawSuggestingSuspect();
			writeSuggestion();

			setUpCLibPicTrayChooseSuspect();
			setUpCLibPicTrayChooseWeapon();

			picBoard.Refresh();
		}

		void DrawRespondingSuspect(enuSuspects eSuspectResponding)
		{
			Bitmap bmpTemp = new Bitmap(bmpSuggestionBoard);
			ptResponseBubbleTL = new Point(50, 0);
			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				g.DrawImage(bmpSuspects[(int)eSuspectResponding], new Rectangle(ptResponseBubbleTL.X + bmpResponseBubble.Width, 0, 220, 220), new Rectangle(0, 0, bmpSuspects[(int)eSuspectResponding].Width, bmpSuspects[(int)eSuspectResponding].Height), GraphicsUnit.Pixel);
				g.DrawImage(bmpResponseBubble, ptResponseBubbleTL);
			}

			if (cButtons[(int)enuButtons.RespondToSuggestion_Ok] == null)
				cButtons[(int)enuButtons.RespondToSuggestion_Ok] = new classButton(this,
																			   ref picBoard,
																				   enuMode.respondToSuggestion,
																			   new Point(ptResponseBubbleTL.X + bmpResponseBubble.Width - 120, ptResponseBubbleTL.Y + bmpResponseBubble.Height - 50),
																				   Color.Black,
																				   "Ok",
																			   new Font("blackadder itc", 26));
			picBoard.Image = bmpTemp; picBoard.Refresh();
			cButtons[(int)enuButtons.RespondToSuggestion_Ok].eButtonName = enuButtons.RespondToSuggestion_Ok;
			cButtons[(int)enuButtons.RespondToSuggestion_Ok].draw();

			autoProceedEnabled = bolAutoProceed;
		}

		Bitmap getRoomBackGroundImage(enuRooms eRoomRequested)
		{
			Bitmap bmpRetVal = new Bitmap(139, 100);

			Rectangle recDest = new Rectangle(0, 0, 139, 100);
			Point ptRoomBackground = new Point(0, 0);

			switch (cSuspects[intSuspectTurn].eRoom)
			{
				case enuRooms.Study:
					ptRoomBackground = new Point(41, 17);
					break;

				case enuRooms.Hall:
					ptRoomBackground = new Point(288, 52);
					break;

				case enuRooms.Lounge:
					ptRoomBackground = new Point(530, 38);
					break;

				case enuRooms.DiningRoom:
					ptRoomBackground = new Point(519, 280);
					break;

				case enuRooms.Kitchen:
					ptRoomBackground = new Point(544, 530);
					break;

				case enuRooms.BallRoom:
					ptRoomBackground = new Point(293, 513);
					break;

				case enuRooms.Conservatory:
					ptRoomBackground = new Point(39, 568);
					break;

				case enuRooms.BilliardRoom:
					ptRoomBackground = new Point(37, 356);
					break;

				case enuRooms.Library:
					ptRoomBackground = new Point(55, 195);
					break;
			}

			Rectangle recSrc = new Rectangle(ptRoomBackground.X, ptRoomBackground.Y, 139, 100);
			using (Graphics g = Graphics.FromImage(bmpRetVal))
				g.DrawImage(bmpBoard, recDest, recSrc, GraphicsUnit.Pixel);

			return bmpRetVal;
		}

		void DrawSuggestingSuspect()
		{
			Bitmap bmpTemp = new Bitmap(picBoard.Image);

			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				Rectangle recDest = new Rectangle(279, 252, 139, 100);				
				Rectangle recSrc = new Rectangle(0,0, 139, 100);

				g.DrawImage(getRoomBackGroundImage(cSuspects[intSuspectTurn].eRoom), recDest, recSrc, GraphicsUnit.Pixel);

				Size szWeapon = new System.Drawing.Size(35, 35);
				recSrc = new Rectangle(0, 0, bmpWeapons_Board[0].Width, bmpWeapons_Board[0].Height);
				for (enuWeapons eWeaponCounter = 0; eWeaponCounter < enuWeapons._numWeapons; eWeaponCounter++)
				{
					if (cWeapons[(int)eWeaponCounter].eRoom == enuRooms._numRooms)
					{					// at center of map -> draw on top of room image
						Point ptPieceCenter = getWeaponGraphicPositionInRoom(eWeaponCounter);
						Point ptPieceTL = new Point(ptPieceCenter.X - szWeapon.Width / 2, ptPieceCenter.Y - szWeapon.Height / 2);
						recDest = new Rectangle(ptPieceTL, szWeapon);

						g.DrawImage(new Bitmap(bmpWeapons_Board[(int)eWeaponCounter]), recDest, recSrc, GraphicsUnit.Pixel);
					}
				}

				Point ptSuspectTL = new Point(0, 400);
				double dblSuspectImageFactor = 2;
				int intSuspectImageSize = (int)(bmpSuspects[intSuspectTurn].Width * dblSuspectImageFactor);
				ptSuggestionBubbleTL = new Point(ptSuspectTL.X + intSuspectImageSize - 50, 365);
				recDest = new Rectangle(ptSuspectTL.X, ptSuspectTL.Y, intSuspectImageSize, intSuspectImageSize);
				recSrc = new Rectangle(0, 0, bmpSuspects[intSuspectTurn].Width, bmpSuspects[intSuspectTurn].Height);
				g.DrawImage(bmpSuspects[intSuspectTurn], recDest, recSrc, GraphicsUnit.Pixel);

				recDest = new Rectangle(ptSuggestionBubbleTL.X, ptSuggestionBubbleTL.Y, bmpSuggestionBubble.Width, bmpSuggestionBubble.Height);
				recSrc = new Rectangle(0, 0, bmpSuggestionBubble.Width, bmpSuggestionBubble.Height);
				g.DrawImage(bmpSuggestionBubble, recDest, recSrc, GraphicsUnit.Pixel);
			}

			picBoard.Image = bmpTemp;
			Font fntButtons = new Font("blackadder itc", 26);

			if (cButtons[(int)enuButtons.MakeSuggestion_Cancel] == null)
				cButtons[(int)enuButtons.MakeSuggestion_Cancel] = new classButton(this,
																				  ref picBoard,
																					  enuMode.Suggest,
																				  new Point(ptSuggestionBubbleTL.X + 225, ptSuggestionBubbleTL.Y + 290),
																					  Color.Black,
																					  "Cancel",
																					  fntButtons);
			if (cSuspects[intSuspectTurn].bolPlayerControlled)
				cButtons[(int)enuButtons.MakeSuggestion_Cancel].draw();


			if (cButtons[(int)enuButtons.MakeSuggestion_Ok] == null)
				cButtons[(int)enuButtons.MakeSuggestion_Ok] = new classButton(this,
																			  ref picBoard,
																				  enuMode.Suggest,
																			  new Point(cButtons[(int)enuButtons.MakeSuggestion_Cancel].pt.X + cButtons[(int)enuButtons.MakeSuggestion_Cancel].sz.Width + 5,
																						cButtons[(int)enuButtons.MakeSuggestion_Cancel].pt.Y),
																				  Color.Black,
																				  "Ok",
																				  fntButtons);
			if (cSuspects[intSuspectTurn].bolPlayerControlled)
				cButtons[(int)enuButtons.MakeSuggestion_Ok].draw(); ;
		}

		public void selectedSuspectChange()
		{
			setBtnChooseSuspectColorAndText();
		}

		private void btnEndTurn_Click(object sender, EventArgs e)
		{
			if (cSuspects[intSuspectTurn].bolPlayerControlled && !cSuspects[intSuspectTurn].bolEliminated)
				eMode = enuMode.endTurn;
		}

		void drawPlayerCards()
		{
			Bitmap bmpNotes = new Bitmap(picNotebook.Image);
			using (Graphics g = Graphics.FromImage(bmpNotes))
			{
				double dblAspectRatioXOverY = ((double)cCards[0].cBmp.getImage(0).Width / (double)cCards[0].cBmp.getImage(0).Height);
				int intHeight = 24;
				int intWidth = (int)((double)intHeight * dblAspectRatioXOverY);

				classSuspect cSuspectPlayer = getPlayerSuspect();


				for (int intCardCounter = 0; intCardCounter < cSuspects[intSuspectTurn].cCards.Length; intCardCounter++)
				{
					Point ptDest = new Point(2, cPlayerNotes[0, (int)cSuspectPlayer.cCards[intCardCounter].eCardName].pt.Y);
					Size szDest = new System.Drawing.Size(intWidth, intHeight);
					Rectangle recDest = new Rectangle(ptDest, szDest);
					Rectangle recSrc = new Rectangle(0, 0, cCards[0].cBmp.getImage(0).Width + 1, cCards[0].cBmp.getImage(0).Height + 1);
					g.DrawImage(cSuspectPlayer.cCards[intCardCounter].cBmp.getImage(0), recDest, recSrc, GraphicsUnit.Pixel);
				}
			}

			picNotebook.Image = bmpNotebook = bmpNotes; picNotebook.Refresh();
		}

		classSuspect getPlayerSuspect()
		{
			for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
				if (cSuspects[(int)eSuspectCounter].bolPlayerControlled)
					return cSuspects[(int)eSuspectCounter];
			return cSuspects[0];
		}

		#region "roll die"
		public void rollDie()
		{
			btnRollDie.Enabled = false;

			eMode = enuMode.rollDie_begin;
			udrRollDieInfo.intDieValue = 0;
			udrRollDieInfo.intDieWidth = 50;
			udrRollDieInfo.intMaxVel = 6;
			udrRollDieInfo.intVelFactor = 20;
			udrRollDieInfo.dblVelocityAttenuationFactor = 0.90;
			udrRollDieInfo.intRightMost = picDieBox.Width;
			udrRollDieInfo.intLowerMost = picDieBox.Height;

			cSuspects[intSuspectTurn].bolCanSuggest = false;

			udrRollDieInfo.dblVel = (double)(udrRollDieInfo.intMaxVel * udrRollDieInfo.intVelFactor / 2) * rnd.NextDouble() + (udrRollDieInfo.intMaxVel * udrRollDieInfo.intVelFactor / 2);

			udrRollDieInfo.dblAngle = 0.0;
			udrRollDieInfo.ptDie = new Point(0, 0);
			switch (cSuspects[intSuspectTurn].eName)
			{
				case enuSuspects.MissScarlet:
					udrRollDieInfo.dblAngle = 10.0 / 18.0 * Math.PI;
					udrRollDieInfo.ptDie = new Point((int)(picDieBox.Width * .7 - udrRollDieInfo.intDieWidth / 2.0), 0);
					break;
				case enuSuspects.ColMustard:
					udrRollDieInfo.dblAngle = 7.0 / 8.8 * Math.PI;
					udrRollDieInfo.ptDie = new Point(picDieBox.Width - udrRollDieInfo.intDieWidth, (int)(picDieBox.Height * .4 - udrRollDieInfo.intDieWidth / 2));
					break;

				case enuSuspects.MrsWhite:
					udrRollDieInfo.dblAngle = 26.0 / 18.0 * Math.PI;
					udrRollDieInfo.ptDie = new Point((int)(picDieBox.Width * .7 - udrRollDieInfo.intDieWidth / 2), picDieBox.Height - udrRollDieInfo.intDieWidth);
					break;

				case enuSuspects.RevGreen:
					udrRollDieInfo.dblAngle = 28.0 / 18.0 * Math.PI;
					udrRollDieInfo.ptDie = new Point((int)(picDieBox.Width * .3 - udrRollDieInfo.intDieWidth / 2), picDieBox.Height - udrRollDieInfo.intDieWidth);
					break;

				case enuSuspects.MrsPeacock:
					udrRollDieInfo.dblAngle = 35.0 / 18.0 * Math.PI;
					udrRollDieInfo.ptDie = new Point(0, (int)(picDieBox.Height * .6 - udrRollDieInfo.intDieWidth / 2));
					break;

				case enuSuspects.ProfPlum:
					udrRollDieInfo.dblAngle = 1.0 / 18.0 * Math.PI;
					udrRollDieInfo.ptDie = new Point(0, (int)(picDieBox.Height * .4 - udrRollDieInfo.intDieWidth / 2));
					break;
			}

			udrRollDieInfo.dblXVel = udrRollDieInfo.dblVel * Math.Cos(udrRollDieInfo.dblAngle);
			udrRollDieInfo.dblYVel = udrRollDieInfo.dblVel * Math.Sin(udrRollDieInfo.dblAngle);

			double dblStartVel = Math.Sqrt(udrRollDieInfo.dblXVel * udrRollDieInfo.dblXVel + udrRollDieInfo.dblYVel * udrRollDieInfo.dblYVel);
			double dblMinVel = 2.0;
			udrRollDieInfo.intRollCount = (int)(Math.Log(dblMinVel / dblStartVel) / Math.Log(udrRollDieInfo.dblVelocityAttenuationFactor));
			udrRollDieInfo.intRollAnimation = 0;
			//
			eMode = enuMode.rollDie_animate;
		}

		void rollDie_animate()
		{
			Bitmap bmpDieBox = new Bitmap(bmpBaize,picDieBox.Size);
			if (udrRollDieInfo.bmpCurrent == null)
				udrRollDieInfo.bmpCurrent = cBmpDie[1].getImage(1);

			Rectangle recDieSrc = new Rectangle(0, 0, udrRollDieInfo.bmpCurrent.Width, udrRollDieInfo.bmpCurrent.Height);

			Rectangle recDieBox = new Rectangle(0, 0, picDieBox.Width, picDieBox.Height);
			Rectangle recDieDest;
			if (udrRollDieInfo.intRollAnimation < udrRollDieInfo.intRollCount)
			{
				udrRollDieInfo.intRollAnimation++;
				udrRollDieInfo.intDieValue = (int)(rnd.NextDouble() * 1000) % 6 + 1;
				int intSleepTime = 0;
				using (Graphics g = Graphics.FromImage(bmpDieBox))
				{
					g.DrawImage(bmpBaize, recDieBox, recDieBox, GraphicsUnit.Pixel);
					udrRollDieInfo.bmpCurrent = cBmpDie[udrRollDieInfo.intDieValue].getImage(udrRollDieInfo.intImageIndex);
					recDieDest = new Rectangle(udrRollDieInfo.ptDie.X - udrRollDieInfo.bmpCurrent.Width / 2, udrRollDieInfo.ptDie.Y - udrRollDieInfo.bmpCurrent.Height / 2, udrRollDieInfo.bmpCurrent.Width, udrRollDieInfo.bmpCurrent.Height);
					g.DrawImage(udrRollDieInfo.bmpCurrent, recDieDest, recDieSrc, GraphicsUnit.Pixel);
					picDieBox.Image = bmpDieBox;
					picDieBox.Refresh();
					
					int intMinSleep = (int)((double)udrRollDieInfo.intVelFactor * (double)udrRollDieInfo.intMaxVel) + 1;
					intSleepTime = intMinSleep - (int)(Math.Sqrt(udrRollDieInfo.dblXVel * udrRollDieInfo.dblXVel + udrRollDieInfo.dblYVel * udrRollDieInfo.dblYVel));

					udrRollDieInfo.intDieValue =  (int)(rnd.NextDouble() * 1000) % 6 + 1;

					if ((int)(rnd.NextDouble() * 1000) % intSleepTime < 300)
					{
						if ((int)(rnd.NextDouble() * 1000) % 2 == 0)
							udrRollDieInfo.intImageIndex = (int)(udrRollDieInfo.intImageIndex + 1) % 16;
						else
							udrRollDieInfo.intImageIndex = (int)(udrRollDieInfo.intImageIndex + 15) % 16;
					}
					udrRollDieInfo.bmpCurrent = cBmpDie[udrRollDieInfo.intDieValue].getImage(udrRollDieInfo.intImageIndex);

					udrRollDieInfo.dblXVel *= udrRollDieInfo.dblVelocityAttenuationFactor;					

					udrRollDieInfo.ptDie.X += (int)udrRollDieInfo.dblXVel;
					if (udrRollDieInfo.ptDie.X - udrRollDieInfo.bmpCurrent .Width/2< 0)
					{
						int intDifference = udrRollDieInfo.ptDie.X - udrRollDieInfo.bmpCurrent.Width / 2;
						udrRollDieInfo.ptDie.X = udrRollDieInfo.bmpCurrent.Width / 2 - intDifference;

						udrRollDieInfo.dblXVel *= -1;
					}
					else if (udrRollDieInfo.ptDie.X + udrRollDieInfo.bmpCurrent .Width/2 > udrRollDieInfo.intRightMost)
					{
						int intDifference = udrRollDieInfo.intRightMost - (udrRollDieInfo.ptDie.X + udrRollDieInfo.bmpCurrent.Width / 2);
						udrRollDieInfo.ptDie.X = udrRollDieInfo.intRightMost + intDifference - udrRollDieInfo.bmpCurrent.Width/2;

						udrRollDieInfo.dblXVel *= -1;
					}

					udrRollDieInfo.dblYVel *= udrRollDieInfo.dblVelocityAttenuationFactor;
					udrRollDieInfo.ptDie.Y += (int)udrRollDieInfo.dblYVel;
					if (udrRollDieInfo.ptDie.Y - udrRollDieInfo.bmpCurrent.Height /2 < 0)
					{
						int intDifference = udrRollDieInfo.ptDie.Y - udrRollDieInfo.bmpCurrent.Height / 2;
						udrRollDieInfo.ptDie.Y = udrRollDieInfo.bmpCurrent.Height / 2 - intDifference;

						udrRollDieInfo.dblYVel *= -1;
					}
					else if (udrRollDieInfo.ptDie.Y + udrRollDieInfo.bmpCurrent.Height/2 > udrRollDieInfo.intLowerMost)
					{
						int intDifference = udrRollDieInfo.intLowerMost - (udrRollDieInfo.ptDie.Y + udrRollDieInfo.bmpCurrent.Height / 2);
						udrRollDieInfo.ptDie.Y = udrRollDieInfo.intLowerMost - udrRollDieInfo.bmpCurrent.Height / 2 + intDifference;

						udrRollDieInfo.dblYVel *= -1;
					}


					double dblVel = Math.Sqrt(Math.Pow(udrRollDieInfo.dblXVel, 2) + Math.Pow(udrRollDieInfo.dblYVel, 2));
					if (dblVel < cBmpDie[1].getImage(0).Width)
						udrRollDieInfo.intRollAnimation = udrRollDieInfo.intRollCount; // quit when moving too slow


				}
				setDelayTimer(intSleepTime);
				return;
			}
			else
				eMode = enuMode.rollDie_end;
		}

		void rollDie_End()
		{
			Bitmap bmpDieBox = new Bitmap(bmpBaize);
			Rectangle recDieSrc = new Rectangle(0, 0, udrRollDieInfo.bmpCurrent.Width + 1, udrRollDieInfo.bmpCurrent.Height + 1);
			Rectangle recDieBox = new Rectangle(0, 0, picDieBox.Width, picDieBox.Height);
			Rectangle recDieDest;
			using (Graphics g = Graphics.FromImage(bmpDieBox))
			{
				g.DrawImage(bmpBaize, recDieBox, recDieBox, GraphicsUnit.Pixel);
				recDieDest = new Rectangle(udrRollDieInfo.ptDie.X - udrRollDieInfo.bmpCurrent.Width/2, udrRollDieInfo.ptDie.Y - udrRollDieInfo.bmpCurrent.Height/2, udrRollDieInfo.bmpCurrent.Width, udrRollDieInfo.bmpCurrent.Height);
				g.DrawImage(udrRollDieInfo.bmpCurrent, recDieDest, recDieSrc, GraphicsUnit.Pixel);
			}

			picDieBox.Image = bmpDieBox;
			picDieBox.Refresh();

			if (!cSuspects[intSuspectTurn].bolPlayerControlled)
			{
				showAllowableMoves();
				setDelayTimer(500);
			}
			else
				showAllowableMoves();
		}
		#endregion

		private void btnRollDie_Click(object sender, EventArgs e)
		{
			if (cSuspects[intSuspectTurn].bolPlayerControlled && !cSuspects[intSuspectTurn].bolEliminated)
			{
				pnlControls.Enabled = false;
				rollDie();
			}
		}

		public void ProveSuggestion()
		{
			// display appropriate images on pic trays
			cLibPicTraySuspects.setSelectedImage((int)udrSuggestion.eSuspect);
			cLibPicTraySuspects.Angle = cLibPicTraySuspects.FrontAngle - cLibPicTraySuspects.Tray[(int)udrSuggestion.eSuspect].angleOnTray;
			cLibPicTraySuspects.RefreshTrayImage();

			cLibPicTrayWeapons.setSelectedImage((int)udrSuggestion.eWeapon);
			cLibPicTrayWeapons.Angle = cLibPicTrayWeapons.FrontAngle - cLibPicTrayWeapons.Tray[(int)udrSuggestion.eWeapon].angleOnTray;
			cLibPicTrayWeapons.RefreshTrayImage();
			udrSuggestionAnimation.intProveSuggestionCycleCounter = 1;

			eMode = enuMode.respondToSuggestion;
			cSuspects[intSuspectTurn].bolCanSuggest = false;
			cSuspects[intSuspectTurn].bolHasNotYetMadeASuggestionThisTurn = true;

			bmpSuggestionBoard = new Bitmap(picBoard.Image);

			// erase pic trays & draw their images onto the bmpSuggestionBoard
			using (Graphics g = Graphics.FromImage(bmpSuggestionBoard))
			{
				Rectangle recSrc, recDest;

				recSrc = new Rectangle(0, 0, cLibPicTraySuspects.Width, cLibPicTraySuspects.Height);
				recDest = new Rectangle(cLibPicTraySuspects.Left, cLibPicTraySuspects.Top, cLibPicTraySuspects.Width, cLibPicTraySuspects.Height);
				g.DrawImage(new Bitmap(cLibPicTraySuspects.Image), recDest, recSrc, GraphicsUnit.Pixel);
				cLibPicTraySuspects.Visible = false;

				recSrc = new Rectangle(0, 0, cLibPicTrayWeapons.Width, cLibPicTrayWeapons.Height);
				recDest = new Rectangle(cLibPicTrayWeapons.Left, cLibPicTrayWeapons.Top, cLibPicTrayWeapons.Width, cLibPicTrayWeapons.Height);
				g.DrawImage(new Bitmap(cLibPicTrayWeapons.Image), recDest, recSrc, GraphicsUnit.Pixel);
				cLibPicTrayWeapons.Visible = false;
			}

			udrSuggestionAnimation.intProveSuggestionCycleCounter = 1;
			ProveSuggestion_CycleThroughSuspects();
		}

		void ProveSuggestion_CycleThroughSuspects()
		{
			// cycle through all suspects
			enuSuspects eSuspectCounter = (enuSuspects)(((int)cSuspects[intSuspectTurn].eName + udrSuggestionAnimation.intProveSuggestionCycleCounter) % (int)enuSuspects._numSuspects);
			if (cSuspects[(int)eSuspectCounter].bolPlayerControlled)
			{
				eMode = enuMode.playerChoosesCardToShow;
				showPlayerResponseOptions();
				return;
			}
			else
			{
				enuCards eResponse = cSuspects[(int)eSuspectCounter].RespondToSuggestion();
				ProveSuggestion_ReceiveResponse(eSuspectCounter, eResponse);
			}
		}

		void showPlayerResponseOptions()
		{
			eValidPlayerResponseCards = new enuCards[0];
			classSuspect cPlayer = getPlayerSuspect();
			enuCards eCardTemp;

			eCardTemp = classCard.getECardFromERoom(udrSuggestion.eRoom);
			if (eCardIsInListeCards(ref cPlayer.cCards, eCardTemp))
				appendCardList(ref eValidPlayerResponseCards, eCardTemp);

			eCardTemp = classCard.getECardFromESuspect(udrSuggestion.eSuspect);
			if (eCardIsInListeCards(ref cPlayer.cCards, eCardTemp))
				appendCardList(ref eValidPlayerResponseCards, eCardTemp);

			eCardTemp = classCard.getECardFromEWeapon(udrSuggestion.eWeapon);
			if (eCardIsInListeCards(ref cPlayer.cCards, eCardTemp))
				appendCardList(ref eValidPlayerResponseCards, eCardTemp);

			double dblBannerAspectRatioXOverY = (double)bmpBannerCardToShow.Width / (double)bmpBannerCardToShow.Height;

			Point ptTLBanner = new Point(100, 135);

			int intBannerWidth = bmpBoard.Width - ptTLBanner.X - 5;
			int intBannerHeight = (int)(intBannerWidth / dblBannerAspectRatioXOverY);

			Size szBanner = new System.Drawing.Size(intBannerWidth, intBannerHeight);

			Rectangle recBanner = new Rectangle(ptTLBanner, szBanner);

			Bitmap bmpBannerBackground = new Bitmap(szBanner.Width, szBanner.Height);
			using (Graphics g = Graphics.FromImage(bmpBannerBackground))
			{
				Rectangle recDest = new Rectangle(0, 0, bmpBannerBackground.Width, bmpBannerBackground.Height);

				g.DrawImage(bmpSuggestionBoard, recDest, recBanner, GraphicsUnit.Pixel);

				if (eValidPlayerResponseCards.Length > 0)
				{
					g.DrawImage(bmpBannerCardToShow, recDest, new Rectangle(0, 0, bmpBannerCardToShow.Width, bmpBannerCardToShow.Height), GraphicsUnit.Pixel);
					// player has at least one card to show 				

					int intTop = 2;
					int intHGap = 10;
					int intWidth = 120;

					Point[] pts = new Point[eValidPlayerResponseCards.Length];
					switch (eValidPlayerResponseCards.Length)
					{
						case 1:
							pts[0] = new Point((bmpBoard.Width - intWidth) / 2, intTop);
							break;

						case 2:
							pts[0] = new Point(bmpBoard.Width / 2 - intWidth - intHGap, intTop);
							pts[1] = new Point(bmpBoard.Width / 2 + intHGap, intTop);
							break;

						case 3:
							pts[0] = new Point((bmpBoard.Width - intWidth) / 2, intTop);
							pts[1] = new Point(pts[0].X - intWidth - intHGap, intTop);
							pts[2] = new Point(pts[0].X + intWidth + intHGap, intTop);
							break;
					}

					for (int intValidCardCounter = 0; intValidCardCounter < eValidPlayerResponseCards.Length; intValidCardCounter++)
					{
						double dblAspectRatioYOverX = (double)cCards[(int)eValidPlayerResponseCards[intValidCardCounter]].cBmp.getImage(0).Height / (double)cCards[(int)eValidPlayerResponseCards[intValidCardCounter]].cBmp.getImage(0).Width;
						int intHeight = (int)(intWidth * dblAspectRatioYOverX);
						Size szButton = new Size(intWidth, intHeight);

						Bitmap bmpBackgroundImage = new Bitmap(cCards[(int)eValidPlayerResponseCards[intValidCardCounter]].cBmp.getImage(0), intWidth, intHeight);
						btnPlayerResponse[intValidCardCounter].BackgroundImage = bmpBackgroundImage;
						btnPlayerResponse[intValidCardCounter].Width = szButton.Width + 3;
						btnPlayerResponse[intValidCardCounter].Height = szButton.Height + 3;
						btnPlayerResponse[intValidCardCounter].Tag = cCards[(int)eValidPlayerResponseCards[intValidCardCounter]];
						btnPlayerResponse[intValidCardCounter].Location = pts[intValidCardCounter];
						btnPlayerResponse[intValidCardCounter].BringToFront();
						btnPlayerResponse[intValidCardCounter].Visible = true;
						btnPlayerResponse[intValidCardCounter].Refresh();
					}
					
					autoProceedEnabled = bolAutoProceed && (eValidPlayerResponseCards.Length == 1); // auto-proceed if there is only one choice
				}
				else
				{
					g.DrawImage(bmpBannerNoCard, recDest, new Rectangle(0, 0, bmpBannerNoCard.Width, bmpBannerNoCard.Height), GraphicsUnit.Pixel);
					autoProceedEnabled = bolAutoProceed; //DEBUGHERE
				}
			}

			Bitmap bmpTemp = new Bitmap(bmpSuggestionBoard);
			using (Graphics g = Graphics.FromImage(bmpTemp))
				g.DrawImage(bmpBannerBackground, recBanner, new Rectangle(0, 0, bmpBannerBackground.Width, bmpBannerBackground.Height), GraphicsUnit.Pixel);
			recBannerButton = new Rectangle(recBanner.Left + 127, recBanner.Top + 29, 363, 68);
			picBoard.Image = bmpTemp;
			picBoard.Refresh();
		}

		void btnPlayerResponse_Click(object sender, MouseEventArgs e)
		{
			autoProceedEnabled = false;
			picBoard.Image = bmpSuggestionBoard; picBoard.Refresh();

			Button btnThis = (Button)sender;
			for (int intButtonCounter = 0; intButtonCounter < btnPlayerResponse.Length; intButtonCounter++)
				btnPlayerResponse[intButtonCounter].Visible = false;

			classCard cCardToShow = (classCard)(btnThis.Tag);
			eMode = enuMode.respondToSuggestion;
			for (int intButtonCounter = 0; intButtonCounter < btnPlayerResponse.Length; intButtonCounter++)
				btnPlayerResponse[intButtonCounter].Visible = false;
			ProveSuggestion_ReceiveResponse(getPlayerSuspect().eName, cCardToShow.eCardName);
		}

		void ProveSuggestion_ReceiveResponse(enuSuspects eRespondingSuspect, enuCards eResponse)
		{
			DrawRespondingSuspect(eRespondingSuspect);
			writeResponse(eResponse, eRespondingSuspect);

			for (enuSuspects eSuspectAICounter = (enuSuspects)0; eSuspectAICounter < enuSuspects._numSuspects; eSuspectAICounter++)
			{
				if (!cSuspects[(int)eSuspectAICounter].bolPlayerControlled
					&& eRespondingSuspect != eSuspectAICounter)
				{
					enuCards eCardThisAISuspectSees = eResponse;
					if (eSuspectAICounter != cSuspects[intSuspectTurn].eName)
					{ // this AISuspect is NOT the player who's turn it is
						if (eResponse != enuCards.NoCardShown)
							eCardThisAISuspectSees = enuCards.Unknown;
					}
					cSuspects[(int)eSuspectAICounter].ResponseToSuggestion(eRespondingSuspect, eCardThisAISuspectSees);
				}
			}

			udrSuggestionAnimation.intProveSuggestionCycleCounter++;

			if (eResponse != enuCards.NoCardShown)
			{
				udrSuggestionAnimation.intProveSuggestionCycleCounter = 6;
			}

		}

		private void btnWarnPlayerWhoseTurnItIs_Click(object sender, EventArgs e)
		{
			btnWarnPlayerWhoseTurnItIs.Visible = false;
			btnRollDie.Enabled
				= grbControls.Enabled
				= btnAccuse.Enabled
				= true;
			eMode = enuMode.beginTurn;
		}
	}

	public class classSearchElement
	{
		public Point pt;
		public int intSteps;
		public int intTurns;
		public int intCost;

		public enuDir SrcDir;
		public classSearchElement next;

		public void set(Point PT, int Cost, enuDir sourceDirection)
		{ set(PT, sourceDirection, Cost, 0); }

		public void set(Point PT, enuDir sourceDirection, int Steps, int turns)
		{
			pt = PT;
			SrcDir = sourceDirection;
			intSteps = Steps;
			intTurns = turns;
			intCost = intTurns * 3 + intSteps;
		}
	}

	public struct udtSearchElementQ
	{
		public classSearchElement head;
		public classSearchElement tail;
	}

	public class classRoom
	{
		public enuRooms name;
		public Point[] ptDoors;
		formClue mainForm;

		public classRoom(enuRooms Name, formClue MainForm)
		{
			mainForm = MainForm;
			name = Name;
			setDoors();
		}
		public Point[] getValidDoors() { return getValidDoors(true); }
		public Point[] getValidDoors(bool bolAllowSecretDoor)
		{
			Point[] ptRetVal = new Point[0];
			for (int intDoorCounter = 0; intDoorCounter < ptDoors.Length; intDoorCounter++)
			{
				if (classSuspect.cFloor[ptDoors[intDoorCounter].X, ptDoors[intDoorCounter].Y].dirDoor == enuDir.secretPassage)
				{
					if (bolAllowSecretDoor)
					{
						Array.Resize<Point>(ref ptRetVal, ptRetVal.Length + 1);
						ptRetVal[ptRetVal.Length - 1] = ptDoors[intDoorCounter];
					}
				}
				else
				{
					Point ptNext = mainForm.movePoint(ptDoors[intDoorCounter], classSuspect.cFloor[ptDoors[intDoorCounter].X, ptDoors[intDoorCounter].Y].dirDoor);
					if (mainForm.floorTileIsFree(ptNext) || mainForm.cSuspects[mainForm.intSuspectTurn].ptTile == ptNext) // tile is free or suspect whose turn it is is standing on it
					{
						// doors are only valid if they are NOT BLOCKED
						bool bolDoorValid = true;
						for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
						{
							if (eSuspectCounter != (enuSuspects)mainForm.intSuspectTurn && mainForm.cSuspects[(int)eSuspectCounter].eRoom == enuRooms.tiles)
								if (mainForm.cSuspects[(int)eSuspectCounter].ptTile == ptNext)
									bolDoorValid = false;
						}
						if (bolDoorValid)
						{
							Array.Resize<Point>(ref ptRetVal, ptRetVal.Length + 1);
							ptRetVal[ptRetVal.Length - 1] = ptDoors[intDoorCounter];
						}
					}
				}
			}
			return ptRetVal;
		}

		void setDoors()
		{
			ptDoors = new Point[0];
			int intRoomID = (int)name;
			for (int intX = 0; intX < mainForm.sz.Width; intX++)
				for (int intY = 0; intY < mainForm.sz.Height; intY++)
				{
					if (classSuspect.cFloor[intX, intY].eType == enuFloor.door
						&& classSuspect.cFloor[intX, intY].eRoom == name)
					{
						Array.Resize<Point>(ref ptDoors, ptDoors.Length + 1);
						ptDoors[ptDoors.Length - 1] = new Point(intX, intY);
					}
				}
		}

		public enuRooms oppositeCornerRoom()
		{
			switch (name)
			{
				case enuRooms.Study:
					return enuRooms.Kitchen;

				case enuRooms.Lounge:
					return enuRooms.Conservatory;

				case enuRooms.Kitchen:
					return enuRooms.Study;

				case enuRooms.Conservatory:
					return enuRooms.Lounge;

				default:
					return name;
			}
		}
	}

	public class classCardsCalled
	{
		public enuCards[] cCardsThatMightHaveBeenShown;
	}

	public class classSuspectCardsCalled
	{
		public classCardsCalled[] cSetsOfCardsCalled;
	}

	public class udtAILogic
	{
		public classSuspectCardsCalled[] cSuspectsUnknowns;
		public enuNote[,] eNotes;
		public enuRooms[] eRoomsLeft;
		public enuWeapons[] eWeaponsLeft;
		public enuSuspects[] eSuspectsLeft;
		public enuRooms eDestinationRoom;
		public Point ptDestinationTile;
		public udtSuggestionAI udrSuggestionAI;
	}

	public class classTurnsReachRoom
	{
		public enuRooms eRoom;
		int intCost;
		public int getCost
		{
			get { return intCost; }
		}

		public void resetCost()
		{
			intCost = 1000;
		}

		public bool setCost(int intNewValue)
		{
			if (intNewValue < intCost)
			{
				intCost = intNewValue;
				return true;
			}
			else
				return false;
		}
	}

	public class classSuspect
	{
		public bool bolPlayerControlled;
		public bool bolEliminated;

		bool _bolCanSuggest;
		public bool bolMustMove;
		public bool bolHasNotYetMadeASuggestionThisTurn;
		public enuSuspects eName;
		public Point ptTile;
		public Point ptFirstTile;
		public enuRooms eRoom;
		public classCard[] cCards = new classCard[0];
		public classSearchElement[,] cSEAllowableMoves;
		public classSearchElement[,] cShortestPath;
		static classSearchElement[] cSEArray = new classSearchElement[0];
		public classTurnsReachRoom[] cNumTurnsToReachRooms = new classTurnsReachRoom[(int)enuRooms._numRooms];
		public static classFloor[,] cFloor;
		public enuRooms[] eRoomsIHoldACardFor;
		public enuWeapons[] eWeaponsIHoldACardFor;
		public enuSuspects[] eSuspectsIHoldACardFor;
		public enuAILevel eAILevel = enuAILevel.average;
		public udtAILogic udrAILogic;

		udtSearchElementQ searchQ;
		formClue MainForm;

		public classSuspect(enuSuspects Name, formClue mainForm)
		{
			eName = Name;
			MainForm = mainForm;
			setFirstTiles();

			if (cFloor == null)
				initFloor();
			bolPlayerControlled = false;

			// init allowable moves table
			if (cSEAllowableMoves == null)
				cSEAllowableMoves = new classSearchElement[MainForm.sz.Width, MainForm.sz.Height];
		}

		public bool bolCanSuggest
		{
			get { return _bolCanSuggest; }
			set
			{
				if (_bolCanSuggest != value)
					_bolCanSuggest = value;
			}
		}

		public void initNotes()
		{
			udrAILogic = new udtAILogic();
			udrAILogic.eNotes = new enuNote[(int)enuSuspects._numSuspects, (int)enuCards._numCards];
			udrAILogic.cSuspectsUnknowns = new classSuspectCardsCalled[(int)enuSuspects._numSuspects];

			for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
			{
				// init logic of suggestion responses
				udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter] = new classSuspectCardsCalled();
				udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled = new classCardsCalled[0];

				// init notes
				for (enuCards eCardCounter = (enuCards)0; eCardCounter < enuCards._numCards; eCardCounter++)
					udrAILogic.eNotes[(int)eSuspectCounter, (int)eCardCounter] = (eSuspectCounter == eName ? enuNote.X : enuNote.blank);
			}

			// reset possible rooms
			udrAILogic.eRoomsLeft = new enuRooms[(int)enuRooms._numRooms];
			for (enuRooms eRoomCounter = (enuRooms)0; eRoomCounter < enuRooms._numRooms; eRoomCounter++)
				udrAILogic.eRoomsLeft[(int)eRoomCounter] = eRoomCounter;

			udrAILogic.eWeaponsLeft = new enuWeapons[(int)enuWeapons._numWeapons];
			for (enuWeapons eWeaponCounter = (enuWeapons)0; eWeaponCounter < enuWeapons._numWeapons; eWeaponCounter++)
				udrAILogic.eWeaponsLeft[(int)eWeaponCounter] = eWeaponCounter;

			udrAILogic.eSuspectsLeft = new enuSuspects[(int)enuSuspects._numSuspects];
			for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
				udrAILogic.eSuspectsLeft[(int)eSuspectCounter] = eSuspectCounter;

			// init suggestionAI
			udrAILogic.udrSuggestionAI.suspectMysteryInfo = new udtSuggestionAI_perSuspect[(int)enuSuspects._numSuspects - 1];
			for (int intSuspectCounter = 1; intSuspectCounter < (int)enuSuspects._numSuspects; intSuspectCounter++)
			{
				udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter - 1].eSuspect = (enuSuspects)(((int)eName + intSuspectCounter) % (int)enuSuspects._numSuspects);
			}

		}

		/// <summary>
		/// uses the 24x24 pixel bitmap bmpClueFloor to set up 2d array describing the game map.
		/// each pixel represents a square on the board.
		/// the pixel color components (Red, Green, Blue) determines the type of tile.
		/// Marble Tile (corridors) : R=255, 
		///                           G=255, 
		///                           B=255                          (white).
		/// Illegal square          : R=0, 
		///                           G=0, 
		///                           B=0                            (black).
		/// Room                    : R=255, 
		///                           G = ROOM ID NUMBER (study =0, hall =1, ... billiard room = 7, library =8), 
		///                           B=0                            (variant of Red).
		/// Door					: R=egress direction (0=north, 1=east, 2=south, 3=west, 4=secretpassage), 
		///                           G=Room ID, 
		///                           B=255                          (variant of Blue).
		/// e.g. the marble tile south of the door (6,4 in 2d array) to the study is white (0,0,0).
		///      the first tile into the study(roomId=0) is considered a door-tile facing south(dir=2) therefore tile (6,3 in 2d array) is colored (2,0,255).
		///      the top-left-most tile (0,0) is the study's secret passage to the kitchen(roomID=4) therefore its tile is colored(4,4,255).
		///      the right-bottom-most tile (23,23) is the kitchen's secret passage to the Study(roomID=0) therefore its tile is colored (4,0,255).
		/// </summary>
		void initFloor()
		{ // static floor tiles 
			Bitmap bmpFloorTiles = new Bitmap(Clue_CS2010.Properties.Resources.ClueFloor);
			cFloor = new classFloor[bmpFloorTiles.Width, bmpFloorTiles.Height];
			for (int intX = 0; intX < bmpFloorTiles.Width; intX++)
				for (int intY = 0; intY < bmpFloorTiles.Height; intY++)
				{
					//if (intX == 0 && intY == 23)
					//    MessageBox.Show("stop initFloor()");
					cFloor[intX, intY] = new classFloor();
					Color clrTile = bmpFloorTiles.GetPixel(intX, intY);

					if (clrTile.R == 255 && clrTile.G == 255 && clrTile.B == 255)
					{ // white = tile
						cFloor[intX, intY].eType = enuFloor.tile;
					}
					else if (clrTile.R == 0 && clrTile.G == 0 && clrTile.B == 0)
					{ // black = invalid
						cFloor[intX, intY].eType = enuFloor.invalid;
					}
					else if (clrTile.B == 255)
					{ // blue = door : R = direction door exits room, G = roomID#
						cFloor[intX, intY].eType = enuFloor.door;
						cFloor[intX, intY].dirDoor = (enuDir)clrTile.R;
						cFloor[intX, intY].eRoom = (enuRooms)clrTile.G;
					}
					else if (clrTile.R == 255)
					{ // red = room : G = roomID#
						cFloor[intX, intY].eType = enuFloor.room;
						cFloor[intX, intY].eRoom = (enuRooms)clrTile.G;
					}
					else
						MessageBox.Show("this should not happen");
				}
		}

		void disposeSE(ref classSearchElement cSE)
		{
			Array.Resize<classSearchElement>(ref cSEArray, cSEArray.Length + 1);
			cSEArray[cSEArray.Length - 1] = cSE;
		}

		classSearchElement getSE()
		{
			classSearchElement cSERetVal;
			if (cSEArray.Length > 0)
			{
				cSERetVal = cSEArray[cSEArray.Length - 1];
				Array.Resize<classSearchElement>(ref cSEArray, cSEArray.Length - 1);
			}
			else
			{
				cSERetVal = new classSearchElement();
			}
			return cSERetVal;
		}

		public void resetAllowableMoves()
		{
			// reset allowable moves table
			for (int intX = 0; intX < MainForm.sz.Width; intX++)
				for (int intY = 0; intY < MainForm.sz.Height; intY++)
				{
					if (cSEAllowableMoves[intX, intY] != null)
					{
						disposeSE(ref cSEAllowableMoves[intX, intY]);
						cSEAllowableMoves[intX, intY] = null;
					}
				}
		}

		public void allowSecretPassage()
		{
			// if in a corner room -> set allowable secret passage
			switch (eRoom)
			{
				case enuRooms.Study:
					Point ptStudySecretPassage = new Point(0, 0);
					cSEAllowableMoves[ptStudySecretPassage.X, ptStudySecretPassage.Y] = getSE();
					cSEAllowableMoves[ptStudySecretPassage.X, ptStudySecretPassage.Y].set(ptStudySecretPassage, 0, enuDir.secretPassage);
					break;

				case enuRooms.Lounge:
					Point ptLoungeSecretPassage = new Point(MainForm.sz.Width - 1, 0);
					cSEAllowableMoves[ptLoungeSecretPassage.X, ptLoungeSecretPassage.Y] = getSE();
					cSEAllowableMoves[ptLoungeSecretPassage.X, ptLoungeSecretPassage.Y].set(ptLoungeSecretPassage, 0, enuDir.secretPassage);
					break;

				case enuRooms.Kitchen:
					Point ptKitchenSecretPassage = new Point(MainForm.sz.Width - 1, MainForm.sz.Height - 1);
					cSEAllowableMoves[ptKitchenSecretPassage.X, ptKitchenSecretPassage.Y] = getSE();
					cSEAllowableMoves[ptKitchenSecretPassage.X, ptKitchenSecretPassage.Y].set(ptKitchenSecretPassage, 0, enuDir.secretPassage);
					break;

				case enuRooms.Conservatory:
					Point ptConservatorySecretPassage = new Point(0, MainForm.sz.Height - 1);
					cSEAllowableMoves[ptConservatorySecretPassage.X, ptConservatorySecretPassage.Y] = getSE();
					cSEAllowableMoves[ptConservatorySecretPassage.X, ptConservatorySecretPassage.Y].set(ptConservatorySecretPassage, 0, enuDir.secretPassage);
					break;
			}
		}

		void resetShortestPath()
		{
			if (cShortestPath == null)
			{
				cShortestPath = new classSearchElement[MainForm.sz.Width, MainForm.sz.Height];
			}
			for (int intX = 0; intX < MainForm.sz.Width; intX++)
				for (int intY = 0; intY < MainForm.sz.Height; intY++)
				{
					if (cShortestPath[intX, intY] != null)
					{
						disposeSE(ref cShortestPath[intX, intY]);
						cShortestPath[intX, intY] = null;
					}
				}
			cNumTurnsToReachRooms = new classTurnsReachRoom[(int)enuRooms._numRooms];
			for (enuRooms eRoomCounter = (enuRooms)0; eRoomCounter < enuRooms._numRooms; eRoomCounter++)
			{
				if (cNumTurnsToReachRooms[(int)eRoomCounter] == null)
					cNumTurnsToReachRooms[(int)eRoomCounter] = new classTurnsReachRoom();
				cNumTurnsToReachRooms[(int)eRoomCounter].resetCost();
				cNumTurnsToReachRooms[(int)eRoomCounter].eRoom = eRoomCounter;
			}

			if (eRoom < enuRooms._numRooms)
				cNumTurnsToReachRooms[(int)eRoom].setCost(0);
		}

		public bool ShortestPath()
		{
			resetShortestPath();
			int intStartTurnCost = 0;
			enuRooms eCurrentRoom = eRoom;
			classSearchElement cSE;

		startShortestPath:

			if (eCurrentRoom == enuRooms.start)  // this suspect is at starting position
			{
				cSE = getSE();
				cSE.set(ptFirstTile, enuDir.secretPassage, 1, intStartTurnCost);
				cShortestPath[cSE.pt.X, cSE.pt.Y] = cSE;
				enQSE(ref cSE);
			}
			else if (eCurrentRoom == enuRooms.tiles)  // this suspect is on a floor tile outside a room
			{
				cSE = getSE();
				cSE.set(ptTile, enuDir.secretPassage, 0, intStartTurnCost);
				cShortestPath[cSE.pt.X, cSE.pt.Y] = cSE;
				enQSE(ref cSE);
			}
			else
			{									// this suspect is in a room
				classRoom cRoom = MainForm.cRooms[(int)eCurrentRoom];
				Point[] ptDoors = cRoom.getValidDoors();
				for (int intDoorCounter = 0; intDoorCounter < ptDoors.Length; intDoorCounter++)
				{
					if (classSuspect.cFloor[ptDoors[intDoorCounter].X, ptDoors[intDoorCounter].Y].dirDoor == enuDir.secretPassage)
					{
						intStartTurnCost = 0;
						switch (eCurrentRoom)
						{
							case enuRooms.Study:
								ptDoors[intDoorCounter] = new Point(0, 0);
								break;

							case enuRooms.Lounge:
								ptDoors[intDoorCounter] = new Point(23, 0);
								break;

							case enuRooms.Kitchen:
								ptDoors[intDoorCounter] = new Point(23, 23);
								break;

							case enuRooms.Conservatory:
								ptDoors[intDoorCounter] = new Point(0, 23);
								break;
						}
					}
					else
						intStartTurnCost = 0;

					cSE = getSE();
					cSE.set(ptDoors[intDoorCounter], enuDir.secretPassage, 0, intStartTurnCost);
					cShortestPath[cSE.pt.X, cSE.pt.Y] = cSE;
					enQSE(ref cSE);
				}
			}

			cSE = deQSE();

			int intAverageRoll = 3;

			while (cSE != null)
			{
				classFloor cTile = cFloor[cSE.pt.X, cSE.pt.Y];
				if (cTile.eType == enuFloor.door && cTile.dirDoor == enuDir.secretPassage && cTile.eRoom != eRoom)
				{ // take secret passage
					if (cNumTurnsToReachRooms[(int)cFloor[cSE.pt.X, cSE.pt.Y].eRoom].setCost((cSE.intTurns + 1) * 3))
					{
						classRoom cRoom = MainForm.cRooms[(int)cFloor[cSE.pt.X, cSE.pt.Y].eRoom];

						for (int intDoorCounter = 0; intDoorCounter < cRoom.ptDoors.Length; intDoorCounter++)
						{
							if (cShortestPath[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y] == null
								&& cFloor[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y].dirDoor != enuDir.secretPassage)
							{
								classSearchElement cSENew = getSE();
								cSENew.set(cRoom.ptDoors[intDoorCounter], cFloor[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y].dirDoor, 0, cSE.intTurns + 1);
								cShortestPath[cSENew.pt.X, cSENew.pt.Y] = cSENew;
								enQSE(ref cSENew);
							}
						}
					}
				}
				else
					for (enuDir dirCounter = enuDir.north; dirCounter <= enuDir.west; dirCounter++)
					{
						bool bolDoor = (cTile.eType == enuFloor.door);
						if ((bolDoor && cTile.dirDoor == dirCounter)
							|| !bolDoor)
						{
							Point ptDir = MainForm.movePoint(cSE.pt, dirCounter);
							if (ptDir.X < MainForm.sz.Width && ptDir.X >= 0 && ptDir.Y < MainForm.sz.Height && ptDir.Y >= 0)
							{
								classFloor cNewTile = cFloor[ptDir.X, ptDir.Y];
								if (cNewTile.eType == enuFloor.tile
									&& MainForm.floorTileIsFree(ptDir))
								{  // floor tile
									if (cShortestPath[ptDir.X, ptDir.Y] == null) // this new tile has not yet been seen
									{
										classSearchElement cSENew = getSE();

										int intNewSteps = cSE.intSteps + 1;
										int intNewTurns = cSE.intTurns;
										if (intNewSteps > intAverageRoll)
										{
											intNewSteps = 1;
											intNewTurns++;
										}

										cSENew.set(ptDir, MainForm.getOppDir(dirCounter), intNewSteps, intNewTurns);
										cShortestPath[cSENew.pt.X, cSENew.pt.Y] = cSENew;
										enQSE(ref cSENew);
									}
								}
								else if (cNewTile.eType == enuFloor.door)
								{    // door to a room 
									if (cNewTile.dirDoor == MainForm.getOppDir(dirCounter))
									{
										if (cNumTurnsToReachRooms[(int)cFloor[ptDir.X, ptDir.Y].eRoom].setCost((cSE.intTurns * 3 + cSE.intSteps + 1)))
										{
											classSearchElement cSENew = getSE();

											int intNewSteps = cSE.intSteps + 1;
											int intNewTurns = cSE.intTurns;
											if (intNewSteps > intAverageRoll)
											{
												intNewSteps = 1;
												intNewTurns++;
											}


											cSENew.set(ptDir, MainForm.getOppDir(dirCounter), intNewSteps, intNewTurns);

											cShortestPath[cSENew.pt.X, cSENew.pt.Y] = cSENew;

											classRoom cRoom = MainForm.cRooms[(int)cFloor[cSENew.pt.X, cSENew.pt.Y].eRoom];
											for (int intDoorCounter = 0; intDoorCounter < cRoom.ptDoors.Length; intDoorCounter++)
											{
												if (cShortestPath[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y] == null
													&& cFloor[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y].dirDoor != enuDir.secretPassage)
												{
													cSENew = getSE();
													cSENew.set(cRoom.ptDoors[intDoorCounter], cFloor[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y].dirDoor, 0, intNewTurns + 1);
													cShortestPath[cSENew.pt.X, cSENew.pt.Y] = cSENew;
													enQSE(ref cSENew);
												}
												else if (cShortestPath[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y] == null
													&& cFloor[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y].dirDoor == enuDir.secretPassage)
												{

													cSENew = getSE();
													switch (cRoom.name)
													{
														case enuRooms.Study:
															cSENew.set(new Point(0, 0), enuDir.secretPassage, 0, intNewTurns);
															break;

														case enuRooms.Lounge:
															cSENew.set(new Point(23, 0), enuDir.secretPassage, 0, intNewTurns);
															break;

														case enuRooms.Kitchen:
															cSENew.set(new Point(23, 23), enuDir.secretPassage, 0, intNewTurns);
															break;

														case enuRooms.Conservatory:
															cSENew.set(new Point(0, 23), enuDir.secretPassage, 0, intNewTurns);
															break;
													}
													cShortestPath[cSENew.pt.X, cSENew.pt.Y] = cSENew;
													enQSE(ref cSENew);
												}
											}
										}
									}
								}
							}
						}
					}
				cSE = deQSE();
			}

			// debugging test
			bool bolRetVal = true;
			for (int intX = 0; intX < MainForm.sz.Width; intX++)
				for (int intY = 0; intY < MainForm.sz.Height; intY++)
					if (cShortestPath[intX, intY] != null)
					{
						bolRetVal = false;
						if (cShortestPath[intX, intY].pt.X != intX || cShortestPath[intX, intY].pt.Y != intY)
							MessageBox.Show("setAllowableMoves() error : cell misplaced (" + intX.ToString() + "," + intY.ToString() + ") thinks it belongs to (" + cShortestPath[intX, intY].pt.X.ToString() + "," + cShortestPath[intX, intY].pt.Y.ToString() + ")");
					}
			//goto startAgain;
			return bolRetVal;
		}

		public void removeSuspectFromDoorways()
		{
			if (eRoom == enuRooms.tiles)
			{
				if (cFloor[ptTile.X, ptTile.Y].eType == enuFloor.tile)
				{
					for (enuDir eDirCounter = (enuDir)0; eDirCounter < enuDir.secretPassage; eDirCounter++)
					{
						Point ptNext = MainForm.movePoint(ptTile, eDirCounter);
						if (cFloor[ptNext.X, ptNext.Y].eType == enuFloor.door)
						{
							eRoom = cFloor[ptNext.X, ptNext.Y].eRoom;
							return;
						}
					}
				}
			}
		}

		public bool setAllowableMoves()
		{
		startAgain:
			resetAllowableMoves();

			classSearchElement cSE;
			if (eRoom == enuRooms.start)  // this suspect is at starting position
			{
				cSE = getSE();
				cSE.set(ptFirstTile, 1, enuDir.secretPassage);
				cSEAllowableMoves[cSE.pt.X, cSE.pt.Y] = cSE;
				enQSE(ref cSE);
			}
			else if (eRoom == enuRooms.tiles)  // this suspect is on a floor tile outside a room
			{
				cSE = getSE();
				cSE.set(ptTile, 0, enuDir.secretPassage);
				cSEAllowableMoves[cSE.pt.X, cSE.pt.Y] = cSE;
				enQSE(ref cSE);
			}
			else
			{									// this suspect is in a room
				classRoom cRoom = MainForm.cRooms[(int)eRoom];
				for (int intDoorCounter = 0; intDoorCounter < cRoom.ptDoors.Length; intDoorCounter++)
				{
					cSE = getSE();
					cSE.set(cRoom.ptDoors[intDoorCounter], 0, enuDir.secretPassage);

					if (cFloor[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y].dirDoor == enuDir.secretPassage)
						enQSE(ref cSE);
					else
					{
						cSE.set(cRoom.ptDoors[intDoorCounter], 0, enuDir.secretPassage);
						cSEAllowableMoves[cSE.pt.X, cSE.pt.Y] = cSE;

						enuDir dirDoor = cFloor[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y].dirDoor;
						Point ptTileOutsideDoor = MainForm.movePoint(cRoom.ptDoors[intDoorCounter], dirDoor);
						cSE.set(ptTileOutsideDoor, 0,MainForm.getOppDir( dirDoor));
						cSEAllowableMoves[cSE.pt.X, cSE.pt.Y] = cSE;
						enQSE(ref cSE);
					}
				}
			}

			cSE = deQSE();

			while (cSE != null)
			{
				if (cSE.intSteps < MainForm.udrRollDieInfo.intDieValue)
				{
					classFloor cTile = cFloor[cSE.pt.X, cSE.pt.Y];
					for (enuDir dirCounter = enuDir.north; dirCounter <= enuDir.west; dirCounter++)
					{
						bool bolDoor = (cTile.eType == enuFloor.door);
						if ((bolDoor && cTile.dirDoor == dirCounter)
							|| !bolDoor)
						{
							Point ptDir = MainForm.movePoint(cSE.pt, dirCounter);
							if (ptDir.X < MainForm.sz.Width && ptDir.X >= 0 && ptDir.Y < MainForm.sz.Height && ptDir.Y >= 0)
							{
								classFloor cNewTile = cFloor[ptDir.X, ptDir.Y];
								if (cNewTile.eType == enuFloor.tile
									&& MainForm.floorTileIsFree(ptDir))
								{  // floor tile
									if (cSEAllowableMoves[ptDir.X, ptDir.Y] == null) // this new tile has not yet been seen
									{
										classSearchElement cSENew = getSE();
										cSENew.set(ptDir, cSE.intSteps + 1, MainForm.getOppDir(dirCounter));
										cSEAllowableMoves[cSENew.pt.X, cSENew.pt.Y] = cSENew;
										enQSE(ref cSENew);
									}
								}
								else if (cNewTile.eType == enuFloor.door)
								{    // door to a room 
									if (cNewTile.dirDoor == MainForm.getOppDir(dirCounter))
									{
										classSearchElement cSENew = getSE();
										cSENew.set(ptDir, cSE.intSteps + 1, MainForm.getOppDir(dirCounter));
										cSEAllowableMoves[cSENew.pt.X, cSENew.pt.Y] = cSENew;
									}
								}
							}
						}
					}
				}
				else if (cSE.intSteps == MainForm.udrRollDieInfo.intDieValue)
				{
					// if next to a door -> allow enter room
					classFloor cTile = cFloor[cSE.pt.X, cSE.pt.Y];
					for (enuDir dirCounter = enuDir.north; dirCounter <= enuDir.west; dirCounter++)
					{
						Point ptDir = MainForm.movePoint(cSE.pt, dirCounter);
						if (ptDir.X < MainForm.sz.Width && ptDir.X >= 0 && ptDir.Y < MainForm.sz.Height && ptDir.Y >= 0)
						{
							classFloor cNewTile = cFloor[ptDir.X, ptDir.Y];
							if (cNewTile.eType == enuFloor.door)
							{    // door to a room 
								if (cNewTile.dirDoor == MainForm.getOppDir(dirCounter))
								{
									classSearchElement cSENew = getSE();
									cSENew.set(ptDir, cSE.intSteps + 1, MainForm.getOppDir(dirCounter));
									cSEAllowableMoves[cSENew.pt.X, cSENew.pt.Y] = cSENew;
								}
							}
						}
					}
				}
				cSE = deQSE();
			}

			if (eRoom < enuRooms._numRooms) // this suspect is inside a room -> remove doors from allowable moves
				removeDoorsFromAllowableMoves();

			bool bolRetVal = true;
			for (int intX = 0; intX < MainForm.sz.Width; intX++)
				for (int intY = 0; intY < MainForm.sz.Height; intY++)
					if (cSEAllowableMoves[intX, intY] != null)
					{
						bolRetVal = false;
						if (cSEAllowableMoves[intX, intY].pt.X != intX || cSEAllowableMoves[intX, intY].pt.Y != intY)
							MessageBox.Show("setAllowableMoves() error : cell misplaced (" + intX.ToString() + "," + intY.ToString() + ") thinks it belongs to (" + cSEAllowableMoves[intX, intY].pt.X.ToString() + "," + cSEAllowableMoves[intX, intY].pt.Y.ToString() + ")");
					}
			//goto startAgain;
			return bolRetVal;
		}

		void removeDoorsFromAllowableMoves()
		{ // this is called when the suspect is moving away from a room
			for (int intX = 0; intX < MainForm.sz.Width; intX++)
				for (int intY = 0; intY < MainForm.sz.Height; intY++)
				{
					if (cSEAllowableMoves[intX, intY] != null)
					{
						classFloor cTile = cFloor[intX, intY];

						if ((cTile.eType == enuFloor.door && cTile.eRoom == oppositeCornerRoomID(eRoom))
							|| (cTile.eType == enuFloor.door && cTile.eRoom == eRoom))
						{
							disposeSE(ref cSEAllowableMoves[intX, intY]);
							cSEAllowableMoves[intX, intY] = null;
						}
					}
				}
		}

		enuRooms oppositeCornerRoomID(enuRooms eRoom)
		{
			switch (eRoom)
			{
				case enuRooms.Study:
					return enuRooms.Kitchen;

				case enuRooms.Lounge:
					return enuRooms.Conservatory;

				case enuRooms.Kitchen:
					return enuRooms.Study;

				case enuRooms.Conservatory:
					return enuRooms.Lounge;

				default:
					return enuRooms._numRooms;
			}
		}

		void enQSE(ref classSearchElement cThisSE)
		{
			if (searchQ.head == null)
			{
				searchQ.head = cThisSE;
				searchQ.tail = cThisSE;
			}
			else if (searchQ.tail == searchQ.head)
			{
				searchQ.head.next = cThisSE;
				searchQ.tail = cThisSE;
			}
			else
			{
				searchQ.tail.next = cThisSE;
				searchQ.tail = cThisSE;
			}
		}

		classSearchElement deQSE()
		{
			classSearchElement SERetVal = searchQ.head;
			if (searchQ.head == null)
			{
				return null;
			}
			else if (searchQ.head == searchQ.tail)
			{
				searchQ.head = searchQ.tail = null;
			}
			else
			{
				searchQ.head = searchQ.head.next;
			}
			return SERetVal;
		}

		public void receiveCard(ref classCard thisCard)
		{
			Array.Resize<classCard>(ref cCards, cCards.Length + 1);
			cCards[cCards.Length - 1] = thisCard;
			checkNote(thisCard.eCardName, eName);
		}

		public void XNote(enuCards eCard, enuSuspects eSuspect)
		{
			udrAILogic.eNotes[(int)eSuspect, (int)eCard] = enuNote.X;

			bool bolAllXs = true;
			for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
			{
				if (udrAILogic.eNotes[(int)eSuspectCounter, (int)eCard] != enuNote.X)
					bolAllXs = false;
			}

			if (bolAllXs)
			{
				// we have eliminated all possibilities -> this card is part of the solution
				if (MainForm.cCards[(int)eCard].IsARoom)
				{
					udrAILogic.eRoomsLeft = new enuRooms[1];
					udrAILogic.eRoomsLeft[0] = MainForm.getERoomFromCard(eCard);
				}
				else if (MainForm.cCards[(int)eCard].IsAWeapon)
				{
					udrAILogic.eWeaponsLeft = new enuWeapons[1];
					udrAILogic.eWeaponsLeft[0] = MainForm.getEWeaponFromCard(eCard);
				}
				else if (MainForm.cCards[(int)eCard].IsASuspect)
				{
					udrAILogic.eSuspectsLeft = new enuSuspects[1];
					udrAILogic.eSuspectsLeft[0] = MainForm.getESuspectFromCard(eCard);
				}
				else
					MessageBox.Show("we have a problem! : xNote(" + eCard.ToString() + ", " + eSuspect.ToString() + ") -> card type invalid");
			}
		}

		/// <summary>
		/// called when a suspect has been determined to have a card
		/// </summary>
		/// <param name="eCard">card which the suspect holds</param>
		/// <param name="eSuspect">suspect holding the card</param>
		void checkNote(enuCards eCard, enuSuspects eSuspect)
		{
			// debug start -> test faulty logic
			if (eCard == classCard.getECardFromERoom(MainForm.udrMurder.eRoom)
				|| eCard == classCard.getECardFromEWeapon(MainForm.udrMurder.eWeapon)
				|| eCard == classCard.getECardFromESuspect(MainForm.udrMurder.eSuspect))
			{
				MessageBox.Show("checkNote : faulty logic");
				return;
			}
			// debug end

			udrAILogic.eNotes[(int)eSuspect, (int)eCard] = enuNote.check;

			if ((eAILevel == enuAILevel.stupid && (int)(MainForm.rnd.NextDouble() * 1000) % 400 == 0) // ai may notice that all of this suspect's cards have been identified
			 || (eAILevel == enuAILevel.dull && (int)(MainForm.rnd.NextDouble() * 1000) % 50 == 0)
			 || (eAILevel == enuAILevel.average && (int)(MainForm.rnd.NextDouble() * 1000) % 10 == 0)
			 || (eAILevel == enuAILevel.bright && (int)(MainForm.rnd.NextDouble() * 1000) % 2 == 0)
			 || (eAILevel == enuAILevel.genius ))
			{
				int intCountNumCardsKnown = 0;
				for (enuCards eCardCounter = (enuCards)0; eCardCounter < enuCards._numCards; eCardCounter++)
				{
					if (udrAILogic.eNotes[(int)eSuspect, (int)eCardCounter] == enuNote.check)
						intCountNumCardsKnown++;
				}
				if (intCountNumCardsKnown == MainForm.cSuspects[(int)eSuspect].cCards.Length)
				{
					// all of this suspect's cards have been identified -> X the ones that are unknown for this suspect
					for (enuCards eCardCounter = (enuCards)0; eCardCounter < enuCards._numCards; eCardCounter++)
					{
						if (udrAILogic.eNotes[(int)eSuspect, (int)eCardCounter] != enuNote.check)
							XNote(eCardCounter, eSuspect);
					}
				}
			}

			// for this card : set 'X' in note for all suspects (they DO NOT have this card) and a 'check' for suspect who does have it
			for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
			{
				if (eSuspect != eSuspectCounter)
				{
					if (udrAILogic.eNotes[(int)eSuspectCounter, (int)eCard] != enuNote.X)
					{
						XNote(eCard, eSuspectCounter);

					startSetLoop:
						if (udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled != null)
							for (int intSetCounter = 0; intSetCounter < udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled.Length; intSetCounter++)
							{
								if (udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter] != null)
								{
									for (int intCardCounter = 0; intCardCounter < udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown.Length; intCardCounter++)
									{
										if (udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown[intCardCounter] == eCard)
										{ // since we now know that this suspect does NOT have this card
											// this suspect therefore did NOT show this card previously
											// remove this card from set of unknowns
											udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown[intCardCounter] = udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown[udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown.Length - 1];
											Array.Resize<enuCards>(ref udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown, udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown.Length - 1);
											if (udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown.Length == 1)
											{ // there is only one card remaining -> the card remaining MUST BE the one this suspect showed (has)
												checkNote(udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown[0], eSuspectCounter);
											}
											goto startSetLoop;
										}
									}
								}
							}
					}
				}
			}

			// scan through all AI sets
		// if this new 'known' card is among the list of unknown sets -> cancel those sets
		startScanningPreviousUnknownSets:
			if (udrAILogic.cSuspectsUnknowns[(int)eSuspect].cSetsOfCardsCalled != null)
			{ // scan each of this suspects MayHaveBeenShown sets of cards
				for (int intSetCounter = 0; intSetCounter < udrAILogic.cSuspectsUnknowns[(int)eSuspect].cSetsOfCardsCalled.Length; intSetCounter++)
				{  // scan each card in this set
					for (int intCardCounter = 0; intCardCounter < udrAILogic.cSuspectsUnknowns[(int)eSuspect].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown.Length; intCardCounter++)
					{ // compare each card in this set to new 'known' card eCard
						if (udrAILogic.cSuspectsUnknowns[(int)eSuspect].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown[intCardCounter] == eCard)
						{
							// this set needs to be deleted
							udrAILogic.cSuspectsUnknowns[(int)eSuspect].cSetsOfCardsCalled[intSetCounter] = udrAILogic.cSuspectsUnknowns[(int)eSuspect].cSetsOfCardsCalled[udrAILogic.cSuspectsUnknowns[(int)eSuspect].cSetsOfCardsCalled.Length - 1];
							Array.Resize<classCardsCalled>(ref udrAILogic.cSuspectsUnknowns[(int)eSuspect].cSetsOfCardsCalled, udrAILogic.cSuspectsUnknowns[(int)eSuspect].cSetsOfCardsCalled.Length - 1);
							goto startScanningPreviousUnknownSets;
						}
					}
				}
			}

			int intNumSuspects = (int)enuSuspects._numSuspects;
			int intNumWeapons = (int)enuWeapons._numWeapons;

			if ((int)eCard < intNumSuspects)
			{ // known card is a suspect
				enuSuspects eSuspectCardShown = (enuSuspects)((int)eCard);
				for (int intUnknownSuspectsCounter = 0; intUnknownSuspectsCounter < udrAILogic.eSuspectsLeft.Length; intUnknownSuspectsCounter++)
				{
					if (udrAILogic.eSuspectsLeft[intUnknownSuspectsCounter] == eSuspectCardShown)
					{
						udrAILogic.eSuspectsLeft[intUnknownSuspectsCounter] = udrAILogic.eSuspectsLeft[udrAILogic.eSuspectsLeft.Length - 1];
						Array.Resize<enuSuspects>(ref udrAILogic.eSuspectsLeft, udrAILogic.eSuspectsLeft.Length - 1);
					}
				}
			}
			else if ((int)eCard < intNumSuspects + intNumWeapons)
			{ // known card is a weapon
				enuWeapons eWeaponCardShown = (enuWeapons)((int)eCard - intNumSuspects);
				for (int intUnknownWeaponsCounter = 0; intUnknownWeaponsCounter < udrAILogic.eWeaponsLeft.Length; intUnknownWeaponsCounter++)
				{
					if (udrAILogic.eWeaponsLeft[intUnknownWeaponsCounter] == eWeaponCardShown)
					{
						udrAILogic.eWeaponsLeft[intUnknownWeaponsCounter] = udrAILogic.eWeaponsLeft[udrAILogic.eWeaponsLeft.Length - 1];
						Array.Resize<enuWeapons>(ref udrAILogic.eWeaponsLeft, udrAILogic.eWeaponsLeft.Length - 1);
					}
				}
			}
			else
			{ // known card is a room
				enuRooms eRoomCardShown = (enuRooms)((int)eCard - intNumSuspects - intNumWeapons);
				for (int intUnknownRoomsCounter = 0; intUnknownRoomsCounter < udrAILogic.eRoomsLeft.Length; intUnknownRoomsCounter++)
				{
					if (udrAILogic.eRoomsLeft[intUnknownRoomsCounter] == eRoomCardShown)
					{
						udrAILogic.eRoomsLeft[intUnknownRoomsCounter] = udrAILogic.eRoomsLeft[udrAILogic.eRoomsLeft.Length - 1];
						Array.Resize<enuRooms>(ref udrAILogic.eRoomsLeft, udrAILogic.eRoomsLeft.Length - 1);
					}
				}
			}
		}


		bool IHaveThisCard(enuRooms eRoom) { return IHaveThisCard(classCard.getECardFromERoom(eRoom)); }
		bool IHaveThisCard(enuWeapons eWeapon) { return IHaveThisCard(classCard.getECardFromEWeapon(eWeapon)); }
		bool IHaveThisCard(enuSuspects eSuspect) { return IHaveThisCard(classCard.getECardFromESuspect(eSuspect)); }
		bool IHaveThisCard(enuCards eCard)
		{
			for (int intCardCounter = 0; intCardCounter < cCards.Length; intCardCounter++)
				if (cCards[intCardCounter].eCardName == eCard)
					return true;
			return false;
		}

		public enuCards RespondToSuggestion()
		{
			enuCards[] eSuggestedCardsIHave = new enuCards[0];
			if (IHaveThisCard(MainForm.udrSuggestion.eSuspect))
				appendECardArray(ref eSuggestedCardsIHave, classCard.getECardFromESuspect(MainForm.udrSuggestion.eSuspect));
			if (IHaveThisCard(MainForm.udrSuggestion.eWeapon))
				appendECardArray(ref eSuggestedCardsIHave, classCard.getECardFromEWeapon(MainForm.udrSuggestion.eWeapon));
			if (IHaveThisCard(MainForm.udrSuggestion.eRoom))
				appendECardArray(ref eSuggestedCardsIHave, classCard.getECardFromERoom(MainForm.udrSuggestion.eRoom));

			if (eSuggestedCardsIHave.Length > 1)
			{
				// cycle through the cards I can respond and see if I've already shown one of them to the suggesting suspect
				for (int intCardCounter = 0; intCardCounter < eSuggestedCardsIHave.Length; intCardCounter++)
				{
					if (udrAILogic.eNotes[MainForm.intSuspectTurn, (int)eSuggestedCardsIHave[intCardCounter]] == enuNote.shown)
						return eSuggestedCardsIHave[intCardCounter];
				}
				// if none of the valid cards have already been shown -> show a new one
				int intRnd = (int)(MainForm.rnd.NextDouble() * 1000) % eSuggestedCardsIHave.Length;
				udrAILogic.eNotes[MainForm.intSuspectTurn, (int)eSuggestedCardsIHave[intRnd]] = enuNote.shown;
				return eSuggestedCardsIHave[intRnd];
			}
			else if (eSuggestedCardsIHave.Length == 1)
			{
				return eSuggestedCardsIHave[0];
			}

			return enuCards.NoCardShown;
		}

		void appendECardArray(ref enuCards[] eCardArray, enuCards eNewCard)
		{
			Array.Resize<enuCards>(ref eCardArray, eCardArray.Length + 1);
			eCardArray[eCardArray.Length - 1] = eNewCard;
		}

		public void ResponseToSuggestion(enuSuspects eSuspectResponding, enuCards eCardShown)
		{
			enuCards[] eCardsCalled = new enuCards[3];
			eCardsCalled[0] = MainForm.getCardFromERoom(MainForm.udrSuggestion.eRoom);
			eCardsCalled[1] = MainForm.getCardFromESuspect(MainForm.udrSuggestion.eSuspect);
			eCardsCalled[2] = MainForm.getCardFromEWeapon(MainForm.udrSuggestion.eWeapon);

			// scan list of cards which we know the responding suspect does NOT have and eliminate those from the current suggestion
		beginScanCardsCalled:
			for (int intCalledCardsCounter = 0; intCalledCardsCounter < eCardsCalled.Length; intCalledCardsCounter++)
			{
				for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
				{ // we know the responding suspect has this card -> remove it from the list of currently suggested cards

					if ((eSuspectCounter == eSuspectResponding && udrAILogic.eNotes[(int)eSuspectCounter, (int)eCardsCalled[intCalledCardsCounter]] == enuNote.X)
						|| (eSuspectCounter != eSuspectResponding && udrAILogic.eNotes[(int)eSuspectCounter, (int)eCardsCalled[intCalledCardsCounter]] == enuNote.check))
					{ // we know some responding suspect does NOT HAVE THIS CARD
						eCardsCalled[intCalledCardsCounter] = eCardsCalled[eCardsCalled.Length - 1];
						Array.Resize<enuCards>(ref eCardsCalled, eCardsCalled.Length - 1);
						goto beginScanCardsCalled;
					}
					else if (eSuspectCounter == eSuspectResponding && udrAILogic.eNotes[(int)eSuspectCounter, (int)eCardsCalled[intCalledCardsCounter]] == enuNote.check)
					{
						// we already know that the responding suspect has one of the cards -> no inference can be made
						return;
					}
				}
			}

			if (eCardsCalled.Length == 1 && eCardShown != enuCards.NoCardShown)
			{ // after eliminating all known cards we are left with one card and that must be the card which was shown
				eCardShown = eCardsCalled[0];
			}

			if (eCardShown == enuCards.Unknown)
			{ // the suspect responding to suggestion holds one of called card but we don't know which of the three (room, suspect or weapon)
				// create a new set and append the current list of unknown sets for the responding suspect
				if (eAILevel == enuAILevel.genius
					|| (eAILevel == enuAILevel.bright && ((int)(MainForm.rnd.NextDouble() * 1000)) % 4 == 0)
					|| (eAILevel == enuAILevel.average && ((int)(MainForm.rnd.NextDouble() * 1000)) % 8 == 0)
					|| (eAILevel == enuAILevel.dull && ((int)(MainForm.rnd.NextDouble() * 1000)) % 12 == 0)
					|| (eAILevel == enuAILevel.stupid && ((int)(MainForm.rnd.NextDouble() * 1000)) % 15 == 0))
				{
					if (udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled == null)
						udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled = new classCardsCalled[0];
					Array.Resize<classCardsCalled>(ref udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled, udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled.Length + 1);

					udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled.Length - 1] = new classCardsCalled();
					udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled.Length - 1].cCardsThatMightHaveBeenShown = eCardsCalled;
				}
			}
			else if (eCardShown == enuCards.NoCardShown)
			{ // this Suspect has none of the suggested cards in his hand
				// set the responding suspect's notes to reflect that he does not have the called cards
				if (eAILevel == enuAILevel.genius
					|| (eAILevel == enuAILevel.bright && ((int)(MainForm.rnd.NextDouble() * 1000)) % 2 == 0)
					|| (eAILevel == enuAILevel.average && ((int)(MainForm.rnd.NextDouble() * 1000)) % 4 == 0)
					|| (eAILevel == enuAILevel.dull && ((int)(MainForm.rnd.NextDouble() * 1000)) % 6 == 0)
					|| (eAILevel == enuAILevel.stupid && ((int)(MainForm.rnd.NextDouble() * 1000)) % 8 == 0))
				{
					for (int intCalledCardCounter = 0; intCalledCardCounter < eCardsCalled.Length; intCalledCardCounter++)
					{
						XNote(eCardsCalled[intCalledCardCounter], eSuspectResponding);
					}
					// scan all previous sets of cards for which this suspect has shown one of the called card (above: eCardShown == enuCards.Unknown)
					// if any of the suggested cards are included in these sets of unknowns -> we now know that that card was NOT SHOWN because the suspect does not have that card
					// eliminate it from the three for that(those) set(s) -> when set is reduced to 1 card -> remaining card is the card he showed, the card he has

					// scan each previous set
					if (udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled != null)
					{
					startSetCounterLoop:
						for (int intSetCounter = 0; intSetCounter < udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled.Length; intSetCounter++)
						{
							// scan each card in this previous set
							for (int intCardsMayHaveBeenShownCounter = 0; intCardsMayHaveBeenShownCounter < udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown.Length; intCardsMayHaveBeenShownCounter++)
							{
								// compare to each of the three cards in the current set (current suggestion)							
								for (int intCardsCalledCounter = 0; intCardsCalledCounter < eCardsCalled.Length; intCardsCalledCounter++)
								{
									if (eCardsCalled[intCardsCalledCounter] == udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown[intCardsMayHaveBeenShownCounter])
									{  // we now know that this is NOT the card which the responding suspect showed previously
										// remove this card from the list of possible cards which the responding suspect showed in an earlier response to another suggestion
										udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown[intCardsMayHaveBeenShownCounter] = udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown[udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown.Length - 1];
										Array.Resize<enuCards>(ref udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown, udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown.Length - 1);
										if (udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown.Length == 1)
										{ // the only card remaining MUST be the card which this responding suspect showed earlier
											checkNote(udrAILogic.cSuspectsUnknowns[(int)eSuspectResponding].cSetsOfCardsCalled[intSetCounter].cCardsThatMightHaveBeenShown[0], eSuspectResponding);
											// this set is removed inside checkNote() -> NO NEED TO REMOVE IT HERE
										}
										goto startSetCounterLoop;
									}
								}
							}
						}
					}
				}
			}
			else
			{
				// responding suspect has shown a card
				// include this information in our notes
				checkNote(eCardShown, eSuspectResponding);
			}
		}

		void setFirstTiles()
		{
			switch (eName)
			{
				case enuSuspects.ColMustard:
					ptFirstTile = new Point(22, 7);
					break;

				case enuSuspects.MissScarlet:
					ptFirstTile = new Point(16, 1);
					break;

				case enuSuspects.RevGreen:
					ptFirstTile = new Point(9, 23);
					break;

				case enuSuspects.MrsPeacock:
					ptFirstTile = new Point(1, 18);
					break;

				case enuSuspects.MrsWhite:
					ptFirstTile = new Point(14, 23);
					break;

				case enuSuspects.ProfPlum:
					ptFirstTile = new Point(1, 5);
					break;
			}
		}

		bool IsACornerRoom() { return IsACornerRoom(eRoom); }
		bool IsACornerRoom(enuRooms eThisRoom)
		{
			return (eThisRoom == enuRooms.Study || eThisRoom == enuRooms.Lounge || eThisRoom == enuRooms.Kitchen || eThisRoom == enuRooms.Conservatory);
		}

		

		bool useSecretPassage()
		{
			if (!IsACornerRoom())
				return false;

			enuRooms eOppositeCornerRoom = MainForm.cRooms[(int)eRoom].oppositeCornerRoom();

			// if heading to opposite corner room
			if (udrAILogic.eDestinationRoom == eOppositeCornerRoom)
			{
				switch (eRoom)
				{
					case enuRooms.Study:
						udrAILogic.ptDestinationTile = new Point(0, 0);
						return true;

					case enuRooms.Lounge:
						udrAILogic.ptDestinationTile = new Point(23, 0);
						return true;

					case enuRooms.Kitchen:
						udrAILogic.ptDestinationTile = new Point(23, 23);
						return true;

					case enuRooms.Conservatory:
						udrAILogic.ptDestinationTile = new Point(0, 23);
						return true;
				}
			}

			// trace steps back from target room
			enuRooms eCurrentRoom = udrAILogic.eDestinationRoom;

			while (true)
			{
				// in a room
				Point ptBestDoorFromRoom = new Point(0, 0);
				if (getBestDoorOutThisRoom(eCurrentRoom, ref ptBestDoorFromRoom, true))
				{
					bool bolOnTiles = true;
					if (ptBestDoorFromRoom.X < 0)
					{ // use a secret passage
						if (Math.Abs(ptBestDoorFromRoom.X) % (int)enuRooms._numRooms == (int)eRoom)
							return true;
						else
						{
							eCurrentRoom = (enuRooms)((int)Math.Abs(ptBestDoorFromRoom.X) % (int)enuRooms._numRooms);
							bolOnTiles = false;
						}
					}
					else
					{
						Point ptTile = MainForm.movePoint(ptBestDoorFromRoom, cFloor[ptBestDoorFromRoom.X, ptBestDoorFromRoom.Y].dirDoor);
						while (bolOnTiles)
						{
							ptTile = MainForm.movePoint(ptTile, cShortestPath[ptTile.X, ptTile.Y].SrcDir);
							bolOnTiles = (cFloor[ptTile.X, ptTile.Y].eType == enuFloor.tile);
						}
						eCurrentRoom = cFloor[ptTile.X, ptTile.Y].eRoom;

					}
					if (eCurrentRoom == eRoom)
						return false;

				}
				else
				{
					return false;
				}
			}




			//classRoom cOppRoom = MainForm.cRooms[(int)eOppositeCornerRoom];
			//Point[] ptOppositeCornerRoomValidDoors = cOppRoom.getValidDoors();

			//for (int intOppCorRooValDoorCounter = 0; intOppCorRooValDoorCounter < ptOppositeCornerRoomValidDoors.Length; intOppCorRooValDoorCounter++)
			//{
			//    if (classSuspect.cFloor[ptOppositeCornerRoomValidDoors[intOppCorRooValDoorCounter].X, ptOppositeCornerRoomValidDoors[intOppCorRooValDoorCounter].Y].dirDoor != enuDir.secretPassage)
			//    {
			//        Point ptTileOutsideOppRoomDoor = MainForm.movePoint(ptOppositeCornerRoomValidDoors[intOppCorRooValDoorCounter], classSuspect.cFloor[ptOppositeCornerRoomValidDoors[intOppCorRooValDoorCounter].X, ptOppositeCornerRoomValidDoors[intOppCorRooValDoorCounter].Y].dirDoor);
			//        if (cShortestPath[ptTileOutsideOppRoomDoor.X, ptTileOutsideOppRoomDoor.Y].intCost == 4)
			//            return true;
			//    }
			//}
			return false;
		}


		bool eRoomIsLeft(enuRooms eThisRoom)
		{
			for (int intRoomsLeftCounter = 0; intRoomsLeftCounter < udrAILogic.eRoomsLeft.Length; intRoomsLeftCounter++)
				if (udrAILogic.eRoomsLeft[intRoomsLeftCounter] == eThisRoom)
					return true;
			return false;
		}

		bool IWantToAccuse()
		{
			return (udrAILogic.eRoomsLeft.Length == 1 && udrAILogic.eSuspectsLeft.Length == 1 && udrAILogic.eWeaponsLeft.Length == 1);
		}

		public void playTurn()
		{
			ShortestPath();

			if (bolMustMove)
				PickDestinationRoom();
			else 
				udrAILogic.eDestinationRoom = eRoom;

			/* /// debug start 
			udrAILogic.eRoomsLeft = new enuRooms[1];
			udrAILogic.eRoomsLeft[0] = MainForm.udrMurder.eRoom;
			
			udrAILogic.eWeaponsLeft = new enuWeapons[1];
			udrAILogic.eWeaponsLeft[0] = MainForm.udrMurder.eWeapon;

			udrAILogic.eSuspectsLeft = new enuSuspects[1];
			udrAILogic.eSuspectsLeft[0] = MainForm.udrMurder.eSuspect;
			/// debug end */



			if (IWantToAccuse())
			{
				udtMurder udrAccusation = new udtMurder();
				udrAccusation.eRoom = udrAILogic.eRoomsLeft[0];
				udrAccusation.eSuspect = udrAILogic.eSuspectsLeft[0];
				udrAccusation.eWeapon = udrAILogic.eWeaponsLeft[0];
				MainForm.Accuse(eName, udrAccusation);
				return;
			}

			if (!bolCanSuggest && udrAILogic.eDestinationRoom == eRoom)
			{ // the room I am in is the destination room because there is no way out
				// I can NOT suggest -> end turn
				MainForm.eMode = enuMode.endTurn;
				resetShortestPath();
				return;
			}


			if (bolCanSuggest && eRoomIsLeft(eRoom)
				&& !(eAILevel == enuAILevel.genius && (int)(MainForm.rnd.NextDouble() * 1000) % 5000 == 0) // lower ai may make a mistake and neglect to suggest
				&& !(eAILevel == enuAILevel.bright && (int)(MainForm.rnd.NextDouble() * 1000) % 1000 == 0)
				&& !(eAILevel == enuAILevel.average && (int)(MainForm.rnd.NextDouble() * 1000) % 500 == 0)
				&& !(eAILevel == enuAILevel.dull && (int)(MainForm.rnd.NextDouble() * 1000) % 100 == 0)
				&& !(eAILevel == enuAILevel.stupid && (int)(MainForm.rnd.NextDouble() * 1000) % 10 == 0))
			{
				makeSuggestion();
				return;
			}
			else
			{
				if (useSecretPassage())
				{
					switch (eRoom)
					{
						case enuRooms.Study:
							udrAILogic.ptDestinationTile = new Point(0, 0);
							break;

						case enuRooms.Lounge:
							udrAILogic.ptDestinationTile = new Point(23, 0);
							break;

						case enuRooms.Kitchen:
							udrAILogic.ptDestinationTile = new Point(23, 23);
							break;

						case enuRooms.Conservatory:
							udrAILogic.ptDestinationTile = new Point(0, 23);
							break;
					}
					allowSecretPassage();
				}
				else
				{
					MainForm.rollDie();
					return;
				}

				MainForm.picMouseClick((object)MainForm.picBoard, new MouseEventArgs(MouseButtons.Left, 1, MainForm.ptBoardTL.X + 28 * udrAILogic.ptDestinationTile.X + 3, MainForm.ptBoardTL.Y + 28 * udrAILogic.ptDestinationTile.Y + 3, 0));
				bolMustMove = false;
				if (bolCanSuggest)
					makeSuggestion();
				return;
			}

		endPlayTurn:
			bolCanSuggest = false;
			resetShortestPath();
		}

		public void endShowAllowableMoves()
		{
			if (!PickDestinationTile())
			{ // can't move
				bolCanSuggest = false;
				resetShortestPath();
			}
			bolMustMove = false;
			MainForm.picMouseClick((object)MainForm.picBoard, new MouseEventArgs(MouseButtons.Left, 1, MainForm.ptBoardTL.X + 28 * udrAILogic.ptDestinationTile.X + 3, MainForm.ptBoardTL.Y + 28 * udrAILogic.ptDestinationTile.Y + 3, 0));
			if (bolCanSuggest)
				makeSuggestion();
		}


		public void playTurnAfterMove()
		{
			if (bolCanSuggest)
			{
				makeSuggestion();
				return;
			}
			bolCanSuggest = false;
			resetShortestPath();
			MainForm.eMode = enuMode.endTurn;
		}

		void prepareSuggestionAI()
		{
			udrAILogic.udrSuggestionAI.udrRoomCardsMysteryFrequency = new udtSuggestionAI_frequenCards[0];
			udrAILogic.udrSuggestionAI.udrWeaponMysteryFrequency = new udtSuggestionAI_frequenCards[0];
			udrAILogic.udrSuggestionAI.udrSuspectMysteryFrequency = new udtSuggestionAI_frequenCards[0];

			for (int intSuspectCounter = 0; intSuspectCounter < udrAILogic.udrSuggestionAI.suspectMysteryInfo.Length; intSuspectCounter++)
			{
				// scan each suspect's unknown "mystery" card sets
				// count the number of each type of card and order them into that suspect's arrays AND accumulate into overall array
				udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrRoomsMystery = new udtSuggestionAI_frequenCards[0];
				udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrWeaponCardsMystery = new udtSuggestionAI_frequenCards[0];
				udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrSuspectCardsMystery = new udtSuggestionAI_frequenCards[0];

				classCardsCalled[] cCardSets = udrAILogic.cSuspectsUnknowns[(int)udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].eSuspect].cSetsOfCardsCalled;
				if (cCardSets != null)
				{
					for (int intSetCounter = 0; intSetCounter < cCardSets.Length; intSetCounter++)
					{
						enuCards[] eCardsCalled = cCardSets[intSetCounter].cCardsThatMightHaveBeenShown;
						// for each card which this suspect was asked when he showed a card
						// separate into type : room, weapon or suspect
						for (int intCardCounter = 0; intCardCounter < eCardsCalled.Length; intCardCounter++)
						{
							if (MainForm.cCards[(int)eCardsCalled[intCardCounter]].IsARoom)
							{
								addECardToFrequencyCards(ref udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrRoomsMystery, eCardsCalled[intCardCounter]);
								addECardToFrequencyCards(ref udrAILogic.udrSuggestionAI.udrRoomCardsMysteryFrequency, eCardsCalled[intCardCounter]);
							}
							else if (MainForm.cCards[(int)eCardsCalled[intCardCounter]].IsAWeapon)
							{
								addECardToFrequencyCards(ref udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrWeaponCardsMystery, eCardsCalled[intCardCounter]);
								addECardToFrequencyCards(ref udrAILogic.udrSuggestionAI.udrWeaponMysteryFrequency, eCardsCalled[intCardCounter]);
							}
							else if (MainForm.cCards[(int)eCardsCalled[intCardCounter]].IsASuspect)
							{
								addECardToFrequencyCards(ref udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrSuspectCardsMystery, eCardsCalled[intCardCounter]);
								addECardToFrequencyCards(ref udrAILogic.udrSuggestionAI.udrSuspectMysteryFrequency, eCardsCalled[intCardCounter]);
							}
							else
								MessageBox.Show("this should NOT HAPPEN! : prepareSuggestionAI() -> don't know what kind of card this is");
						}
					}
					// reorder the three type arrays according to frequency
					reorderFrequencyCardsByNumber(ref udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrRoomsMystery);
					reorderFrequencyCardsByNumber(ref udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrSuspectCardsMystery);
					reorderFrequencyCardsByNumber(ref udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrWeaponCardsMystery);
				}
			}

			// reorder three overall type arrays according to frequency
			reorderFrequencyCardsByNumber(ref udrAILogic.udrSuggestionAI.udrRoomCardsMysteryFrequency);
			reorderFrequencyCardsByNumber(ref udrAILogic.udrSuggestionAI.udrSuspectMysteryFrequency);
			reorderFrequencyCardsByNumber(ref udrAILogic.udrSuggestionAI.udrWeaponMysteryFrequency);
		}

		void reorderFrequencyCardsByNumber(ref udtSuggestionAI_frequenCards[] udrFreqCards)
		{
			if (udrFreqCards == null)
				return;
			int intBestIndex, intInnerLoop, intOuterLoop;

			for (intOuterLoop = 0; intOuterLoop < udrFreqCards.Length - 1; intOuterLoop++)
			{
				intBestIndex = intOuterLoop;
				for (intInnerLoop = intOuterLoop + 1; intInnerLoop < udrFreqCards.Length; intInnerLoop++)
				{
					if (udrFreqCards[intInnerLoop].intNumMystery > udrFreqCards[intBestIndex].intNumMystery)
						intBestIndex = intInnerLoop;
				}
				if (intBestIndex != intOuterLoop)
				{
					enuCards eCardBestIndex = udrFreqCards[intBestIndex].eCards;
					int intNumBestIndex = udrFreqCards[intBestIndex].intNumMystery;

					udrFreqCards[intBestIndex].eCards = udrFreqCards[intOuterLoop].eCards;
					udrFreqCards[intBestIndex].intNumMystery = udrFreqCards[intOuterLoop].intNumMystery;

					udrFreqCards[intOuterLoop].eCards = eCardBestIndex;
					udrFreqCards[intOuterLoop].intNumMystery = intNumBestIndex;
				}
			}
		}

		void addECardToFrequencyCards(ref udtSuggestionAI_frequenCards[] udrFreqCards, enuCards eNewCard)
		{
			if (udrFreqCards == null)
				udrFreqCards = new udtSuggestionAI_frequenCards[0];
			for (int intRoomCounter = 0; intRoomCounter < udrFreqCards.Length; intRoomCounter++)
			{
				if (udrFreqCards[intRoomCounter].eCards == eNewCard)
				{  // this suspect has more than one set which includes this card as a possible solution
					udrFreqCards[intRoomCounter].intNumMystery++;
					return;
				}
			}
			// we have scanned the list and NOT found this new room
			// increase size of array and insert this new room at the end
			Array.Resize<udtSuggestionAI_frequenCards>(ref udrFreqCards, udrFreqCards.Length + 1);
			udrFreqCards[udrFreqCards.Length - 1] = new udtSuggestionAI_frequenCards();
			udrFreqCards[udrFreqCards.Length - 1].eCards = eNewCard;
			udrFreqCards[udrFreqCards.Length - 1].intNumMystery = 1;
		}


		public void makeSuggestion()
		{
			prepareSuggestionAI();

			pickSuspectForSuggestion();
			pickWeaponForSuggestion();
			MainForm.udrSuggestion.eRoom = eRoom;

			MainForm.cLibPicTraySuspects.setSelectedImage((int)MainForm.udrSuggestion.eSuspect);
			MainForm.cLibPicTraySuspects.Angle = MainForm.cLibPicTraySuspects.FrontAngle - MainForm.cLibPicTraySuspects.Tray[(int)MainForm.udrSuggestion.eSuspect].angleOnTray;
			MainForm.cLibPicTraySuspects.RefreshTrayImage();

			MainForm.cLibPicTrayWeapons.setSelectedImage((int)MainForm.udrSuggestion.eWeapon);
			MainForm.cLibPicTrayWeapons.Angle = MainForm.cLibPicTrayWeapons.FrontAngle - MainForm.cLibPicTrayWeapons.Tray[(int)MainForm.udrSuggestion.eWeapon].angleOnTray;
			MainForm.cLibPicTrayWeapons.RefreshTrayImage();
			MainForm.udrSuggestionAnimation.intProveSuggestionCycleCounter = 1;
			MainForm.eMode = enuMode.Suggest;

			bolCanSuggest = false;

			MainForm.btnMakeSuggestion_OK_click();
		}

		void pickSuspectForSuggestion()
		{
			if ((eAILevel == enuAILevel.stupid && (int)(MainForm.rnd.NextDouble() * 1000) % 2 == 0) // ai may make a poor random choice from ALL suspects
				|| (eAILevel == enuAILevel.dull && (int)(MainForm.rnd.NextDouble() * 1000) % 5 == 0)
				|| (eAILevel == enuAILevel.average && (int)(MainForm.rnd.NextDouble() * 1000) % 50 == 0)
				|| (eAILevel == enuAILevel.bright && (int)(MainForm.rnd.NextDouble() * 1000) % 500 == 0)
				|| (eAILevel == enuAILevel.genius && (int)(MainForm.rnd.NextDouble() * 1000) % 5000 == 0))
			{
				MainForm.udrSuggestion.eSuspect = (enuSuspects)((int)(MainForm.rnd.NextDouble() * 1000) % (int)enuSuspects._numSuspects);
				return;
			}
			else if (eAILevel == enuAILevel.stupid													 // ai may make a poor random choice from ALL REMAINING suspects
					 || (eAILevel == enuAILevel.dull && (int)(MainForm.rnd.NextDouble() * 1000) % 2 == 0)
					 || (eAILevel == enuAILevel.average && (int)(MainForm.rnd.NextDouble() * 1000) % 5 == 0)
					 || (eAILevel == enuAILevel.bright && (int)(MainForm.rnd.NextDouble() * 1000) % 50 == 0)
					 || (eAILevel == enuAILevel.genius && (int)(MainForm.rnd.NextDouble() * 1000) % 500 == 0))
			{
				MainForm.udrSuggestion.eSuspect = udrAILogic.eSuspectsLeft[(int)(MainForm.rnd.NextDouble() * 1000) % udrAILogic.eSuspectsLeft.Length];
				return;
			}

			if (udrAILogic.eSuspectsLeft.Length == 1)
			{ // I have narrowed down the number of suspects to one and now know which suspect has committed the murder
				// do not reveal this information to other players
				// select a suspect whose card I have in my hands
				if ((int)(MainForm.rnd.NextDouble() * 1000) % 3 == 0)
				{ // one third of the time -> pick the one I know is part of the solution
					MainForm.udrSuggestion.eSuspect = udrAILogic.eSuspectsLeft[0];
				}
				else
				{
					if (eSuspectsIHoldACardFor.Length > 0)
					{
						MainForm.udrSuggestion.eSuspect = eSuspectsIHoldACardFor[(int)(MainForm.rnd.NextDouble() * 1000) % eSuspectsIHoldACardFor.Length];
						return;
					}

					// I don't hold any suspect cards
					// go around the table in reverse order and pick the first suspect card I know the last suspect to answer my suggest already has
					for (int intSuspectCounter = 1; intSuspectCounter < (int)enuSuspects._numSuspects; intSuspectCounter++)
					{
						enuSuspects eSuspectCounter = (enuSuspects)(((int)eName + (int)enuSuspects._numSuspects - intSuspectCounter) % (int)enuSuspects._numSuspects);
						enuSuspects[] eSuspectCardsIKnowThisSuspectHolds = new enuSuspects[0];
						for (enuCards eSuspectCardCounter = (enuCards)0;
									  eSuspectCardCounter < (enuCards)((enuSuspects)(int)enuSuspects._numSuspects);
									  eSuspectCardCounter++)
						{
							if (udrAILogic.eNotes[(int)eSuspectCounter, (int)eSuspectCardCounter] == enuNote.check)
							{
								Array.Resize<enuSuspects>(ref eSuspectCardsIKnowThisSuspectHolds, eSuspectCardsIKnowThisSuspectHolds.Length + 1);
								eSuspectCardsIKnowThisSuspectHolds[eSuspectCardsIKnowThisSuspectHolds.Length - 1] = MainForm.getESuspectFromCard(eSuspectCardCounter);
							}
						}

						if (eSuspectCardsIKnowThisSuspectHolds.Length > 0)
						{
							MainForm.udrSuggestion.eSuspect = eSuspectCardsIKnowThisSuspectHolds[(int)(MainForm.rnd.NextDouble() * 1000) % eSuspectCardsIKnowThisSuspectHolds.Length];
							return;
						}
						else
						{
							MainForm.udrSuggestion.eSuspect = udrAILogic.eSuspectsLeft[0];
							return;
						}
					}

					// this shouldn't happen
					// if I reach here : I have no suspect cards and neither do any other suspects in the game
					MessageBox.Show("this should not happen : pickSuspectForSuggestion() -> I know the murder suspect is " + udrAILogic.eSuspectsLeft[0].ToString() + " and I can't pick a reasonable card");
					// program will flow into the suspect we know committed the murder
				}
			}

			// make an informed decision based on the udrAISuggestion information
			if (udrAILogic.udrSuggestionAI.udrSuspectMysteryFrequency.Length == 0) // we know of no "mystery" suspect cards -> pick one we don't know at random
				MainForm.udrSuggestion.eSuspect = udrAILogic.eSuspectsLeft[(int)(MainForm.rnd.NextDouble() * 1000) % udrAILogic.eSuspectsLeft.Length];
			else if ((int)(MainForm.rnd.NextDouble() * 1000) % 30 == 0) // tweak random frequency according to suspect's intelligence
			{ // one 30th of the time -> pick one we don't know at random
				MainForm.udrSuggestion.eSuspect = udrAILogic.eSuspectsLeft[(int)(MainForm.rnd.NextDouble() * 1000) % udrAILogic.eSuspectsLeft.Length];
			}
			else
			{
				// use udrAISuggestion information
				// go around the table in reverse order
				for (int intSuspectCounter = 1; intSuspectCounter < (int)enuSuspects._numSuspects; intSuspectCounter++)
				{
					enuSuspects eSuspectCounter = (enuSuspects)(((int)eName + (int)enuSuspects._numSuspects - intSuspectCounter) % (int)enuSuspects._numSuspects);
					classCardsCalled[] cSetsCardsCalled = udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter].cSetsOfCardsCalled;
					if (cSetsCardsCalled != null)
						for (int intSetsCounter = 0; intSetsCounter < cSetsCardsCalled.Length; intSetsCounter++)
						{
							// for each set of mystery cards for this suspect
							enuCards[] eCardsCalled = cSetsCardsCalled[intSetsCounter].cCardsThatMightHaveBeenShown;
							for (int intCardCounter = 0; intCardCounter < eCardsCalled.Length; intCardCounter++)
							{
								// find the first suspect-card and suggest it
								if (classCard.eCardIsASuspect(eCardsCalled[intCardCounter]))
								{
									MainForm.udrSuggestion.eSuspect = MainForm.getESuspectFromCard(eCardsCalled[intCardCounter]);
									return;
								}
							}
						}

				}
				// if still haven't made a choice -> pick the most common 'mystery' suspect
				MainForm.udrSuggestion.eSuspect = MainForm.getESuspectFromCard(udrAILogic.udrSuggestionAI.udrSuspectMysteryFrequency[0].eCards);
			}
		}

		void pickWeaponForSuggestion()
		{
			if ((eAILevel == enuAILevel.stupid && (int)(MainForm.rnd.NextDouble() * 1000) % 2 == 0) // ai may make a poor random choice from ALL suspects
				|| (eAILevel == enuAILevel.dull && (int)(MainForm.rnd.NextDouble() * 1000) % 5 == 0)
				|| (eAILevel == enuAILevel.average && (int)(MainForm.rnd.NextDouble() * 1000) % 50 == 0)
				|| (eAILevel == enuAILevel.bright && (int)(MainForm.rnd.NextDouble() * 1000) % 500 == 0)
				|| (eAILevel == enuAILevel.genius && (int)(MainForm.rnd.NextDouble() * 1000) % 5000 == 0))
			{
				MainForm.udrSuggestion.eWeapon = (enuWeapons)((int)(MainForm.rnd.NextDouble() * 1000) % (int)enuWeapons._numWeapons);
				return;
			}
			else if (eAILevel == enuAILevel.stupid													 // ai may make a poor random choice from ALL REMAINING suspects
					 || (eAILevel == enuAILevel.dull && (int)(MainForm.rnd.NextDouble() * 1000) % 2 == 0)
					 || (eAILevel == enuAILevel.average && (int)(MainForm.rnd.NextDouble() * 1000) % 5 == 0)
					 || (eAILevel == enuAILevel.bright && (int)(MainForm.rnd.NextDouble() * 1000) % 50 == 0)
					 || (eAILevel == enuAILevel.genius && (int)(MainForm.rnd.NextDouble() * 1000) % 500 == 0))
			{
				MainForm.udrSuggestion.eWeapon = udrAILogic.eWeaponsLeft[(int)(MainForm.rnd.NextDouble() * 1000) % udrAILogic.eWeaponsLeft.Length];
				return;
			}

			if (udrAILogic.eWeaponsLeft.Length == 1)
			{ // I have narrowed down the number of Weapons to one and now know which Weapon was used in committing the murder
				// do not reveal this information to other players
				// select a Weapon whose card I have in my hands
				if ((int)(MainForm.rnd.NextDouble() * 1000) % 3 == 0)
				{ // one third of the time -> pick the one I know is part of the solution
					MainForm.udrSuggestion.eWeapon = udrAILogic.eWeaponsLeft[0];
					return;
				}
				else
				{
					if (eWeaponsIHoldACardFor.Length > 0)
					{
						MainForm.udrSuggestion.eWeapon = eWeaponsIHoldACardFor[(int)(MainForm.rnd.NextDouble() * 1000) % eWeaponsIHoldACardFor.Length];
						return;
					}

					// I don't hold any Weapon cards
					// go around the table in reverse order and pick the first Weapon card I know the last suspect to answer my suggest already has
					for (int intSuspectCounter = 1; intSuspectCounter < (int)enuSuspects._numSuspects; intSuspectCounter++)
					{
						enuSuspects eSuspectCounter = (enuSuspects)(((int)eName + (int)enuSuspects._numSuspects - intSuspectCounter) % (int)enuSuspects._numSuspects);

						enuWeapons[] eWeaponCardsIKnowThisSuspectHolds = new enuWeapons[0];
						for (enuCards eWeaponCardCounter = (enuCards)(int)enuSuspects._numSuspects;
									  eWeaponCardCounter < (enuCards)((enuWeapons)((int)enuSuspects._numSuspects + (int)enuWeapons._numWeapons));
									  eWeaponCardCounter++)
						{ // cycle through all weapons cards
							if (udrAILogic.eNotes[(int)eSuspectCounter, (int)eWeaponCardCounter] == enuNote.check)
							{ // I know this suspect has this weapon-card
								Array.Resize<enuWeapons>(ref eWeaponCardsIKnowThisSuspectHolds, eWeaponCardsIKnowThisSuspectHolds.Length + 1);
								eWeaponCardsIKnowThisSuspectHolds[eWeaponCardsIKnowThisSuspectHolds.Length - 1] = MainForm.getEWeaponFromCard(eWeaponCardCounter);
							}
						}

						if (eWeaponCardsIKnowThisSuspectHolds.Length > 0)
						{
							MainForm.udrSuggestion.eWeapon = eWeaponCardsIKnowThisSuspectHolds[(int)(MainForm.rnd.NextDouble() * 1000) % eWeaponCardsIKnowThisSuspectHolds.Length];
							return;
						}
						else
						{
							MainForm.udrSuggestion.eWeapon = udrAILogic.eWeaponsLeft[0];
							return;
						}
					}
				}
				// this shouldn't happen
				// if I reach here : I have no Weapon cards and neither do any other suspects in the game
				MessageBox.Show("this should not happen : pickWeaponForSuggestion() -> I know the murder Weapon is " + udrAILogic.eWeaponsLeft[0].ToString() + " and I can't pick a reasonable card");
				// program will flow into the Weapon we know committed the murder
			}

			// make an informed decision based on the udrAISuggestion information
			if (udrAILogic.udrSuggestionAI.udrWeaponMysteryFrequency.Length == 0) // we know of no "mystery" Weapon cards -> pick one we don't know at random
				MainForm.udrSuggestion.eWeapon = udrAILogic.eWeaponsLeft[(int)(MainForm.rnd.NextDouble() * 1000) % udrAILogic.eWeaponsLeft.Length];
			else if ((eAILevel == enuAILevel.stupid && (int)(MainForm.rnd.NextDouble() * 1000) % 2 == 0) // ai may make a poor random choice from ALL REMAINING weapons
					|| (eAILevel == enuAILevel.dull && (int)(MainForm.rnd.NextDouble() * 1000) % 5 == 0)
					|| (eAILevel == enuAILevel.average && (int)(MainForm.rnd.NextDouble() * 1000) % 50 == 0)
					|| (eAILevel == enuAILevel.bright && (int)(MainForm.rnd.NextDouble() * 1000) % 500 == 0)
					|| (eAILevel == enuAILevel.genius && (int)(MainForm.rnd.NextDouble() * 1000) % 5000 == 0))// tweak random frequency according to suspect's intelligence
			{
				MainForm.udrSuggestion.eWeapon = udrAILogic.eWeaponsLeft[(int)(MainForm.rnd.NextDouble() * 1000) % udrAILogic.eWeaponsLeft.Length];
			}
			else
			{
				// use udrAISuggestion information
				enuCards eSuspectCardSelected = MainForm.getCardFromESuspect(MainForm.udrSuggestion.eSuspect);
				for (int intWeaponCounter = 0; intWeaponCounter < udrAILogic.udrSuggestionAI.udrWeaponMysteryFrequency.Length; intWeaponCounter++)
				{
					// if no suspect has both the previously selected 'suspect card' in his list of unknowns AND this 'weapon card' -> select this weapon card
					bool bolThisWeaponOk = true;
					for (int intSuspectCounter = udrAILogic.udrSuggestionAI.suspectMysteryInfo.Length - 1; intSuspectCounter >= 0; intSuspectCounter--)
					{
						if ((eCardIsInArray(udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrSuspectCardsMystery,
											 eSuspectCardSelected) // 
							&& eCardIsInArray(udrAILogic.udrSuggestionAI.suspectMysteryInfo[intSuspectCounter].udrWeaponCardsMystery,
											  udrAILogic.udrSuggestionAI.udrWeaponMysteryFrequency[intWeaponCounter].eCards)))
						{
							bolThisWeaponOk = false;
						}
					}
					if (bolThisWeaponOk)
					{
						MainForm.udrSuggestion.eWeapon = MainForm.getEWeaponFromCard(udrAILogic.udrSuggestionAI.udrWeaponMysteryFrequency[intWeaponCounter].eCards);
						return;
					}
				}
				// no suspect has only one
				// scan all weapons left
				// pick one that is not in the list of unknowns
				enuWeapons[] eWeaponArray = new enuWeapons[0];
				for (int intWeaponCounter = 0; intWeaponCounter < udrAILogic.eWeaponsLeft.Length; intWeaponCounter++)
				{
					if (!eCardIsInArray(udrAILogic.udrSuggestionAI.udrWeaponMysteryFrequency, MainForm.getCardFromEWeapon(udrAILogic.eWeaponsLeft[intWeaponCounter])))
					{
						Array.Resize<enuWeapons>(ref eWeaponArray, eWeaponArray.Length + 1);
						eWeaponArray[eWeaponArray.Length - 1] = udrAILogic.eWeaponsLeft[intWeaponCounter];
					}
				}

				if (eWeaponArray.Length > 0)
				{ // there are a few options
					MainForm.udrSuggestion.eWeapon = eWeaponArray[((int)MainForm.rnd.NextDouble() * 10000) % eWeaponArray.Length];
					return;
				}

				// the only weapons left are possibly in the hands of the same suspect
				// pick one at random 
				MainForm.udrSuggestion.eWeapon = udrAILogic.eWeaponsLeft[((int)MainForm.rnd.NextDouble() * 10000) % udrAILogic.eWeaponsLeft.Length];
				return;
			}
		}

		bool eCardIsInArray(udtSuggestionAI_frequenCards[] udrFreqCardsArray, enuCards eCard)
		{
			if (udrFreqCardsArray == null)
				return false;
			for (int intCardCounter = 0; intCardCounter < udrFreqCardsArray.Length; intCardCounter++)
			{
				if (udrFreqCardsArray[intCardCounter].eCards == eCard)
					return true;
			}
			return false;
		}

		bool ICanLeaveThisRoom()
		{
			classRoom cRoom = MainForm.cRooms[(int)eRoom];

			for (int intDoorCounter = 0; intDoorCounter < cRoom.ptDoors.Length; intDoorCounter++)
			{
				if (cFloor[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y].dirDoor == enuDir.secretPassage)
					return true;
				else
				{
					Point ptNext = MainForm.movePoint(cRoom.ptDoors[intDoorCounter], cFloor[cRoom.ptDoors[intDoorCounter].X, cRoom.ptDoors[intDoorCounter].Y].dirDoor);
					if (MainForm.floorTileIsFree(ptNext))
						return true;
				}
			}
			return false;
		}

		bool PickDestinationTile()
		{
			// start from destination room 
			// travel back along shortest path until reach a tile that is included in the allowable tiles

			if (eRoom < enuRooms._numRooms)
			{
				if (!ICanLeaveThisRoom())
					return false;
			}

			Point ptCurrentTile = new Point(0, 0);
			bool bolAllowSecretPassage =(eRoom != enuRooms.start 
										&& eRoom != enuRooms.tiles 
										&& (udrAILogic.eDestinationRoom != MainForm.cRooms[(int)eRoom].oppositeCornerRoom()));

			bool bolThereIsADoorOutOfDestinationRoom = getBestDoorOutThisRoom(udrAILogic.eDestinationRoom, ref ptCurrentTile,bolAllowSecretPassage);
			 
			if (ptCurrentTile.X < 0) // using secret passage -> decode roomID -> get best door out of next room
			{
				enuRooms eRoomOnOtherSideOfPassage = (enuRooms)(Math.Abs(ptCurrentTile.X) % ((int)enuRooms._numRooms));
				if (eRoomOnOtherSideOfPassage == udrAILogic.eDestinationRoom)
				{
					switch (eRoom)
					{
						case enuRooms.Study:
							udrAILogic.ptDestinationTile = new Point(0, 0);
							return true;

						case enuRooms.Lounge:
							udrAILogic.ptDestinationTile = new Point(23, 0);
							return true;

						case enuRooms.Kitchen:
							udrAILogic.ptDestinationTile = new Point(23, 23);
							return true;

						case enuRooms.Conservatory:
							udrAILogic.ptDestinationTile = new Point(0, 23);
							return true;
					}
				}
				else if (eRoomOnOtherSideOfPassage == MainForm.cRooms[(int)udrAILogic.eDestinationRoom].oppositeCornerRoom())
				{
					getBestDoorOutThisRoom(eRoomOnOtherSideOfPassage, ref ptCurrentTile, false);
				}
				else
					getBestDoorOutThisRoom((enuRooms)(Math.Abs(ptCurrentTile.X) % (int)enuRooms._numRooms), ref ptCurrentTile, true);
			}
			else if (cSEAllowableMoves[ptCurrentTile.X, ptCurrentTile.Y] == null)
			{
				ptCurrentTile = MainForm.movePoint(ptCurrentTile, classSuspect.cFloor[ptCurrentTile.X, ptCurrentTile.Y].dirDoor);
			}

			while (cSEAllowableMoves[ptCurrentTile.X, ptCurrentTile.Y] == null)
			{
				if (classSuspect.cFloor[ptCurrentTile.X, ptCurrentTile.Y].eType == enuFloor.door)
				{
					getBestDoorOutThisRoom(classSuspect.cFloor[ptCurrentTile.X, ptCurrentTile.Y].eRoom, ref ptCurrentTile, true);
					if (ptCurrentTile.X < 0)
					{ // using secret passage
						enuRooms eThisRoom = (enuRooms)((int)Math.Abs(ptCurrentTile.X) % (int)enuRooms._numRooms);
						getBestDoorOutThisRoom(eThisRoom, ref ptCurrentTile, true);
					}
					else if (cSEAllowableMoves[ptCurrentTile.X, ptCurrentTile.Y] == null)
					{
						ptCurrentTile = MainForm.movePoint(ptCurrentTile, classSuspect.cFloor[ptCurrentTile.X, ptCurrentTile.Y].dirDoor);
					}
				}
				else
					ptCurrentTile = MainForm.movePoint(ptCurrentTile, cShortestPath[ptCurrentTile.X, ptCurrentTile.Y].SrcDir);
			}
			udrAILogic.ptDestinationTile = ptCurrentTile;
			return true;
		}

		bool getBestDoorOutThisRoom(enuRooms eRoom, ref Point ptTileOfBestDoor) { return getBestDoorOutThisRoom(eRoom, ref ptTileOfBestDoor, true); }
		bool getBestDoorOutThisRoom(enuRooms eThisRoom, ref Point ptTileOfBestDoor, bool bolAllowSecretPassage)
		{
			classRoom cRoom = MainForm.cRooms[(int)eThisRoom];
			Point[] ptDoors = cRoom.getValidDoors(bolAllowSecretPassage);

			// cancel blocked doors
			for (int intDoorCounter = 0; intDoorCounter < ptDoors.Length; intDoorCounter++)
			{
				Point ptTileOutsideDoor = MainForm.movePoint(ptDoors[intDoorCounter], cFloor[ptDoors[intDoorCounter].X, ptDoors[intDoorCounter].Y].dirDoor);
				if (!MainForm.floorTileIsFree(ptTileOutsideDoor) && ptTile != ptTileOutsideDoor) // if the door is not blocked (by some other suspect)
				{ // this door is blocked
					ptDoors[intDoorCounter] = ptDoors[ptDoors.Length - 1];
					Array.Resize<Point>(ref ptDoors, ptDoors.Length - 1);
				}
			}

			if (ptDoors.Length == 0)
				return false;

			ptTileOfBestDoor = ptDoors[0];  // start with door 0th index
			if (classSuspect.cFloor[ptTileOfBestDoor.X, ptTileOfBestDoor.Y].dirDoor == enuDir.secretPassage)
				if (ptDoors.Length > 1)
					ptTileOfBestDoor = ptDoors[1];
				else
				{
					if (bolAllowSecretPassage)
					{
						switch (cRoom.name)
						{  // encode destination Room's ID into door's "point"
							case enuRooms.Lounge:
								ptTileOfBestDoor = new Point(-6, -6);
								return true;

							case enuRooms.Study:
								ptTileOfBestDoor = new Point(-4, -4);
								return true;

							case enuRooms.Kitchen:
								ptTileOfBestDoor = new Point(-(int)enuRooms._numRooms, -(int)enuRooms._numRooms); // study's ID is 'zero' -> decode with Modulo of absolute value
								return true;

							case enuRooms.Conservatory:
								ptTileOfBestDoor = new Point(-2, -2);
								return true;
						}
					}
					else
						return false;
				}

			for (int intDoorCounter = 0; intDoorCounter < ptDoors.Length; intDoorCounter++)
			{
				Point ptDoor = ptDoors[intDoorCounter];
				if (classSuspect.cFloor[ptDoor.X, ptDoor.Y].dirDoor == enuDir.secretPassage)
				{ // code roomID of room on other side of secret passage into x & y values of 'best door' point
					Point ptNextBestDoor = new Point(0, 0);
					// test shortest path travel cost for this door
					switch (cRoom.name)
					{
						case enuRooms.Lounge:
							ptNextBestDoor = new Point(0, 23);
							break;

						case enuRooms.Study:
							ptNextBestDoor = new Point(23, 23);
							break;

						case enuRooms.Kitchen:
							ptNextBestDoor = new Point(0, 0);
							break;

						case enuRooms.Conservatory:
							ptNextBestDoor = new Point(23, 0);
							break;
					}

					if (cShortestPath[ptNextBestDoor.X, ptNextBestDoor.Y] != null
						&& cShortestPath[ptNextBestDoor.X, ptNextBestDoor.Y].intTurns * 3 + cShortestPath[ptNextBestDoor.X, ptNextBestDoor.Y].intSteps
							< cShortestPath[ptTileOfBestDoor.X, ptTileOfBestDoor.Y].intTurns * 3 + cShortestPath[ptTileOfBestDoor.X, ptTileOfBestDoor.Y].intSteps)
					{ // using this secret passage is a short cut to destination
						switch (cRoom.name)
						{  // encode destination Room's ID into door's "point"
							case enuRooms.Lounge:
								ptTileOfBestDoor = new Point(-6, -6);
								return true;

							case enuRooms.Study:
								ptTileOfBestDoor = new Point(-4, -4);
								return true;

							case enuRooms.Kitchen:
								ptTileOfBestDoor = new Point(-(int)enuRooms._numRooms, -(int)enuRooms._numRooms); // study's ID is 'zero' -> decode with Modulo of absolute value
								return true;

							case enuRooms.Conservatory:
								ptTileOfBestDoor = new Point(-2, -2);
								return true;
						}
						return true;
					}
				}
				else
				{
					Point ptNextTile = MainForm.movePoint(ptDoor, classSuspect.cFloor[ptDoor.X, ptDoor.Y].dirDoor);
					if (cShortestPath[ptNextTile.X, ptNextTile.Y] != null)
						if (cShortestPath[ptNextTile.X, ptNextTile.Y].intTurns * 3 + cShortestPath[ptNextTile.X, ptNextTile.Y].intSteps
							<
							cShortestPath[ptTileOfBestDoor.X, ptTileOfBestDoor.Y].intTurns * 3 + cShortestPath[ptTileOfBestDoor.X, ptTileOfBestDoor.Y].intSteps)
						{
							ptTileOfBestDoor = ptDoors[intDoorCounter];
						}
				}
			}

			return true;
		}

		void PickDestinationRoom()
		{
			classTurnsReachRoom[] cNumTurnsReachableRooms = new classTurnsReachRoom[0];
			string strReachableRooms = ".";
			for (int intRoomCounter = 0; intRoomCounter < cNumTurnsToReachRooms.Length; intRoomCounter++)
			{
				if (cNumTurnsToReachRooms[intRoomCounter].getCost > 0 && cNumTurnsToReachRooms[intRoomCounter].getCost < 1000)
				{
					Array.Resize<classTurnsReachRoom>(ref	cNumTurnsReachableRooms, cNumTurnsReachableRooms.Length + 1);
					cNumTurnsReachableRooms[cNumTurnsReachableRooms.Length - 1] = cNumTurnsToReachRooms[intRoomCounter];
					strReachableRooms += cNumTurnsToReachRooms[intRoomCounter].ToString().ToUpper() + ".";
				}
			}
			cNumTurnsToReachRooms = cNumTurnsReachableRooms;

			if ((eAILevel == enuAILevel.stupid && (int)(MainForm.rnd.NextDouble() * 1000) % 2 == 0) // ai may make a poor random choice from ALL remaining accessible rooms
				|| (eAILevel == enuAILevel.dull && (int)(MainForm.rnd.NextDouble() * 1000) % 5 == 0)
				|| (eAILevel == enuAILevel.average && (int)(MainForm.rnd.NextDouble() * 1000) % 50 == 0)
				|| (eAILevel == enuAILevel.bright && (int)(MainForm.rnd.NextDouble() * 1000) % 500 == 0)
				|| (eAILevel == enuAILevel.genius && (int)(MainForm.rnd.NextDouble() * 1000) % 5000 == 0))
			{
				if (cNumTurnsToReachRooms.Length > 0)
				{
					udrAILogic.eDestinationRoom = (cNumTurnsToReachRooms[((int)(MainForm.rnd.NextDouble() * 1000) % cNumTurnsToReachRooms.Length)].eRoom);
				}
				else
				{
					udrAILogic.eDestinationRoom = eRoom;

				}
				return;
			}

			// reorder list of rooms in ascending number of turns
			int intBestIndex;
			int intInnerLoop, intOuterLoop;
			for (intOuterLoop = 0; intOuterLoop < cNumTurnsToReachRooms.Length - 1; intOuterLoop++)
			{
				intBestIndex = intOuterLoop;
				for (intInnerLoop = intOuterLoop + 1; intInnerLoop < cNumTurnsToReachRooms.Length; intInnerLoop++)
				{
					if (cNumTurnsToReachRooms[intInnerLoop].getCost < cNumTurnsToReachRooms[intBestIndex].getCost)
						intBestIndex = intInnerLoop;
				}
				if (intBestIndex != intOuterLoop)
				{
					classTurnsReachRoom cTemp = cNumTurnsToReachRooms[intOuterLoop];
					cNumTurnsToReachRooms[intOuterLoop] = cNumTurnsToReachRooms[intBestIndex];
					cNumTurnsToReachRooms[intBestIndex] = cTemp;
				}
			}

			if (cNumTurnsToReachRooms.Length == 0)
			{
				udrAILogic.eDestinationRoom = eRoom;
				return;
			}

			if (udrAILogic.eRoomsLeft.Length == 1)
			{ // I have narrowed down the possible room solutions and now know which room the murder was committed in
				// avoid revealing this information to other players by choosing another room
				udrAILogic.eDestinationRoom = cNumTurnsToReachRooms[0].eRoom; // default is the nearest room

				if ((eAILevel == enuAILevel.stupid && (int)(MainForm.rnd.NextDouble() * 1000) % 2 == 0) // ai may make a poor choice and go to the nearest room
					|| (eAILevel == enuAILevel.dull && (int)(MainForm.rnd.NextDouble() * 1000) % 5 == 0)
					|| (eAILevel == enuAILevel.average && (int)(MainForm.rnd.NextDouble() * 1000) % 50 == 0)
					|| (eAILevel == enuAILevel.bright && (int)(MainForm.rnd.NextDouble() * 1000) % 500 == 0)
					|| (eAILevel == enuAILevel.genius && (int)(MainForm.rnd.NextDouble() * 1000) % 5000 == 0))
					return;

				if (eRoomsIHoldACardFor.Length > 0)
				{ // pick a room for which I hold the card (not give away the murder-room solution)
					for (int intRoomCounter = 0; intRoomCounter < cNumTurnsToReachRooms.Length; intRoomCounter++)
					{ // scan through the list in order ranked by distance (nearest first)
						if (cNumTurnsToReachRooms[intRoomCounter].getCost > 0)
						{ // exclude the room I am in
							for (int intCardRoomsIHaveCounter = 0; intCardRoomsIHaveCounter < eRoomsIHoldACardFor.Length; intCardRoomsIHaveCounter++)
							{ // compare to the rooms I have a card for
								if (eRoomsIHoldACardFor[intCardRoomsIHaveCounter] == cNumTurnsToReachRooms[intRoomCounter].eRoom)
								{ // I have this room's card -> go there
									udrAILogic.eDestinationRoom = cNumTurnsToReachRooms[intRoomCounter].eRoom;
									return;
								}
							}
						}
					}
				}

				// if I am still here it is because I do not hold any room cards
				// go around the table and pick a room which I know player to my right hold
				for (int intSuspectCounter = 1; intSuspectCounter < (int)enuSuspects._numSuspects; intSuspectCounter++)
				{
					enuSuspects eSuspectCounter = (enuSuspects)((int)eName + (int)enuSuspects._numSuspects - intSuspectCounter);

					enuRooms[] eRoomsIKnowThisSuspectHas = new enuRooms[0];
					for (enuCards eCardCounter = (enuCards)((int)enuSuspects._numSuspects + (int)enuWeapons._numWeapons);
								  eCardCounter < enuCards._numCards;
								  eCardCounter++)
					{ // scan through all room cards
						if (strReachableRooms.Contains(eCardCounter.ToString().ToUpper())) // if it is a reachable room
						{
							if (udrAILogic.eNotes[(int)eSuspectCounter, (int)eCardCounter] == enuNote.check)
							{ // my notes tell me this suspect has this room card in his hands
								Array.Resize<enuRooms>(ref eRoomsIKnowThisSuspectHas, eRoomsIKnowThisSuspectHas.Length + 1);
								eRoomsIKnowThisSuspectHas[eRoomsIKnowThisSuspectHas.Length - 1] = MainForm.getERoomFromCard(eCardCounter);
							}
						}
					}

					for (int intRoomCounter = 0; intRoomCounter < cNumTurnsToReachRooms.Length; intRoomCounter++)
					{ // scan through the list in order ranked by distance (nearest first)
						if (cNumTurnsToReachRooms[intRoomCounter].getCost > 0)
						{ // exclude the room I am in
							for (int intCardRoomsThisSuspectHasCounter = 0; intCardRoomsThisSuspectHasCounter < eRoomsIKnowThisSuspectHas.Length; intCardRoomsThisSuspectHasCounter++)
							{ // compare to the rooms I have a card for
								if (eRoomsIKnowThisSuspectHas[intCardRoomsThisSuspectHasCounter] == cNumTurnsToReachRooms[intRoomCounter].eRoom)
								{ // I have this room's card -> go there
									udrAILogic.eDestinationRoom = cNumTurnsToReachRooms[intRoomCounter].eRoom;
									return;
								}
							}
						}
					}
				}
			}

			// scan list until find a good choice

			udrAILogic.eDestinationRoom = cNumTurnsToReachRooms[0].eRoom; // default is the nearest room
			for (int intRoomCounter = 0; intRoomCounter < cNumTurnsToReachRooms.Length; intRoomCounter++)
			{
				if (cNumTurnsToReachRooms[intRoomCounter].getCost > 0)
				{
					if (eRoomIsStillPossibleSolution(cNumTurnsToReachRooms[intRoomCounter].eRoom))
					{
						udrAILogic.eDestinationRoom = cNumTurnsToReachRooms[intRoomCounter].eRoom;
						return;
					}
				}
			}
		}

		bool eRoomIsStillPossibleSolution(enuRooms eRoom)
		{
			for (int intRoomCounter = 0; intRoomCounter < udrAILogic.eRoomsLeft.Length; intRoomCounter++)
				if (eRoom == udrAILogic.eRoomsLeft[intRoomCounter])
					return true;
			return false;
		}

		bool eWeaponIsStillPossibleSolution(enuWeapons eWeapon)
		{
			for (int intWeaponCounter = 0; intWeaponCounter < udrAILogic.eWeaponsLeft.Length; intWeaponCounter++)
				if (eWeapon == udrAILogic.eWeaponsLeft[intWeaponCounter])
					return true;
			return false;
		}

		bool eSuspectIsStillPossibleSolution(enuSuspects eSuspect)
		{
			for (int intSuspectCounter = 0; intSuspectCounter < udrAILogic.eSuspectsLeft.Length; intSuspectCounter++)
				if (eSuspect == udrAILogic.eSuspectsLeft[intSuspectCounter])
					return true;
			return false;
		}

		public void setAI()
		{
			eRoomsIHoldACardFor = new enuRooms[0];
			for (int intCardCounter = 0; intCardCounter < cCards.Length; intCardCounter++)
			{
				if (cCards[intCardCounter].IsARoom)
				{
					Array.Resize<enuRooms>(ref eRoomsIHoldACardFor, eRoomsIHoldACardFor.Length + 1);
					eRoomsIHoldACardFor[eRoomsIHoldACardFor.Length - 1] = MainForm.getERoomFromCard(cCards[intCardCounter].eCardName);
				}
			}

			eSuspectsIHoldACardFor = new enuSuspects[0];
			for (int intCardCounter = 0; intCardCounter < cCards.Length; intCardCounter++)
			{
				if (cCards[intCardCounter].IsASuspect)
				{
					Array.Resize<enuSuspects>(ref eSuspectsIHoldACardFor, eSuspectsIHoldACardFor.Length + 1);
					eSuspectsIHoldACardFor[eSuspectsIHoldACardFor.Length - 1] = MainForm.getESuspectFromCard(cCards[intCardCounter].eCardName);
				}
			}

			eWeaponsIHoldACardFor = new enuWeapons[0];
			for (int intCardCounter = 0; intCardCounter < cCards.Length; intCardCounter++)
			{
				if (cCards[intCardCounter].IsAWeapon)
				{
					Array.Resize<enuWeapons>(ref eWeaponsIHoldACardFor, eWeaponsIHoldACardFor.Length + 1);
					eWeaponsIHoldACardFor[eWeaponsIHoldACardFor.Length - 1] = MainForm.getEWeaponFromCard(cCards[intCardCounter].eCardName);
				}
			}

			for (enuSuspects eSuspectCounter = (enuSuspects)0; eSuspectCounter < enuSuspects._numSuspects; eSuspectCounter++)
				udrAILogic.cSuspectsUnknowns[(int)eSuspectCounter] = new classSuspectCardsCalled();
		}
	}

	public class classWeapon
	{
		public enuWeapons eName;
		public Point pt;
		enuRooms _eRoom;

		public classWeapon(enuWeapons weaponName)
		{
			eName = weaponName;
			_eRoom = enuRooms._numRooms;
		}

		public enuRooms eRoom
		{
			get { return _eRoom; }
			set
			{
				_eRoom = value;
			}
		}
	}

	public class classCard
	{
		public enuCardType eType;
		public enuCards eCardName;
		public classSuspect cSuspect;
		public classRotatedImage cBmp = new classRotatedImage();
		formClue MainForm;

		public udtAnimationInfo udrAnimationInfo;

		public classCard(formClue mainform, enuCards Name)
		{
			MainForm = mainform;
			eCardName = Name;
			setCardType();
			setImage();
		}

		string getRootDirectory(string strThisDirectory)
		{
			int intIndexBackSlash = strThisDirectory.LastIndexOf("\\");
			if (intIndexBackSlash > 0)
				return strThisDirectory.Substring(0, intIndexBackSlash);
			return "";
		}

		string FileExists(string strImageName)
		{
			string strDir = System.IO.Directory.GetCurrentDirectory();
			string strFilename = strImageName + ".rBMP";

			string strFilenameAndDirectory = strDir + "\\" + strFilename;

			if (System.IO.File.Exists(strFilenameAndDirectory))
				return strFilenameAndDirectory;
			else
			{
				while (strDir.Length > 0)
				{
					strDir = getRootDirectory(strDir);
					strFilenameAndDirectory = strDir + "\\" + strFilename;
					if (System.IO.File.Exists(strFilenameAndDirectory))
						return strFilenameAndDirectory;
				}
			}
			return strImageName;
		}

		void setImage()
		{
			string strCurrentDir_Filename = System.IO.Directory.GetCurrentDirectory() + "\\" + eCardName.ToString() + ".rbmp";				
			bool bolSaveCurrentDir = false;
			if (!System.IO.File.Exists(strCurrentDir_Filename))
				bolSaveCurrentDir = true;
			MainForm.advanceProBar();
			string strFilename = FileExists(eCardName.ToString());

			if (System.IO.File.Exists(strFilename))
			{
				cBmp.loadBaseImages(strFilename);
				if (bolSaveCurrentDir)
					cBmp.saveBaseImages(strCurrentDir_Filename);
			}
			else
			{

				double dblFractionSize = 0.75;
				Size sz = new Size((int)(Clue_CS2010.Properties.Resources.cardback.Width * dblFractionSize), (int)(Clue_CS2010.Properties.Resources.cardback.Height * dblFractionSize));

				switch (eCardName)
				{
					/// suspects
					case enuCards.ColMustard:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardSuspectColMustard, sz));
						break;

					case enuCards.ProfPlum:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardSuspectProfPlum, sz));
						break;

					case enuCards.RevGreen:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardSuspectRevGreen, sz));
						break;

					case enuCards.MrsPeacock:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardSuspectMrsPeacock, sz));
						break;

					case enuCards.MissScarlet:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardSuspectMissScarlet, sz));
						break;

					case enuCards.MrsWhite:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardSuspectMrsWhite, sz));
						break;

					/// weapons
					case enuCards.Knife:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardWeaponKnife, sz));
						break;

					case enuCards.Candlestick:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardWeaponCandleStick, sz));
						break;

					case enuCards.Revolver:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardWeaponRevolver, sz));
						break;

					case enuCards.Rope:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardWeaponRope, sz));
						break;

					case enuCards.LeadPipe:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardWeaponLeadPipe, sz));
						break;

					case enuCards.Wrench:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardWeaponWrench, sz));
						break;

					/// rooms
					case enuCards.Hall:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardRoomHall, sz));
						break;

					case enuCards.Lounge:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardRoomLounge, sz));
						break;

					case enuCards.DiningRoom:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardRoomDiningRoom, sz));
						break;

					case enuCards.Kitchen:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardRoomKitchen, sz));
						break;

					case enuCards.BallRoom:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardRoomBallroom, sz));
						break;

					case enuCards.Conservatory:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardRoomConservatory, sz));
						break;

					case enuCards.BilliardRoom:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardBilliardRoom, sz));
						break;

					case enuCards.Library:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardRoomLibrary, sz));
						break;

					case enuCards.Study:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.CardRoomStudy, sz));
						break;

					case enuCards.Unknown:
						cBmp.createBaseImage(new Bitmap(Clue_CS2010.Properties.Resources.cardback, sz));
						break;
				}

				cBmp.getImage(0); MainForm.advanceProBar();

				cBmp.getImage(1); MainForm.advanceProBar();
				cBmp.getImage(2); MainForm.advanceProBar();
				cBmp.getImage(3); MainForm.advanceProBar();

				cBmp.saveBaseImages(strCurrentDir_Filename);
			}
		}

		/// <summary>
		/// assumes card starts with initial velocity, slides across table and slowly stops
		/// </summary>
		/// <param name="ptStart">start position on the screen</param>
		/// <param name="ptEnd">end position on the screen</param>
		/// <param name="intNumSteps">number of clock cycles to reach end position and v=0 given a constant negative acceleration</param>
		public void setAnimationVelocity(Point ptStart, Point ptEnd, int intNumSteps)
		{
			udrAnimationInfo.ptStart = ptStart;
			udrAnimationInfo.ptEnd = ptEnd;
			udrAnimationInfo.dblTravelAngle = classMath.arcTan(ptEnd.X - ptStart.X, ptEnd.Y - ptStart.Y);
			udrAnimationInfo.dblTravelDistance = Math.Sqrt(Math.Pow(ptEnd.X - ptStart.X, 2) + Math.Pow(ptEnd.Y - ptStart.Y, 2));
			udrAnimationInfo.dblTravelAcceleration = -10;
			udrAnimationInfo.intMaxSteps = 25 + (int)(MainForm.rnd.NextDouble() * 1000) % 20;
			udrAnimationInfo.dblTravelInitialVelocity = -udrAnimationInfo.intMaxSteps * udrAnimationInfo.dblTravelAcceleration;
		}

		void setCardType()
		{
			int intCardNum = (int)eCardName;
			if (intCardNum < 6)
				eType = enuCardType.Suspect;
			else if (intCardNum < 12)
				eType = enuCardType.weapon;
			else
				eType = enuCardType.room;
			SetIsARoom();
			SetIsAWeapon();
			SetIsASuspect();
		}

		bool bolIsARoom;
		public bool IsARoom
		{
			get { return bolIsARoom; }
		}
		void SetIsARoom()
		{
			bolIsARoom = eCardIsARoom(eCardName);
		}

		public static bool eCardIsARoom(enuCards eCard)
		{
			return ((int)eCard >= (int)enuSuspects._numSuspects + (int)enuWeapons._numWeapons);
		}

		bool bolIsAWeapon;
		public bool IsAWeapon
		{
			get { return bolIsAWeapon; }
		}
		void SetIsAWeapon()
		{
			bolIsAWeapon = eCardIsAWeapon(eCardName);
		}
		public static bool eCardIsAWeapon(enuCards eCard)
		{
			return ((int)eCard >= (int)enuSuspects._numSuspects && (int)eCard < (int)enuSuspects._numSuspects + (int)enuWeapons._numWeapons);
		}

		bool bolIsASuspect;
		public bool IsASuspect
		{
			get { return bolIsASuspect; }
		}
		void SetIsASuspect()
		{
			bolIsASuspect = eCardIsASuspect(eCardName);
		}
		public static bool eCardIsASuspect(enuCards eCard)
		{
			return ((int)eCard < (int)enuSuspects._numSuspects);
		}

		public static enuCards getECardFromERoom(enuRooms eThisRoom) { return (enuCards)((int)eThisRoom + (int)enuSuspects._numSuspects + (int)enuWeapons._numWeapons); }
		public static enuCards getECardFromESuspect(enuSuspects eThisSuspect) { return (enuCards)(int)eThisSuspect; }
		public static enuCards getECardFromEWeapon(enuWeapons eThisWeapon) { return (enuCards)((int)eThisWeapon + (int)enuSuspects._numSuspects); }
	}

	public class classFloor
	{
		public enuFloor eType;
		public enuDir dirDoor;
		public enuRooms eRoom;
	}

	public class classButton
	{
		static Brush brWhite;
		public Point pt;
		public Size sz;
		public Color clrBorder;
		public string strText;
		public Font fnt;
		public Bitmap bmpMyself;
		public Bitmap bmpMyHighlight;
		public PictureBox picBox;
		public formClue mainForm;
		public enuMode eMode;
		public classNote cNote;

		public enuButtons eButtonName;

		public classButton(formClue MainForm, ref PictureBox picField, enuMode Mode, Point Pt, Color ClrBorder, string text, Font myFont)
		{
			picBox = picField;
			eMode = Mode;
			mainForm = MainForm;
			pt = Pt;
			clrBorder = ClrBorder;
			strText = text;
			fnt = myFont;
			if (text.Length > 0 && fnt != null)
				setImage();
			if (brWhite == null)
				brWhite = new SolidBrush(Color.White);
		}

		public string Text
		{
			get { return strText; }
			set
			{
				strText = value;
				setImage();
			}
		}

		void setImage()
		{
			bmpMyself = mainForm.getTextImage(strText, fnt);
			Rectangle recBorder = new Rectangle(0, 0, bmpMyself.Width - 1, bmpMyself.Height - 7);
			using (Graphics g = Graphics.FromImage(bmpMyself))
			{
				g.DrawRectangle(new Pen(clrBorder), recBorder);
			}

			bmpMyHighlight = new Bitmap(bmpMyself);

			using (Graphics g = Graphics.FromImage(bmpMyHighlight))
				g.DrawRectangle(new Pen(Color.Red), recBorder);
			sz = recBorder.Size;
		}

		public void draw()
		{
			if (mainForm.eMode != eMode && eMode != enuMode.any)
				return;
			if (bmpMyself == null || bmpMyHighlight == null)
				setImage();

			Bitmap bmpTemp = new Bitmap(picBox.Image);
			using (Graphics g = Graphics.FromImage(bmpTemp))
				g.DrawImage(bmpMyself, pt);

			picBox.Image = bmpTemp; picBox.Refresh();
		}

		public void highlight()
		{
			if (mainForm.eMode != eMode && eMode != enuMode.any)
				return;

			if (bmpMyself == null || bmpMyHighlight == null)
				setImage();

			Bitmap bmpTemp = new Bitmap(picBox.Image);
			using (Graphics g = Graphics.FromImage(bmpTemp))
				g.DrawImage(bmpMyHighlight, pt);

			picBox.Image = bmpTemp;
		}

		public void erase()
		{
			Bitmap bmpTemp = new Bitmap(picBox.Image);
			using (Graphics g = Graphics.FromImage(bmpTemp))
				g.FillRectangle(brWhite, new Rectangle(pt, sz));

			picBox.Image = bmpTemp;
		}
	}

	public class classNote
	{
		public enuNote eNote;
		enuSuspects eSuspect;
		enuCards eCard;
		formClue mainForm;
		PictureBox picBox;
		public enuMode eMode;
		public Point pt;
		Bitmap bmpMyself, bmpMyHighlight;
		
		static Bitmap[] bmpSuspects;
		static Bitmap[] bmpNotes;
		static Bitmap bmpHighlight;

		public bool bolUpdateImage = true;

		public classNote(formClue MainForm, ref PictureBox picField, enuMode Mode, enuSuspects Suspect, enuCards Card)
		{
			mainForm = MainForm;
			picBox = picField;
			eMode = Mode;
			eSuspect = Suspect;
			eCard = Card;

			if (bmpSuspects == null)
				initImages();

			placeButton();
		}

		void initImages()
		{
			bmpSuspects = new Bitmap[(int)enuSuspects._numSuspects];
			bmpSuspects[(int)enuSuspects.ColMustard] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_ColMustard); bmpSuspects[(int)enuSuspects.ColMustard].MakeTransparent();
			bmpSuspects[(int)enuSuspects.MissScarlet] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_MissScarlet); bmpSuspects[(int)enuSuspects.MissScarlet].MakeTransparent();
			bmpSuspects[(int)enuSuspects.MrsPeacock] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_MrsPeacock); bmpSuspects[(int)enuSuspects.MrsPeacock].MakeTransparent();
			bmpSuspects[(int)enuSuspects.MrsWhite] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_MrsWhite); bmpSuspects[(int)enuSuspects.MrsWhite].MakeTransparent();
			bmpSuspects[(int)enuSuspects.ProfPlum] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_ProfPlum); bmpSuspects[(int)enuSuspects.ProfPlum].MakeTransparent();
			bmpSuspects[(int)enuSuspects.RevGreen] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_RevGreen); bmpSuspects[(int)enuSuspects.RevGreen].MakeTransparent();

			bmpNotes = new Bitmap[(int)enuNote._numNotes];
			bmpNotes[(int)enuNote.blank] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_blank); bmpNotes[(int)enuNote.blank].MakeTransparent();
			bmpNotes[(int)enuNote.check] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_check); bmpNotes[(int)enuNote.check].MakeTransparent();
			bmpNotes[(int)enuNote.question] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_questionMark); bmpNotes[(int)enuNote.question].MakeTransparent();
			bmpNotes[(int)enuNote.X] = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_X); bmpNotes[(int)enuNote.X].MakeTransparent();

			bmpHighlight = new Bitmap(Clue_CS2010.Properties.Resources.noteBox_highlight); bmpHighlight.MakeTransparent();
		}

		void placeButton()
		{
			int intY = 0;
			switch (eCard)
			{
				case enuCards.ColMustard:
					intY = 39;
					break;

				case enuCards.ProfPlum:
					intY = 65;
					break;

				case enuCards.RevGreen:
					intY = 91;
					break;

				case enuCards.MrsPeacock:
					intY = 119;
					break;

				case enuCards.MissScarlet:
					intY = 145;
					break;

				case enuCards.MrsWhite:
					intY = 171;
					break;

				case enuCards.Knife:
					intY = 221;
					break;

				case enuCards.Candlestick:
					intY = 247;
					break;

				case enuCards.Revolver:
					intY = 273;
					break;

				case enuCards.Rope:
					intY = 301;
					break;

				case enuCards.LeadPipe:
					intY = 327;
					break;

				case enuCards.Wrench:
					intY = 353;
					break;

				case enuCards.Hall:
					intY = 403;
					break;

				case enuCards.Lounge:
					intY = 429;
					break;

				case enuCards.DiningRoom:
					intY = 455;
					break;

				case enuCards.Kitchen:
					intY = 483;
					break;

				case enuCards.BallRoom:
					intY = 509;
					break;

				case enuCards.Conservatory:
					intY = 535;
					break;

				case enuCards.BilliardRoom:
					intY = 563;
					break;

				case enuCards.Library:
					intY = 589;
					break;

				case enuCards.Study:
					intY = 615;
					break;
			}

			int intX = 240 + (int)eSuspect * 25;

			pt = new Point(intX, intY);
			setMyImages();
		}

		public enuSuspects Suspect
		{
			get { return eSuspect; }
		}

		public enuCards Card
		{
			get { return eCard; }
		}

		public enuNote Note
		{
			get { return eNote; }
			set
			{
				if (eNote != value)
				{
					eNote = value;
					//setMyImages();
					//draw();
					bolUpdateImage = true;
				}
			}
		}

		public void draw()
		{
			if (mainForm.eMode != eMode && eMode != enuMode.any)
				return;
			if (bmpMyself == null || bmpMyHighlight == null || bolUpdateImage)
				setMyImages();
			
			Bitmap bmpTemp = new Bitmap(picBox.Image);
			using (Graphics g = Graphics.FromImage(bmpTemp))
				g.DrawImage(bmpMyself, pt);

			picBox.Image = bmpTemp; picBox.Refresh();
		}

		public void highlight()
		{
			if (mainForm.eMode != eMode && eMode != enuMode.any)
				return;

			if (bmpMyself == null || bmpMyHighlight == null || bolUpdateImage)
				setMyImages();

			Bitmap bmpTemp = new Bitmap(picBox.Image);
			using (Graphics g = Graphics.FromImage(bmpTemp))
				g.DrawImage(bmpMyHighlight, pt);

			picBox.Image = bmpTemp;
		}

		public void setMyImages()
		{
			bolUpdateImage = false;
			bmpMyself = new Bitmap(25, 25);
			using (Graphics g = Graphics.FromImage(bmpMyself))
			{
				Rectangle recSrc = new Rectangle(pt.X, pt.Y, 25, 25);
				Rectangle recDest = new Rectangle(0, 0, 25, 25);
				g.DrawImage(mainForm.bmpNotebook, recDest, recSrc, GraphicsUnit.Pixel);
				g.DrawImage(bmpSuspects[(int)eSuspect], new Point(0, 0));
				g.DrawImage(bmpNotes[(int)eNote], new Point(0, 0));
			}

			bmpMyHighlight = new Bitmap(bmpMyself);
			using (Graphics g = Graphics.FromImage(bmpMyHighlight))
				g.DrawImage(bmpHighlight, new Point(0, 0));
		}
	}

	public class classRotatedImage
	{
		Bitmap[] bmp = new Bitmap[16];

		public void loadBaseImages(string strFilename)
		{
			if (System.IO.File.Exists(strFilename))
			{
				FileStream fs = new FileStream(strFilename, FileMode.Open);

				BinaryFormatter formatter = new BinaryFormatter();

				for (int intBaseImageCounter = 0; intBaseImageCounter < 4; intBaseImageCounter++)
				{
					bmp[intBaseImageCounter] = (Bitmap)formatter.Deserialize(fs);
				}

				fs.Close();
			}
		}

		public void saveBaseImages(string strFilename)
		{
			if (System.IO.File.Exists(strFilename))
				System.IO.File.Delete(strFilename);

			FileStream fs = new FileStream(strFilename, FileMode.Create);

			BinaryFormatter formatter = new BinaryFormatter();

			for (int intBaseImageCounter = 0; intBaseImageCounter < 4; intBaseImageCounter++)
			{
				if (bmp[intBaseImageCounter] == null)
					bmp[intBaseImageCounter] = getImage(intBaseImageCounter);
				formatter.Serialize(fs, bmp[intBaseImageCounter]);
			}

			fs.Close();
		}

		public Bitmap getImage(int intIndex)
		{
			if (bmp[0] == null)
				return null;

			if (bmp[intIndex] != null)
				return bmp[intIndex];

			if (intIndex < 4)
			{
				bmp[intIndex] = rotate(bmp[0], Math.PI / 8.0 * (double)intIndex);
			}
			else
			{
				int intBaseIndex = intIndex % 4;
				bmp[intIndex] = new Bitmap(getImage(intBaseIndex));
				int intQuarterRotations = (int)Math.Floor((double)intIndex / 4.0);

				switch (intQuarterRotations)
				{
					case 1:
						bmp[intIndex].RotateFlip(RotateFlipType.Rotate270FlipNone);
						break;

					case 2:
						bmp[intIndex].RotateFlip(RotateFlipType.Rotate180FlipNone);
						break;

					case 3:
						bmp[intIndex].RotateFlip(RotateFlipType.Rotate90FlipNone);
						break;

				}
			}
			bmp[intIndex].MakeTransparent();
			return bmp[intIndex];
		}

		public void createBaseImage(Bitmap bmpBaseImage)
		{
			bmp[0] = bmpBaseImage;
			using (Graphics g = Graphics.FromImage(bmp[0]))
				g.DrawRectangle(new Pen(Color.White, 2), new Rectangle(0, 0, bmp[0].Width - 1, bmp[0].Height - 1));

			bmp[0].MakeTransparent();
		}

		public void createBaseImage(string strFilename)
		{
			if (System.IO.File.Exists(strFilename))
			{
				bmp[0] = new Bitmap(strFilename);
				using (Graphics g = Graphics.FromImage(bmp[0]))
					g.DrawRectangle(new Pen(Color.White, 2), new Rectangle(0, 0, bmp[0].Width - 1, bmp[0].Height - 1));

				bmp[0].MakeTransparent();
			}
		}

		public struct udtPixilateColorFind
		{
			public Color clr;
			public int numFound;
		}

		private void addPixilateColorFound(ref udtPixilateColorFind[] udrPixilateColorFind, Color clrFound)
		{
			if (udrPixilateColorFind == null)
			{
				udrPixilateColorFind = new udtPixilateColorFind[1];
				udrPixilateColorFind[0] = new udtPixilateColorFind();
				udrPixilateColorFind[0].clr = clrFound;
				udrPixilateColorFind[0].numFound = 1;
			}
			else
			{
				for (int intClrCounter = 0; intClrCounter < udrPixilateColorFind.Length; intClrCounter++)
					if (udrPixilateColorFind[intClrCounter].clr == clrFound)
					{
						udrPixilateColorFind[intClrCounter].numFound++;
						return;
					}
				Array.Resize<udtPixilateColorFind>(ref udrPixilateColorFind, udrPixilateColorFind.Length + 1);
				udrPixilateColorFind[udrPixilateColorFind.Length - 1] = new udtPixilateColorFind();
				udrPixilateColorFind[udrPixilateColorFind.Length - 1].clr = clrFound;
				udrPixilateColorFind[udrPixilateColorFind.Length - 1].numFound = 1;
			}
		}
		void reorderPixilateColorFound(ref udtPixilateColorFind[] udrPixilateColorFind)
		{
			int intBestFind;
			for (int intOuterLoop = 0; intOuterLoop < udrPixilateColorFind.Length - 1; intOuterLoop++)
			{
				intBestFind = intOuterLoop;
				for (int intInnerLoop = intOuterLoop + 1; intInnerLoop < udrPixilateColorFind.Length; intInnerLoop++)
				{
					if (udrPixilateColorFind[intInnerLoop].numFound > udrPixilateColorFind[intBestFind].numFound)
						intBestFind = intInnerLoop;
				}
				if (intBestFind != intOuterLoop)
				{
					udtPixilateColorFind udrTemp = udrPixilateColorFind[intOuterLoop];
					udrPixilateColorFind[intOuterLoop] = udrPixilateColorFind[intBestFind];
					udrPixilateColorFind[intBestFind] = udrTemp;
				}
			}
		}
		Bitmap rotate(Bitmap bmpInput, double dblAngleRotation)
		{
			int intMinSquare = bmpInput.Width > bmpInput.Height ?
								3 * bmpInput.Width
								: 3 * bmpInput.Height;
			Color clrHole = Color.YellowGreen;// some color assumed NOT in the input bmp

			Bitmap bmpCopy = new Bitmap(intMinSquare, intMinSquare);
			Point ptTL;
			Point ptBR;
			Point ptCopyCenter = new Point(bmpCopy.Width / 2, bmpCopy.Height / 2);
			Point ptOriginalCenter = new Point(bmpInput.Width / 2, bmpInput.Height / 2);
			using (Graphics g = Graphics.FromImage(bmpCopy))
			{
				g.FillRectangle(new SolidBrush(clrHole), new Rectangle(new Point(0, 0), bmpCopy.Size));
				ptTL = new Point(ptCopyCenter.X, ptCopyCenter.Y);
				ptBR = new Point(ptCopyCenter.X, ptCopyCenter.Y);

				for (int intX = 0; intX < bmpInput.Width; intX++)
				{
					for (int intY = 0; intY < bmpInput.Height; intY++)
					{
						int intDX = ptOriginalCenter.X - intX;
						int intDY = ptOriginalCenter.Y - intY;
						classMath.classRadialCoor udrOriginalRad = new classMath.classRadialCoor(classMath.arcTan(intDX, intDY), Math.Sqrt(intDX * intDX + intDY * intDY));
						classMath.classRadialCoor udrCopyRad = new classMath.classRadialCoor(udrOriginalRad.angle - dblAngleRotation, udrOriginalRad.radius);
						Point ptCopy = new Point((int)(ptCopyCenter.X + udrCopyRad.radius * Math.Cos(udrCopyRad.angle)),
												 (int)(ptCopyCenter.Y + udrCopyRad.radius * Math.Sin(udrCopyRad.angle)));

						try { bmpCopy.SetPixel(ptCopy.X, ptCopy.Y, bmpInput.GetPixel(intX, intY)); }
						catch (Exception) { }

						// keep track of limits of output image
						if (ptCopy.X < ptTL.X)
							ptTL.X = ptCopy.X;
						if (ptCopy.Y < ptTL.Y)
							ptTL.Y = ptCopy.Y;
						if (ptCopy.X > ptBR.X)
							ptBR.X = ptCopy.X;
						if (ptCopy.Y > ptBR.Y)
							ptBR.Y = ptCopy.Y;
					}
				}
			}

			// write image to output array
			Size szOfImage = new Size(ptBR.X - ptTL.X, ptBR.Y - ptTL.Y);
			Rectangle recSrc = new Rectangle(ptTL, szOfImage);
			Rectangle recDest = new Rectangle(new Point(0, 0), szOfImage);

			// fill the blanks missed when rotating image
			// scanning x from 0 to width created a problem in the fill-blank
			for (int intX = ptTL.X; intX < ptBR.X; intX++)
				for (int intY = ptTL.Y; intY < ptBR.Y; intY++)
				{
					Color clrTest = bmpCopy.GetPixel(intX, intY);
					if (clrTest.A == clrHole.A
						&& clrTest.R == clrHole.R
						&& clrTest.G == clrHole.G
						&& clrTest.B == clrHole.B)
					{
						udtPixilateColorFind[] udrColorFind = new udtPixilateColorFind[0];
						if (intX > 0 && intX < bmpCopy.Width - 2 && intY > 0 && intY < bmpCopy.Height - 2)
						{
							Point ptUp = new Point(intX, intY - 1);
							Point ptDown = new Point(intX, intY + 1);
							Point ptLeft = new Point(intX - 1, intY);
							Point ptRight = new Point(intX + 1, intY);
							Point ptUL = new Point(intX - 1, intY - 1);
							Point ptUR = new Point(intX + 1, intY - 1);
							Point ptDR = new Point(intX + 1, intY + 1);
							Point ptDL = new Point(intX - 1, intY + 1);

							addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptUp.X, ptUp.Y));
							addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptDown.X, ptDown.Y));
							addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptLeft.X, ptLeft.Y));
							addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptRight.X, ptRight.Y));
							addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptDL.X, ptDL.Y));
							addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptDR.X, ptDR.Y));
							addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptUL.X, ptUL.Y));
							addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptUR.X, ptUR.Y));
							reorderPixilateColorFound(ref udrColorFind);
							if (udrColorFind[0].numFound >= 2)
								try { bmpCopy.SetPixel(intX, intY, udrColorFind[0].clr); }
								catch (Exception) { }
							else
							{
								int intDX = ptCopyCenter.X - intX;
								int intDY = ptCopyCenter.Y - intY;
								classMath.classRadialCoor udrOriginalRad = new classMath.classRadialCoor(classMath.arcTan(intDX, intDY), Math.Sqrt(intDX * intDX + intDY * intDY));
								classMath.classRadialCoor udrCopyRad = new classMath.classRadialCoor(udrOriginalRad.angle + dblAngleRotation, udrOriginalRad.radius);
								Point ptCopy = new Point((int)(ptOriginalCenter.X + udrCopyRad.radius * Math.Cos(udrCopyRad.angle)),
														 (int)(ptOriginalCenter.Y + udrCopyRad.radius * Math.Sin(udrCopyRad.angle)));

								if (ptCopy.X >= 0 && ptCopy.X < bmpCopy.Width && ptCopy.Y >= 0 && ptCopy.Y < bmpCopy.Height)
									try { bmpCopy.SetPixel(intX, intY, bmpInput.GetPixel(ptCopy.X, ptCopy.Y)); }
									catch (Exception) { }
							}
						}
					}
				}
			if (recDest.Width < 1)
				recDest.Width = 1;
			if (recDest.Height < 1)
				recDest.Height = 1;
			Bitmap bmpTemp = new Bitmap(recDest.Width, recDest.Height);

			using (Graphics g = Graphics.FromImage(bmpTemp))
			{
				g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, bmpTemp.Width, bmpTemp.Height));
				bmpCopy.MakeTransparent(bmpCopy.GetPixel(0, 0));
				g.DrawImage(bmpCopy, recDest, recSrc, GraphicsUnit.Pixel);
			}
			bmpTemp.RotateFlip(RotateFlipType.Rotate180FlipNone);
			return bmpTemp;
		}

	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO unemployable
Canada Canada
Christ Kennedy grew up in the suburbs of Montreal and is a bilingual Quebecois with a bachelor’s degree in computer engineering from McGill University. He is unemployable and currently living in Moncton, N.B. writing his next novel.

Comments and Discussions