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.PrintAll(); } 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.SetName(troll.name + "'s 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.TheName(true) + " 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.You("cast") + " telekinesis. ",user); 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.Your() + " 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.YouVisible("throw") + " " + a.TheName(true) + " into the ceiling. ",user,a); } else{ B.Add(user.YouVisible("throw") + " " + a.TheName(true) + ". ",user,a); } } B.DisplayNow(); 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.TheName(true); if(i.quantity > 1){ itemname = "the " + i.SingularName(); } } 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.You("cast") + " telekinesis. ",user); } 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.YouVisible("throw") + " " + itemname + " into the ceiling. ",user,t); } else{ B.Add(user.YouVisible("throw") + " " + itemname + ". ",user,t); } B.DisplayNow(); 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.You("catch",true) + " 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.the_name + ". ",first); } if(i.IsBreakable()){ if(i.quantity > 1){ B.Add(i.TheName(true) + " break! ",t2); } else{ B.Add(i.TheName(true) + " breaks! ",t2); } if(i.NameOfItemType() == "orb"){ i.Use(null,new List<Tile>{t2}); } else{ i.CheckForMimic(); } } 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.You("cast") + " telekinesis. ",user); } 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.You("cast") + " telekinesis. ",user); } if(line.Count == 1){ B.Add(user.YouVisible("throw") + " the " + feature_name + " into the ceiling. ",user,t); } else{ B.Add(user.YouVisible("throw") + " the " + feature_name + ". ",user,t); } B.DisplayNow(); 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.TheName(true); 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.TheName(true) + ". ",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().TheName(true) + ". ",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; Game.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().YouAre() + " 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; }
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; }