Esempio n. 1
0
        /// <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);
            }
        }
Esempio n. 2
0
        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);
        }