Example #1
0
        public static Grid On(Grid grid)
        {
            foreach (var row in grid.EachRow())
            {
                var run = new List<Cell>();

                foreach(var cell in row)
                {
                    run.Add(cell);
                    var closeOut = cell.East == null || (cell.North != null && rand.Next(2) == 0);

                    if (closeOut)
                    {
                        var member = run.Random();
                        if (member.North != null)
                        {
                            member.Link(member.North);
                        }
                        run.Clear();
                    }
                    else
                    {
                        cell.Link(cell.East);
                    }
                }
            }

            return grid;
        }
Example #2
0
 public Color RandomNeutralColor()
 {
     var lightGreen = new ColorHSV(132f, 0.8f, 1.0f).ToColor();
     var lime = new ColorHSV(0.95f, 0.866f, 1.0f).ToColor();
     var neutrals = new List<Color>()
     {
         lightGreen, lime
     };
     var neutralColor = neutrals.Random();
     return neutralColor;
 }
Example #3
0
        private static void GenerateClicks(List<int> articles, List<string> users)
        {
            Parallel.ForEach(articles, new ParallelOptions { MaxDegreeOfParallelism = 30 }, articleId =>
            {
                var stopWatch = new Stopwatch();
                stopWatch.Start();
                var random = new Random();
                var viewCount = random.Next(50, 1000);
                var acrticlesView = new List<StatiscticArticleView>();
                Console.WriteLine("Proccessing Clicks for ArticleId: {0}, Clicks count: {1}", articleId, viewCount);
                for (int i = 0; i < viewCount; i++)
                {
                    acrticlesView.Add(new StatiscticArticleView
                    {
                        ArticleId = articleId,
                        Time = DateTime.UtcNow.AddDays(0 - random.Next(5, 100)).AddHours(0 - random.Next(0, 24)).AddMinutes(0 - random.Next(0, 60)),
                        UserId = random.Next(0, 100) > 15 ? users.Random() : null
                    });
                }

                try
                {
                    using (var context = new ApplicationDbContext())
                    {
                        var commentEnity = (DbSet<StatiscticArticleView>)context.StatiscticArticleViews;
                        commentEnity.AddRange(acrticlesView);
                        context.SaveChanges();
                    }
                }
                catch (Exception exception)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("ERROR Proccessing Clicks for ArticleId: {0}", articleId);
                    Console.WriteLine(exception.Message);
                    if (exception.InnerException != null)
                    {
                        Console.WriteLine(exception.InnerException.Message);
                    }
                    Console.ResetColor();
                }
                stopWatch.Stop();
                TimeSpan ts = stopWatch.Elapsed;

                var elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                    ts.Hours, ts.Minutes, ts.Seconds,
                    ts.Milliseconds / 10);
                Console.WriteLine("Done with article id {0} time spend {1}", articleId, elapsedTime);
            });
        }
Example #4
0
        private static void GenerateArticles(List<string> users)
        {
            var random = new Random();

            Parallel.For(0, 3000, new ParallelOptions {MaxDegreeOfParallelism = 30}, index =>
            {
                using (var context = new ApplicationDbContext())
                {
                    var articles = new List<Article>();
                    var tags = context.Tags.ToList();
                    for (var i = 0; i < 10; i++)
                    {
                        var article = new Article();
                        article.Tags.Add(tags.Random());
                        article.Tags.Add(tags.Random());
                        article.Header = SeedExtensions.Headers.Random();
                        article.TeaserText = SeedExtensions.TeaserTexts.Random();
                        article.Body = SeedExtensions.Body;
                        article.CreatedDate = DateTime.UtcNow.AddDays(0 - random.Next(5, 100));
                        article.IsPublished = random.Next(0, 100) > 15;
                        article.AuthorId = users.Random();
                        article.Stamp = Guid.NewGuid();
                        articles.Add(article);
                    }
                    ((DbSet<Article>) context.Articles).AddRange(articles);
                    try
                    {
                        Console.WriteLine("Saving categories index {0}, count {1}", index, articles.Count());
                        context.SaveChanges();
                    }
                    catch (Exception exception)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("ERROR Proccessing Clicks for ArticleId: {0}", index);
                        Console.WriteLine(exception.Message);
                        if (exception.InnerException != null)
                        {
                            Console.WriteLine(exception.InnerException.Message);
                        }
                        Console.ResetColor();
                    }
                }
            });
        }
Example #5
0
        public static Grid On(Grid grid)
        {
            foreach (Cell cell in grid)
            {
                var neighbors = new List<Cell>();

                if (cell.North != null)
                    neighbors.Add(cell.North);

                if (cell.East != null)
                    neighbors.Add(cell.East);

                if (neighbors.Any())
                {
                    cell.Link(neighbors.Random());
                }
            }

            return grid;
        }
 public void GettingRepeatedlyRandomItemFromListReturnsItemsWithUniformDistribution()
 {
     IList<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
     int count = 10000;
     IDictionary<int, int> extracted = new Dictionary<int, int>();
     foreach (int i in list)
     {
         extracted.Add(i, 0);
     }
     for (int i = 0; i < count; i++)
     {
         int rnd = list.Random();
         extracted[rnd] =extracted[rnd] + 1;
     }
     int perfectDistributionCount = count / list.Count;
     foreach (int i in extracted.Keys)
     {
         Assert.True(extracted[i] > 0.8 * perfectDistributionCount);
         Assert.True(extracted[i] < 1.2 * perfectDistributionCount);
     }
 }
Example #7
0
    /// <summary>
    /// The neighbour with the most empty space. Otherwise picks at random
    /// </summary>
    /// <returns>The emptiest nieghbour.</returns>
    private Neighbours FindEmptiestNieghbour()
    {
        var neighbourPop = new List<KeyValuePair<Neighbours, int>>(4);

        var directions = Enum.GetValues(typeof(Neighbours)).Cast<Neighbours>().ToList();
        foreach(var dir in directions)
        {
            var n = this[dir];
            if(n != null)
            {
                var space = n.maxPopulation - n.population.Count;
                neighbourPop.Add(new KeyValuePair<Neighbours, int>(dir, space));
            }
        }

        neighbourPop.Sort( (a, b) => a.Value.CompareTo(b.Value) );

        bool allTheSame = true;
        int value = neighbourPop[0].Value;
        if(neighbourPop.Count > 1)
        {
            for (int i = 1; i < neighbourPop.Count; i++)
            {
                var t = neighbourPop[i].Value;
                if(t != value)
                {
                    allTheSame = false;
                    break;
                }
            }
        }

        if(allTheSame)
            return neighbourPop.Random().Key;
        else
            return neighbourPop[neighbourPop.Count-1].Key; //Last has most space
    }
Example #8
0
    /// <summary>
    /// See if some of the population will convert to a different religion
    /// Work down pop from oldest to youngest. Pick a random pop, try and convert.
    /// Atheists don't convert others.
    /// </summary>
    public void Conversion()
    {
        var t = new List<Population>(population);

        t.Sort( (a, b) => a.age.CompareTo(b.age) );
        t.Reverse();

        foreach(var attacker in t)
        {
            //Atheists don't convert
            if(attacker.owner == parent.game.nullGod)
                continue;

            var defender = t.Random();

            if(attacker.owner == defender.owner)
                continue;

            //Attacker roll d6 + age difference.
            //Wins if greater than defenders age or 6
            var attackerBaseRoll = UnityEngine.Random.Range(1, 7);
            var attackerRoll = attackerBaseRoll + (attacker.age - defender.age);

            if(attackerBaseRoll == 6 || attackerRoll > defender.age)
            {
                defender.owner = attacker.owner;
            }

        }
    }
 public void GettingRandomItemFromEmptyListReturnsNull()
 {
     IList<string> list = new List<string>();
     Assert.Null(list.Random());
 }
        void ShowDownloadDialog()
        {
            statusLabel.GetText = () => "Fetching list of mirrors...";
            progressBar.Indeterminate = true;

            var retryButton = panel.Get<ButtonWidget>("RETRY_BUTTON");
            retryButton.IsVisible = () => false;

            var cancelButton = panel.Get<ButtonWidget>("CANCEL_BUTTON");

            var mirrorsFile = Platform.ResolvePath("^", "Content", Game.modData.Manifest.Mod.Id, "mirrors.txt");
            var file = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
            var dest = Platform.ResolvePath("^", "Content", Game.modData.Manifest.Mod.Id);

            Action<DownloadProgressChangedEventArgs> onDownloadProgress = i =>
            {
                var dataReceived = 0.0f;
                var dataTotal = 0.0f;
                var mag = 0;
                var dataSuffix = "";

                if (i.TotalBytesToReceive < 0)
                {
                    dataTotal = float.NaN;
                    dataReceived = i.BytesReceived;
                    dataSuffix = SizeSuffixes[0];
                }
                else
                {
                    mag = (int)Math.Log(i.TotalBytesToReceive, 1024);
                    dataTotal = i.TotalBytesToReceive / (float)(1L << (mag * 10));
                    dataReceived = i.BytesReceived / (float)(1L << (mag * 10));
                    dataSuffix = SizeSuffixes[mag];
                }

                progressBar.Indeterminate = false;
                progressBar.Percentage = i.ProgressPercentage;

                statusLabel.GetText = () => "Downloading from {4} {1:0.00}/{2:0.00} {3} ({0}%)".F(i.ProgressPercentage,
                    dataReceived, dataTotal, dataSuffix,
                    mirror != null ? new Uri(mirror).Host : "unknown host");
            };

            Action<string> onExtractProgress = s => Game.RunAfterTick(() => statusLabel.GetText = () => s);

            Action<string> onError = s => Game.RunAfterTick(() =>
            {
                statusLabel.GetText = () => "Error: " + s;
                retryButton.IsVisible = () => true;
            });

            Action<AsyncCompletedEventArgs, bool> onDownloadComplete = (i, cancelled) =>
            {
                if (i.Error != null)
                {
                    onError(Download.FormatErrorMessage(i.Error));
                    return;
                }
                else if (cancelled)
                {
                    onError("Download cancelled");
                    return;
                }

                // Automatically extract
                statusLabel.GetText = () => "Extracting...";
                progressBar.Indeterminate = true;
                if (InstallUtils.ExtractZip(file, dest, onExtractProgress, onError))
                {
                    Game.RunAfterTick(() =>
                    {
                        Ui.CloseWindow();
                        afterInstall();
                    });
                }
            };

            Action<AsyncCompletedEventArgs, bool> onFetchMirrorsComplete = (i, cancelled) =>
            {
                progressBar.Indeterminate = true;

                if (i.Error != null)
                {
                    onError(Download.FormatErrorMessage(i.Error));
                    return;
                }
                else if (cancelled)
                {
                    onError("Download cancelled");
                    return;
                }

                var mirrorList = new List<string>();
                using (var r = new StreamReader(mirrorsFile))
                {
                    string line;
                    while ((line = r.ReadLine()) != null)
                        if (!string.IsNullOrEmpty(line))
                            mirrorList.Add(line);
                }
                mirror = mirrorList.Random(new MersenneTwister());

                // Save the package to a temp file
                var dl = new Download(mirror, file, onDownloadProgress, onDownloadComplete);
                cancelButton.OnClick = () => { dl.Cancel(); Ui.CloseWindow(); };
                retryButton.OnClick = () => { dl.Cancel(); ShowDownloadDialog(); };
            };

            // Get the list of mirrors
            var updateMirrors = new Download(mirrorListUrl, mirrorsFile, onDownloadProgress, onFetchMirrorsComplete);
            cancelButton.OnClick = () => { updateMirrors.Cancel(); Ui.CloseWindow(); };
            retryButton.OnClick = () => { updateMirrors.Cancel(); ShowDownloadDialog(); };
        }
Example #11
0
 public void TriggerTrap(bool click)
 {
     bool actor_here = (actor() != null);
     if(actor_here && actor().type == ActorType.CYCLOPEAN_TITAN){
         if(name == "floor"){
             B.Add(actor().TheName(true) + " smashes " + Tile.Prototype(type).a_name + ". ",this);
         }
         else{
             B.Add(actor().TheName(true) + " smashes " + the_name + ". ",this);
         }
         TransformTo(TileType.FLOOR);
         return;
     }
     if(click){
         if(actor() == player || (actor() == null && player.CanSee(this))){
             B.Add("*CLICK* ",this);
             B.PrintAll();
         }
         else{
             if(actor() != null && player.CanSee(this) && player.CanSee(actor())){
                 B.Add("You hear a *CLICK* from under " + actor().the_name + ". ");
                 B.PrintAll();
             }
             else{
                 if(DistanceFrom(player) <= 12){
                     B.Add("You hear a *CLICK* nearby. ");
                     B.PrintAll();
                 }
                 else{
                     B.Add("You hear a *CLICK* in the distance. ");
                     B.PrintAll();
                 }
             }
         }
     }
     if(actor() == player){
         Help.TutorialTip(TutorialTopic.Traps);
     }
     switch(type){
     case TileType.GRENADE_TRAP:
     {
         if(actor_here && player.CanSee(actor())){
             B.Add("Grenades fall from the ceiling above " + actor().the_name + "! ",this);
         }
         else{
             B.Add("Grenades fall from the ceiling! ",this);
         }
         List<Tile> valid = new List<Tile>();
         foreach(Tile t in TilesWithinDistance(1)){
             if(t.passable && !t.Is(FeatureType.GRENADE)){
                 valid.Add(t);
             }
         }
         int count = R.OneIn(10)? 3 : 2;
         for(;count>0 & valid.Count > 0;--count){
             Tile t = valid.Random();
             if(t.actor() != null){
                 if(t.actor() == player){
                     B.Add("One lands under you! ");
                 }
                 else{
                     if(player.CanSee(this)){
                         B.Add("One lands under " + t.actor().the_name + ". ",t.actor());
                     }
                 }
             }
             else{
                 if(t.inv != null){
                     B.Add("One lands under " + t.inv.TheName() + ". ",t);
                 }
             }
             t.features.Add(FeatureType.GRENADE);
             valid.Remove(t);
             Q.Add(new Event(t,100,EventType.GRENADE));
         }
         Toggle(actor());
         break;
     }
     case TileType.SLIDING_WALL_TRAP:
     {
         List<int> dirs = new List<int>();
         for(int i=2;i<=8;i+=2){
             Tile t = this;
             bool good = true;
             while(t.type != TileType.WALL){
                 t = t.TileInDirection(i);
                 if(t.opaque && t.type != TileType.WALL){
                     good = false;
                     break;
                 }
                 if(DistanceFrom(t) > 6){
                     good = false;
                     break;
                 }
             }
             if(good && t.row > 0 && t.row < ROWS-1 && t.col > 0 && t.col < COLS-1){
                 t = t.TileInDirection(i);
             }
             else{
                 good = false;
             }
             if(good && t.row > 0 && t.row < ROWS-1 && t.col > 0 && t.col < COLS-1){
                 foreach(Tile tt in t.TilesWithinDistance(1)){
                     if(tt.type != TileType.WALL){
                         good = false;
                     }
                 }
             }
             else{
                 good = false;
             }
             if(good){
                 dirs.Add(i);
             }
         }
         if(dirs.Count == 0){
             B.Add("Nothing happens. ",this);
         }
         else{
             int dir = dirs[R.Roll(dirs.Count)-1];
             Tile first = this;
             while(first.type != TileType.WALL){
                 first = first.TileInDirection(dir);
             }
             first.TileInDirection(dir).TurnToFloor();
             ActorType ac = ActorType.SKELETON;
             if(M.current_level >= 3 && R.CoinFlip()){
                 ac = ActorType.ZOMBIE;
             }
             if(M.current_level >= 9 && R.OneIn(10)){
                 ac = ActorType.STONE_GOLEM;
             }
             if(M.current_level >= 7 && R.PercentChance(1)){
                 ac = ActorType.MECHANICAL_KNIGHT;
             }
             if(M.current_level >= 15 && R.PercentChance(1)){
                 ac = ActorType.CORPSETOWER_BEHEMOTH;
             }
             if(M.current_level >= 15 && R.PercentChance(1)){
                 ac = ActorType.MACHINE_OF_WAR;
             }
             if(R.PercentChance(1)){
                 first.TileInDirection(dir).TransformTo(TileType.CHEST);
                 if(R.PercentChance(1)){
                     first.TileInDirection(dir).color = Color.Yellow;
                 }
             }
             else{
                 Actor.Create(ac,first.TileInDirection(dir).row,first.TileInDirection(dir).col,TiebreakerAssignment.InsertAfterCurrent);
             }
             first.TurnToFloor();
             foreach(Tile t in first.TileInDirection(dir).TilesWithinDistance(1)){
                 t.solid_rock = false;
             }
             if(first.ActorInDirection(dir) != null){
                 first.ActorInDirection(dir).FindPath(first.TileInDirection(dir.RotateDir(true,4)));
                 //first.ActorInDirection(dir).FindPath(TileInDirection(dir));
             }
             if(player.CanSee(first)){
                 B.Add("The wall slides away. ");
             }
             else{
                 if(DistanceFrom(player) <= 6){
                     B.Add("You hear rock sliding on rock. ");
                 }
             }
         }
         Toggle(actor());
         break;
     }
     case TileType.TELEPORT_TRAP:
     {
         if(actor_here){
             B.Add("An unstable energy covers " + actor().TheName(true) + ". ",actor());
             actor().attrs[AttrType.TELEPORTING] = R.Roll(4);
             Q.KillEvents(actor(),AttrType.TELEPORTING); //should be replaced by refreshduration eventually. works the same way, though.
             Q.Add(new Event(actor(),(R.Roll(10)+25)*100,AttrType.TELEPORTING,actor().YouFeel() + " more stable. ",actor()));
         }
         else{
             if(inv != null){
                 B.Add("An unstable energy covers " + inv.TheName(true) + ". ",this);
                 Tile dest = M.AllTiles().Where(x=>x.passable && x.CanGetItem()).RandomOrDefault();
                 if(dest != null){
                     B.Add("It vanishes! ",this);
                     bool seen = player.CanSee(this);
                     Item i = inv;
                     inv = null;
                     dest.GetItem(i);
                     if(seen){
                         B.Add("It reappears! ",dest);
                     }
                     else{
                         B.Add(i.AName(true) + " appears! ",dest);
                     }
                 }
                 else{
                     B.Add("Nothing happens. ",this);
                 }
             }
             else{
                 B.Add("An unstable energy crackles for a moment, then dissipates. ",this);
             }
         }
         Toggle(actor());
         break;
     }
     case TileType.SHOCK_TRAP:
     {
         //int old_radius = light_radius; //This was a cool effect, but caused bugs when the tile's radius changed mid-trigger.
         //UpdateRadius(old_radius,3,true); //I'll restore it when I figure out how...
         if(actor_here){
             if(player.CanSee(actor())){
                 B.Add("Electricity zaps " + actor().the_name + ". ",this);
             }
             if(actor().TakeDamage(DamageType.ELECTRIC,DamageClass.PHYSICAL,R.Roll(3,6),null,"a shock trap")){
                 actor().ApplyStatus(AttrType.STUNNED,(R.Roll(6)+7)*100);
                 /*B.Add(actor().YouAre() + " stunned! ",actor());
                 actor().RefreshDuration(AttrType.STUNNED,actor().DurationOfMagicalEffect(R.Roll(6)+7)*100,(actor().YouAre() + " no longer stunned. "),actor());*/
                 if(actor() == player){
                     Help.TutorialTip(TutorialTopic.Stunned);
                 }
             }
         }
         else{
             B.Add("Arcs of electricity appear and sizzle briefly. ",this); //apply electricity, once wands have been added
         }
         //M.Draw();
         //UpdateRadius(3,old_radius,true);
         Toggle(actor());
         break;
     }
     case TileType.LIGHT_TRAP:
         if(M.wiz_lite == false){
             if(actor_here && player.HasLOS(row,col) && !actor().IsHiddenFrom(player)){
                 B.Add("A wave of light washes out from above " + actor().TheName(true) + "! ");
             }
             else{
                 B.Add("A wave of light washes over the area! ");
             }
             M.wiz_lite = true;
             M.wiz_dark = false;
             Q.KillEvents(null,EventType.NORMAL_LIGHTING);
             Q.Add(new Event((R.Roll(2,20) + 120) * 100,EventType.NORMAL_LIGHTING));
         }
         else{
             B.Add("The air grows even brighter for a moment. ");
             Q.KillEvents(null,EventType.NORMAL_LIGHTING);
             Q.Add(new Event((R.Roll(2,20) + 120) * 100,EventType.NORMAL_LIGHTING));
         }
         Toggle(actor());
         break;
     case TileType.DARKNESS_TRAP:
         if(M.wiz_dark == false){
             if(actor_here && player.CanSee(actor())){
                 B.Add("A surge of darkness radiates out from above " + actor().TheName(true) + "! ");
                 if(player.light_radius > 0){
                     B.Add("Your light is extinguished! ");
                 }
             }
             else{
                 B.Add("A surge of darkness radiates over the area! ");
                 if(player.light_radius > 0){
                     B.Add("Your light is extinguished! ");
                 }
             }
             M.wiz_dark = true;
             M.wiz_lite = false;
             Q.KillEvents(null,EventType.NORMAL_LIGHTING);
             Q.Add(new Event((R.Roll(2,20) + 120) * 100,EventType.NORMAL_LIGHTING));
         }
         else{
             B.Add("The air grows even darker for a moment. ");
             Q.KillEvents(null,EventType.NORMAL_LIGHTING);
             Q.Add(new Event((R.Roll(2,20) + 120) * 100,EventType.NORMAL_LIGHTING));
         }
         Toggle(actor());
         break;
     case TileType.FIRE_TRAP:
     {
         if(actor_here){
             B.Add("A column of flame engulfs " + actor().TheName(true) + "! ",this);
             actor().ApplyBurning();
         }
         else{
             B.Add("A column of flame appears! ",this);
         }
         AddFeature(FeatureType.FIRE);
         Toggle(actor());
         break;
     }
     case TileType.ALARM_TRAP:
         if(actor() == player){
             B.Add("A high-pitched ringing sound reverberates from above you. ");
         }
         else{
             if(actor_here && player.CanSee(actor())){
                 B.Add("A high-pitched ringing sound reverberates from above " + actor().the_name + ". ");
             }
             else{
                 B.Add("You hear a high-pitched ringing sound. ");
             }
         }
         foreach(Actor a in ActorsWithinDistance(12,true)){
             if(a.type != ActorType.GIANT_BAT && a.type != ActorType.BLOOD_MOTH && a.type != ActorType.CARNIVOROUS_BRAMBLE
             && a.type != ActorType.LASHER_FUNGUS && a.type != ActorType.PHASE_SPIDER){
                 a.FindPath(this);
             }
         }
         Toggle(actor());
         break;
     case TileType.BLINDING_TRAP:
         if(actor_here){
             B.Add("A dart flies out and strikes " + actor().TheName(true) + ". ",this); //todo: what about replacing this with blinding dust?
             if(!actor().HasAttr(AttrType.NONLIVING,AttrType.BLINDSIGHT)){
                 actor().ApplyStatus(AttrType.BLIND,(R.Roll(2,6)+6)*100);
                 /*B.Add(actor().YouAre() + " blind! ",actor());
                 actor().RefreshDuration(AttrType.BLIND,(R.Roll(3,6) + 6) * 100,actor().YouAre() + " no longer blinded. ",actor());*/
             }
             else{
                 B.Add("It doesn't affect " + actor().the_name + ". ",actor());
             }
         }
         else{
             B.Add("A dart flies out and hits the floor. ",this);
         }
         Toggle(actor());
         break;
     case TileType.ICE_TRAP:
         if(actor_here){
             if(!actor().IsBurning()){
                 if(player.CanSee(this)){
                     B.Add("The air suddenly freezes around " + actor().TheName(true) + ". ");
                 }
                 actor().ApplyFreezing();
             }
             else{
                 if(player.CanSee(this)){
                     if(player.CanSee(actor())){
                         B.Add("Ice crystals form in the air around " + actor().the_name + " but quickly vanish. ");
                     }
                     else{
                         B.Add("Ice crystals form in the air but quickly vanish. ");
                     }
                 }
             }
         }
         else{
             B.Add("Ice crystals form in the air but quickly vanish. ");
         }
         Toggle(actor());
         break;
     case TileType.PHANTOM_TRAP:
     {
         Tile open = TilesWithinDistance(3).Where(t => t.passable && t.actor() == null && t.HasLOE(this)).RandomOrDefault();
         if(open != null){
             Actor a = Actor.CreatePhantom(open.row,open.col);
             if(a != null){
                 a.attrs[AttrType.PLAYER_NOTICED]++;
                 a.player_visibility_duration = -1;
                 if(player.HasLOS(a)){ //don't print a message if you're just detecting monsters
                     B.Add("A ghostly image rises! ",a);
                 }
             }
             else{
                 B.Add("Nothing happens. ",this);
             }
         }
         else{
             B.Add("Nothing happens. ",this);
         }
         Toggle(actor());
         break;
     }
     case TileType.POISON_GAS_TRAP:
     {
         bool spores = false;
         if(M.current_level >= 5 && R.PercentChance((M.current_level - 4) * 3)){
             //spores = true; //3% at level 5...33% at level 15...48% at level 20. - disabled for now
         }
         int num = R.Roll(5) + 8;
         if(spores){
             List<Tile> new_area = AddGaseousFeature(FeatureType.SPORES,num); //todo: should this be its own trap type? what about other gases?
             if(new_area.Count > 0){
                 B.Add("A cloud of spores fills the area! ",this);
                 Event.RemoveGas(new_area,600,FeatureType.SPORES,12);
             }
         }
         else{
             List<Tile> new_area = AddGaseousFeature(FeatureType.POISON_GAS,num);
             if(new_area.Count > 0){
                 B.Add("Poisonous gas fills the area! ",this);
                 Event.RemoveGas(new_area,300,FeatureType.POISON_GAS,18);
             }
         }
         Toggle(actor());
         break;
     }
     case TileType.SCALDING_OIL_TRAP:
     {
         if(actor_here){
             B.Add("Scalding oil pours over " + actor().TheName(true) + "! ",this);
             if(actor().TakeDamage(DamageType.FIRE,DamageClass.PHYSICAL,R.Roll(3,6),null,"a scalding oil trap")){
                 if(!actor().HasAttr(AttrType.BURNING,AttrType.SLIMED) && !IsBurning()){
                     actor().attrs[AttrType.OIL_COVERED] = 1;
                     B.Add(actor().YouAre() + " covered in oil. ",actor());
                     if(actor() == player){
                         Help.TutorialTip(TutorialTopic.Oiled);
                     }
                 }
             }
         }
         else{
             B.Add("Scalding oil pours over the floor. ",this);
         }
         List<Tile> covered_in_oil = new List<Tile>{this};
         List<Tile> added = new List<Tile>();
         for(int i=0;i<2;++i){
             foreach(Tile t in covered_in_oil){
                 foreach(int dir in U.FourDirections){
                     Tile neighbor = t.TileInDirection(dir);
                     if(neighbor.DistanceFrom(this) == 1 && R.OneIn(3) && neighbor.passable && !covered_in_oil.Contains(neighbor)){
                         added.AddUnique(neighbor);
                     }
                 }
             }
             covered_in_oil.AddRange(added);
         }
         foreach(Tile t in covered_in_oil){
             t.AddFeature(FeatureType.OIL);
         }
         Toggle(actor());
         break;
     }
     case TileType.FLING_TRAP:
     {
         List<int> valid_dirs = new List<int>();
         foreach(int d in U.EightDirections){
             bool good = true;
             Tile current = this;
             for(int i=0;i<2;++i){
                 current = current.TileInDirection(d);
                 if(current == null || (!current.passable && !current.Is(TileType.BARREL,TileType.CRACKED_WALL,TileType.DOOR_C,TileType.HIDDEN_DOOR,TileType.POISON_BULB,TileType.STANDING_TORCH))){
                     good = false; //try to pick directions that are either open, or that have interesting things to be knocked into
                     break;
                 }
             }
             if(good){
                 valid_dirs.Add(d);
             }
         }
         Toggle(actor());
         int dir = -1;
         if(valid_dirs.Count > 0){
             dir = valid_dirs.Random();
         }
         else{
             dir = Global.RandomDirection();
         }
         if(actor_here){
             Actor a = actor();
             B.Add("The floor suddenly tilts up under " + a.TheName(true) + "! ",this);
             a.attrs[AttrType.TURN_INTO_CORPSE]++;
             KnockObjectBack(actor(),GetBestExtendedLineOfEffect(TileInDirection(dir)),5,null);
             a.CorpseCleanup();
         }
         else{
             if(inv != null){
                 B.Add("The floor suddenly tilts up under " + inv.TheName(true) + "! ",this);
                 string item_name = "it";
                 string punctuation = ". ";
                 if(!player.CanSee(this)){
                     item_name = inv.AName(true);
                     punctuation = "! ";
                 }
                 Item i = inv;
                 inv = null;
                 List<Tile> line = GetBestExtendedLineOfEffect(TileInDirection(dir));
                 if(line.Count > 13){
                     line = line.ToCount(13); //for range 12
                 }
                 Tile t = line.LastBeforeSolidTile();
                 Actor first = FirstActorInLine(line);
                 if(first != null){
                     t = first.tile();
                     B.Add(item_name + " hits " + first.the_name + punctuation,first);
                 }
                 line = line.ToFirstSolidTileOrActor();
                 if(line.Count > 0){
                     line.RemoveAt(line.Count - 1);
                 }
                 {
                     Tile first_unseen = null;
                     foreach(Tile tile2 in line){
                         if(!tile2.seen){
                             first_unseen = tile2;
                             break;
                         }
                     }
                     if(first_unseen != null){
                         line = line.To(first_unseen);
                         if(line.Count > 0){
                             line.RemoveAt(line.Count - 1);
                         }
                     }
                 }
                 M.Draw();
                 if(line.Count > 0){
                     Screen.AnimateProjectile(line,new colorchar(i.symbol,i.color));
                 }
                 if(i.IsBreakable()){
                     B.Add("It breaks! ",t);
                     i.CheckForMimic();
                 }
                 else{
                     t.GetItem(i);
                 }
                 t.MakeNoise(2);
                 if(first != null){
                     //first.player_visibility_duration = -1; //not sure how angry monsters should get in this case
                     //first.attrs[AttrType.PLAYER_NOTICED]++;
                 }
                 else{
                     if(t.IsTrap()){
                         t.TriggerTrap();
                     }
                 }
             }
             else{
                 B.Add("Nothing happens. ",this);
             }
         }
         break;
     }
     case TileType.STONE_RAIN_TRAP:
         B.Add("Stones fall from the ceiling! ",this);
         if(actor_here){
             Actor a = actor();
             B.Add(a.YouVisibleAre() + " hit! ",this);
             a.TakeDamage(DamageType.NORMAL,DamageClass.PHYSICAL,R.Roll(3,6),null,"falling stones");
         }
         Toggle(actor());
         foreach(Tile neighbor in TilesWithinDistance(1).Randomize()){
             if(R.PercentChance(40)){
                 if(neighbor.IsTrap()){
                     B.Add("A bouncing stone triggers a trap. ",neighbor);
                 }
                 neighbor.ApplyEffect(DamageType.NORMAL); //break items and set off traps
                 if(neighbor.Is(TileType.FLOOR)){
                     neighbor.Toggle(null,TileType.GRAVEL);
                     neighbor.RemoveFeature(FeatureType.SLIME);
                     neighbor.RemoveFeature(FeatureType.OIL);
                 }
             }
         }
         break;
     default:
         break;
     }
 }
Example #12
0
		/// <summary>
		/// Uses WM, attacking targets.
		/// </summary>
		/// <param name="attacker"></param>
		/// <param name="skill"></param>
		/// <param name="targetAreaId"></param>
		/// <param name="unkInt1"></param>
		/// <param name="unkInt2"></param>
		public void Use(Creature attacker, Skill skill, long targetAreaId = 0, int unkInt1 = 0, int unkInt2 = 0)
		{
			bool wasKnockedDown = (attacker.IsKnockedDown || attacker.WasKnockedBack);
			if ((attacker.Stun > 500 && wasKnockedDown || attacker.IsStunned && !wasKnockedDown || DateTime.Now.AddMilliseconds(2000) < attacker.AttackDelayTime && (wasKnockedDown)) && attacker.InterceptingSkillId == SkillId.None)
			{
				Send.SkillUseSilentCancel(attacker);
				return;
			}
			var range = this.GetRange(attacker, skill);

			ICollection<Creature> targets = attacker.GetTargetableCreaturesInRange(range, true).Where(t => !(DateTime.Now.AddMilliseconds(2000) < t.NotReadyToBeHitTime)).ToList(); //Able to be attacked at 1/3 of knock down time.

			// Check targets
			if (targets.Count == 0)
			{
				Send.Notice(attacker, Localization.Get("There isn't a target nearby to use that on."));
				Send.SkillUseSilentCancel(attacker);
				return;
			}

			// Create actions
			var cap = new CombatActionPack(attacker, skill.Info.Id);

			var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, skill.Info.Id, targetAreaId);
			aAction.Set(AttackerOptions.Result);

			cap.Add(aAction);

			var survived = new List<Creature>();

			var skipped = new List<Creature>();

			var i = 0;
			foreach (var target in targets)
			{
				i++;

				target.StopMove();

				Skill smash = target.Skills.Get(SkillId.Smash);
				if (smash != null && target.Skills.IsReady(SkillId.Smash) && !attacker.IsPlayer)
					attacker.InterceptingSkillId = SkillId.Smash;
				TargetAction tAction;
				if (attacker.InterceptingSkillId == SkillId.Smash && target.GetPosition().InRange(attacker.GetPosition(), target.AttackRangeFor(attacker)))
				{
					aAction.Options |= AttackerOptions.Result;
					tAction = new TargetAction(CombatActionType.CounteredHit, target, attacker, SkillId.Smash);
					tAction.Options |= TargetOptions.Result;

				}
				else
				{
					tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
				}
				attacker.InterceptingSkillId = SkillId.None;
				tAction.Delay = 300; // Usually 300, sometimes 350?

				// Calculate damage
				float damage = 0f;
				if (attacker.RightHand != null && (
				attacker.RightHand.Data.HasTag("/weapon/bow01/") ||
				attacker.RightHand.Data.HasTag("/weapon/bow/") ||
				attacker.RightHand.Data.HasTag("/weapon/crossbow/") ||
				attacker.RightHand.Data.HasTag("/weapon/shuriken/") ||
				attacker.RightHand.Data.HasTag("/weapon/atlatl/") ||
				attacker.RightHand.Data.HasTag("/weapon/gun/dualgun/")))
				{
					damage = attacker.GetRndBareHandDamage();
				}
				else
				{
					damage = attacker.GetRndTotalDamage();
				}
				damage *= skill.RankData.Var1 / 100f;

				// Handle skills and reductions
				var allCrit = false;
				var critSkill = target.Skills.Get(SkillId.CriticalHit);
				if (allCrit)
				{
					// Add crit bonus
					var bonus = critSkill.RankData.Var1 / 100f;
					damage = damage + (damage * bonus);

					// Set target option
					tAction.Set(TargetOptions.Critical);
				}
				else if (i == 1)
				{

					CriticalHit.Handle(attacker, attacker.GetTotalCritChance(0), ref damage, tAction);
					if (tAction.Has(TargetOptions.Critical))
						allCrit = true;
				}
				var maxDamage = damage; //Damage without Defense and Protection
				SkillHelper.HandleDefenseProtection(target, ref damage);
				Defense.Handle(aAction, tAction, ref damage);
				ManaShield.Handle(target, ref damage, tAction, maxDamage);

				// Clean Hit if not defended nor critical
				if (!tAction.Is(CombatActionType.Defended) && !tAction.Has(TargetOptions.Critical))
					tAction.Set(TargetOptions.CleanHit);

				// Take damage if any is left
				if (damage > 0)
					target.TakeDamage(tAction.Damage = damage, attacker);

				// Finish if dead, knock down if not defended
				if (target.IsDead)
					tAction.Set(TargetOptions.KnockDownFinish);
				else if (!tAction.Is(CombatActionType.Defended))
					tAction.Set(TargetOptions.KnockDown);

				// Anger Management
				if (!target.IsDead)
					survived.Add(target);

				if (target.UseBattleStanceFromAOE)
					target.IsInBattleStance = true;

				// Stun & knock back
				aAction.Stun = CombatMastery.GetAttackerStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);

				if (!tAction.Is(CombatActionType.Defended))
				{
					tAction.Stun = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);
					target.Stability = Creature.MinStability;
					attacker.Shove(target, KnockbackDistance);
				}

				// Add action
				cap.Add(tAction);
			}

			// Only select a random aggro if there is no aggro yet,
			// WM only aggroes one target at a time.
			if (survived.Count != 0 && attacker.Region.CountAggro(attacker) < 1)
			{
				var rnd = RandomProvider.Get();
				var aggroTarget = survived.Random();
				aggroTarget.Aggro(attacker);
			}

			// Reduce life in old combat system
			if (!AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal"))
			{
				var amount = (attacker.LifeMax < 10 ? 2 : attacker.LifeMax / 10);
				attacker.ModifyLife(-amount);

				attacker.InvincibilityTime = DateTime.Now.AddMilliseconds(2300);
			}

			// Spin it~
			Send.UseMotion(attacker, 8, 4);

			cap.Handle();

			Send.SkillUse(attacker, skill.Info.Id, targetAreaId, unkInt1, unkInt2);

			skill.Stacks = 0;
		}
Example #13
0
 public void AddPillars(int percent_chance_per_room)
 {
     //currently does 50% 'pillar', 25% 'statue', and 25% 'other', where relevant.
     ForEachRectangularRoom((start_r,start_c,end_r,end_c) => {
         if(PercentChance(percent_chance_per_room)){
             int height = end_r - start_r + 1;
             int width = end_c - start_c + 1;
             if(height > 3 || width > 3){
                 List<PillarArrangement> layouts = new List<PillarArrangement>();
                 if(height % 2 == 1 && width % 2 == 1){
                     layouts.Add(PillarArrangement.Single);
                 }
                 if((height % 2 == 1 || width % 2 == 1) && height != 4 && width != 4){
                     layouts.Add(PillarArrangement.Row);
                 }
                 if(height >= 5 && width >= 5){
                     layouts.Add(PillarArrangement.Corners);
                 }
                 if(height > 2 && width > 2 && height != 4 && width != 4){
                     layouts.Add(PillarArrangement.Full);
                 }
                 if((width % 2 == 1 && width >= 5) || (height % 2 == 1 && height >= 5)){
                     layouts.Add(PillarArrangement.StatueEdges);
                 }
                 if(layouts.Count == 0 || CoinFlip()){ //otherwise they're too common
                     layouts.Add(PillarArrangement.StatueCorners);
                 }
                 if(layouts.Count > 0){
                     CellType pillar = CellType.Pillar;
                     /*switch(Roll(4)){ //this part should be done later. Until then, they should remain pillars.
                     case 1:
                     case 2:
                         pillar = CellType.Pillar;
                         break;
                     case 3:
                         pillar = CellType.Statue;
                         break;
                     case 4:
                         pillar = CellType.OtherRoomFeature;
                         break;
                     }*/
                     switch(layouts.Random()){
                     case PillarArrangement.Single:
                         map[(start_r + end_r)/2,(start_c + end_c)/2] = pillar;
                         break;
                     case PillarArrangement.Row:
                     {
                         bool vertical;
                         if(width % 2 == 1 && height % 2 == 0){
                             vertical = true;
                         }
                         else{
                             if(height % 2 == 1 && width % 2 == 0){
                                 vertical = false;
                             }
                             else{
                                 vertical = CoinFlip();
                             }
                         }
                         if(vertical){
                             if(height % 2 == 1){
                                 for(int i=start_r+1;i<=end_r-1;i+=2){
                                     map[i,(start_c + end_c)/2] = pillar;
                                 }
                             }
                             else{
                                 int offset = 0;
                                 if(height % 4 == 0){
                                     offset = Roll(2) - 1;
                                 }
                                 for(int i=start_r+1+offset;i<(start_r + end_r)/2;i+=2){
                                     map[i,(start_c + end_c)/2] = pillar;
                                 }
                                 for(int i=end_r-1-offset;i>(start_r + end_r)/2+1;i-=2){
                                     map[i,(start_c + end_c)/2] = pillar;
                                 }
                             }
                         }
                         else{
                             if(width % 2 == 1){
                                 for(int i=start_c+1;i<=end_c-1;i+=2){
                                     map[(start_r + end_r)/2,i] = pillar;
                                 }
                             }
                             else{
                                 int offset = 0;
                                 if(width % 4 == 0){
                                     offset = Roll(2) - 1;
                                 }
                                 for(int i=start_c+1+offset;i<(start_c + end_c)/2;i+=2){
                                     map[(start_r + end_r)/2,i] = pillar;
                                 }
                                 for(int i=end_c-1-offset;i>(start_c + end_c)/2+1;i-=2){
                                     map[(start_r + end_r)/2,i] = pillar;
                                 }
                             }
                         }
                         break;
                     }
                     case PillarArrangement.Corners:
                     {
                         int v_offset = 0;
                         int h_offset = 0;
                         if(height % 4 == 0){
                             v_offset = Roll(2) - 1;
                         }
                         if(width % 4 == 0){
                             h_offset = Roll(2) - 1;
                         }
                         map[start_r + 1 + v_offset,start_c + 1 + h_offset] = pillar;
                         map[start_r + 1 + v_offset,end_c - 1 - h_offset] = pillar;
                         map[end_r - 1 - v_offset,start_c + 1 + h_offset] = pillar;
                         map[end_r - 1 - v_offset,end_c - 1 - h_offset] = pillar;
                         break;
                     }
                     case PillarArrangement.Full:
                     {
                         int v_offset = 0;
                         int h_offset = 0;
                         if(height % 4 == 0){
                             v_offset = Roll(2) - 1;
                         }
                         if(width % 4 == 0){
                             h_offset = Roll(2) - 1;
                         }
                         int half_r = (start_r + end_r)/2;
                         int half_c = (start_c + end_c)/2;
                         int half_r_offset = (start_r + end_r + 1)/2;
                         int half_c_offset = (start_c + end_c + 1)/2;
                         for(int i=start_r+1+v_offset;i<half_r;i+=2){
                             for(int j=start_c+1+h_offset;j<half_c;j+=2){
                                 map[i,j] = pillar;
                             }
                         }
                         for(int i=start_r+1+v_offset;i<half_r;i+=2){
                             for(int j=end_c-1-h_offset;j>half_c_offset;j-=2){
                                 map[i,j] = pillar;
                             }
                         }
                         for(int i=end_r-1-v_offset;i>half_r_offset;i-=2){
                             for(int j=start_c+1+h_offset;j<half_c;j+=2){
                                 map[i,j] = pillar;
                             }
                         }
                         for(int i=end_r-1-v_offset;i>half_r_offset;i-=2){
                             for(int j=end_c-1-h_offset;j>half_c_offset;j-=2){
                                 map[i,j] = pillar;
                             }
                         }
                         if((width+1) % 4 == 0){
                             if(height % 2 == 1){
                                 for(int i=start_r+1;i<=end_r-1;i+=2){
                                     map[i,half_c] = pillar;
                                 }
                             }
                             else{
                                 int offset = 0;
                                 if(height % 4 == 0){
                                     offset = Roll(2) - 1;
                                 }
                                 for(int i=start_r+1+offset;i<half_r;i+=2){
                                     map[i,half_c] = pillar;
                                 }
                                 for(int i=end_r-1-offset;i>half_r_offset;i-=2){
                                     map[i,half_c] = pillar;
                                 }
                             }
                         }
                         if((height+1) % 4 == 0){
                             if(width % 2 == 1){
                                 for(int i=start_c+1;i<=end_c-1;i+=2){
                                     map[half_r,i] = pillar;
                                 }
                             }
                             else{
                                 int offset = 0;
                                 if(width % 4 == 0){
                                     offset = Roll(2) - 1;
                                 }
                                 for(int i=start_c+1+offset;i<half_c;i+=2){
                                     map[half_r,i] = pillar;
                                 }
                                 for(int i=end_c-1-offset;i>half_c_offset;i-=2){
                                     map[half_r,i] = pillar;
                                 }
                             }
                         }
                         break;
                     }
                     case PillarArrangement.StatueCorners:
                         map[start_r,start_c] = CellType.Statue;
                         map[start_r,end_c] = CellType.Statue;
                         map[end_r,start_c] = CellType.Statue;
                         map[end_r,end_c] = CellType.Statue;
                         break;
                     case PillarArrangement.StatueEdges:
                     {
                         map[start_r,start_c] = CellType.Statue;
                         map[start_r,end_c] = CellType.Statue;
                         map[end_r,start_c] = CellType.Statue;
                         map[end_r,end_c] = CellType.Statue;
                         if(width % 2 == 1 && width > 3){
                             int half_c = (start_c + end_c)/2;
                             int corridors = new pos(start_r,half_c).CardinalAdjacentPositions().Where(x => BoundsCheck(x) && map[x].IsCorridorType()).Count;
                             if(corridors == 0){
                                 map[start_r,half_c] = CellType.Statue;
                             }
                             corridors = new pos(end_r,half_c).CardinalAdjacentPositions().Where(x => BoundsCheck(x) && map[x].IsCorridorType()).Count;
                             if(corridors == 0){
                                 map[end_r,half_c] = CellType.Statue;
                             }
                         }
                         if(height % 2 == 1 && height > 3){
                             int half_r = (start_r + end_r)/2;
                             int corridors = new pos(half_r,start_c).CardinalAdjacentPositions().Where(x => BoundsCheck(x) && map[x].IsCorridorType()).Count;
                             if(corridors == 0){
                                 map[half_r,start_c] = CellType.Statue;
                             }
                             corridors = new pos(half_r,end_c).CardinalAdjacentPositions().Where(x => BoundsCheck(x) && map[x].IsCorridorType()).Count;
                             if(corridors == 0){
                                 map[half_r,end_c] = CellType.Statue;
                             }
                         }
                         break;
                     }
                     default:
                         break;
                     }
                 }
             }
         }
         return true;
     });
 }
Example #14
0
 public static string GenerateScrollName()
 {
     //List<string> vowel = new List<string>{"a","e","i","o","u"};
     //List<string> consonant = new List<string>{"k","s","t","n","h","m","y","r","w","g","d","p","b"}; //Japanese-inspired - used AEIOU, 4 syllables max, and 3-9 total
     //List<string> consonant = new List<string>{"h","k","l","n","m","p","w"}; //Hawaiian-inspired
     //List<string> vowel = new List<string>{"y","i","e","u","ae"}; //some kinda Gaelic-inspired
     //List<string> consonant = new List<string>{"r","t","s","rr","m","n","w","b","c","d","f","g","l","ss","v"}; //some kinda Gaelic-inspired
     List<string> vowel = new List<string>{"a","e","i","o","u","ea","ei","io","a","e","i","o","u","a","e","i","o","u","a","e","i","o","oo","ee","a","e","o"}; //the result of a bunch of tweaking
     List<string> consonant = new List<string>{"k","s","t","n","h","m","y","r","w","g","d","p","b","f","l","v","z","ch","br","cr","dr","fr","gr","kr","pr","tr","th","sc","sh","sk","sl","sm","sn","sp","st","k","s","t","n","m","r","g","d","p","b","l","k","s","t","n","m","r","d","p","b","l",};
     int syllables = 0;
     List<int> syllable_count = null;
     do{
         syllables = R.Roll(4) + 2;
         syllable_count = new List<int>();
         while(syllables > 0){
             if(syllable_count.Count == 2){
                 syllable_count.Add(syllables);
                 syllables = 0;
                 break;
             }
             int R2 = Math.Min(syllables,3);
             int M = 0;
             if(syllable_count.Count == 0){ //sorry, magic numbers here
                 M = 6;
             }
             if(syllable_count.Count == 1){
                 M = 5;
             }
             int D = 0;
             if(syllable_count.Count == 0){
                 D = Math.Max(0,syllables - M);
             }
             int s = R.Roll(R2 - D) + D;
             syllable_count.Add(s);
             syllables -= s;
         }
     }
     while(!syllable_count.Any(x => x!=1)); // if every word has only 1 syllable, try again
     string result = "";
     while(syllable_count.Count > 0){
         string word = "";
         if(R.OneIn(5)){
             word = word + vowel.Random();
         }
         for(int count = syllable_count.RemoveRandom();count > 0;--count){
             word = word + consonant.Random() + vowel.Random();
             /*if(R.OneIn(20)){ //used for the Japanese-inspired one
                 word = word + "n";
             }*/
         }
         if(result == ""){
             result = result + word;
         }
         else{
             result = result + " " + word;
         }
     }
     return result;
 }
Example #15
0
 public bool Use(Actor user,List<Tile> line)
 {
     bool used = true;
     bool IDed = true;
     switch(type){
     case ConsumableType.HEALING:
         user.curhp = user.maxhp;
         B.Add(user.Your() + " wounds are healed completely. ",user);
         break;
     case ConsumableType.REGENERATION:
     {
         if(user == player){
             B.Add("Your blood tingles. ");
         }
         else{
             B.Add(user.the_name + " looks energized. ",user);
         }
         user.attrs[AttrType.REGENERATING]++;
         int duration = 100;
         Q.Add(new Event(user,duration*100,AttrType.REGENERATING));
         break;
     }
     case ConsumableType.STONEFORM:
     {
         B.Add(user.You("transform") + " into a being of animated stone. ",user);
         int duration = R.Roll(2,20) + 20;
         List<AttrType> attributes = new List<AttrType>{AttrType.REGENERATING,AttrType.BRUTISH_STRENGTH,AttrType.VIGOR,AttrType.SILENCE_AURA,AttrType.SHADOW_CLOAK,AttrType.CAN_DODGE,AttrType.MENTAL_IMMUNITY,AttrType.DETECTING_MONSTERS,AttrType.MYSTIC_MIND};
         foreach(AttrType at in attributes){ //in the rare case where a monster drinks this potion, it can lose these natural statuses permanently. this might eventually be fixed.
             if(user.HasAttr(at)){
                 user.attrs[at] = 0;
                 Q.KillEvents(user,at);
                 switch(at){
                 case AttrType.REGENERATING:
                     B.Add(user.You("no longer regenerate") + ". ",user);
                     break;
                 case AttrType.BRUTISH_STRENGTH:
                     B.Add(user.Your() + " brutish strength fades. ",user);
                     break;
                 case AttrType.VIGOR:
                     B.Add(user.Your() + " extraordinary speed fades. ",user);
                     break;
                 case AttrType.SILENCED:
                     B.Add(user.You("no longer radiate") + " an aura of silence. ",user);
                     break;
                 case AttrType.SHADOW_CLOAK:
                     B.Add(user.YouAre() + " no longer cloaked. ",user);
                     break;
                 case AttrType.MYSTIC_MIND:
                     B.Add(user.Your() + " consciousness returns to normal. ",user);
                     break;
                 }
             }
         }
         if(user.HasAttr(AttrType.PSEUDO_VAMPIRIC)){
             user.attrs[AttrType.LIGHT_SENSITIVE] = 0;
             user.attrs[AttrType.FLYING] = 0;
             user.attrs[AttrType.PSEUDO_VAMPIRIC] = 0;
             Q.KillEvents(user,AttrType.LIGHT_SENSITIVE);
             Q.KillEvents(user,AttrType.FLYING);
             Q.KillEvents(user,AttrType.PSEUDO_VAMPIRIC);
             B.Add(user.YouAre() + " no longer vampiric. ",user);
         }
         if(user.HasAttr(AttrType.ROOTS)){
             foreach(Event e in Q.list){
                 if(e.target == user && !e.dead){
                     if(e.attr == AttrType.IMMOBILE && e.msg.Contains("rooted to the ground")){
                         e.dead = true;
                         user.attrs[AttrType.IMMOBILE]--;
                         B.Add(user.YouAre() + " no longer rooted to the ground. ",user);
                     }
                     else{
                         if(e.attr == AttrType.BONUS_DEFENSE && e.value == 10){
                             e.dead = true; //this would break if there were other timed effects that gave the same amount of defense
                             user.attrs[AttrType.BONUS_DEFENSE] -= 10;
                         }
                         else{
                             if(e.attr == AttrType.ROOTS){
                                 e.dead = true;
                                 user.attrs[AttrType.ROOTS]--;
                             }
                         }
                     }
                 }
             }
         }
         if(user.HasAttr(AttrType.BURNING)){
             user.RefreshDuration(AttrType.BURNING,0);
         }
         user.attrs[AttrType.IMMUNE_BURNING]++;
         Q.Add(new Event(user,duration*100,AttrType.IMMUNE_BURNING));
         user.attrs[AttrType.DAMAGE_RESISTANCE]++;
         Q.Add(new Event(user,duration*100,AttrType.DAMAGE_RESISTANCE));
         user.attrs[AttrType.NONLIVING]++;
         Q.Add(new Event(user,duration*100,AttrType.NONLIVING));
         user.RefreshDuration(AttrType.STONEFORM,duration*100,user.Your() + " rocky form reverts to flesh. ",user);
         if(user == player){
             Help.TutorialTip(TutorialTopic.Stoneform);
         }
         break;
     }
     case ConsumableType.VAMPIRISM:
     {
         B.Add(user.You("become") + " vampiric. ",user);
         B.Add(user.You("rise") + " into the air. ",user);
         int duration = R.Roll(2,20) + 20;
         user.RefreshDuration(AttrType.LIGHT_SENSITIVE,duration*100);
         user.RefreshDuration(AttrType.FLYING,duration*100);
         user.attrs[AttrType.DESCENDING] = 0;
         user.RefreshDuration(AttrType.PSEUDO_VAMPIRIC,duration*100,user.YouAre() + " no longer vampiric. ",user);
         if(user == player){
             Help.TutorialTip(TutorialTopic.Vampirism);
         }
         break;
     }
     case ConsumableType.BRUTISH_STRENGTH:
     {
         if(user == player){
             B.Add("You feel a surge of strength. ");
         }
         else{
             B.Add(user.Your() + " muscles ripple. ",user);
         }
         user.RefreshDuration(AttrType.BRUTISH_STRENGTH,(R.Roll(3,6)+16)*100,user.Your() + " incredible strength wears off. ",user);
         if(user == player){
             Help.TutorialTip(TutorialTopic.BrutishStrength);
         }
         break;
     }
     case ConsumableType.ROOTS:
     {
         if(user.HasAttr(AttrType.ROOTS)){
             foreach(Event e in Q.list){
                 if(e.target == user && !e.dead){
                     if(e.attr == AttrType.IMMOBILE && e.msg.Contains("rooted to the ground")){
                         e.dead = true;
                         user.attrs[AttrType.IMMOBILE]--;
                     }
                     else{
                         if(e.attr == AttrType.BONUS_DEFENSE && e.value == 10){
                             e.dead = true; //this would break if there were other timed effects that gave 5 defense
                             user.attrs[AttrType.BONUS_DEFENSE] -= 10;
                         }
                         else{
                             if(e.attr == AttrType.ROOTS){
                                 e.dead = true;
                                 user.attrs[AttrType.ROOTS]--;
                             }
                         }
                     }
                 }
             }
             B.Add(user.Your() + " roots extend deeper into the ground. ",user);
         }
         else{
             B.Add(user.You("grow") + " roots and a hard shell of bark. ",user);
         }
         int duration = R.Roll(20) + 20;
         user.RefreshDuration(AttrType.ROOTS,duration*100);
         user.attrs[AttrType.BONUS_DEFENSE] += 10;
         Q.Add(new Event(user,duration*100,AttrType.BONUS_DEFENSE,10));
         user.attrs[AttrType.IMMOBILE]++;
         Q.Add(new Event(user,duration*100,AttrType.IMMOBILE,user.YouAre() + " no longer rooted to the ground. ",user));
         if(user == player){
             Help.TutorialTip(TutorialTopic.Roots);
         }
         if(user.HasAttr(AttrType.FLYING) && user.tile().IsTrap()){
             user.tile().TriggerTrap();
         }
         break;
     }
     case ConsumableType.HASTE:
     {
         B.Add(user.You("start") + " moving with extraordinary speed. ",user);
         int duration = (R.Roll(2,10) + 10) * 100;
         user.RefreshDuration(AttrType.CAN_DODGE,duration); //todo: dodging tip goes here
         user.RefreshDuration(AttrType.VIGOR,duration,user.Your() + " extraordinary speed fades. ",user);
         if(user == player){
             Help.TutorialTip(TutorialTopic.IncreasedSpeed);
         }
         break;
     }
     case ConsumableType.SILENCE:
     {
         B.Add("A hush falls around " + user.the_name + ". ",user);
         user.RefreshDuration(AttrType.SILENCE_AURA,(R.Roll(2,20)+20)*100,user.You("no longer radiate") + " an aura of silence. ",user);
         if(user == player){
             Help.TutorialTip(TutorialTopic.Silenced);
         }
         break;
     }
     case ConsumableType.CLOAKING:
         if(user.tile().IsLit()){
             if(user == player){
                 B.Add("You would feel at home in the shadows. ");
             }
             else{
                 B.Add("A shadow moves across " + user.the_name + ". ",user);
             }
         }
         else{
             B.Add(user.You("fade") + " away in the darkness. ",user);
         }
         user.RefreshDuration(AttrType.SHADOW_CLOAK,(R.Roll(2,20)+30)*100,user.YouAre() + " no longer cloaked. ",user);
         break;
     case ConsumableType.MYSTIC_MIND:
     {
         B.Add(user.Your() + " mind expands. ",user);
         int duration = R.Roll(2,20)+60;
         user.attrs[AttrType.ASLEEP] = 0;
         //user.RefreshDuration(AttrType.MAGICAL_DROWSINESS,0);
         user.RefreshDuration(AttrType.CONFUSED,0);
         user.RefreshDuration(AttrType.STUNNED,0);
         user.RefreshDuration(AttrType.ENRAGED,0);
         user.RefreshDuration(AttrType.MENTAL_IMMUNITY,duration*100);
         user.RefreshDuration(AttrType.DETECTING_MONSTERS,duration*100);
         user.RefreshDuration(AttrType.MYSTIC_MIND,duration*100,user.Your() + " consciousness returns to normal. ",user);
         if(user == player){
             Help.TutorialTip(TutorialTopic.MysticMind);
         }
         break;
     }
     case ConsumableType.BLINKING:
     {
         List<Tile> tiles = user.TilesWithinDistance(8).Where(x => x.passable && x.actor() == null && user.ApproximateEuclideanDistanceFromX10(x) >= 45);
         if(tiles.Count > 0 && !user.HasAttr(AttrType.IMMOBILE)){
             Tile t = tiles.Random();
             B.Add(user.You("step") + " through a rip in reality. ",M.tile[user.p],t);
             user.AnimateStorm(2,3,4,'*',Color.DarkMagenta);
             user.Move(t.row,t.col);
             M.Draw();
             user.AnimateStorm(2,3,4,'*',Color.DarkMagenta);
         }
         else{
             B.Add("Nothing happens. ",user);
             IDed = false;
         }
         break;
     }
     case ConsumableType.PASSAGE:
     {
         if(user.HasAttr(AttrType.IMMOBILE)){
             B.Add("Nothing happens. ",user);
             IDed = false;
             break;
         }
         List<int> valid_dirs = new List<int>();
         foreach(int dir in U.FourDirections){
             Tile t = user.TileInDirection(dir);
             if(t != null && t.Is(TileType.WALL,TileType.CRACKED_WALL,TileType.WAX_WALL,TileType.DOOR_C,TileType.HIDDEN_DOOR,TileType.STONE_SLAB)){
                 while(!t.passable){
                     if(t.row == 0 || t.row == Global.ROWS-1 || t.col == 0 || t.col == Global.COLS-1){
                         break;
                     }
                     t = t.TileInDirection(dir);
                 }
                 if(t.passable){
                     valid_dirs.Add(dir);
                 }
             }
         }
         if(valid_dirs.Count > 0){
             int dir = valid_dirs.Random();
             Tile t = user.TileInDirection(dir);
             colorchar ch = new colorchar(Color.Cyan,'!');
             switch(user.DirectionOf(t)){
             case 8:
             case 2:
                 ch.c = '|';
                 break;
             case 4:
             case 6:
                 ch.c = '-';
                 break;
             }
             List<Tile> tiles = new List<Tile>();
             List<colorchar> memlist = new List<colorchar>();
             Screen.CursorVisible = false;
             Tile last_wall = null;
             while(!t.passable){
                 tiles.Add(t);
                 memlist.Add(Screen.MapChar(t.row,t.col));
                 Screen.WriteMapChar(t.row,t.col,ch);
                 Game.GLUpdate();
                 Thread.Sleep(35);
                 last_wall = t;
                 t = t.TileInDirection(dir);
             }
             Input.FlushInput();
             if(t.actor() == null){
                 int r = user.row;
                 int c = user.col;
                 user.Move(t.row,t.col);
                 Screen.WriteMapChar(r,c,M.VisibleColorChar(r,c));
                 Screen.WriteMapChar(t.row,t.col,M.VisibleColorChar(t.row,t.col));
                 int idx = 0;
                 foreach(Tile tile in tiles){
                     Screen.WriteMapChar(tile.row,tile.col,memlist[idx++]);
                     Game.GLUpdate();
                     Thread.Sleep(35);
                 }
                 Input.FlushInput();
                 B.Add(user.You("travel") + " through the passage. ",user,t);
             }
             else{
                 Tile destination = null;
                 List<Tile> adjacent = t.TilesAtDistance(1).Where(x=>x.passable && x.actor() == null && x.DistanceFrom(last_wall) == 1);
                 if(adjacent.Count > 0){
                     destination = adjacent.Random();
                 }
                 else{
                     foreach(Tile tile in M.ReachableTilesByDistance(t.row,t.col,false)){
                         if(tile.actor() == null){
                             destination = tile;
                             break;
                         }
                     }
                 }
                 if(destination != null){
                     int r = user.row;
                     int c = user.col;
                     user.Move(destination.row,destination.col);
                     Screen.WriteMapChar(r,c,M.VisibleColorChar(r,c));
                     Screen.WriteMapChar(destination.row,destination.col,M.VisibleColorChar(destination.row,destination.col));
                     int idx = 0;
                     foreach(Tile tile in tiles){
                         Screen.WriteMapChar(tile.row,tile.col,memlist[idx++]);
                         Game.GLUpdate();
                         Thread.Sleep(35);
                     }
                     Input.FlushInput();
                     B.Add(user.You("travel") + " through the passage. ",user,destination);
                 }
                 else{
                     B.Add("Something blocks " + user.Your() + " movement through the passage. ",user);
                 }
             }
         }
         else{
             B.Add("Nothing happens. ",user);
             IDed = false;
         }
         break;
     }
     case ConsumableType.TIME:
         if(user == player){
             B.Add("Time stops for a moment. ",user);
         }
         else{
             B.Add("Time warps around " + user.the_name + "! ",user);
             B.PrintAll();
         }
         if(Fire.fire_event == null){ //this prevents fire from updating while time is frozen
             Fire.fire_event = new Event(0,EventType.FIRE);
             Fire.fire_event.tiebreaker = 0;
             Q.Add(Fire.fire_event);
         }
         Q.turn -= 200;
         break;
     case ConsumableType.KNOWLEDGE:
     {
         if(user == player){
             B.Add("Knowledge fills your mind. ");
             Event hiddencheck = null;
             foreach(Event e in Q.list){
                 if(!e.dead && e.type == EventType.CHECK_FOR_HIDDEN){
                     hiddencheck = e;
                     break;
                 }
             }
             int max_dist = 0;
             List<Tile> last_tiles = new List<Tile>();
             foreach(Tile t in M.ReachableTilesByDistance(user.row,user.col,true,TileType.STONE_SLAB,TileType.DOOR_C,TileType.STALAGMITE,TileType.RUBBLE,TileType.HIDDEN_DOOR)){
                 if(t.type != TileType.FLOOR){
                     t.seen = true;
                     if(t.type != TileType.WALL){
                         t.revealed_by_light = true;
                     }
                     if(t.IsTrap() || t.Is(TileType.HIDDEN_DOOR)){
                         if(hiddencheck != null){
                             hiddencheck.area.Remove(t);
                         }
                     }
                     if(t.IsTrap()){
                         t.name = Tile.Prototype(t.type).name;
                         t.a_name = Tile.Prototype(t.type).a_name;
                         t.the_name = Tile.Prototype(t.type).the_name;
                         t.symbol = Tile.Prototype(t.type).symbol;
                         t.color = Tile.Prototype(t.type).color;
                     }
                     if(t.Is(TileType.HIDDEN_DOOR)){
                         t.Toggle(null);
                     }
                     colorchar ch2 = Screen.BlankChar();
                     if(t.inv != null){
                         t.inv.revealed_by_light = true;
                         ch2.c = t.inv.symbol;
                         ch2.color = t.inv.color;
                         M.last_seen[t.row,t.col] = ch2;
                     }
                     else{
                         if(t.features.Count > 0){
                             ch2 = t.FeatureVisual();
                             M.last_seen[t.row,t.col] = ch2;
                         }
                         else{
                             ch2.c = t.symbol;
                             ch2.color = t.color;
                             if(ch2.c == '#' && ch2.color == Color.RandomGlowingFungus){
                                 ch2.color = Color.Gray;
                             }
                             M.last_seen[t.row,t.col] = ch2;
                         }
                     }
                     Screen.WriteMapChar(t.row,t.col,t.symbol,Color.RandomRainbow);
                     //Screen.WriteMapChar(t.row,t.col,M.VisibleColorChar(t.row,t.col));
                     if(user.DistanceFrom(t) > max_dist){
                         max_dist = user.DistanceFrom(t);
                         Game.GLUpdate();
                         Thread.Sleep(10);
                         while(last_tiles.Count > 0){
                             Tile t2 = last_tiles.RemoveRandom();
                             Screen.WriteMapChar(t2.row,t2.col,M.last_seen[t2.row,t2.col]);
                             //Screen.WriteMapChar(t2.row,t2.col,M.VisibleColorChar(t2.row,t2.col));
                         }
                     }
                     last_tiles.Add(t);
                 }
             }
             if(user.inv.Count > 0){
                 foreach(Item i in user.inv){
                     identified[i.type] = true;
                     if(i.NameOfItemType() == "wand"){
                         i.other_data = -1;
                     }
                 }
             }
         }
         else{
             B.Add(user.the_name + " looks more knowledgeable. ",user);
         }
         break;
     }
     case ConsumableType.SUNLIGHT:
         if(M.wiz_lite == false){
             B.Add("The air itself seems to shine. ");
             M.wiz_lite = true;
             M.wiz_dark = false;
             Q.KillEvents(null,EventType.NORMAL_LIGHTING);
             Q.Add(new Event((R.Roll(2,20) + 120) * 100,EventType.NORMAL_LIGHTING));
         }
         else{
             B.Add("The air grows even brighter for a moment. ");
             Q.KillEvents(null,EventType.NORMAL_LIGHTING);
             Q.Add(new Event((R.Roll(2,20) + 120) * 100,EventType.NORMAL_LIGHTING));
         }
         break;
     case ConsumableType.DARKNESS:
         if(M.wiz_dark == false){
             B.Add("The air itself grows dark. ");
             if(player.light_radius > 0){
                 B.Add("Your light is extinguished! ");
             }
             M.wiz_dark = true;
             M.wiz_lite = false;
             Q.KillEvents(null,EventType.NORMAL_LIGHTING);
             Q.Add(new Event((R.Roll(2,20) + 120) * 100,EventType.NORMAL_LIGHTING));
         }
         else{
             B.Add("The air grows even darker for a moment. ");
             Q.KillEvents(null,EventType.NORMAL_LIGHTING);
             Q.Add(new Event((R.Roll(2,20) + 120) * 100,EventType.NORMAL_LIGHTING));
         }
         break;
     case ConsumableType.RENEWAL:
     {
         B.Add("A glow envelops " + user.the_name + ". ",user);
         //B.Add("A glow envelops " + user.Your() + " equipment. ",user);
         bool repaired = false;
         foreach(EquipmentStatus eqstatus in Enum.GetValues(typeof(EquipmentStatus))){
             foreach(Weapon w in user.weapons){
                 if(w.status[eqstatus]){
                     repaired = true;
                     w.status[eqstatus] = false;
                 }
             }
             foreach(Armor a in user.armors){
                 if(a.status[eqstatus]){
                     repaired = true;
                     a.status[eqstatus] = false;
                 }
             }
         }
         if(repaired){
             B.Add(user.Your() + " equipment looks as good as new! ",user);
         }
         if(user.HasAttr(AttrType.SLIMED)){
             B.Add(user.YouAre() + " no longer covered in slime. ",user);
             user.attrs[AttrType.SLIMED] = 0;
         }
         if(user.HasAttr(AttrType.OIL_COVERED)){
             B.Add(user.YouAre() + " no longer covered in oil. ",user);
             user.attrs[AttrType.OIL_COVERED] = 0;
         }
         int recharged = 0;
         foreach(Item i in user.inv){
             if(i.NameOfItemType() == "wand"){
                 i.charges++;
                 recharged++;
             }
         }
         if(recharged > 0){
             if(recharged == 1){
                 B.Add("The glow charges " + user.Your() + " wand. ",user);
             }
             else{
                 B.Add("The glow charges " + user.Your() + " wands. ",user);
             }
         }
         break;
     }
     case ConsumableType.CALLING:
     {
         bool found = false;
         if(user == player){
             for(int dist = 1;dist < Math.Max(Global.ROWS,Global.COLS);++dist){
                 List<Tile> tiles = user.TilesAtDistance(dist).Where(x=>x.actor() != null && !x.actor().HasAttr(AttrType.IMMOBILE));
                 if(tiles.Count > 0){
                     Actor a = tiles.Random().actor();
                     Tile t2 = user.TileInDirection(user.DirectionOf(a));
                     if(t2.passable && t2.actor() == null){
                         B.Add("The scroll calls " + a.a_name + " to you. ");
                         a.Move(t2.row,t2.col);
                         found = true;
                         break;
                     }
                     foreach(Tile t in M.ReachableTilesByDistance(user.row,user.col,false)){
                         if(t.actor() == null){
                             B.Add("The scroll calls " + a.a_name + " to you. ");
                             a.Move(t.row,t.col);
                             found = true;
                             break;
                         }
                     }
                     if(found){
                         break;
                     }
                 }
             }
         }
         else{
             if(!player.HasAttr(AttrType.IMMOBILE) && user.DistanceFrom(player) > 1){
                 Tile t2 = user.TileInDirection(user.DirectionOf(player));
                 if(t2.passable && t2.actor() == null){
                     B.Add("The scroll calls you to " + user.TheName(true) + ". ");
                     player.Move(t2.row,t2.col);
                     found = true;
                 }
                 if(!found){
                     foreach(Tile t in M.ReachableTilesByDistance(user.row,user.col,false)){
                         if(t.actor() == null){
                             B.Add("The scroll calls you to " + user.TheName(true) + ". ");
                             player.Move(t.row,t.col);
                             found = true;
                             break;
                         }
                     }
                 }
             }
         }
         if(!found){
             B.Add("Nothing happens. ",user);
             IDed = false;
         }
         break;
     }
     case ConsumableType.TRAP_CLEARING:
     {
         List<Tile> traps = new List<Tile>();
         {
             List<Tile>[] traparray = new List<Tile>[5];
             for(int i=0;i<5;++i){
                 traparray[i] = new List<Tile>();
             }
             for(int i=0;i<=12;++i){
                 foreach(Tile t in user.TilesAtDistance(i)){ //all this ensures that the traps go off in the best order
                     switch(t.type){
                     case TileType.ALARM_TRAP:
                     case TileType.TELEPORT_TRAP:
                     case TileType.ICE_TRAP:
                     case TileType.BLINDING_TRAP:
                     case TileType.SHOCK_TRAP:
                     case TileType.FIRE_TRAP:
                     case TileType.SCALDING_OIL_TRAP:
                         traparray[0].Add(t);
                         break;
                     case TileType.POISON_GAS_TRAP:
                     case TileType.GRENADE_TRAP:
                         traparray[1].Add(t);
                         break;
                     case TileType.SLIDING_WALL_TRAP:
                     case TileType.PHANTOM_TRAP:
                         traparray[2].Add(t);
                         break;
                     case TileType.LIGHT_TRAP:
                     case TileType.DARKNESS_TRAP:
                         traparray[3].Add(t);
                         break;
                     case TileType.FLING_TRAP:
                     case TileType.STONE_RAIN_TRAP:
                         traparray[4].Add(t);
                         break;
                     }
                 }
             }
             for(int i=0;i<5;++i){
                 foreach(Tile t in traparray[i]){
                     traps.Add(t);
                 }
             }
         }
         if(traps.Count > 0){
             B.Add("*CLICK*. ");
             foreach(Tile t in traps){
                 t.TriggerTrap(false);
             }
         }
         else{
             B.Add("Nothing happens. ",user);
             IDed = false;
         }
         break;
     }
     case ConsumableType.ENCHANTMENT:
     {
         if(user == player){
             EnchantmentType ench = (EnchantmentType)R.Between(0,4);
             while(ench == user.EquippedWeapon.enchantment){
                 ench = (EnchantmentType)R.Between(0,4);
             }
             B.Add("Your " + user.EquippedWeapon.NameWithEnchantment() + " glows brightly! ");
             user.EquippedWeapon.enchantment = ench;
             B.Add("Your " + user.EquippedWeapon.NameWithoutEnchantment() + " is now a " + user.EquippedWeapon.NameWithEnchantment() + "! ");
         }
         else{
             B.Add("Nothing happens. ",user);
             IDed = false;
         }
         break;
     }
     case ConsumableType.THUNDERCLAP:
     {
         B.Add("Thunder crashes! ",user);
         var scr = Screen.GetCurrentMap();
         List<Tile>[] printed = new List<Tile>[13];
         Color leading_edge_color = Color.White;
         Color trail_color = Color.DarkCyan;
         if(Global.LINUX && !Screen.GLMode){
             leading_edge_color = Color.Gray;
         }
         for(int dist=0;dist<=12;++dist){
             printed[dist] = new List<Tile>();
             foreach(Tile t in user.TilesAtDistance(dist)){
                 if(t.seen && user.HasLOE(t)){
                     printed[dist].Add(t);
                 }
             }
             foreach(Tile t in printed[dist]){
                 colorchar cch = M.VisibleColorChar(t.row,t.col);
                 cch.bgcolor = leading_edge_color;
                 if(cch.color == leading_edge_color){
                     cch.color = Color.Black;
                 }
                 Screen.WriteMapChar(t.row,t.col,cch);
             }
             if(dist > 0){
                 foreach(Tile t in printed[dist-1]){
                     colorchar cch = M.VisibleColorChar(t.row,t.col);
                     cch.bgcolor = trail_color;
                     if(cch.color == trail_color){
                         cch.color = Color.Black;
                     }
                     Screen.WriteMapChar(t.row,t.col,cch);
                 }
                 if(dist > 4){
                     foreach(Tile t in printed[dist-5]){
                         Screen.WriteMapChar(t.row,t.col,scr[t.row,t.col]);
                     }
                 }
             }
             Game.GLUpdate();
             Thread.Sleep(10);
         }
         List<Actor> actors = new List<Actor>();
         for(int dist=0;dist<=12;++dist){
             foreach(Tile t in user.TilesAtDistance(dist).Randomize()){
                 if(user.HasLOE(t)){
                     if(t.actor() != null && t.actor() != user){
                         actors.Add(t.actor());
                     }
                     t.BreakFragileFeatures();
                 }
             }
         }
         foreach(Actor a in actors){
             if(a.TakeDamage(DamageType.MAGIC,DamageClass.MAGICAL,R.Roll(4,6),user,"a scroll of thunderclap")){
                 a.ApplyStatus(AttrType.STUNNED,R.Between(5,10)*100);
             }
         }
         user.MakeNoise(12);
         break;
     }
     case ConsumableType.FIRE_RING:
     {
         List<pos> cells = new List<pos>();
         List<Tile> valid = new List<Tile>();
         foreach(Tile t in user.TilesWithinDistance(3)){
             if(t.passable && user.DistanceFrom(t) > 1 && user.HasLOE(t) && user.ApproximateEuclideanDistanceFromX10(t) < 45){
                 valid.Add(t);
                 cells.Add(t.p);
             }
         }
         if(valid.Count > 0){
             if(player.CanSee(user)){
                 B.Add("A ring of fire surrounds " + user.the_name + ". ");
             }
             else{
                 B.Add("A ring of fire appears! ",user.tile());
             }
             valid.Randomize();
             foreach(Tile t in valid){
                 t.AddFeature(FeatureType.FIRE);
             }
             Screen.AnimateMapCells(cells,new colorchar('&',Color.RandomFire));
         }
         else{
             B.Add("Nothing happens. ",user);
             IDed = false;
         }
         break;
     }
     case ConsumableType.RAGE:
     {
         B.Add("A murderous red glow cascades outward. ",user);
         List<Tile>[] printed = new List<Tile>[13];
         Color leading_edge_color = Color.Red;
         Color trail_color = Color.DarkRed;
         if(Global.LINUX && !Screen.GLMode){
             leading_edge_color = Color.DarkRed;
         }
         for(int dist=0;dist<=12;++dist){
             printed[dist] = new List<Tile>();
             foreach(Tile t in user.TilesAtDistance(dist)){
                 if(t.seen && user.HasLOS(t)){
                     printed[dist].Add(t);
                 }
             }
             foreach(Tile t in printed[dist]){
                 colorchar cch = M.VisibleColorChar(t.row,t.col);
                 cch.bgcolor = leading_edge_color;
                 if(cch.color == leading_edge_color){
                     cch.color = Color.Black;
                 }
                 Screen.WriteMapChar(t.row,t.col,cch);
             }
             if(dist > 0){
                 foreach(Tile t in printed[dist-1]){
                     colorchar cch = M.VisibleColorChar(t.row,t.col);
                     cch.bgcolor = trail_color;
                     if(cch.color == trail_color){
                         cch.color = Color.Black;
                     }
                     Screen.WriteMapChar(t.row,t.col,cch);
                 }
             }
             Game.GLUpdate();
             Thread.Sleep(5);
         }
         int actors_affected = 0;
         string name_is = "";
         foreach(Actor a in M.AllActors()){
             if(a != user && user.DistanceFrom(a) <= 12 && user.HasLOS(a)){
                 a.ApplyStatus(AttrType.ENRAGED,R.Between(10,17)*100,false,"",a.You("calm") + " down. ",a.You("resist") + "! ");
                 actors_affected++;
                 if(player.CanSee(a)){
                     name_is = a.YouAre();
                 }
             }
         }
         if(actors_affected > 0){
             if(actors_affected == 1){
                 B.Add(name_is + " enraged! ");
             }
             else{
                 B.Add("Bloodlust fills the air. ");
             }
         }
         break;
     }
     case ConsumableType.FREEZING:
     {
         ItemUseResult orb_result = UseOrb(2,false,user,line,(t,LOE_tile,results)=>{
             Screen.AnimateExplosion(t,2,new colorchar('*',Color.RandomIce));
             List<Tile> targets = new List<Tile>();
             foreach(Tile t2 in t.TilesWithinDistance(2)){
                 if(LOE_tile.HasLOE(t2)){
                     targets.Add(t2);
                 }
             }
             while(targets.Count > 0){
                 Tile t2 = targets.RemoveRandom();
                 t2.ApplyEffect(DamageType.COLD);
                 Actor ac = t2.actor();
                 if(ac != null){
                     ac.ApplyFreezing();
                 }
             }
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.FLAMES:
     {
         ItemUseResult orb_result = UseOrb(2,false,user,line,(t,LOE_tile,results)=>{
             List<Tile> area = new List<Tile>();
             List<pos> cells = new List<pos>();
             foreach(Tile tile in t.TilesWithinDistance(2)){
                 if(LOE_tile.HasLOE(tile)){
                     if(tile.passable){
                         tile.AddFeature(FeatureType.FIRE);
                     }
                     else{
                         tile.ApplyEffect(DamageType.FIRE);
                     }
                     if(tile.Is(FeatureType.FIRE)){
                         area.Add(tile);
                     }
                     cells.Add(tile.p);
                 }
             }
             Screen.AnimateMapCells(cells,new colorchar('&',Color.RandomFire));
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.FOG:
     {
         ItemUseResult orb_result = UseOrb(3,false,user,line,(t,LOE_tile,results)=>{
             List<Tile> area = new List<Tile>();
             List<pos> cells = new List<pos>();
             colorchar cch = new colorchar('*',Color.Gray);
             for(int i=0;i<=3;++i){
                 foreach(Tile tile in t.TilesAtDistance(i)){
                     if(tile.passable && LOE_tile.HasLOE(tile)){
                         tile.AddFeature(FeatureType.FOG);
                         area.Add(tile);
                         cells.Add(tile.p);
                         if(tile.seen){
                             M.last_seen[tile.row,tile.col] = cch;
                         }
                     }
                 }
                 Screen.AnimateMapCells(cells,cch,40);
             }
             Q.RemoveTilesFromEventAreas(area,EventType.REMOVE_GAS);
             Event.RemoveGas(area,800,FeatureType.FOG,25);
             //Q.Add(new Event(area,600,EventType.FOG,25));
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.DETONATION:
     {
         ItemUseResult orb_result = UseOrb(3,false,user,line,(t,LOE_tile,results)=>{
             LOE_tile.ApplyExplosion(3,user,"an orb of detonation");
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.BREACHING:
     {
         ItemUseResult orb_result = UseOrb(5,false,user,line,(t,LOE_tile,results)=>{
             int max_dist = -1;
             foreach(Tile t2 in M.TilesByDistance(t.row,t.col,false,true)){
                 if(t.DistanceFrom(t2) > 5){
                     break;
                 }
                 if(t2.Is(TileType.WALL,TileType.WAX_WALL,TileType.STALAGMITE,TileType.CRACKED_WALL,TileType.DOOR_C)){
                     Screen.WriteMapChar(t2.row,t2.col,t2.symbol,Color.RandomBreached);
                     if(t.DistanceFrom(t2) > max_dist){
                         max_dist = t.DistanceFrom(t2);
                         Game.GLUpdate(); //todo: stalagmites - if I add them to caves, they should no longer always vanish. check for an event, maybe?
                         Thread.Sleep(50);
                     }
                 }
             }
             List<Tile> area = new List<Tile>();
             foreach(Tile tile in t.TilesWithinDistance(5)){
                 if(tile.Is(TileType.WALL,TileType.WAX_WALL,TileType.STALAGMITE,TileType.CRACKED_WALL,TileType.DOOR_C) && tile.p.BoundsCheck(M.tile,false)){
                     TileType prev_type = tile.type;
                     if(tile.Is(TileType.STALAGMITE)){
                         tile.Toggle(null,TileType.FLOOR);
                     }
                     else{
                         tile.Toggle(null,TileType.BREACHED_WALL);
                         tile.toggles_into = prev_type;
                         area.Add(tile);
                     }
                     foreach(Tile neighbor in tile.TilesWithinDistance(1)){
                         neighbor.solid_rock = false;
                     }
                 }
             }
             if(area.Count > 0){
                 Q.Add(new Event(t,area,500,EventType.BREACH));
             }
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.SHIELDING:
     {
         ItemUseResult orb_result = UseOrb(1,true,user,line,(t,LOE_tile,results)=>{
             List<Tile> area = new List<Tile>();
             List<pos> cells = new List<pos>();
             List<colorchar> symbols = new List<colorchar>();
             foreach(Tile tile in t.TilesWithinDistance(1)){
                 if(tile.passable && LOE_tile.HasLOE(tile)){
                     colorchar cch = tile.visual;
                     if(tile.actor() != null){
                         if(!tile.actor().HasAttr(AttrType.SHIELDED)){
                             tile.actor().attrs[AttrType.SHIELDED] = 1;
                             B.Add(tile.actor().YouAre() + " shielded. ",tile.actor());
                         }
                         if(player.CanSee(tile.actor())){
                             cch = tile.actor().visual;
                         }
                     }
                     cch.bgcolor = Color.Blue;
                     if(Global.LINUX && !Screen.GLMode){
                         cch.bgcolor = Color.DarkBlue;
                     }
                     if(cch.color == cch.bgcolor){
                         cch.color = Color.Black;
                     }
                     if(cch.c == '.'){
                         cch.c = '+';
                     }
                     symbols.Add(cch);
                     cells.Add(tile.p);
                     area.Add(tile);
                 }
             }
             Screen.AnimateMapCells(cells,symbols,150);
             foreach(Tile tile in area){
                 if(player.CanSee(tile)){
                     B.Add("A zone of protection is created. ");
                     break;
                 }
             }
             Q.Add(new Event(area,100,EventType.SHIELDING,R.Roll(2,6)+6));
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.TELEPORTAL:
     {
         ItemUseResult orb_result = UseOrb(0,false,user,line,(t,LOE_tile,results)=>{
             LOE_tile.AddFeature(FeatureType.TELEPORTAL);
             if(LOE_tile.Is(FeatureType.TELEPORTAL)){
                 Q.Add(new Event(LOE_tile,0,EventType.TELEPORTAL,100));
             }
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.PAIN:
     {
         ItemUseResult orb_result = UseOrb(5,false,user,line,(t,LOE_tile,results)=>{
             List<pos> cells = new List<pos>();
             List<colorchar> symbols = new List<colorchar>();
             foreach(Tile tile in t.TilesWithinDistance(5)){
                 if(LOE_tile.HasLOE(tile)){
                     Actor a = tile.actor();
                     if(a != null){
                         if(a.TakeDamage(DamageType.MAGIC,DamageClass.MAGICAL,R.Roll(2,6),user,"an orb of pain")){
                             a.ApplyStatus(AttrType.VULNERABLE,(R.Roll(2,6)+6)*100);
                             if(a == player){
                                 Help.TutorialTip(TutorialTopic.Vulnerable);
                             }
                         }
                     }
                     symbols.Add(new colorchar('*',Color.RandomDoom));
                     /*if(tile.DistanceFrom(t) % 2 == 0){
                         symbols.Add(new colorchar('*',Color.DarkMagenta));
                     }
                     else{
                         symbols.Add(new colorchar('*',Color.DarkRed));
                     }*/
                     cells.Add(tile.p);
                 }
             }
             player.AnimateVisibleMapCells(cells,symbols,80);
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.CONFUSION:
     {
         ItemUseResult orb_result = UseOrb(2,false,user,line,(t,LOE_tile,results)=>{
             List<Tile> area = new List<Tile>();
             List<pos> cells = new List<pos>();
             colorchar cch = new colorchar('*',Color.RandomConfusion);
             for(int i=0;i<=2;++i){
                 foreach(Tile tile in t.TilesAtDistance(i)){
                     if(tile.passable && LOE_tile.HasLOE(tile)){
                         tile.AddFeature(FeatureType.CONFUSION_GAS);
                         area.Add(tile);
                         cells.Add(tile.p);
                         if(tile.seen){
                             M.last_seen[tile.row,tile.col] = cch;
                         }
                     }
                 }
                 Screen.AnimateMapCells(cells,cch,40);
             }
             Q.RemoveTilesFromEventAreas(area,EventType.REMOVE_GAS);
             Event.RemoveGas(area,R.Between(7,9)*100,FeatureType.CONFUSION_GAS,20);
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.BLADES:
     {
         ItemUseResult orb_result = UseOrb(1,false,user,line,(t,LOE_tile,results)=>{
             List<Tile> targets = new List<Tile>();
             foreach(Tile t2 in t.TilesWithinDistance(1)){
                 if(t2.passable && t2.actor() == null && LOE_tile.HasLOE(t2)){
                     targets.Add(t2);
                 }
             }
             targets.Randomize();
             foreach(Tile t2 in targets){
                 Actor a = Actor.Create(ActorType.BLADE,t2.row,t2.col);
                 if(a != null){
                     a.speed = 50;
                 }
             }
         });
         used = orb_result.used;
         IDed = orb_result.IDed;
         break;
     }
     case ConsumableType.DUST_STORM:
     {
         ItemUseResult wand_result = UseWand(true,false,user,line,(LOE_tile,targeting,results)=>{
             List<Tile> area = new List<Tile>();
             List<pos> cells = new List<pos>();
             foreach(Tile neighbor in LOE_tile.TilesWithinDistance(1)){
                 if(neighbor.passable){
                     area.Add(neighbor);
                 }
             }
             List<Tile> added = new List<Tile>();
             foreach(Tile n1 in area){
                 foreach(int dir in U.FourDirections){
                     if(R.CoinFlip() && n1.TileInDirection(dir).passable){
                         added.Add(n1.TileInDirection(dir));
                     }
                 }
             }
             foreach(Tile n1 in added){
                 area.AddUnique(n1);
             }
             colorchar cch = new colorchar('*',Color.TerrainDarkGray);
             foreach(Tile t2 in area){
                 t2.AddFeature(FeatureType.THICK_DUST);
                 cells.Add(t2.p);
                 if(t2.seen){
                     M.last_seen[t2.row,t2.col] = cch;
                 }
                 Actor a = t2.actor();
                 if(a != null && t2.Is(FeatureType.THICK_DUST)){
                     if(!a.HasAttr(AttrType.NONLIVING,AttrType.PLANTLIKE,AttrType.BLINDSIGHT)){
                         if(a == player){
                             B.Add("Thick dust fills the air! ");
                         }
                         a.ApplyStatus(AttrType.BLIND,R.Between(1,3)*100);
                     }
                 }
             }
             Screen.AnimateMapCells(cells,cch,80);
             Q.RemoveTilesFromEventAreas(area,EventType.REMOVE_GAS);
             Event.RemoveGas(area,R.Between(20,25)*100,FeatureType.THICK_DUST,8);
         });
         used = wand_result.used;
         IDed = wand_result.IDed;
         break;
     }
     case ConsumableType.FLESH_TO_FIRE:
     {
         ItemUseResult wand_result = UseWand(true,false,user,line,(LOE_tile,targeting,results)=>{
             Actor a = targeting.targeted.actor();
             if(a != null){
                 B.Add("Jets of flame erupt from " + a.TheName(true) + ". ",a,targeting.targeted);
                 Screen.AnimateMapCell(a.row,a.col,new colorchar('&',Color.RandomFire));
                 int dmg = (a.curhp+1)/2;
                 if(a.TakeDamage(DamageType.MAGIC,DamageClass.MAGICAL,dmg,user,"a wand of flesh to fire")){
                     a.ApplyBurning();
                 }
             }
             else{
                 if(targeting.targeted.Is(FeatureType.TROLL_CORPSE)){
                     B.Add("Jets of flame erupt from the troll corpse. ",a,targeting.targeted);
                     targeting.targeted.ApplyEffect(DamageType.FIRE);
                     if(targeting.targeted.Is(FeatureType.TROLL_CORPSE)){ //if it's still there because of thick gas, it still gets destroyed.
                         targeting.targeted.RemoveFeature(FeatureType.TROLL_CORPSE);
                         B.Add("The troll corpse burns to ashes! ",targeting.targeted);
                     }
                 }
                 else{
                     if(targeting.targeted.Is(FeatureType.TROLL_BLOODWITCH_CORPSE)){
                         B.Add("Jets of flame erupt from the troll bloodwitch corpse. ",a,targeting.targeted);
                         targeting.targeted.ApplyEffect(DamageType.FIRE);
                         if(targeting.targeted.Is(FeatureType.TROLL_BLOODWITCH_CORPSE)){ //if it's still there because of thick gas, it still gets destroyed.
                             targeting.targeted.RemoveFeature(FeatureType.TROLL_BLOODWITCH_CORPSE);
                             B.Add("The troll bloodwitch corpse burns to ashes! ",targeting.targeted);
                         }
                     }
                     else{
                         B.Add("Nothing happens. ",user);
                         results.IDed = false;
                     }
                 }
             }
         });
         used = wand_result.used;
         IDed = wand_result.IDed;
         break;
     }
     case ConsumableType.INVISIBILITY:
     {
         ItemUseResult wand_result = UseWand(false,false,user,line,(LOE_tile,targeting,results)=>{
             Actor a = targeting.targeted.actor();
             if(a != null){
                 B.Add(a.You("vanish",true) + " from view. ",a);
                 if(a.light_radius > 0 && !M.wiz_dark && !M.wiz_lite){
                     B.Add(a.Your() + " light still reveals " + a.Your() + " location. ",a);
                 }
                 a.RefreshDuration(AttrType.INVISIBLE,(R.Between(2,20)+30)*100,a.YouAre() + " no longer invisible. ",a);
             }
             else{
                 B.Add("Nothing happens. ",user);
                 results.IDed = false;
             }
         });
         used = wand_result.used;
         IDed = wand_result.IDed;
         break;
     }
     case ConsumableType.REACH:
     {
         ItemUseResult wand_result = UseWand(true,false,user,line,(LOE_tile,targeting,results)=>{
             Actor a = targeting.targeted.actor();
             if(a != null && a != user){
                 user.Attack(0,a,true);
             }
             else{
                 B.Add("Nothing happens. ",user);
                 results.IDed = false;
             }
         });
         used = wand_result.used;
         IDed = wand_result.IDed;
         break;
     }
     case ConsumableType.SLUMBER:
     {
         ItemUseResult wand_result = UseWand(true,false,user,line,(LOE_tile,targeting,results)=>{
             Actor a = targeting.targeted.actor();
             if(a != null){
                 if(a.HasAttr(AttrType.MENTAL_IMMUNITY)){
                     if(a.HasAttr(AttrType.NONLIVING,AttrType.PLANTLIKE)){
                         B.Add(a.You("resist") + " becoming dormant. ",a);
                     }
                     else{
                         B.Add(a.You("resist") + " falling asleep. ",a);
                     }
                 }
                 else{
                     if(a.ResistedBySpirit()){
                         if(player.HasLOS(a)){
                             if(a.HasAttr(AttrType.NONLIVING,AttrType.PLANTLIKE)){
                                 B.Add(a.You("resist") + " becoming dormant. ",a);
                             }
                             else{
                                 B.Add(a.You("almost fall") + " asleep. ",a);
                             }
                         }
                     }
                     else{
                         if(player.HasLOS(a)){
                             if(a.HasAttr(AttrType.NONLIVING,AttrType.PLANTLIKE)){
                                 B.Add(a.You("become") + " dormant. ",a);
                             }
                             else{
                                 B.Add(a.You("fall") + " asleep. ",a);
                             }
                         }
                         a.attrs[AttrType.ASLEEP] = 6 + R.Roll(4,6);
                     }
                 }
             }
             else{
                 B.Add("Nothing happens. ",user);
                 results.IDed = false;
             }
         });
         used = wand_result.used;
         IDed = wand_result.IDed;
         break;
     }
     case ConsumableType.TELEKINESIS:
     {
         ItemUseResult wand_result = UseWand(true,false,user,line,(LOE_tile,targeting,results)=>{
             if(!SharedEffect.Telekinesis(false,user,targeting.targeted)){
                 results.used = false;
             }
         });
         used = wand_result.used;
         IDed = wand_result.IDed;
         break;
     }
     case ConsumableType.WEBS:
     {
         ItemUseResult wand_result = UseWand(true,true,user,line,(LOE_tile,targeting,results)=>{
             if(targeting.targeted == user.tile()){
                 B.Add("Nothing happens. ",user);
                 results.IDed = false;
             }
             else{
                 Screen.CursorVisible = false;
                 foreach(Tile t in targeting.line_to_targeted){
                     if(t.passable && t != user.tile()){
                         t.AddFeature(FeatureType.WEB);
                         if(t.seen){
                             Screen.WriteMapChar(t.row,t.col,';',Color.White);
                             Game.GLUpdate();
                             Thread.Sleep(15);
                         }
                     }
                 }
                 M.Draw();
             }
         });
         used = wand_result.used;
         IDed = wand_result.IDed;
         break;
     }
     case ConsumableType.BLAST_FUNGUS:
     {
         if(line == null){
             line = user.GetTargetTile(12,0,false,true);
         }
         if(line != null){
             revealed_by_light = true;
             ignored = true;
             Tile t = line.LastBeforeSolidTile();
             Actor first = user.FirstActorInLine(line);
             B.Add(user.You("fling") + " " + TheName() + ". ");
             if(first != null && first != user){
                 t = first.tile();
                 B.Add("It hits " + first.the_name + ". ",first);
             }
             line = line.ToFirstSolidTileOrActor();
             if(line.Count > 0){
                 line.RemoveAt(line.Count - 1);
             }
             int idx = 0;
             foreach(Tile tile2 in line){
                 if(tile2.seen){
                     ++idx;
                 }
                 else{
                     line = line.To(tile2);
                     if(line.Count > 0){
                         line.RemoveAt(line.Count - 1);
                     }
                     break;
                 }
             }
             if(line.Count > 0){
                 user.AnimateProjectile(line,symbol,color);
             }
             t.GetItem(this);
             //inv.Remove(i);
             t.MakeNoise(2);
             if(first != null && first != user){
                 first.player_visibility_duration = -1;
                 first.attrs[AttrType.PLAYER_NOTICED]++;
             }
             else{
                 if(t.IsTrap()){
                     t.TriggerTrap();
                 }
             }
         }
         else{
             used = false;
         }
         break;
     }
     case ConsumableType.BANDAGES:
         if(!user.HasAttr(AttrType.BANDAGED)){
             user.attrs[AttrType.BANDAGED] = 20;
             //user.recover_time = Q.turn + 100;
             B.Add(user.You("apply",false,true) + " a bandage. ",user);
         }
         else{
             B.Add(user.the_name + " can't apply another bandage yet. ",user);
             used = false;
         }
         break;
     case ConsumableType.FLINT_AND_STEEL:
     {
         int dir = -1;
         if(user == player){
             dir = user.GetDirection("Which direction? ",false,true);
         }
         else{
             dir = user.DirectionOf(player);
         }
         if(dir != -1){
             Tile t = user.TileInDirection(dir);
             B.Add(user.You("use") + " your flint & steel. ",user);
             if(t.actor() != null && t.actor().HasAttr(AttrType.OIL_COVERED) && !t.Is(FeatureType.POISON_GAS,FeatureType.THICK_DUST)){
                 t.actor().ApplyBurning();
             }
             if(!t.Is(TileType.WAX_WALL)){
                 t.ApplyEffect(DamageType.FIRE);
             }
         }
         else{
             used = false;
         }
         break;
     }
     default:
         used = false;
         break;
     }
     if(used){
         if(IDed){
             bool seen = true; //i'll try letting orbs always be IDed. keep an eye on this.
             /*bool seen = (user == player);
             if(user != player){
                 if(player.CanSee(line[0])){ //fix this line - or at least check for null/empty
                     seen = true;
                 }
                 if(user != null && player.CanSee(user)){ //heck, I could even check to see whose turn it is, if I really wanted to be hacky.
                     seen = true;
                 }
             }*/
             if(!identified[type] && seen){
                 identified[type] = true;
                 B.Add("(It was " + SingularName(true) + "!) ");
             }
         }
         else{
             if(!unIDed_name[type].Contains("{tried}")){
                 unIDed_name[type] = unIDed_name[type] + " {tried}";
             }
         }
         if(quantity > 1){
             --quantity;
         }
         else{
             if(type == ConsumableType.BANDAGES){
                 --other_data;
                 if(user != null && other_data == 0){
                     B.Add(user.You("use") + " your last bandage. ",user);
                     user.inv.Remove(this);
                 }
             }
             else{
                 if(type == ConsumableType.FLINT_AND_STEEL){
                     if(R.OneIn(3)){
                         --other_data;
                         if(user != null){
                             if(other_data == 2){
                                 B.Add("Your flint & steel shows signs of wear. ",user);
                             }
                             if(other_data == 1){
                                 B.Add("Your flint & steel is almost depleted. ",user);
                             }
                             if(other_data == 0){
                                 B.Add("Your flint & steel is used up. ",user);
                                 user.inv.Remove(this);
                             }
                         }
                     }
                 }
                 else{
                     if(NameOfItemType() == "wand"){
                         if(charges > 0){
                             --charges;
                             if(other_data >= 0){
                                 ++other_data;
                             }
                         }
                         else{
                             other_data = -1;
                         }
                     }
                     else{
                         if(user != null){
                             user.inv.Remove(this);
                         }
                     }
                 }
             }
         }
         CheckForMimic();
     }
     return used;
 }
Example #16
0
        private static void GenerateComments(List<int> articles, List<string> users)
        {
            Parallel.ForEach(articles,new ParallelOptions{ MaxDegreeOfParallelism = 30} , articleId =>
            {
                var commentsList = new List<Comment>();
                var random = new Random();
                var viewCount = random.Next(5, 60);
                Console.WriteLine("Proccessing Comments ArticleId: {0}, Comments Count: {1}", articleId, viewCount);
                for (int i = 0; i < viewCount; i++)
                {
                    var comment = new Comment
                    {
                        ArticleId = articleId,
                        Stamp = Guid.NewGuid(),
                        CreatedDate =
                            DateTime.UtcNow.AddDays(0 - random.Next(5, 100))
                                .AddHours(0 - random.Next(0, 24))
                                .AddMinutes(0 - random.Next(0, 60)),
                        AuthorId = users.Random(),
                        Body = SeedExtensions.Headers.Random() + " " + SeedExtensions.Headers.Random()
                    };
                    commentsList.Add(comment);
                }

                try
                {
                    using (var context = new ApplicationDbContext())
                    {
                        var commentEnity = (DbSet<Comment>) context.Comments;
                        commentEnity.AddRange(commentsList);
                        context.SaveChanges();
                    }
                }
                catch (Exception exception)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("ERROR Proccessing Comments ArticleId: {0}", articleId);
                    Console.WriteLine(exception.Message);
                    if (exception.InnerException != null)
                    {
                        Console.WriteLine(exception.InnerException.Message);
                    }
                    Console.ResetColor();
                }
            });
        }
Example #17
0
 private void GetNextArea(int idx, int step, Block block)
 {
     var possibleAreas = new List<long>();
     FillPossibleAreas(idx, step, block, possibleAreas);
     Area = possibleAreas.Random();
 }
Example #18
0
        public void Execute()
        {
            if(!dead){
                switch(type){
                case EventType.MOVE:
                {
                    Actor temp = target as Actor;
                    temp.Act();
                    break;
                }
                case EventType.REMOVE_ATTR:
                {
                    Actor temp = target as Actor;
                    if(attr == AttrType.FLYING){
                        temp.attrs[AttrType.DESCENDING] = 2;
                        if(temp == player){
                            B.Add("You start to descend as your flight wears off. ");
                            B.Print(true);
                        }
                        break;
                    }
                    if(attr == AttrType.SHINING){
                        int old_rad = temp.LightRadius();
                        temp.attrs[attr] -= value;
                        if(old_rad != temp.LightRadius() && !temp.HasAttr(AttrType.BURROWING)){
                            temp.UpdateRadius(old_rad,temp.LightRadius());
                        }
                        break;
                    }
                    if(temp.type == ActorType.BERSERKER && attr == AttrType.COOLDOWN_2){
                        temp.attrs[attr] = 0; //this hack can probably be removed
                    }
                    else{
                        temp.attrs[attr] -= value;
                    }
                    if(attr == AttrType.BURNING && temp.LightRadius() == 0 && !temp.HasAttr(AttrType.BURROWING)){
                        temp.UpdateRadius(1,0);
                    }
                    if(attr == AttrType.TELEPORTING){
                        temp.attrs[attr] = 0;
                    }
                    if(attr == AttrType.CONVICTION){
                        if(temp.HasAttr(AttrType.IN_COMBAT)){
                            temp.attrs[AttrType.CONVICTION] += value; //whoops, undo that
                        }
                        else{
                            temp.attrs[AttrType.BONUS_SPIRIT] -= value;      //otherwise, set things to normal
                            temp.attrs[AttrType.BONUS_COMBAT] -= (value+1) / 2;
                            if(temp.attrs[AttrType.KILLSTREAK] >= 2){
                                B.Add("You wipe off your weapon. ");
                            }
                            temp.attrs[AttrType.KILLSTREAK] = 0;
                        }
                    }
                    if(attr == AttrType.COOLDOWN_1 && temp.type == ActorType.BERSERKER){
                        B.Add(temp.Your() + " rage diminishes. ",temp);
                        B.Add(temp.the_name + " dies. ",temp);
                        temp.Kill();
                    }
                    break;
                }
                case EventType.REMOVE_GAS:
                {
                    List<Tile> removed = new List<Tile>();
                    foreach(Tile t in area){
                        if(t.Is(feature)){
                            if(R.PercentChance(value)){
                                t.RemoveFeature(feature);
                                removed.Add(t);
                            }
                        }
                        else{
                            removed.Add(t);
                        }
                    }
                    foreach(Tile t in removed){
                        area.Remove(t);
                    }
                    if(area.Count > 0){
                        Event.RemoveGas(area,100,feature,value);
                    }
                    break;
                }
                case EventType.CHECK_FOR_HIDDEN:
                {
                    List<Tile> removed = new List<Tile>();
                    foreach(Tile t in area){
                        if(player.CanSee(t)){
                            int exponent = player.DistanceFrom(t) + 1;
                            if(player.magic_trinkets.Contains(MagicTrinketType.RING_OF_KEEN_SIGHT)){
                                --exponent;
                            }
                            if(!t.IsLit()){
                                if(!player.HasAttr(AttrType.SHADOWSIGHT)){
                                    ++exponent;
                                }
                            }
                            if(exponent > 8){
                                exponent = 8; //because 1 in 256 is enough.
                            }
                            int difficulty = 1;
                            for(int i=exponent;i>0;--i){
                                difficulty = difficulty * 2;
                            }
                            if(R.Roll(difficulty) == difficulty){
                                if(t.IsTrap() || t.Is(TileType.FIRE_GEYSER) || t.Is(TileType.FOG_VENT) || t.Is(TileType.POISON_GAS_VENT)){
                                    t.name = Tile.Prototype(t.type).name;
                                    t.a_name = Tile.Prototype(t.type).a_name;
                                    t.the_name = Tile.Prototype(t.type).the_name;
                                    t.symbol = Tile.Prototype(t.type).symbol;
                                    t.color = Tile.Prototype(t.type).color;
                                    B.Add("You notice " + t.AName(true) + ". ");
                                }
                                else{
                                    if(t.type == TileType.HIDDEN_DOOR){
                                        t.Toggle(null);
                                        B.Add("You notice a hidden door. ");
                                    }
                                }
                                removed.Add(t);
                            }
                        }
                    }
                    foreach(Tile t in removed){
                        area.Remove(t);
                    }
                    if(area.Count > 0){
                        Q.Add(new Event(area,100,EventType.CHECK_FOR_HIDDEN));
                    }
                    break;
                }
                case EventType.RELATIVELY_SAFE:
                {
                    if(M.AllActors().Count == 1 && !Q.Contains(EventType.POLTERGEIST)
                    && !Q.Contains(EventType.REGENERATING_FROM_DEATH) && !Q.Contains(EventType.MIMIC) && !Q.Contains(EventType.MARBLE_HORROR)){
                        //B.Add("The dungeon is still and silent. ");
                        B.Add("The dungeon is utterly silent for a moment. ");
                        B.PrintAll();
                    }
                    else{
                        Q.Add(new Event((R.Roll(20)+30)*100,EventType.RELATIVELY_SAFE));
                    }
                    break;
                }
                case EventType.POLTERGEIST:
                {
                    if(target != null && target is Actor){ //target can either be a stolen item, or the currently manifested poltergeist.
                        Q.Add(new Event(target,area,(R.Roll(8)+6)*100,EventType.POLTERGEIST,AttrType.NO_ATTR,0,""));
                        break; //if it's manifested, the event does nothing for now.
                    }
                    if(area.Any(t => t.actor() == player)){
                        bool manifested = false;
                        if(value == 0){
                            B.Add("You feel like you're being watched. ");
                        }
                        else{
                            if(target != null){ //if it has a stolen item
                                Tile tile = null;
                                tile = area.Where(t => t.actor() == null && t.DistanceFrom(player) >= 2
                                    && t.HasLOE(player) && t.FirstActorInLine(player) == player).RandomOrDefault();
                                if(tile != null){
                                    Actor temporary = new Actor(ActorType.POLTERGEIST,"something",'G',Color.DarkGreen,1,1,0,0);
                                    temporary.a_name = "something";
                                    temporary.the_name = "something";
                                    temporary.p = tile.p;
                                    temporary.inv = new List<Item>();
                                    temporary.inv.Add(target as Item);
                                    Item item = temporary.inv[0];
                                    if(item.NameOfItemType() == "orb"){
                                        temporary.inv[0].Use(temporary,temporary.GetBestExtendedLineOfEffect(player));
                                    }
                                    else{
                                        B.Add("Something throws " + item.AName() + ". ",temporary);
                                        B.DisplayNow();
                                        Screen.AnimateProjectile(tile.GetBestExtendedLineOfEffect(player).ToFirstSolidTileOrActor(),new colorchar(item.color,item.symbol));
                                        player.tile().GetItem(item);
                                        B.Add(item.TheName() + " hits you. ");
                                        player.TakeDamage(DamageType.NORMAL,DamageClass.PHYSICAL,R.Roll(6),temporary,"a flying " + item.Name());
                                    }
                                    target = null;
                                }
                                else{
                                    Q.Add(new Event(target,area,100,EventType.POLTERGEIST,AttrType.NO_ATTR,value,""));
                                    return; //try again next turn
                                }
                            }
                            else{
                                if(value >= 2 && area.Any(t => t.DistanceFrom(player) == 1 && t.passable && t.actor() == null)){
                                    Tile tile = area.Where(t => t.DistanceFrom(player) == 1 && t.passable && t.actor() == null).Random();
                                    B.DisplayNow();
                                    for(int i=4;i>0;--i){
                                        Screen.AnimateStorm(tile.p,i,2,1,'G',Color.DarkGreen);
                                    }
                                    Actor a = Actor.Create(ActorType.POLTERGEIST,tile.row,tile.col,TiebreakerAssignment.UseCurrent);
                                    Q.KillEvents(a,EventType.MOVE);
                                    a.Q0();
                                    a.player_visibility_duration = -1;
                                    B.Add("A poltergeist manifests in front of you! ");
                                    Q.Add(new Event(a,area,(R.Roll(8)+6)*100,EventType.POLTERGEIST,AttrType.NO_ATTR,0,""));
                                    manifested = true;
                                }
                                else{
                                    if(player.tile().type == TileType.DOOR_O){
                                        B.Add("The door slams closed on you! ");
                                        player.TakeDamage(DamageType.NORMAL,DamageClass.PHYSICAL,R.Roll(6),null,"a slamming door");
                                    }
                                    else{
                                        Tile tile = null; //check for items to throw...
                                        tile = area.Where(t => t.inv != null && t.actor() == null && t.DistanceFrom(player) >= 2
                                            && t.HasLOE(player) && t.FirstActorInLine(player) == player).RandomOrDefault();
                                        if(tile != null){
                                            Actor temporary = new Actor(ActorType.POLTERGEIST,"something",'G',Color.DarkGreen,1,1,0,0);
                                            temporary.a_name = "something";
                                            temporary.the_name = "something";
                                            temporary.p = tile.p;
                                            temporary.inv = new List<Item>();
                                            if(tile.inv.quantity <= 1){
                                                temporary.inv.Add(tile.inv);
                                                tile.inv = null;
                                            }
                                            else{
                                                temporary.inv.Add(new Item(tile.inv,-1,-1));
                                                tile.inv.quantity--;
                                            }
                                            M.Draw();
                                            Item item = temporary.inv[0];
                                            if(item.NameOfItemType() == "orb"){
                                                temporary.inv[0].Use(temporary,temporary.GetBestExtendedLineOfEffect(player));
                                            }
                                            else{
                                                B.Add("Something throws " + item.TheName() + ". ",temporary);
                                                B.DisplayNow();
                                                Screen.AnimateProjectile(tile.GetBestExtendedLineOfEffect(player).ToFirstSolidTileOrActor(),new colorchar(item.color,item.symbol));
                                                player.tile().GetItem(item);
                                                B.Add(item.TheName() + " hits you. ");
                                                player.TakeDamage(DamageType.NORMAL,DamageClass.PHYSICAL,R.Roll(6),temporary,"a flying " + item.Name());
                                            }
                                        }
                                        else{
                                            if(area.Any(t => t.type == TileType.DOOR_O || t.type == TileType.DOOR_C)){
                                                Tile door = area.Where(t=>t.type == TileType.DOOR_O || t.type == TileType.DOOR_C).Random();
                                                if(door.type == TileType.DOOR_C){
                                                    if(player.CanSee(door)){
                                                        B.Add("The door flies open! ",door);
                                                    }
                                                    else{
                                                        if(door.seen || player.DistanceFrom(door) <= 12){
                                                            B.Add("You hear a door slamming. ");
                                                        }
                                                    }
                                                    door.Toggle(null);
                                                }
                                                else{
                                                    if(door.actor() == null){
                                                        if(player.CanSee(door)){
                                                            B.Add("The door slams closed! ",door);
                                                        }
                                                        else{
                                                            if(door.seen || player.DistanceFrom(door) <= 12){
                                                                B.Add("You hear a door slamming. ");
                                                            }
                                                        }
                                                        door.Toggle(null);
                                                    }
                                                    else{
                                                        if(player.CanSee(door)){
                                                            B.Add("The door slams closed on " + door.actor().TheName(true) + "! ",door);
                                                        }
                                                        else{
                                                            if(player.DistanceFrom(door) <= 12){
                                                                B.Add("You hear a door slamming and a grunt of pain. ");
                                                            }
                                                        }
                                                        door.actor().TakeDamage(DamageType.NORMAL,DamageClass.PHYSICAL,R.Roll(6),null,"a slamming door");
                                                    }
                                                }
                                            }
                                            else{
                                                B.Add("You hear mocking laughter from nearby. ");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        if(!manifested){
                            Q.Add(new Event(target,area,(R.Roll(8)+6)*100,EventType.POLTERGEIST,AttrType.NO_ATTR,value+1,""));
                        }
                    }
                    else{
                        Q.Add(new Event(target,area,(R.Roll(8)+6)*100,EventType.POLTERGEIST,AttrType.NO_ATTR,0,""));
                    }
                    break;
                }
                case EventType.MIMIC:
                {
                    Item item = target as Item;
                    if(area[0].inv != item){ //it could have been picked up by the player or moved in another way
                        foreach(Tile t in M.AllTiles()){ //if it was moved, make the correction to the event's area.
                            if(t.inv == item){
                                area = new List<Tile>{t};
                                break;
                            }
                        }
                    }
                    if(area[0].inv == item){
                        bool attacked = false;
                        if(player.DistanceFrom(area[0]) == 1 && area[0].actor() == null){
                            if(player.TotalSkill(SkillType.STEALTH) * 5 < R.Roll(1,100)){
                                B.Add(item.TheName(true) + " suddenly grows tentacles! ");
                                attacked = true;
                                area[0].inv = null;
                                Actor a = Actor.Create(ActorType.MIMIC,area[0].row,area[0].col,TiebreakerAssignment.UseCurrent);
                                Q.KillEvents(a,EventType.MOVE);
                                a.Q0();
                                a.player_visibility_duration = -1;
                                a.symbol = item.symbol;
                                a.color = item.color;
                            }
                        }
                        if(!attacked){
                            Q.Add(new Event(target,area,100,EventType.MIMIC,AttrType.NO_ATTR,0,""));
                        }
                    }
                    else{ //if the item is missing, we assume that the player just picked it up
                        List<Tile> open = new List<Tile>();
                        foreach(Tile t in player.TilesAtDistance(1)){
                            if(t.passable && t.actor() == null){
                                open.Add(t);
                            }
                        }
                        if(open.Count > 0){
                            Tile t = open.Random();
                            B.Add(item.TheName() + " suddenly grows tentacles! ");
                            Actor a = Actor.Create(ActorType.MIMIC,t.row,t.col,TiebreakerAssignment.UseCurrent);
                            Q.KillEvents(a,EventType.MOVE);
                            a.Q0();
                            a.player_visibility_duration = -1;
                            a.symbol = item.symbol;
                            a.color = item.color;
                            player.inv.Remove(item);
                        }
                        else{
                            B.Add("Your pack feels lighter. ");
                            player.inv.Remove(item);
                        }
                    }
                    break;
                }
                case EventType.GRENADE:
                {
                    Tile t = target as Tile;
                    if(t.Is(FeatureType.GRENADE)){
                        t.features.Remove(FeatureType.GRENADE);
                        B.Add("The grenade explodes! ",t);
                        if(t.seen){
                            Screen.WriteMapChar(t.row,t.col,M.VisibleColorChar(t.row,t.col));
                        }
                        B.DisplayNow();
                        t.ApplyExplosion(1,"an exploding grenade");
                        /*List<pos> cells = new List<pos>();
                        foreach(Tile tile in t.TilesWithinDistance(1)){
                            if(tile.passable && tile.seen){ //animation LOS check here
                                cells.Add(tile.p);
                            }
                        }
                        Screen.AnimateMapCells(cells,new colorchar('*',Color.RandomExplosion));
                        Actor a = t.actor();
                        if(a != null){
                            a.attrs[AttrType.TURN_INTO_CORPSE] = 1;
                        }
                        foreach(Actor a2 in t.ActorsWithinDistance(1)){
                            a2.TakeDamage(DamageType.NORMAL,DamageClass.PHYSICAL,R.Roll(3,6),null,"an exploding grenade");
                        }
                        if(a != null){
                            int dir = Global.RandomDirection();
                            if(a.curhp > 0 || !a.HasAttr(AttrType.NO_CORPSE_KNOCKBACK)){
                                t.TileInDirection(dir).KnockObjectBack(a,1);
                            }
                            a.CorpseCleanup();
                        }
                        t.MakeNoise(8);*/
                    }
                    break;
                }
                case EventType.BLAST_FUNGUS:
                {
                    Item i = target as Item;
                    i.other_data--;
                    if(i.other_data == 0){
                        Tile t = null;
                        if(M.tile.BoundsCheck(i.row,i.col) && M.tile[i.p].inv == i){
                            t = M.tile[i.p];
                            t.inv = null;
                        }
                        else{
                            foreach(Actor a in M.AllActors()){
                                if(a.inv.Contains(i)){
                                    a.inv.Remove(i);
                                    t = a.tile();
                                    break;
                                }
                            }
                        }
                        if(t != null){
                            B.Add("The blast fungus explodes! ",t);
                            if(t.seen){
                                Screen.WriteMapChar(t.row,t.col,M.VisibleColorChar(t.row,t.col));
                            }
                            B.DisplayNow();
                            t.ApplyExplosion(3,"an exploding blast fungus");
                        }
                    }
                    else{
                        Tile t = null;
                        if(M.tile.BoundsCheck(i.row,i.col) && M.tile[i.p].inv == i){
                            t = M.tile[i.p];
                        }
                        else{
                            foreach(Actor a in M.AllActors()){
                                if(a.inv.Contains(i)){
                                    t = a.tile();
                                    break;
                                }
                            }
                        }
                        if(t != null && t.seen){
                            Screen.AnimateMapCell(t.row,t.col,new colorchar(i.other_data.ToString()[0],Color.Red),100);
                        }
                        Q.Add(new Event(i,100,EventType.BLAST_FUNGUS));
                    }
                    break;
                }
                case EventType.STALAGMITE:
                {
                    if(value > 1){
                        int stalagmites = 0; //number removed
                        int number_left = 0;
                        List<Tile> crumbled = new List<Tile>();
                        foreach(Tile tile in area){
                            if(tile.type == TileType.STALAGMITE){
                                if(R.OneIn(value)){
                                    crumbled.Add(tile);
                                    tile.Toggle(null);
                                    ++stalagmites;
                                }
                                else{
                                    ++number_left;
                                }
                            }
                        }
                        if(stalagmites > 0){
                            if(stalagmites > 1){
                                B.Add("The stalagmites crumble. ",crumbled.ToArray());
                            }
                            else{
                                B.Add("The stalagmite crumbles. ",crumbled.ToArray());
                            }
                        }
                        if(number_left > 0){
                            Q.Add(new Event(area,100,EventType.STALAGMITE,value));
                        }
                    }
                    else{
                        int stalagmites = 0;
                        foreach(Tile tile in area){
                            if(tile.type == TileType.STALAGMITE){
                                stalagmites++;
                            }
                        }
                        if(stalagmites > 0){
                            if(stalagmites > 1){
                                B.Add("The stalagmites crumble. ",area.ToArray());
                            }
                            else{
                                B.Add("The stalagmite crumbles. ",area.ToArray());
                            }
                            foreach(Tile tile in area){
                                if(tile.type == TileType.STALAGMITE){
                                    tile.Toggle(null);
                                }
                            }
                        }
                    }
                    break;
                }
                case EventType.FIRE_GEYSER:
                {
                    int frequency = value / 10; //9-39
                    int variance = value % 10; //0-9
                    int variance_amount = (frequency * variance) / 10;
                    int number_of_values = variance_amount*2 + 1;
                    int minimum_value = frequency - variance_amount;
                    if(minimum_value < 5){
                        int diff = 5 - minimum_value;
                        number_of_values -= diff;
                        minimum_value = 5;
                    }
                    int delay = ((minimum_value - 1) + R.Roll(number_of_values)) * 100;
                    Q.Add(new Event(target,delay+200,EventType.FIRE_GEYSER,value));
                    Q.Add(new Event(target,delay,EventType.FIRE_GEYSER_ERUPTION,2));
                    break;
                }
                case EventType.FIRE_GEYSER_ERUPTION:
                {
                    foreach(Tile t in target.TilesWithinDistance(2)){
                        t.RemoveFeature(FeatureType.FOG);
                    }
                    //int old_radius = target.light_radius;
                    //target.UpdateRadius(old_radius,2,true);
                    B.Add(target.the_name + " spouts flames! ",target);
                    if(target.actor() != null){
                        target.actor().ApplyBurning();
                    }
                    for(int i=0;i<4;++i){
                        Tile t = target.TilesWithinDistance(2).Where(x=>target.HasLOE(x)).RandomOrDefault();
                        if(t != null){
                            if(t.passable){
                                t.AddFeature(FeatureType.FIRE);
                            }
                            else{
                                t.ApplyEffect(DamageType.FIRE);
                            }
                        }
                    }
                    //target.UpdateRadius(2,old_radius,true);
                    if(value > 0){
                        Q.Add(new Event(target,100,EventType.FIRE_GEYSER_ERUPTION,value - 1));
                    }
                    break;
                }
                case EventType.FOG_VENT:
                {
                    Tile current = target as Tile;
                    if(!current.Is(FeatureType.FOG)){
                        current.AddFeature(FeatureType.FOG);
                        List<Tile> new_area = new List<Tile>{current};
                        Q.RemoveTilesFromEventAreas(new_area,EventType.REMOVE_GAS);
                        Event.RemoveGas(new_area,600,FeatureType.FOG,25);
                        //Q.Add(new Event(new_area,600,EventType.FOG,25));
                    }
                    else{
                        for(int tries=0;tries<50;++tries){
                            List<Tile> open = new List<Tile>();
                            foreach(Tile t in current.TilesAtDistance(1)){ //perhaps the rework could involve refreshing the duration of nearby tiles - if enough are refreshed, then no new tiles need to be added
                                if(t.passable){
                                    open.Add(t);
                                    if(!t.Is(FeatureType.FOG)){
                                        open.Add(t); //3x as likely if it can expand there
                                        open.Add(t);
                                    }
                                }
                            }
                            if(open.Count > 0){
                                Tile possible = open.Random();
                                if(!possible.Is(FeatureType.FOG)){
                                    possible.AddFeature(FeatureType.FOG);
                                    List<Tile> new_area = new List<Tile>{possible};
                                    Q.RemoveTilesFromEventAreas(new_area,EventType.REMOVE_GAS);
                                    Event.RemoveGas(new_area,600,FeatureType.FOG,25);
                                    break;
                                }
                                else{
                                    current = possible;
                                }
                            }
                            else{
                                break;
                            }
                        }
                    }
                    Q.Add(new Event(target,100,EventType.FOG_VENT));
                    break;
                }
                case EventType.POISON_GAS_VENT:
                {
                    Tile current = target as Tile;
                    if(R.OneIn(7)){
                        int num = R.Roll(5) + 2;
                        List<Tile> new_area = new List<Tile>();
                        for(int i=0;i<num;++i){
                            if(!current.Is(FeatureType.POISON_GAS)){
                                current.AddFeature(FeatureType.POISON_GAS);
                                new_area.Add(current);
                            }
                            else{
                                for(int tries=0;tries<50;++tries){
                                    List<Tile> open = new List<Tile>();
                                    foreach(Tile t in current.TilesAtDistance(1)){
                                        if(t.passable){
                                            open.Add(t);
                                        }
                                    }
                                    if(open.Count > 0){
                                        Tile possible = open.Random();
                                        if(!possible.Is(FeatureType.POISON_GAS)){
                                            possible.AddFeature(FeatureType.POISON_GAS);
                                            new_area.Add(possible);
                                            break;
                                        }
                                        else{
                                            current = possible;
                                        }
                                    }
                                    else{
                                        break;
                                    }
                                }
                            }
                        }
                        if(new_area.Count > 0){
                            B.Add("Toxic vapors pour from " + target.the_name + "! ",target);
                            Event.RemoveGas(new_area,200,FeatureType.POISON_GAS,18);
                        }
                    }
                    Q.Add(new Event(target,100,EventType.POISON_GAS_VENT));
                    break;
                }
                case EventType.STONE_SLAB:
                {
                    Tile t = target as Tile;
                    if(t.type == TileType.STONE_SLAB && (t.IsLitFromAnywhere(true) || area.Any(x=>x.actor()!=null))){
                        bool vis = player.CanSee(t);
                        t.Toggle(null);
                        //t.Toggle(null,TileType.FLOOR);
                        //t.symbol = '-';
                        //t.revealed_by_light = true;
                        if(!vis && player.CanSee(t)){
                            vis = true;
                        }
                        if(vis){
                            B.Add("The stone slab rises with a grinding sound. ");
                        }
                        else{
                            if(player.DistanceFrom(t) <= 6){
                                B.Add("You hear a grinding sound. ");
                            }
                        }
                    }
                    else{
                        if(t.type == TileType.STONE_SLAB_OPEN && !t.IsLitFromAnywhere(true) && t.actor() == null && !area.Any(x=>x.actor()!=null)){
                            bool vis = player.CanSee(t);
                            //t.Toggle(null,TileType.STONE_SLAB);
                            t.Toggle(null);
                            if(!vis && player.CanSee(t)){
                                vis = true;
                            }
                            if(vis){
                                B.Add("The stone slab descends with a grinding sound. ");
                            }
                            else{
                                if(player.DistanceFrom(t) <= 6){
                                    B.Add("You hear a grinding sound. ");
                                }
                            }
                        }
                    }
                    Q.Add(new Event(target,area,100,EventType.STONE_SLAB));
                    break;
                }
                case EventType.MARBLE_HORROR:
                {
                    Tile t = target as Tile;
                    if(t.type == TileType.STATUE){
                        if(value == 1 && player.CanSee(t) && !t.IsLit() && t.actor() == null){ //if target was visible last turn & this turn, and it's currently in darkness...
                            t.TransformTo(TileType.FLOOR);
                            Actor a = Actor.Create(ActorType.MARBLE_HORROR,t.row,t.col,TiebreakerAssignment.AtEnd); //todo: not sure - should this get a placeholder like poltergeist and mimic?
                            foreach(Event e in Q.list){
                                if(e.target == a && e.type == EventType.MOVE){
                                    e.dead = true;
                                    break;
                                }
                            }
                            a.Q0();
                            switch(R.Roll(2)){
                            case 1:
                                B.Add("You think that statue might have just moved... ");
                                B.Print(true);
                                break;
                            case 2:
                                B.Add("The statue turns its head to face you. ");
                                B.Print(true);
                                break;
                            }
                        }
                        else{
                            if(player.CanSee(t)){
                                Q.Add(new Event(target,100,EventType.MARBLE_HORROR,1));
                            }
                            else{
                                Q.Add(new Event(target,100,EventType.MARBLE_HORROR,0));
                            }
                        }
                    }
                    break;
                }
                case EventType.REGENERATING_FROM_DEATH:
                {
                    int health = value;
                    int permanent_damage = secondary_value;
                    if(target.tile().Is(FeatureType.TROLL_CORPSE)){ //otherwise, assume it was destroyed by fire
                        int maxhp = Actor.Prototype(ActorType.TROLL).maxhp;
                        int recovered = Actor.Prototype(ActorType.TROLL).attrs[AttrType.REGENERATING];
                        if(health + recovered > maxhp - permanent_damage){
                            recovered = (maxhp - permanent_damage) - health;
                        }
                        health += recovered;
                        if(permanent_damage >= maxhp){
                            break;
                        }
                        if(health > 0 && target.actor() == null){
                            Actor a = Actor.Create(ActorType.TROLL,target.row,target.col,TiebreakerAssignment.UseCurrent);
                            a.curhp = health;
                            a.attrs[AttrType.PERMANENT_DAMAGE] = permanent_damage;
                            a.attrs[AttrType.NO_ITEM]++;
                            a.attrs[AttrType.DANGER_SENSED]++;
                            B.Add("The troll stands up! ",target);
                            a.player_visibility_duration = -1;
                            if(target.tile().type == TileType.DOOR_C){
                                target.tile().Toggle(a);
                            }
                            target.tile().features.Remove(FeatureType.TROLL_CORPSE);
                            a.attrs[AttrType.WANDERING]++;
                        }
                        else{
                            int roll = R.Roll(20);
                            if(health == -1){
                                roll = 1;
                            }
                            if(health == 0){
                                roll = 3;
                            }
                            switch(roll){
                            case 1:
                            case 2:
                                B.Add("The troll's corpse twitches. ",target);
                                break;
                            case 3:
                            case 4:
                                B.Add("You hear sounds coming from the troll's corpse. ",target);
                                break;
                            case 5:
                                B.Add("The troll on the floor regenerates. ",target);
                                break;
                            default:
                                break;
                            }
                            Event e = new Event(target,100,EventType.REGENERATING_FROM_DEATH);
                            e.value = health;
                            e.secondary_value = permanent_damage;
                            Q.Add(e);
                        }
                    }
                    if(target.tile().Is(FeatureType.TROLL_BLOODWITCH_CORPSE)){ //otherwise, assume it was destroyed by fire
                        int maxhp = Actor.Prototype(ActorType.TROLL_BLOODWITCH).maxhp;
                        int recovered = Actor.Prototype(ActorType.TROLL_BLOODWITCH).attrs[AttrType.REGENERATING];
                        if(health + recovered > maxhp - permanent_damage){
                            recovered = (maxhp - permanent_damage) - health;
                        }
                        health += recovered;
                        if(permanent_damage >= maxhp){
                            break;
                        }
                        if(recovered > 0){
                            List<pos> cells = new List<pos>();
                            List<colorchar> cch = new List<colorchar>();
                            foreach(pos p2 in target.PositionsWithinDistance(4)){
                                if(target.HasLOE(M.tile[p2]) && player.CanSee(M.tile[p2])){
                                    cells.Add(p2);
                                    colorchar ch = M.VisibleColorChar(p2.row,p2.col);
                                    ch.color = Color.Red;
                                    cch.Add(ch);
                                }
                            }
                            if(cells.Count > 0){
                                M.Draw();
                                Screen.AnimateMapCells(cells,cch,40);
                            }
                            foreach(Actor a in target.ActorsWithinDistance(4)){
                                if(target.HasLOE(a)){
                                    if(a == player){
                                        B.Add("Ow! ");
                                    }
                                    a.TakeDamage(DamageType.NORMAL,DamageClass.MAGICAL,recovered,null,"trollish blood magic");
                                }
                            }
                        }
                        if(health > 0 && target.actor() == null){
                            Actor a = Actor.Create(ActorType.TROLL_BLOODWITCH,target.row,target.col,TiebreakerAssignment.UseCurrent);
                            a.curhp = health;
                            a.attrs[AttrType.PERMANENT_DAMAGE] = permanent_damage;
                            a.attrs[AttrType.NO_ITEM]++;
                            a.attrs[AttrType.DANGER_SENSED]++;
                            B.Add("The troll bloodwitch rises! ",target);
                            a.player_visibility_duration = -1;
                            if(attr == AttrType.COOLDOWN_1){
                                a.attrs[AttrType.COOLDOWN_1]++;
                            }
                            if(target.tile().type == TileType.DOOR_C){
                                target.tile().Toggle(a);
                            }
                            target.tile().features.Remove(FeatureType.TROLL_BLOODWITCH_CORPSE);
                            a.attrs[AttrType.WANDERING]++;
                        }
                        else{
                            int roll = R.Roll(20);
                            if(health == -1){
                                roll = 1;
                            }
                            if(health == 0){
                                roll = 3;
                            }
                            switch(roll){
                            case 1:
                            case 2:
                                B.Add("The bloodwitch's corpse twitches. ",target);
                                break;
                            case 3:
                            case 4:
                                B.Add("You feel a pulse like a heartbeat coming from the bloodwitch. ",target);
                                break;
                            case 5:
                                B.Add("The troll bloodwitch on the floor regenerates. ",target);
                                break;
                            default:
                                break;
                            }
                            Event e = new Event(target,100,EventType.REGENERATING_FROM_DEATH);
                            e.value = health;
                            e.secondary_value = permanent_damage;
                            Q.Add(e);
                        }
                    }
                    break;
                }
                case EventType.REASSEMBLING:
                {
                    Tile t = target as Tile;
                    if(t.Is(FeatureType.BONES)){
                        if(t.actor() == null){
                            Actor a = Actor.Create(ActorType.SKELETON,target.row,target.col,TiebreakerAssignment.UseCurrent);
                            B.Add("The skeleton reassembles itself. ",target);
                            a.player_visibility_duration = -1;
                            if(target.tile().type == TileType.DOOR_C){
                                target.tile().Toggle(a);
                            }
                            target.tile().features.Remove(FeatureType.BONES);
                            if(R.OneIn(3)){
                                a.attrs[AttrType.WANDERING]++;
                            }
                        }
                        else{
                            Q.Add(new Event(target,100,EventType.REASSEMBLING));
                        }
                    }
                    break;
                }
                case EventType.SHIELDING:
                {
                    List<pos> cells = new List<pos>();
                    List<colorchar> symbols = new List<colorchar>();
                    int animation_delay = 75;
                    foreach(Tile tile in area){
                        colorchar cch = tile.visual;
                        if(tile.actor() != null){
                            if(!tile.actor().HasAttr(AttrType.SHIELDED)){
                                tile.actor().attrs[AttrType.SHIELDED] = 1;
                                B.Add(tile.actor().YouAre() + " shielded. ",tile.actor());
                            }
                            if(player.CanSee(tile.actor())){
                                animation_delay = 150;
                                cch = tile.actor().visual;
                            }
                        }
                        cch.bgcolor = Color.Blue;
                        if(Global.LINUX && !Screen.GLMode){
                            cch.bgcolor = Color.DarkBlue;
                        }
                        if(cch.color == cch.bgcolor){
                            cch.color = Color.Black;
                        }
                        if(cch.c == '.'){
                            cch.c = '+';
                        }
                        symbols.Add(cch);
                        cells.Add(tile.p);
                    }
                    M.Draw();
                    Screen.AnimateMapCells(cells,symbols,animation_delay);
                    --value;
                    if(value > 0){
                        Q.Add(new Event(area,100,EventType.SHIELDING,value));
                    }
                    break;
                }
                case EventType.FINAL_LEVEL_SPAWN_CULTISTS:
                {
                    int num_cultists = M.AllActors().Where(x=>x.Is(ActorType.FINAL_LEVEL_CULTIST)).Count;
                    if(num_cultists < 5){
                        Actor a = M.SpawnMob(ActorType.CULTIST);
                        if(a != null){
                            List<Actor> group = null;
                            if(a.group != null){
                                group = new List<Actor>(a.group);
                                a.group.Clear();
                            }
                            else{
                                group = new List<Actor>{a};
                            }
                            List<int> valid_circles = new List<int>();
                            for(int i=0;i<5;++i){
                                if(M.FinalLevelSummoningCircle(i).PositionsWithinDistance(2,M.tile).Any(x=>M.tile[x].Is(TileType.DEMONIC_IDOL))){
                                    valid_circles.Add(i);
                                }
                            }
                            foreach(Actor a2 in group){
                                int i = valid_circles.RemoveLast();
                                pos circle = M.FinalLevelSummoningCircle(i);
                                a2.FindPath(circle.row,circle.col);
                                a2.attrs[AttrType.COOLDOWN_2] = i;
                                a2.type = ActorType.FINAL_LEVEL_CULTIST;
                                a2.group = null;
                                if(!R.OneIn(20)){
                                    a2.attrs[AttrType.NO_ITEM] = 1;
                                }
                            }
                        }
                    }
                    Q.Add(new Event(R.Between(5,8)*100,EventType.FINAL_LEVEL_SPAWN_CULTISTS));
                    break;
                }
                /*case EventType.BOSS_SIGN:
                {
                    string s = "";
                    switch(R.Roll(8)){
                    case 1:
                        s = "You see scratch marks on the walls and floor. ";
                        break;
                    case 2:
                        s = "There are deep gouges in the floor here. ";
                        break;
                    case 3:
                        s = "The floor here is scorched and blackened. ";
                        break;
                    case 4:
                        s = "You notice bones of an unknown sort on the floor. ";
                        break;
                    case 5:
                        s = "You hear a distant roar. ";
                        break;
                    case 6:
                        s = "You smell smoke. ";
                        break;
                    case 7:
                        s = "You spot a large reddish scale on the floor. ";
                        break;
                    case 8:
                        s = "A small tremor shakes the area. ";
                        break;
                    default:
                        s = "Debug message. ";
                        break;
                    }
                    if(!player.HasAttr(AttrType.RESTING)){
                        B.AddIfEmpty(s);
                    }
                    Q.Add(new Event((R.Roll(20)+35)*100,EventType.BOSS_SIGN));
                    break;
                }
                case EventType.BOSS_ARRIVE:
                {
                    bool spawned = false;
                    Actor a = null;
                    if(M.AllActors().Count == 1 && !Q.Contains(EventType.POLTERGEIST)){
                        List<Tile> trolls = new List<Tile>();
                        for(LinkedListNode<Event> current = Q.list.First;current!=null;current = current.Next){
                            if(current.Value.type == EventType.REGENERATING_FROM_DEATH){
                                trolls.Add((current.Value.target) as Tile);
                            }
                        }
                        foreach(Tile troll in trolls){
                            if(troll.Is(FeatureType.TROLL_CORPSE)){
                                B.Add("The troll corpse burns to ashes! ",troll);
                                troll.features.Remove(FeatureType.TROLL_CORPSE);
                            }
                            else{
                                if(troll.Is(FeatureType.TROLL_BLOODWITCH_CORPSE)){
                                    B.Add("The troll bloodwitch corpse burns to ashes! ",troll);
                                    troll.features.Remove(FeatureType.TROLL_BLOODWITCH_CORPSE);
                                }
                            }
                        }
                        Q.KillEvents(null,EventType.REGENERATING_FROM_DEATH);
                        List<Tile> goodtiles = M.AllTiles();
                        List<Tile> removed = new List<Tile>();
                        foreach(Tile t in goodtiles){
                            if(!t.passable || t.Is(TileType.CHASM) || player.CanSee(t)){
                                removed.Add(t);
                            }
                        }
                        foreach(Tile t in removed){
                            goodtiles.Remove(t);
                        }
                        if(goodtiles.Count > 0){
                            B.Add("You hear a loud crash and a nearby roar! ");
                            Tile t = goodtiles[R.Roll(goodtiles.Count)-1];
                            a = Actor.Create(ActorType.FIRE_DRAKE,t.row,t.col,true,false);
                            spawned = true;
                        }
                        else{
                            if(M.AllTiles().Any(t=>t.passable && !t.Is(TileType.CHASM) && t.actor() == null)){
                                B.Add("You hear a loud crash and a nearby roar! ");
                                Tile tile = M.AllTiles().Where(t=>t.passable && !t.Is(TileType.CHASM) && t.actor() == null).Random();
                                a = Actor.Create(ActorType.FIRE_DRAKE,tile.row,tile.col,true,false);
                                spawned = true;
                            }
                        }
                    }
                    if(!spawned){
                        Q.Add(new Event(null,null,(R.Roll(20)+10)*100,EventType.BOSS_ARRIVE,attr,value,""));
                    }
                    else{
                        if(value > 0){
                            a.curhp = value;
                        }
                        else{ //if there's no good value, this means that this is the first appearance.
                            B.Add("The ground shakes as dust and rocks fall from the cavern ceiling. ");
                            B.Add("This place is falling apart! ");
                            List<Tile> floors = M.AllTiles().Where(t=>t.passable && t.type != TileType.CHASM && player.tile() != t);
                            Tile tile = null;
                            if(floors.Count > 0){
                                tile = floors.Random();
                                (tile as Tile).Toggle(null,TileType.CHASM);
                            }
                            Q.Add(new Event(tile,100,EventType.FLOOR_COLLAPSE));
                            Q.Add(new Event((R.Roll(20)+20)*100,EventType.CEILING_COLLAPSE));

                        }
                    }
                    break;
                }
                case EventType.FLOOR_COLLAPSE:
                {
                    Tile current = target as Tile;
                    int tries = 0;
                    if(current != null){
                        for(tries=0;tries<50;++tries){
                            List<Tile> open = new List<Tile>();
                            foreach(Tile t in current.TilesAtDistance(1)){
                                if(t.passable || t.Is(TileType.RUBBLE)){
                                    open.Add(t);
                                }
                            }
                            if(open.Count > 0){
                                Tile possible = open.Random();
                                if(!possible.Is(TileType.CHASM)){
                                    possible.Toggle(null,TileType.CHASM);
                                    List<Tile> open_neighbors = possible.TilesAtDistance(1).Where(t=>t.passable && t.type != TileType.CHASM);
                                    int num_neighbors = open_neighbors.Count;
                                    while(open_neighbors.Count > num_neighbors/2){
                                        Tile neighbor = open_neighbors.RemoveRandom();
                                        neighbor.Toggle(null,TileType.CHASM);
                                    }
                                    break;
                                }
                                else{
                                    current = possible;
                                }
                            }
                            else{
                                break;
                            }
                        }
                    }
                    if(tries == 50 || current == null){
                        List<Tile> floors = M.AllTiles().Where(t=>t.passable && t.type != TileType.CHASM && player.tile() != t);
                        if(floors.Count > 0){
                            target = floors.Random();
                            (target as Tile).Toggle(null,TileType.CHASM);
                        }
                    }
                    Q.Add(new Event(target,100,EventType.FLOOR_COLLAPSE));
                    break;
                }
                case EventType.CEILING_COLLAPSE:
                {
                    B.Add("The ground shakes and debris falls from the ceiling! ");
                    for(int i=1;i<Global.ROWS-1;++i){
                        for(int j=1;j<Global.COLS-1;++j){
                            Tile t = M.tile[i,j];
                            if(t.Is(TileType.WALL)){
                                int num_walls = t.TilesAtDistance(1).Where(x=>x.Is(TileType.WALL)).Count;
                                if(num_walls < 8 && R.OneIn(20)){
                                    if(R.CoinFlip()){
                                        t.Toggle(null,TileType.FLOOR);
                                        foreach(Tile neighbor in t.TilesAtDistance(1)){
                                            neighbor.solid_rock = false;
                                        }
                                    }
                                    else{
                                        t.Toggle(null,TileType.RUBBLE);
                                        foreach(Tile neighbor in t.TilesAtDistance(1)){
                                            neighbor.solid_rock = false;
                                            if(neighbor.type == TileType.FLOOR && R.OneIn(10)){
                                                neighbor.Toggle(null,TileType.RUBBLE);
                                            }
                                        }
                                    }
                                }
                            }
                            else{
                                int num_walls = t.TilesAtDistance(1).Where(x=>x.Is(TileType.WALL)).Count;
                                if(num_walls == 0 && R.OneIn(100)){
                                    if(R.OneIn(6)){
                                        t.Toggle(null,TileType.RUBBLE);
                                    }
                                    foreach(Tile neighbor in t.TilesAtDistance(1)){
                                        if(neighbor.type == TileType.FLOOR && R.OneIn(6)){
                                            neighbor.Toggle(null,TileType.RUBBLE);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    Q.Add(new Event((R.Roll(20)+20)*100,EventType.CEILING_COLLAPSE));
                    break;
                }*/
                case EventType.NORMAL_LIGHTING:
                {
                    bool check_for_torch_dimming = false;
                    if(M.wiz_lite){
                        B.Add("The supernatural brightness fades from the air. ");
                    }
                    if(M.wiz_dark){
                        B.Add("The supernatural darkness fades from the air. ");
                        check_for_torch_dimming = true;
                    }
                    M.wiz_lite = false;
                    M.wiz_dark = false;
                    if(check_for_torch_dimming && player.HasAttr(AttrType.DIM_LIGHT)){
                        player.CalculateDimming();
                    }
                    break;
                }
                case EventType.TELEPORTAL:
                {
                    Tile t = target as Tile;
                    if(t != null && t.Is(FeatureType.TELEPORTAL,FeatureType.STABLE_TELEPORTAL)){
                        if(t.Is(FeatureType.TELEPORTAL)){
                            value--; //unstable teleportals (from the item) degrade each turn
                        }
                        else{
                            if(value < 100){
                                value++; //stable ones repair themselves after use
                            }
                        }
                        Actor a = t.actor();
                        Tile dest = null;
                        if(a != null && !a.HasAttr(AttrType.JUST_TELEPORTED,AttrType.IMMOBILE)){
                            if(area != null){
                                dest = area.RandomOrDefault();
                            }
                            else{
                                List<Tile> tiles = M.AllTiles().Where(x => x.passable && x.actor() == null && t.ApproximateEuclideanDistanceFromX10(x) >= 45);
                                dest = tiles.RandomOrDefault();
                            }
                            if(dest != null){
                                a.RefreshDuration(AttrType.JUST_TELEPORTED,101);
                                value -= 25;
                                bool visible = false;
                                if(a == player){
                                    B.Add("You disappear into the teleportal. ");
                                }
                                else{
                                    if(player.CanSee(a)){
                                        visible = true;
                                        B.Add(a.the_name + " disappears into the teleportal. ",t);
                                    }
                                }
                                a.Move(dest.row,dest.col);
                                if(a != player && player.CanSee(a)){
                                    if(visible){
                                        B.Add(a.the_name + " reappears. ",a);
                                    }
                                    else{
                                        B.Add(a.a_name + " suddenly appears! ",a);
                                    }
                                }
                            }
                        }
                        else{
                            if(a != null && a.HasAttr(AttrType.JUST_TELEPORTED)){
                                a.RefreshDuration(AttrType.JUST_TELEPORTED,101);
                            }
                        }
                        if(t.inv != null && t.Is(FeatureType.TELEPORTAL)){
                            List<Tile> tiles = M.AllTiles().Where(x => x.passable && x.inv == null && t.ApproximateEuclideanDistanceFromX10(x) >= 45);
                            dest = tiles.RandomOrDefault();
                            if(dest != null){
                                Item i = t.inv;
                                bool visible = false;
                                if(player.CanSee(t)){
                                    visible = true;
                                    B.Add(i.TheName(true) + " disappears into the teleportal. ",t);
                                }
                                t.inv = null;
                                dest.GetItem(i);
                                if(player.CanSee(dest)){
                                    if(visible){
                                        B.Add(i.TheName(true) + " reappears. ",dest);
                                    }
                                    else{
                                        B.Add(i.AName(true) + " suddenly appears! ",dest);
                                    }
                                }
                            }
                        }
                        if(value > 0){
                            Q.Add(new Event(target,area,100,EventType.TELEPORTAL,AttrType.NO_ATTR,value,""));
                            if(value < 25){
                                if(dest != null || R.OneIn(8)){
                                    B.Add("The teleportal flickers. ",t,dest);
                                }
                            }
                        }
                        else{
                            if(t.Is(FeatureType.TELEPORTAL)){
                                t.RemoveFeature(FeatureType.TELEPORTAL);
                            }
                            if(t.Is(FeatureType.STABLE_TELEPORTAL)){
                                foreach(Tile t2 in area){
                                    Event e2 = Q.FindTargetedEvent(t2,EventType.TELEPORTAL);
                                    if(e2 != null && t2.features.Contains(FeatureType.STABLE_TELEPORTAL)){
                                        e2.area.Remove(t);
                                        if(e2.area.Count == 0){
                                            t2.RemoveFeature(FeatureType.STABLE_TELEPORTAL);
                                            //t2.AddFeature(FeatureType.INACTIVE_TELEPORTAL);
                                            e2.dead = true;
                                        }
                                    }
                                }
                                t.RemoveFeature(FeatureType.STABLE_TELEPORTAL);
                            }
                            B.Add("The teleportal flickers and vanishes. ",t,dest);
                        }
                    }
                    break;
                }
                case EventType.BREACH:
                {
                    if(!R.OneIn(3)){
                        Tile t = area.WhereGreatest(x=>x.DistanceFrom(target)).RandomOrDefault();
                        if(t != null){
                            t.Toggle(null);
                            if(t.actor() != null || t.inv != null){
                                foreach(Tile nearby in M.ReachableTilesByDistance(t.row,t.col,false)){
                                    if(t.inv != null && nearby.inv == null){
                                        nearby.GetItem(t.inv);
                                        t.inv = null;
                                        if(t.actor() == null){
                                            break;
                                        }
                                    }
                                    if(t.actor() != null && nearby.actor() == null){
                                        t.actor().Move(nearby.row,nearby.col);
                                        if(t.inv == null){
                                            break;
                                        }
                                    }
                                }
                                if(t.actor() != null){ //if there wasn't an actual path to a passable tile, just move to the nearest
                                    for(int i=1;i<Math.Max(Global.ROWS,Global.COLS);++i){
                                        List<Tile> tiles = t.TilesAtDistance(i).Where(x=>x.passable && x.actor() == null);
                                        bool done = false;
                                        while(tiles.Count > 0){
                                            Tile dest = tiles.Random();
                                            t.actor().Move(dest.row,dest.col);
                                            done = true;
                                            break;
                                        }
                                        if(done){
                                            break;
                                        }
                                    }
                                }
                                if(t.inv != null){
                                    for(int i=1;i<Math.Max(Global.ROWS,Global.COLS);++i){
                                        List<Tile> tiles = t.TilesAtDistance(i).Where(x=>x.passable && x.inv == null);
                                        bool done = false;
                                        while(tiles.Count > 0){
                                            Tile dest = tiles.Random();
                                            dest.GetItem(t.inv);
                                            t.inv = null;
                                            done = true;
                                            break;
                                        }
                                        if(done){
                                            break;
                                        }
                                    }
                                }
                            }
                            if(t.features.Count > 0){
                                t.features.Clear();
                            }
                            area.Remove(t);
                        }
                    }
                    if(area.Count > 0){
                        Q.Add(new Event(target,area,100,EventType.BREACH));
                    }
                    break;
                }
                case EventType.GRAVE_DIRT:
                {
                    foreach(Tile t in area){
                        Actor a = t.actor();
                        if(a != null && a.type != ActorType.CORPSETOWER_BEHEMOTH && !a.HasAttr(AttrType.IMMOBILE,AttrType.JUST_GRABBED,AttrType.FROZEN,AttrType.FLYING) && R.OneIn(12)){
                            if(player.CanSee(a)){
                                B.Add("A dead hand reaches up and grabs " + a.the_name + "! ",t);
                            }
                            if(a == player){
                                B.Print(true);
                            }
                            if(a.HasAttr(AttrType.SLIMED,AttrType.OIL_COVERED,AttrType.BRUTISH_STRENGTH)){
                                if(player.CanSee(a)){
                                    B.Add(a.You("slip") + " out of its grasp. ",t);
                                }
                            }
                            else{
                                int duration = R.Roll(4) * 100;
                                a.attrs[AttrType.IMMOBILE]++;
                                Q.Add(new Event(a,duration,AttrType.IMMOBILE,"The dead hand releases " + a.TheName(true) + ". ",t)); //it'd be nice to check LOS here
                                a.RefreshDuration(AttrType.JUST_GRABBED,duration + 100);
                            }
                        }
                    }
                    Q.Add(new Event(area,100,EventType.GRAVE_DIRT));
                    break;
                }
                case EventType.TOMBSTONE_GHOST:
                {
                    if(area.Count > 0){
                        Tile t = area[0];
                        if(target == null && t.actor() == player){
                            foreach(Tile t2 in M.ReachableTilesByDistance(player.row,player.col,false)){
                                if(t2.passable && t2.actor() == null){
                                    Actor ghost = Actor.Create(ActorType.GHOST,t2.row,t2.col);
                                    if(ghost != null){
                                        target = ghost;
                                        ghost.player_visibility_duration = -1;
                                        ghost.target = player;
                                        t.color = Color.White;
                                        B.Add("A vengeful ghost rises! ");
                                        B.PrintAll();
                                        break;
                                    }
                                }
                            }
                        }
                        Q.Add(new Event(target,area,100,EventType.TOMBSTONE_GHOST));
                    }
                    break;
                }
                case EventType.POPPIES:
                {
                    List<Tile> new_area = new List<Tile>();
                    bool recalculate_distance_map = false;
                    foreach(Tile t in area){
                        if(t.type == TileType.POPPY_FIELD){
                            new_area.Add(t);
                            Actor a = t.actor();
                            if(a == player){
                                Help.TutorialTip(TutorialTopic.Poppies);
                            }
                            if(a != null && !a.HasAttr(AttrType.NONLIVING,AttrType.PLANTLIKE)){
                                if(a.attrs[AttrType.POPPY_COUNTER] < 4){
                                    a.GainAttrRefreshDuration(AttrType.POPPY_COUNTER,200);
                                    if(a == player && a.attrs[AttrType.POPPY_COUNTER] == 1){
                                        B.Add("You breathe in the overwhelming scent of the poppies. "); //todo: this was set to "no interrupt" before. why?
                                    }
                                }
                                else{
                                    a.RefreshDuration(AttrType.POPPY_COUNTER,200);
                                }
                                if(a.attrs[AttrType.POPPY_COUNTER] >= 4){
                                    if(!a.HasAttr(AttrType.ASLEEP,AttrType.JUST_AWOKE)){
                                        if(a.ResistedBySpirit()){
                                            if(player.HasLOS(a)){
                                                B.Add(a.You("resist") + " falling asleep. ",a);
                                            }
                                        }
                                        else{
                                            if(player.HasLOS(a)){
                                                B.Add(a.You("fall") + " asleep in the poppies. ",a);
                                                //B.Add("The poppies lull " + a.the_name + " to sleep. ",a);
                                            }
                                            a.attrs[AttrType.ASLEEP] = R.Between(4,6);
                                        }
                                    }
                                    /*a.ApplyStatus(AttrType.MAGICAL_DROWSINESS,(R.Roll(3)+4)*100);
                                    if(a == player && !a.HasAttr(AttrType.MAGICAL_DROWSINESS)){
                                        //B.Add("The poppies make you drowsy. ");
                                        Help.TutorialTip(TutorialTopic.Drowsiness);
                                    }
                                    a.RefreshDuration(AttrType.MAGICAL_DROWSINESS,a.DurationOfMagicalEffect((R.Roll(3)+4)) * 100,a.YouFeel() + " less drowsy. ",a);*/
                                }
                            }
                        }
                        else{
                            recalculate_distance_map = true;
                        }
                    }
                    if(new_area.Count > 0){
                        Q.Add(new Event(new_area,100,EventType.POPPIES));
                        if(recalculate_distance_map){
                            M.CalculatePoppyDistanceMap();
                        }
                    }
                    break;
                }
                case EventType.BURROWING:
                {
                    List<Tile> open = area.Where(x=>x.passable && x.actor() == null);
                    Actor a = target as Actor;
                    if(open.Count > 0){
                        Tile t = open.Random();
                        Event e = new Event(a,100,EventType.MOVE);
                        e.tiebreaker = this.tiebreaker;
                        Q.Add(e);
                        a.attrs[AttrType.BURROWING] = 0;
                        a.Move(t.row,t.col);
                        if(player.CanSee(a)){
                            a.AnimateStorm(1,2,3,'*',Color.Gray);
                        }
                        B.Add(a.TheName(true) + " emerges from the ground. ",a,t);
                    }
                    else{
                        if(a.HasAttr(AttrType.REGENERATING)){
                            a.curhp += a.attrs[AttrType.REGENERATING];
                            if(a.curhp > a.maxhp){
                                a.curhp = a.maxhp;
                            }
                        }
                        Q.Add(new Event(target,area,100,EventType.BURROWING));
                    }
                    break;
                }
                case EventType.SPAWN_WANDERING_MONSTER:
                {
                    int spawn_chance = 2;
                    foreach(Actor a in Actor.tiebreakers){
                        if(a != player && a != null && !a.HasAttr(AttrType.IMMOBILE) && (a.group == null || a.group.Count == 0 || a.group[0] == a)){
                            spawn_chance *= 2;
                            if(spawn_chance >= 65536){
                                break;
                            }
                        }
                    }
                    if(R.OneIn(spawn_chance)){
                        if(M.extra_danger < 8 && R.CoinFlip() && M.current_level != 1){
                            M.extra_danger++;
                            B.Add("You sense danger. ");
                        }
                        Actor a = M.SpawnWanderingMob();
                        if(a != null){
                            a.attrs[AttrType.WANDERING] = 1;
                            a.attrs[AttrType.NO_ITEM] = 1;
                            if(player.CanSee(a)){
                                B.Add("You suddenly sense the presence of " + a.AName(true) + ". ");
                            }
                        }
                    }
                    Q.Add(new Event(R.Between(20,60)*100,EventType.SPAWN_WANDERING_MONSTER));
                    break;
                }
                /*case EventType.GAS_UPDATE:
                {
                    int ROWS = Global.ROWS;
                    int COLS = Global.COLS;
                    float[,] g = null;
                    for(int num=0;num<3;++num){
                        g = new float[ROWS,COLS];
                        for(int i=1;i<ROWS-1;++i){
                            for(int j=1;j<COLS-1;++j){
                                if(M.tile[i,j].passable){
                                    float neighbors_total = 0.0f;
                                    int open = 0;
                                    foreach(int dir in U.EightDirections){
                                        if(M.tile[i,j].TileInDirection(dir).passable){
                                            pos p = new pos(i,j).PosInDir(dir);
                                            neighbors_total += M.gas[p.row,p.col];
                                            ++open;
                                        }
                                    }
                                    if(open > 0){
                                        float avg = neighbors_total / (float)open;
                                        float d = 0.03f * open;
                                        g[i,j] = M.gas[i,j] * (1-d) + avg * d;
                                    }
                                }
                            }
                        }
                        M.gas = g;
                    }
                    for(int i=0;i<ROWS;++i){
                        for(int j=0;j<COLS;++j){
                            if(g[i,j] > 0.0f){
                                if(g[i,j] <= 0.001f){
                                    g[i,j] = 0.0f;
                                    M.tile[i,j].features.Remove(FeatureType.POISON_GAS);
                                }
                                else{
                                    g[i,j] -= 0.001f;// * (float)R.r.NextDouble();
                                    M.tile[i,j].features.AddUnique(FeatureType.POISON_GAS);
                                }
                            }
                            else{
                                M.tile[i,j].features.Remove(FeatureType.POISON_GAS);
                            }
                        }
                    }
                    Q.Add(new Event(100,EventType.GAS_UPDATE));
                    break;
                }*/
                case EventType.FIRE:
                {
                    List<Tile> chance_to_burn = new List<Tile>(); //tiles that might be affected
                    List<Tile> chance_to_die_out = new List<Tile>(); //fires that might die out
                    List<PhysicalObject> no_fire = new List<PhysicalObject>();
                    foreach(PhysicalObject o in new List<PhysicalObject>(Fire.burning_objects)){
                        if(o.IsBurning()){
                            foreach(Tile neighbor in o.TilesWithinDistance(1)){
                                if(neighbor.actor() != null && neighbor.actor() != o){
                                    if(neighbor.actor() == player){
                                        if(!player.HasAttr(AttrType.JUST_SEARED,AttrType.FROZEN,AttrType.DAMAGE_RESISTANCE)){
                                            B.Add("The heat sears you! ");
                                        }
                                        player.RefreshDuration(AttrType.JUST_SEARED,50);
                                    }
                                    neighbor.actor().TakeDamage(DamageType.FIRE,DamageClass.PHYSICAL,false,1,null,"searing heat");
                                }
                                //every actor adjacent to a burning object takes proximity fire damage. (actors never get set on
                                //  fire directly this way, but an actor covered in oil will ignite if it takes any fire damage)
                                //every tile adjacent to a burning object has a chance to be affected by fire. oil-covered objects are always affected.
                                //if the roll is passed, fire is applied to the tile.
                                chance_to_burn.AddUnique(neighbor);
                            }
                            if(o is Tile){
                                chance_to_die_out.AddUnique(o as Tile);
                            }
                        }
                        else{
                            no_fire.AddUnique(o);
                        }
                    }
                    foreach(Tile t in chance_to_burn){
                        if(R.OneIn(6) || t.Is(FeatureType.OIL,FeatureType.SPORES,FeatureType.CONFUSION_GAS) || t.Is(TileType.BARREL)){
                            t.ApplyEffect(DamageType.FIRE);
                        }
                    }
                    foreach(Tile t in chance_to_die_out){
                        if(!t.Is(TileType.BARREL)){
                            bool more_flammable_terrain = false;
                            bool more_fire = false;
                            bool final_level_demonic_idol_present = false; //this will soon become a check for any terrain that prevents fires from dying
                            foreach(Tile neighbor in t.TilesAtDistance(1)){
                                if(neighbor.IsCurrentlyFlammable()){
                                    more_flammable_terrain = true;
                                }
                                if(neighbor.Is(TileType.DEMONIC_IDOL)){
                                    final_level_demonic_idol_present = true;
                                }
                                if(neighbor.IsBurning()){
                                    more_fire = true;
                                }
                            }
                            if(final_level_demonic_idol_present){
                                continue; //this fire never goes out
                            }
                            int chance = 5;
                            if(more_fire){
                                chance = 10;
                            }
                            if(more_flammable_terrain){
                                chance = 20;
                            }
                            if(R.OneIn(chance)){
                                t.RemoveFeature(FeatureType.FIRE);
                                Fire.burning_objects.Remove(t);
                                if(t.name == "floor" && t.type != TileType.BREACHED_WALL){
                                    t.MakeFloorCharred();
                                }
                            }
                        }
                    }
                    foreach(PhysicalObject o in no_fire){
                        Fire.burning_objects.Remove(o);
                    }
                    if(Fire.burning_objects.Count > 0){
                        Event e = new Event(100,EventType.FIRE);
                        Q.Add(e);
                        Fire.fire_event = e;
                    }
                    else{
                        Fire.fire_event = null;
                    }
                    break;
                }
                }
                if(msg != ""){
                    if(msg_objs == null){
                        B.Add(msg);
                    }
                    else{
                        if(msg_objs.Count == 1 && msg_objs[0] is Actor && (msg_objs[0] as Actor).HasAttr(AttrType.BURROWING)){
                            //do nothing
                        }
                        else{
                            B.Add(msg,msg_objs.ToArray());
                        }
                    }
                }
            }
        }
Example #19
0
        public void OnNudge(Actor self, Actor nudger, bool force)
        {
            /* initial fairly braindead implementation. */
            if (!force && self.Owner.Stances[nudger.Owner] != Stance.Ally)
                return;		/* don't allow ourselves to be pushed around
                             * by the enemy! */

            if (!force && !self.IsIdle)
                return;		/* don't nudge if we're busy doing something! */

            // pick an adjacent available cell.
            var availCells = new List<int2>();
            var notStupidCells = new List<int2>();

            for (var i = -1; i < 2; i++)
                for (var j = -1; j < 2; j++)
                {
                    var p = toCell + new int2(i, j);
                    if (CanEnterCell(p))
                        availCells.Add(p);
                    else
                        if (p != nudger.Location && p != toCell)
                            notStupidCells.Add(p);
                }

            var moveTo = availCells.Any() ? availCells.Random(self.World.SharedRandom) :
                notStupidCells.Any() ? notStupidCells.Random(self.World.SharedRandom) : (int2?)null;

            if (moveTo.HasValue)
            {
                self.CancelActivity();
                self.SetTargetLine(Target.FromCell(moveTo.Value), Color.Green, false);
                self.QueueActivity(new Move(moveTo.Value, 0));

                Log.Write("debug", "OnNudge #{0} from {1} to {2}",
                    self.ActorID, self.Location, moveTo.Value);
            }
            else
                Log.Write("debug", "OnNudge #{0} refuses at {1}",
                    self.ActorID, self.Location);
        }
Example #20
0
 public void AlterRooms(int no_change_freq,int add_pillars_freq,int cross_room_freq,int cave_widen_freq,int cave_fill_freq)
 {
     List<int> modification = new List<int>();
     for(int i=0;i<no_change_freq;++i){
         modification.Add(0);
     }
     for(int i=0;i<add_pillars_freq;++i){
         modification.Add(1);
     }
     for(int i=0;i<cross_room_freq;++i){
         modification.Add(2);
     }
     for(int i=0;i<cave_widen_freq;++i){
         modification.Add(3);
     }
     for(int i=0;i<cave_fill_freq;++i){
         modification.Add(4);
     }
     if(modification.Count == 0){
         return;
     }
     ForEachRectangularRoom((start_r,start_c,end_r,end_c) => {
         int mod = modification.Random();
         switch(mod){
         case 0:
             return true;
         case 1:
         {
             int height = end_r - start_r + 1;
             int width = end_c - start_c + 1;
             if(height > 3 || width > 3){
                 List<PillarArrangement> layouts = new List<PillarArrangement>();
                 if(height % 2 == 1 && width % 2 == 1){
                     layouts.Add(PillarArrangement.Single);
                 }
                 if((height % 2 == 1 || width % 2 == 1) && height != 4 && width != 4){
                     layouts.Add(PillarArrangement.Row);
                 }
                 if(height >= 5 && width >= 5){
                     layouts.Add(PillarArrangement.Corners);
                 }
                 if(height > 2 && width > 2 && height != 4 && width != 4){
                     layouts.Add(PillarArrangement.Full);
                 }
                 if((width % 2 == 1 && width >= 5) || (height % 2 == 1 && height >= 5)){
                     layouts.Add(PillarArrangement.StatueEdges);
                 }
                 if(layouts.Count == 0 || CoinFlip()){ //otherwise they're too common
                     layouts.Add(PillarArrangement.StatueCorners);
                 }
                 if(layouts.Count > 0){
                     CellType pillar = CellType.Pillar;
                     switch(layouts.Random()){
                     case PillarArrangement.Single:
                         map[(start_r + end_r)/2,(start_c + end_c)/2] = pillar;
                         break;
                     case PillarArrangement.Row:
                     {
                         bool vertical;
                         if(width % 2 == 1 && height % 2 == 0){
                             vertical = true;
                         }
                         else{
                             if(height % 2 == 1 && width % 2 == 0){
                                 vertical = false;
                             }
                             else{
                                 vertical = CoinFlip();
                             }
                         }
                         if(vertical){
                             if(height % 2 == 1){
                                 for(int i=start_r+1;i<=end_r-1;i+=2){
                                     map[i,(start_c + end_c)/2] = pillar;
                                 }
                             }
                             else{
                                 int offset = 0;
                                 if(height % 4 == 0){
                                     offset = Roll(2) - 1;
                                 }
                                 for(int i=start_r+1+offset;i<(start_r + end_r)/2;i+=2){
                                     map[i,(start_c + end_c)/2] = pillar;
                                 }
                                 for(int i=end_r-1-offset;i>(start_r + end_r)/2+1;i-=2){
                                     map[i,(start_c + end_c)/2] = pillar;
                                 }
                             }
                         }
                         else{
                             if(width % 2 == 1){
                                 for(int i=start_c+1;i<=end_c-1;i+=2){
                                     map[(start_r + end_r)/2,i] = pillar;
                                 }
                             }
                             else{
                                 int offset = 0;
                                 if(width % 4 == 0){
                                     offset = Roll(2) - 1;
                                 }
                                 for(int i=start_c+1+offset;i<(start_c + end_c)/2;i+=2){
                                     map[(start_r + end_r)/2,i] = pillar;
                                 }
                                 for(int i=end_c-1-offset;i>(start_c + end_c)/2+1;i-=2){
                                     map[(start_r + end_r)/2,i] = pillar;
                                 }
                             }
                         }
                         break;
                     }
                     case PillarArrangement.Corners:
                     {
                         int v_offset = 0;
                         int h_offset = 0;
                         if(height % 4 == 0){
                             v_offset = Roll(2) - 1;
                         }
                         if(width % 4 == 0){
                             h_offset = Roll(2) - 1;
                         }
                         map[start_r + 1 + v_offset,start_c + 1 + h_offset] = pillar;
                         map[start_r + 1 + v_offset,end_c - 1 - h_offset] = pillar;
                         map[end_r - 1 - v_offset,start_c + 1 + h_offset] = pillar;
                         map[end_r - 1 - v_offset,end_c - 1 - h_offset] = pillar;
                         break;
                     }
                     case PillarArrangement.Full:
                     {
                         int v_offset = 0;
                         int h_offset = 0;
                         if(height % 4 == 0){
                             v_offset = Roll(2) - 1;
                         }
                         if(width % 4 == 0){
                             h_offset = Roll(2) - 1;
                         }
                         int half_r = (start_r + end_r)/2;
                         int half_c = (start_c + end_c)/2;
                         int half_r_offset = (start_r + end_r + 1)/2;
                         int half_c_offset = (start_c + end_c + 1)/2;
                         for(int i=start_r+1+v_offset;i<half_r;i+=2){
                             for(int j=start_c+1+h_offset;j<half_c;j+=2){
                                 map[i,j] = pillar;
                             }
                         }
                         for(int i=start_r+1+v_offset;i<half_r;i+=2){
                             for(int j=end_c-1-h_offset;j>half_c_offset;j-=2){
                                 map[i,j] = pillar;
                             }
                         }
                         for(int i=end_r-1-v_offset;i>half_r_offset;i-=2){
                             for(int j=start_c+1+h_offset;j<half_c;j+=2){
                                 map[i,j] = pillar;
                             }
                         }
                         for(int i=end_r-1-v_offset;i>half_r_offset;i-=2){
                             for(int j=end_c-1-h_offset;j>half_c_offset;j-=2){
                                 map[i,j] = pillar;
                             }
                         }
                         if((width+1) % 4 == 0){
                             if(height % 2 == 1){
                                 for(int i=start_r+1;i<=end_r-1;i+=2){
                                     map[i,half_c] = pillar;
                                 }
                             }
                             else{
                                 int offset = 0;
                                 if(height % 4 == 0){
                                     offset = Roll(2) - 1;
                                 }
                                 for(int i=start_r+1+offset;i<half_r;i+=2){
                                     map[i,half_c] = pillar;
                                 }
                                 for(int i=end_r-1-offset;i>half_r_offset;i-=2){
                                     map[i,half_c] = pillar;
                                 }
                             }
                         }
                         if((height+1) % 4 == 0){
                             if(width % 2 == 1){
                                 for(int i=start_c+1;i<=end_c-1;i+=2){
                                     map[half_r,i] = pillar;
                                 }
                             }
                             else{
                                 int offset = 0;
                                 if(width % 4 == 0){
                                     offset = Roll(2) - 1;
                                 }
                                 for(int i=start_c+1+offset;i<half_c;i+=2){
                                     map[half_r,i] = pillar;
                                 }
                                 for(int i=end_c-1-offset;i>half_c_offset;i-=2){
                                     map[half_r,i] = pillar;
                                 }
                             }
                         }
                         break;
                     }
                     case PillarArrangement.StatueCorners:
                         map[start_r,start_c] = CellType.Statue;
                         map[start_r,end_c] = CellType.Statue;
                         map[end_r,start_c] = CellType.Statue;
                         map[end_r,end_c] = CellType.Statue;
                         break;
                     case PillarArrangement.StatueEdges:
                     {
                         map[start_r,start_c] = CellType.Statue;
                         map[start_r,end_c] = CellType.Statue;
                         map[end_r,start_c] = CellType.Statue;
                         map[end_r,end_c] = CellType.Statue;
                         if(width % 2 == 1 && width > 3){
                             int half_c = (start_c + end_c)/2;
                             int corridors = new pos(start_r,half_c).CardinalAdjacentPositions().Where(x => BoundsCheck(x) && map[x].IsCorridorType()).Count;
                             if(corridors == 0){
                                 map[start_r,half_c] = CellType.Statue;
                             }
                             corridors = new pos(end_r,half_c).CardinalAdjacentPositions().Where(x => BoundsCheck(x) && map[x].IsCorridorType()).Count;
                             if(corridors == 0){
                                 map[end_r,half_c] = CellType.Statue;
                             }
                         }
                         if(height % 2 == 1 && height > 3){
                             int half_r = (start_r + end_r)/2;
                             int corridors = new pos(half_r,start_c).CardinalAdjacentPositions().Where(x => BoundsCheck(x) && map[x].IsCorridorType()).Count;
                             if(corridors == 0){
                                 map[half_r,start_c] = CellType.Statue;
                             }
                             corridors = new pos(half_r,end_c).CardinalAdjacentPositions().Where(x => BoundsCheck(x) && map[x].IsCorridorType()).Count;
                             if(corridors == 0){
                                 map[half_r,end_c] = CellType.Statue;
                             }
                         }
                         break;
                     }
                     default:
                         break;
                     }
                 }
             }
             return true;
         }
         case 2:
         {
             int height = end_r - start_r + 1;
             int width = end_c - start_c + 1;
             if(height < 4 || width < 4){ //nothing happens until we get above 4x4
                 return true;
             }
             int rows_to_convert = Roll((height/2)-1);
             int cols_to_convert = Roll((width/2)-1);
             if(rows_to_convert == 1 && cols_to_convert == 1){
                 return true;
             }
             List<pos> blocked = new List<pos>();
             for(int i=start_r;i<=end_r;++i){
                 for(int j=start_c;j<=end_c;++j){
                     if((i < start_r + rows_to_convert || i > end_r - rows_to_convert) && (j < start_c + cols_to_convert || j > end_c - cols_to_convert)){
                         pos p = new pos(i,j);
                         foreach(pos neighbor in p.CardinalAdjacentPositions()){
                             if(map[neighbor].IsCorridorType()){
                                 blocked.Add(p);
                             }
                         }
                         map[i,j] = CellType.Wall;
                     }
                 }
             }
             blocked.Randomize();
             foreach(pos p in blocked){
                 bool done = false;
                 foreach(pos neighbor in p.CardinalAdjacentPositions()){
                     if(map[neighbor].IsRoomType()){
                         map[p] = CellType.RoomInterior;
                         done = true;
                         break;
                     }
                 }
                 if(!done){
                     List<int> valid_dirs = new List<int>();
                     foreach(int dir in U.FourDirections){
                         pos next = p.PosInDir(dir);
                         while(next.row >= start_r && next.row <= end_r && next.col >= start_c && next.col <= end_c){
                             if(next.CardinalAdjacentPositions().Any(x=>map[x].IsRoomType())){
                                 valid_dirs.Add(dir);
                                 break;
                             }
                             next = next.PosInDir(dir);
                         }
                     }
                     int valid_dir = valid_dirs.RandomOrDefault();
                     pos next2 = p.PosInDir(valid_dir);
                     List<pos> new_corridor = new List<pos>{p};
                     while(true){
                         new_corridor.Add(next2);
                         if(next2.CardinalAdjacentPositions().Any(x=>map[x].IsRoomType())){
                             break;
                         }
                         next2 = next2.PosInDir(valid_dir);
                     }
                     foreach(pos p2 in new_corridor){
                         map[p2] = CellType.RoomInterior;
                     }
                 }
             }
             return true;
         }
         case 3:
         {
             List<pos> list = map.PositionsWhere(x=>x.row >= start_r && x.row <= end_r && x.col >= start_c && x.col <= end_c);
             PosArray<CellType> old_map = new PosArray<CellType>(H,W);
             foreach(pos p in list){
                 old_map[p] = map[p];
                 map[p] = CellType.Wall;
             }
             PosArray<bool> rock = new PosArray<bool>(H,W);
             for(int i=0;i<H;++i){
                 for(int j=0;j<W;++j){
                     pos p = new pos(i,j);
                     rock[p] = true;
                     if(BoundsCheck(i,j,false)){
                         foreach(pos neighbor in p.AdjacentPositionsClockwise()){
                             if(map[neighbor] != CellType.Wall){
                                 rock[p] = false;
                                 break;
                             }
                         }
                     }
                 }
             }
             foreach(pos p in list){
                 map[p] = CellType.RoomInterior; //todo: might this step be extraneous?
             }
             List<pos> frontier = new List<pos>();
             {
                 PosArray<bool> in_list = new PosArray<bool>(H,W);
                 foreach(pos p in list){
                     in_list[p] = true;
                 }
                 for(int i=0;i<H;++i){
                     for(int j=0;j<W;++j){
                         pos p = new pos(i,j);
                         if(in_list[p]){
                             foreach(pos neighbor in p.PositionsAtDistance(1,in_list)){
                                 if(!in_list[neighbor]){
                                     frontier.Add(p);
                                     break;
                                 }
                             }
                         }
                     }
                 }
             }
             int fail_counter = 0;
             int num_added = 0;
             bool finished = false;
             while(!finished){
                 if(frontier.Count == 0 || num_added >= 30){ //todo check this value
                     finished = true;
                     break;
                 }
                 pos f = frontier.RemoveRandom();
                 foreach(pos neighbor in f.CardinalAdjacentPositions()){
                     if(!BoundsCheck(neighbor,false) || !rock[neighbor.row,neighbor.col]){
                         ++fail_counter; //this might now be unreachable
                         if(!BoundsCheck(neighbor,false)){
                             fail_counter += 25; //fail quicker when against the edge of the map to prevent ugliness
                         } //however, this doesn't actually fail as quickly as it should - i've overlooked something.
                         if(fail_counter >= 50){
                             finished = true;
                             break;
                         }
                     }
                     else{
                         if(map[neighbor] != CellType.RoomInterior){
                             map[neighbor] = CellType.RoomInterior;
                             ++num_added;
                             bool add_neighbor = true;
                             foreach(pos n2 in neighbor.CardinalAdjacentPositions()){
                                 if(!BoundsCheck(n2,false) || !rock[n2.row,n2.col]){
                                     add_neighbor = false;
                                     ++fail_counter; //this might now be unreachable
                                     if(!BoundsCheck(neighbor,false)){
                                         fail_counter += 25; //fail quicker when against the edge of the map to prevent ugliness
                                     } //however, this doesn't actually fail as quickly as it should - i've overlooked something.
                                     if(fail_counter >= 50){
                                         finished = true;
                                     }
                                     break;
                                 }
                             }
                             if(finished){
                                 break;
                             }
                             if(add_neighbor){
                                 frontier.Add(neighbor);
                             }
                         }
                     }
                 }
             }
             foreach(pos p in list){
                 map[p] = old_map[p];
             }
             return true;
         }
         case 4:
         {
             List<pos> list = map.PositionsWhere(x=>x.row >= start_r && x.row <= end_r && x.col >= start_c && x.col <= end_c);
             Dungeon room = new Dungeon((end_r - start_r) + 3,(end_c - start_c) + 3); //includes borders
             List<pos> map_exits = list.Where(x=>x.CardinalAdjacentPositions().Any(y=>map[y].IsCorridorType())); //grab the positions from list that have any adjacent corridor-type cells
             if(map_exits.Count < 2){
                 return true;
             }
             List<pos> room_exits = new List<pos>();
             foreach(pos exit in map_exits){
                 room_exits.Add(new pos(exit.row-start_r+1,exit.col-start_c+1));
             }
             int tries = 0;
             while(true){
                 room.FillWithRandomWalls(25);
                 room.ApplyCellularAutomataXYRule(3);
                 room.ConnectDiagonals();
                 room.RemoveDeadEndCorridors();
                 room.RemoveUnconnectedAreas();
                 bool exits_open = true;
                 foreach(pos p in room_exits){
                     if(!room[p].IsPassable()){
                         exits_open = false;
                     }
                 }
                 if(exits_open){
                     for(int i=start_r;i<=end_r;++i){
                         for(int j=start_c;j<=end_c;++j){
                             if(list.Contains(new pos(i,j))){
                                 map[i,j] = room[(i-start_r)+1,(j-start_c)+1];
                             }
                         }
                     }
                     break;
                 }
                 ++tries;
                 if(tries > 50){
                     return false;
                 }
             }
             return true;
         }
         default:
             break;
         }
         return true;
     });
 }
Example #21
0
 public void OpenChest()
 {
     if(type == TileType.CHEST){
         if(spellbooks_generated < 5 && R.OneIn(50)){ //keep an eye on this value
             ++spellbooks_generated;
             SpellType spell = SpellType.NO_SPELL;
             List<SpellType> random_spell_list = new List<SpellType>();
             foreach(SpellType sp in Enum.GetValues(typeof(SpellType))){
                 random_spell_list.Add(sp);
             }
             while(spell == SpellType.NO_SPELL && random_spell_list.Count > 0){
                 SpellType sp = random_spell_list.RemoveRandom();
                 if(!player.HasSpell(sp) && sp != SpellType.NO_SPELL && sp != SpellType.NUM_SPELLS){
                     spell = sp;
                 }
             }
             if(spell != SpellType.NO_SPELL){
                 B.Add("You find a spellbook! ");
                 B.Add("You learn " + Spell.Name(spell) + ". ");
                 player.spells[spell] = true;
                 Actor.spells_in_order.Add(spell);
             }
             else{
                 B.Add("The chest is empty! ");
             }
         }
         else{
             ConsumableType item = Item.RandomChestItem();
             if(item == ConsumableType.MAGIC_TRINKET){
                 List<MagicTrinketType> valid = new List<MagicTrinketType>();
                 foreach(MagicTrinketType trinket in Enum.GetValues(typeof(MagicTrinketType))){
                     if(trinket != MagicTrinketType.NO_MAGIC_TRINKET && trinket != MagicTrinketType.NUM_MAGIC_TRINKETS && !player.magic_trinkets.Contains(trinket)){
                         valid.Add(trinket);
                     }
                 }
                 if(valid.Count > 0){
                     MagicTrinketType trinket = valid.Random();
                     if(trinket == MagicTrinketType.BRACERS_OF_ARROW_DEFLECTION || trinket == MagicTrinketType.BOOTS_OF_GRIPPING){
                         B.Add("You find " + MagicTrinket.Name(trinket) + "! ");
                     }
                     else{
                         B.Add("You find a " + MagicTrinket.Name(trinket) + "! ");
                     }
                     player.magic_trinkets.Add(trinket);
                     Help.TutorialTip(TutorialTopic.MagicTrinkets);
                 }
                 else{
                     B.Add("The chest is empty! ");
                 }
             }
             else{
                 bool no_room = false;
                 if(player.InventoryCount() >= Global.MAX_INVENTORY_SIZE){
                     no_room = true;
                 }
                 Item i = Item.Create(Item.RandomItem(),player);
                 if(i != null){
                     i.revealed_by_light = true;
                     B.Add("You find " + Item.Prototype(i.type).AName() + ". ");
                     if(no_room){
                         B.Add("Your pack is too full to pick it up. ");
                         i.ignored = true;
                     }
                 }
             }
         }
         if(color == Color.Yellow){
             B.Add("There's something else in the chest! ");
             color = Color.DarkYellow;
         }
         else{
             TurnToFloor();
         }
     }
 }
Example #22
0
		/// <summary>
		/// Uses WM, attacking targets.
		/// </summary>
		/// <param name="attacker"></param>
		/// <param name="skill"></param>
		/// <param name="targetAreaId"></param>
		/// <param name="unkInt1"></param>
		/// <param name="unkInt2"></param>
		public void Use(Creature attacker, Skill skill, long targetAreaId, int unkInt1, int unkInt2)
		{
			var range = this.GetRange(attacker, skill);
			var targets = attacker.GetTargetableCreaturesInRange(range, true);

			// Check targets
			if (targets.Count == 0)
			{
				Send.Notice(attacker, Localization.Get("There isn't a target nearby to use that on."));
				Send.SkillUseSilentCancel(attacker);
				return;
			}

			// Create actions
			var cap = new CombatActionPack(attacker, skill.Info.Id);

			var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, skill.Info.Id, targetAreaId);
			aAction.Set(AttackerOptions.Result);

			cap.Add(aAction);

			var survived = new List<Creature>();

			foreach (var target in targets)
			{
				target.StopMove();

				var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
				tAction.Delay = 300; // Usually 300, sometimes 350?

				// Calculate damage
				var damage = attacker.GetRndTotalDamage();
				damage *= skill.RankData.Var1 / 100f;

				// Handle skills and reductions
				CriticalHit.Handle(attacker, attacker.GetTotalCritChance(0), ref damage, tAction);
				SkillHelper.HandleDefenseProtection(target, ref damage);
				Defense.Handle(aAction, tAction, ref damage);
				ManaShield.Handle(target, ref damage, tAction);

				// Clean Hit if not defended nor critical
				if (tAction.SkillId != SkillId.Defense && !tAction.Has(TargetOptions.Critical))
					tAction.Set(TargetOptions.CleanHit);

				// Take damage if any is left
				if (damage > 0)
					target.TakeDamage(tAction.Damage = damage, attacker);

				// Finish if dead, knock down if not defended
				if (target.IsDead)
					tAction.Set(TargetOptions.KnockDownFinish);
				else if (tAction.SkillId != SkillId.Defense)
					tAction.Set(TargetOptions.KnockDown);

				// Anger Management
				if (!target.IsDead)
					survived.Add(target);

				// Stun & knock back
				aAction.Stun = CombatMastery.GetAttackerStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);

				if (tAction.SkillId != SkillId.Defense)
				{
					tAction.Stun = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);
					target.Stability = Creature.MinStability;
					attacker.Shove(target, KnockbackDistance);
				}

				// Add action
				cap.Add(tAction);
			}

			// Only select a random aggro if there is no aggro yet,
			// WM only aggroes one target at a time.
			if (survived.Count != 0 && attacker.Region.CountAggro(attacker) < 1)
			{
				var rnd = RandomProvider.Get();
				var aggroTarget = survived.Random();
				aggroTarget.Aggro(attacker);
			}

			// Reduce life in old combat system
			if (!AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal"))
			{
				var amount = (attacker.LifeMax < 10 ? 2 : attacker.LifeMax / 10);
				attacker.ModifyLife(-amount);

				// TODO: Invincibility
			}

			// Spin it~
			Send.UseMotion(attacker, 8, 4);

			cap.Handle();

			Send.SkillUse(attacker, skill.Info.Id, targetAreaId, unkInt1, unkInt2);

			skill.Stacks = 0;
		}
Example #23
0
 public List<Tile> AddGaseousFeature(FeatureType f,int num)
 {
     List<Tile> area = new List<Tile>();
     Tile current = this;
     for(int i=0;i<num;++i){
         if(!current.Is(f)){
             current.AddFeature(f);
             area.Add(current);
         }
         else{
             for(int tries=0;tries<50;++tries){
                 List<Tile> open = new List<Tile>();
                 foreach(Tile t in current.TilesAtDistance(1)){
                     if(t.passable){
                         open.Add(t);
                         if(!t.Is(f)){
                             open.Add(t); //3x as likely if it can expand there
                             open.Add(t);
                         }
                     }
                 }
                 /*foreach(int dir in U.FourDirections){
                     if(current.TileInDirection(dir).passable){
                         open.Add(current.TileInDirection(dir));
                     }
                 }*/
                 if(open.Count > 0){
                     Tile possible = open.Random();
                     if(!possible.Is(f)){
                         possible.AddFeature(f);
                         area.Add(possible);
                         break;
                     }
                     else{
                         current = possible;
                     }
                 }
                 else{
                     break;
                 }
             }
         }
     }
     return area;
 }
 public void GettingRandomItemFromListReturnsAnElementFromTheList()
 {
     IList<int> list = new List<int>() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
     int rnd = list.Random();
     Assert.True(list.Contains(rnd));
 }
Example #25
0
        public void OnNudge(Actor self, Actor nudger)
        {
            /* initial fairly braindead implementation. */

            if (self.Owner.Stances[nudger.Owner] != Stance.Ally)
                return;		/* don't allow ourselves to be pushed around
                             * by the enemy! */

            if (!self.IsIdle)
                return;		/* don't nudge if we're busy doing something! */

            // pick an adjacent available cell.
            var availCells = new List<int2>();
            var notStupidCells = new List<int2>(); //cells that we could enter if the mobile occupants left

            for( var i = -1; i < 2; i++ )
                for (var j = -1; j < 2; j++)
                {
                    var p = toCell + new int2(i, j);
                    if (p != self.Location)
                    {
                        if (CanEnterCell(p))
                            availCells.Add(p);
                        else
                            if (CanEnterCell(p, null, false) && p != nudger.Location)
                                notStupidCells.Add(p);
                    }
                }

            var moveTo = availCells.Any() ? availCells.Random(self.World.SharedRandom) :
                notStupidCells.Any() ? notStupidCells.Random(self.World.SharedRandom) : (int2?)null;

            if (moveTo.HasValue)
            {
                self.CancelActivity();
                if (self.Owner == self.World.LocalPlayer)
                    self.World.AddFrameEndTask(w =>
                    {
                        var line = self.TraitOrDefault<DrawLineToTarget>();
                        if (line != null)
                            line.SetTargetSilently(self, Target.FromCell(moveTo.Value), Color.Green);
                    });
                self.QueueActivity(new Move(moveTo.Value, 0));
            }
        }
Example #26
0
        public void Initialize()
        {
            Native.Document.body.style.padding = "0";
            Native.Document.body.style.margin = "0";

            var Images = new Dictionary<string, IHTMLImage>();
            var ImagesLoaded = default(Action);
            Func<string, IHTMLImage> CloneImage = name => (IHTMLImage)Images[name].cloneNode(false);

            var Zoom = Data.Zoom.ToDouble();

            var ControlSize = new ZoomedPoint
            {
                Z = Zoom,
                X = Data.ControlSize.Xint,
                Y = Data.ControlSize.Yint
            };

            Control.style.SetSize(ControlSize.ZoomedXint, ControlSize.ZoomedYint);
            Control.style.backgroundColor = Data.BackgroundColor;
            Control.style.color = Data.TextColor;
            Control.AttachAsNextOrToDocument(null);
            Control.style.position = IStyle.PositionEnum.relative;

            Action LoadImages =
                delegate
                {
                    Data.Sprites.ForEach(
                        i =>
                        {
                            Images[i.Value] = i.ImageValue;
                        }
                    );

                    ImagesLoaded();
                };

            ImagesLoaded =
                delegate
                {
                    var ClientRectPos = new ZoomedPoint
                    {
                        Z = Zoom,
                        X = Data.ClientRect.From.Xint,
                        Y = Data.ClientRect.From.Yint
                    };

                    var ClientRectSize = new ZoomedPoint
                    {
                        Z = Zoom,
                        X = Data.ClientRect.Size.Xint,
                        Y = Data.ClientRect.Size.Yint
                    };

                    var ContentLayer = new IHTMLDiv();

                    ContentLayer.style.backgroundColor = Data.ClientRectColor;
                    ContentLayer.style.overflow = IStyle.OverflowEnum.hidden;

                    ContentLayer.style.SetLocation(
                        ClientRectPos.ZoomedXint,
                        ClientRectPos.ZoomedYint,
                        ClientRectSize.ZoomedXint,
                        ClientRectSize.ZoomedYint
                        );
                    ContentLayer.AttachTo(Control);


                    //var r1 = CloneImage("room 001").AttachTo(ContentLayer);

                    //r1.style.SetLocation(0, 0, ClientRectSize.ZoomedXint, ClientRectSize.ZoomedYint);

                    Func<string, IHTMLImage> CreateRoomImage =
                        name =>
                        {
                            var r2 = CloneImage(name);
                            
                            r2.AttachTo(ContentLayer);

                            var r2_Zoom = new ZoomedPoint
                            {
                                Z = Zoom,
                                X = Images[name].width,
                                Y = Images[name].height
                            };

                            r2.Hide();
                            r2.style.SetLocation(0, 0, r2_Zoom.ZoomedXint, r2_Zoom.ZoomedYint);

                            return r2;
                        };

                    var KnownRooms = new List<IHTMLImage>();

                    KnownRooms.AddRange(
                        new [] 
                        {
                            CreateRoomImage("room 001"),
                            CreateRoomImage("room 002"),
                            CreateRoomImage("room 024"),
                            CreateRoomImage("room 031"),
                            CreateRoomImage("room 032"),
                        }
                    );

                    var CurrentRoom = KnownRooms.Random();

                    CurrentRoom.Show();

                    Action<double> SetClipTo =
                        percentage =>
                        {
                            var x = (ClientRectSize.ZoomedX * percentage / 2).ToInt32();
                            var y = (ClientRectSize.ZoomedY * percentage / 2).ToInt32();

                            var clip = new CSSClip
                            {
                                Left = x,
                                Top = y,
                                Right = (ClientRectSize.ZoomedX - x).ToInt32(),
                                Bottom = (ClientRectSize.ZoomedY - y).ToInt32()
                            };

                            Console.WriteLine(percentage + " clip: " + clip);

                            ContentLayer.style.clip = clip;

                        };

                    //ContentLayer.style.clip = "rect(15px auto auto 15px)";

                    //var timer = new ScriptCoreLib.JavaScript.Runtime.Timer(
                    //    delegate
                    //    {
                    //        var p = (Math.Sin(DateTime.Now.Ticks) + 1) / 2;

                    //        Console.WriteLine("p: " + p);
                    //        SetClipTo(p);
                    //    }
                    //    , 0, 200);

                    //var pc = 50;
                    //var px = 200;

                    //Action<double> pChange = i => { px += (i * pc).ToInt32(); timer.StartInterval(px); };

                    Action<Action, Action> FadeOut =
                        (Starting, Stopping) =>
                            new LinearTimeTween
                            {
                                Length = 300,
                                Starting = Starting,
                                Stopping = Stopping,
                                Changed = t => SetClipTo(t),
                                Percision = 20
                            }.Start();

                    Action<Action, Action> FadeIn =
                                  (Starting, Stopping) =>
                                      new LinearTimeTween
                                      {
                                          Length = 300,
                                          Starting = Starting,
                                          Stopping = Stopping,
                                          Changed = t => SetClipTo(1d - t),
                                          Percision = 20
                                      }.Start();

                    var kbd = new KeyboardEvents { Enabled = true };

                    kbd.left += ev =>
                        FadeOut(
                            () => kbd.Enabled = false,
                            () =>
                            {
                                CurrentRoom.Hide();
                                CurrentRoom = KnownRooms.Previous(i => CurrentRoom == i);
                                CurrentRoom.Show();

                                //r1.Hide();
                                //r2.Show();

                                FadeIn(null, () => kbd.Enabled = true);
                            }
                        );

                    kbd.right += ev =>
                         FadeOut(
                            () => kbd.Enabled = false,
                            () =>
                            {
                                CurrentRoom.Hide();
                                CurrentRoom = KnownRooms.Next(i => CurrentRoom == i);
                                CurrentRoom.Show();

                                FadeIn(null, () => kbd.Enabled = true);
                            }
                        );


                    Native.Document.onkeydown += kbd;

                    Native.Document.onmousedown +=
                       ev =>
                         FadeOut(
                            () => kbd.Enabled = false,
                            () =>
                            {
                                CurrentRoom.Hide();
                                CurrentRoom = KnownRooms.Next(i => CurrentRoom == i);
                                CurrentRoom.Show();

                                FadeIn(null, () => kbd.Enabled = true);
                            }
                        );

                    /*
                    var div1 = SpawnDiv(Images, false);

                    div1.style.backgroundColor = Color.Yellow;
                    div1.AttachTo(ClientRect);
                    div1.style.SetLocation(4, 4, 100, 100);

                    var div2 = SpawnDiv(Images, true);

                    div2.style.backgroundColor = Color.Gray;
                    div2.AttachTo(ClientRect);
                    div2.style.SetLocation(100, 4, 100, 100);

                    */

                };

            LoadImages();
        }
Example #27
0
        CPos ChooseRallyLocationNear(Actor self, CPos startPos)
        {
            List<CPos> possibleRallyPoints = new List<CPos>();

            if (self.Info.Name.Equals("spen") || self.Info.Name.Equals("syrd"))
                possibleRallyPoints = world.FindTilesInCircle(startPos, 16).Where(a => world.GetTerrainType(new CPos(a.X, a.Y)).Equals("Water")).ToList();
            else
                possibleRallyPoints = world.FindTilesInCircle(startPos, 8).Where(IsRallyPointValid).ToList();

            if (possibleRallyPoints.Count == 0)
                return startPos;

            return possibleRallyPoints.Random(random);
        }
Example #28
0
		/// <summary>
		/// Uses WM, attacking targets.
		/// </summary>
		/// <param name="attacker"></param>
		/// <param name="skill"></param>
		/// <param name="targetAreaId"></param>
		/// <param name="unkInt1"></param>
		/// <param name="unkInt2"></param>
		public void Use(Creature attacker, Skill skill, long targetAreaId, int unkInt1, int unkInt2)
		{
			var range = this.GetRange(attacker, skill);
			var targets = attacker.GetTargetableCreaturesInRange(range, TargetableOptions.AddAttackRange);

			// Check targets
			if (targets.Count == 0)
			{
				Send.Notice(attacker, Localization.Get("There isn't a target nearby to use that on."));
				Send.SkillUseSilentCancel(attacker);
				return;
			}

			// Create actions
			var cap = new CombatActionPack(attacker, skill.Info.Id);

			var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId);
			aAction.Set(AttackerOptions.Result);
			aAction.Stun = CombatMastery.GetAttackerStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);

			cap.Add(aAction);

			var survived = new List<Creature>();
			var rnd = RandomProvider.Get();

			// Check crit
			var crit = false;
			if (attacker.Skills.Has(SkillId.CriticalHit, SkillRank.RF))
				crit = (rnd.Next(100) < attacker.GetTotalCritChance(0));

			// Handle all targets
			foreach (var target in targets)
			{
				target.StopMove();

				var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
				tAction.Delay = 300; // Usually 300, sometimes 350?

				// Calculate damage
				var damage = attacker.GetRndTotalDamage();
				damage *= skill.RankData.Var1 / 100f;

				// Elementals
				damage *= attacker.CalculateElementalDamageMultiplier(target);

				// Crit bonus
				if (crit)
					CriticalHit.Handle(attacker, 100, ref damage, tAction);

				// Handle skills and reductions
				SkillHelper.HandleDefenseProtection(target, ref damage);
				SkillHelper.HandleConditions(attacker, target, ref damage);
				Defense.Handle(aAction, tAction, ref damage);
				ManaShield.Handle(target, ref damage, tAction);
				HeavyStander.Handle(attacker, target, ref damage, tAction);

				// Clean Hit if not defended nor critical
				if (tAction.SkillId != SkillId.Defense && !tAction.Has(TargetOptions.Critical))
					tAction.Set(TargetOptions.CleanHit);

				// Take damage if any is left
				if (damage > 0)
					target.TakeDamage(tAction.Damage = damage, attacker);

				// Knock down on deadly
				if (target.Conditions.Has(ConditionsA.Deadly))
				{
					tAction.Set(TargetOptions.KnockDown);
					tAction.Stun = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);
				}

				// Finish if dead, knock down if not defended
				if (target.IsDead)
					tAction.Set(TargetOptions.KnockDownFinish);
				else if (tAction.SkillId != SkillId.Defense)
					tAction.Set(TargetOptions.KnockDown);

				// Anger Management
				if (!target.IsDead)
					survived.Add(target);

				// Stun and shove if not defended
				if (target.IsDead || tAction.SkillId != SkillId.Defense || target.Conditions.Has(ConditionsA.Deadly))
				{
					tAction.Stun = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);
					target.Stability = Creature.MinStability;
					attacker.Shove(target, KnockbackDistance);
				}

				// Add action
				cap.Add(tAction);
			}

			// Update current weapon
			SkillHelper.UpdateWeapon(attacker, targets.FirstOrDefault(), ProficiencyGainType.Melee, attacker.RightHand, attacker.LeftHand);

			// Only select a random aggro if there is no aggro yet,
			// WM only aggroes one target at a time.
			if (survived.Count != 0 && attacker.Region.CountAggro(attacker) < 1)
			{
				var aggroTarget = survived.Random();
				aggroTarget.Aggro(attacker);
			}

			// Reduce life in old combat system
			if (!AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal"))
			{
				// Default reduction is 10%, it's reduced to 2% if attacker
				// has less max life than the rate is set to.
				var lifeReducationRate = skill.RankData.Var2;
				if (attacker.LifeMax < lifeReducationRate)
					lifeReducationRate /= 5;

				var amount = attacker.LifeMax / 100f * lifeReducationRate;
				attacker.ModifyLife(-amount);

				// TODO: Invincibility
			}

			// Spin it~
			Send.UseMotion(attacker, 8, 4);

			cap.Handle();

			Send.SkillUse(attacker, skill.Info.Id, targetAreaId, unkInt1, unkInt2);

			skill.Stacks = 0;
		}
Example #29
0
        private static void SendContinuousErrors(int delay, CancellationToken token, bool randomizeDates = false, int maxErrors = Int32.MaxValue, int uniqueCount = 1, bool randomizeCritical = true, int maxDaysOld = 90)
        {
            _sendingContinuous = true;
            Console.WriteLine();
            Console.WriteLine("Press 's' to stop sending.");
            int errorCount = 0;
            if (uniqueCount <= 0)
                uniqueCount = 1;

            var errorCodeList = new List<int>();
            for (int i = 0; i < uniqueCount; i++)
                errorCodeList.Add(_random.Next());

            Task.Factory.StartNew(delegate {
                while (errorCount < maxErrors) {
                    if (token.IsCancellationRequested) {
                        _sendingContinuous = false;
                        break;
                    }

                    SendError(randomizeDates, errorCodeList.Random(), randomizeCritical ? RandomHelper.GetBool() : false, writeToConsole: false, maxDaysOld: maxDaysOld);
                    errorCount++;

                    Console.SetCursorPosition(0, 13);
                    Console.WriteLine("Sent {0} errors.", errorCount);
                    Trace.WriteLine(String.Format("Sent {0} errors.", errorCount));

                    Thread.Sleep(delay);
                }
            }, token);
        }
Example #30
0
        public static IEnumerable<Person> GeneratePeople(string connectionString, int gameId, int count = 1)
        {
            var personInsert = new SqlInsertStatement(connectionString)
                                    .InsertInto("dbo.BZ_Person")
                                        .Column("GameId", gameId)
                                        .Column("GenderId")
                                        .Column("FirstName")
                                        .Column("LastName")
                                        .Column("Birthday")
                                        .Column("RetirementDate")
                                        .Column("PersonalityId", 1);

            for (var index = 0; index < count; index++)
            {
                var gender = (int)Utilities.GetRandomValue(Gender.None);

                var first = Utilities.GetRandomString(16).Replace("'", "''");

                var last = Utilities.GetRandomString(16).Replace("'", "''");

                var birthday = Utilities.GetRandomDate();

                var retirement = birthday.AddYears(Utilities.GetRandomInt(65, 85));

                var intensity = Utilities.GetRandomDecimal(0, 1);

                personInsert.Values()
                            .Value("GenderId", gender)
                            .Value("FirstName", first)
                            .Value("LastName", last)
                            .Value("Birthday", birthday)
                            .Value("RetirementDate", retirement);
            }

            personInsert.Execute();

            var select = new SqlSelectStatement(connectionString);

            select.Select("Id")
                    .Select("GenderId")
                    .Select("FirstName")
                    .Select("LastName")
                    .Select("Birthday")
                  .From("BZ_Person")
                  .WhereEquals("GameId", gameId);

            var output = select.ExecuteComplex<Person>();

            var skillIds = new SqlSelectStatement(connectionString)
                                .Select("Id")
                                .From("dbo.BZ_Skill_Definition")
                                .Execute<int>();

            var skillInsert = new SqlInsertStatement(connectionString)
                                    .InsertInto("dbo.BZ_Person_Skill")
                                    .Column("PersonId")
                                    .Column("SkillDefinitionId")
                                    .Column("Value")
                                    .Column("LearnRate")
                                    .Column("ForgetRate");

            var skillsProperty = typeof(Person).GetProperty("Skills");

            foreach (var person in output)
            {
                var remainingSkillIds = new List<int>(skillIds);

                var skills = new List<Skill>();

                var skillCount = Utilities.GetRandomInt(1, remainingSkillIds.Count);

                while (skillCount-- > 0)
                {
                    var skill = new Skill
                    {
                        ForgetRate = Utilities.GetRandomDecimal(0, 10),
                        LearnRate = Utilities.GetRandomDecimal(0, 10),
                        Value = Utilities.GetRandomDecimal(0, 255),
                        SkillDefinition = new SkillDefinition
                        {
                            Id = (byte)remainingSkillIds.Random()
                        }
                    };

                    remainingSkillIds.Remove(skill.SkillDefinition.Id);

                    skillInsert.Values()
                                .Value("PersonId", person.Id)
                                .Value("SkillDefinitionId", skill.SkillDefinition.Id)
                                .Value("Value", skill.Value)
                                .Value("LearnRate", skill.LearnRate)
                                .Value("ForgetRate", skill.ForgetRate);

                    skills.Add(skill);
                }

                skillsProperty.SetValue(person, skills);
            }

            skillInsert.Execute();

            return output;
        }