static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p) { var ri = info.Traits.Get<RenderSimpleInfo>(); string image = null; if (ri.OverrideTheater != null) for (int i = 0; i < ri.OverrideTheater.Length; i++) if (ri.OverrideTheater[i] == tileset.Id) image = ri.OverrideImage[i]; image = image ?? ri.Image ?? info.Name; using (var s = FileSystem.OpenWithExts(image, tileset.Extensions)) { var shp = new ShpReader(s); var frame = shp[0]; var bitmap = new Bitmap(shp.Width, shp.Height); var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); unsafe { int* q = (int*)data.Scan0.ToPointer(); var stride = data.Stride >> 2; for (var i = 0; i < shp.Width; i++) for (var j = 0; j < shp.Height; j++) q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb(); } bitmap.UnlockBits(data); return new ActorTemplate { Bitmap = bitmap, Info = info, Centered = !info.Traits.Contains<BuildingInfo>() }; } }
// TODO: This can be removed after the legacy and redundant 0% = not targetable // assumption has been removed from the yaml definitions public override bool CanTargetActor(ActorInfo victim, Actor firedBy) { var health = victim.Traits.GetOrDefault<HealthInfo>(); if (health == null) return false; return DamageVersus(victim) > 0; }
public virtual int2? ExitLocation(Actor self, ActorInfo producee) { var pos = (1 / 24f * self.CenterLocation).ToInt2(); var pi = self.Info.Traits.Get<ProductionInfo>(); if (pi.ExitOffset != null) pos += new int2(pi.ExitOffset[0], pi.ExitOffset[1]); return pos; }
public int DamageVersus(ActorInfo victim) { var armor = victim.Traits.GetOrDefault<ArmorInfo>(); if (armor != null && armor.Type != null) { int versus; if (Versus.TryGetValue(armor.Type, out versus)) return versus; } return 100; }
public float EffectivenessAgainst(ActorInfo ai) { var health = ai.Traits.GetOrDefault<HealthInfo>(); if (health == null) return 0f; var armor = ai.Traits.GetOrDefault<ArmorInfo>(); if (armor == null || armor.Type == null) return 1; float versus; return Versus.TryGetValue(armor.Type, out versus) ? versus : 1; }
public override bool Produce( Actor self, ActorInfo producee ) { var owner = self.Owner; // Start and end beyond the edge of the map, to give a finite delay, and ability to land when AFLD is on map edge var startPos = new int2(owner.World.Map.XOffset + owner.World.Map.Width+15, self.Location.Y); var endPos = new int2(owner.World.Map.XOffset-15, self.Location.Y); var unloadOffset = new int2(1,1); var exitOffset = new int2(3,1); var rp = self.traits.GetOrDefault<RallyPoint>(); owner.World.AddFrameEndTask(w => { var a = w.CreateActor("C17", startPos, owner); var cargo = a.traits.Get<Cargo>(); a.traits.Get<Unit>().Facing = 64; a.traits.Get<Unit>().Altitude = a.Info.Traits.Get<PlaneInfo>().CruiseAltitude; var newUnit = new Actor(self.World, producee.Name, new int2(0, 0), self.Owner); cargo.Load(a, newUnit); a.CancelActivity(); a.QueueActivity(new Land(self)); a.QueueActivity(new CallFunc(() => { if (self.IsDead) return; var actor = cargo.Unload(self); self.World.AddFrameEndTask(ww => { ww.Add(actor); actor.traits.Get<Mobile>().TeleportTo(actor, self.Location + unloadOffset); newUnit.traits.Get<Unit>().Facing = 192; actor.CancelActivity(); actor.QueueActivity(new Move(self.Location + exitOffset, self)); actor.QueueActivity(new Move(rp.rallyPoint, 0)); foreach (var t in self.traits.WithInterface<INotifyProduction>()) t.UnitProduced(self, actor); }); })); a.QueueActivity(new Fly(endPos)); a.QueueActivity(new RemoveSelf()); }); return true; }
public bool CanBuild( ActorInfo info, Player player, Cache<string, List<Actor>> playerBuildings ) { var bi = info.Traits.GetOrDefault<BuildableInfo>(); if( bi == null ) return false; if( !bi.Owner.Contains( player.Country.Race ) ) return false; foreach( var p in bi.Prerequisites ) if( playerBuildings[ p ].Count == 0 ) return false; if( producesIndex[ info.Category ].All( x => playerBuildings[ x.Name ].Count == 0 ) ) return false; return true; }
public override bool Produce( Actor self, ActorInfo producee ) { var owner = self.Owner; // Start and end beyond the edge of the map, to give a finite delay, and ability to land when AFLD is on map edge var startPos = new int2(owner.World.Map.XOffset + owner.World.Map.Width+5, self.Location.Y); var endPos = new int2(owner.World.Map.XOffset-5, self.Location.Y); // Assume a single exit point for simplicity var spawn = self.CenterLocation + Spawns.First().First; var exit = self.Location + Spawns.First().Second; owner.World.AddFrameEndTask(w => { var a = w.CreateActor("C17", new TypeDictionary { new LocationInit( startPos ), new OwnerInit( owner ), new FacingInit( 64 ), new AltitudeInit( Rules.Info["c17"].Traits.Get<PlaneInfo>().CruiseAltitude ), }); var cargo = a.Trait<Cargo>(); var newUnit = self.World.CreateActor(false, producee.Name, new TypeDictionary { new OwnerInit( self.Owner ), }); cargo.Load(a, newUnit); a.QueueActivity(new Land(Target.FromActor(self))); a.QueueActivity(new CallFunc(() => { if (self.IsDead()) return; self.World.AddFrameEndTask(ww => DoProduction(self, cargo.Unload(self), exit, spawn)); })); a.QueueActivity(new Fly(endPos)); a.QueueActivity(new RemoveSelf()); }); return true; }
public void RulesetLoaded(Ruleset rules, ActorInfo ai) { ExplosionWeapon = string.IsNullOrEmpty(Explosion) ? null : rules.Weapons[Explosion.ToLowerInvariant()]; }
public void RulesetLoaded(Ruleset rules, ActorInfo ai) { WeaponInfo = rules.Weapons[Weapon.ToLowerInvariant()]; }
public void RulesetLoaded(Ruleset rules, ActorInfo ai) { WeaponInfos = Weapons.Select(w => rules.Weapons[w.ToLowerInvariant()]).ToArray(); }
public IEnumerable<ActorInfo> UnitBuiltAt( ActorInfo info ) { var builtAt = info.Traits.Get<BuildableInfo>().BuiltAt; if( builtAt.Length != 0 ) return builtAt.Select( x => Rules.Info[ x.ToLowerInvariant() ] ); else return producesIndex[ info.Category ]; }
// TODO: This can be removed after the legacy and redundant 0% = not targetable // assumption has been removed from the yaml definitions public override bool CanTargetActor(ActorInfo victim, Actor firedBy) { return true; }
public override int2? CreationLocation(Actor self, ActorInfo producee) { return FindAdjacentTile(self, producee.Traits.Get<OwnedActorInfo>().WaterBound); }
public virtual bool Produce( Actor self, ActorInfo producee ) { var location = CreationLocation( self, producee ); if( location == null || self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt( location.Value ).Any() ) return false; var newUnit = self.World.CreateActor( producee.Name, location.Value, self.Owner ); newUnit.traits.Get<Unit>().Facing = CreationFacing( self, newUnit ); ; var pi = self.Info.Traits.Get<ProductionInfo>(); var rp = self.traits.GetOrDefault<RallyPoint>(); if( rp != null || pi.ExitOffset != null) { var mobile = newUnit.traits.GetOrDefault<Mobile>(); if( mobile != null ) { if (pi.ExitOffset != null) newUnit.QueueActivity(new Activities.Move(ExitLocation( self, producee).Value, 1)); if (rp != null) newUnit.QueueActivity( new Activities.Move( rp.rallyPoint, 1 ) ); } } if (pi != null && pi.SpawnOffset != null) newUnit.CenterLocation = self.CenterLocation + new float2(pi.SpawnOffset[0], pi.SpawnOffset[1]); foreach (var t in self.traits.WithInterface<INotifyProduction>()) t.UnitProduced(self, newUnit); return true; }
// TODO: This can be removed after the legacy and redundant 0% = not targetable // assumption has been removed from the yaml definitions public virtual bool CanTargetActor(ActorInfo victim, Actor firedBy) { return false; }