Ejemplo n.º 1
0
 private ItemUseResult UseOrb(int radius,bool never_target_enemies,Actor user,List<Tile> line,OrbTargetingDelegate orb_effect)
 {
     ItemUseResult result = new ItemUseResult(true,true);
     if(line == null){
         if(!identified[type]){
             radius = 0;
         }
         line = user.GetTargetTile(12,radius,false,!(never_target_enemies && identified[type]));
     }
     if(line != null){
         Tile t = line.LastOrDefault();
         Tile prev = line.LastBeforeSolidTile();
         Actor first = null;
         bool trigger_trap = true;
         Screen.CursorVisible = false;
         if(user != null){
             first = user.FirstActorInLine(line);
             B.Add(user.You("fling") + " the " + SingularName() + ". ",user);
             if(first != null && first != user){
                 trigger_trap = false;
                 t = first.tile();
                 if(player.CanSee(user)){
                     B.Add("It shatters on " + first.the_name + "! ",first);
                 }
                 else{
                     B.Add("Something shatters on " + first.the_name + "! ",first);
                 }
                 first.player_visibility_duration = -1;
                 first.attrs[AttrType.PLAYER_NOTICED]++;
             }
             else{
                 if(player.CanSee(user)){
                     B.Add("It shatters on " + t.the_name + "! ",t);
                 }
                 else{
                     B.Add("Something shatters on " + t.the_name + "! ",t);
                 }
             }
             user.AnimateProjectile(line.ToFirstSolidTileOrActor(),'*',color);
             Screen.CursorVisible = false;
         }
         else{
             trigger_trap = false;
         }
         Tile LOE_tile = t;
         if(!t.passable && prev != null){
             LOE_tile = prev;
         }
         orb_effect(t,LOE_tile,result);
         t.MakeNoise(2);
         if(trigger_trap && t.IsTrap()){
             t.TriggerTrap();
         }
         if(!revealed_by_light){
             result.IDed = false;
         }
     }
     else{
         result.used = false;
     }
     return result;
 }
Ejemplo n.º 2
0
        public static bool Telekinesis(bool cast, Actor user, Tile t)
        {
            bool wand = !cast;

            if (t == null)
            {
                return(false);
            }
            if (t != null)
            {
                if (wand && user == player && !Item.identified[ConsumableType.TELEKINESIS])
                {
                    Item.identified[ConsumableType.TELEKINESIS] = true;
                    B.Add("(It was a wand of telekinesis!) ");
                    B.Print(true);
                }
                List <Tile> ai_line = null;
                if (user != player && t == player.tile())
                {
                    var fires = user.TilesWithinDistance(12).Where(x => x.passable && x.actor() == null && x.Is(FeatureType.FIRE) && user.CanSee(x) && player.HasBresenhamLineWithCondition(x, false, y => y.passable && y.actor() == null));
                    if (fires.Count > 0)
                    {
                        ai_line = player.GetBestExtendedLineOfEffect(fires.Random());
                    }
                    else
                    {
                        if (wand)
                        {
                            ai_line = player.GetBestExtendedLineOfEffect(user);
                        }
                        else
                        {
                            ai_line = player.GetBestExtendedLineOfEffect(player.TileInDirection(Global.RandomDirection()));
                        }
                    }
                }
                Actor a = t.actor();
                if (a == null && t.inv == null && !t.Is(FeatureType.GRENADE) && t.Is(FeatureType.TROLL_CORPSE, FeatureType.TROLL_BLOODWITCH_CORPSE))
                {
                    ActorType   troll_type   = t.Is(FeatureType.TROLL_CORPSE)? ActorType.TROLL : ActorType.TROLL_BLOODWITCH;
                    FeatureType troll_corpse = t.Is(FeatureType.TROLL_CORPSE)? FeatureType.TROLL_CORPSE : FeatureType.TROLL_BLOODWITCH_CORPSE;
                    Event       troll_event  = Q.FindTargetedEvent(t, EventType.REGENERATING_FROM_DEATH);
                    troll_event.dead = true;
                    Actor troll = Actor.Create(troll_type, t.row, t.col);
                    foreach (Event e in Q.list)
                    {
                        if (e.target == troll && e.type == EventType.MOVE)
                        {
                            e.tiebreaker = troll_event.tiebreaker;
                            e.dead       = true;
                            break;
                        }
                    }
                    Actor.tiebreakers[troll_event.tiebreaker] = troll;
                    troll.symbol = '%';
                    troll.attrs[AttrType.CORPSE] = 1;
                    troll.Name  = new Name(troll.GetName(Possessive) + " corpse");
                    troll.curhp = troll_event.value;
                    troll.attrs[AttrType.PERMANENT_DAMAGE] = troll_event.secondary_value;
                    troll.attrs[AttrType.NO_ITEM]++;
                    t.features.Remove(troll_corpse);
                    a = troll;
                }
                if (a != null)
                {
                    string msg = "Throw " + a.GetName(true, The) + " in which direction? ";
                    if (a == player)
                    {
                        msg = "Throw yourself in which direction? ";
                    }
                    List <Tile> line = null;
                    if (user == player)
                    {
                        TargetInfo info = a.GetTarget(false, 12, 0, false, true, false, msg);
                        if (info != null)
                        {
                            line = info.extended_line;
                        }
                    }
                    else
                    {
                        line = ai_line;
                    }
                    if (line != null)
                    {
                        if (line.Count == 1 && line[0].actor() == user)
                        {
                            if (wand)
                            {
                                return(true);
                            }
                            return(false);
                        }
                        if (cast)
                        {
                            B.Add(user.GetName(false, The, Verb("cast")) + " telekinesis. ", user);
                            user.MakeNoise(6);                             //should match spellVolume, hack
                            if (a.type == ActorType.ALASI_BATTLEMAGE && !a.HasSpell(SpellType.TELEKINESIS))
                            {
                                a.curmp += Spell.Tier(SpellType.TELEKINESIS);
                                if (a.curmp > a.maxmp)
                                {
                                    a.curmp = a.maxmp;
                                }
                                a.GainSpell(SpellType.TELEKINESIS);
                                B.Add("Runes on " + a.GetName(false, The, Possessive) + " armor align themselves with the spell. ", a);
                            }
                        }
                        if (a == user && a == player)
                        {
                            B.Add("You throw yourself forward. ");
                        }
                        else
                        {
                            if (line.Count == 1)
                            {
                                B.Add(user.GetName(true, The, Verb("throw")) + " " + a.GetName(true, The) + " into the ceiling. ", user, a);
                            }
                            else
                            {
                                B.Add(user.GetName(true, The, Verb("throw")) + " " + a.GetName(true, The) + ". ", user, a);
                            }
                        }
                        B.DisplayContents();
                        user.attrs[AttrType.SELF_TK_NO_DAMAGE]   = 1;
                        a.attrs[AttrType.TELEKINETICALLY_THROWN] = 1;
                        a.attrs[AttrType.TURN_INTO_CORPSE]++;
                        if (line.Count == 1)
                        {
                            a.TakeDamage(DamageType.NORMAL, DamageClass.PHYSICAL, R.Roll(3, 6), user, "colliding with the ceiling");
                            a.CollideWith(a.tile());
                        }
                        else
                        {
                            a.tile().KnockObjectBack(a, line, 12, user);
                        }
                        a.attrs[AttrType.TELEKINETICALLY_THROWN] = 0;
                        user.attrs[AttrType.SELF_TK_NO_DAMAGE]   = 0;
                        if (a.curhp <= 0 && a.HasAttr(AttrType.REGENERATES_FROM_DEATH))
                        {
                            a.attrs[AttrType.TURN_INTO_CORPSE] = 0;
                            a.attrs[AttrType.CORPSE]           = 0;
                            a.attrs[AttrType.FROZEN]           = 0;
                            a.attrs[AttrType.INVULNERABLE]     = 0;
                            a.attrs[AttrType.SHIELDED]         = 0;
                            a.attrs[AttrType.BLOCKING]         = 0;
                            a.curhp = 1;                             //this is all pretty hacky - perhaps I should relocate the regenerating corpse through other means.
                            a.TakeDamage(DamageType.NORMAL, DamageClass.NO_TYPE, 500, null);
                        }
                        else
                        {
                            a.CorpseCleanup();
                        }
                    }
                    else
                    {
                        if (wand)
                        {
                            return(true);
                        }
                        return(false);
                    }
                }
                else
                {
                    bool blast_fungus = false;
                    if (t.type == TileType.BLAST_FUNGUS && !t.Is(FeatureType.GRENADE, FeatureType.WEB, FeatureType.FORASECT_EGG, FeatureType.BONES))
                    {
                        blast_fungus = true;
                    }
                    if (t.inv != null || blast_fungus)
                    {
                        Item   i        = t.inv;
                        string itemname = "";
                        if (blast_fungus)
                        {
                            itemname = "the blast fungus";
                        }
                        else
                        {
                            itemname = i.GetName(true, The, Extra);
                        }
                        string      msg  = "Throw " + itemname + " in which direction? ";
                        List <Tile> line = null;
                        if (user == player)
                        {
                            TargetInfo info = t.GetTarget(false, 12, 0, false, true, false, msg);
                            if (info != null)
                            {
                                line = info.extended_line;
                            }
                        }
                        else
                        {
                            line = ai_line;
                        }
                        if (line != null)
                        {
                            if (line.Count > 13)
                            {
                                line = line.ToCount(13);                                 //for range 12
                            }
                            if (cast)
                            {
                                B.Add(user.GetName(false, The, Verb("cast")) + " telekinesis. ", user);
                                user.MakeNoise(6);                                 //should match spellVolume
                            }
                            if (blast_fungus)
                            {
                                B.Add("The blast fungus is pulled from the floor. ", t);
                                B.Add("Its fuse ignites! ", t);
                                t.Toggle(null);
                                i = Item.Create(ConsumableType.BLAST_FUNGUS, t.row, t.col);
                                if (i != null)
                                {
                                    i.other_data        = 3;
                                    i.revealed_by_light = true;
                                    Q.Add(new Event(i, 100, EventType.BLAST_FUNGUS));
                                    Screen.AnimateMapCell(t.row, t.col, new colorchar('3', Color.Red), 100);
                                }
                            }
                            if (line.Count == 1)
                            {
                                B.Add(user.GetName(true, The, Verb("throw")) + " " + itemname + " into the ceiling. ", user, t);
                            }
                            else
                            {
                                B.Add(user.GetName(true, The, Verb("throw")) + " " + itemname + ". ", user, t);
                            }
                            B.DisplayContents();
                            if (i.quantity > 1)
                            {
                                i.quantity--;
                                bool revealed = i.revealed_by_light;
                                i = new Item(i, -1, -1);
                                i.revealed_by_light = revealed;
                            }
                            else
                            {
                                t.inv = null;
                                Screen.WriteMapChar(t.row, t.col, M.VisibleColorChar(t.row, t.col));
                            }
                            bool  trigger_traps = false;
                            Tile  t2            = line.LastBeforeSolidTile();
                            Actor first         = user.FirstActorInLine(line);
                            if (t2 == line.LastOrDefault() && first == null)
                            {
                                trigger_traps = true;
                            }
                            if (first != null)
                            {
                                t2 = first.tile();
                            }
                            line = line.ToFirstSolidTileOrActor();
                            //if(line.Count > 0){
                            //	line.RemoveAt(line.Count - 1);
                            //}
                            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);
                                    }
                                }
                            }
                            if (line.Count > 0)                             //or > 1 ?
                            {
                                user.AnimateProjectile(line, i.symbol, i.color);
                            }
                            if (first == user)
                            {
                                B.Add(user.GetName(false, The, Verb("catch")) + " it! ", user);
                                if (user.inv.Count < Global.MAX_INVENTORY_SIZE)
                                {
                                    user.GetItem(i);
                                }
                                else
                                {
                                    B.Add("Your pack is too full to fit anything else. ");
                                    i.ignored = true;
                                    user.tile().GetItem(i);
                                }
                            }
                            else
                            {
                                if (first != null)
                                {
                                    B.Add("It hits " + first.GetName(The) + ". ", first);
                                }
                                if (i.IsBreakable())
                                {
                                    B.Add($"{i.GetName(true,The,Extra,Verb("break"))}! ", t2);
                                    if (i.ItemClass == ConsumableClass.ORB)
                                    {
                                        i.Use(null, new List <Tile> {
                                            t2
                                        });
                                    }
                                    else
                                    {
                                        i.CheckForMimic();
                                    }
                                    t2.MakeNoise(4);
                                }
                                else
                                {
                                    t2.GetItem(i);
                                }
                                t2.MakeNoise(2);
                            }
                            if (first != null && first != user && first != player)
                            {
                                first.player_visibility_duration = -1;
                                first.attrs[AttrType.PLAYER_NOTICED]++;
                            }
                            else
                            {
                                if (trigger_traps && t2.IsTrap())
                                {
                                    t2.TriggerTrap();
                                }
                            }
                        }
                        else
                        {
                            if (wand)
                            {
                                return(true);
                            }
                            return(false);
                        }
                    }
                    else
                    {
                        if (!t.Is(FeatureType.GRENADE) && (t.Is(TileType.DOOR_C, TileType.DOOR_O, TileType.POISON_BULB) || t.Is(FeatureType.WEB, FeatureType.FORASECT_EGG, FeatureType.BONES)))
                        {
                            if (cast)
                            {
                                B.Add(user.GetName(false, The, Verb("cast")) + " telekinesis. ", user);
                                user.MakeNoise(6);                                 //should match spellVolume
                            }
                            if (t.Is(TileType.DOOR_C))
                            {
                                B.Add("The door slams open. ", t);
                                t.Toggle(null);
                            }
                            else
                            {
                                if (t.Is(TileType.DOOR_O))
                                {
                                    B.Add("The door slams open. ", t);
                                    t.Toggle(null);
                                }
                            }
                            if (t.Is(TileType.POISON_BULB))
                            {
                                t.Bump(0);
                            }
                            if (t.Is(FeatureType.WEB))
                            {
                                B.Add("The web is destroyed. ", t);
                                t.RemoveFeature(FeatureType.WEB);
                            }
                            if (t.Is(FeatureType.FORASECT_EGG))
                            {
                                B.Add("The egg is destroyed. ", t);
                                t.RemoveFeature(FeatureType.FORASECT_EGG);                                 //todo: forasect pathing?
                            }
                            if (t.Is(FeatureType.BONES))
                            {
                                B.Add("The bones are scattered. ", t);
                                t.RemoveFeature(FeatureType.BONES);
                            }
                        }
                        else
                        {
                            bool      grenade            = t.Is(FeatureType.GRENADE);
                            bool      barrel             = t.Is(TileType.BARREL);
                            bool      flaming_barrel     = barrel && t.IsBurning();
                            bool      torch              = t.Is(TileType.STANDING_TORCH);
                            string    feature_name       = "";
                            int       impact_damage_dice = 3;
                            colorchar vis = new colorchar(t.symbol, t.color);
                            switch (t.type)
                            {
                            case TileType.CRACKED_WALL:
                                feature_name = "cracked wall";
                                break;

                            case TileType.RUBBLE:
                                feature_name = "pile of rubble";
                                break;

                            case TileType.STATUE:
                                feature_name = "statue";
                                break;
                            }
                            if (grenade)
                            {
                                impact_damage_dice = 0;
                                feature_name       = "grenade";
                                vis.c     = ',';
                                vis.color = Color.Red;
                            }
                            if (flaming_barrel)
                            {
                                feature_name = "flaming barrel of oil";
                            }
                            if (barrel)
                            {
                                feature_name = "barrel";
                            }
                            if (torch)
                            {
                                feature_name = "torch";
                            }
                            if (feature_name == "")
                            {
                                if (wand)
                                {
                                    if (user == player)
                                    {
                                        B.Add("The wand grabs at empty space. ", t);
                                    }
                                    return(true);
                                }
                                return(false);
                            }
                            string msg           = "Throw the " + feature_name + " in which direction? ";
                            bool   passable_hack = !t.passable;
                            if (passable_hack)
                            {
                                t.passable = true;
                            }
                            List <Tile> line = null;
                            if (user == player)
                            {
                                TargetInfo info = t.GetTarget(false, 12, 0, false, true, false, msg);
                                if (info != null)
                                {
                                    line = info.extended_line;
                                }
                            }
                            else
                            {
                                line = ai_line;
                            }
                            if (passable_hack)
                            {
                                t.passable = false;
                            }
                            if (line != null)
                            {
                                if (cast)
                                {
                                    B.Add(user.GetName(false, The, Verb("cast")) + " telekinesis. ", user);
                                    user.MakeNoise(6);                                     //should match spellVolume
                                }
                                if (line.Count == 1)
                                {
                                    B.Add(user.GetName(true, The, Verb("throw")) + " the " + feature_name + " into the ceiling. ", user, t);
                                }
                                else
                                {
                                    B.Add(user.GetName(true, The, Verb("throw")) + " the " + feature_name + ". ", user, t);
                                }
                                B.DisplayContents();
                                user.attrs[AttrType.SELF_TK_NO_DAMAGE] = 1;
                                switch (t.type)
                                {
                                case TileType.CRACKED_WALL:
                                case TileType.RUBBLE:
                                case TileType.STATUE:
                                case TileType.BARREL:
                                case TileType.STANDING_TORCH:
                                    if (flaming_barrel)
                                    {
                                        t.RemoveFeature(FeatureType.FIRE);
                                    }
                                    t.Toggle(null, TileType.FLOOR);
                                    foreach (Tile neighbor in t.TilesAtDistance(1))
                                    {
                                        neighbor.solid_rock = false;
                                    }
                                    break;
                                }
                                if (grenade)
                                {
                                    t.RemoveFeature(FeatureType.GRENADE);
                                    Event e = Q.FindTargetedEvent(t, EventType.GRENADE);
                                    if (e != null)
                                    {
                                        e.dead = true;
                                    }
                                }
                                Screen.WriteMapChar(t.row, t.col, M.VisibleColorChar(t.row, t.col));
                                colorchar[,] mem = Screen.GetCurrentMap();
                                int current_row = t.row;
                                int current_col = t.col;
                                //
                                int knockback_strength = 12;
                                if (line.Count == 1)
                                {
                                    knockback_strength = 0;
                                }
                                int i = 0;
                                while (true)
                                {
                                    Tile t2 = line[i];
                                    if (t2 == t)
                                    {
                                        break;
                                    }
                                    ++i;
                                }
                                line.RemoveRange(0, i + 1);
                                while (knockback_strength > 0)                                 //if the knockback strength is greater than 1, you're passing *over* at least one tile.
                                {
                                    Tile t2 = line[0];
                                    line.RemoveAt(0);
                                    if (!t2.passable)
                                    {
                                        if (t2.Is(TileType.CRACKED_WALL, TileType.DOOR_C, TileType.HIDDEN_DOOR) && impact_damage_dice > 0)
                                        {
                                            string tilename = t2.GetName(true, The);
                                            if (t2.type == TileType.HIDDEN_DOOR)
                                            {
                                                tilename = "a hidden door";
                                                t2.Toggle(null);
                                            }
                                            B.Add("The " + feature_name + " flies into " + tilename + ". ", t2);
                                            t2.Toggle(null);
                                            Screen.WriteMapChar(current_row, current_col, mem[current_row, current_col]);
                                        }
                                        else
                                        {
                                            B.Add("The " + feature_name + " flies into " + t2.GetName(true, The) + ". ", t2);
                                            if (impact_damage_dice > 0)
                                            {
                                                t2.Bump(M.tile[current_row, current_col].DirectionOf(t2));
                                            }
                                            Screen.WriteMapChar(current_row, current_col, mem[current_row, current_col]);
                                        }
                                        knockback_strength = 0;
                                        break;
                                    }
                                    else
                                    {
                                        if (t2.actor() != null)
                                        {
                                            B.Add("The " + feature_name + " flies into " + t2.actor().GetName(true, The) + ". ", t2);
                                            if (t2.actor().type != ActorType.SPORE_POD && !t2.actor().HasAttr(AttrType.SELF_TK_NO_DAMAGE))
                                            {
                                                t2.actor().TakeDamage(DamageType.NORMAL, DamageClass.PHYSICAL, R.Roll(impact_damage_dice, 6), user, "colliding with a " + feature_name);
                                            }
                                            knockback_strength = 0;
                                            Screen.WriteMapChar(t2.row, t2.col, vis);
                                            Screen.WriteMapChar(current_row, current_col, mem[current_row, current_col]);
                                            current_row = t2.row;
                                            current_col = t2.col;
                                            break;
                                        }
                                        else
                                        {
                                            if (t2.Is(FeatureType.WEB))                                             //unless perhaps grenades should get stuck and explode in the web?
                                            {
                                                t2.RemoveFeature(FeatureType.WEB);
                                            }
                                            Screen.WriteMapChar(t2.row, t2.col, vis);
                                            Screen.WriteMapChar(current_row, current_col, mem[current_row, current_col]);
                                            current_row = t2.row;
                                            current_col = t2.col;
                                            Screen.GLUpdate();
                                            Thread.Sleep(20);
                                        }
                                    }
                                    //M.Draw();
                                    knockback_strength--;
                                }
                                Tile current = M.tile[current_row, current_col];
                                if (grenade)
                                {
                                    B.Add("The grenade explodes! ", current);
                                    current.ApplyExplosion(1, user, "an exploding grenade");
                                }
                                if (barrel)
                                {
                                    B.Add("The barrel smashes! ", current);
                                    List <Tile> cone  = current.TilesWithinDistance(1).Where(x => x.passable);
                                    List <Tile> added = new List <Tile>();
                                    foreach (Tile t3 in cone)
                                    {
                                        foreach (int dir in U.FourDirections)
                                        {
                                            if (R.CoinFlip() && t3.TileInDirection(dir).passable)
                                            {
                                                added.AddUnique(t3.TileInDirection(dir));
                                            }
                                        }
                                    }
                                    cone.AddRange(added);
                                    foreach (Tile t3 in cone)
                                    {
                                        t3.AddFeature(FeatureType.OIL);
                                        if (t3.actor() != null && !t3.actor().HasAttr(AttrType.OIL_COVERED, AttrType.SLIMED))
                                        {
                                            if (t3.actor().IsBurning())
                                            {
                                                t3.actor().ApplyBurning();
                                            }
                                            else
                                            {
                                                t3.actor().attrs[AttrType.OIL_COVERED] = 1;
                                                B.Add(t3.actor().GetName(false, The, Are) + " covered in oil. ", t3.actor());
                                                if (t3.actor() == player)
                                                {
                                                    Help.TutorialTip(TutorialTopic.Oiled);
                                                }
                                            }
                                        }
                                    }
                                    if (flaming_barrel)
                                    {
                                        current.ApplyEffect(DamageType.FIRE);
                                    }
                                }
                                if (torch)
                                {
                                    current.AddFeature(FeatureType.FIRE);
                                }
                                user.attrs[AttrType.SELF_TK_NO_DAMAGE] = 0;
                            }
                            else
                            {
                                if (wand)
                                {
                                    return(true);
                                }
                                return(false);
                            }
                        }
                    }
                }
            }
            else
            {
                return(false);
            }
            return(true);
        }
Ejemplo n.º 3
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;
 }