public override void UnitInRange(CharacterBase unit) { base.UnitInRange(unit); //if is attacking, then ignore any new units if (AttackedUnit != null) return; //if the new unit in range is a player or a villager npc, stop idling (supposedly) //and attack it in the Ready() method if (!unit.IsNpc || unit is VillagerNpc) { Engine.CancelAllActions(this); } }
private void ActionHandler(CharacterBase unit) { try { ActionBase action; if (_unitActionDict.TryRemove(unit, out action)) { switch (action.ActionType) { case ActionType.Move: MoveActionHandler(unit, (MoveAction)action); break; case ActionType.Idle: IdleActionHandler(unit, (IdleAction)action); break; }; } } catch (Exception e) { } }
public bool ProcessMove(CharacterBase unit, Location nextLeg) { Debug.WriteLineIf(unit.Id == 0, "Engine: ProcessMove"); if (_unitActionDict.ContainsKey(unit)) { Debug.WriteLineIf(unit.Id == 0, "Engine: ProcessMove returning false"); return false; } return ProcessMoveInternal(unit, nextLeg); }
public bool ProcessIdle(CharacterBase unit, int idleTicks) { if (_unitActionDict.ContainsKey(unit)) return false; IdleAction idleAction = new IdleAction { Tick = _timeKeeper.Tick + idleTicks }; AddAction(unit, idleAction); return true; }
public void ProcessAttack(CharacterBase attackignUnit, CharacterBase attackedUnit) { //TODO: check that the attacked unit is in range throw new NotImplementedException(); }
/// <summary> /// Engine event. Called when a new unit comes in range. /// </summary> public virtual void UnitInRange(CharacterBase unit) { UnitsInRange.Add(unit); }
public void CancelAllActions(CharacterBase unit) { throw new NotImplementedException(); }
private void MoveActionHandler(CharacterBase unit, MoveAction action) { Location oldLocation = unit.Location; Location newLocation = action.Location; _map.Move(unit, oldLocation, newLocation); //unit.EndMove(action.Location); unit.Ready(action); }
public void Add(CharacterBase unit, Location location) { MapIdentifier identifier = _identifierPool.Get(); _objectIdDictionary.Add(unit, identifier); _map[location.X, location.Y] = identifier.Id; }
protected virtual bool MoveToAttack(CharacterBase unit) { throw new NotImplementedException(); }
/// <summary> /// Checks if the unit is in sensory range. /// </summary> protected virtual bool IsInRange(CharacterBase unit) { return CartesianDistance(unit.Location) <= Range; }
protected virtual bool IsInAttackRange(CharacterBase unit) { //TODO: in the future should check if the unit uses a ranged weapon and //do a Cartesian distance calculation return DistanceToUnit(unit) <= AttackRange; }
/// <summary> /// Returns a cell distance to the unit not considering any obstacles. /// </summary> protected virtual int DistanceToUnit(CharacterBase unit) { return Math.Abs(Location.X - unit.Location.X) + Math.Abs(Location.Y - unit.Location.Y); }
/// <summary> /// Engine event. Called when a unit gets out of range (or also if dies). /// </summary> public virtual void UnitOutOfRange(CharacterBase unit) { UnitsInRange.Remove(unit); }
private void AddAction(CharacterBase unit, ActionBase action) { if (action.Tick <= _timeKeeper.Tick) { } _unitActionDict.TryAdd(unit, action); ConcurrentQueue<CharacterBase> actionList = _scheduledActionsDict .GetOrAdd(action.Tick, new ConcurrentQueue<CharacterBase>()); actionList.Enqueue(unit); }
private void IdleActionHandler(CharacterBase unit, IdleAction action) { unit.Ready(action); }
public void Move(CharacterBase unit, Location oldLocation, Location newLocation) { _map[oldLocation.X, oldLocation.Y] = 0; _map[newLocation.X, newLocation.Y] = _objectIdDictionary[unit].Id; }
/// <summary> /// We need an internal ProcessMove method to avoid altering the original path. /// </summary> /// <param name="unit"></param> /// <param name="nextLeg"></param> /// <returns></returns> private bool ProcessMoveInternal(CharacterBase unit, Location nextLeg) { //check that the map is empty at the desired location if (!_map.ReserveIfEmpty(nextLeg, unit)) return false; MoveAction moveAction = new MoveAction { Tick = _timeKeeper.Tick + unit.MovementSpeed, Location = nextLeg }; unit.BeginMove(nextLeg); AddAction(unit, moveAction); return true; }
public void Remove(CharacterBase unit, Location location) { _map[location.X, location.Y] = 0; }
public bool ReserveIfEmpty(Location location, CharacterBase reservationOwner) { //TODO: move to some constants if will keep it (see below) const int RESERVED = 1; //TODO: maybe set the map id of the unit instead of a reservation code? lock (_mapLockObject) { if (_map[location.X, location.Y] == 0 && 0 == Interlocked.CompareExchange( ref _map[location.X, location.Y], RESERVED, 0)) { //TODO: track the reservation owner return true; } return false; } }
/// <summary> /// Attack order. /// </summary> /// <param name="unit"></param> /// <returns></returns> public bool AttackUnitOrder(CharacterBase unit) { throw new NotImplementedException(); //first thing we must check that the unit can be attacked unit.OnDie += AttackedUnitDiedOrOutOfRange; unit.OnEndMove += AttackedUnitMoved; if (!IsInAttackRange(unit)) { if (!MoveToAttack(unit)) return false; } else { } }