Пример #1
0
 public PlaceBlockSpell(string voxelType, bool transmute)
 {
     Texture2D icons = TextureManager.GetTexture(ContentPaths.GUI.icons);
     Image = new ImageFrame(icons, 32, 1, 2);
     VoxelType = voxelType;
     Transmute = transmute;
     if (!transmute)
     {
         Name = VoxelType + " Wall";
         Description = "Create a wall of " + VoxelType;
         Hint = "Click and drag to place " + VoxelType;
         Recharges = false;
         RechargeTimer = new Timer(5.0f, false);
         ManaCost = 15;
         Mode = SpellMode.SelectEmptyVoxels;
     }
     else
     {
         Name = "Transmute " + VoxelType;
         Description = "Transmute any block into " + VoxelType;
         Hint = "Click and drag to transmute.";
         Recharges = false;
         RechargeTimer = new Timer(5.0f, false);
         ManaCost = 25;
         Mode = SpellMode.SelectFilledVoxels;
     }
 }
Пример #2
0
        public BearTrap(Vector3 pos)
            : base("BearTrap", PlayState.ComponentManager.RootComponent, Matrix.CreateTranslation(pos),
            new Vector3(1.0f, 1.0f, 1.0f), Vector3.Zero, true)
        {
            Allies = PlayState.PlayerFaction;
            Sensor = new Sensor("Sensor", this, Matrix.Identity, new Vector3(0.5f, 0.5f, 0.5f), Vector3.Zero)
            {
                FireTimer = new Timer(0.5f, false)
            };
            Sensor.OnSensed += Sensor_OnSensed;
            DeathTimer = new Timer(0.6f, true);
            DeathParticles = new ParticleTrigger("puff", PlayState.ComponentManager, "DeathParticles", this,
                Matrix.Identity, new Vector3(0.5f, 0.5f, 0.5f), Vector3.Zero)
            {
                SoundToPlay = ""
            };

            DamageAmount = 200;
            Voxel voxUnder = new Voxel();
            PlayState.ChunkManager.ChunkData.GetFirstVoxelUnder(pos, ref voxUnder);
            VoxListener = new VoxelListener(PlayState.ComponentManager, this, PlayState.ChunkManager, voxUnder);
            Sprite = new Sprite(PlayState.ComponentManager, "Sprite", this, Matrix.Identity, new SpriteSheet(ContentPaths.Entities.DwarfObjects.beartrap), false);
            Sprite.AddAnimation(new Animation(0, ContentPaths.Entities.DwarfObjects.beartrap, 32, 32,  0) {Name = IdleAnimation});
            Sprite.AddAnimation(new Animation(1, ContentPaths.Entities.DwarfObjects.beartrap, 32, 32,  0, 1, 2, 3) {Name = TriggerAnimation, Speeds =  new List<float>() {6.6f}, Loops = true});
        }
Пример #3
0
        public AnnouncementViewer(DwarfGUI gui, GUIComponent parent, AnnouncementManager manager)
            : base(gui, parent)
        {
            TweenTimer = new Timer(0.5f, true);
            TweenOutTimer = new Timer(0.5f, true);
            SpeechBubble = new Panel(gui, this)
            {
                Mode = Panel.PanelMode.SpeechBubble,
                DrawOrder = -2
            };
            SpeechBubble.IsVisible = false;
            Manager = manager;

            Manager.OnAdded += Manager_OnAdded;
            Manager.OnRemoved += Manager_OnRemoved;

            IsMaximized = false;

            AnnouncementViews = new List<AnnouncementView>();
            MaxViews = 4;
            WaitTimer = new Timer(5, true);
            Talker = new AnimatedImagePanel(GUI, this, animation);
            animation.Play();
            animation.Loops = true;
            animation.FrameHZ = 2.0f;
        }
Пример #4
0
 public InspectSpell(InspectType type)
 {
     Type = type;
     Texture2D icons = TextureManager.GetTexture(ContentPaths.GUI.icons);
     Recharges = false;
     switch (type)
     {
         case InspectType.InspectBlock:
         {
             Image = new ImageFrame(icons, 32, 7, 1);
             ManaCost = 0;
             Mode = Spell.SpellMode.SelectFilledVoxels;
             Name = "Inspect Blocks";
             Description = "Mouse over a block to get info about it";
             Hint = "Mouse over a block for info";
             RechargeTimer = new Timer(0.1f, true);
             break;
         }
         case InspectType.InspectEntity:
         {
             Image = new ImageFrame(icons, 32, 7, 1);
             ManaCost = 0;
             Mode = Spell.SpellMode.Continuous;
             Name = "Inspect Objects";
             Description = "Select an entity to get info about it";
             Hint = "Mouse over entities for info";
             RechargeTimer = new Timer(0.1f, true);
             break;
         }
     }
 }
Пример #5
0
 public TrapSensor(ComponentManager manager, string name, GameComponent parent, Matrix localTransform, Vector3 boundingBoxExtents, Vector3 boundingBoxPos)
     : base(name, parent, localTransform, boundingBoxExtents, boundingBoxPos)
 {
     OnSensed += TrapSensor_OnSensed;
     Tags.Add("Sensor");
     DrawBoundingBox = true;
     FireTimer = new Timer(0.5f, false);
 }
Пример #6
0
 public EnemySensor()
     : base()
 {
     Enemies = new List<CreatureAI>();
     OnEnemySensed += EnemySensor_OnEnemySensed;
     SenseTimer = new Timer(0.5f, false);
     SenseRadius = 15 * 15;
 }
Пример #7
0
 public ToolTipManager(DwarfGUI gui)
 {
     GUI = gui;
     HoverTimer = new Timer(0.8f, true, Timer.TimerMode.Real);
     ToolTip = "";
     LastMouse = Mouse.GetState();
     MovementThreshold = 2;
     PopupTimer = new Timer(2.5f, true, Timer.TimerMode.Real);
 }
Пример #8
0
 public ShipmentOrder(float time, Room destination)
 {
     BuyOrder = new List<ResourceAmount>();
     SellOrder = new List<ResourceAmount>();
     OrderTotal = 0.0f;
     OrderTimer = new Timer(time, true);
     Destination = destination;
     HasSentResources = false;
 }
Пример #9
0
 public EnemySensor(ComponentManager manager, string name, GameComponent parent, Matrix localTransform, Vector3 boundingBoxExtents, Vector3 boundingBoxPos)
     : base(name, parent, localTransform, boundingBoxExtents, boundingBoxPos)
 {
     Enemies = new List<CreatureAI>();
     OnEnemySensed += EnemySensor_OnEnemySensed;
     Tags.Add("Sensor");
     SenseTimer = new Timer(0.5f, false);
     SenseRadius = 15 * 15;
 }
Пример #10
0
 public Shadow(ComponentManager manager, string name, GameComponent parent, Matrix localTransform, SpriteSheet spriteSheet)
     : base(manager, name, parent, localTransform, spriteSheet, false)
 {
     OrientationType = OrientMode.Fixed;
     GlobalScale = LocalTransform.Left.Length();
     LightsWithVoxels = false;
     UpdateTimer = new Timer(0.5f, false);
     Tint = Color.Black;
     OriginalTransform = LocalTransform;
 }
Пример #11
0
 public NecromancerAI()
 {
     Skeletons = new List<Skeleton>();
     MaxSkeletons = 5;
     SummonTimer = new Timer(5, false);
     WanderTimer = new Timer(1, false);
     AttackTimer = new Timer(3, false);
     SummonTimer.HasTriggered = true;
     AttackRange = 10;
 }
Пример #12
0
 public ResourceInfoComponent(DwarfGUI gui, GUIComponent parent, Faction faction)
     : base(gui, parent)
 {
     Faction = faction;
     UpdateTimer = new Timer(0.5f, false);
     Layout = new GridLayout(gui, this, 1, 1);
     CurrentResources = new List<ResourceAmount>();
     PanelWidth = 40;
     PanelHeight = 40;
 }
Пример #13
0
 public Fairy(string allies, Vector3 position)
     : base(new CreatureStats(new FairyClass(), 0), "Player", PlayState.PlanService, PlayState.ComponentManager.Factions.Factions[allies],
    new Physics("Fairy", PlayState.ComponentManager.RootComponent, Matrix.CreateTranslation(position),
                new Vector3(0.5f, 0.5f, 0.5f), new Vector3(0.0f, -0.25f, 0.0f), 1.0f, 1.0f, 0.999f, 0.999f, new Vector3(0, 0, 0)),
       PlayState.ChunkManager, GameState.Game.GraphicsDevice, GameState.Game.Content, "Fairy")
 {
     ParticleTimer = new Timer(0.2f, false);
     DeathTimer = new Timer(30.0f, true);
     Initialize(new FairyClass());
 }
Пример #14
0
 public NecromancerAI(Creature creature, string name, EnemySensor sensor, PlanService planService)
     : base(creature, name, sensor, planService)
 {
     Skeletons = new List<Skeleton>();
     MaxSkeletons = 5;
     SummonTimer = new Timer(5, false);
     WanderTimer = new Timer(1, false);
     AttackTimer = new Timer(3, false);
     SummonTimer.HasTriggered = true;
     AttackRange = 10;
 }
Пример #15
0
 public Flammable(ComponentManager manager, string name, Body parent, Health health)
     : base(name, parent)
 {
     LocParent = parent;
     Heat = 0.0f;
     Flashpoint = 100.0f;
     Damage = 50.0f;
     Health = health;
     CheckLavaTimer = new Timer(1.0f, false);
     SoundTimer = new Timer(1.0f, false);
     DamageTimer = new Timer(1.0f, false);
 }
Пример #16
0
 public Tinter(string name, GameComponent parent, Matrix localTransform, Vector3 boundingBoxExtents, Vector3 boundingBoxPos, bool collisionManager)
     : base(name, parent, localTransform, boundingBoxExtents, boundingBoxPos, collisionManager)
 {
     LightsWithVoxels = true;
     Tint = new Color(255, 255, 0);
     LightingTimer = new Timer(0.2f, true);
     StartTimer = new Timer(0.5f, true);
     TargetTint = Tint;
     TintChangeRate = 1.0f;
     LightsWithVoxels = true;
     VoxelUnder = new Voxel();
 }
Пример #17
0
 public FlyWanderAct(CreatureAI creature, float seconds, float turnTime, float radius, float altitude)
     : base(creature)
 {
     Altitude = altitude;
     Name = "FlyWander " + seconds;
     WanderTime = new Timer(seconds, false);
     TurnTime = new Timer(turnTime, false);
     Radius = radius;
     YRadius = 2.0f;
     GravityCompensation = 0.1f;
     Damping = 0.25f;
     TurnThreshold = 2.0f;
 }
Пример #18
0
        public Tree(Vector3 position, string asset, float treeSize)
            : base("Tree", PlayState.ComponentManager.RootComponent, Matrix.Identity, new Vector3(treeSize * 2, treeSize * 3, treeSize * 2), new Vector3(treeSize * 0.5f, treeSize * 0.25f, treeSize * 0.5f))
        {
            HurtTimer = new Timer(1.0f, false);
            ComponentManager componentManager = PlayState.ComponentManager;
            Matrix matrix = Matrix.Identity;
            matrix.Translation = position;
            LocalTransform = matrix;

            new Mesh(componentManager, "Model", this, Matrix.CreateRotationY((float)(PlayState.Random.NextDouble() * Math.PI)) * Matrix.CreateScale(treeSize, treeSize, treeSize) * Matrix.CreateTranslation(new Vector3(0.7f, 0.0f, 0.7f)), asset, false);

            Health health = new Health(componentManager, "HP", this, 100.0f * treeSize, 0.0f, 100.0f * treeSize);

            new Flammable(componentManager, "Flames", this, health);

            Tags.Add("Vegetation");
            Tags.Add("EmitsWood");

            new MinimapIcon(this, new ImageFrame(TextureManager.GetTexture(ContentPaths.GUI.map_icons), 16, 1, 0));
            Voxel voxelUnder = new Voxel();

            if (PlayState.ChunkManager.ChunkData.GetFirstVoxelUnder(position, ref voxelUnder))
            {
                new VoxelListener(componentManager, this, PlayState.ChunkManager, voxelUnder);
            }

            Inventory inventory = new Inventory("Inventory", this)
            {
                Resources = new ResourceContainer
                {
                    MaxResources = (int)(treeSize * 10)
                }
            };

            inventory.Resources.AddResource(new ResourceAmount()
            {
                NumResources = (int)(treeSize * 10),
                ResourceType = ResourceLibrary.Resources[ResourceLibrary.ResourceType.Wood]
            });

            Particles = new ParticleTrigger("Leaves", componentManager, "LeafEmitter", this,
                Matrix.Identity, new Vector3(treeSize * 2, treeSize * 3, treeSize * 2), new Vector3(treeSize * 0.5f, treeSize * 0.25f, treeSize * 0.5f))
            {
                SoundToPlay = ContentPaths.Audio.vegetation_break
            };

            AddToCollisionManager = true;
            CollisionType = CollisionManager.CollisionType.Static;
        }
Пример #19
0
 public Attack(Attack other)
 {
     Name = other.Name;
     DamageAmount = other.DamageAmount;
     Range = other.Range;
     HitNoise = other.HitNoise;
     RechargeTimer = new Timer(other.RechargeRate + MathFunctions.Rand(-0.2f, 0.2f), false);
     Mode = other.Mode;
     Knockback = other.Knockback;
     HitAnimation = other.HitAnimation;
     HitParticles = other.HitParticles;
     ProjectileType = other.ProjectileType;
     LaunchSpeed = other.LaunchSpeed;
     AnimationAsset = other.AnimationAsset;
 }
Пример #20
0
 public Attack(string name, float damage, float time, float range, string noise, string animation)
 {
     Name = name;
     DamageAmount = damage;
     RechargeTimer = new Timer(time + MathFunctions.Rand(-0.2f, 0.2f), false);
     Range = range;
     HitNoise = noise;
     Mode = AttackMode.Melee;
     Knockback = 0.0f;
     HitAnimation = null;
     HitParticles = "";
     ProjectileType = "";
     AnimationAsset = animation;
     CreateHitAnimation();
 }
Пример #21
0
 public PlanAct(CreatureAI agent, string pathOut, string target, PlanType planType)
     : base(agent)
 {
     Type = planType;
     Name = "Plan to " + target;
     PlannerTimer = new Timer(1.0f, false);
     MaxExpansions = 1000;
     PathOut = pathOut;
     TargetName = target;
     PlanSubscriber = new PlanSubscriber(PlayState.PlanService);
     WaitingOnResponse = false;
     MaxTimeouts = 4;
     Timeouts = 0;
     Radius = 0;
 }
Пример #22
0
        IEnumerable<Act.Status> ChirpRandomly()
        {
            Timer chirpTimer = new Timer(MathFunctions.Rand(6f, 10f), false);
            while (true)
            {
                chirpTimer.Update(DwarfTime.LastTime);
                if (chirpTimer.HasTriggered)
                {
                    Creature.NoiseMaker.MakeNoise("chirp", Creature.AI.Position, true, 0.5f);
                }
                yield return Act.Status.Running;
            }

            yield return Act.Status.Success;
        }
Пример #23
0
        public override IEnumerable<Status> Run()
        {
            Timer waitTimer = new Timer(1.0f, true);
            bool removed = Agent.Faction.RemoveResources(Resources, Agent.Position);

            if(!removed)
            {
                yield return Status.Fail;
            }
            else
            {
                foreach(ResourceAmount resource in Resources)
                {
                    Agent.Creature.Inventory.Resources.AddResource(resource.CloneResource());
                }

                while (!waitTimer.HasTriggered)
                {
                    waitTimer.Update(DwarfTime.LastTime);
                    yield return Status.Running;
                }
                yield return Status.Success;
            }
        }
Пример #24
0
 public MotionAnimation(float time, bool loop)
 {
     Time = new Timer(time, !loop);
     OnComplete += MotionAnimation_OnComplete;
 }
Пример #25
0
 public GUITween(float time)
 {
     TweenTimer = new Timer(time, true, Timer.TimerMode.Real);
 }
Пример #26
0
        public IEnumerable <Status> AvoidTarget(float range, float time)
        {
            if (Target == null)
            {
                yield return(Status.Fail);

                yield break;
            }

            Timer avoidTimer = new Timer(time, true, Timer.TimerMode.Game);

            while (true)
            {
                avoidTimer.Update(DwarfTime.LastTime);

                if (avoidTimer.HasTriggered)
                {
                    yield return(Status.Success);
                }

                float dist = (Target.Position - Agent.Position).Length();

                if (dist > range)
                {
                    yield return(Status.Success);

                    yield break;
                }

                List <MoveAction> neighbors = Agent.Movement.GetMoveActions(Agent.Position, Creature.World.OctTree).ToList();
                neighbors.Sort((a, b) =>
                {
                    if (a.Equals(b))
                    {
                        return(0);
                    }

                    float da = (a.DestinationVoxel.WorldPosition - Target.Position).LengthSquared();
                    float db = (b.DestinationVoxel.WorldPosition - Target.Position).LengthSquared();

                    return(da.CompareTo(db));
                });

                neighbors.RemoveAll(
                    a => a.MoveType == MoveType.Jump || a.MoveType == MoveType.Climb);

                if (neighbors.Count == 0)
                {
                    yield return(Status.Fail);

                    yield break;
                }

                MoveAction furthest      = neighbors.Last();
                bool       reachedTarget = false;
                Timer      timeout       = new Timer(2.0f, true, Timer.TimerMode.Real);
                while (!reachedTarget)
                {
                    Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, furthest.DestinationVoxel.WorldPosition + Vector3.One * 0.5f,
                                                                   Agent.Position);
                    Creature.Physics.ApplyForce(output, DwarfTime.Dt);

                    if (Creature.AI.Movement.CanFly)
                    {
                        Creature.Physics.ApplyForce(Vector3.Up * 10, DwarfTime.Dt);
                    }

                    timeout.Update(DwarfTime.LastTime);

                    yield return(Status.Running);

                    if (timeout.HasTriggered || (furthest.DestinationVoxel.WorldPosition - Agent.Position).Length() < 1)
                    {
                        reachedTarget = true;
                    }

                    Agent.Creature.CurrentCharacterMode = CharacterMode.Walking;
                }

                yield return(Status.Success);

                yield break;
            }
        }
Пример #27
0
 public Attack(Weapon Weapon)
 {
     this.Weapon   = Weapon;
     RechargeTimer = new Timer(Weapon.RechargeRate, false);
 }
Пример #28
0
        public IEnumerable<Status> WaitUntilBored()
        {
            Timer waitTimer = new Timer(SitTime, false);
            Timer eatTimer = new Timer(10.0f + MathFunctions.Rand(0, 1), false);
            Vector3 snapPosition = Agent.Position + new Vector3(0, 0.2f, 0);
            Body body = Creature.AI.Blackboard.GetData<Body>("Chair");

            if (body == null || body.IsDead)
            {
                Creature.OverrideCharacterMode = false;
                yield return Status.Success;
                yield break;
            }

            while (true)
            {
                if (Creature.AI.Tasks.Count > 1)
                {
                    Creature.OverrideCharacterMode = false;
                    yield return Status.Success;
                }

                if (Creature.AI.Status.Energy.IsUnhappy())
                {
                    Creature.OverrideCharacterMode = false;
                    yield return Status.Success;
                }

                if (Creature.AI.Status.Hunger.IsUnhappy())
                {
                    Creature.OverrideCharacterMode = false;
                    yield return Status.Success;
                }

                if (Creature.AI.Sensor.Enemies.Count > 0)
                {
                    Creature.OverrideCharacterMode = false;
                    yield return Status.Success;
                }

                waitTimer.Update(DwarfTime.LastTime);

                if (waitTimer.HasTriggered)
                {
                    Creature.OverrideCharacterMode = false;
                    yield return Status.Success;
                }

                ConverseFriends();

                eatTimer.Update(DwarfTime.LastTime);

                if(eatTimer.HasTriggered)
                    foreach (Act.Status status in EatFood())
                    {
                        if (status == Act.Status.Running)
                        {
                            Creature.OverrideCharacterMode = false;
                            yield return Act.Status.Running;
                        }
                    }

                Agent.Position = snapPosition;
                Agent.Physics.IsSleeping = true;
                Creature.CurrentCharacterMode = Creature.CharacterMode.Sitting;
                Creature.OverrideCharacterMode = true;
                yield return Status.Running;
            }
        }
Пример #29
0
        public override IEnumerable<Act.Status> Run()
        {
            if (Spell.IsResearched)
            {
                Creature.CurrentCharacterMode = Creature.CharacterMode.Idle;
                Creature.OverrideCharacterMode = false;
                yield return Status.Success;
                yield break;
            }
            Timer starParitcle = new Timer(0.5f, false);
            float totalResearch = 0.0f;
            while (!Spell.IsResearched)
            {
                Creature.CurrentCharacterMode = Creature.CharacterMode.Attacking;
                Creature.OverrideCharacterMode = true;
                float research = Creature.Stats.BuffedInt * 0.25f * DwarfTime.Dt;
                Spell.ResearchProgress += research;
                totalResearch += research;
                Creature.Physics.Velocity *= 0;
                if ((int) totalResearch > 0)
                {
                    SoundManager.PlaySound(ContentPaths.Audio.tinkle, Creature.AI.Position, true);
                    Creature.AI.AddXP((int)(totalResearch));
                    totalResearch = 0.0f;
                }

                if (Spell.ResearchProgress >= Spell.ResearchTime)
                {
                    PlayState.AnnouncementManager.Announce("Researched " + Spell.Spell.Name, Creature.Stats.FullName + " (" + Creature.Stats.CurrentLevel.Name + ")" + " discovered the " + Spell.Spell.Name + " spell!", Agent.ZoomToMe);
                }

                starParitcle.Update(DwarfTime.LastTime);
                if(starParitcle.HasTriggered)
                    PlayState.ParticleManager.Trigger("star_particle", Creature.AI.Position, Color.White, 3);
                yield return Status.Running;
            }
            Creature.AI.AddThought(Thought.ThoughtType.Researched);
            Creature.OverrideCharacterMode = false;
            Creature.CurrentCharacterMode = Creature.CharacterMode.Idle;
            yield return Status.Success;
            yield break;
        }
Пример #30
0
 public Wait(Timer time)
 {
     Name = "Wait " + time.TargetTimeSeconds;
     Time = time;
 }
Пример #31
0
 public SummoningCircle()
 {
     ParticleTimer = new Timer(0.5f + MathFunctions.Rand(-0.25f, 0.25f), false);
 }
Пример #32
0
        public ComboBoxSelector(DwarfGUI gui, ComboBox parent, List<string> values, string currentValue)
            : base(gui, parent)
        {
            Columns = new List<List<string>>();
            Values = values;
            CurrentValue = currentValue;

            int height = 0;
            Columns.Add(new List<string>());
            int currentColumn = 0;
            int columnWidth = parent.GlobalBounds.Width - 37;
            ColumnWidth = columnWidth;
            int bestHeight = 0;
            foreach(string s in values)
            {
                List<string> column = Columns[currentColumn];
                Vector2 measure = Datastructures.SafeMeasure(GUI.DefaultFont, s);
                height += (int) measure.Y;
                column.Add(s);

                if(height > bestHeight)
                {
                    bestHeight = height;
                }

                if(height >= MaxHeight)
                {
                    height = 0;
                    Columns.Add(new List<string>());
                    currentColumn++;
                    columnWidth += ColumnWidth;
                }
            }

            List<List<string>> removals = new List<List<string>>();

            foreach(List<string> column in Columns)
            {
                if(column.Count == 0)
                {
                    removals.Add(column);
                }
            }

            foreach(List<string> column in removals)
            {
                Columns.Remove(column);
                columnWidth -= ColumnWidth;
            }

            bestHeight += 15;

            LocalBounds = new Rectangle(0, parent.GlobalBounds.Height / 2 + GUI.Skin.TileHeight / 2, columnWidth, bestHeight);
            Box = parent;

            ClickTimer = new Timer(0.1f, true, Timer.TimerMode.Real);
            InputManager.MouseClickedCallback += InputManager_MouseClickedCallback;
            Drawn = true;
        }
Пример #33
0
        public virtual void Update(DwarfTime gameTime, Timer.TimerMode mode = Timer.TimerMode.Game)
        {
            if(IsPlaying)
            {
                float dt = mode == Timer.TimerMode.Game ? (float)gameTime.ElapsedGameTime.TotalSeconds : (float)gameTime.ElapsedRealTime.TotalSeconds;
                FrameTimer += dt;

                float time = FrameHZ;

                if (Speeds.Count > 0)
                {
                    time = Speeds[Math.Min(CurrentFrame, Speeds.Count - 1)];
                }
                if(FrameTimer * SpeedMultiplier >= 1.0f / time)
                {
                    NextFrame();
                    FrameTimer = 0.0f;
                }
            }
        }
Пример #34
0
        public override IEnumerable <Status> Run()
        {
            Creature.IsCloaked = false;

            if (CurrentAttack == null)
            {
                yield return(Status.Fail);

                yield break;
            }

            Timeout.Reset();
            FailTimer.Reset();
            if (Target == null && TargetName != null)
            {
                Target = Agent.Blackboard.GetData <Body>(TargetName);

                if (Target == null)
                {
                    yield return(Status.Fail);

                    yield break;
                }
            }

            if (Agent.Faction.Race.IsIntelligent)
            {
                var targetInventory = Target.GetRoot().GetComponent <Inventory>();
                if (targetInventory != null)
                {
                    targetInventory.SetLastAttacker(Agent);
                }
            }

            CharacterMode defaultCharachterMode = Creature.AI.Movement.CanFly
                ? CharacterMode.Flying
                : CharacterMode.Walking;

            bool avoided = false;

            while (true)
            {
                Timeout.Update(DwarfTime.LastTime);
                FailTimer.Update(DwarfTime.LastTime);
                if (FailTimer.HasTriggered)
                {
                    Creature.Physics.Orientation   = Physics.OrientMode.RotateY;
                    Creature.OverrideCharacterMode = false;
                    Creature.CurrentCharacterMode  = defaultCharachterMode;
                    yield return(Status.Fail);

                    yield break;
                }

                if (Timeout.HasTriggered)
                {
                    if (Training)
                    {
                        Agent.AddXP(1);
                        Creature.Physics.Orientation   = Physics.OrientMode.RotateY;
                        Creature.OverrideCharacterMode = false;
                        Creature.CurrentCharacterMode  = defaultCharachterMode;
                        yield return(Status.Success);

                        yield break;
                    }
                    else
                    {
                        Creature.Physics.Orientation   = Physics.OrientMode.RotateY;
                        Creature.OverrideCharacterMode = false;
                        Creature.CurrentCharacterMode  = defaultCharachterMode;
                        yield return(Status.Fail);

                        yield break;
                    }
                }

                if (Target == null || Target.IsDead)
                {
                    Creature.CurrentCharacterMode = defaultCharachterMode;
                    Creature.Physics.Orientation  = Physics.OrientMode.RotateY;
                    yield return(Status.Success);
                }

                // Find the location of the melee target
                Vector3 targetPos = new Vector3(Target.GlobalTransform.Translation.X,
                                                Target.GetBoundingBox().Min.Y,
                                                Target.GlobalTransform.Translation.Z);

                Vector2 diff = new Vector2(targetPos.X, targetPos.Z) - new Vector2(Creature.AI.Position.X, Creature.AI.Position.Z);

                Creature.Physics.Face(targetPos);

                bool intersectsbounds = Creature.Physics.BoundingBox.Intersects(Target.BoundingBox);

                // If we are really far from the target, something must have gone wrong.
                if (!intersectsbounds && diff.Length() > CurrentAttack.Range * 4)
                {
                    Creature.Physics.Orientation   = Physics.OrientMode.RotateY;
                    Creature.OverrideCharacterMode = false;
                    Creature.CurrentCharacterMode  = defaultCharachterMode;
                    yield return(Status.Fail);

                    yield break;
                }

                // If we're out of attack range, run toward the target.
                if (!Creature.AI.Movement.IsSessile && !intersectsbounds && diff.Length() > CurrentAttack.Range)
                {
                    Creature.CurrentCharacterMode = defaultCharachterMode;

                    /*
                     * Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, targetPos, Creature.Physics.GlobalTransform.Translation) * 0.9f;
                     * output.Y = 0.0f;
                     * if (Creature.AI.Movement.CanFly)
                     * {
                     *  Creature.Physics.ApplyForce(-Creature.Physics.Gravity, DwarfTime.Dt);
                     * }
                     * if (Creature.AI.Movement.IsSessile)
                     * {
                     *  output *= 0.0f;
                     * }
                     * Creature.Physics.ApplyForce(output, DwarfTime.Dt);
                     * Creature.Physics.Orientation = Physics.OrientMode.RotateY;
                     */
                    GreedyPathAct greedyPath = new GreedyPathAct(Creature.AI, Target, CurrentAttack.Range * 0.75f)
                    {
                        PathLength = 5
                    };
                    greedyPath.Initialize();

                    foreach (Act.Status stat in greedyPath.Run())
                    {
                        if (stat == Act.Status.Running)
                        {
                            yield return(Status.Running);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                // If we have a ranged weapon, try avoiding the target for a few seconds to get within range.
                else if (!Creature.AI.Movement.IsSessile && !intersectsbounds && !avoided && (CurrentAttack.Mode == Attack.AttackMode.Ranged &&
                                                                                              diff.Length() < CurrentAttack.Range * 0.15f))
                {
                    FailTimer.Reset();
                    foreach (Act.Status stat in AvoidTarget(CurrentAttack.Range, 3.0f))
                    {
                        yield return(Status.Running);
                    }
                    avoided = true;
                }
                // Else, stop and attack
                else
                {
                    if (CurrentAttack.Mode == Attack.AttackMode.Ranged &&
                        VoxelHelpers.DoesRayHitSolidVoxel(Creature.World.ChunkManager.ChunkData,
                                                          Creature.AI.Position, Target.Position))
                    {
                        yield return(Status.Fail);

                        yield break;
                    }

                    FailTimer.Reset();
                    avoided = false;
                    Creature.Physics.Orientation = Physics.OrientMode.Fixed;
                    Creature.Physics.Velocity    = new Vector3(Creature.Physics.Velocity.X * 0.9f, Creature.Physics.Velocity.Y, Creature.Physics.Velocity.Z * 0.9f);
                    CurrentAttack.RechargeTimer.Reset(CurrentAttack.RechargeRate);

                    Creature.Sprite.ResetAnimations(Creature.AttackMode);
                    Creature.Sprite.PlayAnimations(Creature.AttackMode);
                    Creature.CurrentCharacterMode  = Creature.AttackMode;
                    Creature.OverrideCharacterMode = true;
                    Timer timeout = new Timer(10.0f, true);
                    while (!CurrentAttack.Perform(Creature, Target, DwarfTime.LastTime, Creature.Stats.BuffedStr + Creature.Stats.BuffedSiz,
                                                  Creature.AI.Position, Creature.Faction.Name))
                    {
                        timeout.Update(DwarfTime.LastTime);
                        if (timeout.HasTriggered)
                        {
                            break;
                        }

                        Creature.Physics.Velocity = new Vector3(Creature.Physics.Velocity.X * 0.9f, Creature.Physics.Velocity.Y, Creature.Physics.Velocity.Z * 0.9f);
                        if (Creature.AI.Movement.CanFly)
                        {
                            Creature.Physics.ApplyForce(-Creature.Physics.Gravity * 0.1f, DwarfTime.Dt);
                        }
                        yield return(Status.Running);
                    }

                    timeout.Reset();
                    while (!Agent.Creature.Sprite.AnimPlayer.IsDone())
                    {
                        timeout.Update(DwarfTime.LastTime);
                        if (timeout.HasTriggered)
                        {
                            break;
                        }
                        if (Creature.AI.Movement.CanFly)
                        {
                            Creature.Physics.ApplyForce(-Creature.Physics.Gravity * 0.1f, DwarfTime.Dt);
                        }
                        yield return(Status.Running);
                    }

                    var targetCreature = Target.GetRoot().GetComponent <CreatureAI>();
                    if (targetCreature != null && !Creature.AI.FightOrFlight(targetCreature))
                    {
                        yield return(Act.Status.Fail);

                        yield break;
                    }
                    Creature.CurrentCharacterMode = CharacterMode.Attacking;

                    Vector3 dogfightTarget = Vector3.Zero;
                    while (!CurrentAttack.RechargeTimer.HasTriggered && !Target.IsDead)
                    {
                        CurrentAttack.RechargeTimer.Update(DwarfTime.LastTime);
                        if (CurrentAttack.Mode == Attack.AttackMode.Dogfight)
                        {
                            dogfightTarget += MathFunctions.RandVector3Cube() * 0.1f;
                            Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, dogfightTarget + Target.Position, Creature.Physics.GlobalTransform.Translation) * 0.9f;
                            Creature.Physics.ApplyForce(output - Creature.Physics.Gravity, DwarfTime.Dt);
                        }
                        else
                        {
                            Creature.Physics.Velocity = Vector3.Zero;
                            if (Creature.AI.Movement.CanFly)
                            {
                                Creature.Physics.ApplyForce(-Creature.Physics.Gravity, DwarfTime.Dt);
                            }
                        }
                        yield return(Status.Running);
                    }

                    Creature.CurrentCharacterMode = defaultCharachterMode;
                    Creature.Physics.Orientation  = Physics.OrientMode.RotateY;

                    if (Target.IsDead)
                    {
                        Target = null;
                        Agent.AddXP(10);
                        Creature.Physics.Face(Creature.Physics.Velocity + Creature.Physics.GlobalTransform.Translation);
                        Creature.Stats.NumThingsKilled++;
                        Creature.AddThought(Thought.ThoughtType.KilledThing);
                        Creature.Physics.Orientation   = Physics.OrientMode.RotateY;
                        Creature.OverrideCharacterMode = false;
                        Creature.CurrentCharacterMode  = defaultCharachterMode;
                        yield return(Status.Success);

                        break;
                    }
                }

                yield return(Status.Running);
            }
        }