Exemple #1
0
        public override void on_message(string msg, dynamic data)
        {
            if (msg.Equals("fireInput"))
            {
                if (((Playing_State)state).game_conf.soccer_mode)
                {
                    return;
                }

                Entity    origin = data.Origin;
                Weapon    weapon = data.Weapon;
                Ship_Info ship   = data.Ship;
                Bullet_Factory.fire_weapon(origin, weapon);
                if (!ship.has_powerup(typeof(Free_Fire_Powerup)))
                {
                    ship.energy_value -= weapon.energy_cost;
                }



                var input = origin.get_component <Input>();
                if (input != null)
                {
                    input.left_vib  += weapon.vib_left;
                    input.right_vib += weapon.vib_right;
                }
                Fab5_Game.inst().message("weapon_fired", new { name = weapon.sound, entity1 = origin, varying_pitch = true });
                weapon.timeSinceLastShot = 0f;
                if (weapon.GetType() == typeof(Secondary_Weapon) && ship.has_powerup(typeof(Fast_Bombs_Powerup)))
                {
                    weapon.timeSinceLastShot = weapon.fire_rate * 0.8f;
                }
            }
        }
Exemple #2
0
        public override void draw(float t, float dt)
        {
            var entities     = Fab5_Game.inst().get_entities_fast(typeof(FpsCounter));
            int num_entities = entities.Count;

            for (int i = 0; i < num_entities; i++)
            {
                var entity = entities[i];
                var fps    = entity.get_component <FpsCounter>();
                fps.frameCounter += 1;
                elapsedTime      += dt;

                if (elapsedTime > 1)
                {
                    elapsedTime     -= 1;
                    fps.frameRate    = fps.frameCounter;
                    fps.frameCounter = 0;

                    display_fps    = (int)fps.frameRate;
                    display_begins = (float)Rendering_System.num_begins / (float)Rendering_System.num_draws;

                    Rendering_System.num_begins = 0;
                    Rendering_System.num_draws  = 0;

                    Fab5_Game.inst().message("set_w_title", new { str = " * Starburst * " + fps.frameRate });
                    display_num_entities = state.get_num_entities();
                }
            }

            sprite_batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
            GFX_Util.draw_def_text(sprite_batch, "fps: " + display_fps, 10, 90);
            GFX_Util.draw_def_text(sprite_batch, "begins: " + string.Format("{0:0.00}", display_begins), 10, 126);
            GFX_Util.draw_def_text(sprite_batch, "entities: " + display_num_entities, 10, 162);
            sprite_batch.End();
        }
        public override void on_message(string msg, dynamic data)
        {
            if (msg == "destroy_entity")
            {
                var    id = data.id;
                Entity e  = Fab5_Game.inst().get_entity(id);
                if (e == null)
                {
                    return;
                }

                var ttl = e.get_component <TTL>();

                if (ttl != null)
                {
                    var cb = ttl.destroy_cb;
                    if (cb != null)
                    {
                        cb();
                    }
                }

                var s = e.state;
                if (s != null)
                {
                    s.remove_entity(e.id);
                }
            }
        }
Exemple #4
0
 public static Component[] create_components()
 {
     return(new Component[] {
         //new Bounding_Circle { radius = 6.0f },
         new Angle           {
         },
         //new Mass            { },
         new Position        {
             x = -1700.0f, y = 1700.0f
         },
         //new Velocity        { x = 0.0f, y = 0.0f },
         new Sprite          {
             texture = Fab5_Game.inst().get_content <Texture2D>("redturret")
         },
         new Brain           {
             think_fn = think, think_interval = THINK_INTERVAL
         },
         new Ship_Info(100, 100, 100, 100)
         {
             pindex = 8, team = 1
         },
         new Score {
         },
         new Data {
         }
     });
 }
Exemple #5
0
 public override void on_message(string msg, dynamic data)
 {
     if (msg == "set_w_title" && Fab5_Game.inst().Window != null)
     {
         Fab5_Game.inst().Window.Title = data.str;
     }
 }
Exemple #6
0
        public static float ShouldBePlayed(Position p1)
        {
            var min_dist = 99999999.0f;

            foreach (var e in Fab5_Game.inst().get_entities_fast(typeof(Input)))
            {
                var p    = e.get_component <Position>();
                var dx   = p.x - p1.x;
                var dy   = p.y - p1.y;
                var dist = dx * dx + dy * dy;
                if (dist < min_dist)
                {
                    min_dist = dist;
                }
            }

            if (min_dist < 0.1f)
            {
                // probably player making the sound
                return(1.0f);
            }

            var r = (float)Math.Sqrt(min_dist);

            r *= 3.0f / (float)Fab5_Game.inst().GraphicsMgr.PreferredBackBufferWidth;
            return((float)Math.Min(1.0f, 1.0f / (r * r)));
        }
        public override void draw(float t, float dt)
        {
            foreach (var entity in Fab5_Game.inst().get_entities_fast(typeof(Particle_Emitter)))
            {
                var emitter = entity.get_component <Particle_Emitter>();

                emitter.time_since_emit += dt;
                if (emitter.time_since_emit >= emitter.interval)
                {
                    emitter.time_since_emit -= emitter.interval;

                    for (int j = 0; j < emitter.num_particles_per_emit; j++)
                    {
                        Component[] components = emitter.emit_fn();

                        if (components == null)
                        {
                            continue;
                        }

                        var particle = state.create_entity(components);
                        if (emitter.on_emit_cb != null)
                        {
                            emitter.on_emit_cb(particle);
                        }
                    }
                }
            }
        }
 private static void fire(Entity entity, Ship_Info ship, Weapon weapon)
 {
     if (weapon.timeSinceLastShot >= weapon.fire_rate && ship.energy_value >= weapon.energy_cost)
     {
         var message = new { Origin = entity, Weapon = weapon, Ship = ship };
         Fab5_Game.inst().message("fireInput", message);
     }
 }
        public override void draw(float t, float dt)
        {
            var entities     = Fab5_Game.inst().get_entities_fast(typeof(TTL));
            int num_entities = entities.Count;

            /*        int counter = num_entities;
             *
             * if (counter == 0) {
             *  return;
             * }*/

            for (int i = 0; i < num_entities; i++)
            {
                var o = entities[i];
                //System.Threading.Tasks.Task.Factory.StartNew(() => {
                var entity = (Entity)o;//entities[i];
                var ttl    = entity.get_component <TTL>();

                ttl.time += dt;

                if (ttl.time >= ttl.max_time)
                {
                    Fab5_Game.inst().message("destroy_entity", new { id = entity.id });
                }

                ttl.counter = (ttl.counter + 1) & 3;

                if (ttl.alpha_fn != null && ttl.counter == 0)
                {
                    var s = entity.get_component <Sprite>();
                    if (s != null)
                    {
                        var a = ttl.alpha_fn(ttl.time, ttl.max_time) * 255.0f;
                        if (a < 0.0f)
                        {
                            a = 0.0f;
                        }
                        if (a > 255.0f)
                        {
                            a = 255.0f;
                        }
                        s.color.A = (byte)a;
                    }
                    else
                    {
                        var txt = entity.get_component <Text>();
                        if (txt != null)
                        {
                            var a = ttl.alpha_fn(ttl.time, ttl.max_time);
                            txt.color = txt.original_color * a;;
                        }
                    }
                }
                //});
            }

            //mre.WaitOne();
        }
        public static Component[] create_components(Fab5.Starburst.States.Playing.Game_Config conf, int team)
        {
            List <Component> components = new List <Component>(Fab5.Starburst.States.Playing.Entities.Player_Ship.create_components(new Input(), conf, team));

            Input input = (Input)components[0];

            components.RemoveAt(0);

            /*return new Component[] {
             *  new Angle           { },
             *
             *  new Bounding_Circle { radius = 16.0f },
             *
             *  new Brain           { think_fn       = think,
             *                        think_interval = THINK_INTERVAL },
             *
             *  new Data            { },
             *
             *  new Mass            { mass = 15.0f, friction = 0.0f, restitution_coeff = 0.4f },
             *
             *  new Position        { x = -1700.0f,
             *                        y = 1700.0f },
             *
             *  new Ship_Info(100.0f, 100.0f, 100.0f, 100.0f) { },
             *
             *  new Sprite          { texture = Fab5_Game.inst().get_content<Texture2D>("ships/ship1" + ai_counter) },
             *
             *  new Velocity        { x = 0.0f,
             *                        y = 0.0f },
             * };*/

            components.Add(
                new Brain {
                think_fn         = think,
                think_interval   = THINK_INTERVAL,
                time_since_think = (float)rand.NextDouble() * THINK_INTERVAL
            }
                );

            var data = new Data {
            };

            data.data["input"]            = input;
            data.data["ai_index"]         = string.Format("{0:00}", ai_index++);
            data.data["path_recalc_time"] = Fab5_Game.inst().get_time() - 0.5f + (float)rand.NextDouble() * 2.0f;

            //Console.WriteLine(data.data["path_recalc_time"]);

            data.data["courage_fac"]    = 1.0f + 3.0f * (float)Math.Pow((float)rand.NextDouble(), 3.0f);
            data.data["aggression_fac"] = 0.5f + 10.0f * (float)Math.Pow((float)rand.NextDouble(), 2.0f);
            data.data["greed_fac"]      = 0.2f + 10.0f * (float)Math.Pow((float)rand.NextDouble(), 3.0f);


            components.Add(data);

            return(components.ToArray());
        }
Exemple #11
0
 public Fab5SoundEffect(string file, string desc)
 {
     File           = file;
     Desc           = desc;
     SoundEffectIns = new Dictionary <int, SoundEffectInstance>();
     SoundEffect    = Fab5_Game.inst().Content.Load <SoundEffect>(file);
     IsStarted      = new Dictionary <int, bool>();
     LastPLayedDic  = new Dictionary <long, DateTime>();
 }
        public static void fire_weapon(Entity origin, Weapon weapon)
        {
            if (weapon.GetType() == typeof(Secondary_Weapon))
            {
                Fab5_Game.inst().create_entity(weapon2(origin, weapon));

                var theta = 2.0f * 3.141592f * (float)rand.NextDouble();
                var force = 28.0f;
                var dx    = (float)Math.Cos(theta) * force;
                var dy    = (float)Math.Sin(theta) * force;
                Fab5_Game.inst().message("shake_camera", new { player = origin, disp_x = dx, disp_y = dy });
                return;
            }

            if (origin.get_component <Ship_Info>().has_powerup(typeof(Multifire_Powerup)))
            {
                var a      = origin.get_component <Angle>();
                var angle1 = new Angle {
                    angle = a.angle - 15.0f * 3.141592f / 180.0f, ang_vel = a.ang_vel
                };
                var angle2 = new Angle {
                    angle = a.angle, ang_vel = a.ang_vel
                };
                var angle3 = new Angle {
                    angle = a.angle + 15.0f * 3.141592f / 180.0f, ang_vel = a.ang_vel
                };
                Fab5_Game.inst().create_entity(weapon1(origin, weapon, angle1));
                Fab5_Game.inst().create_entity(weapon1(origin, weapon, angle2));
                Fab5_Game.inst().create_entity(weapon1(origin, weapon, angle3));

                var theta = 2.0f * 3.141592f * (float)rand.NextDouble();
                var force = 16.0f;
                var dx    = (float)Math.Cos(theta) * force;
                var dy    = (float)Math.Sin(theta) * force;
                Fab5_Game.inst().message("shake_camera", new { player = origin, disp_x = dx, disp_y = dy });
            }
            else
            {
                Fab5_Game.inst().create_entity(weapon1(origin, weapon, origin.get_component <Angle>()));

                var theta = 2.0f * 3.141592f * (float)rand.NextDouble();
                var force = 8.0f;
                var dx    = (float)Math.Cos(theta) * force;
                var dy    = (float)Math.Sin(theta) * force;
                Fab5_Game.inst().message("shake_camera", new { player = origin, disp_x = dx, disp_y = dy });
            }
        }
Exemple #13
0
        //private int number_of_players;

        public Hudsystem(SpriteBatch sprite_batch, Tile_Map tile_map)
        {
            this.sprite_batch = sprite_batch;

            enball = new Sprite()
            {
                texture = Fab5_Game.inst().get_content <Texture2D>("EnergiAtlas"),
                //color = new Color(0.70f, 0.70f, 0.70f)
            };

            minimap_tex = new Texture2D(Fab5_Game.inst().GraphicsDevice, 256, 256);

            for (int i = 0; i < 256; i++)
            {
                for (int j = 0; j < 256; j++)
                {
                    var x = i >> 1;
                    var y = j >> 1;

                    minimap_tex.SetData(0, new Rectangle(x, y, 1, 1), new [] { new Color(0.0f, 0.0f, 0.0f, 0.0f) }, 0, 1);

                    if ((x % 16) == 0 || (y % 16) == 0)
                    {
                        minimap_tex.SetData(0, new Rectangle(x, y, 1, 1), new [] { Color.White * 0.3f }, 0, 1);
                    }
                }
            }

            for (int i = 0; i < 256; i++)
            {
                for (int j = 0; j < 256; j++)
                {
                    var x = i >> 1;
                    var y = j >> 1;

                    var k = i + 256 * j;
                    if (tile_map.tiles[k] != 0 && tile_map.tiles[k] < 7)
                    {
                        minimap_tex.SetData(0, new Rectangle(x, y, 1, 1), new [] { Color.White }, 0, 1);
                    }
                }
            }

            white_pixel_tex = new Texture2D(Fab5_Game.inst().GraphicsDevice, 1, 1);
            white_pixel_tex.SetData(new [] { Color.White });
        }
Exemple #14
0
        public override void update(float t, float dt)
        {
            var entities     = Fab5_Game.inst().get_entities_fast(typeof(Velocity));
            int num_entities = entities.Count;

            for (int i = 0; i < num_entities; i++)
            {
                var entity   = entities[i];
                var position = entity.get_component <Position>();
                var velocity = entity.get_component <Velocity>();
                var angle    = entity.get_component <Angle>();
                var mass     = entity.get_component <Mass>();

                if (mass != null)
                {
                    var dtm = dt * mass.drag_coeff;
                    velocity.x -= velocity.x * dtm;
                    velocity.y -= velocity.y * dtm;
                }

                velocity.x += velocity.ax * dt;
                velocity.y += velocity.ay * dt;

                position.x += velocity.x * dt;
                position.y += velocity.y * dt;

                if (angle != null)
                {
                    angle.angle += angle.ang_vel * dt;

                    while (angle.angle <= 0.0f)
                    {
                        angle.angle += 2.0f * 3.141592653f;
                    }

                    while (angle.angle >= 2.0f * 3.141592653f)
                    {
                        angle.angle -= 2.0f * 3.141592653f;
                    }

                    angle.ang_vel -= angle.drag * angle.ang_vel * dt;
                }
            }
        }
Exemple #15
0
        public override void draw(float t, float dt)
        {
            var entities       = Fab5_Game.inst().get_entities_fast(typeof(SoundLibrary));
            int num_components = entities.Count;

            for (int i = 0; i < num_components; i++)
            {
                var entity = entities[i];
                var music  = entity.get_component <SoundLibrary>();
                if (!music.IsSongStarted)
                {
                    var bmusic = music.Library.ElementAt(music.song_index).Value as BackgroundMusic;
                    if (bmusic != null)
                    {
                        MediaPlayer.Play(bmusic.BackSong);
                        MediaPlayer.IsRepeating = bmusic.IsRepeat;
                        music.NowPlayingIndex   = 0;
                        music.IsSongStarted     = true;
                    }
                }
            }

            if (fading_in)
            {
                fade_cur += fade_val * dt;
                if (fade_cur > fade_vol)
                {
                    fade_cur  = fade_vol;
                    fading_in = false;
                }
                MediaPlayer.Volume = (float)Math.Max(0.0f, Math.Min(fade_cur, 1.0f));
            }
            else if (fading_out)
            {
                fade_cur += fade_val * dt;
                if (fade_cur < fade_vol)
                {
                    fade_cur   = fade_vol;
                    fading_out = false;
                }
                //System.Console.WriteLine("faded down to " + fade_cur + ", " + fade_val);
                MediaPlayer.Volume = (float)Math.Max(0.0f, Math.Min(fade_cur, 1.0f));
            }
        }
        public static void fire_burst_powerup(Entity origin, Weapon weapon)
        {
            var a = origin.get_component <Angle>();

            var rand = new Random();

            for (int i = 0; i < 100; i++)
            {
                Fab5_Game.inst().create_entity(weapon1(origin, weapon, new Angle {
                    angle = a.angle - (360.0f * (float)rand.NextDouble()) * 3.141592f / 180.0f, ang_vel = a.ang_vel
                }));
            }

            var theta = 2.0f * 3.141592f * (float)rand.NextDouble();
            var force = 16.0f;
            var dx    = (float)Math.Cos(theta) * force;
            var dy    = (float)Math.Sin(theta) * force;

            Fab5_Game.inst().message("shake_camera", new { player = origin, disp_x = dx, disp_y = dy });
        }
Exemple #17
0
        public override void update(float t, float dt)
        {
            var entities = Fab5_Game.inst().get_entities_fast(typeof(Brain));

            foreach (var entity in entities)
            {
                var brain = entity.get_component <Brain>();

                brain.time_since_think += dt;
                if (brain.time_since_think > brain.think_interval)
                {
                    brain.time_since_think = 0.0f;

                    //try {
                    brain.think_fn(entity);
                    //}
                    //catch (Exception e) {
                    //    Console.WriteLine("think function failed!");
                    //    Console.WriteLine(e);
                    //}
                }
            }
        }
Exemple #18
0
        public override void draw(float t, float dt)
        {
            var entities        = Fab5_Game.inst().get_entities_fast(typeof(Primary_Weapon));
            int numberOfWeapons = entities.Count;

            for (int i = 0; i < numberOfWeapons; i++)
            {
                Weapon weapon  = entities[i].get_component <Primary_Weapon>();
                Weapon weapon2 = entities[i].get_component <Secondary_Weapon>();
                if (weapon != null && weapon.timeSinceLastShot <= weapon.fire_rate)
                {
                    weapon.timeSinceLastShot += dt;
                }
                if (weapon2 != null && weapon2.timeSinceLastShot <= weapon2.fire_rate)
                {
                    weapon2.timeSinceLastShot += dt;
                }

                // @To-do: putting inv here to not introduce another subsystem
                var si = entities[i].get_component <Ship_Info>();

                if (si != null)
                {
                    foreach (var s in si.powerups.Keys.ToArray())
                    {
                        si.powerups[s].time -= dt;
                        if (si.powerups[s].time <= 0.0f)
                        {
                            si.powerups[s].end();
                            si.powerups.Remove(s);
                        }
                    }
                }
            }

            base.update(t, dt);
        }
Exemple #19
0
        private static void think(Entity self)
        {
            var self_pos = self.get_component <Position>();

            var entities = Fab5_Game.inst().get_entities_fast(typeof(Ship_Info));

            if (entities.Count == 0)
            {
                return;
            }

            var enemies = new List <Entity>();

            foreach (var player in entities)
            {
                var si = player.get_component <Ship_Info>();
                if (si.is_dead)
                {
                    continue;
                }

                var pos = player.get_component <Position>();
                if (pos == null)
                {
                    continue;
                }

                var dx = self_pos.x - pos.x;
                var dy = self_pos.y - pos.y;

                var dist = dx * dx + dy * dy;

                if (dist > awareness_dist)
                {
                    continue;
                }

                if (player.get_component <Ship_Info>().team != 2)
                {
                    continue;
                }

                enemies.Add(player);
            }

            if (enemies.Count == 0)
            {
                return;
            }

            var n      = rand.Next(0, enemies.Count);
            var target = enemies[n];

            var p = target.get_component <Position>();
            var r = (float)Math.Atan2(p.y - self_pos.y, p.x - self_pos.x);

            // var w = 5.0f * (r - self.get_component<Angle>().angle);
            // if (w < -5.0f) w = -5.0f;
            // else if (w > 5.0f) w = 5.0f;

            self.get_component <Angle>().angle = r;

            //Fab5.Starburst.States.Playing.Entities.Bullet_Factory.fire_weapon(self, new Primary_Weapon());

            var last_shot = (float)(self.get_component <Data>().get_data("last_shot", 0.0f));

            if (Fab5_Game.inst().get_time() - last_shot < 1.0f / 2.0f)
            {
                return;
            }

            Fab5_Game.inst().create_entity(shoot(self, self.get_component <Angle>()));

            self.get_component <Data>().data["last_shot"] = (float)Fab5_Game.inst().get_time();
        }
Exemple #20
0
        private static Component[] shoot(Entity self, Angle shipAngle)
        {
            Fab5_Game.inst().message("turretsound", new { name = "turret", varying_pitch = true, entity1 = self });

            float shipRadian = 21f;  // offset från skeppets mitt där skottet utgår ifrån
            float speed      = 900f; // skottets hastighet (kanske ska vara vapenberoende?)
            float lifeTime   = 1.5f; // skottets livstid (i sekunder? iaf baserad på dt)

            Position position = self.get_component <Position>();
            Velocity shipVel  = self.get_component <Velocity>() ?? new Velocity();


            double dAngle = (double)shipAngle.angle + ((float)rand.NextDouble() - 0.5f) * 0.08f;
            float  sfa    = (float)Math.Sin(dAngle);
            float  cfa    = (float)Math.Cos(dAngle);

            var pos = new Position()
            {
                x = position.x + shipRadian * cfa, y = position.y + shipRadian * sfa
            };
            var angle = new Angle()
            {
                angle = shipAngle.angle + rotationOffset, ang_vel = 0.0f
            };
            var velocity = new Velocity()
            {
                x = cfa * speed + shipVel.x, y = sfa * speed + shipVel.y
            };

            Sprite bulletSprite = new Sprite()
            {
                texture = Fab5_Game.inst().get_content <Texture2D>("wbeam"), blend_mode = Sprite.BM_ADD, scale = 1.0f, color = new Color(0.5f, 0.5f, 1.0f)
            };

            var particle_tex = Fab5_Game.inst().get_content <Texture2D>("particle");

            return(new Component[] {
                new Particle_Emitter()
                {
                    emit_fn = () => {
                        var theta1 = 2.0f * 3.1415f * (float)rand.NextDouble();
                        var theta2 = 2.0f * 3.1415f * (float)rand.NextDouble();
                        var radius = 4.0f * (float)rand.NextDouble();
                        var speed2 = 20.0f * (float)(rand.NextDouble() + 0.5f);

                        return new Component[] {
                            new Position {
                                x = pos.x + (float)Math.Cos(theta1) * radius,
                                y = pos.y + (float)Math.Sin(theta1) * radius
                            },
                            new Velocity {
                                x = velocity.x * 0.2f + (float)Math.Cos(theta2) * speed2,
                                y = velocity.y * 0.2f + (float)Math.Sin(theta2) * speed2
                            },
                            new Sprite {
                                texture = particle_tex,
                                color = new Color(1.0f, 0.2f, 0.2f, 1.0f),
                                scale = 0.2f + (float)rand.NextDouble() * 0.6f,
                                blend_mode = Sprite.BM_ADD,
                                layer_depth = 0.3f
                            },
                            new TTL {
                                alpha_fn = (x, max) => 1.0f - (x / max) * (x / max),
                                max_time = 0.05f + (float)(rand.NextDouble() * 0.05f)
                            }
                        };
                    },
                    interval = 0.03f,
                    num_particles_per_emit = 2
                },
                pos,
                velocity,
                angle,
                bulletSprite,
                new Bounding_Circle()
                {
                    radius = 6,
                    ignore_collisions = IG_BULLET,
                    ignore_collisions2 = self.get_component <Ship_Info>().team,
                    collision_cb = (bullet, other_entity) => {
                        Fab5_Game.inst().create_entity(new Component[] {
                            new TTL {
                                max_time = 0.05f
                            },
                            new Particle_Emitter {
                                emit_fn = () => {
                                    return new Component[] {
                                        new Position {
                                            x = pos.x,
                                            y = pos.y
                                        },
                                        new Velocity {
                                            x = (float)Math.Cos((float)rand.NextDouble() * 6.28) * (100.0f + 80.0f * (float)rand.NextDouble()),
                                            y = (float)Math.Sin((float)rand.NextDouble() * 6.28) * (100.0f + 80.0f * (float)rand.NextDouble())
                                        },
                                        new Sprite {
                                            blend_mode = Sprite.BM_ADD,
                                            color = new Color(1.0f, 0.5f, 0.5f),
                                            layer_depth = 0.3f,
                                            scale = 0.2f + (float)rand.NextDouble() * 0.3f,
                                            texture = Fab5_Game.inst().get_content <Texture2D>("particle")
                                        },
                                        new TTL {
                                            alpha_fn = (x, max) => 1.0f - x / max,
                                            max_time = 0.1f + (float)(rand.NextDouble() * 0.1f)
                                        }
                                    };
                                },
                                interval = 0.01f,
                                num_particles_per_emit = 10 + rand.Next(0, 20)
                            }
                        });
                        bullet.destroy();
                    }
                },
                new Mass {
                    mass = .1f, restitution_coeff = -1.0f, friction = 0.0f
                },
                new TTL()
                {
                    alpha_fn = (x, max) => 10.0f - 10.0f * x / max, max_time = lifeTime
                },
                new Bullet_Info()
                {
                    damage = 65, sender = self, max_speed = speed
                },
                new Light_Source {
                    color = new Color(1.0f, 0.3f, 0.3f), size = 0.35f, intensity = 0.7f
                },
            });
        }
        public override void update(float t, float dt)
        {
            var           entities             = Fab5_Game.inst().get_entities_fast(typeof(Input));
            int           num_components       = entities.Count;
            KeyboardState currentKeyboardState = Keyboard.GetState();

            for (int i = 0; i < num_components; i++)
            {
                var entity       = entities[i];
                var inputHandler = entity.get_component <Input>();

                if (inputHandler.device == Input.InputType.Keyboard)
                {
                    if (is_key_clicked(inputHandler.up, currentKeyboardState, inputHandler.keyboardState))
                    {
                        Fab5_Game.inst().message("up", new { Player = entity });
                    }
                    if (is_key_clicked(inputHandler.left, currentKeyboardState, inputHandler.keyboardState))
                    {
                        Fab5_Game.inst().message("left", new { Player = entity });
                    }
                    if (is_key_clicked(inputHandler.down, currentKeyboardState, inputHandler.keyboardState))
                    {
                        Fab5_Game.inst().message("down", new { Player = entity });
                    }
                    if (is_key_clicked(inputHandler.right, currentKeyboardState, inputHandler.keyboardState))
                    {
                        Fab5_Game.inst().message("right", new { Player = entity });
                    }
                    if (is_key_clicked(inputHandler.primary_fire, currentKeyboardState, inputHandler.keyboardState))
                    {
                        Fab5_Game.inst().message("select", new { Player = entity });
                    }
                    if (is_key_clicked(inputHandler.secondary_fire, currentKeyboardState, inputHandler.keyboardState))
                    {
                        Fab5_Game.inst().message("back", new { Player = entity });
                    }
                }
                else
                {
                    GamePadState currentState = GamePad.GetState(inputHandler.gp_index);
                    float        threshold    = .5f; // tröskelvärde för styrspak
                    if (is_gamepad_thumbstick_up(threshold, currentState, inputHandler.gamepadState))
                    {
                        Fab5_Game.inst().message("up", new { Player = entity });
                    }
                    if (is_gamepad_thumbstick_down(threshold, currentState, inputHandler.gamepadState))
                    {
                        Fab5_Game.inst().message("down", new { Player = entity });
                    }
                    if (is_gamepad_thumbstick_left(threshold, currentState, inputHandler.gamepadState))
                    {
                        Fab5_Game.inst().message("left", new { Player = entity });
                    }
                    if (is_gamepad_thumbstick_right(threshold, currentState, inputHandler.gamepadState))
                    {
                        Fab5_Game.inst().message("right", new { Player = entity });
                    }
                    if (is_gamepad_clicked(Buttons.A, currentState, inputHandler.gamepadState))
                    {
                        Fab5_Game.inst().message("select", new { Player = entity });
                    }
                    if (is_gamepad_clicked(Buttons.B, currentState, inputHandler.gamepadState))
                    {
                        Fab5_Game.inst().message("back", new { Player = entity });
                    }
                    if (is_gamepad_clicked(Buttons.Start, currentState, inputHandler.gamepadState))
                    {
                        Fab5_Game.inst().message("start", null);
                    }
                    inputHandler.gamepadState = currentState;
                }
                if (currentKeyboardState.IsKeyDown(Keys.LeftAlt) && is_key_clicked(Keys.Enter, currentKeyboardState, inputHandler.keyboardState))
                {
                    Fab5_Game.inst().message("fullscreen", null);
                }
                else if (is_key_clicked(Keys.Enter, currentKeyboardState, inputHandler.keyboardState))
                {
                    Fab5_Game.inst().message("start", null);
                }
                else if (is_key_clicked(Keys.Escape, currentKeyboardState, inputHandler.keyboardState))
                {
                    Fab5_Game.inst().message("escape", null);
                }

                inputHandler.keyboardState = currentKeyboardState;
            }
        }
        public override void init()
        {
            sprite_batch = new SpriteBatch(Starburst.inst().GraphicsDevice);

            add_subsystems(
                new Menu_Input_Handler(),
                new Sound(),
                new Particle_System(),
                new Background_Renderer(sprite_batch)
                );

            outDelay      = delay + inDuration + displayTime;
            animationTime = outDelay + outDuration;
            randoms       = new List <double>();
            Random rn = new Random();

            for (int i = 0; i < 30; i++)
            {
                randoms.Add(rn.NextDouble());
            }

            Viewport vp = Starburst.inst().GraphicsDevice.Viewport;

            lowRes = (vp.Height < 800 && vp.Width < 1600);

            // load textures
            background = Starburst.inst().get_content <Texture2D>("backdrops/menubg");
            rectBg     = new Texture2D(Fab5_Game.inst().GraphicsDevice, 1, 1);
            rectBg.SetData(new Color[] { Color.Black }, 1, 1);//Starburst.inst().get_content<Texture2D>("controller_rectangle");
            font                = Starburst.inst().get_content <SpriteFont>(!lowRes ? "sector034" : "small");
            smallFont           = Starburst.inst().get_content <SpriteFont>(!lowRes ? "small" : "tiny");
            largeFont           = Starburst.inst().get_content <SpriteFont>("sector034");
            controller_a_button = Starburst.inst().get_content <Texture2D>("menu/Xbox_A_white");
            keyboard_key        = Starburst.inst().get_content <Texture2D>("menu/Key");
            controller_l_stick  = Starburst.inst().get_content <Texture2D>("menu/Xbox_L_white");
            downArrow           = Starburst.inst().get_content <Texture2D>("menu/arrow_down");

            Input wasd = new Input()
            {
                left           = Keys.A,
                right          = Keys.D,
                up             = Keys.W,
                down           = Keys.S,
                gp_index       = PlayerIndex.Two,
                primary_fire   = Keys.F,
                secondary_fire = Keys.G,
                powerup_next   = Keys.T,
                powerup_use    = Keys.R
            };
            var keyboardPlayer1 = create_entity(Player.create_components(wasd));
            var keyboardPlayer2 = create_entity(Player.create_components());

            gamepads = new List <bool>(GamePad.MaximumGamePadCount);
            for (int i = 0; i < GamePad.MaximumGamePadCount; i++)
            {
                gamepads.Add(GamePad.GetState(i).IsConnected);
                if (gamepads[i])
                {
                    Input input = new Input()
                    {
                        device = Input.InputType.Controller, gp_index = (PlayerIndex)i
                    };
                    var gamepadPlayer = create_entity(Player.create_components(input));
                }
            }
            playerSlots = new List <SlotStatus>();
            for (int i = 0; i < GamePad.MaximumGamePadCount; i++)
            {
                playerSlots.Add(SlotStatus.Empty);
            }
        }
Exemple #23
0
 public BackgroundMusic(String file, bool isRepeat)
 {
     File     = file;
     IsRepeat = isRepeat;
     BackSong = Fab5_Game.inst().Content.Load <Song>(file);
 }
Exemple #24
0
        public override void init()
        {
            sprite_batch = new SpriteBatch(Starburst.inst().GraphicsDevice);

            add_subsystems(
                new Menu_Input_Handler(),
                new Sound(),
                new Particle_System(),
                new Background_Renderer(sprite_batch)
                );

            outDelay      = delay + inDuration + displayTime;
            animationTime = outDelay + outDuration;

            soundMgr = create_entity(SoundManager.create_backmusic_component());
            soundMgr.get_component <SoundLibrary>().song_index = 1;

            Viewport vp = sprite_batch.GraphicsDevice.Viewport;

            lowRes = (vp.Height < 800 && vp.Width < 1600);

            // load textures
            background = Starburst.inst().get_content <Texture2D>("backdrops/backdrop4");
            rectBg     = new Texture2D(Fab5_Game.inst().GraphicsDevice, 1, 1);
            rectBg.SetData(new Color[] { Color.Black }, 1, 1);//Starburst.inst().get_content<Texture2D>("controller_rectangle");
            font                = Starburst.inst().get_content <SpriteFont>(!lowRes?"sector034":"small");
            largeFont           = Starburst.inst().get_content <SpriteFont>("large");
            controller_a_button = Starburst.inst().get_content <Texture2D>("menu/Xbox_A_white");
            keyboard_key        = Starburst.inst().get_content <Texture2D>("menu/Key");
            controller_l_stick  = Starburst.inst().get_content <Texture2D>("menu/Xbox_L_white");

            text_ok           = "Ok";
            text_select       = "Select";
            okSize            = font.MeasureString(text_ok);
            controllerBtnSize = !lowRes ? 50 : 37; // ikon för knapp
            heightDiff        = (int)(controllerBtnSize - okSize.Y);
            yPos = (int)(vp.Height - controllerBtnSize - 15);

            Input wasd = new Input()
            {
                left           = Keys.A,
                right          = Keys.D,
                up             = Keys.W,
                down           = Keys.S,
                gp_index       = PlayerIndex.Two,
                primary_fire   = Keys.F,
                secondary_fire = Keys.G,
                powerup_next   = Keys.T,
                powerup_use    = Keys.R
            };
            var keyboardPlayer1 = create_entity(Player.create_components(wasd));
            var keyboardPlayer2 = create_entity(Player.create_components());

            gamepads = new List <bool>(GamePad.MaximumGamePadCount);
            for (int i = 0; i < GamePad.MaximumGamePadCount; i++)
            {
                gamepads.Add(GamePad.GetState(i).IsConnected);
                if (gamepads[i])
                {
                    Input input = new Input()
                    {
                        device = Input.InputType.Controller, gp_index = (PlayerIndex)i
                    };
                    var gamepadPlayer = create_entity(Player.create_components(input));
                }
            }

            // Map-configs
            maps = new List <MapConfig>();
            maps.Add(new MapConfig()
            {
                fileName   = "map1.png",
                mapName    = "Team Deathmatch",
                bots       = true,
                gameMode   = Playing.Game_Config.GM_TEAM_DEATHMATCH,
                preview    = Fab5_Game.inst().get_content <Texture2D>("maps/preview1"),
                soccerBall = true
            });
            maps.Add(new MapConfig()
            {
                fileName        = "map2.png",
                mapName         = "Deathmatch",
                bots            = true,
                gameMode        = Playing.Game_Config.GM_DEATHMATCH,
                preview         = Fab5_Game.inst().get_content <Texture2D>("maps/preview2"),
                asteroidAmounts = new int[] { 5, 10, 20 }
            });
            maps.Add(new MapConfig()
            {
                fileName        = "map3_soccer.png",
                mapName         = "Soccer",
                bots            = false,
                soccerBall      = true,
                soccerMode      = true,
                gameMode        = Playing.Game_Config.GM_TEAM_DEATHMATCH,
                preview         = Fab5_Game.inst().get_content <Texture2D>("maps/preview3_soccer"),
                asteroidAmounts = new int[] { 5, 10, 20 }
            });
            maps.Add(new MapConfig()
            {
                fileName = "map0.png",
                mapName  = "Deathmatch",
                bots     = true,
                gameMode = Playing.Game_Config.GM_DEATHMATCH,
                preview  = Fab5_Game.inst().get_content <Texture2D>("maps/preview0")
            });
            updateMapSettings();
        }
        private static float rotationOffset     = MathHelper.ToRadians(-90f); // rotationsoffset för skott-texturen


        private static Component[] weapon1(Entity origin, Weapon weapon, Angle shipAngle)
        {
            float shipRadian = 21f;  // offset från skeppets mitt där skottet utgår ifrån
            float speed      = 600f; // skottets hastighet (kanske ska vara vapenberoende?)
            float lifeTime   = 1.5f; // skottets livstid (i sekunder? iaf baserad på dt)

            Position position = origin.get_component <Position>();
            Velocity shipVel  = origin.get_component <Velocity>() ?? new Velocity();

            double dAngle = (double)shipAngle.angle + ((float)rand.NextDouble() - 0.5f) * 0.08f;
            float  sfa    = (float)Math.Sin(dAngle);
            float  cfa    = (float)Math.Cos(dAngle);

            var pos = new Position()
            {
                x = position.x + shipRadian * cfa, y = position.y + shipRadian * sfa
            };
            var angle = new Angle()
            {
                angle = shipAngle.angle + rotationOffset, ang_vel = 0.0f
            };
            var velocity = new Velocity()
            {
                x = cfa * speed + shipVel.x, y = sfa * speed + shipVel.y
            };

            Sprite bulletSprite = new Sprite()
            {
                texture = bulletTexture1, layer_depth = 1, blend_mode = Sprite.BM_ADD, scale = 0.35f
            };
            var light_color = new Color(1.0f, 0.6f, 0.2f);
            var tail_color  = new Color(1.0f, 0.6f, 0.2f, 1.0f);

            if (origin.get_component <Ship_Info>().has_powerup(typeof(Bouncy_Bullets_Powerup)))
            {
                bulletSprite.color = new Color(1.0f, 0.2f, 0.2f);
                light_color        = new Color(1.0f, 0.2f, 0.9f);
                tail_color         = new Color(1.0f, 0.2f, 0.9f);
            }

            var particle_tex = Starburst.inst().get_content <Texture2D>("particle");


            return(new Component[] {
                new Particle_Emitter()
                {
                    emit_fn = () => {
                        var theta1 = 2.0f * 3.1415f * (float)rand.NextDouble();
                        var theta2 = 2.0f * 3.1415f * (float)rand.NextDouble();
                        var radius = 4.0f * (float)rand.NextDouble();
                        var speed2 = 20.0f * (float)(rand.NextDouble() + 0.5f);

                        return new Component[] {
                            new Position()
                            {
                                x = pos.x + (float)Math.Cos(theta1) * radius,
                                y = pos.y + (float)Math.Sin(theta1) * radius
                            },
                            new Velocity()
                            {
                                x = velocity.x * 0.2f + (float)Math.Cos(theta2) * speed2,
                                y = velocity.y * 0.2f + (float)Math.Sin(theta2) * speed2
                            },
                            new Sprite()
                            {
                                texture = particle_tex,
                                color = tail_color,
                                scale = 0.2f + (float)rand.NextDouble() * 0.6f,
                                blend_mode = Sprite.BM_ADD,
                                layer_depth = 0.3f
                            },
                            new TTL()
                            {
                                alpha_fn = (x, max) => 1.0f - (x / max) * (x / max), max_time = 0.05f + (float)(rand.NextDouble() * 0.05f)
                            }
                            //                        new Bounding_Circle() { radius = 1.0f },
                            //                        new Mass() { mass = 0.0f }
                        };
                    },
                    interval = 0.03f,
                    num_particles_per_emit = 2
                },
                pos,
                velocity,
                angle,
                bulletSprite,
                //bulletDrawArea,
                new Bounding_Circle()
                {
                    radius = 6,
                    ignore_collisions = IG_BULLET,
                    ignore_collisions2 = origin.get_component <Ship_Info>().team,
                    collision_cb = (self, other_entity) => {
                        if (self.get_component <Bullet_Info>().sender.get_component <Ship_Info>().has_powerup(typeof(Bouncy_Bullets_Powerup)))
                        {
                            return;
                        }

                        Fab5_Game.inst().create_entity(new Component[] {
                            new TTL {
                                max_time = 0.05f
                            },
                            new Particle_Emitter {
                                emit_fn = () => {
                                    return new Component[] {
                                        new Position {
                                            x = pos.x,
                                            y = pos.y
                                        },
                                        new Velocity {
                                            x = (float)Math.Cos((float)rand.NextDouble() * 6.28) * (100.0f + 80.0f * (float)rand.NextDouble()),
                                            y = (float)Math.Sin((float)rand.NextDouble() * 6.28) * (100.0f + 80.0f * (float)rand.NextDouble())
                                        },
                                        new Sprite {
                                            blend_mode = Sprite.BM_ADD,
                                            color = new Color(0.2f, 0.6f, 1.0f),
                                            layer_depth = 0.3f,
                                            scale = 0.2f + (float)rand.NextDouble() * 0.3f,
                                            texture = Starburst.inst().get_content <Texture2D>("particle")
                                        },
                                        new TTL {
                                            alpha_fn = (x, max) => 1.0f - x / max,
                                            max_time = 0.1f + (float)(rand.NextDouble() * 0.1f)
                                        }
                                    };
                                },
                                interval = 0.01f,
                                num_particles_per_emit = 10 + rand.Next(0, 20)
                            }
                        });
                        self.destroy();
                    }
                },
                new Mass {
                    mass = 1.0f, restitution_coeff = -1.0f, friction = 0.0f
                },
                new TTL()
                {
                    alpha_fn = (x, max) => 10.0f - 10.0f * x / max, max_time = lifeTime
                },
                new Bullet_Info()
                {
                    damage = weapon.damage, sender = origin, max_speed = speed
                },
                new Light_Source {
                    color = light_color, size = 0.45f, intensity = 0.7f
                }
            });
        }
        private static Component[] weapon2(Entity origin, Weapon weapon)
        {
            float shipRadian = 23f;  // offset från skeppets mitt där skottet utgår ifrån
            float speed      = 300f; // skottets hastighet (kanske ska vara vapenberoende?)
            float lifeTime   = 4.0f; // skottets livstid (i sekunder? iaf baserad på dt)

            Position position  = origin.get_component <Position>();
            Angle    shipAngle = origin.get_component <Angle>();
            Velocity shipVel   = origin.get_component <Velocity>();

            double dAngle = (double)shipAngle.angle + ((float)rand.NextDouble() - 0.5f) * 0.08f;
            float  sfa    = (float)Math.Sin(dAngle);
            float  cfa    = (float)Math.Cos(dAngle);

            var pos = new Position()
            {
                x = position.x + shipRadian * cfa, y = position.y + shipRadian * sfa
            };
            var angle = new Angle()
            {
                angle = shipAngle.angle + rotationOffset, ang_vel = 0.0f
            };
            var velocity = new Velocity()
            {
                x = cfa * speed + shipVel.x, y = sfa * speed + shipVel.y
            };

            Sprite bulletSprite = new Sprite()
            {
                blend_mode = Sprite.BM_ADD, texture = bulletTexture2, layer_depth = 1, num_frames = 4, frame_width = 32, frame_height = 32, fps = 8.0f
            };

            var bounce_counter = 0;

            return(new Component[] {
                new Particle_Emitter()
                {
                    emit_fn = () => {
                        var theta1 = 2.0f * 3.1415f * (float)rand.NextDouble();
                        var theta2 = 2.0f * 3.1415f * (float)rand.NextDouble();
                        var radius = 13.0f * (float)rand.NextDouble();
                        var speed2 = (20.0f * (float)Math.Pow(rand.NextDouble(), 2.0f));

                        return new Component[] {
                            new Position()
                            {
                                x = pos.x + (float)Math.Cos(theta1) * radius,
                                y = pos.y + (float)Math.Sin(theta1) * radius
                            },
                            new Velocity()
                            {
                                x = velocity.x * 0.05f + (float)Math.Cos(theta2) * speed2,
                                y = velocity.y * 0.05f + (float)Math.Sin(theta2) * speed2
                            },
                            new Sprite()
                            {
                                texture = Starburst.inst().get_content <Texture2D>("particle2"),
                                color = new Color(0.9f, 0.7f, 1.0f, 1.0f),
                                scale = 0.2f + (float)rand.NextDouble() * 0.6f,
                                blend_mode = Sprite.BM_ADD,
                                layer_depth = 0.3f
                            },
                            new TTL()
                            {
                                alpha_fn = (x, max) => 1.0f - (x / max) * (x / max), max_time = 0.35f + (float)(rand.NextDouble() * 0.3f)
                            }
                            //                        new Bounding_Circle() { radius = 1.0f },
                            //                        new Mass() { mass = 0.0f }
                        };
                    },
                    interval = 0.06f,
                    num_particles_per_emit = 4
                },
                pos,
                velocity,
                angle,
                bulletSprite,
                //bulletDrawArea,
                new Bounding_Circle()
                {
                    radius = 12.0f,
                    ignore_collisions = IG_BULLET,
                    ignore_collisions2 = origin.get_component <Ship_Info>().team,
                    collision_cb = (self, other_entity) => {
                        if (bounce_counter++ > 1)
                        {
                            var p_x = self.get_component <Position>().x;
                            var p_y = self.get_component <Position>().y;
                            Fab5_Game.inst().create_entity(new Component[] {
                                new TTL {
                                    max_time = 0.01f
                                },
                                new Particle_Emitter {
                                    emit_fn = () => {
                                        var theta1 = 2.0f * 3.1415f * (float)rand.NextDouble();
                                        var theta2 = 2.0f * 3.1415f * (float)rand.NextDouble();
                                        var radius = 20.0f * (float)rand.NextDouble();
                                        var speed2 = (10.0f + 30.0f * (float)Math.Pow(rand.NextDouble(), 2.0f));

                                        return new Component[] {
                                            new Mass {
                                                drag_coeff = 0.9f
                                            },
                                            new Position {
                                                x = p_x + (float)Math.Cos(theta1) * radius,
                                                y = p_y + (float)Math.Sin(theta1) * radius
                                            },
                                            new Velocity {
                                                x = velocity.x * 0.1f + (float)Math.Cos(theta2) * speed2,
                                                y = velocity.y * 0.1f + (float)Math.Sin(theta2) * speed2
                                            },
                                            new Sprite {
                                                blend_mode = Sprite.BM_ADD,
                                                color = new Color(0.9f, 0.7f, 1.0f, 1.0f),
                                                layer_depth = 0.3f,
                                                scale = 0.4f + (float)rand.NextDouble() * 0.7f,
                                                texture = Starburst.inst().get_content <Texture2D>("particle2")
                                            },
                                            new TTL {
                                                alpha_fn = (x, max) => 1.0f - x / max,
                                                max_time = 0.3f + 1.8f * (float)(Math.Pow(rand.NextDouble(), 3.0f))
                                            }
                                        };
                                    },
                                    interval = 0.01f,
                                    num_particles_per_emit = 50
                                }
                            });
                            self.destroy();
                        }
                    }
                },
                new Mass {
                    mass = 90.0f, restitution_coeff = -1.0f, friction = 0.0f
                },
                new TTL()
                {
                    alpha_fn = (x, max) => 20.0f - 20.0f * x / max, max_time = lifeTime
                },
                new Bullet_Info()
                {
                    damage = weapon.damage, sender = origin, max_speed = speed
                },
                new Light_Source {
                    color = new Color(0.9f, 0.7f, 1.0f), size = 0.75f, intensity = 0.6f
                }
            });
        }
        private static void think(Entity self)
        {
            var data = self.get_component <Data>();

            var waypoints = (List <Entity>)data.get_data("waypoints", null);

            if (waypoints == null)
            {
                waypoints = new List <Entity>();
            }

            var w          = self.get_component <Angle>();
            var p          = self.get_component <Position>();
            var v          = self.get_component <Velocity>();
            var x          = (int)((p.x + 2048.0f) / 16.0f);
            var y          = (int)((p.y + 2048.0f) / 16.0f);
            var calc_state = (int)data.get_data("path_calc", 0);

            Input input = (Input)data.get_data("input", null);

            w.ang_vel      = 0.0f;
            v.ax           = 0.0f;
            v.ay           = 0.0f;
            input.throttle = 0.0f;

            var si = self.get_component <Ship_Info>();

            if (si.is_dead)
            {
                data.data.Remove("escape_point");
                return;
            }
            else
            {
                if (!data.data.ContainsKey("escape_point"))
                {
                    data.data["escape_point"] = new Position {
                        x = p.x, y = p.y
                    };
                }
            }

            for (int i = 0; i < si.max_powerups_inv; i++)
            {
                if (si.powerup_inv[i] != null)
                {
                    Fab5_Game.inst().message("ai_use_powerup", new { self = self, index = i });
                    break;
                }
            }

            float path_recalc_time = (float)data.get_data("path_recalc_time", 0.0f);
            //Console.WriteLine("{0}, {1}", Fab5_Game.inst().get_time(), path_recalc_time);
            var tile_map = ((Playing_State)self.state).tile_map;

            if (calc_state == 0 && Fab5_Game.inst().get_time() - path_recalc_time > 0.5f)
            {
                data.data["path_calc"] = 1;
                Position targetpos = null;
                var      escape    = false;
                if (si.energy_value > si.top_energy * 0.18f)
                {
                    var players  = new List <Entity>();
                    var powerups = Fab5_Game.inst().get_entities_fast(typeof(Powerup));


                    int num_friends_nearby = 0;
                    int num_enemies_nearby = 0;
                    foreach (var player in Fab5_Game.inst().get_entities_fast(typeof(Ship_Info)))
                    {
                        var other_si = player.get_component <Ship_Info>();
                        if (player == self)
                        {
                            continue;
                        }

                        if (other_si.is_dead)
                        {
                            continue;
                        }

                        if (((Playing_State)self.state).game_conf.mode == Game_Config.GM_TEAM_DEATHMATCH && other_si.team == si.team)
                        {
                            // following team mate behavior?
                            var other_p = player.get_component <Position>();
                            var distd   = new Vector2(p.x - other_p.x, p.y - other_p.y).Length();
                            if (distd < 600.0f)
                            {
                                num_friends_nearby++;
                            }
                        }
                        else
                        {
                            var other_p = player.get_component <Position>();
                            var distd   = new Vector2(p.x - other_p.x, p.y - other_p.y).Length();
                            if (distd < 900.0f)
                            {
                                num_enemies_nearby++;
                            }

                            if (!player.has_component <Velocity>())
                            {
                                // probably a turret
                                continue;
                            }

                            players.Add(player);
                        }
                    }

                    data.data["num_enemies"] = num_enemies_nearby;
                    data.data["num_friends"] = num_friends_nearby;

                    if (((Playing_State)self.state).game_conf.mode == Game_Config.GM_TEAM_DEATHMATCH && num_enemies_nearby > 1 + 2 * num_friends_nearby * (float)data.data["courage_fac"])
                    {
                        escape = true;
                    }
                    else
                    {
                        Entity etarget;
                        targetpos           = closest_pos(p, out etarget, (float)data.data["greed_fac"], players, powerups);
                        data.data["target"] = etarget;
                    }
                }
                else
                {
                    escape = true;
                }

                if (escape)
                {
                    targetpos = (Position)data.data["escape_point"];
                }

                if (targetpos == null)
                {
                    targetpos = new Position {
                        x = 0.0f, y = 0.0f
                    };
                }


                var tx = (int)((targetpos.x + 2048.0f) / 16.0f);
                var ty = (int)((targetpos.y + 2048.0f) / 16.0f);

                var vx    = v.x / 16.0f;
                var vy    = v.y / 16.0f;
                var speed = (float)Math.Sqrt(vx * vx + vy * vy);

                System.Threading.Tasks.Task.Factory.StartNew(() => {
                    var t = Fab5_Game.inst().get_time();
                    calc_path(data, x, y, tx, ty, tile_map, speed);
                    //Console.WriteLine("calc_path took {0:0.000} s", Fab5_Game.inst().get_time() - t);
                });
            }
            else if (calc_state == 2)
            {
                foreach (var e in waypoints)
                {
                    e.destroy();
                }
                var wps = new List <Entity>();
                data.data["waypoints"] = wps;
                foreach (var comps in (List <Component[]>)data.data["waypoints2"])
                {
                    wps.Add(Fab5_Game.inst().create_entity(comps));
                }
                data.data["path_calc"] = 0;
            }

            if (waypoints.Count == 0)
            {
                return;
            }

            bool   target_is_friend = true;
            float  fac    = 1.0f;
            Entity target = (Entity)data.get_data("target", null);

            if (target == null)
            {
                fac = 1.0f; // shouldnt really happen much
                return;
            }
            else if (target.has_component <Ship_Info>())
            {
                // player or other ai, move close but not pin-point
                fac = 5.0f;
                var tsi = target.get_component <Ship_Info>();
                target_is_friend = ((Playing_State)self.state).game_conf.mode == Game_Config.GM_TEAM_DEATHMATCH && tsi.team == si.team;
            }
            else if (target.has_component <Powerup>())
            {
                // powerup, pin-point
                if (waypoints.Count > 2)
                {
                    fac = 5.0f;
                }
                else
                {
                    fac = 0.9f;
                }
            }


            Position wp  = waypoints[0].get_component <Position>();
            Entity   wpe = null;

            var min_dist = 99999999999.0f;

            foreach (var waypoint in waypoints)
            {
                var waypointpos = waypoint.get_component <Position>();
                var wpx         = (int)((waypointpos.x + 2048.0f) / 16.0f);
                var wpy         = (int)((waypointpos.y + 2048.0f) / 16.0f);

                if (!is_open_path(x, y, wpx, wpy, tile_map))
                {
                    continue;
                }

                var dxwp = waypointpos.x - p.x;
                var dywp = waypointpos.y - p.y;

                var wpdist = dxwp * dxwp + dywp * dywp;
                if (wpdist < min_dist)
                {
                    min_dist = wpdist;
                    wp       = waypointpos;
                    wpe      = waypoint;
                }
            }

            var dx = wp.x - p.x;
            var dy = wp.y - p.y;

            var hx = (float)Math.Cos(w.angle);
            var hy = (float)Math.Sin(w.angle);

            var a = new Vector2(-dy, dx);
            var b = new Vector2(hx, hy);

            var dist = a.Length();

            a.Normalize();
            b.Normalize();

            var dot = Vector2.Dot(a, b);
            var c   = new Vector2(dx, dy);

            c.Normalize();
            var dot2 = 0.25 + 0.75f * Vector2.Dot(c, b);

            if (dot2 < 0.0f)
            {
                dot2 = -dot2 * 0.5f;
            }


            // 5 degrees off per 1000 pixels distance
            var angle_error_fac = 1.0f + dist / 1000.0f;
            var threshold       = (float)Math.Cos((90.0f - 5.0f * angle_error_fac) * 3.141592f / 180.0f);

            //Console.WriteLine(dot + ", " + threshold);

            var target_energy     = target.get_component <Ship_Info>()?.energy_value ?? 1.0f;
            var target_max_energy = target.get_component <Ship_Info>()?.top_energy ?? 1.0f;
            var inv_aggression    = 0.1f + (target_energy / target_max_energy) * (float)((int)data.get_data("num_enemies", 0)) / (float)data.data["aggression_fac"];

            if (inv_aggression > 1.0f)
            {
                inv_aggression = 1.0f;
            }
            if (si.energy_value > si.top_energy * 0.7f * inv_aggression)
            {
                data.data["shoot"] = true;
            }
            else if (si.energy_value < si.top_energy * 0.25f)
            {
                data.data["shoot"] = false;
            }

            if (waypoints.Count < 4 && !target_is_friend)
            {
                var tpos = target.get_component <Position>();
                var tvel = target.get_component <Velocity>() ?? new Velocity();

                var tx             = (int)((tpos.x + 2048.0f) / 16.0f);
                var ty             = (int)((tpos.y + 2048.0f) / 16.0f);
                var d              = new Vector2(-(tpos.y - p.y), tpos.x - p.x);
                var dist_to_target = d.Length();

                bool shoot_bomb = false;
                var  vfac       = 1.0f;

                if (si.energy_value > si.top_energy * 0.8f)
                {
                    shoot_bomb = true;
                    vfac       = 2.0f;
                }

                var tpos_x = tpos.x + (tvel.x - v.x) * (dist_to_target * 0.0015f * vfac);
                var tpos_y = tpos.y + (tvel.y - v.y) * (dist_to_target * 0.0015f * vfac);
                var e      = new Vector2(-(tpos_y - p.y), tpos_x - p.x);
                e.Normalize();
                var dot3            = Vector2.Dot(b, e);
                var aim_threshold   = (float)Math.Cos((90.0f - 1.5f) * 3.141592f / 180.0f);
                var shoot_threshold = (float)Math.Cos((90.0f - 5f) * 3.141592f / 180.0f);
                if (dot3 < -aim_threshold)
                {
                    w.ang_vel = 6.0f * Math.Abs(dot3);
                }
                else if (dot3 > aim_threshold)
                {
                    w.ang_vel = -6.0f * Math.Abs(dot3);
                }
                if (dot3 > -shoot_threshold && dot3 < shoot_threshold && is_open_path(x, y, tx, ty, tile_map))
                {
                    //Console.WriteLine("pew");
                    if ((bool)data.get_data("shoot", false))
                    {
                        if (shoot_bomb)
                        {
                            var va = new Vector2(v.x, v.y);
                            var vb = new Vector2(tpos.x - p.x, tpos.y - p.y);
                            va.Normalize();
                            vb.Normalize();
                            var vdot     = Vector2.Dot(va, vb);
                            var curspeed = (float)Math.Sqrt(v.x * v.x + v.y * v.y) * vdot;
                            if (curspeed < 150.0f)
                            {
                                //Console.WriteLine("cur speed is " + curspeed);
                                v.ax           = si.top_velocity * (float)Math.Cos(w.angle) - v.x;
                                v.ay           = si.top_velocity * (float)Math.Sin(w.angle) - v.y;
                                input.throttle = 1.0f;

                                if (curspeed < 100.0f)
                                {
                                    fire(self, si, self.get_component <Primary_Weapon>());
                                }
                            }
                            else
                            {
                                fire(self, si, self.get_component <Secondary_Weapon>());
                            }
                        }
                        else
                        {
                            fire(self, si, self.get_component <Primary_Weapon>());
                        }
                    }
                }

                var dist_mult = 1.0f / (si.energy_value / si.top_energy);
                if (dist_to_target < 180.0f * dist_mult)
                {
                    v.ax           = -si.top_velocity * (float)Math.Cos(w.angle) - v.x;
                    v.ay           = -si.top_velocity * (float)Math.Sin(w.angle) - v.y;
                    input.throttle = -1.0f;
                }
                else if (dist_to_target > 220.0f)
                {
                    v.ax           = si.top_velocity * (float)Math.Cos(w.angle) - v.x;
                    v.ay           = si.top_velocity * (float)Math.Sin(w.angle) - v.y;
                    input.throttle = 1.0f;
                }
            }
            else if (dist < 22.624f * fac * dot2)
            {
                Entity old_wp;
                do
                {
                    old_wp = waypoints[0];
                    waypoints[0].destroy();
                    waypoints.RemoveAt(0);
                } while (old_wp != wpe && waypoints.Count > 0);

                // think again!

                think(self);
            }
            else if (dot < -threshold)
            {
                w.ang_vel = 8.0f * Math.Abs(dot - 0.2f);
            }
            else if (dot > threshold)
            {
                w.ang_vel = -8.0f * Math.Abs(dot + 0.2f);
            }
            else
            {
                v.ax           = si.top_velocity * (float)Math.Cos(w.angle) - v.x;
                v.ay           = si.top_velocity * (float)Math.Sin(w.angle) - v.y;
                input.throttle = 1.0f;
            }
        }
        public static Component[] create_components()
        {
            var pos = new Position()
            {
                x = 600, y = 200
            };
            var vel = new Velocity();

            return(new Component[] {
                new Shadow {
                },
                new Particle_Emitter()
                {
                    emit_fn = () => {
                        //var speed = vel.x * vel.x + vel.y*vel.y;
                        var radius = 20.0f;
                        var theta1 = 2.0f * 3.141592f * (float)rand.NextDouble();
                        var theta2 = 2.0f * 3.141592f * (float)rand.NextDouble();
                        var ball_speed = (float)Math.Sqrt(vel.x * vel.x + vel.y * vel.y) * 0.05f;
                        var speed = 3.0f + 3.0f * (float)rand.NextDouble() + ball_speed;
                        return new Component[] {
                            new Position()
                            {
                                x = pos.x + (float)Math.Cos(theta1) * radius,
                                y = pos.y + (float)Math.Sin(theta1) * radius
                            },
                            new Velocity()
                            {
                                x = vel.x * 0.2f + (float)Math.Cos(theta2) * speed,
                                y = vel.y * 0.2f + (float)Math.Sin(theta2) * speed
                            },
                            new Sprite()
                            {
                                texture = Starburst.inst().get_content <Texture2D>("particle"),
                                color = new Color(1.0f, 0.8f, 0.3f, 1.0f),
                                scale = 1.0f + (float)rand.NextDouble() * 0.6f,
                                blend_mode = Sprite.BM_ADD,
                                layer_depth = 0.95f
                            },
                            new TTL()
                            {
                                alpha_fn = (x, max) => 1.0f - (x / max) * (x / max), max_time = 2.65f + (float)(rand.NextDouble() * 1.3f)
                            }
//                        new Bounding_Circle() { radius = 1.0f },
//                        new Mass() { mass = 0.0f }
                        };
                    },
                    interval = 0.11f,
                    num_particles_per_emit = 2
                },
                new Angle()
                {
                    angle = 0.1f * (float)rand.NextDouble(), ang_vel = 1.0f
                },
                pos,
                vel,
                new Sprite()
                {
                    texture = Starburst.inst().get_content <Texture2D>("soccerball"),
                    scale = 1.5f
                            //color = new Color(0.6f, 0.9f, 1.0f)
                },
                new Bounding_Circle()
                {
                    radius = 17.0f
                },
                new Mass()
                {
                    mass = 15.0f, restitution_coeff = 0.92f, drag_coeff = 0.1f
                },
                new Light_Source()
                {
                    color = new Color(1.0f, 0.8f, 0.3f), intensity = 0.5f
                },

                new Brain {
                    think_interval = 1.0f / 2.0f, // @To-do: Is this enough?
                    think_fn = (self) => {
                        var position = self.get_component <Position>();
                        var radius = self.get_component <Bounding_Circle>().radius;
                        var tw = 16.0f;
                        var th = 16.0f;
                        var w = 2.0f * radius;
                        var h = 2.0f * radius;
                        var left = (int)((position.x + 2048.0f - w * 0.5f) / tw);
                        var top = (int)((position.y + 2048.0f - h * 0.5f) / th);
                        var right = (int)(left + w / tw) + 1;
                        var bottom = (int)(top + h / th) + 1;

                        var tiles = ((Playing_State)self.state).tile_map.tiles;
                        var scoring_team = 0;

                        for (int i = left; i <= right; i++)
                        {
                            for (int j = top; j <= bottom; j++)
                            {
                                if (i < 0 || i > 255 || j < 0 || j > 255)
                                {
                                    continue;
                                }

                                var t = tiles[i + (j << 8)];
                                if (t == 8)
                                {
                                    scoring_team = 2;
                                    right = left - 1; // to break outer loop
                                    break;
                                }
                                else if (t == 9)
                                {
                                    scoring_team = 1;
                                    right = left - 1; // to break outer loop
                                    break;
                                }
                            }
                        }

                        if (scoring_team > 0)
                        {
                            var ball_x = position.x;
                            var ball_y = position.y;

                            foreach (var e in Starburst.inst().get_entities_fast(typeof(Ship_Info)))
                            {
                                var si = e.get_component <Ship_Info>();
                                if (si.team == scoring_team)
                                {
                                    var score = e.get_component <Score>();
                                    if (score != null)
                                    {
                                        score.score += 1500;
                                    }
                                    score.num_goals++;
                                }
                            }

                            Console.WriteLine("team {0} scored", scoring_team);
                            Fab5_Game.inst().create_entity(new Component[] {
                                new Post_Render_Hook  {
                                    render_fn = (camera, sprite_batch) => {
                                        /*if (((camera.index-1) % 2)+1 != scoring_team) {
                                         *  return;
                                         * }*/

                                        var text = string.Format("{0} TEAM SCORED A GOAL!!", scoring_team == 1 ? "RED" : "BLUE");
                                        var ts = GFX_Util.measure_string(text);

                                        // @To-do: larger text plz
                                        GFX_Util.draw_def_text(sprite_batch, text, (camera.viewport.Width - ts.X) * 0.5f, (camera.viewport.Height - ts.Y) * 0.5f);
                                    }
                                },

                                new TTL {
                                    max_time = 5.0f,
                                }
                            });

                            Fab5_Game.inst().create_entity(new Component[] {
                                new TTL {
                                    max_time = 0.1f
                                },
                                new Particle_Emitter()
                                {
                                    emit_fn = () => {
                                        var theta1 = 2.0f * 3.1415f * (float)rand.NextDouble();
                                        var theta2 = 2.0f * 3.1415f * (float)rand.NextDouble();
                                        var speed = 200.0f * (float)(0.05f + rand.NextDouble());

                                        return new Component[] {
                                            new Position()
                                            {
                                                x = ball_x + (float)Math.Cos(theta1) * radius,
                                                y = ball_y + (float)Math.Sin(theta1) * radius
                                            },
                                            new Velocity()
                                            {
                                                x = (float)Math.Cos(theta2) * speed,
                                                y = (float)Math.Sin(theta2) * speed
                                            },
                                            new Sprite()
                                            {
                                                texture = Starburst.inst().get_content <Texture2D>("particle"),
                                                color = new Color(1.0f, 0.8f, 0.3f, 1.0f),
                                                scale = 0.4f + (float)rand.NextDouble() * 0.3f,
                                                blend_mode = Sprite.BM_ADD,
                                                layer_depth = 0.3f
                                            },
                                            new TTL {
                                                alpha_fn = (x, max) => 1.0f - (x / max) * (x / max), max_time = 0.35f + (float)Math.Pow((float)(rand.NextDouble() * 0.7f), 3.0f)
                                            }
                                        };
                                    },
                                    interval = 0.05f,
                                    num_particles_per_emit = 40
                                }
                            });

                            var ball_pos = ((Playing_State)self.state).spawner.get_soccerball_spawn_pos(((Playing_State)self.state).tile_map);
                            self.get_component <Position>().x = ball_pos.x;
                            self.get_component <Position>().y = ball_pos.y;
                            self.get_component <Velocity>().x = 0.0f;
                            self.get_component <Velocity>().y = 0.0f;
                            self.get_component <Angle>().ang_vel = 3.141592f * 2.0f * -2.0f;

                            Starburst.inst().message("play_sound_asset", new { name = "sound/effects/goal" });

                            Starburst.inst().create_entity(new Component[] {
                                new TTL {
                                    max_time = 5.0f,
                                    destroy_cb = () => {
                                        Starburst.inst().message("play_sound_asset", new { name = "sound/effects/goal" });
                                    }
                                }
                            });

                            Starburst.inst().message("play_song_asset", new { name = "sound/effects/song_victory", fade_time = 14.0f });
                            //self.add_components(new TTL { max_time = 0.0f });
                        }
                    }
                }
            });
        }
        public override void init()
        {
            Gamepad_Util.vibrate(0, 0.0f, 0.0f);

            Gamepad_Util.vibrate(1, 0.0f, 0.0f);

            Gamepad_Util.vibrate(2, 0.0f, 0.0f);

            Gamepad_Util.vibrate(3, 0.0f, 0.0f);


            sprite_batch = new SpriteBatch(Starburst.inst().GraphicsDevice);

            add_subsystems(
                new Menu_Input_Handler(),
                new Sound(),
                new Particle_System(),
                new Background_Renderer(sprite_batch)
                );

            outDelay      = delay + inDuration + displayTime;
            animationTime = outDelay + outDuration;

            soundMgr = create_entity(SoundManager.create_backmusic_component());
            soundMgr.get_component <SoundLibrary>().song_index = 1;

            vp     = sprite_batch.GraphicsDevice.Viewport;
            lowRes = (vp.Height < 800 && vp.Width < 1600);

            // load textures
            background = Starburst.inst().get_content <Texture2D>("backdrops/backdrop4");
            rectBg     = new Texture2D(Fab5_Game.inst().GraphicsDevice, 1, 1);
            rectBg.SetData(new Color[] { Color.Black }, 1, 1);//Starburst.inst().get_content<Texture2D>("controller_rectangle");
            font                = Starburst.inst().get_content <SpriteFont>(!lowRes ? "sector034" : "small");
            largeFont           = Starburst.inst().get_content <SpriteFont>("large");
            controller_a_button = Starburst.inst().get_content <Texture2D>("menu/Xbox_A_white");
            keyboard_key        = Starburst.inst().get_content <Texture2D>("menu/Key");
            controller_l_stick  = Starburst.inst().get_content <Texture2D>("menu/Xbox_L_white");

            okSize = font.MeasureString(" ");

            controllerBtnSize = !lowRes ? 50 : 38; // ikon för knapp
            heightDiff        = (int)(controllerBtnSize - okSize.Y);
            yPos = (int)(vp.Height - controllerBtnSize - 15);

            for (int i = 0; i < players.Count; i++)
            {
                if (players[i].get_component <Input>() != null)
                {
                    create_entity(Player.create_components(players[i].get_component <Input>()));
                }
            }
            graphicsDevice    = sprite_batch.GraphicsDevice;
            resultsViewHeight = (int)(vp.Height * .83f);
            resultsRT         = new RenderTarget2D(graphicsDevice, vp.Width, resultsViewHeight);

            Comparer <Entity> sort_on_score = Comparer <Entity> .Create((e1, e2) => - e1.get_component <Score>().score.CompareTo(e2.get_component <Score>().score));

            if (gameConfig.mode == Game_Config.GM_TEAM_DEATHMATCH)
            {
                redTeam   = new List <Entity>();
                blueTeam  = new List <Entity>();
                redScore  = 0;
                blueScore = 0;
                redGoals  = 0;
                blueGoals = 0;

                // lägg spelare i rätt lag
                for (int p = 0; p < players.Count; p++)
                {
                    Ship_Info player_info  = players[p].get_component <Ship_Info>();
                    Score     player_score = players[p].get_component <Score>();
                    if (players[p].get_component <Velocity>() == null) // turret, lägg till poäng men inte entiteten i laget
                    {
                        if (player_info.team == 1)
                        {
                            redScore += (int)player_score.score;
                        }
                        else
                        {
                            blueScore += (int)player_score.score;
                        }
                        continue;
                    }
                    if (player_info == null)
                    {
                        continue;
                    }
                    if (player_info.team == 1)
                    {
                        redTeam.Add(players[p]);
                        redGoals  = player_score.num_goals;
                        redScore += (int)player_score.score;
                    }
                    else
                    {
                        blueTeam.Add(players[p]);
                        blueGoals  = player_score.num_goals;
                        blueScore += (int)player_score.score;
                    }
                }
                // sortera lag efter bäst score
                redTeam.Sort(sort_on_score);
                blueTeam.Sort(sort_on_score);

                redTeamHeight  = rowHeight * (redTeam.Count + 0) + vertSpacing * (redTeam.Count - 1);
                blueTeamHeight = rowHeight * (blueTeam.Count + 0) + vertSpacing * (blueTeam.Count - 1);

                totalPlayerHeight = redTeamHeight + 50 + blueTeamHeight + 50;

                totalResultsHeight = totalPlayerHeight - resultsViewHeight + 100;
                if (resultsViewHeight < redTeamHeight + 50 + blueTeamHeight + 50 + 100)
                {
                    scrollable = true;
                }
            }
            else
            {
                bestScore   = 0;
                bestPlayers = new List <Entity>();
                List <Entity> checkedPlayers = new List <Entity>();
                // ta bort turrets (ska inte finnas några här, men tas bort utifall att)
                for (int i = 0; i < players.Count; i++)
                {
                    if (players[i].get_component <Velocity>() != null)
                    {
                        checkedPlayers.Add(players[i]);
                    }
                }
                players = checkedPlayers;
                for (int i = 0; i < players.Count; i++)
                {
                    Score     player_score = players[i].get_component <Score>();
                    Ship_Info player_info  = players[i].get_component <Ship_Info>();

                    if (player_score == null)
                    {
                        continue;
                    }

                    if (player_score.score > bestScore)
                    {
                        bestPlayers.Clear();
                        bestScore = (int)player_score.score;
                        bestPlayers.Add(players[i]);
                    }
                    else if (player_score.score == bestScore)
                    {
                        bestPlayers.Add(players[i]);
                    }
                }
                players.Sort(sort_on_score);

                totalPlayerHeight  = rowHeight * (players.Count + 0) + vertSpacing * (players.Count - 1);
                totalResultsHeight = totalPlayerHeight + 50 - resultsViewHeight;
                if (resultsViewHeight < totalPlayerHeight + 50)
                {
                    scrollable = true;
                }
            }


            vertPadding = 10;
            horPadding  = 20;
            horSpacing  = 20;
            nameWidth   = 300;

            killsHeader  = "Kills";
            deathsHeader = "Deaths";
            scoreHeader  = "Score";
            handlerSize  = new Vector2(80, 64);
            killsSize    = font.MeasureString(killsHeader);
            deathsSize   = font.MeasureString(deathsHeader);
            scoreSize    = font.MeasureString("999999");

            iconSizeX       = 42;
            iconSizeY       = 30;
            iconSizeX       = 63;
            iconSizeY       = 45;
            totalScoreWidth = (int)(iconSizeX + horSpacing + nameWidth + horSpacing + killsSize.X + horSpacing + deathsSize.X + horSpacing + scoreSize.X);
            iconX           = (int)(vp.Width * .5f - totalScoreWidth * .5f);
            nameX           = iconX + iconSizeX + horSpacing;
            killsX          = nameX + nameWidth + horSpacing;
            deathsX         = (int)(killsX + killsSize.X + horSpacing);
            scoreX          = (int)(deathsX + deathsSize.X + horSpacing);

            textOffset = (int)((rowHeight - killsSize.Y) * .5f);
        }
        private static void calc_path(Data data, int x, int y, int tx, int ty, Tile_Map tile_map, float speed)
        {
            List <Component[]> waypoints = new List <Component[]>();

            var path = find_path(x, y, tx, ty, tile_map);

            if (path != null)
            {
                int  counter = (int)(-1 * speed * 0.25f);
                bool first   = true;
                foreach (var node in path)
                {
                    if (first && path.Count < 3)
                    {
                        first = false;
                        var dx = ((float)rand.NextDouble() - 0.5f) * 12.0f;
                        var dy = ((float)rand.NextDouble() - 0.5f) * 12.0f;
                        waypoints.Add(create_waypoint(get_x(node) * 16.0f - 2048.0f + 8.0f + dx, get_y(node) * 16.0f - 2048.0f + 8.0f + dy));
                    }
                    else if (counter++ == 2)
                    {
                        var dx = ((float)rand.NextDouble() - 0.5f) * 12.0f;
                        var dy = ((float)rand.NextDouble() - 0.5f) * 12.0f;
                        waypoints.Add(create_waypoint(get_x(node) * 16.0f - 2048.0f + 8.0f + dx, get_y(node) * 16.0f - 2048.0f + 8.0f + dy));
                        if (waypoints.Count > 10)
                        {
                            break;
                        }
                        counter = 0;
                    }
                }

                var dxx = ((float)rand.NextDouble() - 0.5f) * 8.0f;
                var dyy = ((float)rand.NextDouble() - 0.5f) * 8.0f;
                waypoints.Add(create_waypoint(tx * 16.0f - 2048.0f + 8.0f + dxx, ty * 16.0f - 2048.0f + 8.0f + dyy));
            }
            else
            {
                Console.WriteLine("could not solve path from {0}:{1} to {2}:{3}", x, y, tx, ty);
            }


            // optimize path
            while (waypoints.Count > -2)
            {
                bool all_checked = true;

                for (int i = 0; i < waypoints.Count - 1; i++)
                {
                    var wp0 = (Position)waypoints[i][0];
                    var wp1 = (Position)waypoints[i + 1][0];

                    var v0 = new Vector2(wp1.x - wp0.x, wp1.y - wp0.y);
                    v0.Normalize();

                    var sum_angle = 0.0f;
                    int last_ok   = -1;
                    for (int j = (i + 1); j < waypoints.Count - 1; j++)
                    {
                        var wp2 = (Position)waypoints[j][0];
                        var wp3 = (Position)waypoints[j + 1][0];

                        var v1 = new Vector2(wp3.x - wp2.x, wp3.y - wp2.y);
                        v1 = new Vector2(-v1.Y, v1.X);
                        v1.Normalize();

                        var dot = Vector2.Dot(v0, v1);
                        sum_angle += (float)Math.Abs(dot);
                        if (sum_angle < (float)Math.Cos(65.0f * 3.141592f / 180.0f))
                        {
                            last_ok = j;
                        }
                        else
                        {
                            break;
                        }

                        v0 = new Vector2(v1.Y, -v1.X);
                    }

                    if (last_ok != -1)
                    {
                        all_checked = false;

                        int num = last_ok - (i + 1) + 1;
                        for (int n = 0; n < num; n++)
                        {
                            waypoints.RemoveAt(i + 1);
                        }

                        break;
                    }
                }

                if (all_checked)
                {
                    break;
                }
            }


            data.data["path_recalc_time"] = Fab5_Game.inst().get_time();
            data.data["path_calc"]        = 2;
            data.data["waypoints2"]       = waypoints;
        }