예제 #1
0
        public Game()
            : base(DefaultWidth, DefaultHeight)
        {
            InitializeRoutedActions();
            InitializeSharedState();

            SoundEnabled = true;

            Action <Sound> play =
                s =>
            {
                if (CanvasOverlay.parent == null)
                {
                    return;
                }

                if (SoundEnabled)
                {
                    s.play();
                }
            };

            var Menu = new MenuSprite(DefaultWidth).AttachTo(base.InfoOverlay);

            Menu.TextExternalLink2.htmlText = LinkPlayMoreGames;

            var DefenseY = 420;

            #region DebugDump
            var DebugDump = new DebugDumpTextField();

            DebugDump.Field.y = DefaultHeight / 4;
            DebugDump.Field.x = 0;

            DebugDump.Field.width  = DefaultWidth;
            DebugDump.Field.height = DefaultHeight / 2;

            DebugDump.Visible.ValueChangedToTrue +=
                delegate
            {
                Menu.TextExternalLink2.htmlText = LinkPoweredByJSC;
                DebugDump.Field.AttachToBefore(BorderOverlay);
                DebugDump.DebugDumpUpdate();
            };

            DebugDump.Visible.ValueChangedToFalse +=
                delegate
            {
                Menu.TextExternalLink2.htmlText = LinkPlayMoreGames;
            };
            #endregion

            RoutedActions.SendTextMessage.Direct =
                e => DebugDump.Write(new { Message = e });

            this.Statusbar = new Statusbar();

            Statusbar.Lives.Value = 3;
            Statusbar.Score.Value = 0;

            Statusbar.Element.AttachTo(InfoOverlay);

            var MenuFader = new DualFader {
                Value = Menu
            };



            #region common keys
            this.InvokeWhenStageIsReady(
                delegate
            {
                stage.click +=
                    delegate
                {
                    if (MenuFader.Value != CanvasOverlay)
                    {
                        MenuFader.Value = CanvasOverlay;
                    }
                };


                stage.keyUp +=
                    e =>
                {
                    if (e.keyCode == Keyboard.ENTER)
                    {
                        MenuFader.Value = CanvasOverlay;
                    }

                    if (e.keyCode == Keyboard.ESCAPE)
                    {
                        MenuFader.Value = Menu;
                    }

                    if (e.keyCode == Keyboard.T)
                    {
                        DebugDump.Visible.Toggle();
                    }

                    if (e.keyCode == Keyboard.M)
                    {
                        SoundEnabled = !SoundEnabled;
                    }

                    if (e.keyCode == Keyboard.C)
                    {
                        play(Sounds.miu);

                        foreach (var v in cloud1.Members)
                        {
                            DebugDump.Write(new { v.Element.x, v.Element.y });
                        }

                        DebugDump.Write(new { PlaysSurvived = this.PlaysSurvived.Value });
                    }
                };
            }
                );

            #endregion



            this.Ego = new PlayerShip(DefaultWidth, DefaultHeight)
            {
                Name = "Ego"
            };

            // addding our entities to list ensures we know under what id to send them
            this.Ego.AddTo(this.SharedState.LocalObjects);
            this.Ego.GoodEgo.AddTo(this.SharedState.LocalObjects);
            this.Ego.EvilEgo.AddTo(this.SharedState.LocalObjects);

            // our ego cannot be hit while the menu is showing
            this.Ego.GodMode.ValueChangedTo +=
                GodMode => DebugDump.Write(new { GodMode });

            // MenuFader.ValueChangedTo += e => this.Ego.GodMode.Value = e == Menu;
            // this.Ego.GodMode.Value = true;



            var ReportedScore = 0;

            #region lives and gameover

            Action <StarShip> ApplyEgoRespawn =
                xego =>
            {
                var WaitingForRespawn = false;

                xego.IsAlive.ValueChangedToFalse +=
                    delegate
                {
                    if (WaitingForRespawn)
                    {
                        return;
                    }

                    WaitingForRespawn = true;

                    this.ApplyFilter(Filters.GrayScaleFilter);
                    this.RoutedActions.SendTextMessage.Direct("waiting for respawn...");

                    if (PlayerInput != null)
                    {
                        PlayerInput.Enabled.Value = false;
                    }

                    Statusbar.Lives.Value--;

                    if (Statusbar.Lives <= 0)
                    {
                        var ScoreMinStep = this.Statusbar.Score.Value / 30;

                        100.AtInterval(
                            t =>
                        {
                            var v = Math.Max((this.Statusbar.Score.Value - ScoreMinStep), 0);

                            Statusbar.Score.Value = v;

                            if (v == 0)
                            {
                                t.stop();
                            }
                        }
                            );
                    }

                    3100.AtDelayDo(
                        delegate
                    {
                        this.RoutedActions.SendTextMessage.Direct("respawn!");


                        if (Statusbar.Lives == 0)
                        {
                            Statusbar.Lives.Value = 3;
                            Statusbar.Score.Value = 0;
                            PlaysSurvived.Value   = 0;
                        }



                        if (Statusbar.Score.Value > 0)
                        {
                            this.RoutedActions.AddRankingScore.Chained(Statusbar.Score.Value - ReportedScore);

                            ReportedScore = Statusbar.Score.Value;
                        }

                        WaitingForRespawn = false;

                        this.RoutedActions.RestoreStarship.Chained(xego);

                        this.filters = null;

                        if (PlayerInput != null)
                        {
                            PlayerInput.Enabled.Value = true;
                        }

                        play(Sounds.insertcoin);
                    }
                        );
                };
            };


            ApplyEgoRespawn(this.Ego.GoodEgo);
            ApplyEgoRespawn(this.Ego.EvilEgo);

            #endregion


            #region input
            RoutedActions.DoPlayerMovement.Direct +=
                (e, p) =>
            {
                e.GoodEgo.MoveToTarget.Value = p;
            };

            Action <double, double> DoEgoPlayerMovement =
                (arc, length) =>
                RoutedActions.DoPlayerMovement.Chained(Ego, Ego.GoodEgo.ToPoint().MoveToArc(arc, Ego.GoodEgo.MaxStep * length));

            this.RoutedActions.RestoreStarship.Direct =
                s =>
            {
                DebugDump.Write("restore starship: " + s.Name);


                s.GodMode.Value = true;
                s.TakeDamage(0);
                s.ApplyFilter(new BlurFilter());
                s.alpha = 1;

                2000.AtDelayDo(
                    delegate
                {
                    s.GodMode.Value = false;
                    s.filters       = null;

                    if (this.CoPlayers.Any(k => s == k.GoodEgo))
                    {
                        s.ApplyFilter(Filters.ColorFillFilter(0xff));
                    }
                }
                    );
            };

            this.InvokeWhenStageIsReady(
                delegate
            {
                PlayerInput = new PlayerInput(stage, Ego, this)
                {
                    StepLeft    = () => DoEgoPlayerMovement(Math.PI, 2),
                    StepLeftEnd = () => DoEgoPlayerMovement(Math.PI, 0.5),

                    StepRight    = () => DoEgoPlayerMovement(0, 2),
                    StepRightEnd = () => DoEgoPlayerMovement(0, 0.5),

                    FireBullet = () => Ego.FireBullet(),

                    SmartMoveTo = (x, y) =>
                    {
                        // ignore mouse while out of bounds
                        if (x < 0)
                        {
                            return;
                        }

                        if (x > DefaultWidth)
                        {
                            return;
                        }

                        RoutedActions.DoPlayerMovement.Chained(Ego, new Point(Ego.Wrapper(x, y), Ego.GoodEgoY));
                    }
                };

                PlayerInput.Enabled.ValueChangedTo +=
                    InputEnabled =>
                {
                    DebugDump.Write(new { InputEnabled });
                };
            }
                );
            #endregion

            this.GroupEnemies.Add(this.Ego.EvilEgo);

            // hide menu for fast start
            // MenuFader.Value = CanvasOverlay;

            this.PlaysSurvived.ValueChangedTo +=
                PlaysSurvived => DebugDump.Write(new { PlaysSurvived });

            this.PlaysSurvived.ValueChangedTo +=
                PlaysSurvived =>
            {
                if (PlaysSurvived == 5)
                {
                    this.RoutedActions.AddAchivementFiver.ChainedOnce();
                }

                if (PlaysSurvived == 1)
                {
                    this.RoutedActions.AddAchivementFirst.ChainedOnce();
                }
            };


            const int ClipMargin = 20;

            #region evilmode

            this.Ego.EvilMode.ValueChangedToTrue +=
                delegate
            {
                play(Sounds.fade);

                #region keep ego here for 10 secs

                this.Ego.GoodEgo.Clip =
                    p =>
                {
                    if (p.x < DefaultWidth / 2)
                    {
                        p.x = Math.Min(p.x, -ClipMargin);
                    }
                    else
                    {
                        p.x = Math.Max(p.x, DefaultWidth + ClipMargin);
                    }

                    return(p);
                };

                5000.AtDelayDo(
                    delegate
                {
                    this.Ego.GoodEgo.Clip = null;
                    play(Sounds.fade);
                }
                    );
                #endregion
            };

            this.Ego.EvilMode.ValueChangedToFalse +=
                delegate
            {
                play(Sounds.insertcoin);
            };

            #endregion

            this.Ego.EvilMode.LinkTo(Statusbar.EvilMode);

            #region evilmode indicator
            this.Ego.EvilMode.ValueChangedToTrue +=
                delegate
            {
                this.filters = new[] { Filters.RedChannelFilter };
            };

            this.Ego.EvilMode.ValueChangedToFalse +=
                delegate
            {
                this.filters = null;
            };
            #endregion

            this.Ego.GoodEgo.FireBullet = RoutedActions.FireBullet;
            this.Ego.GoodEgo.AttachTo(CanvasOverlay);

            this.Ego.EvilEgo.FireBullet = RoutedActions.FireBullet;
            this.Ego.EvilEgo.AttachTo(CanvasOverlay);

            #region  build shared defense buildings
            for (int i = 0; i < 4; i++)
            {
                var offset = DefaultWidth * (i * 2 + 1) / 8;


                foreach (var v in DefenseBlock.CreateDefenseArray(offset, DefenseY))
                {
                    v.AttachTo(CanvasOverlay);
                    v.AddTo(DefenseBlocks);
                    v.AddTo(FragileEntities.Items);

                    // defense blocks like invaders cloud are shared
                    this.SharedState.SharedObjects.Add(v);
                }
            }
            #endregion


            Ego.AddTo(FragileEntities);

            #region Create and Move CoPlayer

            RoutedActions.CreateCoPlayer.Direct =
                (user, handler) =>
            {
                var cp1 = new PlayerShip(DefaultWidth, DefaultHeight)
                {
                    Name = "CoPlayer"
                }.AddTo(CoPlayers);

                cp1.GoodEgo.AttachTo(CanvasOverlay);
                cp1.EvilEgo.AttachTo(CanvasOverlay);

                // we are adding remote controlled objects
                cp1.AddTo(this.SharedState.RemoteObjects[user]);

                cp1.GoodEgo.AddTo(this.SharedState.RemoteObjects[user]);
                cp1.EvilEgo.AddTo(this.SharedState.RemoteObjects[user]);

                // group as enemies
                cp1.EvilEgo.AddTo(this.GroupEnemies);
                cp1.GoodEgo.ApplyFilter(Filters.ColorFillFilter(0xff));
                cp1.AddTo(FragileEntities);

                handler(cp1);

                // this entity only moves when that player wants to move...

                // yet we might need to notify of damage
            };

            RoutedActions.RemoveCoPlayer.Direct =
                user =>
            {
                var CoPlayer = (PlayerShip)this.SharedState.RemoteObjects[user][0];

                this.SharedState.RemoteObjects[user].Clear();

                CoPlayers.Remove(CoPlayer);

                CoPlayer.EvilEgo.Orphanize();
                CoPlayer.GoodEgo.Orphanize();

                GroupEnemies.Remove(CoPlayer.EvilEgo);

                CoPlayer.EvilEgo.RemoveFrom(FragileEntities.Items);
                CoPlayer.GoodEgo.RemoveFrom(FragileEntities.Items);
            };

            RoutedActions.MoveCoPlayer.Direct =
                (ego, p) =>
            {
                ego.GoodEgo.TweenMoveTo(p.x, p.y);
            };

            #endregion



            #region AddEnemy
            RoutedActions.AddEnemy.Direct +=
                (e, p) =>
            {
                e.Name = "Enemy";

                e.TeleportTo(p.x, p.y)
                .AttachTo(CanvasOverlay)
                .AddTo(FragileEntities.Items)
                .AddTo(GroupEnemies);
            };
            #endregion

            #region cloud
            cloud1 = new EnemyCloud
            {
                PlaySound = play
            };

            cloud1.Members.ForEach(
                m =>
            {
                // if a cloud member fires, it will go across network...
                m.Element.FireBullet = RoutedActions.FireBullet;

                this.SharedState.SharedObjects.Add(m.Element);

                // we are adding enemies over network - but they actually are shared objects
                RoutedActions.AddEnemy.Chained(m.Element, m.Element.ToPoint());
            }
                );

            cloud1.TickSounds =
                new Sound[] {
                Sounds.duh0,
                Sounds.duh1,
                Sounds.duh2,
                Sounds.duh3,
            };

            cloud1.AttachTo(this.CanvasOverlay);



            cloud1.TickInterval.ValueChangedTo +=
                e => DebugDump.Write(new { TickInterval = e });



            //var CloudSpeedAcc = 1.04;
            //var CloudSpeed = 12.0;
            //var CloudMove = new Point();

            Action ResetCloudLocal =
                delegate
            {
                cloud1.Speed      = 12;
                cloud1.NextMove.x = cloud1.Speed;
                cloud1.NextMove.y = 0;



                cloud1.TeleportTo(60, 80);
                cloud1.TickInterval.Value = 1000;

                // rebuild defense

                foreach (var v in DefenseBlocks)
                {
                    v.alpha = 1;
                }

                foreach (var v in KnownEgos)
                {
                    v.GoodEgo.alpha = 1;
                    v.EvilEgo.alpha = 1;
                }
            };

            ResetCloudLocal();

            bool ResetCloudSoonDisabled = false;

            RoutedActions.KillAllInvaders.Direct =
                delegate
            {
                cloud1.Members.ForEach(m => m.Element.alpha = 0);
            };

            Action ResetCloudSoon =
                delegate
            {
                if (ResetCloudSoonDisabled)
                {
                    return;
                }

                ResetCloudSoonDisabled = true;

                RoutedActions.KillAllInvaders.Chained();

                // do not count evil mode
                if (!Ego.EvilMode)
                {
                    PlaysSurvived.Value++;
                }

                cloud1.TickInterval.Value = 0;
                cloud1.TeleportTo(60, 80);

                cloud1.Speed      = 12;
                cloud1.NextMove.x = cloud1.Speed;
                cloud1.NextMove.y = 0;


                3000.AtDelayDo(
                    delegate
                {
                    cloud1.ResetColors();

                    ResetCloudLocal();

                    cloud1.ResetLives();

                    ResetCloudSoonDisabled = false;
                }
                    );
            };


            cloud1.Tick +=
                delegate
            {
                var r = cloud1.Warzone;

                if (r == null)
                {
                    ResetCloudSoon();

                    return;
                }

                //this.graphics.clear();
                //this.graphics.beginFill(0xffffff);
                //this.graphics.drawRect(r.x, r.y, r.width, r.height);

                //DebugDump.Write(new { r.left, r.right, cloud1.FrontRow.Length });

                if (r.bottom > DefenseY)
                {
                    ResetCloudSoon();

                    return;
                }

                var Skip = 4 * (CoPlayers.Count + 1);

                if (cloud1.Counter % Skip == 0)
                {
                    // fire some bullets
                    var rr = cloud1.FrontRow.Random();

                    // invaders bullets should have different sound or be silent
                    rr.Element.FireBulletChained(1, new Point(rr.Element.x, rr.Element.y), new Point(rr.Element.x, DefaultHeight), Ego.GoodEgoY);

                    //rb.Silent = true;

                    //AddBullet.Chained(
                    //    rb
                    //);
                }

                var IsFarRight = r.right >= (DefaultWidth - EnemyCloud.DefaultCloudMargin);

                if (cloud1.NextMove.x < 0)
                {
                    IsFarRight = false;
                }

                var IsFarLeft = r.left <= (EnemyCloud.DefaultCloudMargin);

                if (cloud1.NextMove.x > 0)
                {
                    IsFarLeft = false;
                }


                var WillStartVerticalMovement = IsFarLeft || IsFarRight;


                if (WillStartVerticalMovement && cloud1.NextMove.y == 0)
                {
                    cloud1.NextMove.x = 0;
                    cloud1.NextMove.y = 8;

                    cloud1.Speed *= cloud1.SpeedAcc;
                }
                else
                {
                    if (WillStartVerticalMovement)
                    {
                        cloud1.NextMove.y -= cloud1.Speed / 2;
                    }
                    else
                    {
                    }

                    if (cloud1.NextMove.y <= 0)
                    {
                        cloud1.NextMove.y = 0;

                        if (IsFarLeft)
                        {
                            cloud1.NextMove.x = cloud1.Speed;
                        }
                        else if (IsFarRight)
                        {
                            cloud1.NextMove.x = -cloud1.Speed;
                        }
                    }
                }

                //DebugDump.Write(new { CloudMove.x, CloudMove.y });

                cloud1.MoveToOffset(cloud1.NextMove);
            };



            #endregion



            //AddEnemy.Chained(new EnemyA(), new Point(200, 200));
            //AddEnemy.Chained(new EnemyB(), new Point(240, 200));
            //AddEnemy.Chained(new EnemyC(), new Point(280, 200));
            //AddEnemy.Chained(new EnemyUFO(), new Point(160, 200));
            //AddEnemy.Chained(new EnemyBigGun(), new Point(120, 200));

            #region FireBullet

            RoutedActions.FireBullet.Direct =
                (StarShip starship, int Multiplier, Point From, Point To, double Limit, Action <BulletInfo> handler) =>
            {
                var bullet = new SpriteWithMovement();

                Multiplier = Math.Max(Multiplier, 1);

                for (int i = 1; i <= Multiplier; i++)
                {
                    bullet.graphics.beginFill(Colors.Green);
                    bullet.graphics.drawRect((i - Multiplier) * 2, -8, 1, 16);
                }


                bullet.StepMultiplier = 0.3;
                bullet.MaxStep        = 24;

                if (From.y < To.y)
                {
                    bullet.TeleportTo(From.x, From.y);
                    bullet.TweenMoveTo(To.x + 0.00001, To.y);

                    bullet.PositionChanged +=
                        delegate
                    {
                        if (bullet.y > Limit)
                        {
                            bullet.Orphanize();
                        }
                    };
                }
                else
                {
                    bullet.TeleportTo(From.x, From.y);
                    bullet.TweenMoveTo(To.x + 0.00001, To.y);


                    bullet.PositionChanged +=
                        delegate
                    {
                        if (bullet.y < Limit)
                        {
                            bullet.Orphanize();
                        }
                    };
                }

                // it should not be null and provide the correct parent for the bullet
                if (starship == null)
                {
                    starship = this.Ego.ActiveEgo;
                }

                var bulletp = new BulletInfo(bullet.WithParent(starship))
                {
                    Multiplier = Multiplier
                };

                // local only
                FragileEntities.AddBullet(bulletp);

                bulletp.Element.AttachTo(CanvasOverlay);
                bulletp.Element.removed +=
                    delegate
                {
                    FragileEntities.Bullets.Remove(bulletp);
                };

                if (!bulletp.Silent)
                {
                    play(Sounds.firemissile);
                }

                if (handler != null)
                {
                    handler(bulletp);
                }
            };

            #endregion



            #region SetWeaponMultiplier

            RoutedActions.SetWeaponMultiplier.Direct =
                (p, value) =>
            {
                p.CurrentBulletMultiplier.Value = value;
            };
            #endregion

            #region AddDamage
            RoutedActions.AddDamage.Direct +=
                (target, damage, shooter) =>
            {
                target.TakeDamage(damage);

                if (target.HitPoints <= 0)
                {
                    // did we kill anything?
                    // shall we take credit?

                    if (GroupEnemies.Any(k => k == target))
                    {
                        cloud1.TickInterval.Value = Math.Max((cloud1.TickInterval.Value - 25), 200);
                        cloud1.Speed *= cloud1.SpeedAcc;
                    }

                    // we shot a coplayer while in evil mode! yay!
                    if (shooter == Ego.EvilEgo)
                    {
                        if (KnownEgos.Any(k => k.GoodEgo == target))
                        {
                            this.RoutedActions.AddAchivementUFO.Chained();
                        }
                    }

                    #region award localplayer and upgrade weapon
                    if (shooter == Ego.ActiveEgo)
                    {
                        Statusbar.Score.Value += target.ScorePoints;

                        TryUpgradeWeapon();
                    }
                    #endregion


                    play(target.GetDeathSound());
                }
                else
                {
                    play(Sounds.shortwhite);
                }

                //DebugDump.Write(
                //    new
                //    {
                //        From = bullet.Parent.Name,
                //        Delta = bullet.TotalDamage,
                //        target.HitPoints,
                //        To = target.Name
                //    }
                //);
            };
            #endregion



            #region FragileEntities
            this.FragileEntities.AddDamage = RoutedActions.AddDamage;

            this.FragileEntities.PrepareFilter =
                delegate
            {
                var GroupGood = KnownEgos.Select(i => i.GoodEgo).ToArray();
                var GroupEvil = GroupEnemies.ToArray();

                this.FragileEntities.Filter =
                    (source, n) =>
                {
                    // spare yourself
                    var query = source;

                    // spare coplayers in the same mode
                    if (GroupEnemies.Contains(n.Parent))
                    {
                        query = query.Where(x => !GroupEvil.Contains(x));
                    }
                    else
                    {
                        query = query.Where(x => !GroupGood.Contains(x));
                    }

                    return(query);
                };
            };
            #endregion

            this.RoutedActions.AddAchivementFiver.Direct =
                delegate
            {
                play(Sounds.insertcoin);
            };

            this.RoutedActions.AddAchivementMaxGun.Direct =
                delegate
            {
                play(Sounds.insertcoin);
            };

            this.RoutedActions.AddAchivementUFO.Direct =
                delegate
            {
                play(Sounds.mothershiploop);
            };

            Action <RoutedActionInfoBase> BaseHandler =
                e => DebugDump.Write(new { e.EventName });

            // events for network
            // RoutedActions.AddDamage.BaseHandler += BaseHandler;
            RoutedActions.RestoreStarship.BaseHandler     += BaseHandler;
            RoutedActions.AddAchivementFiver.BaseHandler  += BaseHandler;
            RoutedActions.AddAchivementUFO.BaseHandler    += BaseHandler;
            RoutedActions.AddAchivementMaxGun.BaseHandler += BaseHandler;

            //this.AddEnemy.BaseHandler += BaseHandler;
            ////this.AddBullet.BaseHandler += BaseHandler;
            //this.DoPlayerMovement.BaseHandler += BaseHandler;
            //this.SetWeaponMultiplier.BaseHandler += BaseHandler;
        }