private ItemUseResult UseWand(bool targets_enemies,bool visible_line,Actor user,List<Tile> line,WandTargetingDelegate wand_effect) { ItemUseResult result = new ItemUseResult(true,true); if(charges == 0){ B.Add(TheName(true) + " is empty. Nothing happens. ",user); other_data = -1; result.IDed = false; return result; } TargetInfo info = null; if(user != player && line != null){ info = new TargetInfo(); info.extended_line = line; info.targeted = player.tile(); } if(!identified[type]){ targets_enemies = true; visible_line = false; } if(info == null){ info = user.GetTarget(false,12,0,!visible_line,false,targets_enemies,""); } if(info != null){ if(user != null && !user.HasLOE(info.targeted)){ foreach(Tile t in info.extended_line){ if(!t.passable){ info.targeted = t; break; } } } if(user == null || user.HasLOE(info.targeted)){ Tile LOE_tile = null; if(user != null){ LOE_tile = user.tile(); } else{ LOE_tile = info.extended_line[0]; } Tile prev = null; foreach(Tile t in info.extended_line){ if(!t.passable){ if(prev != null){ LOE_tile = prev; } break; } else{ if(t == info.targeted){ LOE_tile = t; break; } } prev = t; } wand_effect(LOE_tile,info,result); } } else{ result.used = false; } return result; }
public TargetInfo GetTarget(bool lookmode,int max_distance,int radius,bool no_line,bool extend_line,bool start_at_interesting_target,string always_displayed) { TargetInfo result = new TargetInfo(max_distance); MouseUI.PushButtonMap(MouseMode.Targeting); if(MouseUI.fire_arrow_hack){ MouseUI.CreateStatsButton(ConsoleKey.S,false,21,1); MouseUI.fire_arrow_hack = false; } ConsoleKeyInfo command; int r,c; int minrow = 0; int maxrow = Global.ROWS-1; int mincol = 0; int maxcol = Global.COLS-1; if(max_distance > 0){ minrow = Math.Max(minrow,row - max_distance); maxrow = Math.Min(maxrow,row + max_distance); mincol = Math.Max(mincol,col - max_distance); maxcol = Math.Min(maxcol,col + max_distance); } bool hide_descriptions = false; List<PhysicalObject> interesting_targets = new List<PhysicalObject>(); for(int i=1;(i<=max_distance || max_distance==-1) && i<=Math.Max(ROWS,COLS);++i){ foreach(Actor a in ActorsAtDistance(i)){ if(player.CanSee(a)){ //if(lookmode || ((player.IsWithinSightRangeOf(a) || a.tile().IsLit(player.row,player.col,false)) && player.HasLOE(a))){ if(lookmode || player.GetBestLineOfEffect(a).All(x=>x.passable || !x.seen)){ interesting_targets.Add(a); } } } } if(lookmode){ for(int i=1;(i<=max_distance || max_distance==-1) && i<=Math.Max(ROWS,COLS);++i){ foreach(Tile t in TilesAtDistance(i)){ if(t.Is(TileType.STAIRS,TileType.CHEST,TileType.FIREPIT,TileType.FIRE_GEYSER,TileType.FOG_VENT,TileType.POISON_GAS_VENT, TileType.POOL_OF_RESTORATION,TileType.BLAST_FUNGUS,TileType.BARREL,TileType.STANDING_TORCH,TileType.POISON_BULB,TileType.DEMONIC_IDOL) || t.Is(FeatureType.GRENADE,FeatureType.FIRE,FeatureType.TROLL_CORPSE,FeatureType.TROLL_BLOODWITCH_CORPSE,FeatureType.BONES, FeatureType.INACTIVE_TELEPORTAL,FeatureType.STABLE_TELEPORTAL,FeatureType.TELEPORTAL,FeatureType.POISON_GAS, FeatureType.FOG,FeatureType.PIXIE_DUST,FeatureType.SPORES,FeatureType.WEB,FeatureType.CONFUSION_GAS,FeatureType.THICK_DUST) || t.IsShrine() || t.inv != null || t.IsKnownTrap()){ //todo: update this with new terrain & features if(player.CanSee(t)){ interesting_targets.Add(t); } } } } } colorchar[,] mem = new colorchar[ROWS,COLS]; List<Tile> line = new List<Tile>(); List<Tile> oldline = new List<Tile>(); bool description_shown_last_time = false; int desc_row = -1; int desc_col = -1; int desc_height = -1; int desc_width = -1; for(int i=0;i<ROWS;++i){ for(int j=0;j<COLS;++j){ mem[i,j] = Screen.MapChar(i,j); } } string unseen_area_message = ""; if(!lookmode){ unseen_area_message = "Move cursor to choose target, then press Enter. "; } if(always_displayed == ""){ if(!start_at_interesting_target || interesting_targets.Count == 0){ if(lookmode){ B.DisplayNow("Move the cursor to look around. "); } else{ B.DisplayNow(unseen_area_message); } } } else{ B.DisplayNow(always_displayed); } if(lookmode){ if(!start_at_interesting_target || interesting_targets.Count == 0){ r = row; c = col; } else{ r = interesting_targets[0].row; c = interesting_targets[0].col; } } else{ if(player.target == null || !player.CanSee(player.target) || !player.HasLOE(player.target) || (max_distance > 0 && player.DistanceFrom(player.target) > max_distance)){ if(!start_at_interesting_target || interesting_targets.Count == 0){ r = row; c = col; } else{ r = interesting_targets[0].row; c = interesting_targets[0].col; } } else{ r = player.target.row; c = player.target.col; } } UI.MapCursor = new pos(r,c); bool first_iteration = true; bool done = false; //when done==true, we're ready to return 'result' Tile tc = M.tile[r,c]; while(!done){ Screen.ResetColors(); tc = M.tile[r,c]; Targeting_DisplayContents(tc,always_displayed,unseen_area_message,true,first_iteration); if(!lookmode){ bool blocked = false; Screen.CursorVisible = false; if(!no_line){ if(extend_line){ line = GetBestExtendedLineOfEffect(r,c); if(max_distance > 0 && line.Count > max_distance+1){ line.RemoveRange(max_distance+1,line.Count - max_distance - 1); } } else{ line = GetBestLineOfEffect(r,c); } } else{ line = new List<Tile>{M.tile[r,c]}; if(!player.HasBresenhamLineWithCondition(r,c,true,x=>!(x.seen && x.opaque))){ //"player" here might be better as "this" blocked = true; } } Targeting_ShowLine(tc,radius,mem,line,oldline,ref blocked,x=>{ if(x.seen && !x.passable && x != line.LastOrDefault()){ return true; } if(x.actor() != null && player.CanSee(x.actor()) && !no_line && x != line.LastOrDefault() && x != line[0]){ return true; } return false; }); foreach(Tile t in oldline){ Screen.WriteMapChar(t.row,t.col,mem[t.row,t.col]); } } else{ colorchar cch = mem[r,c]; cch.bgcolor = Color.Green; if(Global.LINUX && !Screen.GLMode){ //no bright bg in terminals cch.bgcolor = Color.DarkGreen; } if(cch.color == cch.bgcolor){ cch.color = Color.Black; } Screen.WriteMapChar(r,c,cch); line = new List<Tile>{M.tile[r,c]}; oldline.Remove(M.tile[r,c]); foreach(Tile t in oldline){ //to prevent the previous target appearing on top of the description box Screen.WriteMapChar(t.row,t.col,mem[t.row,t.col]); } if(!hide_descriptions){ if(M.actor[r,c] != null && M.actor[r,c] != this && player.CanSee(M.actor[r,c])){ bool description_on_right = false; int max_length = 29; if(c - 6 < max_length){ max_length = c - 6; } if(max_length < 20){ description_on_right = true; max_length = 29; } List<colorstring> desc = Actor.MonsterDescriptionBox(M.actor[r,c],false,max_length); if(description_on_right){ int start_c = COLS - desc[0].Length(); description_shown_last_time = true; desc_row = 0; desc_col = start_c; desc_height = desc.Count; desc_width = desc[0].Length(); for(int i=0;i<desc.Count;++i){ Screen.WriteMapString(i,start_c,desc[i]); } } else{ description_shown_last_time = true; desc_row = 0; desc_col = 0; desc_height = desc.Count; desc_width = desc[0].Length(); for(int i=0;i<desc.Count;++i){ Screen.WriteMapString(i,0,desc[i]); } } } else{ if(M.tile[r,c].inv != null && player.CanSee(r,c)){ bool description_on_right = false; int max_length = 29; if(c - 6 < max_length){ max_length = c - 6; } if(max_length < 20){ description_on_right = true; max_length = 29; } List<colorstring> desc = UI.ItemDescriptionBox(M.tile[r,c].inv,true,false,max_length); if(description_on_right){ int start_c = COLS - desc[0].Length(); description_shown_last_time = true; desc_row = 0; desc_col = start_c; desc_height = desc.Count; desc_width = desc[0].Length(); for(int i=0;i<desc.Count;++i){ Screen.WriteMapString(i,start_c,desc[i]); } } else{ description_shown_last_time = true; desc_row = 0; desc_col = 0; desc_height = desc.Count; desc_width = desc[0].Length(); for(int i=0;i<desc.Count;++i){ Screen.WriteMapString(i,0,desc[i]); } } } } } else{ //description_shown_last_time = false; } } oldline = new List<Tile>(line); if(radius > 0){ foreach(Tile t in M.tile[r,c].TilesWithinDistance(radius,true)){ oldline.AddUnique(t); } } first_iteration = false; M.tile[r,c].Cursor(); Screen.CursorVisible = true; command = Input.ReadKey().GetAction(); char ch = command.GetCommandChar(); if(!Targeting_HandleCommonCommands(command,ch,ref r,ref c,interesting_targets,ref done,minrow,maxrow,mincol,maxcol,!lookmode)){ switch(ch){ case '=': if(lookmode){ hide_descriptions = !hide_descriptions; } break; case (char)13: case 's': if(M.actor[r,c] != null && M.actor[r,c] != this && player.CanSee(M.actor[r,c]) && player.HasLOE(M.actor[r,c])){ player.target = M.actor[r,c]; } result.extended_line = GetBestExtendedLineOfEffect(r,c); result.targeted = M.tile[r,c]; done = true; break; case 'X': if(lookmode && this == player && B.YesOrNoPrompt("Travel to this location?")){ //player.path = player.GetPath(r,c); Tile nearest = M.tile[r,c]; PosArray<bool> known_reachable = M.tile.GetFloodFillArray(this.p,false,x=>(M.tile[x].passable || M.tile[x].IsDoorType(false)) && M.tile[x].seen); PosArray<int> distance_to_nearest_known_passable = M.tile.GetDijkstraMap(y=>M.tile[y].seen && (M.tile[y].passable || M.tile[y].IsDoorType(false)) && !M.tile[y].IsKnownTrap() && known_reachable[y],x=>false); if(!nearest.seen || nearest.IsKnownTrap() || !nearest.TilesWithinDistance(1).Any(x=>x.passable && known_reachable[x.p])){ nearest = nearest.TilesAtDistance(distance_to_nearest_known_passable[r,c]).Where(x=>x.seen && (x.passable || x.IsDoorType(false)) && !x.IsKnownTrap() && known_reachable[x.p]).WhereLeast(x=>x.ApproximateEuclideanDistanceFromX10(r,c)).LastOrDefault(); } player.path = player.GetPath(nearest.row,nearest.col,-1,true,true,Actor.UnknownTilePathingPreference.UnknownTilesAreClosed); player.path.StopAtBlockingTerrain(); Actor.interrupted_path = new pos(-1,-1); done = true; } break; } } UI.MapCursor = new pos(r,c); if(description_shown_last_time){ Screen.MapDrawWithStrings(mem,desc_row,desc_col,desc_height,desc_width); description_shown_last_time = false; } } Targeting_RemoveLine(tc,done,line,mem,radius); MouseUI.PopButtonMap(); if(result.extended_line == null){ return null; } return result; }