예제 #1
0
파일: Unit.cs 프로젝트: arcticnw/Wildmen
    /// <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;
      }
    }
예제 #2
0
 /// <summary>
 /// Creates a new instance of the GameEffect class using the serialized data
 /// </summary>
 /// <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>GameEffect created using the provided serialized data</returns>
 public static GameEffect Create(string[] line, ref int position, WildmenGame context)
 {
   GameEffect e = null;
   EffectTypes et = (EffectTypes)int.Parse(line[position++]);
   switch (et)
   {
     case EffectTypes.Scripted:
       e = new GameEffect();
       break;
     case EffectTypes.UnitDeath:
       e = new UnitDeathEffect();
       break;
     case EffectTypes.ScrollText:
       e = new ScrollTextEffect();
       break;
     case EffectTypes.Animation:
       e = new AnimationEffect();
       break;
     case EffectTypes.Spawner:
       e = new SpawnerEffect();
       break;
     default:
       throw new Exception("Unknown effect");
   }
   e.game = context;
   e.Deserialize(MessageType.GameEffectCreate, line, ref position, context);
   return e;
 }