Ejemplo n.º 1
0
        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();
        }
Ejemplo n.º 2
0
        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();
        }