public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Transform     transform = entity.GetOrCreate <Transform>("Transform");
            PhysicsBlock  physics   = entity.GetOrCreate <PhysicsBlock>("Physics");
            ModelInstance model     = entity.GetOrCreate <ModelInstance>("Model");

            physics.Add(new TwoWayBinding <Matrix>(transform.Matrix, physics.Transform));

            SceneryBlock sceneryBlock = entity.GetOrCreate <SceneryBlock>("SceneryBlock");

            physics.Add(new Binding <Vector3, float>(physics.Size, x => new Vector3(x), sceneryBlock.Scale));
            model.Add(new Binding <Matrix>(model.Transform, () => Matrix.CreateScale(sceneryBlock.Scale) * transform.Matrix, transform.Matrix, sceneryBlock.Scale));

            this.SetMain(entity, main);

            entity.Add("IsAffectedByGravity", physics.IsAffectedByGravity);
            sceneryBlock.EditorProperties();

            if (!main.EditorEnabled && !physics.IsAffectedByGravity &&
                (sceneryBlock.Type.Value == Voxel.t.WhitePermanent || sceneryBlock.Type.Value == Voxel.t.White))
            {
                Sound.AttachTracker(entity);
                AkSoundEngine.PostEvent(AK.EVENTS.PLAY_WHITE_LIGHT, entity);
                SoundKiller.Add(entity, AK.EVENTS.STOP_WHITE_LIGHT);
                physics.Add(new CommandBinding <Collidable, ContactCollection>(physics.Collided, delegate(Collidable other, ContactCollection contacts)
                {
                    float impulse = contacts.Max(x => x.NormalImpulse);
                    if (impulse > 0.2f)
                    {
                        AkSoundEngine.PostEvent(AK.EVENTS.PLAY_WHITE_LIGHT_HIT, entity);
                    }
                }));
            }
        }
Esempio n. 2
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            entity.CannotSuspendByDistance = true;
            Transform transform    = entity.GetOrCreate <Transform>("Transform");
            Transform mapTransform = entity.GetOrCreate <Transform>("MapTransform");

            mapTransform.Selectable.Value = false;
            StaticSlider slider = entity.GetOrCreate <StaticSlider>("StaticSlider");

            Factory.Get <VoxelFactory>().InternalBind(entity, main, creating, mapTransform);
            slider.Add(new TwoWayBinding <Matrix>(mapTransform.Matrix, slider.Transform));
            slider.Add(new Binding <Matrix>(slider.EditorTransform, transform.Matrix));

            Voxel voxel = entity.Get <Voxel>();

            slider.Add(new Binding <Vector3>(voxel.LinearVelocity, slider.LinearVelocity));

            Sound.AttachTracker(entity, voxel.Transform);
            SoundKiller.Add(entity, AK.EVENTS.STOP_ALL_OBJECT);

            if (main.EditorEnabled)
            {
                entity.Add(new Binding <Matrix>(entity.GetOrCreate <SliderCommon>("SliderCommon").OriginalTransform, voxel.Transform));
            }

            entity.Add("Forward", slider.Forward);
            entity.Add("Backward", slider.Backward);
            entity.Add("OnHitMax", slider.OnHitMax);
            entity.Add("OnHitMin", slider.OnHitMin);

            entity.Add("Direction", slider.Direction);
            entity.Add("Minimum", slider.Minimum);
            entity.Add("Maximum", slider.Maximum);
            entity.Add("Speed", slider.Speed);
            entity.Add("Goal", slider.Goal);
            entity.Add("StartAtMinimum", slider.StartAtMinimum);
            entity.Add("EnablePhysics", voxel.EnablePhysics);
            entity.Add("Position", slider.Position, new PropertyEntry.EditorData {
                Readonly = true
            });
            entity.Add("MovementLoop", slider.MovementLoop, new PropertyEntry.EditorData {
                Options = WwisePicker.Get(main)
            });
            entity.Add("MovementStop", slider.MovementStop, new PropertyEntry.EditorData {
                Options = WwisePicker.Get(main)
            });

            entity.Add("UVRotation", voxel.UVRotation);
            entity.Add("UVOffset", voxel.UVOffset);

            if (main.EditorEnabled)
            {
                this.attachEditorComponents(entity, main);
            }
        }
Esempio n. 3
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Transform mapTransform = entity.GetOrCreate <Transform>("MapTransform");

            mapTransform.Selectable.Value = false;
            Transform transform = entity.GetOrCreate <Transform>("Transform");
            VoxelFill voxelFill = entity.GetOrCreate <VoxelFill>("VoxelFill");

            voxelFill.Add(new CommandBinding(voxelFill.Delete, entity.Delete));

            Sound.AttachTracker(entity, voxelFill.RumblePosition);

            this.InternalBind(entity, main, creating, mapTransform, true);

            if (main.EditorEnabled)
            {
                Voxel voxel = entity.Get <Voxel>();

                Action refreshMapTransform = delegate()
                {
                    Entity parent = voxelFill.Target.Value.Target;
                    if (parent != null && parent.Active)
                    {
                        Voxel staticMap = parent.Get <Voxel>();
                        if (staticMap == null)
                        {
                            mapTransform.Matrix.Value = transform.Matrix;
                        }
                        else
                        {
                            mapTransform.Position.Value = staticMap.GetAbsolutePosition(staticMap.GetRelativePosition(staticMap.GetCoordinate(transform.Matrix.Value.Translation)) - new Vector3(0.5f) + staticMap.Offset + voxel.Offset.Value);
                            Matrix parentOrientation = staticMap.Transform;
                            parentOrientation.Translation = Vector3.Zero;
                            mapTransform.Quaternion.Value = Quaternion.CreateFromRotationMatrix(parentOrientation);
                        }
                    }
                    else
                    {
                        mapTransform.Matrix.Value = transform.Matrix;
                    }
                };

                entity.Add(new NotifyBinding(refreshMapTransform, transform.Matrix, voxel.Offset, voxelFill.Target));
                refreshMapTransform();
            }

            entity.Add("Enabled", voxelFill.Enabled);
            entity.Add("Enable", voxelFill.Enable);
            entity.Add("Disable", voxelFill.Disable);
            entity.Add("IntervalMultiplier", voxelFill.IntervalMultiplier);
            entity.Add("BlockLifetime", voxelFill.BlockLifetime);
        }
Esempio n. 4
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Transform     transform = entity.GetOrCreate <Transform>("Transform");
            PlayerTrigger trigger   = entity.GetOrCreate <PlayerTrigger>("PlayerTrigger");

            trigger.Serialize = false;

            VoxelAttachable attachable  = VoxelAttachable.MakeAttachable(entity, main);
            Collectible     collectible = entity.GetOrCreate <Collectible>("Collectible");

            trigger.Radius.Value = 3;
            trigger.Add(new Binding <Vector3>(trigger.Position, transform.Position));
            trigger.Add(new Binding <bool>(trigger.Enabled, x => !x, collectible.PickedUp));

            collectible.Add(new CommandBinding(trigger.PlayerEntered, collectible.PlayerTouched));

            Sound.AttachTracker(entity, trigger.Position);

            PointLight light = entity.Create <PointLight>();

            light.Serialize         = false;
            light.Attenuation.Value = 10.0f;
            light.Color.Value       = new Vector3(1.25f, 1.75f, 2.0f);
            light.Add(new Binding <Vector3>(light.Position, transform.Position));
            light.Add(new Binding <bool>(light.Enabled, x => !x, collectible.PickedUp));

            ParticleEmitter distortionEmitter = entity.GetOrCreate <ParticleEmitter>("DistortionEmitter");

            distortionEmitter.Serialize = false;
            distortionEmitter.Add(new Binding <Vector3>(distortionEmitter.Position, trigger.Position));
            distortionEmitter.ParticleType.Value       = "Distortion";
            distortionEmitter.ParticlesPerSecond.Value = 4;
            distortionEmitter.Jitter.Value             = new Vector3(0.5f);
            distortionEmitter.Add(new Binding <bool>(distortionEmitter.Enabled, x => !x, collectible.PickedUp));

            Model model = entity.GetOrCreate <Model>("Model");

            model.Filename.Value = "Models\\sphere";
            model.Serialize      = false;
            model.Scale.Value    = new Vector3(0.5f);
            model.Add(new Binding <Matrix>(model.Transform, transform.Matrix));
            model.Add(new Binding <bool>(model.Enabled, x => !x, collectible.PickedUp));

            this.SetMain(entity, main);

            attachable.EditorProperties();
            entity.Add("Collected", collectible.PlayerTouched);
        }
Esempio n. 5
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Slider slider = entity.GetOrCreate <Slider>("Slider");

            JointFactory.Bind(entity, main, slider.CreateJoint, false, creating);

            Components.Joint joint = entity.GetOrCreate <Components.Joint>("Joint");
            slider.Add(new Binding <Direction>(slider.Direction, joint.Direction));

            DynamicVoxel voxel = entity.Get <DynamicVoxel>();

            voxel.KineticFriction.Value = voxel.StaticFriction.Value = 0;
            Sound.AttachTracker(entity, voxel.Transform);
            SoundKiller.Add(entity, AK.EVENTS.STOP_ALL_OBJECT);

            if (main.EditorEnabled)
            {
                entity.Add(new Binding <Matrix>(entity.GetOrCreate <SliderCommon>("SliderCommon").OriginalTransform, voxel.Transform));
            }

            entity.Add("Forward", slider.Forward);
            entity.Add("Backward", slider.Backward);
            entity.Add("OnHitMax", slider.OnHitMax);
            entity.Add("OnHitMin", slider.OnHitMin);

            entity.Add("MovementLoop", slider.MovementLoop, new PropertyEntry.EditorData {
                Options = WwisePicker.Get(main)
            });
            entity.Add("MovementStop", slider.MovementStop, new PropertyEntry.EditorData {
                Options = WwisePicker.Get(main)
            });
            entity.Add("Direction", joint.Direction);
            entity.Add("Minimum", slider.Minimum);
            entity.Add("Maximum", slider.Maximum);
            entity.Add("Locked", slider.Locked);
            entity.Add("Speed", slider.Speed);
            entity.Add("Goal", slider.Goal);
            entity.Add("Servo", slider.Servo);
            entity.Add("StartAtMinimum", slider.StartAtMinimum);
            entity.Add("MaxForce", slider.MaxForce);

            entity.Add("UVRotation", voxel.UVRotation);
            entity.Add("UVOffset", voxel.UVOffset);
            entity.Add("CannotSuspendByDistance", voxel.CannotSuspendByDistance);
        }
Esempio n. 6
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Transform transform = entity.GetOrCreate <Transform>("Transform");

            this.SetMain(entity, main);

            VoxelAttachable attachable = VoxelAttachable.MakeAttachable(entity, main);

            attachable.Enabled.Value = true;

            entity.Add("AttachOffset", attachable.Offset);

            if (!main.EditorEnabled)
            {
                Property <Vector3> soundPosition = new Property <Vector3>();
                VoxelAttachable.BindTarget(entity, soundPosition);
                Sound.AttachTracker(entity, soundPosition);
                AkSoundEngine.PostEvent(AK.EVENTS.PLAY_WHITE_LIGHT, entity);
                SoundKiller.Add(entity, AK.EVENTS.STOP_WHITE_LIGHT);
            }
        }
Esempio n. 7
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            BlockCloud blockCloud = entity.GetOrCreate <BlockCloud>("BlockCloud");

            blockCloud.Add(new CommandBinding(blockCloud.Delete, entity.Delete));
            blockCloud.Add(new CommandBinding <Collidable, ContactCollection>(blockCloud.Collided, delegate(Collidable other, ContactCollection contacts)
            {
                if (other.Tag != null && other.Tag.GetType() == typeof(Character))
                {
                    // Damage the player
                    Entity p = PlayerFactory.Instance;
                    if (p != null && p.Active)
                    {
                        p.Get <Agent>().Damage.Execute(0.1f);
                    }
                }
            }));
            blockCloud.Type.Value = Voxel.t.Black;

            Transform transform = entity.GetOrCreate <Transform>("Transform");

            Sound.AttachTracker(entity);

            AI ai = entity.GetOrCreate <AI>("AI");

            if (!main.EditorEnabled)
            {
                entity.Add(new PostInitialization(delegate()
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_EVIL_CUBES, entity);
                    AkSoundEngine.PostEvent(ai.CurrentState == "Chase" ? AK.EVENTS.EVIL_CUBES_CHASE : AK.EVENTS.EVIL_CUBES_IDLE, entity);
                }));

                SoundKiller.Add(entity, AK.EVENTS.STOP_EVIL_CUBES);
            }

            Agent agent = entity.GetOrCreate <Agent>();

            agent.Add(new Binding <Vector3>(agent.Position, transform.Position));

            RaycastAI raycastAI = entity.GetOrCreate <RaycastAI>("RaycastAI");

            raycastAI.BlendTime.Value = 1.0f;
            raycastAI.Add(new TwoWayBinding <Vector3>(transform.Position, raycastAI.Position));
            raycastAI.Add(new Binding <Quaternion>(transform.Quaternion, raycastAI.Orientation));

            RaycastAIMovement movement = entity.GetOrCreate <RaycastAIMovement>("Movement");

            blockCloud.Add(new Binding <Vector3>(blockCloud.Position, transform.Position));

            AI.Task checkOperationalRadius = new AI.Task
            {
                Interval = 2.0f,
                Action   = delegate()
                {
                    bool shouldBeActive = (transform.Position.Value - main.Camera.Position).Length() < movement.OperationalRadius;
                    if (shouldBeActive && ai.CurrentState == "Suspended")
                    {
                        ai.CurrentState.Value = "Idle";
                    }
                    else if (!shouldBeActive && ai.CurrentState != "Suspended")
                    {
                        ai.CurrentState.Value = "Suspended";
                    }
                },
            };

            AI.Task updatePosition = new AI.Task
            {
                Action = delegate()
                {
                    raycastAI.Update();
                },
            };

            ai.Add(new AI.AIState
            {
                Name  = "Suspended",
                Tasks = new[] { checkOperationalRadius, },
            });

            const float sightDistance   = 25.0f;
            const float hearingDistance = 0.0f;

            ai.Add(new AI.AIState
            {
                Name  = "Idle",
                Tasks = new[]
                {
                    checkOperationalRadius,
                    updatePosition,
                    new AI.Task
                    {
                        Interval = 1.0f,
                        Action   = delegate()
                        {
                            raycastAI.Move(new Vector3(((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f));
                        }
                    },
                    new AI.Task
                    {
                        Interval = 1.0f,
                        Action   = delegate()
                        {
                            Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player");
                            if (a != null)
                            {
                                ai.CurrentState.Value = "Alert";
                            }
                        },
                    },
                },
            });

            ai.Add(new AI.AIState
            {
                Name  = "Alert",
                Tasks = new[]
                {
                    checkOperationalRadius,
                    updatePosition,
                    new AI.Task
                    {
                        Interval = 1.0f,
                        Action   = delegate()
                        {
                            if (ai.TimeInCurrentState > 3.0f)
                            {
                                ai.CurrentState.Value = "Idle";
                            }
                            else
                            {
                                Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player");
                                if (a != null)
                                {
                                    ai.TargetAgent.Value  = a.Entity;
                                    ai.CurrentState.Value = "Chase";
                                }
                            }
                        },
                    },
                },
            });

            AI.Task checkTargetAgent = new AI.Task
            {
                Action = delegate()
                {
                    Entity target = ai.TargetAgent.Value.Target;
                    if (target == null || !target.Active || (target.Get <Transform>().Position.Value - transform.Position.Value).Length() > sightDistance * 1.25f)
                    {
                        ai.TargetAgent.Value  = null;
                        ai.CurrentState.Value = "Alert";
                    }
                },
            };

            Action findNextPosition = delegate()
            {
                movement.LastPosition.Value = transform.Position.Value;
                float   radius = 5.0f;
                Vector3 center = ai.TargetAgent.Value.Target.Get <Transform>().Position;
                Vector3 candidate;
                do
                {
                    candidate = center + new Vector3((float)this.random.NextDouble() - 0.5f, (float)this.random.NextDouble(), (float)this.random.NextDouble() - 0.5f) * radius;
                    radius   += 1.0f;
                }while (!RaycastAI.DefaultPositionFilter(candidate));

                Vector3     toCandidate         = candidate - movement.LastPosition;
                float       distance            = toCandidate.Length();
                const float maxMovementDistance = 9.0f;
                if (distance > maxMovementDistance)
                {
                    toCandidate *= maxMovementDistance / distance;
                }

                movement.NextPosition.Value  = movement.LastPosition.Value + toCandidate;
                movement.PositionBlend.Value = 0.0f;
            };

            // Chase AI state

            ai.Add(new AI.AIState
            {
                Name  = "Chase",
                Enter = delegate(AI.AIState previous)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.EVIL_CUBES_CHASE, entity);
                    findNextPosition();
                },
                Exit = delegate(AI.AIState next)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.EVIL_CUBES_IDLE, entity);
                },
                Tasks = new[]
                {
                    checkOperationalRadius,
                    checkTargetAgent,
                    new AI.Task
                    {
                        Action = delegate()
                        {
                            if (ai.TimeInCurrentState.Value > 15.0f)
                            {
                                Entity voxel = raycastAI.Voxel.Value.Target;
                                if (voxel != null && voxel.Active)
                                {
                                    raycastAI.Coord.Value = raycastAI.LastCoord.Value = voxel.Get <Voxel>().GetCoordinate(transform.Position);
                                }
                                raycastAI.Move(new Vector3(((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f));
                                ai.CurrentState.Value = "Idle";
                            }
                            else
                            {
                                movement.PositionBlend.Value += (main.ElapsedTime.Value / 1.0f);
                                if (movement.PositionBlend > 1.0f)
                                {
                                    findNextPosition();
                                }
                                transform.Position.Value = Vector3.Lerp(movement.LastPosition, movement.NextPosition, movement.PositionBlend);
                            }
                        }
                    },
                },
            });

            this.SetMain(entity, main);
        }
Esempio n. 8
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Transform     transform = entity.GetOrCreate <Transform>("Transform");
            PlayerTrigger trigger   = entity.GetOrCreate <PlayerTrigger>("PlayerTrigger");

            VoxelAttachable attachable = VoxelAttachable.MakeAttachable(entity, main);

            attachable.Enabled.Value = true;

            this.SetMain(entity, main);

            VoxelAttachable.BindTarget(entity, trigger.Position);

            PointLight light = entity.GetOrCreate <PointLight>();

            light.Add(new Binding <Vector3>(light.Position, trigger.Position));
            light.Color.Value = new Vector3(1.0f, 0.5f, 1.7f);

            Property <float> lightBaseRadius = new Property <float> {
                Value = 10.0f
            };

            Updater updater = new Updater
                              (
                delegate(float dt)
            {
                light.Attenuation.Value = lightBaseRadius.Value * (1.0f + (((float)this.random.NextDouble() - 0.5f) * 0.1f));
            }
                              );

            updater.EnabledInEditMode = true;
            entity.Add(updater);

            SignalTower tower = entity.GetOrCreate <SignalTower>("SignalTower");

            Animation enterAnimation = null;

            trigger.Add(new CommandBinding(trigger.PlayerEntered, delegate()
            {
                if (!string.IsNullOrEmpty(tower.Initial) && (enterAnimation == null || !enterAnimation.Active))
                {
                    enterAnimation = new Animation
                                     (
                        new Animation.FloatMoveTo(lightBaseRadius, 20.0f, 0.25f),
                        new Animation.FloatMoveTo(lightBaseRadius, 10.0f, 0.5f)
                                     );
                    entity.Add(enterAnimation);
                }
            }));

            tower.Add(new CommandBinding(trigger.PlayerEntered, tower.PlayerEnteredRange));
            tower.Add(new CommandBinding(trigger.PlayerExited, tower.PlayerExitedRange));
            tower.Add(new Binding <Entity.Handle>(tower.Player, trigger.Player));

            Sound.AttachTracker(entity, trigger.Position);

            ParticleEmitter distortionEmitter = entity.GetOrCreate <ParticleEmitter>("DistortionEmitter");

            distortionEmitter.Serialize = false;
            distortionEmitter.Add(new Binding <Vector3>(distortionEmitter.Position, trigger.Position));
            distortionEmitter.ParticleType.Value       = "Distortion";
            distortionEmitter.ParticlesPerSecond.Value = 4;
            distortionEmitter.Jitter.Value             = new Vector3(0.5f);

            ParticleEmitter purpleEmitter = entity.GetOrCreate <ParticleEmitter>("PurpleEmitter");

            purpleEmitter.Serialize = false;
            purpleEmitter.Add(new Binding <Vector3>(purpleEmitter.Position, trigger.Position));
            purpleEmitter.ParticleType.Value       = "Purple";
            purpleEmitter.ParticlesPerSecond.Value = 30;
            purpleEmitter.Jitter.Value             = new Vector3(0.5f);

            entity.Add("AttachOffset", attachable.Offset);
            trigger.EditorProperties();
            entity.Add("Initial", tower.Initial);
        }
Esempio n. 9
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            if (ParticleSystem.Get(main, "SnakeSparks") == null)
            {
                ParticleSystem.Add(main, "SnakeSparks",
                                   new ParticleSystem.ParticleSettings
                {
                    TextureName           = "Particles\\splash",
                    MaxParticles          = 1000,
                    Duration              = TimeSpan.FromSeconds(1.0f),
                    MinHorizontalVelocity = -7.0f,
                    MaxHorizontalVelocity = 7.0f,
                    MinVerticalVelocity   = 0.0f,
                    MaxVerticalVelocity   = 7.0f,
                    Gravity        = new Vector3(0.0f, -10.0f, 0.0f),
                    MinRotateSpeed = -2.0f,
                    MaxRotateSpeed = 2.0f,
                    MinStartSize   = 0.3f,
                    MaxStartSize   = 0.7f,
                    MinEndSize     = 0.0f,
                    MaxEndSize     = 0.0f,
                    BlendState     = Microsoft.Xna.Framework.Graphics.BlendState.AlphaBlend,
                    MinColor       = new Vector4(2.0f, 2.0f, 2.0f, 1.0f),
                    MaxColor       = new Vector4(2.0f, 2.0f, 2.0f, 1.0f),
                });
                ParticleSystem.Add(main, "SnakeSparksRed",
                                   new ParticleSystem.ParticleSettings
                {
                    TextureName           = "Particles\\splash",
                    MaxParticles          = 1000,
                    Duration              = TimeSpan.FromSeconds(1.0f),
                    MinHorizontalVelocity = -7.0f,
                    MaxHorizontalVelocity = 7.0f,
                    MinVerticalVelocity   = 0.0f,
                    MaxVerticalVelocity   = 7.0f,
                    Gravity        = new Vector3(0.0f, -10.0f, 0.0f),
                    MinRotateSpeed = -2.0f,
                    MaxRotateSpeed = 2.0f,
                    MinStartSize   = 0.3f,
                    MaxStartSize   = 0.7f,
                    MinEndSize     = 0.0f,
                    MaxEndSize     = 0.0f,
                    BlendState     = Microsoft.Xna.Framework.Graphics.BlendState.AlphaBlend,
                    MinColor       = new Vector4(1.4f, 0.8f, 0.7f, 1.0f),
                    MaxColor       = new Vector4(1.4f, 0.8f, 0.7f, 1.0f),
                });
                ParticleSystem.Add(main, "SnakeSparksYellow",
                                   new ParticleSystem.ParticleSettings
                {
                    TextureName           = "Particles\\splash",
                    MaxParticles          = 1000,
                    Duration              = TimeSpan.FromSeconds(1.0f),
                    MinHorizontalVelocity = -7.0f,
                    MaxHorizontalVelocity = 7.0f,
                    MinVerticalVelocity   = 0.0f,
                    MaxVerticalVelocity   = 7.0f,
                    Gravity        = new Vector3(0.0f, -10.0f, 0.0f),
                    MinRotateSpeed = -2.0f,
                    MaxRotateSpeed = 2.0f,
                    MinStartSize   = 0.3f,
                    MaxStartSize   = 0.7f,
                    MinEndSize     = 0.0f,
                    MaxEndSize     = 0.0f,
                    BlendState     = Microsoft.Xna.Framework.Graphics.BlendState.AlphaBlend,
                    MinColor       = new Vector4(1.4f, 1.4f, 0.7f, 1.0f),
                    MaxColor       = new Vector4(1.4f, 1.4f, 0.7f, 1.0f),
                });
            }

            Snake snake = entity.GetOrCreate <Snake>("Snake");

            entity.CannotSuspendByDistance = true;
            Transform transform = entity.GetOrCreate <Transform>("Transform");

            AI ai = entity.GetOrCreate <AI>("AI");

            Agent agent = entity.GetOrCreate <Agent>("Agent");

            const float defaultSpeed    = 5.0f;
            const float chaseSpeed      = 18.0f;
            const float closeChaseSpeed = 12.0f;
            const float crushSpeed      = 125.0f;

            VoxelChaseAI chase = entity.GetOrCreate <VoxelChaseAI>("VoxelChaseAI");

            chase.Add(new TwoWayBinding <Vector3>(transform.Position, chase.Position));
            chase.Speed.Value             = defaultSpeed;
            chase.EnablePathfinding.Value = ai.CurrentState.Value == "Chase";
            chase.Filter = delegate(Voxel.State state)
            {
                if (state == Voxel.States.Infected || state == Voxel.States.Neutral || state == Voxel.States.Hard || state == Voxel.States.HardInfected)
                {
                    return(true);
                }
                return(false);
            };
            entity.Add(new CommandBinding(chase.Delete, entity.Delete));

            PointLight positionLight = null;

            if (!main.EditorEnabled)
            {
                positionLight                   = new PointLight();
                positionLight.Serialize         = false;
                positionLight.Color.Value       = new Vector3(1.5f, 0.5f, 0.5f);
                positionLight.Attenuation.Value = 20.0f;
                positionLight.Add(new Binding <bool, string>(positionLight.Enabled, x => x != "Suspended", ai.CurrentState));
                positionLight.Add(new Binding <Vector3, string>(positionLight.Color, delegate(string state)
                {
                    switch (state)
                    {
                    case "Chase":
                    case "Crush":
                        return(new Vector3(1.5f, 0.5f, 0.5f));

                    case "Alert":
                        return(new Vector3(1.5f, 1.5f, 0.5f));

                    default:
                        return(new Vector3(1.0f, 1.0f, 1.0f));
                    }
                }, ai.CurrentState));
                entity.Add("PositionLight", positionLight);
                ParticleEmitter emitter = entity.GetOrCreate <ParticleEmitter>("Particles");
                emitter.Serialize = false;
                emitter.ParticlesPerSecond.Value = 100;
                emitter.Add(new Binding <string>(emitter.ParticleType, delegate(string state)
                {
                    switch (state)
                    {
                    case "Chase":
                    case "Crush":
                        return("SnakeSparksRed");

                    case "Alert":
                        return("SnakeSparksYellow");

                    default:
                        return("SnakeSparks");
                    }
                }, ai.CurrentState));
                emitter.Add(new Binding <Vector3>(emitter.Position, transform.Position));
                emitter.Add(new Binding <bool, string>(emitter.Enabled, x => x != "Suspended", ai.CurrentState));

                positionLight.Add(new Binding <Vector3>(positionLight.Position, transform.Position));
                emitter.Add(new Binding <Vector3>(emitter.Position, transform.Position));
                agent.Add(new Binding <Vector3>(agent.Position, transform.Position));
                Sound.AttachTracker(entity);
            }

            AI.Task checkMap = new AI.Task
            {
                Action = delegate()
                {
                    if (chase.Voxel.Value.Target == null || !chase.Voxel.Value.Target.Active)
                    {
                        entity.Delete.Execute();
                    }
                },
            };

            AI.Task checkOperationalRadius = new AI.Task
            {
                Interval = 2.0f,
                Action   = delegate()
                {
                    bool shouldBeActive = (transform.Position.Value - main.Camera.Position).Length() < snake.OperationalRadius;
                    if (shouldBeActive && ai.CurrentState == "Suspended")
                    {
                        ai.CurrentState.Value = "Idle";
                    }
                    else if (!shouldBeActive && ai.CurrentState != "Suspended")
                    {
                        ai.CurrentState.Value = "Suspended";
                    }
                },
            };

            AI.Task checkTargetAgent = new AI.Task
            {
                Action = delegate()
                {
                    Entity target = ai.TargetAgent.Value.Target;
                    if (target == null || !target.Active)
                    {
                        ai.TargetAgent.Value  = null;
                        ai.CurrentState.Value = "Idle";
                    }
                },
            };

            Func <Voxel, Direction> randomValidDirection = delegate(Voxel m)
            {
                Voxel.Coord c    = chase.Coord;
                Direction[] dirs = new Direction[6];
                Array.Copy(DirectionExtensions.Directions, dirs, 6);

                // Shuffle directions
                int i = 5;
                while (i > 0)
                {
                    int       k    = this.random.Next(i);
                    Direction temp = dirs[i];
                    dirs[i] = dirs[k];
                    dirs[k] = temp;
                    i--;
                }

                foreach (Direction dir in dirs)
                {
                    if (chase.Filter(m[c.Move(dir)]))
                    {
                        return(dir);
                    }
                }
                return(Direction.None);
            };

            Direction currentDir = Direction.None;

            chase.Add(new CommandBinding <Voxel, Voxel.Coord>(chase.Moved, delegate(Voxel m, Voxel.Coord c)
            {
                if (chase.Active)
                {
                    string currentState = ai.CurrentState.Value;
                    Voxel.t id          = m[c].ID;
                    if (id == Voxel.t.Hard)
                    {
                        m.Empty(c);
                        m.Fill(c, Voxel.States.HardInfected);
                        m.Regenerate();
                    }
                    else if (id == Voxel.t.Neutral)
                    {
                        m.Empty(c);
                        m.Fill(c, Voxel.States.Infected);
                        m.Regenerate();
                    }
                    else if (id == Voxel.t.Empty)
                    {
                        m.Fill(c, Voxel.States.Infected);
                        m.Regenerate();
                    }

                    if (currentState == "Idle")
                    {
                        if (currentDir == Direction.None || !chase.Filter(m[chase.Coord.Value.Move(currentDir)]) || this.random.Next(8) == 0)
                        {
                            currentDir = randomValidDirection(m);
                        }
                        chase.Coord.Value = chase.Coord.Value.Move(currentDir);
                    }
                    else if (snake.Path.Length > 0)
                    {
                        chase.Coord.Value = snake.Path[0];
                        snake.Path.RemoveAt(0);
                    }
                }
            }));

            Sound.AttachTracker(entity);
            SoundKiller.Add(entity, AK.EVENTS.STOP_SNAKE);
            ai.Add(new ChangeBinding <string>(ai.CurrentState, delegate(string old, string value)
            {
                if (value == "Suspended" || value == "Alert")
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.STOP_SNAKE, entity);
                }
                else if (old != "Idle" && old != "Chase" && old != "Crush")
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_SNAKE, entity);
                }
            }));

            const float sightDistance   = 50.0f;
            const float hearingDistance = 0.0f;

            ai.Setup
            (
                new AI.AIState
            {
                Name  = "Suspended",
                Tasks = new[] { checkOperationalRadius },
            },
                new AI.AIState
            {
                Name  = "Idle",
                Enter = delegate(AI.AIState previous)
                {
                    Entity voxelEntity = chase.Voxel.Value.Target;
                    if (voxelEntity != null)
                    {
                        Voxel m = voxelEntity.Get <Voxel>();
                        if (currentDir == Direction.None || !chase.Filter(m[chase.Coord.Value.Move(currentDir)]))
                        {
                            currentDir = randomValidDirection(m);
                        }
                        chase.Coord.Value = chase.Coord.Value.Move(currentDir);
                    }
                },
                Tasks = new[]
                {
                    checkMap,
                    checkOperationalRadius,
                    new AI.Task
                    {
                        Interval = 1.0f,
                        Action   = delegate()
                        {
                            Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player");
                            if (a != null)
                            {
                                ai.CurrentState.Value = "Alert";
                            }
                        },
                    },
                },
            },
                new AI.AIState
            {
                Name  = "Alert",
                Enter = delegate(AI.AIState previous)
                {
                    chase.EnableMovement.Value = false;
                },
                Exit = delegate(AI.AIState next)
                {
                    chase.EnableMovement.Value = true;
                },
                Tasks = new[]
                {
                    checkMap,
                    checkOperationalRadius,
                    new AI.Task
                    {
                        Interval = 0.4f,
                        Action   = delegate()
                        {
                            if (ai.TimeInCurrentState > 3.0f)
                            {
                                ai.CurrentState.Value = "Idle";
                            }
                            else
                            {
                                Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player");
                                if (a != null)
                                {
                                    ai.TargetAgent.Value  = a.Entity;
                                    ai.CurrentState.Value = "Chase";
                                }
                            }
                        },
                    },
                },
            },
                new AI.AIState
            {
                Name  = "Chase",
                Enter = delegate(AI.AIState previousState)
                {
                    chase.EnablePathfinding.Value = true;
                    chase.Speed.Value             = chaseSpeed;
                },
                Exit = delegate(AI.AIState nextState)
                {
                    chase.EnablePathfinding.Value = false;
                    chase.Speed.Value             = defaultSpeed;
                },
                Tasks = new[]
                {
                    checkMap,
                    checkOperationalRadius,
                    checkTargetAgent,
                    new AI.Task
                    {
                        Interval = 0.07f,
                        Action   = delegate()
                        {
                            Vector3 targetPosition = ai.TargetAgent.Value.Target.Get <Agent>().Position;

                            float targetDistance = (targetPosition - transform.Position).Length();

                            chase.Speed.Value = targetDistance < 15.0f ? closeChaseSpeed : chaseSpeed;

                            if (targetDistance > 50.0f || ai.TimeInCurrentState > 30.0f)                                     // He got away
                            {
                                ai.CurrentState.Value = "Alert";
                            }
                            else if (targetDistance < 4.0f)                                     // We got 'im
                            {
                                // First, make sure we're not near a reset block
                                Voxel v = chase.Voxel.Value.Target.Get <Voxel>();
                                if (VoxelAStar.BroadphaseSearch(v, chase.Coord, 6, x => x.Type == Lemma.Components.Voxel.States.Reset) == null)
                                {
                                    ai.CurrentState.Value = "Crush";
                                }
                            }
                            else
                            {
                                chase.Target.Value = targetPosition;
                            }
                        },
                    },
                },
            },
                new AI.AIState
            {
                Name  = "Crush",
                Enter = delegate(AI.AIState lastState)
                {
                    // Set up cage
                    Voxel.Coord center = chase.Voxel.Value.Target.Get <Voxel>().GetCoordinate(ai.TargetAgent.Value.Target.Get <Agent>().Position);

                    int radius = 1;

                    // Bottom
                    for (int x = center.X - radius; x <= center.X + radius; x++)
                    {
                        for (int z = center.Z - radius; z <= center.Z + radius; z++)
                        {
                            snake.Path.Add(new Voxel.Coord {
                                X = x, Y = center.Y - 4, Z = z
                            });
                        }
                    }

                    // Outer shell
                    radius = 2;
                    for (int y = center.Y - 3; y <= center.Y + 3; y++)
                    {
                        // Left
                        for (int z = center.Z - radius; z <= center.Z + radius; z++)
                        {
                            snake.Path.Add(new Voxel.Coord {
                                X = center.X - radius, Y = y, Z = z
                            });
                        }

                        // Right
                        for (int z = center.Z - radius; z <= center.Z + radius; z++)
                        {
                            snake.Path.Add(new Voxel.Coord {
                                X = center.X + radius, Y = y, Z = z
                            });
                        }

                        // Backward
                        for (int x = center.X - radius; x <= center.X + radius; x++)
                        {
                            snake.Path.Add(new Voxel.Coord {
                                X = x, Y = y, Z = center.Z - radius
                            });
                        }

                        // Forward
                        for (int x = center.X - radius; x <= center.X + radius; x++)
                        {
                            snake.Path.Add(new Voxel.Coord {
                                X = x, Y = y, Z = center.Z + radius
                            });
                        }
                    }

                    // Top
                    for (int x = center.X - radius; x <= center.X + radius; x++)
                    {
                        for (int z = center.Z - radius; z <= center.Z + radius; z++)
                        {
                            snake.Path.Add(new Voxel.Coord {
                                X = x, Y = center.Y + 3, Z = z
                            });
                        }
                    }

                    chase.EnablePathfinding.Value = false;
                    chase.Speed.Value             = crushSpeed;

                    snake.CrushCoordinate.Value = chase.Coord;
                },
                Exit = delegate(AI.AIState nextState)
                {
                    chase.Speed.Value = defaultSpeed;
                    chase.Coord.Value = chase.LastCoord.Value = snake.CrushCoordinate;
                    snake.Path.Clear();
                },
                Tasks = new[]
                {
                    checkMap,
                    checkOperationalRadius,
                    checkTargetAgent,
                    new AI.Task
                    {
                        Interval = 0.01f,
                        Action   = delegate()
                        {
                            Agent a = ai.TargetAgent.Value.Target.Get <Agent>();
                            a.Damage.Execute(0.01f / 1.5f);                                     // seconds to kill
                            if (!a.Active)
                            {
                                ai.CurrentState.Value = "Alert";
                            }
                            else
                            {
                                if ((a.Position - transform.Position.Value).Length() > 5.0f)                                         // They're getting away
                                {
                                    ai.CurrentState.Value = "Chase";
                                }
                            }
                        }
                    }
                },
            }
            );

            this.SetMain(entity, main);

            entity.Add("OperationalRadius", snake.OperationalRadius);
        }
Esempio n. 10
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Transform transform = entity.GetOrCreate <Transform>("Transform");

            ModelAlpha model = entity.GetOrCreate <ModelAlpha>("Model");

            model.Filename.Value   = "AlphaModels\\waterfall";
            model.Distortion.Value = true;

            this.SetMain(entity, main);

            VoxelAttachable.MakeAttachable(entity, main).EditorProperties();

            entity.Add("Scale", model.Scale);
            entity.Add("Color", model.Color);
            entity.Add("Alpha", model.Alpha);

            model.Add(new Binding <Matrix>(model.Transform, transform.Matrix));

            Property <Vector2> uvScale = model.GetVector2Parameter("UVScale");

            model.Add(new Binding <Vector2, Vector3>(uvScale, x => new Vector2(x.X, x.Y), model.Scale));

            Property <Vector3> soundPosition = new Property <Vector3>();

            Sound.AttachTracker(entity, soundPosition);

            if (!main.EditorEnabled && !model.Suspended)
            {
                AkSoundEngine.PostEvent(AK.EVENTS.PLAY_WATERFALL_LOOP, entity);
            }

            Action stopSound = delegate()
            {
                AkSoundEngine.PostEvent(AK.EVENTS.STOP_WATERFALL_LOOP, entity);
            };

            model.Add(new CommandBinding(model.OnSuspended, stopSound));
            model.Add(new CommandBinding(model.Delete, stopSound));
            model.Add(new CommandBinding(model.OnResumed, delegate()
            {
                if (!main.EditorEnabled)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_WATERFALL_LOOP, entity);
                }
            }));

            Property <Vector2> offset  = model.GetVector2Parameter("Offset");
            Updater            updater = new Updater
                                         (
                delegate(float dt)
            {
                offset.Value           = new Vector2(0, main.TotalTime * -0.6f);
                Vector3 relativeCamera = Vector3.Transform(main.Camera.Position, Matrix.Invert(transform.Matrix));
                Vector3 bounds         = model.Scale.Value * 0.5f;
                relativeCamera.X       = MathHelper.Clamp(relativeCamera.X, -bounds.X, bounds.X);
                relativeCamera.Y       = Math.Min(0, relativeCamera.Y);
                relativeCamera.Z       = MathHelper.Clamp(relativeCamera.Z, -bounds.Z, bounds.Z);
                soundPosition.Value    = Vector3.Transform(relativeCamera, transform.Matrix);
            }
                                         );

            updater.EnabledInEditMode = true;
            entity.Add(updater);
        }
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Transform transform = entity.GetOrCreate <Transform>("Transform");

            this.SetMain(entity, main);

            Sound.AttachTracker(entity);
            VoxelAttachable attachable = VoxelAttachable.MakeAttachable(entity, main, true, false);

            attachable.Offset.Value  = 1;
            attachable.Enabled.Value = true;

            PowerBlockSocket socket = entity.GetOrCreate <PowerBlockSocket>("PowerBlockSocket");

            socket.Add(new Binding <Voxel.Coord>(socket.Coord, attachable.Coord));
            socket.Add(new Binding <Entity.Handle>(socket.AttachedVoxel, attachable.AttachedVoxel));

            const float maxLightAttenuation = 15.0f;
            PointLight  light = entity.Create <PointLight>();

            light.Attenuation.Value = maxLightAttenuation;
            light.Add(new Binding <Vector3>(light.Position, transform.Position));
            light.Add(new Binding <Vector3, Voxel.t>(light.Color, delegate(Voxel.t t)
            {
                switch (t)
                {
                case Voxel.t.GlowBlue:
                    return(new Vector3(0.8f, 0.9f, 1.2f));

                case Voxel.t.GlowYellow:
                    return(new Vector3(1.2f, 1.2f, 0.8f));

                default:
                    return(Vector3.One);
                }
            }, socket.Type));
            light.Add(new Binding <bool>(light.Enabled, socket.Powered));

            PointLight animationLight = entity.Create <PointLight>();

            animationLight.Add(new Binding <Vector3>(animationLight.Position, light.Position));
            animationLight.Add(new Binding <Vector3>(animationLight.Color, light.Color));
            animationLight.Enabled.Value = false;

            PlayerTrigger trigger = entity.GetOrCreate <PlayerTrigger>("PlayerTrigger");

            trigger.Radius.Value = 7;
            trigger.Add(new Binding <Vector3>(trigger.Position, transform.Position));
            const float minimumChangeTime = 1.5f;
            float       lastChange        = -minimumChangeTime;

            trigger.Add(new CommandBinding(trigger.PlayerEntered, delegate()
            {
                if (main.TotalTime - lastChange > minimumChangeTime)
                {
                    BlockCloud cloud = PlayerFactory.Instance.Get <BlockCloud>();

                    bool changed    = false;
                    Voxel sockVoxel = attachable.AttachedVoxel.Value.Target.Get <Voxel>();
                    if (!socket.Powered && cloud.Type.Value == socket.Type.Value)
                    {
                        // Plug in to the socket
                        List <Voxel.Coord> coords = new List <Voxel.Coord>();
                        Queue <Voxel.Coord> queue = new Queue <Voxel.Coord>();
                        queue.Enqueue(sockVoxel.GetCoordinate(transform.Position));
                        while (queue.Count > 0)
                        {
                            Voxel.Coord c = queue.Dequeue();
                            coords.Add(c);
                            if (coords.Count >= cloud.Blocks.Length)
                            {
                                break;
                            }

                            Voxel.CoordSetCache.Add(c);
                            foreach (Direction adjacentDirection in DirectionExtensions.Directions)
                            {
                                Voxel.Coord adjacentCoord = c.Move(adjacentDirection);
                                if (!Voxel.CoordSetCache.Contains(adjacentCoord))
                                {
                                    Voxel.t adjacentID = sockVoxel[adjacentCoord].ID;
                                    if (adjacentID == Voxel.t.Empty)
                                    {
                                        queue.Enqueue(adjacentCoord);
                                    }
                                }
                            }
                        }
                        Voxel.CoordSetCache.Clear();

                        EffectBlockFactory factory = Factory.Get <EffectBlockFactory>();
                        int i = 0;
                        foreach (Entity block in cloud.Blocks)
                        {
                            Entity effectBlockEntity = factory.CreateAndBind(main);
                            Voxel.States.All[cloud.Type].ApplyToEffectBlock(effectBlockEntity.Get <ModelInstance>());
                            EffectBlock effectBlock      = effectBlockEntity.Get <EffectBlock>();
                            effectBlock.DoScale          = false;
                            Transform blockTransform     = block.Get <Transform>();
                            effectBlock.StartPosition    = blockTransform.Position;
                            effectBlock.StartOrientation = blockTransform.Quaternion;
                            effectBlock.TotalLifetime    = (i + 1) * 0.04f;
                            effectBlock.Setup(sockVoxel.Entity, coords[i], cloud.Type);
                            main.Add(effectBlockEntity);
                            block.Delete.Execute();
                            i++;
                        }
                        cloud.Blocks.Clear();
                        cloud.Type.Value     = Voxel.t.Empty;
                        socket.Powered.Value = true;
                        changed = true;
                    }
                    else if (socket.Powered && cloud.Type.Value == Voxel.t.Empty && !socket.PowerOnOnly)
                    {
                        // Pull blocks out of the socket
                        AkSoundEngine.PostEvent(AK.EVENTS.PLAY_MAGIC_CUBES, entity);
                        SceneryBlockFactory factory = Factory.Get <SceneryBlockFactory>();
                        Quaternion quat             = Quaternion.CreateFromRotationMatrix(sockVoxel.Transform);
                        cloud.Type.Value            = socket.Type;
                        List <Voxel.Coord> coords   = sockVoxel.GetContiguousByType(new[] { sockVoxel.GetBox(transform.Position) }).SelectMany(x => x.GetCoords()).ToList();
                        sockVoxel.Empty(coords, true);
                        sockVoxel.Regenerate();
                        ParticleSystem particles = ParticleSystem.Get(main, "WhiteShatter");
                        int count = 0;
                        foreach (Voxel.Coord c in coords)
                        {
                            Vector3 pos = sockVoxel.GetAbsolutePosition(c);
                            for (int j = 0; j < 20; j++)
                            {
                                Vector3 offset = new Vector3((float)this.random.NextDouble() - 0.5f, (float)this.random.NextDouble() - 0.5f, (float)this.random.NextDouble() - 0.5f);
                                particles.AddParticle(pos + offset, offset);
                            }
                            if (count < BlockCloud.TotalBlocks)
                            {
                                Entity block                    = factory.CreateAndBind(main);
                                Transform blockTransform        = block.Get <Transform>();
                                blockTransform.Position.Value   = pos;
                                blockTransform.Quaternion.Value = quat;
                                SceneryBlock sceneryBlock       = block.Get <SceneryBlock>();
                                sceneryBlock.Type.Value         = socket.Type;
                                sceneryBlock.Scale.Value        = 0.5f;
                                cloud.Blocks.Add(block);
                                main.Add(block);
                            }
                            count++;
                        }
                        socket.Powered.Value = false;
                        changed = true;
                    }

                    if (changed)
                    {
                        lastChange = main.TotalTime;
                        animationLight.Enabled.Value     = true;
                        animationLight.Attenuation.Value = 0.0f;
                        entity.Add(new Animation
                                   (
                                       new Animation.FloatMoveTo(animationLight.Attenuation, maxLightAttenuation, 0.25f),
                                       new Animation.FloatMoveTo(animationLight.Attenuation, 0.0f, 2.0f),
                                       new Animation.Set <bool>(animationLight.Enabled, false)
                                   ));
                    }
                }
            }));

            entity.Add("Type", socket.Type);
            entity.Add("Powered", socket.Powered, new PropertyEntry.EditorData {
                Readonly = true
            });
            entity.Add("PowerOnOnly", socket.PowerOnOnly);
            entity.Add("OnPowerOn", socket.OnPowerOn);
            entity.Add("OnPowerOff", socket.OnPowerOff);
            entity.Add("Enabled", trigger.Enabled);
            entity.Add("Enable", trigger.Enable);
            entity.Add("Disable", trigger.Disable);
        }
Esempio n. 12
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Main.Config settings  = main.Settings;
            Transform   transform = entity.GetOrCreate <Transform>("Transform");

            entity.CannotSuspend = true;

            PlayerFactory.Instance = entity;

            this.SetMain(entity, main);

            FPSInput input = new FPSInput();

            input.EnabledWhenPaused = false;
            entity.Add("Input", input);

            Updater parkour = entity.Create <Updater>();
            Updater jumper  = entity.Create <Updater>();

            Player player = entity.GetOrCreate <Player>("Player");

            AnimatedModel firstPersonModel = entity.GetOrCreate <AnimatedModel>("FirstPersonModel");

            firstPersonModel.MapContent            = false;
            firstPersonModel.Serialize             = false;
            firstPersonModel.Filename.Value        = "Models\\joan-firstperson";
            firstPersonModel.CullBoundingBox.Value = false;

            AnimatedModel model = entity.GetOrCreate <AnimatedModel>("Model");

            model.MapContent            = false;
            model.Serialize             = false;
            model.Filename.Value        = "Models\\joan";
            model.CullBoundingBox.Value = false;

            AnimationController anim      = entity.GetOrCreate <AnimationController>("AnimationController");
            RotationController  rotation  = entity.GetOrCreate <RotationController>("Rotation");
            BlockPredictor      predictor = entity.GetOrCreate <BlockPredictor>("BlockPredictor");
            Jump          jump            = entity.GetOrCreate <Jump>("Jump");
            RollKickSlide rollKickSlide   = entity.GetOrCreate <RollKickSlide>("RollKickSlide");
            Vault         vault           = entity.GetOrCreate <Vault>("Vault");
            WallRun       wallRun         = entity.GetOrCreate <WallRun>("WallRun");
            VoxelTools    voxelTools      = entity.GetOrCreate <VoxelTools>("VoxelTools");
            Footsteps     footsteps       = entity.GetOrCreate <Footsteps>("Footsteps");
            FallDamage    fallDamage      = entity.GetOrCreate <FallDamage>("FallDamage");
            FPSCamera     fpsCamera       = entity.GetOrCreate <FPSCamera>("FPSCamera");

            fpsCamera.Enabled.Value = false;
            Rumble           rumble        = entity.GetOrCreate <Rumble>("Rumble");
            CameraController cameraControl = entity.GetOrCreate <CameraController>("CameraControl");

            Property <Vector3> floor = new Property <Vector3>();

            transform.Add(new Binding <Vector3>(floor, () => transform.Position + new Vector3(0, player.Character.Height * -0.5f, 0), transform.Position, player.Character.Height));
            Sound.AttachTracker(entity, floor);

            predictor.Add(new Binding <Vector3>(predictor.FootPosition, floor));
            predictor.Add(new Binding <Vector3>(predictor.LinearVelocity, player.Character.LinearVelocity));
            predictor.Add(new Binding <float>(predictor.Rotation, rotation.Rotation));
            predictor.Add(new Binding <float>(predictor.MaxSpeed, player.Character.MaxSpeed));
            predictor.Add(new Binding <float>(predictor.JumpSpeed, player.Character.JumpSpeed));
            predictor.Add(new Binding <bool>(predictor.IsSupported, player.Character.IsSupported));

            jump.Add(new Binding <bool>(jump.Crouched, player.Character.Crouched));
            jump.Add(new TwoWayBinding <bool>(player.Character.IsSupported, jump.IsSupported));
            jump.Add(new TwoWayBinding <bool>(player.Character.HasTraction, jump.HasTraction));
            jump.Add(new TwoWayBinding <Vector3>(player.Character.LinearVelocity, jump.LinearVelocity));
            jump.Add(new TwoWayBinding <BEPUphysics.Entities.Entity>(jump.SupportEntity, player.Character.SupportEntity));
            jump.Add(new TwoWayBinding <Vector3>(jump.SupportVelocity, player.Character.SupportVelocity));
            jump.Add(new Binding <Vector2>(jump.AbsoluteMovementDirection, player.Character.MovementDirection));
            jump.Add(new Binding <WallRun.State>(jump.WallRunState, wallRun.CurrentState));
            jump.Add(new Binding <float>(jump.Rotation, rotation.Rotation));
            jump.Add(new Binding <Vector3>(jump.Position, transform.Position));
            jump.Add(new Binding <Vector3>(jump.FloorPosition, floor));
            jump.Add(new Binding <float>(jump.MaxSpeed, player.Character.MaxSpeed));
            jump.Add(new Binding <float>(jump.JumpSpeed, player.Character.JumpSpeed));
            jump.Add(new Binding <float>(jump.Mass, player.Character.Mass));
            jump.Add(new Binding <float>(jump.LastRollKickEnded, rollKickSlide.LastRollKickEnded));
            jump.Add(new Binding <Voxel>(jump.WallRunMap, wallRun.WallRunVoxel));
            jump.Add(new Binding <Direction>(jump.WallDirection, wallRun.WallDirection));
            jump.Add(new CommandBinding <Voxel, Voxel.Coord, Direction>(jump.WalkedOn, footsteps.WalkedOn));
            jump.Add(new CommandBinding(jump.DeactivateWallRun, (Action)wallRun.Deactivate));
            jump.Add(new CommandBinding <float>(jump.FallDamage, fallDamage.ApplyJump));
            jump.Predictor = predictor;
            jump.Bind(model);
            jump.Add(new TwoWayBinding <Voxel>(wallRun.LastWallRunMap, jump.LastWallRunMap));
            jump.Add(new TwoWayBinding <Direction>(wallRun.LastWallDirection, jump.LastWallDirection));
            jump.Add(new TwoWayBinding <bool>(rollKickSlide.CanKick, jump.CanKick));
            jump.Add(new TwoWayBinding <float>(player.Character.LastSupportedSpeed, jump.LastSupportedSpeed));

            wallRun.Add(new Binding <bool>(wallRun.IsSwimming, player.Character.IsSwimming));
            wallRun.Add(new TwoWayBinding <Vector3>(player.Character.LinearVelocity, wallRun.LinearVelocity));
            wallRun.Add(new TwoWayBinding <Vector3>(transform.Position, wallRun.Position));
            wallRun.Add(new TwoWayBinding <bool>(player.Character.IsSupported, wallRun.IsSupported));
            wallRun.Add(new CommandBinding(wallRun.LockRotation, (Action)rotation.Lock));
            wallRun.Add(new CommandBinding <float>(wallRun.UpdateLockedRotation, rotation.UpdateLockedRotation));
            vault.Add(new CommandBinding(wallRun.Vault, delegate() { vault.Go(true); }));
            wallRun.Predictor = predictor;
            wallRun.Add(new Binding <float>(wallRun.Height, player.Character.Height));
            wallRun.Add(new Binding <float>(wallRun.JumpSpeed, player.Character.JumpSpeed));
            wallRun.Add(new Binding <float>(wallRun.MaxSpeed, player.Character.MaxSpeed));
            wallRun.Add(new TwoWayBinding <float>(rotation.Rotation, wallRun.Rotation));
            wallRun.Add(new TwoWayBinding <bool>(player.Character.AllowUncrouch, wallRun.AllowUncrouch));
            wallRun.Add(new TwoWayBinding <bool>(player.Character.HasTraction, wallRun.HasTraction));
            wallRun.Add(new Binding <float>(wallRun.LastWallJump, jump.LastWallJump));
            wallRun.Add(new Binding <float>(player.Character.LastSupportedSpeed, wallRun.LastSupportedSpeed));
            player.Add(new Binding <WallRun.State>(player.Character.WallRunState, wallRun.CurrentState));

            input.Bind(rollKickSlide.RollKickButton, settings.RollKick);
            rollKickSlide.Add(new Binding <bool>(rollKickSlide.EnableCrouch, player.EnableCrouch));
            rollKickSlide.Add(new Binding <float>(rollKickSlide.Rotation, rotation.Rotation));
            rollKickSlide.Add(new Binding <bool>(rollKickSlide.IsSwimming, player.Character.IsSwimming));
            rollKickSlide.Add(new Binding <bool>(rollKickSlide.IsSupported, player.Character.IsSupported));
            rollKickSlide.Add(new Binding <Vector3>(rollKickSlide.FloorPosition, floor));
            rollKickSlide.Add(new Binding <float>(rollKickSlide.Height, player.Character.Height));
            rollKickSlide.Add(new Binding <float>(rollKickSlide.MaxSpeed, player.Character.MaxSpeed));
            rollKickSlide.Add(new Binding <float>(rollKickSlide.JumpSpeed, player.Character.JumpSpeed));
            rollKickSlide.Add(new Binding <Vector3>(rollKickSlide.SupportVelocity, player.Character.SupportVelocity));
            rollKickSlide.Add(new TwoWayBinding <bool>(wallRun.EnableEnhancedWallRun, rollKickSlide.EnableEnhancedRollSlide));
            rollKickSlide.Add(new TwoWayBinding <bool>(player.Character.AllowUncrouch, rollKickSlide.AllowUncrouch));
            rollKickSlide.Add(new TwoWayBinding <bool>(player.Character.Crouched, rollKickSlide.Crouched));
            rollKickSlide.Add(new TwoWayBinding <bool>(player.Character.EnableWalking, rollKickSlide.EnableWalking));
            rollKickSlide.Add(new TwoWayBinding <Vector3>(player.Character.LinearVelocity, rollKickSlide.LinearVelocity));
            rollKickSlide.Add(new TwoWayBinding <Vector3>(transform.Position, rollKickSlide.Position));
            rollKickSlide.Predictor = predictor;
            rollKickSlide.Bind(model);
            rollKickSlide.VoxelTools = voxelTools;
            rollKickSlide.Add(new CommandBinding(rollKickSlide.DeactivateWallRun, (Action)wallRun.Deactivate));
            rollKickSlide.Add(new CommandBinding(rollKickSlide.Footstep, footsteps.Footstep));
            rollKickSlide.Add(new CommandBinding(rollKickSlide.LockRotation, (Action)rotation.Lock));
            SoundKiller.Add(entity, AK.EVENTS.STOP_PLAYER_SLIDE_LOOP);

            vault.Add(new Binding <Vector3>(vault.Position, transform.Position));
            vault.Add(new Binding <Vector3>(vault.FloorPosition, floor));
            vault.Add(new Binding <float>(vault.MaxSpeed, player.Character.MaxSpeed));
            vault.Add(new Binding <WallRun.State>(vault.WallRunState, wallRun.CurrentState));
            vault.Add(new CommandBinding(vault.LockRotation, (Action)rotation.Lock));
            vault.Add(new CommandBinding(vault.DeactivateWallRun, (Action)wallRun.Deactivate));
            vault.Add(new TwoWayBinding <float>(player.Character.LastSupportedSpeed, vault.LastSupportedSpeed));
            vault.Add(new CommandBinding <float>(vault.FallDamage, fallDamage.Apply));
            vault.Bind(model);
            vault.Predictor = predictor;
            vault.Add(new TwoWayBinding <float>(rotation.Rotation, vault.Rotation));
            vault.Add(new TwoWayBinding <bool>(player.Character.IsSupported, vault.IsSupported));
            vault.Add(new TwoWayBinding <bool>(player.Character.HasTraction, vault.HasTraction));
            vault.Add(new TwoWayBinding <Vector3>(player.Character.LinearVelocity, vault.LinearVelocity));
            vault.Add(new TwoWayBinding <bool>(player.Character.EnableWalking, vault.EnableWalking));
            vault.Add(new TwoWayBinding <bool>(player.Character.AllowUncrouch, vault.AllowUncrouch));
            vault.Add(new TwoWayBinding <bool>(player.Character.Crouched, vault.Crouched));
            vault.Add(new Binding <float>(vault.Radius, player.Character.Radius));

            rotation.Add(new TwoWayBinding <Vector2>(rotation.Mouse, input.Mouse));
            rotation.Add(new Binding <bool>(rotation.Rolling, rollKickSlide.Rolling));
            rotation.Add(new Binding <bool>(rotation.Kicking, rollKickSlide.Kicking));
            rotation.Add(new Binding <Vault.State>(rotation.VaultState, vault.CurrentState));
            rotation.Add(new Binding <WallRun.State>(rotation.WallRunState, wallRun.CurrentState));

            voxelTools.Add(new Binding <float>(voxelTools.Height, player.Character.Height));
            voxelTools.Add(new Binding <float>(voxelTools.SupportHeight, player.Character.SupportHeight));
            voxelTools.Add(new Binding <Vector3>(voxelTools.Position, transform.Position));

            anim.Add(new Binding <bool>(anim.IsSupported, player.Character.IsSupported));
            anim.Add(new Binding <WallRun.State>(anim.WallRunState, wallRun.CurrentState));
            anim.Add(new Binding <bool>(anim.EnableWalking, player.Character.EnableWalking));
            anim.Add(new Binding <bool>(anim.Crouched, player.Character.Crouched));
            anim.Add(new Binding <Vector3>(anim.LinearVelocity, player.Character.LinearVelocity));
            anim.Add(new Binding <Vector2>(anim.Movement, input.Movement));
            anim.Add(new Binding <Vector2>(anim.Mouse, input.Mouse));
            anim.Add(new Binding <float>(anim.Rotation, rotation.Rotation));
            anim.Add(new Binding <Voxel>(anim.WallRunMap, wallRun.WallRunVoxel));
            anim.Add(new Binding <Direction>(anim.WallDirection, wallRun.WallDirection));
            anim.Add(new Binding <bool>(anim.IsSwimming, player.Character.IsSwimming));
            anim.Add(new Binding <bool>(anim.Kicking, rollKickSlide.Kicking));
            anim.Add(new Binding <Vector3>(anim.SupportVelocity, player.Character.SupportVelocity));
            anim.Add
            (
                new Binding <bool>
                (
                    anim.EnableLean,
                    () => player.Character.EnableWalking.Value && player.Character.IsSupported.Value && input.Movement.Value.Y > 0.5f,
                    player.Character.EnableWalking, player.Character.IsSupported, input.Movement
                )
            );
            anim.Bind(model);

            // Camera control
            model.UpdateWorldTransforms();

            cameraControl.Add(new Binding <Vector2>(cameraControl.Mouse, input.Mouse));
            cameraControl.Add(new Binding <float>(cameraControl.Lean, x => x * (float)Math.PI * 0.05f, anim.Lean));
            cameraControl.Add(new Binding <Vector3>(cameraControl.LinearVelocity, player.Character.LinearVelocity));
            cameraControl.Add(new Binding <float>(cameraControl.MaxSpeed, player.Character.MaxSpeed));
            cameraControl.Add(new Binding <Matrix>(cameraControl.CameraBone, model.GetBoneTransform("Camera")));
            cameraControl.Add(new Binding <Matrix>(cameraControl.HeadBone, model.GetBoneTransform("ORG-head")));
            cameraControl.Add(new Binding <Matrix>(cameraControl.ModelTransform, model.Transform));
            cameraControl.Add(new Binding <float>(cameraControl.BaseCameraShakeAmount, () => MathHelper.Clamp((player.Character.LinearVelocity.Value.Length() - (player.Character.MaxSpeed * 2.5f)) / (player.Character.MaxSpeed * 4.0f), 0, 1), player.Character.LinearVelocity, player.Character.MaxSpeed));
            cameraControl.Offset = model.GetBoneTransform("Camera").Value.Translation - model.GetBoneTransform("ORG-head").Value.Translation;

            float heightOffset = 0.1f;

#if VR
            if (main.VR)
            {
                heightOffset = 0.4f;
            }
#endif
            cameraControl.Offset += new Vector3(0, heightOffset, 0);

            rumble.Add(new Binding <float>(rumble.CameraShake, cameraControl.TotalCameraShake));
            rumble.Add(new CommandBinding <float>(fallDamage.Rumble, rumble.Go));
            rumble.Add(new CommandBinding <float>(player.Rumble, rumble.Go));
            rumble.Add(new CommandBinding <float>(rollKickSlide.Rumble, rumble.Go));

            firstPersonModel.Add(new Binding <bool>(firstPersonModel.Enabled, x => !x, cameraControl.ThirdPerson));

            model.Add(new ChangeBinding <bool>(cameraControl.ThirdPerson, delegate(bool old, bool value)
            {
                if (value && !old)
                {
                    model.UnsupportedTechniques.Remove(Technique.Clip);
                    model.UnsupportedTechniques.Remove(Technique.Render);
                }
                else if (old && !value)
                {
                    model.UnsupportedTechniques.Add(Technique.Clip);
                    model.UnsupportedTechniques.Add(Technique.Render);
                }
            }));

            Lemma.Console.Console.AddConCommand(new Console.ConCommand("third_person", "Toggle third-person view (WARNING: EXPERIMENTAL)", delegate(Console.ConCommand.ArgCollection args)
            {
                cameraControl.ThirdPerson.Value = !cameraControl.ThirdPerson;
            }));
            entity.Add(new CommandBinding(entity.Delete, delegate()
            {
                Lemma.Console.Console.RemoveConCommand("third_person");
            }));

            // When rotation is locked, we want to make sure the player can't turn their head
            // 180 degrees from the direction they're facing

#if VR
            if (main.VR)
            {
                input.MaxY.Value = input.MinY.Value = 0;
            }
            else
#endif
            input.Add(new Binding <float>(input.MaxY, () => rotation.Locked ? (float)Math.PI * 0.3f : (float)Math.PI * 0.4f, rotation.Locked));

            input.Add(new Binding <float>(input.MinX, () => rotation.Locked ? rotation.Rotation + ((float)Math.PI * -0.4f) : 0.0f, rotation.Rotation, rotation.Locked));
            input.Add(new Binding <float>(input.MaxX, () => rotation.Locked ? rotation.Rotation + ((float)Math.PI * 0.4f) : 0.0f, rotation.Rotation, rotation.Locked));
            input.Add(new NotifyBinding(delegate() { input.Mouse.Changed(); }, rotation.Locked));             // Make sure the rotation locking takes effect even if the player doesn't move the mouse

            // Setup rendering properties

            model.Materials = firstPersonModel.Materials = new Model.Material[3];

            // Hoodie and shoes
            model.Materials[0] = new Model.Material
            {
                SpecularIntensity = 0.0f,
                SpecularPower     = 1.0f,
            };

            // Hands
            model.Materials[1] = new Model.Material
            {
                SpecularIntensity = 0.3f,
                SpecularPower     = 2.0f,
            };

            // Pants and skin
            model.Materials[2] = new Model.Material
            {
                SpecularIntensity = 0.5f,
                SpecularPower     = 20.0f,
            };

            firstPersonModel.Bind(model);

            // Third person model only gets rendered for shadows. No regular rendering or reflections.
            model.UnsupportedTechniques.Add(Technique.Clip);
            model.UnsupportedTechniques.Add(Technique.Render);

            // First-person model only used for regular rendering. No shadows or reflections.
            firstPersonModel.UnsupportedTechniques.Add(Technique.Shadow);
            firstPersonModel.UnsupportedTechniques.Add(Technique.Clip);

            // Build UI
            UIRenderer ui = new UIRenderer();
            ui.DrawOrder.Value   = -1;
            ui.EnabledWhenPaused = true;
            ui.EnabledInEditMode = false;
            entity.Add("UI", ui);

            input.Add(new Binding <float>(input.MouseSensitivity, settings.MouseSensitivity));
            input.Add(new Binding <bool>(input.InvertMouseX, settings.InvertMouseX));
            input.Add(new Binding <bool>(input.InvertMouseY, settings.InvertMouseY));
            input.Add(new Binding <PCInput.PCInputBinding>(input.LeftKey, settings.Left));
            input.Add(new Binding <PCInput.PCInputBinding>(input.RightKey, settings.Right));
            input.Add(new Binding <PCInput.PCInputBinding>(input.BackwardKey, settings.Backward));
            input.Add(new Binding <PCInput.PCInputBinding>(input.ForwardKey, settings.Forward));

            model.StartClip("Idle", 0, true, AnimatedModel.DefaultBlendTime);

            // Set up AI agent
            Agent agent = entity.GetOrCreate <Agent>();
            agent.Add(new TwoWayBinding <float>(player.Health, agent.Health));
            agent.Add(new Binding <Vector3>(agent.Position, () => transform.Position.Value + new Vector3(0, player.Character.Height * -0.5f, 0), transform.Position, player.Character.Height));
            agent.Add(new Binding <bool>(agent.Loud, () => player.Character.MovementDirection.Value.LengthSquared() > 0 && !player.Character.Crouched, player.Character.Crouched));

            // Blocks
            BlockCloud blockCloud = entity.GetOrCreate <BlockCloud>("BlockCloud");
            blockCloud.Scale.Value = 0.5f;
            blockCloud.Add(new Binding <Vector3>(blockCloud.Position, () => transform.Position.Value + new Vector3(0, player.Character.Height * 0.5f + player.Character.LinearVelocity.Value.Y, 0), transform.Position, player.Character.Height, player.Character.LinearVelocity));
            blockCloud.Blocks.ItemAdded += delegate(int index, Entity.Handle block)
            {
                Entity e = block.Target;
                if (e != null)
                {
                    e.Serialize = false;
                    PhysicsBlock.CancelPlayerCollisions(e.Get <PhysicsBlock>());
                }
            };
            predictor.Add(new Binding <Voxel.t>(predictor.BlockType, blockCloud.Type));

            PointLight blockLight = entity.Create <PointLight>();
            blockLight.Add(new Binding <Vector3>(blockLight.Position, blockCloud.AveragePosition));
            blockLight.Add(new Binding <bool, int>(blockLight.Enabled, x => x > 0, blockCloud.Blocks.Length));
            blockLight.Attenuation.Value = 30.0f;
            blockLight.Add(new Binding <Vector3, Voxel.t>(blockLight.Color, delegate(Voxel.t t)
            {
                switch (t)
                {
                case Voxel.t.GlowBlue:
                    return(new Vector3(0.7f, 0.7f, 0.9f));

                case Voxel.t.GlowYellow:
                    return(new Vector3(0.9f, 0.9f, 0.7f));

                default:
                    return(new Vector3(0.8f, 0.8f, 0.8f));
                }
            }, blockCloud.Type));

            blockLight.Add(new ChangeBinding <bool>(blockLight.Enabled, delegate(bool old, bool value)
            {
                if (!old && value)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_MAGIC_CUBE_LOOP, entity);
                }
                else if (old && !value)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.STOP_MAGIC_CUBE_LOOP, entity);
                }
            }));
            if (blockLight.Enabled)
            {
                AkSoundEngine.PostEvent(AK.EVENTS.PLAY_MAGIC_CUBE_LOOP, entity);
            }

            // Death
            entity.Add(new CommandBinding(player.Die, blockCloud.Clear));
            entity.Add(new CommandBinding(player.Die, delegate()
            {
                Session.Recorder.Event(main, "Die");
                if (agent.Killed || Agent.Query(transform.Position, 0.0f, 10.0f, x => x != agent) != null)
                {
                    Session.Recorder.Event(main, "Killed");
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_DEATH, entity);
                    main.Spawner.RespawnDistance = Spawner.KilledRespawnDistance;
                    main.Spawner.RespawnInterval = Spawner.KilledRespawnInterval;
                }
                entity.Add(new Animation(new Animation.Execute(entity.Delete)));
            }));

            player.EnabledInEditMode = false;

            player.Add(new TwoWayBinding <Matrix>(transform.Matrix, player.Character.Transform));

            model.Add(new Binding <Matrix>(model.Transform, delegate()
            {
                const float leanAmount = (float)Math.PI * 0.1f;
                return(Matrix.CreateTranslation(0, (player.Character.Height * -0.5f) - player.Character.SupportHeight, 0) * Matrix.CreateRotationZ(anim.Lean * leanAmount) * Matrix.CreateRotationY(rotation.Rotation) * transform.Matrix);
            }, transform.Matrix, rotation.Rotation, player.Character.Height, player.Character.SupportHeight, anim.Lean));

            firstPersonModel.Add(new Binding <Matrix>(firstPersonModel.Transform, model.Transform));
            firstPersonModel.Add(new Binding <Vector3>(firstPersonModel.Scale, model.Scale));

            WallRun.State[] footstepWallrunStates = new[]
            {
                WallRun.State.Left,
                WallRun.State.Right,
                WallRun.State.Straight,
                WallRun.State.None,
            };
            footsteps.Add(new Binding <bool>(footsteps.SoundEnabled, () => !player.Character.Crouched && footstepWallrunStates.Contains(wallRun.CurrentState) || (player.Character.IsSupported && player.Character.EnableWalking), player.Character.IsSupported, player.Character.EnableWalking, wallRun.CurrentState, player.Character.Crouched));
            footsteps.Add(new Binding <Vector3>(footsteps.Position, transform.Position));
            footsteps.Add(new Binding <float>(footsteps.Rotation, rotation.Rotation));
            footsteps.Add(new Binding <float>(footsteps.CharacterHeight, player.Character.Height));
            footsteps.Add(new Binding <float>(footsteps.SupportHeight, player.Character.SupportHeight));
            footsteps.Add(new Binding <bool>(footsteps.IsSupported, player.Character.IsSupported));
            footsteps.Add(new Binding <bool>(footsteps.IsSwimming, player.Character.IsSwimming));
            footsteps.Add(new CommandBinding <float>(footsteps.Damage, agent.Damage));
            footsteps.Add(new CommandBinding <Voxel, Voxel.Coord, Direction>(wallRun.WalkedOn, footsteps.WalkedOn));
            model.Trigger("Run", 0.16f, footsteps.Footstep);
            model.Trigger("Run", 0.58f, footsteps.Footstep);
            model.Trigger("WallRunLeft", 0.16f, footsteps.Footstep);
            model.Trigger("WallRunLeft", 0.58f, footsteps.Footstep);
            model.Trigger("WallRunRight", 0.16f, footsteps.Footstep);
            model.Trigger("WallRunRight", 0.58f, footsteps.Footstep);
            model.Trigger("WallRunStraight", 0.16f, footsteps.Footstep);
            model.Trigger("WallRunStraight", 0.58f, footsteps.Footstep);
            model.Trigger("TurnLeft", 0.15f, footsteps.Footstep);
            model.Trigger("TurnRight", 0.15f, footsteps.Footstep);
            model.Trigger("TopOut", 1.0f, new Command
            {
                Action = delegate()
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_GRUNT, entity);
                }
            });

            main.UI.IsMouseVisible.Value = false;

            SkinnedModel.Clip sprintAnimation = model["Sprint"], runAnimation = model["Run"];

            // Movement binding
            player.Add(new Binding <Vector2>(player.Character.MovementDirection, delegate()
            {
                Vector2 movement = input.Movement;
                if (movement.LengthSquared() == 0.0f)
                {
                    return(Vector2.Zero);
                }

                Matrix matrix = Matrix.CreateRotationY(rotation.Rotation);

                Vector2 forwardDir = new Vector2(matrix.Forward.X, matrix.Forward.Z);
                Vector2 rightDir   = new Vector2(matrix.Right.X, matrix.Right.Z);
                return(-(forwardDir * movement.Y) - (rightDir * movement.X));
            }, input.Movement, rotation.Rotation));

            player.Character.Crouched.Value      = true;
            player.Character.AllowUncrouch.Value = true;

            // Fall damage
            fallDamage.Add(new Binding <bool>(fallDamage.IsSupported, player.Character.IsSupported));
            fallDamage.Add(new TwoWayBinding <Vector3>(player.Character.LinearVelocity, fallDamage.LinearVelocity));
            fallDamage.Add(new TwoWayBinding <float>(player.Health, fallDamage.Health));
            fallDamage.Add(new CommandBinding <BEPUphysics.BroadPhaseEntries.Collidable, ContactCollection>(player.Character.Collided, fallDamage.Collided));
            fallDamage.Add(new TwoWayBinding <bool>(player.Character.EnableWalking, fallDamage.EnableWalking));
            fallDamage.Add(new TwoWayBinding <bool>(player.EnableMoves, fallDamage.EnableMoves));
            fallDamage.Add(new TwoWayBinding <bool>(fallDamage.Landing, rotation.Landing));
            fallDamage.Add(new CommandBinding(fallDamage.LockRotation, (Action)rotation.Lock));
            fallDamage.Add(new CommandBinding <float>(fallDamage.PhysicsDamage, agent.Damage));
            fallDamage.Bind(model);

            // Swim up
            input.Bind(player.Character.SwimUp, settings.Jump);

            float parkourTime = 0;
            float jumpTime = 0;
            jumper.Action = delegate(float dt)
            {
                if (player.EnableMoves && player.Character.EnableWalking &&
                    vault.CurrentState.Value == Vault.State.None &&
                    !rollKickSlide.Rolling && !rollKickSlide.Kicking &&
                    jumpTime < Player.SlowmoTime)
                {
                    if (jump.Go())
                    {
                        parkour.Enabled.Value = false;
                        jumper.Enabled.Value  = false;
                    }
                    jumpTime += dt;
                }
                else
                {
                    jumper.Enabled.Value = false;
                }
            };
            jumper.Add(new CommandBinding(jumper.Enable, delegate() { jumpTime = 0; }));
            jumper.Enabled.Value = false;
            entity.Add(jumper);

            // Jumping
            input.Bind(settings.Jump, PCInput.InputState.Down, delegate()
            {
                jumper.Enabled.Value = true;
            });

            input.Bind(settings.Jump, PCInput.InputState.Up, delegate()
            {
                jumper.Enabled.Value = false;
            });

            // Wall-run, vault, predictive
            parkour.Action = delegate(float dt)
            {
                if (player.EnableMoves &&
                    player.Character.EnableWalking &&
                    !(player.Character.Crouched && player.Character.IsSupported) &&
                    vault.CurrentState.Value == Vault.State.None &&
                    !rollKickSlide.Kicking &&
                    !rollKickSlide.Rolling &&
                    wallRun.CurrentState.Value == WallRun.State.None &&
                    parkourTime < Player.SlowmoTime)
                {
                    bool didSomething = false;

                    bool parkourBeganThisFrame = parkourTime == 0;
                    if (predictor.PossibilityCount > 0)
                    {
                        // In slow motion, prefer left and right wall-running
                        if (!(didSomething = wallRun.Activate(WallRun.State.Left, parkourBeganThisFrame)))
                        {
                            if (!(didSomething = wallRun.Activate(WallRun.State.Right, parkourBeganThisFrame)))
                            {
                                if (!(didSomething = vault.Go(parkourBeganThisFrame)))
                                {
                                    didSomething = wallRun.Activate(WallRun.State.Straight, parkourBeganThisFrame);
                                }
                            }
                        }
                    }
                    else
                    {
                        // In normal mode, prefer straight wall-running
                        if (!(didSomething = vault.Go(parkourBeganThisFrame)))
                        {
                            if (!(didSomething = wallRun.Activate(WallRun.State.Straight, parkourBeganThisFrame)))
                            {
                                if (!(didSomething = wallRun.Activate(WallRun.State.Left, parkourBeganThisFrame)))
                                {
                                    didSomething = wallRun.Activate(WallRun.State.Right, parkourBeganThisFrame);
                                }
                            }
                        }
                    }

                    if (didSomething)
                    {
                        jumper.Enabled.Value    = false;
                        player.SlowMotion.Value = false;
                        parkour.Enabled.Value   = false;
                    }
                    else if (parkourBeganThisFrame && player.Character.LinearVelocity.Value.Y > FallDamage.RollingDeathVelocity)
                    {
                        if (blockCloud.Blocks.Length > 0)
                        {
                            player.SlowMotion.Value = true;
                            predictor.ClearPossibilities();
                            predictor.PredictPlatforms();
                            predictor.PredictWalls();
                        }
                        else if (player.EnableSlowMotion)
                        {
                            player.SlowMotion.Value = true;
                        }
                    }

                    parkourTime += dt;
                }
                else
                {
                    parkour.Enabled.Value = false;
                }
            };
            parkour.Add(new CommandBinding(parkour.Enable, delegate()
            {
                parkourTime = 0;
            }));
            entity.Add(parkour);
            parkour.Enabled.Value = false;

            input.Bind(settings.Parkour, PCInput.InputState.Down, delegate()
            {
                parkour.Enabled.Value = true;
            });

            input.Bind(settings.Parkour, PCInput.InputState.Up, delegate()
            {
                parkour.Enabled.Value = false;
                wallRun.Deactivate();
                if (player.SlowMotion)
                {
                    player.SlowMotion.Value = false;
                }
            });

            input.Bind(settings.RollKick, PCInput.InputState.Down, delegate()
            {
                if (player.EnableMoves && player.Character.EnableWalking)
                {
                    rollKickSlide.Go();
                    parkour.Enabled.Value = false;
                    jumper.Enabled.Value  = false;
                }
            });

            input.Bind(settings.RollKick, PCInput.InputState.Up, delegate()
            {
                if (!rollKickSlide.Rolling && !rollKickSlide.Kicking)
                {
                    player.Character.AllowUncrouch.Value = true;
                }
            });

            // Special ability

            /*
             * input.Bind(settings.SpecialAbility, PCInput.InputState.Down, delegate()
             * {
             *      Voxel.GlobalRaycastResult hit = Voxel.GlobalRaycast(main.Camera.Position, main.Camera.Forward, main.Camera.FarPlaneDistance, null);
             *      if (hit.Voxel != null && hit.Voxel.GetType() != typeof(DynamicVoxel))
             *      {
             *              VoxelRip.Go(hit.Voxel, hit.Coordinate.Value, 7, delegate(List<DynamicVoxel> results)
             *              {
             *                      foreach (DynamicVoxel v in results)
             *                      {
             *                              v.IsAffectedByGravity.Value = false;
             *                              v.LinearVelocity.Value = hit.Voxel.GetAbsoluteVector(hit.Normal.GetVector()) * 7.0f
             + new Vector3((float)this.random.NextDouble() * 2.0f - 1.0f, (float)this.random.NextDouble() * 2.0f - 1.0f, (float)this.random.NextDouble() * 2.0f - 1.0f);
             +                      }
             +              });
             +      }
             + });
             */

            // Player data bindings

            entity.Add(new PostInitialization(delegate()
            {
                Entity dataEntity     = PlayerDataFactory.Instance;
                PlayerData playerData = dataEntity.Get <PlayerData>();

                // HACK. Overwriting the property rather than binding the two together. Oh well.
                // This is because I haven't written a two-way list binding.
                footsteps.RespawnLocations = playerData.RespawnLocations;

                // Bind player data properties
                entity.Add(new TwoWayBinding <float>(WorldFactory.Instance.Get <World>().CameraShakeAmount, cameraControl.CameraShakeAmount));
                entity.Add(new TwoWayBinding <bool>(playerData.EnableRoll, rollKickSlide.EnableRoll));
                entity.Add(new TwoWayBinding <bool>(playerData.EnableCrouch, player.EnableCrouch));
                entity.Add(new TwoWayBinding <bool>(playerData.EnableKick, rollKickSlide.EnableKick));
                entity.Add(new TwoWayBinding <bool>(playerData.EnableWallRun, wallRun.EnableWallRun));
                entity.Add(new TwoWayBinding <bool>(playerData.EnableWallRunHorizontal, wallRun.EnableWallRunHorizontal));
                entity.Add(new TwoWayBinding <bool>(playerData.EnableEnhancedWallRun, wallRun.EnableEnhancedWallRun));
                entity.Add(new TwoWayBinding <bool>(playerData.EnableMoves, player.EnableMoves));
                entity.Add(new TwoWayBinding <float>(playerData.MaxSpeed, player.Character.MaxSpeed));
                entity.Add(new Binding <bool>(fallDamage.PhoneOrNoteActive, () => playerData.PhoneActive || playerData.NoteActive, playerData.PhoneActive, playerData.NoteActive));

                if (playerData.CloudType.Value == Voxel.t.Empty)                 // This makes everything work if we spawn next to a power block socket
                {
                    entity.Add(new TwoWayBinding <Voxel.t>(blockCloud.Type, playerData.CloudType));
                }
                else
                {
                    entity.Add(new TwoWayBinding <Voxel.t>(playerData.CloudType, blockCloud.Type));
                }

                entity.Add(new TwoWayBinding <bool>(playerData.ThirdPerson, cameraControl.ThirdPerson));
                entity.Add(new TwoWayBinding <bool>(playerData.EnableSlowMotion, player.EnableSlowMotion));

                Phone phone = dataEntity.GetOrCreate <Phone>("Phone");

                entity.Add
                (
                    new Binding <bool>
                    (
                        phone.CanReceiveMessages,
                        () => player.Character.IsSupported && !player.Character.IsSwimming && !player.Character.Crouched,
                        player.Character.IsSupported,
                        player.Character.IsSwimming,
                        player.Character.Crouched
                    )
                );

                PhoneNote.Attach(main, entity, player, model, input, phone, player.Character.EnableWalking, playerData.PhoneActive, playerData.NoteActive);

                PlayerUI.Attach(main, entity, ui, player.Health, rotation.Rotation, playerData.NoteActive, playerData.PhoneActive);
            }));

            fpsCamera.Add(new Binding <Vector2>(fpsCamera.Mouse, input.Mouse));
            fpsCamera.Add(new Binding <Vector2>(fpsCamera.Movement, input.Movement));
            input.Bind(fpsCamera.SpeedMode, settings.Parkour);
            input.Bind(fpsCamera.Up, settings.Jump);
            fpsCamera.Add(new Binding <bool>(fpsCamera.Down, input.GetKey(Keys.LeftControl)));
            Lemma.Console.Console.AddConCommand(new ConCommand("noclip", "Toggle free camera mode", delegate(ConCommand.ArgCollection args)
            {
                bool freeCameraMode            = !fpsCamera.Enabled;
                fpsCamera.Enabled.Value        = freeCameraMode;
                cameraControl.Enabled.Value    = !freeCameraMode;
                firstPersonModel.Enabled.Value = !freeCameraMode;
                model.Enabled.Value            = !freeCameraMode;
                ui.Enabled.Value = !freeCameraMode;
                player.Character.EnableWalking.Value      = !freeCameraMode;
                player.EnableMoves.Value                  = !freeCameraMode;
                player.Character.Body.IsAffectedByGravity = !freeCameraMode;
                if (freeCameraMode)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.STOP_PLAYER_BREATHING_SOFT, entity);
                }
                else
                {
                    transform.Position.Value = main.Camera.Position;
                }
            }));

            entity.Add(new CommandBinding(entity.Delete, delegate()
            {
                Lemma.Console.Console.RemoveConCommand("noclip");
                if (fpsCamera.Enabled)                 // Movement is disabled. Re-enable it.
                {
                    player.Character.EnableWalking.Value = true;
                    player.EnableMoves.Value             = true;
                }
                PlayerFactory.Instance = null;
            }));
        }
Esempio n. 13
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            PointLight light = entity.GetOrCreate <PointLight>("PointLight");

            light.Serialize = false;

            const float defaultLightAttenuation = 15.0f;

            light.Attenuation.Value = defaultLightAttenuation;

            Transform transform = entity.GetOrCreate <Transform>("Transform");

            light.Add(new Binding <Vector3>(light.Position, transform.Position));

            if (!main.EditorEnabled)
            {
                Sound.AttachTracker(entity);
                SoundKiller.Add(entity, AK.EVENTS.STOP_GLOWSQUARE);
                entity.Add(new PostInitialization(delegate()
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_GLOWSQUARE, entity);
                    AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, -1.0f, entity);
                }));
            }

            AI ai = entity.GetOrCreate <AI>("AI");

            ModelAlpha model = entity.GetOrCreate <ModelAlpha>();

            model.Add(new Binding <Matrix>(model.Transform, transform.Matrix));
            model.Filename.Value  = "AlphaModels\\box";
            model.Serialize       = false;
            model.DrawOrder.Value = 15;

            RaycastAIMovement movement  = entity.GetOrCreate <RaycastAIMovement>("Movement");
            Levitator         levitator = entity.GetOrCreate <Levitator>("Levitator");

            const float defaultModelScale = 1.0f;

            model.Scale.Value = new Vector3(defaultModelScale);

            model.Add(new Binding <Vector3, string>(model.Color, delegate(string state)
            {
                switch (state)
                {
                case "Alert":
                    return(new Vector3(1.5f, 1.5f, 0.5f));

                case "Chase":
                    return(new Vector3(1.5f, 0.5f, 0.5f));

                case "Levitating":
                    return(new Vector3(2.0f, 1.0f, 0.5f));

                default:
                    return(new Vector3(1.0f, 1.0f, 1.0f));
                }
            }, ai.CurrentState));

            entity.Add(new Updater
                       (
                           delegate(float dt)
            {
                float source            = 1.0f + ((float)this.random.NextDouble() - 0.5f) * 2.0f * 0.05f;
                model.Scale.Value       = new Vector3(defaultModelScale * source);
                light.Attenuation.Value = defaultLightAttenuation * source;
            }
                       ));

            light.Add(new Binding <Vector3>(light.Color, model.Color));

            Agent agent = entity.GetOrCreate <Agent>();

            agent.Add(new Binding <Vector3>(agent.Position, transform.Position));

            RaycastAI raycastAI = entity.GetOrCreate <RaycastAI>("RaycastAI");

            raycastAI.Add(new TwoWayBinding <Vector3>(transform.Position, raycastAI.Position));
            raycastAI.Add(new Binding <Quaternion>(transform.Quaternion, raycastAI.Orientation));

            AI.Task checkOperationalRadius = new AI.Task
            {
                Interval = 2.0f,
                Action   = delegate()
                {
                    bool shouldBeActive = (transform.Position.Value - main.Camera.Position).Length() < movement.OperationalRadius;
                    if (shouldBeActive && ai.CurrentState == "Suspended")
                    {
                        ai.CurrentState.Value = "Idle";
                    }
                    else if (!shouldBeActive && ai.CurrentState != "Suspended")
                    {
                        ai.CurrentState.Value = "Suspended";
                    }
                },
            };

            AI.Task updatePosition = new AI.Task
            {
                Action = delegate()
                {
                    raycastAI.Update();
                },
            };

            ai.Add(new AI.AIState
            {
                Name  = "Suspended",
                Tasks = new[] { checkOperationalRadius, },
            });

            const float sightDistance   = 30.0f;
            const float hearingDistance = 0.0f;

            ai.Add(new AI.AIState
            {
                Name  = "Idle",
                Enter = delegate(AI.AIState previous)
                {
                    AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, -1.0f, entity);
                },
                Tasks = new[]
                {
                    checkOperationalRadius,
                    updatePosition,
                    new AI.Task
                    {
                        Interval = 1.0f,
                        Action   = delegate()
                        {
                            raycastAI.Move(new Vector3(((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f));
                        }
                    },
                    new AI.Task
                    {
                        Interval = 1.0f,
                        Action   = delegate()
                        {
                            Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player");
                            if (a != null)
                            {
                                ai.CurrentState.Value = "Alert";
                            }
                        },
                    },
                },
            });

            ai.Add(new AI.AIState
            {
                Name  = "Alert",
                Enter = delegate(AI.AIState previous)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.STOP_GLOWSQUARE, entity);
                },
                Exit = delegate(AI.AIState next)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_GLOWSQUARE, entity);
                },
                Tasks = new[]
                {
                    checkOperationalRadius,
                    updatePosition,
                    new AI.Task
                    {
                        Interval = 1.0f,
                        Action   = delegate()
                        {
                            if (ai.TimeInCurrentState > 3.0f)
                            {
                                ai.CurrentState.Value = "Idle";
                            }
                            else
                            {
                                Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player");
                                if (a != null)
                                {
                                    ai.TargetAgent.Value  = a.Entity;
                                    ai.CurrentState.Value = "Chase";
                                }
                            }
                        },
                    },
                },
            });

            AI.Task checkTargetAgent = new AI.Task
            {
                Action = delegate()
                {
                    Entity target = ai.TargetAgent.Value.Target;
                    if (target == null || !target.Active)
                    {
                        ai.TargetAgent.Value  = null;
                        ai.CurrentState.Value = "Idle";
                    }
                },
            };

            // Levitate

            const int levitateRipRadius = 4;

            Func <bool> tryLevitate = delegate()
            {
                Entity voxelEntity = raycastAI.Voxel.Value.Target;
                if (voxelEntity == null)
                {
                    return(false);
                }

                Voxel       map       = voxelEntity.Get <Voxel>();
                Voxel.Coord?candidate = map.FindClosestFilledCell(raycastAI.Coord, 3);

                if (!candidate.HasValue)
                {
                    return(false);
                }

                if (VoxelRip.Go(map, candidate.Value, levitateRipRadius, delegate(List <DynamicVoxel> spawnedMaps)
                {
                    foreach (DynamicVoxel spawnedMap in spawnedMaps)
                    {
                        if (spawnedMap[candidate.Value] != Voxel.States.Empty)
                        {
                            spawnedMap.Dangerous.Value = true;
                            levitator.LevitatingVoxel.Value = spawnedMap.Entity;
                            break;
                        }
                    }
                }))
                {
                    levitator.GrabCoord.Value = candidate.Value;
                    return(true);
                }

                return(false);
            };

            Action delevitateMap = delegate()
            {
                Entity levitatingMapEntity = levitator.LevitatingVoxel.Value.Target;
                if (levitatingMapEntity == null || !levitatingMapEntity.Active)
                {
                    return;
                }

                DynamicVoxel dynamicMap = levitatingMapEntity.Get <DynamicVoxel>();
                VoxelRip.Consolidate(main, dynamicMap);
            };

            // Chase AI state

            ai.Add(new AI.AIState
            {
                Name  = "Chase",
                Enter = delegate(AI.AIState previous)
                {
                    AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, 0.0f, entity);
                },
                Tasks = new[]
                {
                    checkOperationalRadius,
                    checkTargetAgent,
                    new AI.Task
                    {
                        Interval = 0.35f,
                        Action   = delegate()
                        {
                            raycastAI.Move(ai.TargetAgent.Value.Target.Get <Transform>().Position.Value - transform.Position);
                        }
                    },
                    updatePosition,
                    new AI.Task
                    {
                        Interval = 0.1f,
                        Action   = delegate()
                        {
                            Entity target          = ai.TargetAgent.Value.Target;
                            Vector3 targetPosition = target.Get <Transform>().Position;
                            if ((targetPosition - transform.Position).Length() < 15.0f)
                            {
                                if (tryLevitate())
                                {
                                    ai.CurrentState.Value = "Levitating";
                                }
                            }
                        }
                    }
                },
            });

            Action findNextPosition = delegate()
            {
                movement.LastPosition.Value = transform.Position.Value;
                float   radius = 5.0f;
                Vector3 center = ai.TargetAgent.Value.Target.Get <Transform>().Position;
                Vector3 candidate;
                do
                {
                    candidate = center + new Vector3((float)this.random.NextDouble() - 0.5f, (float)this.random.NextDouble(), (float)this.random.NextDouble() - 0.5f) * radius;
                    radius   += 1.0f;
                }while (!RaycastAI.DefaultPositionFilter(candidate));

                movement.NextPosition.Value  = candidate;
                movement.PositionBlend.Value = 0.0f;
            };

            ai.Add(new AI.AIState
            {
                Name  = "Levitating",
                Enter = delegate(AI.AIState previous)
                {
                    findNextPosition();
                },
                Exit = delegate(AI.AIState next)
                {
                    delevitateMap();
                    levitator.LevitatingVoxel.Value = null;

                    //volume.Value = defaultVolume;
                    //pitch.Value = 0.0f;
                },
                Tasks = new[]
                {
                    checkTargetAgent,
                    new AI.Task
                    {
                        Action = delegate()
                        {
                            //volume.Value = 1.0f;
                            //pitch.Value = 1.0f;
                            Entity levitatingMapEntity = levitator.LevitatingVoxel.Value.Target;
                            if (levitatingMapEntity == null || !levitatingMapEntity.Active || ai.TimeInCurrentState.Value > 8.0f)
                            {
                                Entity voxel = raycastAI.Voxel.Value.Target;
                                if (voxel != null && voxel.Active)
                                {
                                    raycastAI.Coord.Value = raycastAI.LastCoord.Value = voxel.Get <Voxel>().GetCoordinate(transform.Position);
                                }
                                raycastAI.Move(new Vector3(((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f));
                                ai.CurrentState.Value = "Alert";
                                return;
                            }

                            DynamicVoxel dynamicMap = levitatingMapEntity.Get <DynamicVoxel>();

                            movement.PositionBlend.Value += (main.ElapsedTime.Value / 1.0f);
                            if (movement.PositionBlend > 1.0f)
                            {
                                findNextPosition();
                            }

                            transform.Position.Value = Vector3.Lerp(movement.LastPosition, movement.NextPosition, movement.PositionBlend);

                            Vector3 grabPoint = dynamicMap.GetAbsolutePosition(levitator.GrabCoord);
                            Vector3 diff      = transform.Position.Value - grabPoint;
                            if (diff.Length() > 15.0f)
                            {
                                ai.CurrentState.Value = "Chase";
                                return;
                            }

                            diff *= (float)Math.Sqrt(dynamicMap.PhysicsEntity.Mass) * 0.5f;
                            dynamicMap.PhysicsEntity.ApplyImpulse(ref grabPoint, ref diff);
                        },
                    },
                },
            });

            this.SetMain(entity, main);
        }
Esempio n. 14
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            PointLight light = entity.GetOrCreate <PointLight>("PointLight");

            light.Serialize = false;

            const float defaultLightAttenuation = 15.0f;

            light.Attenuation.Value = defaultLightAttenuation;

            Transform transform = entity.GetOrCreate <Transform>("Transform");

            light.Add(new Binding <Vector3>(light.Position, transform.Position));

            if (!main.EditorEnabled)
            {
                Sound.AttachTracker(entity);
                SoundKiller.Add(entity, AK.EVENTS.STOP_GLOWSQUARE);
                entity.Add(new PostInitialization(delegate()
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_GLOWSQUARE, entity);
                    AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, -1.0f, entity);
                }));
            }

            AI ai = entity.GetOrCreate <AI>("AI");

            ModelAlpha model = entity.GetOrCreate <ModelAlpha>();

            model.Add(new Binding <Matrix>(model.Transform, transform.Matrix));
            model.Filename.Value  = "AlphaModels\\box";
            model.Serialize       = false;
            model.DrawOrder.Value = 15;

            const float defaultModelScale = 1.0f;

            model.Scale.Value = new Vector3(defaultModelScale);

            model.Add(new Binding <Vector3, string>(model.Color, delegate(string state)
            {
                switch (state)
                {
                case "Alert":
                    return(new Vector3(1.5f, 1.5f, 0.5f));

                case "Chase":
                    return(new Vector3(1.5f, 0.5f, 0.5f));

                case "Explode":
                    return(new Vector3(2.0f, 1.0f, 0.5f));

                default:
                    return(new Vector3(1.0f, 1.0f, 1.0f));
                }
            }, ai.CurrentState));

            entity.Add(new Updater
                       (
                           delegate(float dt)
            {
                float source            = 1.0f + ((float)this.random.NextDouble() - 0.5f) * 2.0f * 0.05f;
                model.Scale.Value       = new Vector3(defaultModelScale * source);
                light.Attenuation.Value = defaultLightAttenuation * source;
            }
                       ));

            model.Add(new Binding <bool, string>(model.Enabled, x => x != "Exploding", ai.CurrentState));

            light.Add(new Binding <Vector3>(light.Color, model.Color));

            Agent agent = entity.GetOrCreate <Agent>();

            agent.Add(new Binding <Vector3>(agent.Position, transform.Position));

            RaycastAIMovement movement = entity.GetOrCreate <RaycastAIMovement>("Movement");
            Exploder          exploder = entity.GetOrCreate <Exploder>("Exploder");

            AI.Task checkOperationalRadius = new AI.Task
            {
                Interval = 2.0f,
                Action   = delegate()
                {
                    bool shouldBeActive = (transform.Position.Value - main.Camera.Position).Length() < movement.OperationalRadius;
                    if (shouldBeActive && ai.CurrentState == "Suspended")
                    {
                        ai.CurrentState.Value = "Idle";
                    }
                    else if (!shouldBeActive && ai.CurrentState != "Suspended")
                    {
                        ai.CurrentState.Value = "Suspended";
                    }
                },
            };

            RaycastAI raycastAI = entity.GetOrCreate <RaycastAI>("RaycastAI");

            raycastAI.Add(new TwoWayBinding <Vector3>(transform.Position, raycastAI.Position));
            raycastAI.Add(new Binding <Quaternion>(transform.Quaternion, raycastAI.Orientation));

            AI.Task updatePosition = new AI.Task
            {
                Action = delegate()
                {
                    raycastAI.Update();
                },
            };

            ai.Add(new AI.AIState
            {
                Name  = "Suspended",
                Tasks = new[] { checkOperationalRadius, },
            });

            const float sightDistance   = 40.0f;
            const float hearingDistance = 0.0f;

            ai.Add(new AI.AIState
            {
                Name  = "Idle",
                Enter = delegate(AI.AIState previous)
                {
                    AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, -1.0f, entity);
                },
                Tasks = new[]
                {
                    checkOperationalRadius,
                    updatePosition,
                    new AI.Task
                    {
                        Interval = 1.0f,
                        Action   = delegate()
                        {
                            raycastAI.Move(new Vector3(((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f));
                        }
                    },
                    new AI.Task
                    {
                        Interval = 0.5f,
                        Action   = delegate()
                        {
                            Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player");
                            if (a != null)
                            {
                                ai.CurrentState.Value = "Alert";
                            }
                        },
                    },
                },
            });

            ai.Add(new AI.AIState
            {
                Name  = "Alert",
                Enter = delegate(AI.AIState previous)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.STOP_GLOWSQUARE, entity);
                },
                Exit = delegate(AI.AIState next)
                {
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_GLOWSQUARE, entity);
                },
                Tasks = new[]
                {
                    checkOperationalRadius,
                    updatePosition,
                    new AI.Task
                    {
                        Interval = 1.0f,
                        Action   = delegate()
                        {
                            if (ai.TimeInCurrentState > 3.0f)
                            {
                                ai.CurrentState.Value = "Idle";
                            }
                            else
                            {
                                Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player");
                                if (a != null)
                                {
                                    ai.TargetAgent.Value  = a.Entity;
                                    ai.CurrentState.Value = "Chase";
                                }
                            }
                        },
                    },
                },
            });

            AI.Task checkTargetAgent = new AI.Task
            {
                Action = delegate()
                {
                    Entity target = ai.TargetAgent.Value.Target;
                    if (target == null || !target.Active)
                    {
                        ai.TargetAgent.Value  = null;
                        ai.CurrentState.Value = "Idle";
                    }
                },
            };

            ai.Add(new AI.AIState
            {
                Name  = "Chase",
                Enter = delegate(AI.AIState previous)
                {
                    AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, 0.0f, entity);
                },
                Tasks = new[]
                {
                    checkOperationalRadius,
                    checkTargetAgent,
                    new AI.Task
                    {
                        Interval = 0.35f,
                        Action   = delegate()
                        {
                            raycastAI.Move(ai.TargetAgent.Value.Target.Get <Transform>().Position.Value - transform.Position);
                        }
                    },
                    new AI.Task
                    {
                        Action = delegate()
                        {
                            if ((ai.TargetAgent.Value.Target.Get <Transform>().Position.Value - transform.Position).Length() < 10.0f)
                            {
                                ai.CurrentState.Value = "Explode";
                            }
                        }
                    },
                    updatePosition,
                },
            });

            EffectBlockFactory factory = Factory.Get <EffectBlockFactory>();

            ai.Add(new AI.AIState
            {
                Name  = "Explode",
                Enter = delegate(AI.AIState previous)
                {
                    exploder.CoordQueue.Clear();

                    Entity voxelEntity = raycastAI.Voxel.Value.Target;
                    if (voxelEntity == null || !voxelEntity.Active)
                    {
                        ai.CurrentState.Value = "Alert";
                        return;
                    }

                    Voxel m = voxelEntity.Get <Voxel>();

                    Voxel.Coord c = raycastAI.Coord.Value;

                    Direction toSupport = Direction.None;

                    foreach (Direction dir in DirectionExtensions.Directions)
                    {
                        if (m[raycastAI.Coord.Value.Move(dir)].ID != 0)
                        {
                            toSupport = dir;
                            break;
                        }
                    }

                    if (toSupport == Direction.None)
                    {
                        ai.CurrentState.Value = "Alert";
                        return;
                    }

                    Direction up = toSupport.GetReverse();

                    exploder.ExplosionOriginalCoord.Value = raycastAI.Coord;

                    Direction right;
                    if (up.IsParallel(Direction.PositiveX))
                    {
                        right = Direction.PositiveZ;
                    }
                    else
                    {
                        right = Direction.PositiveX;
                    }
                    Direction forward = up.Cross(right);

                    for (Voxel.Coord y = c.Clone(); y.GetComponent(up) < c.GetComponent(up) + 3; y = y.Move(up))
                    {
                        for (Voxel.Coord x = y.Clone(); x.GetComponent(right) < c.GetComponent(right) + 2; x = x.Move(right))
                        {
                            for (Voxel.Coord z = x.Clone(); z.GetComponent(forward) < c.GetComponent(forward) + 2; z = z.Move(forward))
                            {
                                exploder.CoordQueue.Add(z);
                            }
                        }
                    }
                },
                Exit = delegate(AI.AIState next)
                {
                    exploder.CoordQueue.Clear();
                },
                Tasks = new[]
                {
                    checkOperationalRadius,
                    new AI.Task
                    {
                        Interval = 0.15f,
                        Action   = delegate()
                        {
                            if (exploder.CoordQueue.Length > 0)
                            {
                                raycastAI.MoveTo(exploder.CoordQueue[0]);

                                exploder.CoordQueue.RemoveAt(0);

                                Entity blockEntity = factory.CreateAndBind(main);
                                Voxel.States.Infected.ApplyToEffectBlock(blockEntity.Get <ModelInstance>());

                                Entity mapEntity = raycastAI.Voxel.Value.Target;
                                if (mapEntity != null && mapEntity.Active)
                                {
                                    EffectBlock effectBlock = blockEntity.Get <EffectBlock>();
                                    Voxel m = mapEntity.Get <Voxel>();

                                    effectBlock.Offset.Value = m.GetRelativePosition(raycastAI.Coord);

                                    Vector3 absolutePos = m.GetAbsolutePosition(raycastAI.Coord);

                                    effectBlock.StartPosition    = absolutePos + new Vector3(0.05f, 0.1f, 0.05f);
                                    effectBlock.StartOrientation = Quaternion.CreateFromYawPitchRoll(0.15f, 0.15f, 0);
                                    effectBlock.TotalLifetime    = 0.05f;
                                    effectBlock.Setup(raycastAI.Voxel.Value.Target, raycastAI.Coord, Voxel.t.Infected);
                                    main.Add(blockEntity);
                                }
                            }
                        }
                    },
                    new AI.Task
                    {
                        Action = delegate()
                        {
                            AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, MathHelper.Lerp(0.0f, 1.0f, ai.TimeInCurrentState.Value / 2.0f), entity);
                            if (exploder.CoordQueue.Length == 0)
                            {
                                // Explode
                                ai.CurrentState.Value = "Exploding";
                            }
                        },
                    },
                    updatePosition,
                },
            });

            ai.Add(new AI.AIState
            {
                Name  = "Exploding",
                Enter = delegate(AI.AIState previous)
                {
                    exploder.Exploded.Value = false;
                    AkSoundEngine.PostEvent(AK.EVENTS.STOP_GLOWSQUARE, entity);
                },
                Exit = delegate(AI.AIState next)
                {
                    exploder.Exploded.Value = false;
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_GLOWSQUARE, entity);
                },
                Tasks = new[]
                {
                    new AI.Task
                    {
                        Interval = 0.1f,
                        Action   = delegate()
                        {
                            const int radius = 9;

                            float timeInCurrentState = ai.TimeInCurrentState;
                            if (timeInCurrentState > 1.0f && !exploder.Exploded)
                            {
                                Entity mapEntity = raycastAI.Voxel.Value.Target;
                                if (mapEntity != null && mapEntity.Active)
                                {
                                    Explosion.Explode(main, mapEntity.Get <Voxel>(), raycastAI.Coord, radius, 18.0f);
                                }

                                exploder.Exploded.Value = true;
                            }

                            if (timeInCurrentState > 2.0f)
                            {
                                raycastAI.Move(new Vector3(((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f));
                                ai.CurrentState.Value = "Alert";
                            }
                        },
                    },
                    updatePosition,
                },
            });

            this.SetMain(entity, main);

            entity.Add("OperationalRadius", movement.OperationalRadius);
        }