Exemplo n.º 1
0
 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;
 }