// This is actually much more like unit broken but oh well! public static List <EncounterAction> ActionsForUnitRetreat(EncounterState state, Entity parent, Unit unit) { var parentPos = parent.GetComponent <PositionComponent>().EncounterPosition; EncounterPosition targetEndPos = parentPos; var backwardsPositions = new List <EncounterPosition>() { AIUtils.RotateAndProject(parentPos, 0, 1, unit.UnitFacing), AIUtils.RotateAndProject(parentPos, 1, 1, unit.UnitFacing), AIUtils.RotateAndProject(parentPos, -1, 1, unit.UnitFacing), }; GameUtils.Shuffle(state.EncounterRand, backwardsPositions); foreach (var position in backwardsPositions) { if (state.EntitiesAtPosition(position.X, position.Y).Count == 0) { targetEndPos = position; break; } } if (targetEndPos == parentPos) { targetEndPos = backwardsPositions[0]; } return(new List <EncounterAction>() { new MoveAction(parent.EntityId, targetEndPos) }); }
private List <EncounterAction> MoveAndAttack(EncounterState state, int dx, int dy) { var positionComponent = state.Player.GetComponent <PositionComponent>(); var oldPos = positionComponent.EncounterPosition; var newPos = new EncounterPosition(oldPos.X + dx, oldPos.Y + dy); // TODO: maybe not hostile? var hostiles = AIUtils.HostilesInPosition(state, FactionName.PLAYER, newPos.X, newPos.Y); if (hostiles.Count > 0) { var attackAction = new MeleeAttackAction(state.Player.EntityId, hostiles[state.EncounterRand.Next(hostiles.Count)]); return(new List <EncounterAction>() { attackAction }); } else { var moveAction = new MoveAction(state.Player.EntityId, newPos); return(new List <EncounterAction>() { moveAction }); } }
public static bool IsPositionTooFarBehind(EncounterPosition position, Unit unit) { var behindVec = AIUtils.VectorFromCenterRotated(unit.AveragePosition, position.X, position.Y, unit.UnitFacing); // This can't be too restrictive or it stops you from sitting at the back of the line when rotating. return(behindVec.Item2 > -Mathf.CeilToInt(unit.Depth / 2) + 5); }
public static Tuple <int, int> VectorFromCenterRotated(EncounterPosition center, int tx, int ty, FormationFacing facing) { int dx = tx - center.X; int dy = ty - center.Y; return(ToNorthCoordinates(dx, dy, facing)); }
public static bool IsNextRowTooFarAhead(EncounterPosition parentPos, Unit unit) { var directlyInFrontPosition = AIUtils.RotateAndProject(parentPos, 0, -1, unit.UnitFacing); var forwardVec = AIUtils.VectorFromCenterRotated(unit.AveragePosition, directlyInFrontPosition.X, directlyInFrontPosition.Y, unit.UnitFacing); return(forwardVec.Item2 < -Mathf.CeilToInt(unit.Depth / 2) - 1); }
private bool ShouldHighlightEntity(EncounterState state, Entity entity, EncounterPosition entityPos, int nextPlayerTick) { var aiComponent = entity.GetComponent <AIComponent>(); return(aiComponent != null && !(aiComponent is PathAIComponent) && state.FoVCache.IsVisible(entityPos) && entity.GetComponent <ActionTimeComponent>().NextTurnAtTick < nextPlayerTick); }
public override EncounterPosition PositionInFormation(int formationNumber, Unit unit) { EncounterPosition center = unit.RallyPoint; int dx = formationNumber % 10; int dy = Mathf.FloorToInt(formationNumber / 10) - 1; Tuple <int, int> rotated = AIUtils.RotateForFormation(dx, dy, unit.UnitFacing); return(new EncounterPosition(center.X + rotated.Item1, center.Y + rotated.Item2)); }
public static FireProjectileAction CreateRailgunAction(string actorId, EncounterPosition targetPosition) { return(new FireProjectileAction( actorId, ProjectileType.RAILGUN, power: 15, (sourcePos) => EncounterPathBuilder.BuildStraightLinePath(sourcePos, targetPosition, maxSteps: 40), speed: 20 )); }
public static FireProjectileAction CreateReverserAction(string actorId, EncounterPosition targetPosition) { return(new FireProjectileAction( actorId, ProjectileType.REVERSER, power: 2, (sourcePos) => EncounterPathBuilder.BuildReverseLinePath(sourcePos, targetPosition, overshoot: 4), speed: 33 )); }
private static FireProjectileAction CreateSmallShotgunAction(string actorId, EncounterPosition targetPosition) { return(new FireProjectileAction( actorId, ProjectileType.SMALL_SHOTGUN, power: 1, (sourcePos) => EncounterPathBuilder.BuildStraightLinePath(sourcePos, targetPosition, maxSteps: 25), speed: 25 )); }
public static FireProjectileAction CreateSmallGatlingAction(string actorId, EncounterPosition targetPosition) { return(new FireProjectileAction( actorId, ProjectileType.SMALL_GATLING, power: 2, (sourcePos) => EncounterPathBuilder.BuildStraightLinePath(sourcePos, targetPosition, maxSteps: 25), speed: 50 )); }
public Lane(int laneIdx, EncounterPosition laneCenter) { this.LaneIdx = laneIdx; this.LaneCenter = laneCenter; this._UnitsForFaction = new Dictionary <FactionName, List <UnitAtLanePosition> >() { { FactionName.ENEMY, new List <UnitAtLanePosition>() }, { FactionName.NEUTRAL, new List <UnitAtLanePosition>() }, { FactionName.PLAYER, new List <UnitAtLanePosition>() } }; }
private static void TryAddAttackAdjacent(EncounterState state, Entity parent, List <EncounterAction> actions, FactionName parentFaction, EncounterPosition targetEndPos) { var adjacentHostiles = AIUtils.AdjacentHostiles(state, parentFaction, targetEndPos); if (adjacentHostiles.Count > 0) { // TODO: don't attack randomly var target = adjacentHostiles[state.EncounterRand.Next(adjacentHostiles.Count)]; actions.Add(new MeleeAttackAction(parent.EntityId, target)); } }
private Label CreateLabel(int power, EncounterPosition position) { var label = new Label(); label.Text = power.ToString(); var numCenterPos = PositionComponent.IndexToVector(position.X, position.Y); label.AddFontOverride("font", this._damageFont); label.AddColorOverride("font_color", new Color(1f, 0f, 0f)); // The size isn't determined until after it's first placed, so we place, then reposition according to size to center it. label.SetPosition(numCenterPos); var size = label.RectSize; label.SetPosition(new Vector2(numCenterPos.x - size.x / 2, numCenterPos.y - size.y / 2)); return(label); }
private bool positionNotTooFarAheadAndMovable(EncounterState state, EncounterPosition parentPos, Unit unit, EncounterPosition possible) { var entitiesAtPos = state.EntitiesAtPosition(possible.X, possible.Y); if (!AIUtils.IsNextRowTooFarAhead(parentPos, unit) && entitiesAtPos.Count == 0) { return(true); } var hostilesAtPos = AIUtils.HostilesInPosition(state, FactionName.PLAYER, possible.X, possible.Y); if (hostilesAtPos.Count > 0) { return(true); } return(false); }
public static FoVCache ComputeFoV(EncounterState state, EncounterPosition center, int radius) { int _x = center.X - radius; int _y = center.Y - radius; bool[,] visibleCells = new bool[radius * 2 + 1, radius * 2 + 1]; var visible = rpasCalc.CalcVisibleCellsFrom(center.X, center.Y, radius, state.IsPositionVisible); foreach ((int, int)pos in visible) { if (state.IsInBounds(pos.Item1, pos.Item2)) { visibleCells[pos.Item1 - _x, pos.Item2 - _y] = true; } } return(new FoVCache(_x, _y, visibleCells)); }
public string ToCardinalDirection(EncounterPosition parentPos, EncounterPosition adjacentPos) { int dx = adjacentPos.X - parentPos.X; int dy = adjacentPos.Y - parentPos.Y; if (dx == 0 && dy == -1) { return(InputHandler.ActionMapping.MOVE_N); } else if (dx == 1 && dy == -1) { return(InputHandler.ActionMapping.MOVE_NE); } else if (dx == 1 && dy == 0) { return(InputHandler.ActionMapping.MOVE_E); } else if (dx == 1 && dy == 1) { return(InputHandler.ActionMapping.MOVE_SE); } else if (dx == 0 && dy == 1) { return(InputHandler.ActionMapping.MOVE_S); } else if (dx == -1 && dy == 1) { return(InputHandler.ActionMapping.MOVE_SW); } else if (dx == -1 && dy == 0) { return(InputHandler.ActionMapping.MOVE_W); } else if (dx == -1 && dy == -1) { return(InputHandler.ActionMapping.MOVE_NW); } else { throw new NotImplementedException(); } }
public override EncounterPosition PositionInFormation(int formationNumber, Unit unit) { EncounterPosition center = unit.RallyPoint; int halfFormation = unit.NumInFormation / 2 + 1; if (formationNumber < halfFormation) { int dx = formationNumber % 10; int dy = Mathf.FloorToInt(formationNumber / 10) - 1; var rotated = AIUtils.RotateForFormation(dx, dy, unit.UnitFacing); return(new EncounterPosition(center.X + rotated.Item1, center.Y + rotated.Item2)); } else { int dx = formationNumber % 10 - 10; int dy = Mathf.FloorToInt((formationNumber - halfFormation) / 10) - 1; var rotated = AIUtils.RotateForFormation(dx, dy, unit.UnitFacing); return(new EncounterPosition(center.X + rotated.Item1, center.Y + rotated.Item2)); } }
public SpawnEntityAction(string spawnerId, Entity entityToSpawn, EncounterPosition position, bool ignoreCollision) : base(spawnerId, ActionType.SPAWN_ENTITY) { this.EntityToSpawn = entityToSpawn; this.Position = position; this.IgnoreCollision = ignoreCollision; }
// Last 5 items are "retreat zone" - TODO: color them yellow, or something private static bool IsInRetreatZone(EncounterState state, EncounterPosition position) { return(!(5 <= position.X && state.MapWidth - 5 >= position.X && 5 <= position.Y && state.MapHeight - 5 >= position.Y)); }
/** * Fires a spread of shotgun pellets in a box formation around the centerpoint. Spread is half the width/height of the box. */ public static List <FireProjectileAction> CreateSmallShotgunAction(string actorId, EncounterPosition targetPosition, int numPellets, int spread, Random seededRand) { if (spread == 0) { throw new NotImplementedException("shotguns can't have 0 spread what is this"); } List <FireProjectileAction> pellets = new List <FireProjectileAction>(); for (int i = 0; i < numPellets; i++) { var dx = seededRand.Next(spread * 2 + 1) - spread; var dy = seededRand.Next(spread * 2 + 1) - spread; pellets.Add(CreateSmallShotgunAction(actorId, new EncounterPosition(targetPosition.X + dx, targetPosition.Y + dy))); } return(pellets); }
public bool IsVisible(EncounterPosition position) { return(this.IsVisible(position.X, position.Y)); }
public static void PopulateStateForLevel(Entity player, int dungeonLevel, EncounterState state, Random seededRand, int width = 300, int height = 300, int maxZoneGenAttempts = 100) { InitializeMapAndAddBorderWalls(state, width, height); // Place each empty zone onto the map int zoneGenAttemps = 0; List <EncounterZone> zones = new List <EncounterZone>(); while (zoneGenAttemps < maxZoneGenAttempts && zones.Count < LevelData.GetNumberOfZones(dungeonLevel)) { int zoneWidth = seededRand.Next(ZONE_MIN_SIZE, ZONE_MAX_SIZE + 1); int zoneHeight = seededRand.Next(ZONE_MIN_SIZE, ZONE_MAX_SIZE + 1); int zoneX = seededRand.Next(1, state.MapWidth - zoneWidth); int zoneY = seededRand.Next(1, state.MapHeight - zoneHeight); var newZone = new EncounterZone(Guid.NewGuid().ToString(), new EncounterPosition(zoneX, zoneY), zoneWidth, zoneHeight, "Zone " + zones.Count.ToString()); bool overlaps = zones.Any(existing => existing.Intersects(newZone)); if (!overlaps) { zones.Add(newZone); } } state._zones = zones; // Add the player to the map var playerZoneIdx = seededRand.Next(0, zones.Count); state.PlaceEntity(player, zones[playerZoneIdx].Center); /* * var nextToPlayer = new EncounterPosition(zones[playerZoneIdx].Center.X + 2, zones[playerZoneIdx].Center.Y + 1); * state.PlaceEntity(EntityBuilder.CreateItemByEntityDefId(EntityDefId.ITEM_RED_PAINT), nextToPlayer); * nextToPlayer = new EncounterPosition(zones[playerZoneIdx].Center.X + 1, zones[playerZoneIdx].Center.Y + 1); * state.PlaceEntity(EntityBuilder.CreateItemByEntityDefId(EntityDefId.ITEM_EMP), nextToPlayer); * for (int i = 0; i < 26; i++) { * nextToPlayer = new EncounterPosition(zones[playerZoneIdx].Center.X + i, zones[playerZoneIdx].Center.Y + 3); * state.PlaceEntity(EntityBuilder.CreateItemByEntityDefId(EntityDefId.ITEM_EXTRA_BATTERY), nextToPlayer); * } */ var nextToPlayer = new EncounterPosition(zones[playerZoneIdx].Center.X + 2, zones[playerZoneIdx].Center.Y + 2); //string[] defs = new string[] { EntityDefId.SCOUT, EntityDefId.FIGHTER, EntityDefId.GUNSHIP, EntityDefId.FRIGATE, EntityDefId.DESTROYER, EntityDefId.CRUISER, EntityDefId.CARRIER, EntityDefId.DIPLOMAT }; string[] defs = new string[] { EntityDefId.ITEM_DUCT_TAPE, EntityDefId.ITEM_EMP, EntityDefId.ITEM_EXTRA_BATTERY, EntityDefId.ITEM_RED_PAINT }; for (int x = 0; x < defs.Length; x++) { for (int y = 0; y < 3; y++) { var pos = new EncounterPosition(nextToPlayer.X + x, nextToPlayer.Y + y); //state.PlaceEntity(EntityBuilder.CreateEnemyByEntityDefId(defs[x], "12345", 0), pos, ignoreCollision: true); state.PlaceEntity(EntityBuilder.CreateItemByEntityDefId(defs[x]), pos, ignoreCollision: true); } } // Add all the various zone features to the map // TODO: Draw this from LevelData instead of literally special-casing level 10 here if (dungeonLevel != 10) { // Generate the stairs (maybe we should refer interally as something more themetically appropriate?) // You can get stairs in your starting zone, but you probably shouldn't take them... // var stairsZone = zones[playerZoneIdx]; // For testing var stairsZone = zones[seededRand.Next(0, zones.Count)]; var stairsPosition = stairsZone.RandomEmptyPosition(seededRand, state); var stairs = EntityBuilder.CreateStairsEntity(); state.PlaceEntity(stairs, stairsPosition); stairsZone.AddFeatureToReadout(stairs); // Generate intel // var intelZone = zones[playerZoneIdx]; // For testing var intelZone = zones[seededRand.Next(0, zones.Count)]; var intelPosition = intelZone.RandomEmptyPosition(seededRand, state); var intel = EntityBuilder.CreateIntelEntity(dungeonLevel + 1); state.PlaceEntity(intel, intelPosition); intelZone.AddFeatureToReadout(intel); } // Populate each zone with an encounter foreach (EncounterZone zone in zones) { if (zone == zones[playerZoneIdx]) { PopulateZone(zone, dungeonLevel, seededRand, state, safe: true); } else { PopulateZone(zone, dungeonLevel, seededRand, state); } } }
private static EncounterPosition _DecideFormationPosition(int formationNumber, EncounterPosition center, Unit unit) { return(AIUtils.FormationDictionary[unit.UnitFormation].PositionInFormation(formationNumber, unit)); }
public MoveAction(string actorId, EncounterPosition targetPosition) : base(actorId, ActionType.MOVE) { TargetPosition = targetPosition; }
public static List <Entity> AdjacentHostiles(EncounterState state, FactionName parentFaction, EncounterPosition position) { var adjacentHostiles = new List <Entity>(); foreach (var newpos in state.AdjacentPositions(position)) { adjacentHostiles.AddRange(AIUtils.HostilesInPosition(state, parentFaction, newpos.X, newpos.Y)); } return(adjacentHostiles); }
public static FireProjectileAction CreateCuttingLaserAction(string playerId, int playerPower, EncounterPosition targetPosition) { return(new FireProjectileAction( playerId, ProjectileType.CUTTING_LASER, power: playerPower, (sourcePos) => EncounterPathBuilder.BuildStraightLinePath(sourcePos, targetPosition, endsAtTarget: true), speed: 0 )); }
public static EncounterPosition RotateAndProject(EncounterPosition origin, int x, int y, FormationFacing facing) { var vec = Rotate(x, y, facing); return(new EncounterPosition(origin.X + vec.Item1, origin.Y + vec.Item2)); }