/// <summary> /// Call the AI with a status message. /// </summary> /// <param name="xmlMessage">Can be null. The remote AI XML for a message without the status or my player values set.</param> /// <param name="about">The player this status is about. Will be set to receiving user for status not specific to a player.</param> /// <param name="status">The status for this message.</param> /// <param name="players">All the players.</param> /// <param name="passengers">All the passengers.</param> public void GameStatus(XDocument xmlMessage, Player about, PlayerAIBase.STATUS status, List<Player> players, List<Passenger> passengers) { // only care if for me, and an action (ie not status) if ((status == PlayerAIBase.STATUS.UPDATE) || ((about != null) && (about.Guid != aiWorker.MyPlayerGuid))) return; Player player = players.Find(pl => pl.Guid == aiWorker.MyPlayerGuid); Trap.trap(about == null); if (about == null) about = player; aiWorker.AddMessage(status, about, AllPickups(player, passengers)); }
private void toolStripMenuItemSetDest_Click(object sender, EventArgs e) { playerMouseSetDest = contextMenuRMB.Tag as Player; Cursor = Cursors.Cross; }
private void mapDisplay_MouseClickedEvent(Point mapUnits, MouseButtons buttons) { Cursor = Cursors.Default; if (GameFramework.Mode != Framework.COMM_STATE.PAUSED && GameFramework.Mode != Framework.COMM_STATE.READY_TO_START) { playerMouseMove = playerMouseSetDest = null; return; } if ((buttons & MouseButtons.Right) != 0) { foreach (Player plyrOn in GameFramework.GameEngine.Players) { int xDiff = Math.Abs(plyrOn.Limo.Location.MapPosition.X - mapUnits.X); int yDiff = Math.Abs(plyrOn.Limo.Location.MapPosition.Y - mapUnits.Y); if ((xDiff >= PixelsPerTile/4) || (yDiff >= PixelsPerTile/4)) continue; contextMenuRMB.Tag = plyrOn; foreach (ToolStripMenuItem menu in toolStripMenuItemSetPassenger.DropDownItems) menu.Enabled = !plyrOn.PassengersDelivered.Contains((Passenger) menu.Tag); contextMenuRMB.Show(MousePosition); return; } Console.Beep(); return; } if (((buttons & MouseButtons.Left) == 0) || (playerMouseMove == null && playerMouseSetDest == null)) return; // get the quarter tile location (needed for direction) on car move. Point ptQuarter = new Point(mapUnits.X/(TileMovement.UNITS_PER_TILE/2), mapUnits.Y/(TileMovement.UNITS_PER_TILE/2)); Point ptTile = new Point(ptQuarter.X/2, ptQuarter.Y/2); // can only set the car or dest in a road or bus-stop MapSquare square = GameFramework.GameEngine.MainMap.SquareOrDefault(ptTile); if (square == null) { Console.Beep(); Trap.trap(); return; } if (playerMouseSetDest != null) { if (square.Tile.Type != MapTile.TYPE.BUS_STOP) { Console.Beep(); playerMouseMove = playerMouseSetDest = null; return; } List<Point> path = SimpleAStar.CalculatePath(GameFramework.GameEngine.MainMap, playerMouseSetDest.Limo.Location.TilePosition, ptTile); if (path.Count > 1) path.Add(path[path.Count - 2]); GameFramework.GameEngine.ProcessAllMoveMessages(); GameFramework.GameEngine.PlayerOrders(playerMouseSetDest, path, new List<Passenger>()); playerMouseMove = playerMouseSetDest = null; } if (playerMouseMove != null) { if (square.Tile.Type != MapTile.TYPE.ROAD && square.Tile.Type != MapTile.TYPE.BUS_STOP) { Console.Beep(); playerMouseMove = playerMouseSetDest = null; return; } // process before we change the location. GameFramework.GameEngine.ProcessAllMoveMessages(); switch (square.Tile.Direction) { case MapTile.DIRECTION.NORTH_SOUTH: playerMouseMove.Limo.SetTileLocation(square, ptTile, (ptQuarter.X & 1) == 1 ? MapSquare.COMPASS_DIRECTION.NORTH : MapSquare.COMPASS_DIRECTION.SOUTH); break; case MapTile.DIRECTION.EAST_WEST: playerMouseMove.Limo.SetTileLocation(square, ptTile, (ptQuarter.Y & 1) == 1 ? MapSquare.COMPASS_DIRECTION.EAST : MapSquare.COMPASS_DIRECTION.WEST); break; case MapTile.DIRECTION.INTERSECTION: if ((ptQuarter.X & 1) == 1 && (ptQuarter.Y & 1) == 1) playerMouseMove.Limo.SetTileLocation(square, ptTile, MapSquare.COMPASS_DIRECTION.NORTH); else if ((ptQuarter.X & 1) == 0 && (ptQuarter.Y & 1) == 1) playerMouseMove.Limo.SetTileLocation(square, ptTile, MapSquare.COMPASS_DIRECTION.EAST); else if ((ptQuarter.X & 1) == 0 && (ptQuarter.Y & 1) == 0) playerMouseMove.Limo.SetTileLocation(square, ptTile, MapSquare.COMPASS_DIRECTION.SOUTH); else playerMouseMove.Limo.SetTileLocation(square, ptTile, MapSquare.COMPASS_DIRECTION.WEST); break; default: Console.Beep(); playerMouseMove = playerMouseSetDest = null; return; } Point ptDest = playerMouseMove.NextBusStop != null ? playerMouseMove.NextBusStop.BusStop : (playerMouseMove.Limo.PathTiles.Count > 1 ? playerMouseMove.Limo.PathTiles[playerMouseMove.Limo.PathTiles.Count - 2] : Point.Empty); List<Point> path; if (ptDest != Point.Empty) { path = SimpleAStar.CalculatePath(GameFramework.GameEngine.MainMap, playerMouseMove.Limo.Location.TilePosition, ptDest); if (path.Count > 1) path.Add(path[path.Count - 2]); } else path = new List<Point>(); GameFramework.GameEngine.PlayerOrders(playerMouseMove, path, new List<Passenger>()); playerMouseMove = playerMouseSetDest = null; mapDisplay.Invalidate(); UpdatePlayers(); UpdateDebug(); } }
/// <summary> /// Called when the game starts, providing all info. /// </summary> public void Setup(GameMap map, Player me, List<Player> players, List<Company> companies, List<Passenger> passengers, PlayerAIBase.PlayerOrdersEvent ordersEvent) { sendOrders = ordersEvent; XDocument doc = new XDocument(); XElement elemRoot = new XElement("setup", new XAttribute("game-start", true), new XAttribute("my-guid", me.Guid)); doc.Add(elemRoot); // the map XElement elemMap = new XElement("map", new XAttribute("width", map.Width), new XAttribute("height", map.Height), new XAttribute("units-tile", TileMovement.UNITS_PER_TILE)); elemRoot.Add(elemMap); for (int x = 0; x < map.Width; x++ ) for (int y = 0; y < map.Height; y++) { MapSquare square = map.Squares[x][y]; XElement elemRow = new XElement("tile", new XAttribute("x", x), new XAttribute("y", y), new XAttribute("type", square.Tile.Type)); if (square.Tile.IsDriveable) { elemRow.Add(new XAttribute("direction", square.Tile.Direction)); if (square.StopSigns != MapSquare.STOP_SIGNS.NONE) elemRow.Add(new XAttribute("stop-sign", square.StopSigns)); if (square.SignalDirection != MapSquare.SIGNAL_DIRECTION.NONE) elemRow.Add(new XAttribute("signal", true)); } elemMap.Add(elemRow); } // all players (including me) XElement elemPlayers = new XElement("players"); elemRoot.Add(elemPlayers); foreach (Player plyrOn in players) elemPlayers.Add(new XElement("player", new XAttribute("guid", plyrOn.Guid), new XAttribute("name", plyrOn.Name), new XAttribute("limo-x", plyrOn.Limo.Location.TilePosition.X), new XAttribute("limo-y", plyrOn.Limo.Location.TilePosition.Y), new XAttribute("limo-angle", plyrOn.Limo.Location.Angle))); // all companies XElement elemCompanies = new XElement("companies"); elemRoot.Add(elemCompanies); foreach (Company cmpnyOn in companies) elemCompanies.Add(new XElement("company", new XAttribute("name", cmpnyOn.Name), new XAttribute("bus-stop-x", cmpnyOn.BusStop.X), new XAttribute("bus-stop-y", cmpnyOn.BusStop.Y))); // all passengers XElement elemPassengers = new XElement("passengers"); elemRoot.Add(elemPassengers); foreach (Passenger psngrOn in passengers) { XElement elemPassenger = new XElement("passenger", new XAttribute("name", psngrOn.Name), new XAttribute("points-delivered", psngrOn.PointsDelivered)); // if due to a re-start, these can be null if (psngrOn.Lobby != null) elemPassenger.Add(new XAttribute("lobby", psngrOn.Lobby.Name)); if (psngrOn.Destination != null) elemPassenger.Add(new XAttribute("destination", psngrOn.Destination.Name)); foreach (Company route in psngrOn.Companies) elemPassenger.Add(new XElement("route", route.Name)); foreach (Passenger enemy in psngrOn.Enemies) elemPassenger.Add(new XElement("enemy", enemy.Name)); elemPassengers.Add(elemPassenger); } framework.tcpServer.SendMessage(TcpGuid, doc.ToString()); }
public StatusMessage(PlayerAIBase.STATUS status, Player player, List<Passenger> pickup) { Status = status; LimoTileLocation = player.Limo.Location.TilePosition; PassengerDestBusStop = player.Passenger == null ? Point.Empty : player.Passenger.Destination.BusStop; Pickup = pickup; }
/// <summary> /// List of all passengers we can pick up. Does not include ones already delivered and if presently carrying one, /// does not include that one. Returned in random order, different random order each time called. /// </summary> private static List<Passenger> AllPickups(Player me, IEnumerable<Passenger> passengers) { List<Passenger> pickup = new List<Passenger>(); pickup.AddRange(passengers.Where( psngr => (!me.PassengersDelivered.Contains(psngr)) && (psngr != me.Passenger) && (psngr.Car == null) && (psngr.Destination != null)).OrderBy(psngr => rand.Next())); return pickup; }
private void ReadMessage(Player player, XElement root, out List<Point> path, out List<Passenger> pickup) { // get the requested path. Does not check that it is on the map or continuous - the engine checks that. path = new List<Point>(); XElement element = root.Element("path"); if (element != null) { string trail = element.Value; if (!string.IsNullOrEmpty(trail)) { string[] steps = trail.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string stepOn in steps) { string[] coords = stepOn.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); int x, y; if ((coords.Length != 2) || (!int.TryParse(coords[0], out x)) || (!int.TryParse(coords[1], out y))) { Trap.trap(); StatusMessage(string.Format("Player {0} provided an invalid path element {1}", player.Name, stepOn)); break; } path.Add(new Point(x, y)); } } } // get the requested pick-up list. Does not check for already delivered - the engine checks that. pickup = new List<Passenger>(); element = root.Element("pick-up"); if (element != null) { string allNames = element.Value; if (!string.IsNullOrEmpty(allNames)) { string[] names = allNames.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string nameOn in names) { Passenger psngr = GameEngine.Passengers.FirstOrDefault(ps => ps.Name == nameOn); if (psngr != null) pickup.Add(psngr); else { Trap.trap(); StatusMessage(string.Format("Player {0} provided an invalid pick-up name {1}", player.Name, nameOn)); } } } } }
/// <summary> /// Player is ready to start. /// </summary> /// <param name="player">The player. null if a join, non-null (maybe) if a re-join.</param> /// <param name="root">The XML message.</param> private void MsgPlayerOrders(Player player, XElement root) { List<Point> path; List<Passenger> pickup; ReadMessage(player, root, out path, out pickup); GameEngine.RemoteMessages.Enqueue(new Engine.AiMessage(player, path, pickup)); }
internal void PlayerOrders(Player player, List<Point> path, List<Passenger> pickUp) { // sync up - try to find a node in the existing path that matches if (path.Count > 0) { // 1. new path has a match somewhere with the tile presently on (ie we've moved beyond the start of // a path that is duplicated for a bit, then goes elsewhere). for (int index = 0; index < path.Count; index++) if (path[index] == player.Limo.Location.TilePosition) { if (index == 0) break; path.RemoveRange(0, index); break; } // 2. starts on the tile we're on (and this includes 1. above). if (player.Limo.Location.TilePosition == path[0]) { player.Limo.PathTiles.Clear(); // if we need a U-turn, we add the next tile and then the tile on again. Point ptNext = player.Limo.Location.NextTilePosition; if ((path.Count == 1) || (ptNext != path[1])) { // on this tile, then go into the next tile, then path[0] is back to this tile. Trap.trap(!MainMap.SquareOrDefault(ptNext).Tile.IsDriveable); player.Limo.PathTiles.Add(ptNext); } // set it to the new path player.Limo.PathTiles.AddRange(path); } else { // look for existing path has a match with the start of the new path (ie the new path is for // when this path has gotten a little further). bool foundMatch = false; for (int index = 0; index < player.Limo.PathTiles.Count; index++) if (player.Limo.PathTiles[index] == path[0]) { player.Limo.PathTiles.RemoveRange(index, player.Limo.PathTiles.Count - index); player.Limo.PathTiles.AddRange(path); foundMatch = true; break; } // no match - no new path and let the user know if (!foundMatch) player.GameStatus(null, player, PlayerAIBase.STATUS.NO_PATH, Players, Passengers); } for (int ind = 1; ind < player.Limo.PathTiles.Count; ind++) { Company cmpy = companies.FirstOrDefault(cpy => cpy.BusStop == player.Limo.PathTiles[ind]); if (cmpy != null) { player.NextBusStop = cmpy; break; } } } if (pickUp.Count <= 0) return; // new pick-up list. player.PickUp.Clear(); foreach (Passenger psngrOn in pickUp.Where(psngrOn => (!player.PassengersDelivered.Contains(psngrOn)))) player.PickUp.Add(psngrOn); }
public void RestartPlayer(Player player) { Trap.trap(); player.Setup(MainMap, player, Players, companies, Passengers, PlayerAddOrder); }
private void ValidateData(Player plyr) { }
private void ValidateData(Player plyr) { // passengers ok? bool error = false; if (plyr.PassengersDelivered.Contains(plyr.Passenger)) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} is carrying passenger {1} who was already delivered before", plyr.Name, plyr.Passenger.Name)); error = true; } foreach (Passenger pickupOn in plyr.PickUp.Where(pickupOn => plyr.PassengersDelivered.Contains(pickupOn))) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} wants to pick up passenger {1} who was already delivered before", plyr.Name, pickupOn.Name)); error = true; } // passenger location ok? foreach (Passenger psngrOn in Passengers) { if (psngrOn.Car != null && psngrOn.Lobby != null) { if (log.IsWarnEnabled) log.Warn(string.Format("Passenger {0} in car {1} and lobby {2}", psngrOn.Name, psngrOn.Car.Location.TilePosition, psngrOn.Lobby.Name)); error = true; } if (psngrOn.Lobby != null && ! psngrOn.Lobby.Passengers.Contains(psngrOn)) { if (log.IsWarnEnabled) log.Warn(string.Format("Passenger {0} in lobby {1} but that company does not list it", psngrOn.Name, psngrOn.Lobby.Name)); error = true; } } foreach (Company cmpyOn in companies) foreach (Passenger psngrOn in cmpyOn.Passengers) if (psngrOn.Lobby != cmpyOn) { if (log.IsWarnEnabled) log.Warn(string.Format("Passenger {0} in lobby {1} but company {2} lists it", psngrOn.Name, psngrOn.Lobby == null ? "null" : psngrOn.Lobby.Name, cmpyOn.Name)); error = true; } // path ok? foreach (Point ptTileOn in plyr.Limo.PathTiles) { MapTile tile = MainMap.Squares[ptTileOn.X][ptTileOn.Y].Tile; if (! tile.IsDriveable) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} has path entry[{1}] which is of type {2}", plyr.Name, ptTileOn, tile.Type)); error = true; } } for (int ind = 1; ind < plyr.Limo.PathTiles.Count; ind++) { int x = Math.Abs(plyr.Limo.PathTiles[ind].X - plyr.Limo.PathTiles[ind - 1].X); int y = Math.Abs(plyr.Limo.PathTiles[ind].Y - plyr.Limo.PathTiles[ind - 1].Y); if (x + y != 1) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} at path[{1}] illegal {2} -> {3}", plyr.Name, ind, plyr.Limo.PathTiles[ind-1], plyr.Limo.PathTiles[ind])); error = true; } } #if STRICT // cars on top of each other (never should have 2 in the same quarter tile Point ptQtr = BoardLocation.MapToQuarterTile(plyr.Limo.Location.MapPosition); foreach (Player plyrOn in Players.Where(plyrOn => plyrOn != plyr).Where(plyrOn => ptQtr == BoardLocation.MapToQuarterTile(plyrOn.Limo.Location.MapPosition))) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} and Player {1} are both on quarter tile {2}", plyr.Name, plyrOn.Name, ptQtr)); error = true; } #endif // car location ok? Point pt = plyr.Limo.Location.TilePosition; if (! MainMap.Squares[pt.X][pt.Y].Tile.IsDriveable) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} is located at {1} which is of type {2}", plyr.Name, plyr.Limo.Location, MainMap.Squares[pt.X][pt.Y].Tile.Type)); error = true; } if (plyr.Limo.Location.OffsetTileMoves == 0) { int xOff = plyr.Limo.Location.MapPosition.X%TileMovement.UNITS_PER_TILE; int yOff = plyr.Limo.Location.MapPosition.Y%TileMovement.UNITS_PER_TILE; switch (plyr.Limo.Location.Direction) { case MapSquare.COMPASS_DIRECTION.NORTH: if (xOff != 18 || yOff != 0) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} is located at {1} which has a bad offset of {2},{3} (should be 18,0)", plyr.Name, plyr.Limo.Location, xOff, yOff)); error = true; } break; case MapSquare.COMPASS_DIRECTION.EAST: if (xOff != 0 || yOff != 18) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} is located at {1} which has a bad offset of {2},{3} (should be 18,0)", plyr.Name, plyr.Limo.Location, xOff, yOff)); error = true; } break; case MapSquare.COMPASS_DIRECTION.SOUTH: if (xOff != 6 || yOff != 0) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} is located at {1} which has a bad offset of {2},{3} (should be 18,0)", plyr.Name, plyr.Limo.Location, xOff, yOff)); error = true; } break; case MapSquare.COMPASS_DIRECTION.WEST: if (xOff != 0 || yOff != 6) { if (log.IsWarnEnabled) log.Warn(string.Format("Player {0} is located at {1} which has a bad offset of {2},{3} (should be 18,0)", plyr.Name, plyr.Limo.Location, xOff, yOff)); error = true; } break; } } Trap.trap(error); }
/// <summary> /// Initializes a new instance of the <see cref="T:System.Object"/> class. /// </summary> public AiMessage(Player player, List<Point> path, List<Passenger> pickup) { Player = player; Path = path; Pickup = pickup; }
public void Setup(GameMap map, Player me, List<Player> players, List<Company> companies, List<Passenger> passengers, PlayerAIBase.PlayerOrdersEvent ordersEvent) { ai.Setup(map, me, players, companies, passengers, ordersEvent); }
/// <summary> /// Call the AI with a status message. /// </summary> /// <param name="xmlMessage">Can be null. The remote AI XML for a message without the status or my player values set.</param> /// <param name="about">The player this is about.</param> /// <param name="status">The status for this message.</param> /// <param name="players">All the players.</param> /// <param name="passengers">All the passengers.</param> public void GameStatus(XDocument xmlMessage, Player about, PlayerAIBase.STATUS status, List<Player> players, List<Passenger> passengers) { ai.GameStatus(xmlMessage, about, status, players, passengers); }
/// <summary> /// Create the window. /// </summary> /// <param name="player">The player this window is for.</param> public PlayerStatus(Player player) { InitializeComponent(); Player = player; }
/// <summary> /// Player is (re)joining the game. /// </summary> /// <param name="player">The player. null if a join, non-null (maybe) if a re-join.</param> /// <param name="guid">The tcp guid of the message.</param> /// <param name="root">The XML message.</param> private void MsgPlayerJoining(Player player, string guid, XElement root) { // if the player exists do nothing because we're already set up (client sent it twice). if (player != null) { Trap.trap(); log.Error(string.Format("Join on existing connected player. connection: {0}", guid)); return; } // must have a name string name = AttributeOrNull(root, "name"); if (string.IsNullOrEmpty(name)) { Trap.trap(); log.Error(string.Format("Join with no name refused. Guid: {0}", guid)); tcpServer.CloseConnection(guid); return; } // if auto-run, must match if (AutoRunNumGames > 0) { if (! AutoRunUsers.Contains(name)) { log.Error(string.Format("Join from non auto-run player {0} refused. Guid: {1}", name, guid)); tcpServer.CloseConnection(guid); return; } } // check for new connection on existing player player = engine.Players.FirstOrDefault(pl => pl.Name == name); if (player != null && player.TcpGuid == null) { player.TcpGuid = guid; // resend the setup (they may have re-started) if (commState != COMM_STATE.ACCEPTING_JOINS && commState != COMM_STATE.GAME_OVER) { Trap.trap(); player.WaitingForReply = Player.COMM_MODE.WAITING_FOR_START; GameEngine.RestartPlayer(player); } if (log.IsInfoEnabled) log.Info(string.Format("Player {0} reconnected", name)); mainWindow.StatusMessage(string.Format("Player {0} reconnected", name)); return; } // unique name? player = engine.Players.FirstOrDefault(pl => pl.Name == name); if (player != null) { log.Error(string.Format("Player {0} name already exists, duplicate refused.", name)); mainWindow.StatusMessage(string.Format("Player {0} name already exists, duplicate refused.", name)); tcpServer.CloseConnection(guid); return; } int ind = engine.Players.Count; // do we have room? if (ind >= NUM_PLAYERS) { log.Error(string.Format("Can't add a {0}th player. Name: {1}", NUM_PLAYERS + 1, name)); tcpServer.CloseConnection(guid); return; } // we're in progress - no new players if (commState != COMM_STATE.ACCEPTING_JOINS) { Trap.trap(); log.Error(string.Format("Game in progress - new players not allowed. Name: {0}", name)); mainWindow.StatusMessage(string.Format("game in progress - new players not allowed. Name: {0}", name)); tcpServer.CloseConnection(guid); return; } // ok, we're all good. Create the player XElement elemAvatar = root.Element("avatar"); Image avatar = null; if (elemAvatar != null) { try { byte[] data = Convert.FromBase64String(elemAvatar.Value); avatar = new Bitmap(new MemoryStream(data)); // bugbug - scale if not 32x32 if ((avatar.Width != 32) || (avatar.Height != 32)) mainWindow.StatusMessage(string.Format("Avatar for player {0} not 32x32", name)); } catch (Exception ex) { mainWindow.StatusMessage(string.Format("Avatar for player {0} had error {1}", name, ex.Message)); } } string school = AttributeOrNull(root, "school"); string language = AttributeOrNull(root, "language"); player = new Player(Guid.NewGuid().ToString(), name, school, language, avatar, new Limo(engine.StartLocations[ind], robotBitmaps[ind]), playerColors[ind], new RemoteAI(this, guid)); engine.Players.Add(player); // if we have 10, we're ready to go int maxPlayers = AutoRunNumGames == 0 ? NUM_PLAYERS : AutoRunUsers.Count; if (DebugStartMode || engine.Players.Count >= maxPlayers || (!string.IsNullOrEmpty(TestUser))) CloseJoins(); string msg = string.Format("Player {0} joined from {1}", name, tcpServer.GetIpAddress(guid)); log.Info(msg); mainWindow.StatusMessage(msg); mainWindow.NewPlayerAdded(); mainWindow.UpdateMenu(); }
private void BusStopOffOn(Player plyr, Point busStop) { Company cmpny = companies.FirstOrDefault(cpy => cpy.BusStop == busStop); if (cmpny == null) { if (log.IsInfoEnabled) log.Info(string.Format("Player {0} enters bus stop {1} which is NOT a company", plyr.Name, busStop)); return; } if (log.IsInfoEnabled) { log.Info(string.Format("Player {0} enters bus stop {1} with {2}", plyr.Name, cmpny.Name, plyr.Passenger == null ? "{none}" : plyr.Passenger.Name)); if (cmpny.Passengers.Count > 0) log.Info(string.Format(" In lobby: {0}", string.Join(",", cmpny.Passengers.Select(cpy => cpy.Name).ToArray()))); if (plyr.PickUp.Count > 0) log.Info(string.Format(" Pick-up: {0}", string.Join(",", plyr.PickUp.Select(psngr => psngr.Name).ToArray()))); } // drop off if we have one and can do so PlayerAIBase.STATUS status = PlayerAIBase.STATUS.PASSENGER_NO_ACTION; Passenger psngrAbandoned = null; if (plyr.Passenger != null) { // Any enemies here? bool noDrop = cmpny.Passengers.Any(psngr => psngr.Lobby == cmpny && plyr.Passenger.Enemies.Contains(psngr)); string msg; if (noDrop) { status = PlayerAIBase.STATUS.PASSENGER_REFUSED; msg = string.Format("Player {0} could not drop off passenger {1} at {2}", plyr.Name, plyr.Passenger.Name, cmpny.Name); framework.StatusMessage(msg); } else if (plyr.Passenger.Destination == cmpny) { msg = string.Format("Player {0} dropped off passenger {1} at {2}", plyr.Name, plyr.Passenger.Name, cmpny.Name); framework.StatusMessage(msg); plyr.Delivered(plyr.Passenger); plyr.Passenger.Arrived(cmpny); cmpny.Passengers.Add(plyr.Passenger); plyr.Passenger = null; status = PlayerAIBase.STATUS.PASSENGER_DELIVERED; } else { msg = string.Format("Player {0} abandoned passenger {1} at {2}", plyr.Name, plyr.Passenger.Name, cmpny.Name); framework.StatusMessage(msg); psngrAbandoned = plyr.Passenger; plyr.Passenger.Abandoned(cmpny); cmpny.Passengers.Add(plyr.Passenger); plyr.Passenger = null; status = PlayerAIBase.STATUS.PASSENGER_ABANDONED; } if (log.IsInfoEnabled) log.Info(msg); } // pick up if we have none (check because drop off may have been disallowed). // Can't be one we completed and can't be the one we dropped above. if (plyr.Passenger == null) { Passenger passenger = plyr.PickUp.FirstOrDefault(psngr => (psngr.Lobby == cmpny) && (psngr.Car == null) && (! plyr.PassengersDelivered.Contains(psngr)) && (psngr != psngrAbandoned)); if (passenger != null) { string msg = string.Format("Player {0} picked up passenger {1} at {2}", plyr.Name, passenger.Name, cmpny.Name); if (log.IsInfoEnabled) log.Info(msg); framework.StatusMessage(msg); passenger.EnterCar(plyr.Limo); plyr.Passenger = passenger; plyr.PickUp.Remove(passenger); cmpny.Passengers.Remove(passenger); status = status == PlayerAIBase.STATUS.PASSENGER_NO_ACTION ? PlayerAIBase.STATUS.PASSENGER_PICKED_UP : PlayerAIBase.STATUS.PASSENGER_DELIVERED_AND_PICKED_UP; } } if (log.IsInfoEnabled) { log.Info(string.Format("Player {0} exits bus stop {1} with {2}", plyr.Name, cmpny.Name, plyr.Passenger == null ? "{none}" : plyr.Passenger.Name)); if (cmpny.Passengers.Count > 0) log.Info(string.Format(" In lobby: {0}", string.Join(",", cmpny.Passengers.Select(cpy => cpy.Name).ToArray()))); if (plyr.PickUp.Count > 0) log.Info(string.Format(" Pick-up: {0}", string.Join(",", plyr.PickUp.Select(psngr => psngr.Name).ToArray()))); } // Tell all players (and reset when next general status update will occur) framework.ticksSinceLastUpdate = 0; foreach (Player plyrOn in Players) plyrOn.GameStatus(null, plyr, status, Players, Passengers); if (!framework.FullSpeed) { framework.mainWindow.UpdatePlayers(); framework.mainWindow.UpdateDebug(); } }
/// <summary> /// Player is ready to start. /// </summary> /// <param name="player">The player. null if a join, non-null (maybe) if a re-join.</param> /// <param name="root">The XML message.</param> private void MsgPlayerReady(Player player, XElement root) { List<Point> path; List<Passenger> pickup; ReadMessage(player, root, out path, out pickup); GameEngine.RemoteMessages.Enqueue(new Engine.AiMessage(player, path, pickup)); player.WaitingForReply = Player.COMM_MODE.RECEIVED_START; // if all ready (or all AI), we start if (engine.Players.All(pl => pl.WaitingForReply == Player.COMM_MODE.RECEIVED_START || pl.TcpGuid == null)) { if (commState == COMM_STATE.ACCEPTING_JOINS || commState == COMM_STATE.ACCEPTING_SETUP) commState = COMM_STATE.READY_TO_START; CommTimerClose(); mainWindow.SetupGame(); // test mode? If so we're good and so exit with code 0. if ((!string.IsNullOrEmpty(TestUser)) && player.Name == TestUser) { tcpServer.SendMessage(player.TcpGuid, "<exit/>"); Thread.Sleep(100); Environment.Exit(0); } if (DebugStartMode || AutoRunNumGames != 0) Play(); } }
/// <summary> /// Determine if any other limos are in this intersection. /// </summary> /// <param name="plyr">The player checking for. Ok if this player's car is in the intersection.</param> /// <param name="ptIntersection">The intersection tile. This is in tile units.</param> /// <param name="numFutureLook">How many steps into the future to look.</param> /// <returns></returns> private bool CarInIntersection(Player plyr, Point ptIntersection, int numFutureLook) { // bugbug numFutureLook (elsewhere too) depends on left/right/straight foreach (Player plyrOn in Players.Where(plyrOn => plyrOn != plyr)) { // if they're more than the numFutureLook + limo size (Bitmap/2) away, then no need to walk as it can't match. if ((Math.Abs(plyr.Limo.Location.MapPosition.X - plyrOn.Limo.Location.MapPosition.X) > numFutureLook + TileMovement.UNITS_PER_TILE) || (Math.Abs(plyr.Limo.Location.MapPosition.Y - plyrOn.Limo.Location.MapPosition.Y) > numFutureLook + TileMovement.UNITS_PER_TILE)) continue; // we walk numFutureLook (or till Future runs out) steps in the future to see if it's in the intersection. int stepsRemaining = numFutureLook; foreach (Limo.QuarterSteps stepOn in plyrOn.Limo.Future) { if (BoardLocation.QuarterTileToTile(stepOn.QuarterLocation) == ptIntersection) { if (log.IsDebugEnabled) log.Debug(string.Format("Player {0} : Player {1} Future in intersection {2}", plyr.Name, plyrOn.Name, ptIntersection)); return true; } stepsRemaining -= stepOn.Steps; if (stepsRemaining <= 0) break; } // checking the tail if (plyrOn.Limo.TailQuarter.Any(qtrOn => BoardLocation.QuarterTileToTile(qtrOn) == ptIntersection)) { // bus stop (or any u-turn), one car wants out, the other pulls in where it has 1 map unit tail still in the intersection. // so if both vehicle center's are in the same tile AND they are in oppisate directions, then we say not in the intersection var tile = MainMap.SquareOrDefault(ptIntersection).Tile; if ((tile.Type == MapTile.TYPE.BUS_STOP) || (tile.Type == MapTile.TYPE.ROAD)) if (tile.Direction == MapTile.DIRECTION.NORTH_UTURN || tile.Direction == MapTile.DIRECTION.EAST_UTURN || tile.Direction == MapTile.DIRECTION.SOUTH_UTURN || tile.Direction == MapTile.DIRECTION.WEST_UTURN) { Trap.trap(); if (plyrOn.Limo.Location.Direction == MapSquare.UTurn(plyr.Limo.Location.Direction)) { Trap.trap(); continue; } Trap.trap(); } if (log.IsDebugEnabled) log.Debug(string.Format("Player {0} : Player {1} Future in intersection {2}", plyr.Name, plyrOn.Name, ptIntersection)); return true; } if (log.IsDebugEnabled) log.Debug(string.Format("Player {0} : Player {1} NOT in intersection {2}", plyr.Name, plyrOn.Name, ptIntersection)); } return false; }
/// <summary> /// Called when the game starts, providing all info. /// </summary> /// <param name="map">The game map.</param> /// <param name="me">The player being setup..</param> /// <param name="players">All the players.</param> /// <param name="companies">All companies on the board.</param> /// <param name="passengers">All the passengers.</param> /// <param name="ordersEvent">Callback to pass orders to the engine.</param> public void Setup(GameMap map, Player me, List<Player> players, List<Company> companies, List<Passenger> passengers, PlayerAIBase.PlayerOrdersEvent ordersEvent) { // start the thread aiWorker = new AiWorker(map, me.Guid, companies, ordersEvent); aiThread = new Thread(aiWorker.MainLoop) {Name = me.Name.Replace(' ', '_'), IsBackground = true}; aiThread.Start(); // cause it to pick a passenger to pick up and calculate the path to that company. aiWorker.AddMessage(PlayerAIBase.STATUS.NO_PATH, me, AllPickups(me, passengers)); }
/// <summary> /// Move the limo. /// </summary> /// <param name="plyr">The player who's limo is being moved.</param> /// <param name="signalsSet">Tiles where the signal has had it's value set/locked.</param> /// <param name="lastPass">true if last pass. Any slow down or stopping occurs this time.</param> private void MoveLimo(Player plyr, List<Point> signalsSet, bool lastPass) { bool isDebugEnabled = log.IsDebugEnabled; // 4.7% of total CPU time when called in each case here. if (isDebugEnabled) log.Debug(string.Format("{0} : MoveLimo, speed = {1}, accrued = {2}, steps = {3}, location = {4}", plyr.Name, plyr.Limo.Speed, plyr.Limo.AccruedSteps, plyr.Limo.StepsRemaining, plyr.Limo.Location)); // if stuck, un-stick it if (plyr.Limo.NumTurnsStopped >= Limo.MAX_TURNS_STOPPED) { plyr.Limo.Accelerate(); plyr.Limo.IsForceMove = true; plyr.Limo.StepsRemaining = TileMovement.MAX_STRAIGHT_SPEED; } else plyr.Limo.IsForceMove = false; // once for each step on this tick while (plyr.Limo.StepsRemaining > 0) { // there's the point that the center of the sprite is on - actual movement goes from that // plyr.Limo.Location is map & tile on. Point ptCenterNextMapPos = plyr.Limo.Location.NextPosition; // there's the point the front of the sprite is at - stop signs and traffic go from that. Point ptFrontMapPos = plyr.Limo.Front; Point ptFrontTile = BoardLocation.MapToTile(ptFrontMapPos); Point ptFrontNextMapPos = plyr.Limo.FrontNextStep; Point ptFrontNextTile = BoardLocation.MapToTile(ptFrontNextMapPos); if (isDebugEnabled) log.Debug(string.Format("{0} : MoveLimo, ptFront = {1} ({2}), ptNext = {3} ({4})", plyr.Name, ptFrontMapPos, ptFrontTile, ptFrontNextMapPos, ptFrontNextTile)); MapSquare square = MainMap.Squares[ptFrontNextTile.X][ptFrontNextTile.Y]; MapSquare.COMPASS_DIRECTION direction = plyr.Limo.Location.Direction; // stop sign or red light - we stop. Only test when we would enter the tile (once in, you don't stop!) if ((! plyr.Limo.IsForceMove) && (ptFrontTile != ptFrontNextTile)) { bool isStop = square.IsStop(direction); int limoHalfLength = plyr.Limo.VehicleBitmap.Height / 4 + 1; // signal - turn green if allowed. Otherwise request green and it will go yellow the other way. if (square.SignalDirection != MapSquare.SIGNAL_DIRECTION.NONE) { // the /2 for half length and the other /2 because map units are 1/2 sprite units. bool carInInter = CarInIntersection(plyr, ptFrontNextTile, limoHalfLength); // We have to lock the signal once it is used. Otherwise car #1 gets a green and car #2 flips it to the other direction. bool signalLocked = signalsSet.Contains(ptFrontNextTile); // if the signal is not locked and we can only flip to yellow, wait in case the car will move out if ((!signalLocked) && carInInter && (!lastPass)) { if (isDebugEnabled) log.Debug(string.Format("{0} : see if signal opens up, location = {1}", plyr.Name, plyr.Limo.Location)); return; } // if the signal has not been locked yet, lock it. // we are here even if we are not stopped (have a green) - because we need to lock in the green. if (!signalLocked) signalsSet.Add(ptFrontNextTile); // if this is the first on this square, then we can set the signal. if (isStop && (!signalLocked)) { if (carInInter) { // flip it to yellow so we get it when the car in there exits. switch (direction) { case MapSquare.COMPASS_DIRECTION.NORTH: case MapSquare.COMPASS_DIRECTION.SOUTH: square.SignalDirection = MapSquare.SIGNAL_DIRECTION.EAST_WEST_YELLOW; break; case MapSquare.COMPASS_DIRECTION.EAST: case MapSquare.COMPASS_DIRECTION.WEST: square.SignalDirection = MapSquare.SIGNAL_DIRECTION.NORTH_SOUTH_YELLOW; break; } } else { // all ours - flip to green (may already be green) and keep going isStop = false; switch (direction) { case MapSquare.COMPASS_DIRECTION.NORTH: case MapSquare.COMPASS_DIRECTION.SOUTH: square.SignalDirection = MapSquare.SIGNAL_DIRECTION.NORTH_SOUTH_GREEN; break; case MapSquare.COMPASS_DIRECTION.EAST: case MapSquare.COMPASS_DIRECTION.WEST: square.SignalDirection = MapSquare.SIGNAL_DIRECTION.EAST_WEST_GREEN; break; } } if (isDebugEnabled) log.Debug(string.Format("{0} : signal at {1} flipped to {2}", plyr.Name, ptFrontNextTile, square.SignalDirection)); } } // see if we can go again. if (isStop && (square.StopSigns != MapSquare.STOP_SIGNS.NONE) && (plyr.Limo.IsStopped)) { bool carInInter = CarInIntersection(plyr, ptFrontNextTile, limoHalfLength + TileMovement.NUM_UNITS_CROSS_ROAD); if (!carInInter) { isStop = false; plyr.Limo.Go(); } // wait and see if it clears out. if (isStop && (! lastPass)) { if (isDebugEnabled) log.Debug(string.Format("{0} : see if stop opens up, location = {1}", plyr.Name, plyr.Limo.Location)); ValidateData(plyr); return; } } // stop signs will always have this true if (isStop) { plyr.Limo.Stop(); if (isDebugEnabled) log.Debug(string.Format("{0} : STOP, location = {1}", plyr.Name, plyr.Limo.Location)); ValidateData(plyr); return; } // if we're making a left turn in an intersection, we have to look at future of other cars. We can only do this if they have // a path because the random direction is selected when the center croses into the new tile. if (plyr.Limo.PathTiles.Count > 0) switch (square.Tile.Direction) { case MapTile.DIRECTION.INTERSECTION: case MapTile.DIRECTION.T_NORTH: case MapTile.DIRECTION.T_EAST: case MapTile.DIRECTION.T_SOUTH: case MapTile.DIRECTION.T_WEST: Point ptNext = plyr.Limo.PathTiles[0]; int indPath = 1; if (ptNext == ptFrontTile && indPath < plyr.Limo.PathTiles.Count) ptNext = plyr.Limo.PathTiles[indPath++]; if (ptNext == ptFrontNextTile && indPath < plyr.Limo.PathTiles.Count) ptNext = plyr.Limo.PathTiles[indPath]; if (ptFrontNextTile == ptNext) { if (isDebugEnabled) log.Debug(string.Format("{0} : ptFrontNextTile == ptNext == {1} (count = {2}", plyr.Name, ptNext, plyr.Limo.PathTiles.Count)); break; } MapSquare.COMPASS_DIRECTION dirEnter = MapSquare.PointsDirection(ptFrontTile, ptFrontNextTile); MapSquare.COMPASS_DIRECTION dirExit = MapSquare.PointsDirection(ptFrontNextTile, ptNext); // fast exit for straight if (dirEnter == dirExit) break; // exit if right turn if ((dirEnter != MapSquare.COMPASS_DIRECTION.NORTH || dirExit != MapSquare.COMPASS_DIRECTION.WEST) && (dirEnter != MapSquare.COMPASS_DIRECTION.EAST || dirExit != MapSquare.COMPASS_DIRECTION.NORTH) && (dirEnter != MapSquare.COMPASS_DIRECTION.SOUTH || dirExit != MapSquare.COMPASS_DIRECTION.EAST) && (dirEnter != MapSquare.COMPASS_DIRECTION.WEST || dirExit != MapSquare.COMPASS_DIRECTION.SOUTH)) break; // ok it's a left or U turn - need to check oncoming traffic if (isDebugEnabled) log.Debug(string.Format("{0} : making left turn {1} to {2} (ptNext = {3})", plyr.Name, dirEnter, dirExit, ptNext)); // check the future of other cars - see if it is anywhere in the square. Distance is MaxTileSteps steps through the curve // at speed MAX_CURVE_SPEED while the oncoming is at MAX_STRAIGHT_SPEED. Plus the car from center to front * 3/4 for car plus space between int safeDistance = (plyr.Limo.VehicleBitmap.Height * 3) / 4 + 1 + ((TileMovement.MAX_TILE_STEPS + TileMovement.MAX_CURVE_SPEED - 1) / TileMovement.MAX_CURVE_SPEED) * TileMovement.MAX_STRAIGHT_SPEED; foreach (Player plyrOn in Players.Where(plyrOn => plyrOn != plyr)) { // if they're more than the Limo.NUM_FUTURE away, then no need to walk as it can't match. if ((Math.Abs(plyr.Limo.Location.MapPosition.X - plyrOn.Limo.Location.MapPosition.X) > safeDistance + TileMovement.UNITS_PER_TILE) || (Math.Abs(plyr.Limo.Location.MapPosition.Y - plyrOn.Limo.Location.MapPosition.Y) > safeDistance + TileMovement.UNITS_PER_TILE)) continue; // if they're stopped, not an issue if (plyrOn.Limo.IsStopped && BoardLocation.MapToTile(plyrOn.Limo.Front) != ptFrontNextTile) { if (isDebugEnabled) log.Debug(string.Format("{0} : player {1} limo stopped - ignore for turn check", plyr.Name, plyrOn.Name)); continue; } // see if anyone's future goes into this quarter tile (we use quarter tiles for collision detection). int numSteps = safeDistance; if (isDebugEnabled) log.Debug(string.Format("{0} : check {1} oncoming into tile {2}, safeDist = {3}", plyr.Name, plyrOn.Name, ptFrontNextTile, safeDistance)); // we first check for the cent of the limo in this tile. This handles cars turning (which will end up cross and not catch in the below foreach). // this also handles any case of any car in the intersection for any reason - we don't turn then because that would be a conflict for an // outer curve (exception being an inverse inner curve - but tough). bool waitForOncoming = plyrOn.Limo.Location.TilePosition == ptFrontNextTile; if (! waitForOncoming) foreach (Limo.QuarterSteps stepOn in plyrOn.Limo.Future) { if (isDebugEnabled) log.Debug(string.Format("{0} : stepOn = {1} ({2})", plyr.Name, stepOn, BoardLocation.QuarterTileToTile(stepOn.QuarterLocation))); if (BoardLocation.QuarterTileToTile(stepOn.QuarterLocation) == ptFrontNextTile) { // they must be coming from the opposite direction to matter. If coming from the left/right // they are going to hit a signal or stoplight. We need the next tile out to get direction (next quarter tile can be diaganol). Point ptCenterPlyrOn = plyrOn.Limo.Location.TilePosition; MapSquare.COMPASS_DIRECTION dirPlyrOn = MapSquare.COMPASS_DIRECTION.NONE; foreach (Limo.QuarterSteps qs in plyrOn.Limo.Future) { Point ptFutureTile = BoardLocation.QuarterTileToTile(qs.QuarterLocation); if (ptFutureTile != ptCenterPlyrOn) { dirPlyrOn = MapSquare.PointsDirection(ptCenterPlyrOn, ptFutureTile); break; } } Trap.trap(dirPlyrOn == MapSquare.COMPASS_DIRECTION.NONE); if (dirPlyrOn != MapSquare.COMPASS_DIRECTION.NONE && MapSquare.UTurn(dirPlyrOn) != dirEnter) { if (isDebugEnabled) log.Debug(string.Format("{0} : player {1} dir from side {2} - ignore for turn check", plyr.Name, plyrOn.Name, dirPlyrOn)); break; } waitForOncoming = true; break; } // see if gone enough steps numSteps -= stepOn.Steps; if (numSteps <= 0) break; } if (!waitForOncoming) continue; // wait and see if it moves if ((!lastPass) && (plyrOn.Limo.StepsRemaining > 0)) { if (isDebugEnabled) log.Debug(string.Format("{0} : left turn wait - behind {1}, location = {2}", plyr.Name, plyrOn.Name, plyrOn.Limo.Location)); ValidateData(plyr); return; } // need to stop plyr.Limo.Stop(); if (isDebugEnabled) log.Debug(string.Format("{0} : left turn stop because of {1}, location = {2}", plyr.Name, plyrOn.Name, plyrOn.Limo.Location)); ValidateData(plyr); return; } break; } else if (isDebugEnabled) log.Debug(string.Format("{0} : path.count == 0", plyr.Name)); } // is there anyone in our way? 1.5 is center to front plus 1 car length. Additional /2 is because map units are 1/2 sprite units. if (!plyr.Limo.IsForceMove) { int safeDistance = (plyr.Limo.VehicleBitmap.Height*3)/4 + 1; foreach (Player plyrOn in Players.Where(plyrOn => plyrOn != plyr)) { // if they're more than the Limo.NUM_FUTURE + Limo.NUM_TAIL away, then no need to walk as it can't match. if ((Math.Abs(plyr.Limo.Location.MapPosition.X - plyrOn.Limo.Location.MapPosition.X) > Limo.NUM_FUTURE + Limo.NUM_TAIL + TileMovement.UNITS_PER_TILE) || (Math.Abs(plyr.Limo.Location.MapPosition.Y - plyrOn.Limo.Location.MapPosition.Y) > Limo.NUM_FUTURE + Limo.NUM_TAIL + TileMovement.UNITS_PER_TILE)) continue; // see if we hit anyone's tail with our future int stepsRemaining = safeDistance; foreach (Limo.QuarterSteps stepOn in plyr.Limo.Future) { // see if both are in the same quarter tile. We use quarter tiles for collision detection. if (plyrOn.Limo.TailQuarter.Contains(stepOn.QuarterLocation)) { // wait and see if it moves if ((!lastPass) && (plyrOn.Limo.StepsRemaining > 0)) { if (isDebugEnabled) log.Debug(string.Format("{0} : wait - behind {1}, location = {2}", plyr.Name, plyrOn.Name, plyrOn.Limo.Location)); ValidateData(plyr); return; } // next turn will +0.5 so this will have a final affect of -0.5 plyr.Limo.Decelerate(); plyr.Limo.NumTurnsStopped++; if (isDebugEnabled) log.Debug(string.Format("{0} : stuck behind {1}, location = {2}", plyr.Name, plyrOn.Name, plyrOn.Limo.Location)); ValidateData(plyr); return; } // see if we've walked far enough. stepsRemaining -= stepOn.Steps; if (stepsRemaining <= 0) break; } } } // if the next center position is in the same tile, we can move along the offset if (plyr.Limo.Location.IsMoveInsideTile) { plyr.Limo.Move(); plyr.Limo.StepsRemaining--; if (isDebugEnabled) log.Debug(string.Format("{0} : move within tile, location = {1}", plyr.Name, plyr.Limo.Location)); Trap.trap(ptCenterNextMapPos != plyr.Limo.Location.MapPosition); ValidateData(plyr); // have we arrived at a bus stop - needs to be the center point. Point ptCenterTile = plyr.Limo.Location.TilePosition; MapSquare squareCenter = MainMap.Squares[ptCenterTile.X][ptCenterTile.Y]; if ((squareCenter.Tile.Type == MapTile.TYPE.BUS_STOP) && (plyr.Limo.Location.OffsetTileMoves == plyr.Limo.Location.TileMoves.Moves.Length / 2)) { BusStopOffOn(plyr, ptCenterTile); plyr.Limo.Stop(); plyr.Limo.Go(); if (isDebugEnabled) log.Debug(string.Format("{0} : bus stop processed limo = {1}", plyr.Name, plyr.Limo)); Trap.trap(ptCenterNextMapPos != plyr.Limo.Location.MapPosition); ValidateData(plyr); } continue; } // we may be holding the tile we're on in the path. If so, get rid of it. (Generally occurs when given a new path.) if ((plyr.Limo.PathTiles.Count > 0) && (plyr.Limo.PathTiles[0] == plyr.Limo.Location.TilePosition)) plyr.Limo.PathTiles.RemoveAt(0); // we move to the next spot (start of next tile), then below assign movement within the tile plyr.Limo.Move(); plyr.Limo.StepsRemaining--; if (isDebugEnabled) log.Debug(string.Format("{0} : move 1 prep for next tile, location = {1}", plyr.Name, plyr.Limo.Location)); Trap.trap(plyr.Limo.Location.OffsetTileMoves != plyr.Limo.Location.TileMoves.Moves.Length); Trap.trap(ptCenterNextMapPos != plyr.Limo.Location.MapPosition); // we now work with the next position because that moves us into the next tile if we are at offset 0 and going north or west. // this has to be the next map position converted to tile position because that is sometimes this tile position, sometimes next. ptCenterNextMapPos = plyr.Limo.Location.NextPosition; Point ptCenterNextTile = BoardLocation.MapToTile(ptCenterNextMapPos); // discard next tile(s) - if it has it and if it's the one we're entering. int indexPath = plyr.Limo.PathTiles.FindIndex(pt => pt == ptCenterNextTile); if (indexPath != -1) plyr.Limo.PathTiles.RemoveRange(0, indexPath + 1); // get our new destination - from the path if valid MapSquare.COMPASS_DIRECTION destDirection = MapSquare.COMPASS_DIRECTION.NONE; if (plyr.Limo.PathTiles.Count > 0) { int x = plyr.Limo.PathTiles[0].X - ptCenterNextTile.X; int y = plyr.Limo.PathTiles[0].Y - ptCenterNextTile.Y; if (Math.Abs(x) + Math.Abs(y) == 1) { if (MainMap.Squares[plyr.Limo.PathTiles[0].X][plyr.Limo.PathTiles[0].Y].Tile.IsDriveable) { destDirection = MapSquare.PointsDirection(ptCenterNextTile, plyr.Limo.PathTiles[0]); if (isDebugEnabled) log.Debug(string.Format("{0} : {1} = {2} - {3}", plyr.Name, destDirection, ptCenterNextTile, plyr.Limo.PathTiles[0])); } else { Trap.trap(); plyr.GameStatus(null, plyr, PlayerAIBase.STATUS.NO_PATH, Players, Passengers); plyr.Limo.PathTiles.Clear(); } } } // need to grab one of the exit tiles at random. U-turn only if no alternative if (destDirection == MapSquare.COMPASS_DIRECTION.NONE) { destDirection = square.Tile.GetRandomNext(direction); if (isDebugEnabled) log.Debug(string.Format("{0} : {1} = GetRandomNext({2})", plyr.Name, destDirection, direction)); } // get the inter-tile movement and assign TileMovement movement = TileMovement.GetMove(direction, destDirection); plyr.Limo.Location.SetMapPosition(plyr.Limo.Location.MapPosition, movement); // do we have to slow down? if (plyr.Limo.Location.TileMoves.MaxSpeed < plyr.Limo.Speed) { float diff = plyr.Limo.Speed - plyr.Limo.Location.TileMoves.MaxSpeed; plyr.Limo.Speed = plyr.Limo.Location.TileMoves.MaxSpeed; plyr.Limo.StepsRemaining = Math.Max(0, plyr.Limo.StepsRemaining - (int) (diff + 0.9f)); } if (isDebugEnabled) log.Debug(string.Format("{0} : next tile complete, location = {1}", plyr.Name, plyr.Limo.Location)); ValidateData(plyr); } }
public void AddMessage(PlayerAIBase.STATUS status, Player about, List<Passenger> pickup) { StatusMessage msg = new StatusMessage(status, about, pickup); lock (messages) messages.Enqueue(msg); EventThread.Set(); }
/// <summary> /// Calculates the estimated path for each limo. Resets count of steps taken. Adjusts speed. /// </summary> /// <param name="plyr">The player being reset for the move.</param> private void PrepareToMove(Player plyr) { if (log.IsDebugEnabled) log.Debug(string.Format("{0} : PrepareToMove, location = {1}", plyr.Name, plyr.Limo.Location)); plyr.Limo.Future.Clear(); Point ptOn = plyr.Limo.Location.MapPosition; Point ptMapStart = BoardLocation.MapToTile(ptOn); plyr.Limo.AddFuture(ptOn); BoardLocation location = new BoardLocation(plyr.Limo.Location); int pathOffset = 0; for (int ind = 0; ind < Limo.NUM_FUTURE; ind++) { if (location.IsMoveInsideTile) { location.Move(); plyr.Limo.AddFuture(location.MapPosition); continue; } // get where we enter the next tile Point ptNextMap = location.NextPosition; Point ptNextTile = location.NextTilePosition; MapSquare squareNext = MainMap.Squares[ptNextTile.X][ptNextTile.Y]; MapSquare.COMPASS_DIRECTION dirOn = location.Direction; // if we enter a stop or signal, we're done guessing the future. We've actually moved the car half way into the // intersection in this case. But it's more efficient than getting the front location each step and // we need the path up to the tile edge. // We go on a signal regardless of color because it can be green when we get there and this is used to see if cars // the other way can turn left. if (ptNextTile != ptMapStart) { if (squareNext.IsStopAllGreen(dirOn)) { if (log.IsDebugEnabled) log.Debug(string.Format("{0} : PrepareToMove hit stop at = {1}, {2}", plyr.Name, ptNextTile, dirOn)); break; } // might be a u-turn ptMapStart = Point.Empty; } // move into the next tile - so below calculations are based on the tile we've just entered (but can now move through in any direction). location.Move(); plyr.Limo.AddFuture(location.MapPosition); // we now work with the next position because that moves us into the next tile if we are at offset 0 and going north or west. // this has to be the next map position converted to tile position because that is sometimes this tile position, sometimes next. Trap.trap(location.MapPosition != ptNextMap); ptNextMap = location.NextPosition; ptNextTile = BoardLocation.MapToTile(ptNextMap); // we increment it here because a U-turn does not move to the next tile and we need the same offset again. if ((pathOffset < plyr.Limo.PathTiles.Count) && (plyr.Limo.PathTiles[pathOffset] == ptNextTile)) pathOffset++; // get our new destination - from the path if valid MapSquare.COMPASS_DIRECTION destDirection = MapSquare.COMPASS_DIRECTION.NONE; if (plyr.Limo.PathTiles.Count > pathOffset) { int x = plyr.Limo.PathTiles[pathOffset].X - ptNextTile.X; int y = plyr.Limo.PathTiles[pathOffset].Y - ptNextTile.Y; if (Math.Abs(x) + Math.Abs(y) == 1) destDirection = MapSquare.PointsDirection(ptNextTile, plyr.Limo.PathTiles[pathOffset]); else if (log.IsDebugEnabled) log.Debug(string.Format("{0} : PrepareToMove path error at = {1}, {2}; pathOff={3}, count={4}; x={5}, y={6}", plyr.Name, ptNextTile, dirOn, pathOffset, plyr.Limo.PathTiles.Count, x, y)); } // if no path, we get the next one only if just one choice (straight/curves) or straight is allowed. // in other words, entering the top of a T we assume straight across. Entering from the base we stop (returns NONE). if (destDirection == MapSquare.COMPASS_DIRECTION.NONE) destDirection = squareNext.Tile.GetStraightNext(dirOn); if (destDirection == MapSquare.COMPASS_DIRECTION.NONE) { if (log.IsDebugEnabled) log.Debug(string.Format("{0} : PrepareToMove no dirNext at = {1}, {2}; pathOff={3}, count={4}", plyr.Name, ptNextTile, dirOn, pathOffset, plyr.Limo.PathTiles.Count)); break; } // get the inter-tile movement and assign TileMovement movement = TileMovement.GetMove(dirOn, destDirection); location.SetMapPosition(location.MapPosition, movement); if (log.IsDebugEnabled) log.Debug(string.Format("{0} : PrepareToMove next tile complete, location = {1}", plyr.Name, location)); } if (log.IsDebugEnabled) { if (plyr.Limo.Future.Count == 0) log.Debug(string.Format("{0} : PrepareToMove complete, future, len=0", plyr.Name)); else log.Debug(string.Format("{0} : PrepareToMove complete, future = {1}..{2}, len={3}", plyr.Name, plyr.Limo.Future[0], plyr.Limo.Future[plyr.Limo.Future.Count - 1], plyr.Limo.Future.Count)); } }
public PlayerInfo(Player src) { Trap.trap(); Guid = src.Guid; }
/// <summary> /// Call the AI with a status message. /// </summary> /// <param name="xmlMessage">Can be null. The remote AI XML for a message without the status or my player values set.</param> /// <param name="about">The player this status is about. Will be set to receiving user for status not specific to a player.</param> /// <param name="status">The status for this message.</param> /// <param name="players">All the players.</param> /// <param name="passengers">All the passengers.</param> public void GameStatus(XDocument xmlMessage, Player about, PlayerAIBase.STATUS status, List<Player> players, List<Passenger> passengers) { if (TcpGuid == null) return; if (xmlMessage == null) xmlMessage = BuildMessageXml(players, passengers); XAttribute attr = xmlMessage.Root.Attribute("status"); if (attr == null) xmlMessage.Root.Add(new XAttribute("status", status)); else attr.Value = status.ToString(); attr = xmlMessage.Root.Attribute("player-guid"); if (attr == null) xmlMessage.Root.Add(new XAttribute("player-guid", about.Guid)); else attr.Value = about.Guid; StringBuilder buf = new StringBuilder(); Player player = framework.GameEngine.Players.Find(pl => pl.TcpGuid == TcpGuid); if (player != null) foreach (Point ptOn in player.Limo.PathTiles) buf.Append(Convert.ToString(ptOn.X) + ',' + Convert.ToString(ptOn.Y) + ';'); XElement elem = xmlMessage.Root.Element("path"); if (elem == null) { elem = new XElement("path"); xmlMessage.Root.Add(elem); elem.Value = buf.ToString(); } else elem.Value = buf.ToString(); if (player != null) { buf.Clear(); foreach (Passenger psngr in player.PickUp) buf.Append(psngr.Name + ';'); } elem = xmlMessage.Root.Element("pick-up"); if (elem == null) { elem = new XElement("pick-up"); xmlMessage.Root.Add(elem); elem.Value = buf.ToString(); } else elem.Value = buf.ToString(); framework.tcpServer.SendMessage(TcpGuid, xmlMessage.ToString()); }