Пример #1
0
        public void From_should_return_correct_subset_from_array()
        {
            var items = new List <string>()
            {
                "meat", "cheese", "beer", "bread"
            };
            var from = items.From("beer");

            Assert.True(from.SequenceEqual(new[] { "beer", "bread" }));
        }
Пример #2
0
        public void From_should_return_entire_array_if_item_is_at_front_of_array()
        {
            var items = new List <string>()
            {
                "meat", "cheese", "beer", "bread"
            };
            var from = items.From("meat");

            Assert.True(from.SequenceEqual(items));
        }
Пример #3
0
        public void From_should_return_empty_set_when_item_not_found()
        {
            var items = new List <int>()
            {
                1, 2, 3, 4, 5, 6
            };
            var from7 = items.From(7).Take(2);

            from7.Count().ShouldBe(0);
        }
Пример #4
0
        static SoloLevelingUtility()
        {
            Ditto.Connected += async() =>
            {
                // Recheck the valid links
                _links.Clear();
                await Ditto.Database.ReadAsync(uow =>
                {
                    _links.AddRange(uow.Links.GetAllWithLinks(l => l.Type == LinkType.SoloLeveling));
                }).ConfigureAwait(false);

                // TODO: Recalculate number of messages
                foreach (var link in _links)
                {
                    var   messages         = new List <IMessage>();
                    var   lastRecordedDate = GetLastRecordedDateFromLink(link);
                    ulong lastMessageId    = ulong.MaxValue;
                    while (true)
                    {
                        var messagesChunk = Enumerable.Empty <IMessage>();
                        if (lastMessageId != ulong.MaxValue)
                        {
                            messagesChunk = (await link.Channel.GetMessagesAsync(lastMessageId, Direction.Before, 100, CacheMode.AllowDownload).ToListAsync().ConfigureAwait(false))
                                            .SelectMany(m => m)
                                            .Where(m => m.CreatedAt.UtcDateTime > link.Date);
                        }
                        else
                        {
                            messagesChunk = (await link.Channel.GetMessagesAsync(100, CacheMode.AllowDownload).ToListAsync().ConfigureAwait(false))
                                            .SelectMany(m => m)
                                            .Where(m => m.CreatedAt.UtcDateTime > link.Date);
                        }

                        messages.AddRange(messagesChunk);
                        lastMessageId = messagesChunk.LastOrDefault()?.Id ?? ulong.MaxValue;

                        // Cancel when the last recorded message is larger than the earliest message date of the collection, meaning we're good to go.
                        if (lastRecordedDate > messages.Min(x => x.CreatedAt.UtcDateTime))
                        {
                            messages = messages.From(x => x.CreatedAt.UtcDateTime > lastRecordedDate).ToList();
                            break;
                        }

                        // Cancel when message count is less than the maximum.
                        if (messagesChunk.Count() < 100)
                        {
                            break;
                        }
                    }

                    // Process any missed messages
                    if (messages.Count > 0)
                    {
                        foreach (var message in messages)
                        {
                            await ProcessMessageAsync(message).ConfigureAwait(false);
                        }
                    }
                }

                // Start listening to new messages
                await Ditto.Client.DoAsync(client =>
                {
                    client.MessageReceived += OnMessageReceived;
                }).ConfigureAwait(false);
            };

            Ditto.Exit += async() =>
            {
                await Ditto.Client.DoAsync(client =>
                {
                    client.MessageReceived -= OnMessageReceived;
                }).ConfigureAwait(false);
            };
        }
Пример #5
0
        /// <summary>
        /// Run tasks of all phases including and after the given phase.
        /// </summary>
        /// <param name="fromPhase">Optional. The phase to start the run from.</param>
        /// <returns>A task that is completed when all such tasks have been completed, or
        /// there is failure when <see cref="Phase.Recover"/> is disabled.</returns>
        /// <remarks>
        /// It is safe to call this method multiple times. It will only run once.
        /// </remarks>
        public Task <Done> Run(string fromPhase = null)
        {
            if (_runStarted.CompareAndSet(false, true))
            {
                var debugEnabled = Log.IsDebugEnabled;
                Func <List <string>, Task <Done> > loop = null;
                loop = remainingPhases =>
                {
                    var phase = remainingPhases.FirstOrDefault();
                    if (phase == null)
                    {
                        return(TaskEx.Completed);
                    }
                    var         remaining   = remainingPhases.Skip(1).ToList();
                    Task <Done> phaseResult = null;
                    ImmutableList <Tuple <string, Func <Task <Done> > > > phaseTasks;
                    if (!_tasks.TryGetValue(phase, out phaseTasks))
                    {
                        if (debugEnabled)
                        {
                            Log.Debug("Performing phase [{0}] with [0] tasks.", phase);
                        }
                        phaseResult = TaskEx.Completed;
                    }
                    else
                    {
                        if (debugEnabled)
                        {
                            Log.Debug("Performing phase [{0}] with [{1}] tasks: [{2}]", phase,
                                      phaseTasks.Count, string.Join(",", phaseTasks.Select(x => x.Item1)));
                        }

                        // note that tasks within same phase are performed in parallel
                        var recoverEnabled = Phases[phase].Recover;
                        var result         = Task.WhenAll <Done>(phaseTasks.Select(x =>
                        {
                            var taskName = x.Item1;
                            var task     = x.Item2;
                            try
                            {
                                // need to begin execution of task
                                var r = task();

                                if (recoverEnabled)
                                {
                                    return(r.ContinueWith(tr =>
                                    {
                                        if (tr.IsCanceled || tr.IsFaulted)
                                        {
                                            Log.Warning("Task [{0}] failed in phase [{1}]: {2}", taskName, phase,
                                                        tr.Exception?.Flatten().Message);
                                        }
                                        return Done.Instance;
                                    }));
                                }


                                return(r);
                            }
                            catch (Exception ex)
                            {
                                // in case task.Start() throws
                                if (recoverEnabled)
                                {
                                    Log.Warning("Task [{0}] failed in phase [{1}]: {2}", taskName, phase, ex.Message);
                                    return(TaskEx.Completed);
                                }

                                return(TaskEx.FromException <Done>(ex));
                            }
                        })).ContinueWith(tr =>
                        {
                            // forces downstream error propagation if recover is disabled
                            var force = tr.Result;
                            return(Done.Instance);
                        });
                        var         timeout         = Phases[phase].Timeout;
                        var         deadLine        = MonotonicClock.Elapsed + timeout;
                        Task <Done> timeoutFunction = null;
                        try
                        {
                            timeoutFunction = After(timeout, System.Scheduler, () =>
                            {
                                if (phase == CoordinatedShutdown.PhaseActorSystemTerminate &&
                                    MonotonicClock.ElapsedHighRes < deadLine)
                                {
                                    // too early, i.e. triggered by system termination
                                    return(result);
                                }
                                else if (result.IsCompleted)
                                {
                                    return(TaskEx.Completed);
                                }
                                else if (recoverEnabled)
                                {
                                    Log.Warning("Coordinated shutdown phase [{0}] timed out after {1}", phase, timeout);
                                    return(TaskEx.Completed);
                                }
                                else
                                {
                                    return
                                    (TaskEx.FromException <Done>(
                                         new TimeoutException(
                                             $"Coordinated shutdown phase[{phase}] timed out after {timeout}")));
                                }
                            });
                        }
                        catch (SchedulerException)
                        {
                            // The call to `after` threw SchedulerException, triggered by system termination
                            timeoutFunction = result;
                        }
                        catch (InvalidOperationException)
                        {
                            // The call to `after` threw SchedulerException, triggered by Scheduler being in unset state
                            timeoutFunction = result;
                        }

                        phaseResult = Task.WhenAny <Done>(result, timeoutFunction).Unwrap();
                    }

                    if (!remaining.Any())
                    {
                        return(phaseResult);
                    }
                    return(phaseResult.ContinueWith(tr =>
                    {
                        // force any exceptions to be rethrown so next phase stops
                        // and so failure gets propagated back to caller
                        var r = tr.Result;
                        return loop(remaining);
                    }).Unwrap());
                };

                var runningPhases = (fromPhase == null
                    ? OrderedPhases // all
                    : OrderedPhases.From(fromPhase)).ToList();

                var done = loop(runningPhases);
                done.ContinueWith(tr =>
                {
                    if (!tr.IsFaulted && !tr.IsCanceled)
                    {
                        _runPromise.SetResult(tr.Result);
                    }
                    else
                    {
                        // ReSharper disable once PossibleNullReferenceException
                        _runPromise.SetException(tr.Exception.Flatten());
                    }
                });
            }
            return(_runPromise.Task);
        }
 public void From_should_return_entire_array_if_item_is_at_front_of_array()
 {
     var items = new List<string>() { "meat", "cheese", "beer", "bread" };
     var from = items.From("meat");
     Assert.True(from.SequenceEqual(items));
 }
 public void From_should_return_correct_subset_from_array()
 {
     var items = new List<string>() {"meat", "cheese", "beer", "bread"};
     var from = items.From("beer");
     Assert.True(from.SequenceEqual(new[]{ "beer", "bread" }));
 }
 public void From_should_return_empty_set_when_item_not_found()
 {
     var items = new List<int>() {1, 2, 3, 4, 5, 6};
     var from7 = items.From(7).Take(2);
     from7.Count().ShouldBe(0);
 }
Пример #9
0
 public void FireArrow(List<Tile> line,bool free_attack)
 {
     if(!free_attack && StunnedThisTurn()){
         return;
     }
     int mod = -30; //bows have base accuracy 45%
     /*if(magic_trinkets.Contains(MagicTrinketType.RING_OF_KEEN_SIGHT)){
         mod = -15; //keen sight now only affects trap detection
     }*/
     if(this == player && Bow.status[EquipmentStatus.ONE_ARROW_LEFT]){
         mod = 25; //...but the last arrow gets a bonus
     }
     mod += TotalSkill(SkillType.COMBAT);
     Tile t = null;
     Actor a = null;
     bool solid_object_hit = false;
     bool no_terrain_collision_message = free_attack; //don't show "the arrow hits the wall" for echoes.
     List<string> misses = new List<string>();
     List<Actor> missed = new List<Actor>();
     List<Tile> animation_line = new List<Tile>(line);
     line.RemoveAt(0); //remove the source of the arrow first
     if(line.Count > 12){
         line = line.GetRange(0,Math.Min(12,line.Count));
     }
     int flaming_arrow_start = HasAttr(AttrType.FIERY_ARROWS)? 0 : -1; //tracks where an arrow caught fire
     bool blocked_by_armor_miss = false;
     bool blocked_by_root_shell_miss = false;
     for(int i=0;i<line.Count;++i){
         a = line[i].actor();
         t = line[i];
         if(a != null){
             no_terrain_collision_message = true;
             int plus_to_hit = mod - a.TotalSkill(SkillType.DEFENSE)*3;
             bool hit = true;
             if(!a.IsHit(plus_to_hit)){
                 hit = false;
                 int armor_value = a.TotalProtectionFromArmor();
                 if(a != player){
                     armor_value = a.TotalSkill(SkillType.DEFENSE); //if monsters have Defense skill, it's from armor
                 }
                 int roll = R.Roll(55 - plus_to_hit);
                 if(roll <= armor_value * 3){
                     blocked_by_armor_miss = true;
                 }
                 else{
                     if(a.HasAttr(AttrType.ROOTS) && roll <= (armor_value + 10) * 3){ //potion of roots gives 10 defense
                         blocked_by_root_shell_miss = true;
                     }
                 }
             }
             else{
                 if(a.HasAttr(AttrType.TUMBLING)){
                     a.attrs[AttrType.TUMBLING] = 0;
                     hit = false;
                 }
             }
             if(R.CoinFlip() && !CanSee(a)){ //extra 50% miss chance for enemies you can't see
                 hit = false;
                 blocked_by_armor_miss = false;
                 blocked_by_root_shell_miss = false;
             }
             if(hit || blocked_by_armor_miss || blocked_by_root_shell_miss){
                 solid_object_hit = true;
                 break;
             }
             else{
                 misses.Add("The arrow misses " + a.the_name + ". ");
                 missed.Add(a);
             }
             a = null;
         }
         if(!t.passable){
             a = null;
             solid_object_hit = true;
             break;
         }
         if(flaming_arrow_start == -1 && t.IsBurning()){
             flaming_arrow_start = i;
         }
     }
     if(!free_attack){
         if(Bow != null && Bow.status[EquipmentStatus.ONE_ARROW_LEFT]){
             B.Add(You("take") + " careful aim. ",this);
             B.Add(You("fire") + " " + Your() + " last arrow. ",this);
         }
         else{
             if(HasAttr(AttrType.FIERY_ARROWS)){
                 B.Add(You("fire") + " a flaming arrow. ",this);
             }
             else{
                 B.Add(You("fire") + " an arrow. ",this);
             }
         }
         B.DisplayNow();
     }
     int idx = 0;
     /*foreach(Tile tile2 in animation_line){
         if(tile2.seen){
             ++idx; //todo: remove idx here, right?
         }
         else{
             animation_line = animation_line.To(tile2);
             if(animation_line.Count > 0){
                 animation_line.RemoveAt(animation_line.Count - 1);
             }
             break;
         }
     }*/
     if(animation_line.Count > 0){
         Screen.CursorVisible = false;
         PhysicalObject o = t;
         if(a != null){
             o = a;
         }
         animation_line = animation_line.To(o);
         if(flaming_arrow_start >= 0 && !M.wiz_dark && !player.HasAttr(AttrType.BLIND)){ //fire should be visible unless darkened or blind
             List<Tile> first_line = animation_line.ToCount(flaming_arrow_start+2);
             List<Tile> second_line = animation_line.FromCount(flaming_arrow_start+2);
             if(first_line.Count > 0){
                 Screen.AnimateBoltProjectile(animation_line.ToCount(flaming_arrow_start+2),Color.DarkYellow,20);
             }
             Screen.CursorVisible = false;
             if(second_line.Count > 0){
                 Screen.AnimateBoltProjectile(animation_line.FromCount(flaming_arrow_start+2),Color.RandomFire,20);
             }
         }
         else{
             Screen.AnimateBoltProjectile(animation_line,Color.DarkYellow,20);
         }
         Screen.CursorVisible = false;
         if(this == player && solid_object_hit && !player.CanSee(o) && (o is Actor || !o.tile().seen)){
             Screen.AnimateMapCell(o.row,o.col,new colorchar('?',Color.DarkGray),50);
         }
         Screen.CursorVisible = false;
     }
     idx = 0;
     foreach(string s in misses){
         B.Add(s,missed[idx]);
         if(missed[idx] != player){
             missed[idx].player_visibility_duration = -1;
             if(HasLOE(missed[idx])){
                 missed[idx].target = this;
                 missed[idx].target_location = tile();
             }
         }
         ++idx;
     }
     if(flaming_arrow_start != -1){
         foreach(Tile affected in line.FromCount(flaming_arrow_start+2)){
             affected.ApplyEffect(DamageType.FIRE);
             if((a != null && affected.actor() == a) || affected == t){
                 break;
             }
         }
     }
     if(a != null){
         pos target_original_position = a.p;
         if(a.HasAttr(AttrType.IMMUNE_ARROWS)){
             B.Add("The arrow sticks out ineffectively from " + a.the_name + ". ",a);
         }
         else{
             if(a.magic_trinkets.Contains(MagicTrinketType.BRACERS_OF_ARROW_DEFLECTION)){
                 B.Add(a.You("deflect") + " the arrow! ",a);
             }
             else{
                 if(blocked_by_armor_miss){
                     B.Add(a.YourVisible() + " armor blocks the arrow. ",a);
                 }
                 else{
                     if(blocked_by_root_shell_miss){
                         B.Add(a.YourVisible() + " root shell blocks the arrow. ",a);
                     }
                     else{
                         bool alive = true;
                         bool crit = false;
                         int crit_chance = 8; //base crit rate is 1/8
                         if(a.EquippedArmor != null && (a.EquippedArmor.status[EquipmentStatus.WEAK_POINT] || a.EquippedArmor.status[EquipmentStatus.DAMAGED] || a.HasAttr(AttrType.SWITCHING_ARMOR))){
                             crit_chance /= 2;
                         }
                         if(a.HasAttr(AttrType.SUSCEPTIBLE_TO_CRITS)){
                             crit_chance /= 2;
                         }
                         if(Bow != null && Bow.enchantment == EnchantmentType.PRECISION && !Bow.status[EquipmentStatus.NEGATED]){
                             crit_chance /= 2;
                         }
                         if(crit_chance <= 1 || R.OneIn(crit_chance)){
                             crit = true;
                         }
                         if(this == player && IsHiddenFrom(a) && crit && !a.HasAttr(AttrType.NONLIVING,AttrType.PLANTLIKE,AttrType.BOSS_MONSTER) && a.type != ActorType.CYCLOPEAN_TITAN){ //none of the bow-wielding monsters should ever be hidden from the player
                             B.Add(a.the_name + " falls with your arrow between the eyes. ",a);
                             //B.Add("Headshot! ",a);
                             a.Kill();
                             alive = false;
                         }
                         else{
                             B.Add("The arrow hits " + a.the_name + ". ",a);
                             if(!a.TakeDamage(DamageType.NORMAL,DamageClass.PHYSICAL,R.Roll(2,6)+TotalSkill(SkillType.COMBAT),this,a_name + "'s arrow")){
                                 alive = false;
                             }
                             if(crit && alive){
                                 if(a.type == ActorType.CYCLOPEAN_TITAN){
                                     if(!a.HasAttr(AttrType.COOLDOWN_1)){
                                         B.Add(YourVisible() + " arrow pierces its eye, blinding it! ",this,a);
                                         Q.KillEvents(a,AttrType.BLIND);
                                         a.attrs[AttrType.BLIND] = 1;
                                         a.attrs[AttrType.COOLDOWN_1] = 1;
                                     }
                                 }
                                 else{
                                     Event e = Q.FindAttrEvent(a,AttrType.IMMOBILE);
                                     if(!a.HasAttr(AttrType.IMMOBILE) || (e != null && e.msg.Contains("no longer pinned"))){ //i.e. don't pin naturally immobile monsters //todo - new refreshduration implementation should allow this to be done more naturally
                                         B.Add(a.YouAre() + " pinned! ",a);
                                         a.RefreshDuration(AttrType.IMMOBILE,100,a.YouAre() + " no longer pinned. ",a);
                                         if(a.HasAttr(AttrType.FLYING) && a.tile().IsTrap()){
                                             a.tile().TriggerTrap();
                                         }
                                     }
                                 }
                             }
                             if(alive && a.HasAttr(AttrType.NONLIVING)){
                                 if(Bow != null && Bow.enchantment == EnchantmentType.DISRUPTION && !Bow.status[EquipmentStatus.NEGATED]){
                                     B.Add(a.YouAre() + " disrupted! ",a);
                                     if(!a.TakeDamage(DamageType.MAGIC,DamageClass.MAGICAL,a.maxhp / 5,this)){
                                         alive = false;
                                     }
                                 }
                             }
                             if(alive && !a.HasAttr(AttrType.IMMUNE_COLD)){
                                 if(Bow != null && Bow.enchantment == EnchantmentType.CHILLING && !Bow.status[EquipmentStatus.NEGATED]){
                                     B.Add(a.YouAre() + " chilled. ",a);
                                     if(!a.HasAttr(AttrType.CHILLED)){
                                         a.attrs[AttrType.CHILLED] = 1;
                                     }
                                     else{
                                         a.attrs[AttrType.CHILLED] *= 2;
                                     }
                                     if(!a.TakeDamage(DamageType.COLD,DamageClass.MAGICAL,a.attrs[AttrType.CHILLED],this)){
                                         alive = false;
                                     }
                                 }
                             }
                             if(alive && flaming_arrow_start != -1){
                                 a.ApplyBurning();
                             }
                         }
                         if(!alive && Bow != null && Bow.enchantment == EnchantmentType.VICTORY && !Bow.status[EquipmentStatus.NEGATED]){
                             curhp += 5;
                             if(curhp > maxhp){
                                 curhp = maxhp;
                             }
                         }
                     }
                 }
             }
         }
         if(Bow != null && Bow.enchantment == EnchantmentType.ECHOES && !Bow.status[EquipmentStatus.NEGATED]){
             List<Tile> line2 = line.From(M.tile[target_original_position]);
             if(line2.Count > 1){
                 FireArrow(line2,true); //todo: does this need special handling? should a burning monster cause a flaming echo?
             }
         }
     }
     else{
         if(!no_terrain_collision_message || t.Is(TileType.POISON_BULB) || (t.Is(TileType.WAX_WALL) && flaming_arrow_start != -1)){
             B.Add("The arrow hits " + t.the_name + ". ",t);
             if(t.Is(TileType.POISON_BULB)){
                 t.Bump(DirectionOf(t));
             }
             if(flaming_arrow_start != -1){
                 t.ApplyEffect(DamageType.FIRE);
             }
         }
     }
     if(!free_attack){
         Q1();
     }
 }