private void HandleAttack(GameEvent_PrepareAttack ev) { if (ev.ExecutorEntity == this.Parent) { // If it's out of range, then the attack misses int weaponRange = ev.ExecutorEntity.TryGetAttribute(EntityAttributeType.MAX_RANGE, ev.ExecutorEntity) .Value; int distance = FloorState.DistanceBetweenEntities(ev.Target, ev.CommandEntity); if (distance > weaponRange) { ev.RegisterResult("MISS (out of range)"); return; } // TODO: This sequence of early exists is crufty because there's a lot of "before-exit-do" stuff here! // If any of the cells isn't walkable, then your shot is blocked and the attack stops var targetPos = ev.Target.TryGetPosition(); var attackerPos = ev.CommandEntity.TryGetPosition(); var lineCells = ev.GameMap.GetCellsAlongLine(attackerPos.X, attackerPos.Y, targetPos.X, targetPos.Y); if (lineCells.Any(c => !c.IsWalkable)) { ev.RegisterResult("MISS (no straight shot)"); return; } // Forward the attack to the target var receiveAttack = new GameEvent_ReceiveAttack(ev); ev.Target.HandleEvent(receiveAttack); if (!receiveAttack.Completed) { Log.DebugLine("Could not resolve attack against " + ev.Target.ToString()); } } }
private void HandleQueryCommand(GameQuery_Command q) { if (this.Alerted) { this.activeBook.TryRegisterCommand(q); } else if (q.FloorState.Player != null && FloorState.DistanceBetweenEntities(this.Parent, q.FloorState.Player) <= this.Parent.TryGetAttribute(EntityAttributeType.DETECTION_RADIUS).Value) { q.FloorState.AlertAllAIs(); } else { var myPos = this.Parent.TryGetPosition(); if (myPos.X == this.PatrolStart.X && myPos.Y == this.PatrolStart.Y) { this.OnReturnLeg = false; } else if (myPos.X == this.PatrolEnd.X && myPos.Y == this.PatrolEnd.Y) { this.OnReturnLeg = true; } Cell myCell = q.FloorState.FloorMap.GetCell(myPos.X, myPos.Y); Path patrolPath; if (!this.OnReturnLeg) { patrolPath = q.FloorState.ShortestPath(myCell, this.PositionToCell(this.PatrolEnd, q.FloorState)); } else { patrolPath = q.FloorState.ShortestPath(myCell, this.PositionToCell(this.PatrolStart, q.FloorState)); } if (patrolPath != null) { q.RegisterCommand(this.MoveEventForPath(q, patrolPath)); } else { q.RegisterCommand(new CommandStub_Delay(this.Parent.EntityID, Config.ONE)); } } }
public override bool IsMet(GameQuery_Command commandQuery) { // TODO: This is gonna show up in a lot of conditions, and looks pretty janky. Entity target = commandQuery.FloorState.Player; // TODO: Smooth out this int? business! // It's an int? because some conditions (asking for WEAPON_RANGE on something which has no range, like a // MechSkeleton, but which does get turns) are nonsensical. int?optionDistance = this.ResolveOptionDistance(commandQuery, target); if (optionDistance == null) { return(true); } int currDist = FloorState.DistanceBetweenEntities(target, commandQuery.CommandEntity); switch (this.Operator) { case ComparisonOperator.EQUAL: return(currDist == optionDistance); case ComparisonOperator.LESS_THAN: return(currDist < optionDistance); case ComparisonOperator.LESS_THAN_EQUAL: return(currDist <= optionDistance); case ComparisonOperator.GREATER_THAN: return(currDist > optionDistance); case ComparisonOperator.GREATER_THAN_EQUAL: return(currDist >= optionDistance); default: throw new InvalidOperationException("Condition_Distance can't handle " + this.Operator); } }