示例#1
0
文件: Api.cs 项目: UofG-CS21/SGame
        /// <summary>
        /// Handle scanning/shooting on this node:
        /// - Broadcasts the Struck response for the local node
        /// - Moves ships to the graveyard as needed
        /// </summary>
        private Messages.Struck HandleLocalScanShoot(Messages.ScanShoot msg)
        {
            Messages.Struck results = QuadTreeNode.ScanShootLocal(msg);
            Bus.BroadcastMessage(results);

            foreach (var ourStruck in results.ShipsInfo)
            {
                if (ourStruck.Damage < 0.0) // ship ded
                {
                    var ourDeadShip = ourStruck.Ship;
                    QuadTreeNode.ShipsByToken.Remove(ourDeadShip.Token);
                    DeadShips.Add(ourDeadShip.Token, ourDeadShip);
                }
            }

            return(results);
        }
示例#2
0
        public override Messages.Struck ScanShootLocal(Messages.ScanShoot msg)
        {
            bool affected = MathUtils.DoesQuadIntersectCircleSector(this.Bounds, msg);

            if (affected)
            {
                Bus.SendMessage(msg, NodePeer);

                var             struckTask = new MessageWaiter <Messages.Struck>(Bus, NodePeer, (struck) => struck.Originator == msg.Originator).Wait;
                Messages.Struck results    = new Messages.Struck();
                if (Task.WaitAll(new Task[] { struckTask }, REPLYTIMEOUT))
                {
                    results.OriginatorAreaGain += struckTask.Result.OriginatorAreaGain;
                    results.ShipsInfo.AddRange(struckTask.Result.ShipsInfo);
                }
                return(results);
            }
            else
            {
                return(null);
            }
        }
示例#3
0
        public override Messages.Struck ScanShootLocal(Messages.ScanShoot msg)
        {
            Messages.Struck results = new Messages.Struck();

            // 1) Search ships locally (but only if affected by the scan)
            //bool affected = MathUtils.DoesQuadIntersectCircleSector(this.Bounds, msg);
            bool affected = true; // FIXME - This is here to make sure scans always go through; ideally, though, ships would always be in the SGame node that manages them...

            if (affected)
            {
                Vector2 leftPoint  = MathUtils.DirVec(msg.Direction + msg.Width) * msg.Radius;
                Vector2 rightPoint = MathUtils.DirVec(msg.Direction - msg.Width) * msg.Radius;

                Console.WriteLine($"Scanning with radius {msg.Radius}, in triangle <{msg.Origin}, {leftPoint}, {rightPoint}>");

                var iscanned = ShipsByToken.Values
                               .Where((ship) =>
                                      ship.Token != msg.Originator &&
                                      (MathUtils.CircleTriangleIntersection(ship.Pos, ship.Radius(), msg.Origin, leftPoint, rightPoint) ||
                                       MathUtils.CircleSegmentIntersection(ship.Pos, ship.Radius(), msg.Origin, msg.Radius, msg.Direction, msg.Width))
                                      )
                               .Select((ship) => new Messages.Struck.ShipInfo()
                {
                    Ship = ship
                });

                results.ShipsInfo.AddRange(iscanned);

                if (msg.ScaledShotEnergy > 0.0)
                {
                    foreach (var struck in results.ShipsInfo)
                    {
                        var ourShip = (LocalSpaceship)struck.Ship;

                        double shipDistance = (ourShip.Pos - msg.Origin).Length();
                        double damage       = MathUtils.ShotDamage(msg.ScaledShotEnergy, msg.Width, shipDistance);
                        double shielding    = MathUtils.ShieldingAmount(ourShip, msg.Origin, msg.Direction, msg.Width, msg.Radius);
                        if (shielding > 0.0)
                        {
                            Console.WriteLine($"{ourShip.PublicId} shielded itself for {shielding * 100.0}% of {msg.Originator}'s shot (= {damage * shielding} damage)");
                        }
                        damage *= (1.0 - shielding);

                        // We have killed a ship, gain it's kill reward, and move struck ship to the graveyard
                        if (ourShip.Area - damage < MINIMUM_AREA)
                        {
                            results.OriginatorAreaGain += ourShip.KillReward;
                            struck.Damage = -damage;
                        }
                        else // Struck ship survived - note that it's in combat
                        {
                            if (ourShip.LastUpdate - ourShip.LastCombat > LocalSpaceship.COMBAT_COOLDOWN)
                            {
                                // Reset kill reward when hit ship was not in combat
                                ourShip.KillReward = ourShip.Area;
                            }
                            ourShip.LastCombat = ourShip.LastUpdate;
                            ourShip.Area      -= damage;
                            struck.Damage      = damage;
                        }
                    }
                }
            }
            return(results);
        }
示例#4
0
文件: Api.cs 项目: UofG-CS21/SGame
        public async Task Shoot(ApiResponse response, ApiData data)
        {
#if DEBUG
            // HACK: Force game update so older tests still function
            UpdateGameState();
#endif
            LocalSpaceship ship = await IntersectionParamCheck(response, data, true);

            if (ship == null)
            {
                return;
            }
            double widthDeg      = (double)data.Json["width"];
            double directionDeg  = (double)data.Json["direction"];
            double damageScaling = (double)data.Json["damage"];

            int energy = (int)Math.Min((int)data.Json["energy"], Math.Floor(ship.Energy / damageScaling));
            ship.Energy -= energy * damageScaling; //remove energy for the shot

            Console.WriteLine($"Shot by {ship.PublicId}, pos={ship.Pos}, dir={directionDeg}°, width={widthDeg}°, energy spent={energy}, scaling={damageScaling}");

            // 1) Broadcast the "need to shoot this" message
            var shootMsg = new SShared.Messages.ScanShoot()
            {
                Originator       = ship.Token,
                Origin           = ship.Pos,
                Direction        = MathUtils.Deg2Rad(directionDeg),
                ScaledShotEnergy = energy * damageScaling,
                Width            = MathUtils.Deg2Rad(widthDeg),
                Radius           = MathUtils.ScanShootRadius(MathUtils.Deg2Rad(widthDeg), energy),
            };

            // Construct waiters BEFORE we potentially get a reply so that we know for sure it will reach us
            var resultWaiters = Bus.Host.ConnectedPeerList
                                .Where(peer => peer != ArbiterPeer)
                                .Select(peer => new MessageWaiter <Messages.Struck>(Bus, peer, struck => struck.Originator == shootMsg.Originator).Wait)
                                .ToArray();

            Bus.BroadcastMessage(shootMsg, excludedPeer: ArbiterPeer);

            // 2) Shoot locally and broadcast the results of the local shoot
            Messages.Struck results = HandleLocalScanShoot(shootMsg);

            // 3) Wait for the scanning results of all other nodes
            Task.WaitAll(resultWaiters, ScanShootTimeout);

            // 4) Combine the results that arrived with our local ones to find the complete list of all victims
            foreach (var waiter in resultWaiters)
            {
                if (waiter.Status != TaskStatus.RanToCompletion)
                {
                    continue;
                }
                lock (results)
                {
                    results.ShipsInfo.AddRange(waiter.Result.ShipsInfo);
                    results.OriginatorAreaGain += waiter.Result.OriginatorAreaGain;
                }
            }

            // 5) Apply area gain to the local shooter ship (if any)
            ship.Area += results.OriginatorAreaGain;

            JArray respDict = new JArray();
            foreach (var struckShip in results.ShipsInfo)
            {
                // ignore our ship
                if (struckShip.Ship.Token == ship.Token)
                {
                    continue;
                }

                double preShotArea = struckShip.Ship.Area + Math.Abs(struckShip.Damage);

                //The api doesnt have a return value for shooting, but ive left this in for now for testing purposes.
                JToken struckShipInfo = new JObject();
                struckShipInfo["id"]   = struckShip.Ship.PublicId;
                struckShipInfo["area"] = preShotArea;
                struckShipInfo["posX"] = struckShip.Ship.Pos.X;
                struckShipInfo["posY"] = struckShip.Ship.Pos.Y;
                respDict.Add(struckShipInfo);
            }

            //Ship performed combat action, lock kill reward if not in combat from before
            if (ship.LastUpdate - ship.LastCombat > LocalSpaceship.COMBAT_COOLDOWN)
            {
                ship.KillReward = ship.Area;
            }
            ship.LastCombat = ship.LastUpdate;

            response.Data["struck"] = respDict;
            await response.Send();
        }
示例#5
0
文件: Api.cs 项目: UofG-CS21/SGame
        public async Task Scan(ApiResponse response, ApiData data)
        {
            var ship = await IntersectionParamCheck(response, data);

            if (ship == null)
            {
                return;
            }

            int    energy       = (int)data.Json["energy"];
            double directionDeg = (double)data.Json["direction"];
            double widthDeg     = (double)data.Json["width"];

            energy       = (int)Math.Min(energy, Math.Floor(ship.Energy));
            ship.Energy -= energy;

            Console.WriteLine($"Scan by {ship.PublicId}, pos={ship.Pos}, dir={directionDeg}°, width={widthDeg}°, energy spent={energy}");

            // 1) Broadcast the "need to scan this" message
            var scanMsg = new SShared.Messages.ScanShoot()
            {
                Originator       = ship.Token,
                Origin           = ship.Pos,
                Direction        = MathUtils.Deg2Rad(directionDeg),
                ScaledShotEnergy = 0,
                Width            = MathUtils.Deg2Rad(widthDeg),
                Radius           = MathUtils.ScanShootRadius(MathUtils.Deg2Rad(widthDeg), energy),
            };

            // Construct waiters BEFORE we potentially get a reply so that we know for sure it will reach us
            var resultWaiters = Bus.Host.ConnectedPeerList
                                .Where(peer => peer != ArbiterPeer)
                                .Select(peer => new MessageWaiter <Messages.Struck>(Bus, peer, struck => struck.Originator == scanMsg.Originator).Wait)
                                .ToArray();

            Bus.BroadcastMessage(scanMsg, excludedPeer: ArbiterPeer);

            // 2) Scan locally and broadcast the results of the local scan
            Messages.Struck results = HandleLocalScanShoot(scanMsg);

            // 3) Wait for the scanning results of all other nodes
            Task.WaitAll(resultWaiters, ScanShootTimeout);

            // 4) Combine the results that arrived with our local ones to find the whole list of scanned ships
            foreach (var waiter in resultWaiters)
            {
                if (waiter.Status != TaskStatus.RanToCompletion)
                {
                    continue;
                }
                results.ShipsInfo.AddRange(waiter.Result.ShipsInfo);
            }

            JArray respDict = new JArray();

            foreach (var scanned in results.ShipsInfo)
            {
                if (scanned.Ship.Token == ship.Token)
                {
                    continue;
                }

                //The api doesnt have a return value for shooting, but ive left this in for now for testing purposes.
                JToken struckShipInfo = new JObject();
                struckShipInfo["id"]   = scanned.Ship.PublicId;
                struckShipInfo["area"] = scanned.Ship.Area;
                struckShipInfo["posX"] = scanned.Ship.Pos.X;
                struckShipInfo["posY"] = scanned.Ship.Pos.Y;
                respDict.Add(struckShipInfo);
            }

            response.Data["scanned"] = respDict;
            await response.Send();
        }