Click here to Skip to main content
15,885,141 members
Articles / Multimedia / DirectX

Night Stalker

Rate me:
Please Sign up or sign in to vote.
4.26/5 (10 votes)
27 Jan 2010CPOL15 min read 47.7K   693   36  
A C# game using Sprite-Editor graphics, way-points for AI controlled characters, and a mini-map collision detection scheme.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Sprite;

namespace Night_Stalker
{
    public enum enuDir { E_, NE, N_, NW, W_, SW, S_, SE, _numDir }
    public enum wallTypes { no_Wall = 0, wall, unbreakableWall, door, open_Door }

    public struct udtKeyCommands
    {
        public classJessica.enuJessica_Rabbit_Configurations JessicaAction;
        public enuDir dirAction;
        public bool Flag;
    }

    public partial class formNightStalker : Form
    {
        public classSpriteMaker cLibSpriteMaker = new Sprite.classSpriteMaker();
        public classMath cLibMath = new classMath();
        public classHelperFunctions cLibHelper;
        public classWayPointPaths cLibWPPaths;
        public classCollisionDetection cLibCD;

        public Size szRoom = new Size(12, 6);
        public bool bolGameOver = true;
        bool bolStartup = true;
        public int intStandardWallLength = 100;

        udtKeyCommands udrUserKeyCommand;

        Timer tmrGamePlay = new Timer();
        Timer tmrNewRobot = new Timer();
        Timer tmrHeartBeat = new Timer();
        Timer tmrInitData = new Timer();

        Label lblHelp = new Label();

        Point ptRobot_Den = new Point(0, Night_Stalker.Properties.Resources.Map.Height - Night_Stalker.Properties.Resources.Robot_Den_New.Height);

        PictureBox picTitle = new PictureBox();

        classRoom room;
        Point ptMouse;
        classJessica Jessica;
        classRobot[] robots = new classRobot[3];
        Microsoft.DirectX.AudioVideoPlayback.Audio DXHeartBeat;
                    
        Label lblGameOver = new Label();
        Bitmap bmpMap = new Bitmap(Night_Stalker.Properties.Resources.Map);
                   
        public bool bolDebug = false;
        bool bolRebuildNearestWayPoints = false;

        int intInitPhase = -1;

        public formNightStalker()
        {
            InitializeComponent();
            
            cLibHelper = new classHelperFunctions(ref cLibMath);
            picMap.Controls.Add(cLibHelper.lblFeedback);
            cLibHelper.lblFeedback.BringToFront();
            cLibHelper.lblFeedback.AutoSize = true;

            //cLibHelper.clearDebug();
            
            Controls.Add(lblGameOver);
            lblGameOver.Font = new Font("ms sans-serif", 48);
            lblGameOver.Text = "Game Over";
            lblGameOver.BackColor = Color.Black;
            lblGameOver.ForeColor = Color.Red;
            lblGameOver.AutoSize = true;
            lblGameOver.Top = (Screen.PrimaryScreen.WorkingArea.Height - lblGameOver.Height) / 2;
            lblGameOver.Left = (Screen.PrimaryScreen.WorkingArea.Width - lblGameOver.Width) / 2;
            lblGameOver.BringToFront();
            lblGameOver.Visible = false;

            cLibWPPaths = new classWayPointPaths(ref cLibHelper);
            cLibHelper.cLibWPs = cLibWPPaths;

            this.Size = Screen.PrimaryScreen.WorkingArea.Size;
            this.StartPosition = FormStartPosition.CenterScreen;

            Controls.Add(lblHelp);
            lblHelp.BringToFront();
            lblHelp.Visible = true;
            cLibCD = new classCollisionDetection(ref cLibHelper);
            Jessica = new classJessica(ref cLibHelper, ref cLibCD);
            cLibCD.Jessica = Jessica;
            cLibHelper.cLibCD = cLibCD;

            picMap.Dock = DockStyle.Fill;

            room = new classRoom(this);

            Jessica.ptLoc = Jessica.ptJessicaStartLoc;
            ptMouse = Jessica.ptLoc;
            Jessica.intLives = 0;

            Jessica.Action = classJessica.enuJessica_Rabbit_Configurations.standStill;

            KeyPress += new KeyPressEventHandler(formNightStalker_KeyPress);
            KeyDown += new KeyEventHandler(formNightStalker_KeyDown);
            picMap.GotFocus += new EventHandler(picMap_GotFocus);
            
            /// debug start
            cLibCD.bolDrawCDInfo = System.IO.Directory.GetCurrentDirectory().ToUpper().Contains("DEBUG");
            /// mnuDebug.Visible = System.IO.Directory.GetCurrentDirectory().ToUpper().Contains("DEBUG");
            /// debug end

            if (false && cLibCD.bolDrawCDInfo)
                cLibCD.drawCDOnMap(ref bmpMap);

            Controls.Add(picTitle);
            picTitle.Image = Night_Stalker.Properties.Resources.nightstalker;
            picTitle.SizeMode = PictureBoxSizeMode.AutoSize;
            picTitle.Left = (Screen.PrimaryScreen.WorkingArea.Width - picTitle.Width) / 2;
            picTitle.Top = (Screen.PrimaryScreen.WorkingArea.Height - picTitle.Height) / 2;
            picTitle.BringToFront();
            picTitle.Visible = true;

            grbPlayerScore.Top = 25;
            grbPlayerScore.Left = Screen.PrimaryScreen.WorkingArea.Width - grbPlayerScore.Width - 5;

            string strDir = cLibHelper.getResourceDirectoryString();
            DXHeartBeat = new Microsoft.DirectX.AudioVideoPlayback.Audio(strDir + cLibHelper.strDX_HeartBeat);
            bolGameOver = true;

            classCorpse.sprite = cLibSpriteMaker.loadSprite(strDir + "corpse (small).spr");

            resetBunkerImage();

            tmrGamePlay.Interval = 125;
            tmrGamePlay.Tick += new EventHandler(tmrGamePlay_Tick);

            tmrNewRobot.Interval = 2000;
            tmrNewRobot.Tick += new EventHandler(tmrNewRobot_Tick);

            tmrHeartBeat.Interval = 1000;
            tmrHeartBeat.Tick += new EventHandler(tmrHeartBeat_Tick);
            tmrHeartBeat.Enabled = true;

            tmrInitData.Interval = 5;
            tmrInitData.Tick += new EventHandler(tmrInitData_Tick);
            tmrInitData.Enabled = true;
        }

        void formNightStalker_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Home:
                    cLibWPPaths.bolWPDebug = !cLibWPPaths.bolWPDebug;
                    cLibHelper.lblFeedback.Text = cLibWPPaths.bolWPDebug.ToString();
                    break;

                case Keys.Pause:
                    tmrGamePlay.Enabled = !tmrGamePlay.Enabled;
                    break;

                case Keys.Left:
                    udrUserKeyCommand.dirAction = enuDir.W_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case Keys.Right:
                    udrUserKeyCommand.dirAction = enuDir.E_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case Keys.Up:
                    udrUserKeyCommand.dirAction = enuDir.N_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case Keys.Down:
                    udrUserKeyCommand.dirAction = enuDir.S_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case Keys.Enter:
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.standStill;
                    udrUserKeyCommand.Flag = true;
                    break;

                case Keys.Space:
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Down;
                    switch (udrUserKeyCommand.dirAction )
                    {
                        case enuDir.E_:
                        case enuDir.W_:
                            udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Straight;
                            udrUserKeyCommand.Flag = true;
                            break;

                        case enuDir.NE:
                        case enuDir.NW:
                            udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_High;
                            udrUserKeyCommand.Flag = true;
                            break;

                        case enuDir.SE:
                        case enuDir.SW:
                            udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Low;
                            udrUserKeyCommand.Flag = true;
                            break;

                        case enuDir.N_:
                            udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Up ;
                            udrUserKeyCommand.Flag = true;
                            break;

                        case enuDir.S_:
                            udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Down;
                            udrUserKeyCommand.Flag = true;
                            break;

                    }

                    break;
            }
            if (udrUserKeyCommand.Flag)
                e.SuppressKeyPress = true;
        }

        void resetBunkerImage() { cLibHelper.bmpBunker = new Bitmap(Night_Stalker.Properties.Resources.bunker); }

        void tmrInitData_Tick(object sender, EventArgs e)
        {
            tmrInitData.Enabled = false;
            string strDir = cLibHelper.getResourceDirectoryString();            
                   
            switch (intInitPhase)
            {
                case -1:
                    int intNumRobots = 4;
                    robots = new classRobot[intNumRobots];
                    cLibCD.robots = new classRobot[intNumRobots];

                    classRobot.sprites = new classSprite[7];
            
                    cLibHelper.lblFeedback.Top = 0;
                    cLibHelper.lblFeedback.Left = (Width - cLibHelper.lblFeedback.Width) / 2;            
                    break;

                case 0:
                case 1:
                case 2:
                case 3:
                    robots[intInitPhase] = new classRobot((classRobot.enuRobotID)intInitPhase,
                                                             ref cLibWPPaths,
                                                             ref cLibCD,
                                                             ref Jessica,
                                                             ref cLibHelper);
                    cLibCD.robots[intInitPhase] = robots[intInitPhase];
                    break;
                
                case 4:
                     classRobot.sprites[(int)classRobot.enuRobotType.bat] = cLibSpriteMaker.loadSprite(strDir + "mini bat.spr");
                    break;

                case 5:
                    classRobot.sprites[(int)classRobot.enuRobotType.spider] = cLibSpriteMaker.loadSprite(strDir + "spider (small).spr");
                    break;

                case 6:
                    classRobot.sprites[(int)classRobot.enuRobotType.gray] = cLibSpriteMaker.loadSprite(strDir + "Robot_A.spr");
                    break;

                case 7:                   
                    classRobot.sprites[(int)classRobot.enuRobotType.Smurf] = cLibSpriteMaker.loadSprite(strDir + "Smurf (small).spr");
                    break;

                case 8:
                    classRobot.sprites[(int)classRobot.enuRobotType.Felix] = cLibSpriteMaker.loadSprite(strDir + "felix the cat (small).spr");
                    break;

                case 9:
                    classRobot.sprites[(int)classRobot.enuRobotType.evilJessica] = cLibSpriteMaker.loadSprite(strDir + "Evil Jessica (small).spr");
                    break;

                case 10:
                    classRobot.sprites[(int)classRobot.enuRobotType.invisibleJessica] = cLibSpriteMaker.loadSprite(strDir + "Evil Jessica (small).spr");
                    break;

                case 11:
                    formHelp.largeJessicaSprite = cLibSpriteMaker.loadSprite(strDir + "largeJessica.spr");
                    break;

                case 12: // these bullets are user interface player-info picture boxes
                    initBullets();  
                    break;

                case 13: // initialize corpse sprites
                    cLibHelper.newCorpse(new Point(0, 0), classCorpse.enuCorpseType.guts);
                    break;

                case 14: // initialize bullet sprites
                    classBullet myBullet = new classBullet(classBullet.bulletType.colt, new Point(0, 0), 0, true, ref cLibHelper);
                    break;

                default:
                    tmrGamePlay.Enabled = true;
                    cLibHelper.lblFeedback.Visible = false;
                    picTitle.Visible = false;
                    picMap.Focus();
                    Jessica.init();
                    grbPlayerScore.Visible = true;
                    cLibHelper.lblFeedback.Location = new Point(0, 0);
                    return;
            }

            intInitPhase++;
            cLibHelper.lblFeedback.Text = "initializing " + intInitPhase.ToString() + "/15)";
            tmrInitData.Enabled = true;
        }

        void tmrHeartBeat_Tick(object sender, EventArgs e)
        {
            DXHeartBeat.CurrentPosition = 0;
            DXHeartBeat.Play();
        }

        void initBullets()
        {
            Jessica.picBullets = new System.Windows.Forms.PictureBox[6];
            int intGap = 15;
            int intBottom = Screen.PrimaryScreen.WorkingArea.Height - Night_Stalker.Properties.Resources.Colt_Round.Height - intGap;

            for (int intBulletCounter = 0; intBulletCounter < 6; intBulletCounter++)
            {
                Jessica.picBullets[intBulletCounter] = new PictureBox();
                Jessica.picBullets[intBulletCounter].Image = Night_Stalker.Properties.Resources.Colt_Round;
                Jessica.picBullets[intBulletCounter].SizeMode = PictureBoxSizeMode.AutoSize;
                Controls.Add(Jessica.picBullets[intBulletCounter]);
                Jessica.picBullets[intBulletCounter].Left = Screen.PrimaryScreen.WorkingArea.Width - Jessica.picBullets[intBulletCounter].Width - 30;
                Jessica.picBullets[intBulletCounter].Top = intBottom - (Jessica.picBullets[intBulletCounter].Height + intGap) * intBulletCounter;
                Jessica.picBullets[intBulletCounter].BackColor = Color.Black;
                Jessica.picBullets[intBulletCounter].BringToFront();
            }
        }

        void resetRobots()
        {
            for (int intRobotCounter = 0; intRobotCounter < robots.Length; intRobotCounter++)
                robots[intRobotCounter].reset();
        }

        void tmrNewRobot_Tick(object sender, EventArgs e)
        {
            tmrNewRobot.Enabled = false;
            bool bolDone = false;
            for (int intRobotCounter = 0; intRobotCounter < robots.Length; intRobotCounter++)
            {
                if (robots[intRobotCounter].bolDead)
                {
                    if (bolDone)
                    {
                        tmrNewRobot.Enabled = true;
                        return;
                    }
                    else
                    {
                        robots[intRobotCounter].reset();
                        bolDone = true;
                    }
                }
            }
        }

        void picMap_GotFocus(object sender, EventArgs e) { this.Focus(); }

        void formNightStalker_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (bolGameOver) return;

            switch (e.KeyChar)
            {
                case 's':
                case 'S':
                    udrUserKeyCommand.dirAction = enuDir.W_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'W':
                case 'w':
                    udrUserKeyCommand.dirAction = enuDir.NW;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'E':
                case 'e':
                    udrUserKeyCommand.dirAction = enuDir.N_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'R':
                case 'r':
                    udrUserKeyCommand.dirAction = enuDir.NE;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'F':
                case 'f':
                    udrUserKeyCommand.dirAction = enuDir.E_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'V':
                case 'v':
                    udrUserKeyCommand.dirAction = enuDir.SE;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'C':
                case 'c':
                    udrUserKeyCommand.dirAction = enuDir.S_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'X':
                case 'x':
                    udrUserKeyCommand.dirAction = enuDir.SW;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;
                    udrUserKeyCommand.Flag = true;
                    break;

                // fire
                case 'L':
                case 'l':
                    udrUserKeyCommand.dirAction = enuDir.E_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Straight;
                    udrUserKeyCommand.Flag = true;
                    break;

                case '.':
                case '>':
                    udrUserKeyCommand.dirAction = enuDir.SE;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Low;
                    udrUserKeyCommand.Flag = true;
                    break;

                case ',':
                case '<':
                    udrUserKeyCommand.dirAction = enuDir.S_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Down;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'M':
                case 'm':
                    udrUserKeyCommand.dirAction = enuDir.SW;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Low;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'J':
                case 'j':
                    udrUserKeyCommand.dirAction = enuDir.W_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Straight;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'U':
                case 'u':
                    udrUserKeyCommand.dirAction = enuDir.NW;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_High;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'I':
                case 'i':
                    udrUserKeyCommand.dirAction = enuDir.N_;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_Up;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'O':
                case 'o':
                    udrUserKeyCommand.dirAction = enuDir.NE;
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.Shoot_High;
                    udrUserKeyCommand.Flag = true;
                    break;

                case 'D':
                case 'd':
                default:
                    udrUserKeyCommand.JessicaAction = classJessica.enuJessica_Rabbit_Configurations.standStill;
                    udrUserKeyCommand.Flag = true;
                    break;
            }

            Text = udrUserKeyCommand.JessicaAction.ToString() + " (" + udrUserKeyCommand.dirAction.ToString() + ")" + udrUserKeyCommand.Flag.ToString();
        }

        public int getRnd(int intMax) { return cLibHelper.getRnd(intMax); }


        public Point getTileLoc(int intX, int intY) { return new Point(intX * intStandardWallLength, intY * intStandardWallLength); }
        public Point getTileLoc(Point ptTile) { return new Point(ptTile.X * intStandardWallLength, ptTile.Y * intStandardWallLength); }

        void tmrGamePlay_Tick(object sender, EventArgs e)
        {// e.g. WPTable[WPIndex_current, WPIndex_destination]
            tmrGamePlay.Enabled = false;
            if (bolRebuildNearestWayPoints)
                return;
            //return;
            bolGameOver = Jessica.intLives < 1;
            lblGameOver.Visible = (bolGameOver && !bolStartup);

            if (picMap.Width > 10 && picMap.Height > 10)
            {
                lblHelp.Left = Width - lblHelp.Width;
                lblHelp.Top = 100;

                Bitmap bmp = new Bitmap(bmpMap);

                using (Graphics g = Graphics.FromImage(bmp))
                {
                    if (classCorpse.corpseQ != null)
                        classCorpse.corpseQ.animate(ref bmp);

                    JessicaAction();
                    Jessica.animate(ref bmp);

                    cLibCD.setJessicaLocation();
                    for (int intRobotCounter = 0; intRobotCounter < robots.Length; intRobotCounter++)
                    {
                        if (intRobotCounter < (int)classRobot.enuRobotID.Spider)
                        {
                            if (robots[intRobotCounter].bolDead)
                                tmrNewRobot.Enabled = true;
                            else
                                robots[intRobotCounter].animate(ref bmp);
                        }
                        else
                            if (robots[intRobotCounter].bolDead)
                                robots[intRobotCounter].reset();
                            else
                                robots[intRobotCounter].animate(ref bmp);
                    }

                    cLibCD.animateBullets(ref bmp);

                    Bitmap spiderWeb = Night_Stalker.Properties.Resources.Spider_Web;
                    spiderWeb.MakeTransparent(Color.White);
                    g.DrawImage(spiderWeb,
                                new Rectangle(0, 0, spiderWeb.Width, spiderWeb.Height),
                                new Rectangle(0, 0, spiderWeb.Width, spiderWeb.Height),
                                GraphicsUnit.Pixel);

                    cLibHelper.bmpBunker.MakeTransparent(Color.White);
                    g.DrawImage(cLibHelper.bmpBunker,
                                new Rectangle(cLibHelper.ptBunker.X, cLibHelper.ptBunker.Y, spiderWeb.Width, spiderWeb.Height),
                                new Rectangle(0, 0, spiderWeb.Width, spiderWeb.Height),
                                GraphicsUnit.Pixel);

                    Bitmap Robot_Den = Night_Stalker.Properties.Resources.Robot_Den_New;
                    Robot_Den.MakeTransparent(Color.White);
                    g.DrawImage(Robot_Den,
                                new Rectangle(ptRobot_Den.X, ptRobot_Den.Y, spiderWeb.Width, spiderWeb.Height),
                                new Rectangle(0, 0, spiderWeb.Width, spiderWeb.Height),
                                GraphicsUnit.Pixel);
                }

                displayJessicaInfo();
                picMap.Image = bmp;
                picMap.Refresh();
                udrUserKeyCommand.Flag = false;
                tmrGamePlay.Enabled = true;
            }
        }

        void displayJessicaInfo()
        {
            lblLives.Text = "Lives : " + Jessica.intLives.ToString();
            lblScore.Text =  Jessica.intScore.ToString();
            lblScore.Left = grbPlayerScore.Width - lblScore.Width - 5;
        }

        void JessicaAction()
        {
            if (udrUserKeyCommand.Flag)
            {
                Jessica.Action = udrUserKeyCommand.JessicaAction; // this will be rejected if Jessica is in the middle of another action, e.g. shoot
                if (Jessica.udrRunAfterFireGun.flag)
                {
                    if (udrUserKeyCommand.JessicaAction == classJessica.enuJessica_Rabbit_Configurations.Walk_new)
                    {
                        Jessica.udrRunAfterFireGun.dir = udrUserKeyCommand.dirAction;
                    }
                }
                if (Jessica.Action == udrUserKeyCommand.JessicaAction) // property change may be rejected, e.g. sleeping or firing gun action not completed
                {
                    Jessica.ActionDirection = udrUserKeyCommand.dirAction;
                    Jessica.intConfigStep = 0;
                    if (Jessica.udrRunAfterFireGun.flag)
                    {
                        if (udrUserKeyCommand.JessicaAction == classJessica.enuJessica_Rabbit_Configurations.Walk_new)
                            Jessica.udrRunAfterFireGun.dir = udrUserKeyCommand.dirAction;
                    }
                }
            }

            switch (Jessica.Action)
            {
                case classJessica.enuJessica_Rabbit_Configurations.Walk_new:
                    setJessicaMove();
                    break;

                case classJessica.enuJessica_Rabbit_Configurations.Stand_fix_far_shoe:
                case classJessica.enuJessica_Rabbit_Configurations.Stand_fix_near_shoe:
                case classJessica.enuJessica_Rabbit_Configurations.Stand_flick_far_hair:
                case classJessica.enuJessica_Rabbit_Configurations.Stand_flick_near_hair_with_gun:
                case classJessica.enuJessica_Rabbit_Configurations.Stand_hold_gun_up:
                case classJessica.enuJessica_Rabbit_Configurations.Stand_scratch_far_calf_with_gun:
                case classJessica.enuJessica_Rabbit_Configurations.stand_scratch_head:
                case classJessica.enuJessica_Rabbit_Configurations.stand_swipe_near_arm_with_far_hand:
                case classJessica.enuJessica_Rabbit_Configurations.standStill:

                case classJessica.enuJessica_Rabbit_Configurations.Shoot_Down:
                case classJessica.enuJessica_Rabbit_Configurations.Shoot_High:
                case classJessica.enuJessica_Rabbit_Configurations.Shoot_Low:
                case classJessica.enuJessica_Rabbit_Configurations.Shoot_Straight:
                case classJessica.enuJessica_Rabbit_Configurations.Shoot_Up:
                    break;

                default:
                    //udrUserKeyCommand.Flag = false;
                    break;
            }
        }

        void setJessicaMove()
        {
            classJessica.enuJessica_Rabbit_Configurations JessAction = classJessica.enuJessica_Rabbit_Configurations.Walk_new;

            if (udrUserKeyCommand.Flag)
            {
                Jessica.Action = JessAction = udrUserKeyCommand.JessicaAction;
                Jessica.ActionDirection = udrUserKeyCommand.dirAction;
            }
        }

        
        private void mnuNewGame_Click(object sender, EventArgs e)
        {
            tmrGamePlay.Enabled = false;
            tmrHeartBeat.Enabled = false;
            bolGameOver = false;
            bolStartup = false;

            picMap.Size = new Size(bmpMap.Width,
                                   bmpMap.Height);

            Jessica.init();

            Jessica.intLives = 3;
            Jessica.intScore = 0;
            cLibCD.bulletQ = null;

            resetRobots();
            Jessica.placeGun();
            Jessica.showBullets();

            for (int intRobotCounter = 0; intRobotCounter < robots.Length; intRobotCounter++)
                robots[intRobotCounter].bolDead = true;

            DXHeartBeat.CurrentPosition = 0;
            classCorpse.corpseQ = null;

            resetBunkerImage();
            cLibCD.resetCDMap();

            picMap.Focus();

            picTitle.Visible = false;

            tmrNewRobot.Enabled = true;
            tmrGamePlay.Enabled = true;
            tmrHeartBeat.Enabled = true;
        }


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

        private void mnuHelp_Click(object sender, EventArgs e)
        {
            formHelp frmHelp = new formHelp(ref cLibHelper);

            tmrGamePlay.Enabled = false;

            frmHelp.Owner = this;
            frmHelp.ShowDialog();
            frmHelp.Dispose();

            tmrGamePlay.Enabled = true;
        }



        /*
        private void mnuDebug_RebuildWPs_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure you want to rebuild the Way-Points?", "rebuild way points?", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                tmrGamePlay.Enabled = false;
                cLibWPPaths.findWPs();
                cLibWPPaths.rebuildNeaghboursArray();
                cLibWPPaths.buildWPTable();// e.g. WPTable[WPIndex_current, WPIndex_destination]
                cLibWPPaths.writeWPsAndTable();
                tmrGamePlay.Enabled = true;
            }
        }

        private void mnuRebuildNearestWPsTable_Click(object sender, EventArgs e)
        {
            tmrGamePlay.Enabled = false;
            bolRebuildNearestWayPoints = true;
            cLibWPPaths.rebuildNearestWayPointsTable();

            bolRebuildNearestWayPoints = false;
        }
        */
      
    

       
    }

    public class formHelp : Form
    {
        classHelperFunctions cLibHelper;
        PictureBox picAnimate = new PictureBox();
        PictureBox picLbl = new PictureBox();
        public static classSprite largeJessicaSprite;
        classTransparentLabel.classTransparentLabel[] lbl;

        int intVGap, intStartX, intTimeReset;
        int intTimeCounter = 0;

        public struct udtBaddie
        {
            public classRobot.enuRobotType typeRobot;
            public int intConfigId;
            public int intConfigStep;
            public Point pt;
            public udtBullet bullet;
        }

        public struct udtBullet
        {
            public classBullet.bulletType typeBullet;
            public int intStepSize;
            public int intConfigId;
            public int intConfigStep;
            public Point pt;
            public Microsoft.DirectX.AudioVideoPlayback.Audio sound;
            public int intFireTrip;
            public bool flag;
        }

        Bitmap bmpLbl;
        Bitmap bmpAnimate;
        
        udtBaddie[] Help;
        udtBaddie Jessica;
        udtBaddie largeJessica;

        Timer tmrAnimateHelp = new Timer();

        Color clrBack = Color.Gray;
        bool bolInit = false;

        public formHelp(ref classHelperFunctions Helper)
        {
            cLibHelper = Helper;

            Size = Screen.PrimaryScreen.WorkingArea.Size;
            StartPosition = FormStartPosition.CenterScreen;
            FormBorderStyle = FormBorderStyle.None;
            BringToFront();
            
            string strDir = cLibHelper.getResourceDirectoryString();

            Controls.Add(picLbl);
            picLbl.Width = 700;
            picLbl.Height = Screen.PrimaryScreen.WorkingArea.Height;
            
            intVGap = Screen.PrimaryScreen.WorkingArea.Height / 7;            
            intTimeReset = 50;
            intStartX = 50;
            int intFireInterval = 8;
            Help = new udtBaddie[7];

            largeJessica.pt = new Point(435, 70);
            largeJessica.intConfigId = (int)classJessica.enuJessica_Rabbit_Configurations.standStill;

            Help[0].intConfigId = 0;
            Help[0].intConfigStep = 0;
            Help[0].pt = new Point(intStartX, intVGap/2);
            Help[0].typeRobot = classRobot.enuRobotType.bat;
            Help[0].bullet.flag = false;

            Help[1].intConfigId = 0;
            Help[1].intConfigStep = 0;
            Help[1].pt = new Point(intStartX, intVGap + intVGap / 2);
            Help[1].typeRobot = classRobot.enuRobotType.spider;
            Help[1].bullet.flag = false;

            Help[2].intConfigId = 0;
            Help[2].intConfigStep = 0;
            Help[2].pt = new Point(intStartX, intVGap * 2 + intVGap / 2);
            Help[2].bullet.flag = false;
            Help[2].typeRobot = classRobot.enuRobotType.gray;
            Help[2].bullet.intConfigId = 2;
            Help[2].bullet.intConfigStep = 0;
            Help[2].bullet.intFireTrip = intFireInterval * 4;
            Help[2].bullet.typeBullet = classBullet.bulletType.laser;
            Help[2].bullet.sound = new Microsoft.DirectX.AudioVideoPlayback.Audio(strDir +  cLibHelper.strDX_LaserFire);

            Help[3].intConfigId = 0;
            Help[3].intConfigStep = 0;
            Help[3].pt = new Point(intStartX, intVGap * 3 + 25 + intVGap / 2);
            Help[3].bullet.flag = false;
            Help[3].typeRobot = classRobot.enuRobotType.Smurf;
            Help[3].bullet.intConfigId = 2;
            Help[3].bullet.intConfigStep = 0;
            Help[3].bullet.intFireTrip = intFireInterval * 3;
            Help[3].bullet.typeBullet = classBullet.bulletType.SmurfAttack;
            Help[3].bullet.sound = new Microsoft.DirectX.AudioVideoPlayback.Audio(strDir + cLibHelper.strDX_LaserFire);

            Help[4].intConfigId = 0;
            Help[4].intConfigStep = 0;
            Help[4].pt = new Point(intStartX, intVGap * 4 + 25 + intVGap / 2);
            Help[4].bullet.flag = false;
            Help[4].typeRobot = classRobot.enuRobotType.Felix;
            Help[4].bullet.intConfigId = 1;
            Help[4].bullet.intConfigStep = 0;
            Help[4].bullet.intFireTrip = intFireInterval * 2;
            Help[4].bullet.typeBullet = classBullet.bulletType.FelixFire;
            Help[4].bullet.sound = new Microsoft.DirectX.AudioVideoPlayback.Audio(strDir + cLibHelper.strDX_FelixFire);

            Help[5].intConfigId = 0;
            Help[5].intConfigStep = 0;
            Help[5].pt = new Point(intStartX, intVGap * 5 + intVGap / 2);
            Help[5].bullet.flag = false;
            Help[5].typeRobot = classRobot.enuRobotType.evilJessica;
            Help[5].bullet.intConfigId = 0;
            Help[5].bullet.intConfigStep = 0;
            Help[5].bullet.intFireTrip = intFireInterval ;
            Help[5].bullet.typeBullet = classBullet.bulletType.bulletEater;
            Help[5].bullet.sound = new Microsoft.DirectX.AudioVideoPlayback.Audio(strDir + cLibHelper.strDX_BulletEater);

            Help[6].intConfigId = 0;
            Help[6].intConfigStep = 0;
            Help[6].pt = new Point(intStartX, intVGap * 6 + intVGap / 2);
            Help[6].bullet.flag = false;
            Help[6].typeRobot = classRobot.enuRobotType.invisibleJessica;
            Help[6].bullet.intConfigId = 0;
            Help[6].bullet.intConfigStep = 0;
            Help[6].bullet.intFireTrip = 0;
            Help[6].bullet.typeBullet = classBullet.bulletType.bunkerBuster;
            Help[6].bullet.sound = new Microsoft.DirectX.AudioVideoPlayback.Audio(strDir + cLibHelper.strDX_BunkerBuster);

            Jessica.intConfigId = (int)classJessica.enuJessica_Rabbit_Configurations.Walk_new;
            Jessica.intConfigStep = 0;
            Jessica.pt = new Point(Screen.PrimaryScreen.WorkingArea.Width -60 - picLbl.Width, 0);
            Jessica.bullet.typeBullet = classBullet.bulletType.colt;
            Jessica.bullet.flag = false;
            Jessica.bullet.intConfigId = (int)classBullet.enuColt_Configurations.fly_straight;
            Jessica.bullet.intConfigStep = 0;
            Jessica.bullet.intFireTrip = -1;            

            KeyDown += new KeyEventHandler(formHelp_KeyDown);

            tmrAnimateHelp.Interval = 150;
            tmrAnimateHelp.Tick += new EventHandler(tmrAnimateHelp_Tick);
            tmrAnimateHelp.Enabled = true;
        }

        void init()
        {
            int intLblHeight = Screen.PrimaryScreen.WorkingArea.Height / 7 + 2;

            Controls.Add(picAnimate);
            picAnimate.Width = Screen.PrimaryScreen.WorkingArea.Width - picLbl.Width;
            picAnimate.Height = Screen.PrimaryScreen.WorkingArea.Height;

            bmpLbl = new Bitmap(picLbl.Width, picLbl.Height);
            Rectangle recDest = new Rectangle(0, 0, bmpLbl.Width, bmpLbl.Height);
            Rectangle recSrc = new Rectangle(0, 0, bmpLbl.Width, bmpLbl.Height);
            using (Graphics g = Graphics.FromImage(bmpLbl))
                g.DrawImage(Night_Stalker.Properties.Resources.help_background, recDest, recSrc, GraphicsUnit.Pixel);
            picLbl.Image = bmpLbl;

            bmpAnimate = new Bitmap(picAnimate.Width, picAnimate.Height);
            recDest = new Rectangle(0, 0, bmpAnimate.Width, bmpAnimate.Height);
            recSrc = new Rectangle(bmpLbl.Width, 0, bmpAnimate.Width, bmpAnimate.Height);
            using (Graphics g = Graphics.FromImage(bmpAnimate))
                g.DrawImage(Night_Stalker.Properties.Resources.help_background, recDest, recSrc, GraphicsUnit.Pixel);
           
            Array.Resize<classTransparentLabel.classTransparentLabel>(ref lbl, 7);
            for (int intLblCounter = 0; intLblCounter < 7; intLblCounter++)
            {
                classTransparentLabel.classTransparentLabel thislbl = new classTransparentLabel.classTransparentLabel();
                picLbl.Controls.Add(thislbl);
                thislbl.Font = new Font("ms sans-serif", 12);
                thislbl.Width = picLbl.Width;
                thislbl.Height = intLblHeight ;
                thislbl.BackColor = Color.Transparent;                

                thislbl.Top = intLblHeight * intLblCounter;
                thislbl.Left = 0;
                thislbl.KeyDown += new KeyEventHandler(formHelp_KeyDown);
                thislbl.BringToFront();

                lbl[intLblCounter] = thislbl;

                switch (intLblCounter)
                {
                    case 0: // bat
                        lbl[intLblCounter].Text = "Bats \r\nII: Bats - Annoying pests just like the spider, though short-lived. After the Blue Robot appears, if you destroy a bat a gray robot will appear instead of another bat. As with the spider, bats cause temporary paralysis, which leaves you wide-open to robot fire. Defeating him scores you 300 points.";
                        break;

                    case 1: // spider
                        lbl[intLblCounter].Text = "Spider \r\nThis is the maze pest. While not deadly, he can paralyze you for a short time if you come into contact with him. Steer clear of him, if at all possible. The spider is present throughout the entire game and you can never eliminate him. Defeating him scores you 100 points.";
                        break;

                    case 2: // gray
                        lbl[intLblCounter].Text = "Robot \r\nNot a very intelligent robot and he generally wanders around aimlessly, firing shots off at Jessica only when he sees her. This is the robot you'll face at the very beginning. He's slow, which allows you to get used to the controls. Defeating him scores you 300 points.";
                        break;

                    case 3: // smurf
                        lbl[intLblCounter].Text = "Smurf\r\nThis is a craftier enemy, and is more intelligent than the robot.   He will pursue you on sight but only appears in the maze after you score 5,000 points. Defeating him scores you 500 points.";
                        break;

                    case 4: // felix
                        lbl[intLblCounter].Text = "Felix\r\nThis cat's got three lives so you can kick and kick but only the third strike will knock him down.  He appears in the maze after 15000 points and he'll pursue on sight but he also has a vague homing sense to track you down.  Defeating him scores you 1000 points.";
                        break;

                    case 5: // evil-jessica
                        lbl[intLblCounter].Text = "Evil-Jessica\r\nYou may have thought that Jessica Rabbit was bad but this one's badder.  She appears in the maze after 30000 and takes three bullets before getting knocked down.  She has a better homing sense than Felix AND her gun fires bullets which eat yours.  Defeating her scores you 2000 points."
                                                + "At 50000 Evil-Jessica gets a newer arsenal that allows her to shoot Bunker Buster bullets!";
                        break;

                    case 6: // invisible jessica
                        lbl[intLblCounter].Text = "Invisible Evil Jessica\r\nNow you've done it.  Jessica's evil twin suddenly gets an invisibility cloak at 80000 points and killing her earns you 4000 points.";
                        break;
                }
            }
        }

        void tmrAnimateHelp_Tick(object sender, EventArgs e)
        {
            if (!bolInit)
            {
                picLbl.Top = 0;
                picLbl.Left = 0;
                picAnimate.Top = 0;
                picAnimate.Left = picLbl.Width;
                init();
                bolInit = true;
            }           
            Bitmap bmp = new Bitmap(bmpAnimate);
         
            using (Graphics g = Graphics.FromImage(bmp))
            {
                for (int intBaddieCounter = 0; intBaddieCounter < Help.Length; intBaddieCounter++)
                {
                    bool bolVisible = true;
                    if (intBaddieCounter == Help.Length - 1)
                    {
                        if (intTimeCounter < 5)
                            bolVisible = true;
                        else if (intTimeCounter <10 && intTimeCounter % 4 == 0)
                            bolVisible = true;
                        else if (intTimeCounter < 30 &&  intTimeCounter % 5 == 0)
                            bolVisible = true;
                        else
                            bolVisible = false;
                    }

                    double dblAngle = (Help[intBaddieCounter].typeRobot == classRobot.enuRobotType.spider) ? Math.PI * 1.5 : 0;

                    if (bolVisible)
                    {
                        classRobot.sprites[(int)Help[intBaddieCounter].typeRobot]
                            .putConfigurationOnScreen(ref bmp,
                                                      Help[intBaddieCounter].intConfigId,
                                                      Help[intBaddieCounter].intConfigStep,
                                                      Help[intBaddieCounter].pt,
                                                      dblAngle,
                                                      1.0,
                                                      enuMirror.none,
                                                      false);
                    }

                    Help[intBaddieCounter].intConfigStep = (Help[intBaddieCounter].intConfigStep + 1)
                            % classRobot.sprites[(int)Help[intBaddieCounter].typeRobot]
                                    .Configurations[
                                      Help[intBaddieCounter].intConfigId
                                                   ].steps.Length;

                    if (Help[intBaddieCounter].bullet.flag)
                    {
                        double dblSize = 1.0;
                        if (Help[intBaddieCounter].bullet.typeBullet == classBullet.bulletType.bunkerBuster
                            || Help[intBaddieCounter].bullet.typeBullet == classBullet.bulletType.bulletEater)
                            dblSize = getBulletSize(ref Help[intBaddieCounter].bullet);

                        classBullet.sprite[(int)Help[intBaddieCounter].bullet.typeBullet]
                            .putConfigurationOnScreen(ref bmp,
                                                       Help[intBaddieCounter].bullet.intConfigId,
                                                       Help[intBaddieCounter].bullet.intConfigStep,
                                                       Help[intBaddieCounter].bullet.pt,
                                                       0,
                                                       dblSize,
                                                       enuMirror.none,
                                                       false);

                        Help[intBaddieCounter].bullet.pt.X += 35;

                        Help[intBaddieCounter].bullet.intConfigStep = (Help[intBaddieCounter].bullet.intConfigStep + 1)
                            % classBullet.sprite[(int)Help[intBaddieCounter].bullet.typeBullet]
                                    .Configurations[
                                        Help[intBaddieCounter].bullet.intConfigId
                                                   ].steps.Length;



                        if (Help[intBaddieCounter].bullet.pt.X > Width)
                            Help[intBaddieCounter].bullet.flag = false;
                    }
                    else if (Help[intBaddieCounter].bullet.intFireTrip == intTimeCounter && intBaddieCounter > 1)
                    {
                        Help[intBaddieCounter].bullet.intConfigStep = 0;
                        Help[intBaddieCounter].bullet.pt = Help[intBaddieCounter].pt;
                        Help[intBaddieCounter].bullet.flag = true;
                        cLibHelper.playSound(Help[intBaddieCounter].bullet.sound);
                        if (intBaddieCounter == 5)
                            Jessica.pt.Y = Screen.PrimaryScreen.WorkingArea.Height;
                    }
                }

                cLibHelper.cLibCD.Jessica.Sprite
                    .putConfigurationOnScreen(ref bmp,
                                              Jessica.intConfigId,
                                              Jessica.intConfigStep,
                                              Jessica.pt,
                                              0,
                                              1.0,
                                              enuMirror.horizontal,
                                              false);

                Jessica.intConfigStep = (Jessica.intConfigStep +1)
                    % cLibHelper.cLibCD.Jessica.Sprite.Configurations[Jessica.intConfigId].steps.Length;

                Jessica.pt.Y -= (Screen.PrimaryScreen.WorkingArea.Height / intTimeReset);

                /// animate large Jessica

                largeJessicaSprite.putConfigurationOnScreen(ref bmp, 
                                                            (int)largeJessica.intConfigId, 
                                                            largeJessica.intConfigStep, 
                                                            largeJessica.pt, 
                                                            0, 
                                                            1.0, 
                                                            enuMirror.none, 
                                                            false);
                classConfiguration thisConfiguration = largeJessicaSprite.Configurations[(int)largeJessica.intConfigId];
                largeJessica.intConfigStep = (largeJessica.intConfigStep + 1) % thisConfiguration.steps.Length;

                // when end of this 'stand' routine choose to standstill or animate
                if (largeJessica.intConfigStep == 0)
                    if (((int)(cLibHelper.rnd.NextDouble() * 1000)) % 3 == 0) // 1:2 chance of animation
                        largeJessica.intConfigId = ((int)classJessica.enuJessica_Rabbit_Configurations.standStill + (int)(cLibHelper.rnd.NextDouble() * 1000) % (cLibHelper.cLibCD.Jessica.intNumStandConfigurations + 1));  // randomly pick one of the six stand-animations
                    else
                        largeJessica.intConfigId = (int)classJessica.enuJessica_Rabbit_Configurations.standStill;
            }

            picAnimate.Image = bmp;
            intTimeCounter = (intTimeCounter + 1) % intTimeReset;
        }

        double getBulletSize(ref udtBullet bullet)
        {
            bullet.intStepSize = (bullet.intStepSize + 1) % 8;
            double dblSize = 1.0;
            switch (bullet.intStepSize)
            {
                case 0:
                    dblSize = 0.2;
                    break;

                case 1:
                    dblSize = 0.4;
                    break;

                case 2:
                    dblSize = 0.6;
                    break;

                case 3:
                    dblSize = 0.8;
                    break;

                case 4:
                    dblSize = 0.9;
                    break;
                case 5:
                    dblSize = 0.8;
                    break;

                case 6:
                    dblSize = 0.6;
                    break;

                case 7:
                    dblSize = 0.4;
                    break;
            }
            return dblSize;
        }

        void formHelp_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Escape:
                    tmrAnimateHelp.Enabled = false;
                    Dispose();
                    break;
            }
        }
    }

    public class classHelperFunctions
    {
        public Point[] ptDirMoveSigns = new Point[8];
        public Random rnd = new Random();        
        public Bitmap bmpBunker;
        public Point ptBunker = new Point(438, 236);

        public classMath cLibMath = new classMath();
        
        Bitmap bmpWPs;

        Color clrWP;
        Color clrCD;

        public string strDX_Colt45 = "Colt45.wav";
        public string strDX_LaserFire = "LaserFire.wav";
        public string strDX_BulletEaten = "bulleteaten.wav";
        public string strDX_FelixFire = "FelixFire.wav";
        public string strDX_BulletEater = "bulletEater.wav";
        public string strDX_BunkerBuster = "bunkerBuster.wav";
        public string strDX_EmptyChamber = "EmptyChamber.wav";
        public string strDX_Reload = "loadclip.wav";
        
        public string strDX_dieScream = "diescream.wav";
        public string strDX_Splat = "splat.wav";
        public string strDX_HitHard = "hithard.wav";

        public string strDX_HeartBeat = "heartbeat.wav";
        
        public string strDX_FreeLife = "FreeLife.wav";
        public string strDX_bomb = "bomb.wav";
        

        public classWayPointPaths cLibWPs;
        public classCollisionDetection cLibCD;

        public Label lblFeedback = new Label();

        //const string strDebugFilename = "c:\\temp\\debug.txt";

        Microsoft.DirectX.AudioVideoPlayback.Audio DXBulletEaten;

        public classBullet bulletDebug;

        //public void clearDebug() { System.IO.File.WriteAllText(strDebugFilename, ""); }
        //public void writeDebug(string strText) { System.IO.File.WriteAllText(strDebugFilename, strText); }
        //public void appendDebug(string strText) { System.IO.File.AppendAllText(strDebugFilename, "\r\n" + strText); }

        public classHelperFunctions(ref classMath cMath)
        {
            cLibMath = cMath;
            lblFeedback.ForeColor = Color.Yellow;

            ptDirMoveSigns[(int)enuDir.E_] = new Point(1, 0);
            ptDirMoveSigns[(int)enuDir.NE] = new Point(1, -1);
            ptDirMoveSigns[(int)enuDir.N_] = new Point(0, -1);
            ptDirMoveSigns[(int)enuDir.NW] = new Point(-1, -1);
            ptDirMoveSigns[(int)enuDir.W_] = new Point(-1, 0);
            ptDirMoveSigns[(int)enuDir.SW] = new Point(-1, 1);
            ptDirMoveSigns[(int)enuDir.S_] = new Point(0, 1);
            ptDirMoveSigns[(int)enuDir.SE] = new Point(1, 1);
            bmpWPs = new Bitmap(Night_Stalker.Properties.Resources.Map_WPs);
            clrWP = bmpWPs.GetPixel(0, 0);
            clrCD = bmpWPs.GetPixel(1, 0);

            DXBulletEaten = new Microsoft.DirectX.AudioVideoPlayback.Audio(getResourceDirectoryString() + strDX_BulletEaten);
        }

        /// <summary>
        /// places a new corpse on the map at point pt, then inserts this new corpse into the corpseQ
        /// </summary>
        /// <param name="pt">location where the corpse is to appear</param>
        public void newCorpse(Point pt, classCorpse.enuCorpseType corpseType)
        {
            classCorpse newCorpse = new classCorpse(pt, corpseType);
            newCorpse.next = classCorpse.corpseQ;

            classCorpse.corpseQ = newCorpse;
        }

        /// <summary>
        /// finds a random location on the map that is not a collision point(e.g. not black on WPsMap)
        /// </summary>        
        public Point getRndLocOnMap() { return getRndLocOnMap(new Point((int)(bmpWPs.Width / 2), (int)(bmpWPs.Height / 2)), bmpWPs.Width); }

        /// <summary>
        /// finds a random location on the map that is not a collision point(e.g. black on WPsMap given a point on the map and a range limit
        /// </summary>
        /// <param name="ptNearTo">location around which random range is searched</param>
        /// <param name="intRange">limiting radius away from ptNearTo</param>
        /// <returns>returns a point on map where Jessica can travel</returns>
        public Point getRndLocOnMap(Point ptNearTo, int intRange)
        {
            Point ptTest = new Point(-1, -1);
            while (!isValidLocOnWPMap(ptTest) || bmpWPs.GetPixel(ptTest.X, ptTest.Y) == clrCD)
                ptTest = new Point(ptNearTo.X + getRnd(2 * intRange) - intRange,
                                   ptNearTo.Y + getRnd(2 * intRange) - intRange);
            return ptTest;
        }

        /// <summary>
        /// tests if a point is a valid location on the bmpWPs bitmap
        /// </summary>
        /// <param name="pt">point to test</param>
        /// <returns>true if location is valid</returns>
        public bool isValidLocOnWPMap(Point pt)
        {
            if (pt.X >= 0 && pt.X < bmpWPs.Width && pt.Y >= 0 && pt.Y < bmpWPs.Height)
            {
                Color clrFound = bmpWPs.GetPixel(pt.X, pt.Y);
                return (clrFound != clrCD);
            }
            else
                return false;
        }

        /// <summary>
        /// returns true if direction is NE, SE, SW or NW
        /// </summary>
        /// <param name="dir">direction input to test</param>
        /// <returns>boolean return is true when input is a diagonal direction</returns>
        public bool dirIsDiagonal(enuDir dir) { return ((int)dir % 2 != 0); }

        /// <summary>
        /// returns a string to either the current working directory or the development archives 'resources' directory.
        /// </summary>
        /// <returns>string to resources</returns>
        public string getResourceDirectoryString()
        {
            string strDir = System.IO.Directory.GetCurrentDirectory().ToLower();
            strDir = strDir.Replace("bin\\debug", "resources").Replace("bin\\release", "resources") + "\\";
            return strDir;
        }

        public void playBulletEaten()
        {
            playSound(DXBulletEaten);
        }

        public void playSound(Microsoft.DirectX.AudioVideoPlayback.Audio DXSound)
        {
            if (DXSound == null)
                return;
            DXSound.CurrentPosition = 0;
            DXSound.Play();
        }

        /// <summary>
        /// takes two cartesian coordiantes, calculates the angle in radians then returns the enumerated type direction 
        /// </summary>
        /// <param name="pt1">starting point</param>
        /// <param name="pt2">ending point</param>
        /// <returns></returns>
        public enuDir getDirBetweenTwoPoints(Point pt1, Point pt2)
        {
            int intDX = pt2.X - pt1.X;
            int intDY = pt1.Y - pt2.Y;
            double dblAngle = cLibMath.arcTan(intDX, intDY);

            int intAngle = (int)((dblAngle / Math.PI) * 180) + (180 / 8);
            enuDir dirRetVal = (enuDir)((int)Math.Floor((double)intAngle / (180 / 4)) % 8);

            return dirRetVal;
        }

        public double cleanAngle(double dblAngle)
        {
            while (dblAngle > Math.PI * 2)
                dblAngle -= (Math.PI * 2.0);

            while (dblAngle < 0)
                dblAngle += (Math.PI * 2.0);
            return dblAngle;
        }

        public double convertDirToAngle(enuDir dir) { return -(double)dir * Math.PI / 4.0; }

        public enuDir getOppositeDirection(enuDir dir) { return (enuDir)(((int)dir + 4) % 8); }

        public int getRnd(int intMax)
        {
            if (intMax == 0)
                return intMax;
            long lngRnd = (long)(rnd.NextDouble() * intMax * 10000);
            return (int)(lngRnd % (intMax));
        }

        public string getFloorTileID(int intX, int intY) { return getFloorTileID(new Point(intX, intY)); }
        public string getFloorTileID(Point ptFloorTile) { return (ptFloorTile.X.ToString().PadLeft(3) + ptFloorTile.Y.ToString().PadLeft(3)); }
        public Point getFloorTileFromID(string strFloorTileID)
        {
            return new Point(Convert.ToInt16(strFloorTileID.Substring(0, 3)),
                             Convert.ToInt16(strFloorTileID.Substring(3, 3)));
        }

        public Point movePixel(Point udrStartTile, enuDir dirMove)
        {
            switch (dirMove)
            {
                case enuDir.E_:
                    udrStartTile.X++;
                    break;

                case enuDir.SE:
                    udrStartTile.X++;
                    udrStartTile.Y++;
                    break;

                case enuDir.S_:
                    udrStartTile.Y++;
                    break;

                case enuDir.SW:
                    udrStartTile.X--;
                    udrStartTile.Y++;
                    break;

                case enuDir.W_:
                    udrStartTile.X--;
                    break;

                case enuDir.NW:
                    udrStartTile.X--;
                    udrStartTile.Y--;
                    break;

                case enuDir.N_:
                    udrStartTile.Y--;
                    break;

                case enuDir.NE:
                    udrStartTile.X++;
                    udrStartTile.Y--;
                    break;

                default:
                    break;
            }
            return udrStartTile;
        }


        /// <summary>
        /// http://www.codeproject.com/KB/string/string_optimizations.aspx
        /// get index of pattern string in source string
        /// </summary>
        /// <param name="source">string in which pattern is searched</param>
        /// <param name="pattern">pattern string to be found in source string</param>
        /// <returns>index of first character in pattern string found in source string</returns>
        static int FastIndexOf(string source, string pattern)
        {
            bool found;
            int limit = source.Length - pattern.Length + 1;
            if (limit < 1) return -1;

            // Store the first 2 characters of "pattern"
            char c0 = pattern[0];
            char c1 = pattern.Length > 1 ? pattern[1] : ' ';

            // Find the first occurrence of the first character
            int first = source.IndexOf(c0, 0, limit);

            while (first != -1)
            {
                // Check if the following character is the same like
                // the 2nd character of "pattern"
                if (pattern.Length > 1 && source[first + 1] != c1)
                {
                    first = source.IndexOf(c0, ++first, limit - first);
                    continue;
                }

                // Check the rest of "pattern" (starting with the 3rd character)
                found = true;
                for (int j = 2; j < pattern.Length; j++)
                    if (source[first + j] != pattern[j])
                    {
                        found = false;
                        break;
                    }

                // If the whole word was found, return its index, otherwise try again
                if (found) return first;
                first = source.IndexOf(c0, ++first, limit - first);
            }
            return -1;
        }
    }

    public class classCorpse
    {
        public classCorpse next;
        public classCorpse prev;

        public static classSprite sprite;

        public enum enuCorpseType { human, Smurf, robot, guts, Felix }

        public enum enucorpse_Configurations
        {
            human,
            guts,
            robot,
            smurf,
            Felix,
            _numCon
        }

        int intStep;

        Point loc;
        double dblAngle;
        double dblSize = 1.0;
        public bool bolDie = false;
        public static classCorpse corpseQ;
        public enucorpse_Configurations config;
        public enuCorpseType myType;

        classHelperFunctions cLibHelper;

        public classCorpse(Point pt, 
                           enuCorpseType Type)
        {
            loc = pt;
            myType = Type;
           
            dblSize = 0.5;
            Random rnd = new Random();
            dblAngle = rnd.NextDouble() * Math.PI * 2.0;
            intStep = 0;

            switch (myType)
            {
                case enuCorpseType.human:
                    config = enucorpse_Configurations.human;
                    break;

                case enuCorpseType.Smurf:
                    config = enucorpse_Configurations.smurf;
                    break;

                case enuCorpseType.robot:
                    config = enucorpse_Configurations.robot;
                    break;

                case enuCorpseType.guts:
                    config = enucorpse_Configurations.guts;
                    break;

                case enuCorpseType.Felix:
                    config = enucorpse_Configurations.Felix;
                    break;                    
            }
        }

        public void animate(ref Bitmap bmp)
        {

            int intStepToScreen = (intStep > sprite.Configurations[(int)config].steps.Length - 1) ? sprite.Configurations[(int)config].steps.Length - 1 : intStep;

            sprite.putConfigurationOnScreen(ref bmp, (int)config, intStepToScreen, loc, dblAngle, dblSize, enuMirror.none, false);
            intStep++;


            switch (myType)
            {
                case enuCorpseType.human:
                case enuCorpseType.guts:
                    break;

                case enuCorpseType.robot:
                case enuCorpseType.Smurf:
                case enuCorpseType.Felix:
                    double dblRotat = Math.PI / 16.0;
                    if (intStep < 8)
                        dblAngle += 3*dblRotat;
                    else if (intStep < 20 )
                        dblAngle += 2*dblRotat;
                    else if (intStep > 30 )
                        dblAngle += dblRotat;
                    else if (intStep > 50 && intStep % 2 == 0)
                        dblAngle += dblRotat;

                    while (dblAngle > 2 * Math.PI)
                        dblAngle -= 2 * Math.PI;
                    break;
            }


            if (intStep > 12)
                bolDie = true;

            if (next != null)
                next.animate(ref bmp);

            if (bolDie)
                die();
        }

        void die()
        {
            if (corpseQ == this)
                corpseQ = null;

            if (prev != null)
                prev.next = next;
            if (next != null)
                next.prev = prev;
        }
    }
}

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