Example #1
0
        internal Actor(World world, string name, TypeDictionary initDict)
        {
            var init = new ActorInitializer(this, initDict);

            World   = world;
            ActorID = world.NextAID();
            if (initDict.Contains <OwnerInit>())
            {
                Owner = init.Get <OwnerInit, Player>();
            }

            if (name != null)
            {
                name = name.ToLowerInvariant();

                if (!world.Map.Rules.Actors.ContainsKey(name))
                {
                    throw new NotImplementedException("No rules definition for unit " + name);
                }

                Info = world.Map.Rules.Actors[name];
                foreach (var trait in Info.TraitsInConstructOrder())
                {
                    AddTrait(trait.Create(init));

                    // Some traits rely on properties provided by IOccupySpace in their initialization,
                    // so we must ready it now, we cannot wait until all traits have finished construction.
                    if (trait is IOccupySpaceInfo)
                    {
                        OccupiesSpace = Trait <IOccupySpace>();
                    }
                }
            }

            // PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per
            // actor that allows us to provide some fast implementations of commonly used methods that are relied on by
            // performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering.
            EffectiveOwner      = TraitOrDefault <IEffectiveOwner>();
            facing              = TraitOrDefault <IFacing>();
            health              = TraitOrDefault <IHealth>();
            renderModifiers     = TraitsImplementing <IRenderModifier>().ToArray();
            renders             = TraitsImplementing <IRender>().ToArray();
            mouseBounds         = TraitsImplementing <IMouseBounds>().ToArray();
            visibilityModifiers = TraitsImplementing <IVisibilityModifier>().ToArray();
            defaultVisibility   = Trait <IDefaultVisibility>();
            Targetables         = TraitsImplementing <ITargetable>().ToArray();
            targetablePositions = TraitsImplementing <ITargetablePositions>().ToArray();
            world.AddFrameEndTask(w =>
            {
                // Caching this in a AddFrameEndTask, because trait construction order might cause problems if done directly at creation time.
                // All actors that can move or teleport should have IPositionable, if not it's pretty safe to assume the actor is completely immobile and
                // all targetable positions can be cached if all ITargetablePositions have no conditional requirements.
                if (!Info.HasTraitInfo <IPositionableInfo>() && targetablePositions.Any() && targetablePositions.All(tp => tp.AlwaysEnabled))
                {
                    staticTargetablePositions = targetablePositions.SelectMany(tp => tp.TargetablePositions(this)).ToArray();
                }
            });

            SyncHashes = TraitsImplementing <ISync>().Select(sync => new SyncHash(sync)).ToArray();
        }
Example #2
0
        internal Actor(World world, string name, TypeDictionary initDict)
        {
            var init = new ActorInitializer(this, initDict);

            World   = world;
            ActorID = world.NextAID();
            if (initDict.Contains <OwnerInit>())
            {
                Owner = init.Get <OwnerInit, Player>();
            }

            occupySpace = Lazy.New(() => TraitOrDefault <IOccupySpace>());

            if (name != null)
            {
                if (!Rules.Info.ContainsKey(name.ToLowerInvariant()))
                {
                    throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant()));
                }

                Info = Rules.Info[name.ToLowerInvariant()];
                foreach (var trait in Info.TraitsInConstructOrder())
                {
                    AddTrait(trait.Create(init));
                }
            }

            Move   = Lazy.New(() => TraitOrDefault <IMove>());
            Facing = Lazy.New(() => TraitOrDefault <IFacing>());

            Size = Lazy.New(() =>
            {
                var si = Info.Traits.GetOrDefault <SelectableInfo>();
                if (si != null && si.Bounds != null)
                {
                    return(new int2(si.Bounds[0], si.Bounds[1]));
                }

                return(TraitsImplementing <IAutoSelectionSize>().Select(x => x.SelectionSize(this)).FirstOrDefault());
            });

            if (this.HasTrait <RevealsShroud>())
            {
                Sight = new Shroud.ActorVisibility
                {
                    range = this.Trait <RevealsShroud>().RevealRange,
                    vis   = Shroud.GetVisOrigins(this).ToArray()
                };
            }

            ApplyIRender        = (x, wr) => x.Render(this, wr);
            ApplyRenderModifier = (m, p, wr) => p.ModifyRender(this, wr, m);

            Bounds         = Cached.New(() => CalculateBounds(false));
            ExtendedBounds = Cached.New(() => CalculateBounds(true));
        }
Example #3
0
        internal Actor(World world, string name, TypeDictionary initDict)
        {
            var init = new ActorInitializer(this, initDict);

            World   = world;
            ActorID = world.NextAID();
            if (initDict.Contains <OwnerInit>())
            {
                Owner = init.Get <OwnerInit, Player>();
            }

            if (name != null)
            {
                name = name.ToLowerInvariant();

                if (!world.Map.Rules.Actors.ContainsKey(name))
                {
                    throw new NotImplementedException("No rules definition for unit " + name);
                }

                Info = world.Map.Rules.Actors[name];
                foreach (var trait in Info.TraitsInConstructOrder())
                {
                    AddTrait(trait.Create(init));

                    // Some traits rely on properties provided by IOccupySpace in their initialization,
                    // so we must ready it now, we cannot wait until all traits have finished construction.
                    if (trait is IOccupySpaceInfo)
                    {
                        OccupiesSpace = Trait <IOccupySpace>();
                    }
                }
            }

            // PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per
            // actor that allows us to provide some fast implementations of commonly used methods that are relied on by
            // performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering.
            Bounds              = DetermineBounds();
            VisualBounds        = DetermineVisualBounds();
            EffectiveOwner      = TraitOrDefault <IEffectiveOwner>();
            facing              = TraitOrDefault <IFacing>();
            health              = TraitOrDefault <IHealth>();
            renderModifiers     = TraitsImplementing <IRenderModifier>().ToArray();
            renders             = TraitsImplementing <IRender>().ToArray();
            disables            = TraitsImplementing <IDisable>().ToArray();
            visibilityModifiers = TraitsImplementing <IVisibilityModifier>().ToArray();
            defaultVisibility   = Trait <IDefaultVisibility>();
            Targetables         = TraitsImplementing <ITargetable>().ToArray();

            SyncHashes =
                TraitsImplementing <ISync>()
                .Select(sync => Pair.New(sync, Sync.GetHashFunction(sync)))
                .ToArray()
                .Select(pair => new SyncHash(pair.First, pair.Second(pair.First)));
        }
Example #4
0
        internal Actor(World world, string name, TypeDictionary initDict)
        {
            var init = new ActorInitializer(this, initDict);

            World   = world;
            ActorID = world.NextAID();
            if (initDict.Contains <OwnerInit>())
            {
                Owner = init.Get <OwnerInit, Player>();
            }

            occupySpace = Lazy.New(() => TraitOrDefault <IOccupySpace>());

            if (name != null)
            {
                if (!Rules.Info.ContainsKey(name.ToLowerInvariant()))
                {
                    throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant()));
                }

                Info = Rules.Info[name.ToLowerInvariant()];
                foreach (var trait in Info.TraitsInConstructOrder())
                {
                    AddTrait(trait.Create(init));
                }
            }

            Move = Lazy.New(() => TraitOrDefault <IMove>());

            Size = Lazy.New(() =>
            {
                var si = Info.Traits.GetOrDefault <SelectableInfo>();
                if (si != null && si.Bounds != null)
                {
                    return(new int2(si.Bounds[0], si.Bounds[1]));
                }

                // auto size from render
                var firstSprite = TraitsImplementing <IRender>().SelectMany(ApplyIRender).FirstOrDefault();
                if (firstSprite.Sprite == null)
                {
                    return(int2.Zero);
                }
                return((firstSprite.Sprite.size * firstSprite.Scale).ToInt2());
            });

            ApplyIRender        = x => x.Render(this);
            ApplyRenderModifier = (m, p) => p.ModifyRender(this, m);

            Bounds         = Cached.New(() => CalculateBounds(false));
            ExtendedBounds = Cached.New(() => CalculateBounds(true));
        }
Example #5
0
        internal Actor(World world, string name, TypeDictionary initDict)
        {
            var init = new ActorInitializer(this, initDict);

            World   = world;
            ActorID = world.NextAID();
            if (initDict.Contains <OwnerInit>())
            {
                Owner = init.Get <OwnerInit, Player>();
            }

            occupySpace = Exts.Lazy(() => TraitOrDefault <IOccupySpace>());

            if (name != null)
            {
                name = name.ToLowerInvariant();

                if (!world.Map.Rules.Actors.ContainsKey(name))
                {
                    throw new NotImplementedException("No rules definition for unit " + name);
                }

                Info = world.Map.Rules.Actors[name];
                foreach (var trait in Info.TraitsInConstructOrder())
                {
                    AddTrait(trait.Create(init));
                }
            }

            facing         = Exts.Lazy(() => TraitOrDefault <IFacing>());
            health         = Exts.Lazy(() => TraitOrDefault <Health>());
            effectiveOwner = Exts.Lazy(() => TraitOrDefault <IEffectiveOwner>());

            bounds = Exts.Lazy(() =>
            {
                var si   = Info.Traits.GetOrDefault <SelectableInfo>();
                var size = (si != null && si.Bounds != null) ? new int2(si.Bounds[0], si.Bounds[1]) :
                           TraitsImplementing <IAutoSelectionSize>().Select(x => x.SelectionSize(this)).FirstOrDefault();

                var offset = -size / 2;
                if (si != null && si.Bounds != null && si.Bounds.Length > 2)
                {
                    offset += new int2(si.Bounds[2], si.Bounds[3]);
                }

                return(new Rectangle(offset.X, offset.Y, size.X, size.Y));
            });

            renderModifiers = TraitsImplementing <IRenderModifier>().ToArray();
            renders         = TraitsImplementing <IRender>().ToArray();
            disables        = TraitsImplementing <IDisable>().ToArray();
        }
Example #6
0
        internal Actor(World world, string name, TypeDictionary initDict)
        {
            var init = new ActorInitializer(this, initDict);

            World   = world;
            ActorID = world.NextAID();
            if (initDict.Contains <OwnerInit>())
            {
                Owner = init.Get <OwnerInit, Player>();
            }

            occupySpace = Lazy.New(() => TraitOrDefault <IOccupySpace>());

            if (name != null)
            {
                if (!Rules.Info.ContainsKey(name.ToLowerInvariant()))
                {
                    throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant()));
                }

                Info = Rules.Info[name.ToLowerInvariant()];
                foreach (var trait in Info.TraitsInConstructOrder())
                {
                    AddTrait(trait.Create(init));
                }
            }

            facing = Lazy.New(() => TraitOrDefault <IFacing>());
            health = Lazy.New(() => TraitOrDefault <Health>());

            applyIRender        = (x, wr) => x.Render(this, wr);
            applyRenderModifier = (m, p, wr) => p.ModifyRender(this, wr, m);

            Bounds = Lazy.New(() =>
            {
                var si   = Info.Traits.GetOrDefault <SelectableInfo>();
                var size = (si != null && si.Bounds != null) ? new int2(si.Bounds[0], si.Bounds[1]) :
                           TraitsImplementing <IAutoSelectionSize>().Select(x => x.SelectionSize(this)).FirstOrDefault();

                var offset = -size / 2;
                if (si != null && si.Bounds != null && si.Bounds.Length > 2)
                {
                    offset += new int2(si.Bounds[2], si.Bounds[3]);
                }

                return(new Rectangle(offset.X, offset.Y, size.X, size.Y));
            });
        }
Example #7
0
        internal Actor(World world, string name, TypeDictionary initDict)
        {
            var init = new ActorInitializer(this, initDict);

            World   = world;
            ActorID = world.NextAID();
            if (initDict.Contains <OwnerInit>())
            {
                Owner = init.Get <OwnerInit, Player>();
            }

            if (name != null)
            {
                name = name.ToLowerInvariant();

                if (!world.Map.Rules.Actors.ContainsKey(name))
                {
                    throw new NotImplementedException("No rules definition for unit " + name);
                }

                Info = world.Map.Rules.Actors[name];
                foreach (var trait in Info.TraitsInConstructOrder())
                {
                    AddTrait(trait.Create(init));

                    // Some traits rely on properties provided by IOccupySpace in their initialization,
                    // so we must ready it now, we cannot wait until all traits have finished construction.
                    if (trait is IOccupySpaceInfo)
                    {
                        OccupiesSpace = Trait <IOccupySpace>();
                    }
                }
            }

            Bounds              = DetermineBounds();
            VisualBounds        = DetermineVisualBounds();
            EffectiveOwner      = TraitOrDefault <IEffectiveOwner>();
            facing              = TraitOrDefault <IFacing>();
            health              = TraitOrDefault <IHealth>();
            renderModifiers     = TraitsImplementing <IRenderModifier>().ToArray();
            renders             = TraitsImplementing <IRender>().ToArray();
            disables            = TraitsImplementing <IDisable>().ToArray();
            visibilityModifiers = TraitsImplementing <IVisibilityModifier>().ToArray();
            defaultVisibility   = Trait <IDefaultVisibility>();
        }
Example #8
0
        internal Actor(World world, string name, TypeDictionary initDict)
        {
            var duplicateInit = initDict.WithInterface <ISingleInstanceInit>().GroupBy(i => i.GetType())
                                .FirstOrDefault(i => i.Count() > 1);

            if (duplicateInit != null)
            {
                throw new InvalidDataException("Duplicate initializer '{0}'".F(duplicateInit.Key.Name));
            }

            var init = new ActorInitializer(this, initDict);

            readOnlyConditionCache = new ReadOnlyDictionary <string, int>(conditionCache);

            World   = world;
            ActorID = world.NextAID();
            var ownerInit = init.GetOrDefault <OwnerInit>();

            if (ownerInit != null)
            {
                Owner = ownerInit.Value(world);
            }

            if (name != null)
            {
                name = name.ToLowerInvariant();

                if (!world.Map.Rules.Actors.ContainsKey(name))
                {
                    throw new NotImplementedException("No rules definition for unit " + name);
                }

                Info = world.Map.Rules.Actors[name];

                IPositionable positionable            = null;
                var           resolveOrdersList       = new List <IResolveOrder>();
                var           renderModifiersList     = new List <IRenderModifier>();
                var           rendersList             = new List <IRender>();
                var           mouseBoundsList         = new List <IMouseBounds>();
                var           visibilityModifiersList = new List <IVisibilityModifier>();
                var           becomingIdlesList       = new List <INotifyBecomingIdle>();
                var           tickIdlesList           = new List <INotifyIdle>();
                var           targetablesList         = new List <ITargetable>();
                var           targetablePositionsList = new List <ITargetablePositions>();
                var           syncHashesList          = new List <SyncHash>();

                foreach (var traitInfo in Info.TraitsInConstructOrder())
                {
                    var trait = traitInfo.Create(init);
                    AddTrait(trait);

                    // PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per
                    // actor that allows us to provide some fast implementations of commonly used methods that are relied on by
                    // performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering.
                    // Note: The blocks are required to limit the scope of the t's, so we make an exception to our normal style
                    // rules for spacing in order to keep these assignments compact and readable.
                    { if (trait is IPositionable t)
                      {
                          positionable = t;
                      }
                    }
                    { if (trait is IOccupySpace t)
                      {
                          OccupiesSpace = t;
                      }
                    }
                    { if (trait is IEffectiveOwner t)
                      {
                          EffectiveOwner = t;
                      }
                    }
                    { if (trait is IFacing t)
                      {
                          facing = t;
                      }
                    }
                    { if (trait is IHealth t)
                      {
                          health = t;
                      }
                    }
                    { if (trait is IResolveOrder t)
                      {
                          resolveOrdersList.Add(t);
                      }
                    }
                    { if (trait is IRenderModifier t)
                      {
                          renderModifiersList.Add(t);
                      }
                    }
                    { if (trait is IRender t)
                      {
                          rendersList.Add(t);
                      }
                    }
                    { if (trait is IMouseBounds t)
                      {
                          mouseBoundsList.Add(t);
                      }
                    }
                    { if (trait is IVisibilityModifier t)
                      {
                          visibilityModifiersList.Add(t);
                      }
                    }
                    { if (trait is IDefaultVisibility t)
                      {
                          defaultVisibility = t;
                      }
                    }
                    { if (trait is INotifyBecomingIdle t)
                      {
                          becomingIdlesList.Add(t);
                      }
                    }
                    { if (trait is INotifyIdle t)
                      {
                          tickIdlesList.Add(t);
                      }
                    }
                    { if (trait is ITargetable t)
                      {
                          targetablesList.Add(t);
                      }
                    }
                    { if (trait is ITargetablePositions t)
                      {
                          targetablePositionsList.Add(t);
                      }
                    }
                    { if (trait is ISync t)
                      {
                          syncHashesList.Add(new SyncHash(t));
                      }
                    }
                }

                resolveOrders       = resolveOrdersList.ToArray();
                renderModifiers     = renderModifiersList.ToArray();
                renders             = rendersList.ToArray();
                mouseBounds         = mouseBoundsList.ToArray();
                visibilityModifiers = visibilityModifiersList.ToArray();
                becomingIdles       = becomingIdlesList.ToArray();
                tickIdles           = tickIdlesList.ToArray();
                Targetables         = targetablesList.ToArray();
                var targetablePositions = targetablePositionsList.ToArray();
                enabledTargetablePositions = targetablePositions.Where(Exts.IsTraitEnabled);
                SyncHashes = syncHashesList.ToArray();

                setStaticTargetablePositions = positionable == null && targetablePositions.Any() && targetablePositions.All(tp => tp.AlwaysEnabled);
            }
        }