/// <summary> /// Creates a building of given entry at given tile with given owner /// </summary> /// <param id="entry">Db entry of the building</param> /// <param id="tile">Tile if the building</param> /// <param id="owner">Owner of the building</param> /// <returns>The created building</returns> public IScriptBuilding CreateBuilding(IScriptDbEntry entry, IScriptTile tile, IScriptPlayer owner) { Building bldg = new Building(); bldg.Initialize((EntryDb)entry, this, (Player)owner, (Tile)tile); bldg.InitializeGraphics(); SendData(Network.MakeServerMessage(MessageType.GameObjCreate, bldg)); return bldg; }
public void PlacePlayer(int n, Player player) { foreach (var res in Db.Instance.Resources) { player.ResourceStockpiles[res.Value] += res.Value.StartWith; } Players.Add(player); Tile loc = Map.StartLocations[n]; int x = loc.X; int y = loc.Y; // Place buildings foreach (var bldgEntry in Db.Instance.Buildings.Where(p => p.Value.BuiltOnStart)) { bool tileOk = false; int c = 0; Tile t = null; // Get random location around center while (!tileOk) { int rx = x + (int)(random.NextDouble() * 8) - 4; int ry = y + (int)(random.NextDouble() * 8) - 4; t = Map.Tiles[rx, ry]; if (!Building.CanPlace(Map, t)) { c++; if (c > 100) { Logger.Log("Unable to place building " + bldgEntry.Key + " - no free space", "MapGen"); break; } } else { tileOk = true; } } if (tileOk) { Building bldg = new Building(); bldg.Initialize(bldgEntry.Value, this, player, t); bldg.InitializeGraphics(); bldg.Completed(false); } } // Place units foreach (var unitEntry in Db.Instance.Units.Where(p => p.Value.GivenOnStart > 0)) { for (int i = 0; i < unitEntry.Value.GivenOnStart; i++) { int rx = x + (int)(random.NextDouble() * 8) - 4; int ry = y + (int)(random.NextDouble() * 8) - 4; Tile t = Map.Tiles[rx, ry]; Unit u = new Unit(); u.Initialize(unitEntry.Value, this, player, t.MapPosition); u.InitializeGraphics(); } } }
/// <summary> /// Method that deserializes the data from the line starting at given position in given context depending on the MessageType /// </summary> /// <param id="mt">MessageType defining the extend of deserialization which is to be performed</param> /// <param id="line">String array containing the serialized data</param> /// <param id="position">Current position in the array</param> /// <param id="context">Context of the serialized data, game where this INetworkSerializable object is in</param> public override void Deserialize(MessageType mt, string[] line, ref int position, WildmenGame context) { base.Deserialize(mt, line, ref position, context); switch (mt) { case MessageType.GameTransfer: case MessageType.GameEffectCreate: spawner = (Building)context.GetGameObjectById(int.Parse(line[position++])); ((Building)spawner).ResetSpawner(this); Spawnee = Db.Instance.Units[line[position++]]; int playerId = int.Parse(line[position++]); owner = context.Players.First(u => u.Id == playerId); spawnPoint = new Vector2(float.Parse(line[position++], CultureInfo.InvariantCulture), float.Parse(line[position++], CultureInfo.InvariantCulture)); break; default: throw new Exception(); } }
/// <summary> /// Carries out the order /// </summary> private void UpdateDoOrder() { GameEffect gEff = null; Building bldg = null; Tile tile = null; BuildingDb bldgEntry = null; switch (Order) { case GameObjectOrder.Idle: #region Logger.Log(string.Format("Unit #{0}:{1} finished move order", this.ObjectUID, this.Entry.Id), "Server update"); if (!game.IsServer) { State = GameObjectState.Idle; } else { // Find position along traveling vector available for movement bool closeFound = false; if (NearestTile == null) { // Nearest Tile not yet updated return; } // If standing too close to other unit, move aside (if possible) foreach (var closeUnit in NearestTile.Units) { // Ignore self if (closeUnit == this) continue; // Ignore moving units if (closeUnit.State == GameObjectState.MovingToOrder) continue; // Check minimal distance if ((closeUnit.MapPosition - this.MapPosition).Length() < MIN_IDLE_DISTANCE) { Vector2 vector; // If the map positions aren't same, move in the same amount you are standing towards the other unit if (this.MapPosition != closeUnit.MapPosition) { vector = this.MapPosition - closeUnit.MapPosition; vector.Normalize(); OrderPosition = this.MapPosition + vector * DODGE_DISTANCE; } // If the position is same, come up with some vector else { // Try to move in same amount you are standing from the origin position of the map vector = this.MapPosition; vector.Normalize(); if (NearestTile.Units.Any(q => (q.MapPosition - OrderPosition).Length() >= MOVEMENT_RANGE)) { OrderPosition = this.MapPosition + vector * DODGE_DISTANCE; } // If the place is already occupied, try inverted vector and orthogonal vectors else { Vector2 ort = new Vector2(-vector.Y, vector.X); Queue<Vector2> attemptVector = new Queue<Vector2>(); attemptVector.Enqueue(ort); attemptVector.Enqueue(-vector); attemptVector.Enqueue(-ort); attemptVector.Enqueue(vector); Vector2 projectedPosition = default(Vector2); while (attemptVector.Count > 0) { projectedPosition = this.MapPosition + attemptVector.Dequeue() * DODGE_DISTANCE; if (NearestTile.Units.Any(q => (q.MapPosition - projectedPosition).Length() >= MOVEMENT_RANGE)) break; } // If everything else fails, use last failed OrderPosition = projectedPosition; } } State = GameObjectState.MovingToOrder; closeFound = true; game.SendData(Network.MakeServerMessage(MessageType.GameObjUpdate, this)); break; } } // If there is no other unit, become idle if (!closeFound) { State = GameObjectState.Idle; } else { OrderTarget = null; OrderRange = MOVEMENT_RANGE; } } #endregion break; case GameObjectOrder.Attack: #region if (OrderTarget == null) return; if (OrderTarget == this) { CancelOrders(true); return; } // Animation effect TextureTileSet2D tex = new TextureTileSet2D(UI.Instance.GetTexture("combat"), 24, 1); Vector2 p = (Position + OrderTarget.Position) / 2; gEff = new AnimationEffect(tex, p + AlignmentOffset + Size / 2 - tex.FrameSize / 2, 24, 10, true); gEff.Initialize(game, NearestTile); this.game.Effects.Add(gEff); if (game.IsServer) { // Apply modifiers float amount = entry.AttackAmount; if (entry.Modifiers != null) for (int i = 0; i < entry.Modifiers.Length; i++) if (entry.Modifiers[i].Entry == OrderTarget.Entry) amount *= entry.Modifiers[i].Mod; Logger.Log(string.Format("Unit #{0}:{1} attacking (-{2}) #{3}:{4} (before {5}/?)", this.ObjectUID, entry.Id, (int)amount, OrderTarget.ObjectUID, OrderTarget.Entry.Id, OrderTarget.Health), "Server update"); // Apply damage OrderTarget.ReceiveDamage((int)amount); // Check whether target is alive if (OrderTarget.Health == 0) { CancelOrders(true); return; } } #endregion break; case GameObjectOrder.Construct: #region if (game.IsServer) { if (OrderTarget != null) { Debug.Assert(OrderTarget.GetEntityType == GameEntityType.Building); Logger.Log(string.Format("Unit #{0}:{1} constructing (+{2}) effect #{3}:{4} (before {5}/100)", this.ObjectUID, entry.Id, entry.ConstructAmount, OrderTarget.ObjectUID, OrderTarget.Entry.Id, ((Building)OrderTarget).Construction), "Server update"); // Construct part of the building ((Building)OrderTarget).ConstructionProgress(entry.ConstructAmount); } else { Logger.Log(string.Format("Unit #{0}:{1} starting construction of {2}", this.ObjectUID, entry.Id, OrderEntry.Id), "Server update"); tile = game.Map.GetTileFlat(OrderPosition); // Check whether building can be constructed at given position if (!Building.CanPlace(game.Map, tile) || Owner.Fow[tile.X, tile.Y] == 0) { Logger.Log(string.Format("Unit #{0}:{1} construction of {2} aborted - unable to place", this.ObjectUID, entry.Id, OrderEntry.Id), "Server update"); CancelOrders(true); return; } bldgEntry = (BuildingDb)OrderEntry; // Check whether building can be built more than once if (bldgEntry.OnlyOneAllowed && Owner.Buildings.Any(q => q.Entry == bldgEntry)) { ScrollUpMessage("Only one such building allowed at a time", 100, true); CancelOrders(true); return; } if (bldgEntry.UnlockedBy != null) { bldg = Owner.Buildings.FirstOrDefault(q => q.Entry == bldgEntry.UnlockedBy); if (bldg == null || !bldg.Constructed) { ScrollUpMessage("Building unavailable", 100, true); CancelOrders(true); return; } } // Check whether player canCast enough resources if (bldgEntry.Cost != null) { foreach (var costEntry in bldgEntry.Cost) { if (Owner.ResourceStockpiles[costEntry.Entry] < costEntry.Amount) { ScrollUpMessage("Not enough resources", 100, true); CancelOrders(true); return; } } } // Place new building bldg = new Building(); bldg.Initialize(bldgEntry, game, Owner, tile); bldg.InitializeGraphics(); game.SendData(Network.MakeServerMessage(MessageType.GameObjCreate, bldg)); // Deduct resources from the player if (bldgEntry.Cost != null) foreach (var costEntry in bldgEntry.Cost) Owner.ResourceStockpiles[costEntry.Entry] -= costEntry.Amount; // Set target for this unit (so it will automatically construct the building) OrderTarget = bldg; OrderEntry = null; game.SendData(Network.MakeServerMessage(MessageType.PlayerUpdate, Owner)); game.SendData(Network.MakeServerMessage(MessageType.GameObjUpdate, this)); } } #endregion break; case GameObjectOrder.Spell: #region EffectDb effect = (EffectDb)OrderEntry; if (game.IsServer) { // Check whether spell can be cast if (effect.UnlockedBy != null) { bldg = Owner.Buildings.FirstOrDefault(q => q.Entry == effect.UnlockedBy); if (bldg == null || !bldg.Constructed) { CancelOrders(true); return; } } Logger.Log(string.Format("Unit #{0}:{1} casting {2}", this.ObjectUID, entry.Id, OrderEntry.Id), "Server update"); switch (effect.Spell.Target) { case SpellEntry.TargetType.Tile: tile = game.Map.GetTileFlat(OrderPosition); gEff = new GameEffect(effect, this, tile); gEff.Initialize(game, tile); this.game.Effects.Add(gEff); break; case SpellEntry.TargetType.GameEntity: Debug.Assert(OrderTarget != null); gEff = new GameEffect(effect, this, OrderTarget); gEff.Initialize(game, OrderTarget.NearestTile); this.game.Effects.Add(gEff); break; default: throw new Exception("Undefined spell type"); } game.SendData(Network.MakeServerMessage(MessageType.GameEffectCreate, gEff)); } if (!effect.AutoRepeat) { State = GameObjectState.Idle; } #endregion break; case GameObjectOrder.Gather: #region if (OrderTarget.GetEntityType == GameEntityType.Building) { Debug.Assert(carryType != null); if (carryAmount > 0) { ScrollUpMessage(string.Format("Returned {0} of {1}", carryAmount, carryType.Name), 50); } if (game.IsServer) { // First zoneFound only transfers carried resources and sets order delay, second time around unit moves back to resource if (carryAmount > 0) { Debug.Assert(((BuildingDb)OrderTarget.Entry).ResourceCenter); Logger.Log(string.Format("Unit #{0}:{1} returned +{2} of {3} (before {4}) to #{5}:{6}", this.ObjectUID, this.Entry.Id, carryAmount, carryType.Id, Owner.ResourceStockpiles[carryType], OrderTarget.ObjectUID, OrderTarget.Entry.Id), "Server update"); // Give resources to player Owner.ResourceStockpiles[carryType] += carryAmount; carryAmount = 0; OrderTimeout = GATHER_RETURN_DELAY; game.SendData(Network.MakeServerMessage(MessageType.GameObjUpdate, this)); game.SendData(Network.MakeServerMessage(MessageType.PlayerUpdate, Owner)); } else { if (lastGatheredResource.Amount == 0) { CancelOrders(true); return; } // Head towards resource Debug.Assert(lastGatheredResource != null); OrderTarget = lastGatheredResource; OrderRange = entry.GatherRange; OrderTimeout = entry.GatherSpeed; game.SendData(Network.MakeServerMessage(MessageType.GameObjUpdate, this)); } } } else if (OrderTarget.GetEntityType == GameEntityType.Resource) { Debug.Assert(carryAmount == 0 || carryType == (ResourceDb)OrderTarget.Entry); Resource res = (Resource)OrderTarget; if (res.Cooldown > 0) break; if (game.IsServer) { if (carryAmount == 0) { carryType = (ResourceDb)res.Entry; } if (res.Amount == 0) { CancelOrders(true); return; } int take = res.Take(entry.GatherAmount); Logger.Log(string.Format("Unit #{0}:{1} gathered +{2} of {3} (before {4}) from #{5}:{6}", this.ObjectUID, this.Entry.Id, take, carryType.Id, carryAmount, OrderTarget.ObjectUID, OrderTarget.Entry.Id), "Server update"); carryAmount += take; game.SendData(Network.MakeServerMessage(MessageType.GameObjUpdate, res)); ScrollUpMessage(string.Format("Gathered {0} of {1}", take, OrderTarget.Entry.Name), 30, true); } } else { CancelOrders(true); } #endregion break; case GameObjectOrder.Train: #region if (game.IsServer) { bldg = (Building)OrderTarget; // If the building is already training, wait if (bldg.Spawner != null && bldg.Spawner.Active) break; bldgEntry = (BuildingDb)bldg.Entry; bool noEntry = true; BuildingDb.TrainEntry trainEntry = default(BuildingDb.TrainEntry); if (bldgEntry.Trains != null) { foreach (var iterTrainEntry in bldgEntry.Trains) { if (iterTrainEntry.TrainFrom == this.entry) { noEntry = false; trainEntry = iterTrainEntry; break; } } } if (noEntry) { ScrollUpMessage("Unable to train this unit in this building", 100, true); CancelOrders(true); return; } // Check whether player canCast enough resources if (trainEntry.Cost != null) { foreach (var costEntry in trainEntry.Cost) { if (Owner.ResourceStockpiles[costEntry.Entry] < costEntry.Amount) { ScrollUpMessage("Not enough resources", 100, true); CancelOrders(true); return; } } } Logger.Log(string.Format("Unit #{0}:{1} start training in #{2}:{3} towards {4}", this.ObjectUID, this.Entry.Id, OrderTarget.ObjectUID, OrderTarget.Entry.Id, bldgEntry.Id), "Server update"); // Initialize spawning of the new unit bldg.StartUnitSpawner(trainEntry.TrainTo, trainEntry.Speed); // Deduct resources from the player if (trainEntry.Cost != null) foreach (var costEntry in trainEntry.Cost) Owner.ResourceStockpiles[costEntry.Entry] -= costEntry.Amount; game.SendData(Network.MakeServerMessage(MessageType.PlayerUpdate, Owner)); // Info newText gEff = new ScrollTextEffect("Training", Position, 50, new Vector2(0, -1)); gEff.Initialize(game, bldg.NearestTile); this.game.Effects.Add(gEff); game.SendData(Network.MakeServerMessage(MessageType.GameEffectCreate, gEff)); // Kill the unit Kill(true); return; } #endregion break; } }
/// <summary> /// Constructor of this class /// </summary> /// <param name="spawner">Building doing the spawning</param> /// <param name="spawnee">Unit type to spawn</param> /// <param name="owner">Owner of the new unit</param> /// <param name="spawnPoint">Position of the new unit</param> /// <param name="speed">Spawning speed</param> public SpawnerEffect(Building spawner, UnitDb spawnee, Player owner, Vector2 spawnPoint, int speed) { this.spawner = spawner; this.Spawnee = spawnee; this.owner = owner; this.spawnPoint = spawnPoint; this.Speed = speed; this.Duration = 0; }
/// <summary> /// Disposes resources used by this instance /// </summary> public override void Dispose() { Building bldg; if ((bldg = spawner as Building) != null) if (bldg.Spawner == this) bldg.ResetSpawner(null); spawner = null; Spawnee = null; owner = null; base.Dispose(); }
public bool ShamanAvailable() { // If shaman is dead or not existing, look for new shaman if (shaman == null || shaman.Removed || shaman.Health == 0) { shaman = null; shaman = Units.FirstOrDefault( p => ((UnitDb)p.Entry).Shaman && !p.Removed && p.Health != 0); } // If there is a shaman, player isn't defeated if (shaman != null) return true; // If there's no shaman spawn place, look for new one if (shamanSpawn == null || shamanSpawn.Removed || shamanSpawn.Health == 0 || !shamanSpawn.Constructed) { var shamanSpawnCandidates = Buildings.Where( p => !p.Removed && p.Health != 0 && ((BuildingDb)p.Entry).Spawns != null && ((BuildingDb)p.Entry).Spawns.Any( q => q.Entry.Shaman)); // Try spawn sites that are already constructed shamanSpawn = shamanSpawnCandidates.FirstOrDefault(p => p.Constructed); // If we found one, player isn't defeated if (shamanSpawn != null) return true; // Player has no spawn site return false; } // Player has a working spawn place and isn't defeated return true; }
/// <summary> /// Creates a new instance of the Building class using the serialized data /// </summary> /// <param id="mt">MessageType defining the extend of deserialization which is to be performed</param> /// <param id="line">String array containing the serialized data</param> /// <param id="position">Current position in the array</param> /// <param id="context">Context of the serialized data, game where this INetworkSerializable object is in</param> /// <returns>Building created using the provided serialized data</returns> public static Building Create(MessageType mt, string[] line, ref int position, WildmenGame context) { Building b = new Building(); b.Deserialize(mt, line, ref position, context); b.game = context; b.ClaimTiles(b.NearestTile); b.InitializeGraphics(); return b; }
// public void BuildingFinished(Building building) { GameObjectListModified = true; }
public void Unassign(Building building) { Buildings.Remove(building); game.GameObjectListChanged = true; }
public void Assign(Building building) { Buildings.Add(building); building.Owner = this; game.GameObjectListChanged = true; }
/// <summary> /// Unassigns building from this Tile /// </summary> public void Unassign(Building building) { Debug.Assert(this.Building == building); this.Building = null; }
// ASSIGNMENT /// <summary> /// Assigns building to this Tile /// </summary> public void Assign(Building building) { if (this.Building == building) return; Debug.Assert(this.Building == null); this.Building = building; }