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; }