defens finder

testie

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/539479/1607869/defens%20finder.js

Tabs.Defend = {
  tabOrder: 1000,
  tabLabel: 'Defend',
  tabDisabled: false,
  myDiv: null,
  timer: null,
  defendingCities: [],
  mapScanInProgress: false,
  mapScanX: 0,
  mapScanY: 0,
  mapScanRadius: 10,
  mapScanDelay: 500, // ms between map tile checks
  
  init: function(div) {
    var t = Tabs.Defend;
    t.myDiv = div;
    
    div.innerHTML = '<DIV class=divHeader align=center>' + tx('Defending Cities Scanner') + '</DIV>' +
      '<DIV id=btDefendMain class=btPopMain style="height:100%">' +
      '<CENTER><BR><DIV id=btDefendStatus style="min-width:400px;height:20px;font-weight:bold;"></DIV></CENTER>' +
      '<DIV id=btDefendOptions>' +
      '<TABLE width=100% class=xtab><TR>' +
      '<TD><B>Scan Center:</B> X: <INPUT id=btDefendScanX type=text size=3 maxlength=3 value="' + uW.currentcityid.x + '" /> ' +
      'Y: <INPUT id=btDefendScanY type=text size=3 maxlength=3 value="' + uW.currentcityid.y + '" /></TD>' +
      '<TD>Radius: <INPUT id=btDefendScanRadius type=text size=2 maxlength=2 value="10" /></TD>' +
      '<TD align=right><INPUT id=btDefendScanMap type=button value="Scan Map" /></TD>' +
      '</TR></TABLE>' +
      '<HR>' +
      '<TABLE width=100% class=xtab><TR>' +
      '<TD><INPUT id=btDefendShowOwn type=checkbox checked /> Show my cities</TD>' +
      '<TD><INPUT id=btDefendShowAlliance type=checkbox checked /> Show alliance cities</TD>' +
      '<TD><INPUT id=btDefendShowOthers type=checkbox checked /> Show enemy cities</TD>' +
      '</TR></TABLE>' +
      '</DIV>' +
      '<DIV id=btDefendProgress style="width:100%;height:20px;margin-top:5px;display:none;">' +
      '<DIV style="width:100%;height:10px;background-color:#ddd;border:1px solid #888;">' +
      '<DIV id=btDefendProgressBar style="width:0%;height:10px;background-color:#00a;"></DIV>' +
      '</DIV>' +
      '<DIV id=btDefendProgressText style="text-align:center;font-size:10px;margin-top:2px;"></DIV>' +
      '</DIV>' +
      '<DIV id=btDefendCityList style="max-height:400px; overflow-y:auto;margin-top:10px;"></DIV>' +
      '</DIV>';
    
    // Event listeners
    ById('btDefendScanMap').addEventListener('click', t.startMapScan, false);
    ById('btDefendShowOwn').addEventListener('change', t.filterResults, false);
    ById('btDefendShowAlliance').addEventListener('change', t.filterResults, false);
    ById('btDefendShowOthers').addEventListener('change', t.filterResults, false);
    
    // Initial message
    ById('btDefendStatus').innerHTML = 'Ready to scan for defending cities on the map';
  },
  
  show: function() {
    var t = Tabs.Defend;
    // Update center coordinates to current city when tab is shown
    if (uW.currentcityid) {
      ById('btDefendScanX').value = uW.currentcityid.x;
      ById('btDefendScanY').value = uW.currentcityid.y;
    }
  },
  
  hide: function() {
    var t = Tabs.Defend;
    // Stop any ongoing scan when tab is hidden
    t.stopMapScan();
  },
  
  startMapScan: function() {
    var t = Tabs.Defend;
    
    if (t.mapScanInProgress) {
      t.stopMapScan();
      return;
    }
    
    // Get scan parameters
    t.mapScanX = parseInt(ById('btDefendScanX').value);
    t.mapScanY = parseInt(ById('btDefendScanY').value);
    t.mapScanRadius = parseInt(ById('btDefendScanRadius').value);
    
    // Validate inputs
    if (isNaN(t.mapScanX) || isNaN(t.mapScanY) || isNaN(t.mapScanRadius)) {
      ById('btDefendStatus').innerHTML = '<SPAN style="color:#800;">Invalid coordinates or radius!</SPAN>';
      return;
    }
    
    if (t.mapScanRadius < 1) t.mapScanRadius = 1;
    if (t.mapScanRadius > 35) t.mapScanRadius = 35; // Limit to reasonable size
    
    // Reset results
    t.defendingCities = [];
    t.mapScanInProgress = true;
    ById('btDefendScanMap').value = "Stop Scan";
    
    // Show progress bar
    ById('btDefendProgress').style.display = '';
    ById('btDefendProgressBar').style.width = '0%';
    ById('btDefendProgressText').innerHTML = 'Preparing scan...';
    ById('btDefendStatus').innerHTML = 'Scanning map for defending cities...';
    
    // Create list of coordinates to scan
    t.scanCoords = [];
    for (var x = t.mapScanX - t.mapScanRadius; x <= t.mapScanX + t.mapScanRadius; x++) {
      for (var y = t.mapScanY - t.mapScanRadius; y <= t.mapScanY + t.mapScanRadius; y++) {
        // Check if coordinates are within map bounds
        if (x >= 0 && x <= 749 && y >= 0 && y <= 749) {
          // Calculate distance from center
          var dist = Math.sqrt(Math.pow(x - t.mapScanX, 2) + Math.pow(y - t.mapScanY, 2));
          if (dist <= t.mapScanRadius) {
            t.scanCoords.push({x: x, y: y});
          }
        }
      }
    }
    
    t.totalTiles = t.scanCoords.length;
    t.tilesScanned = 0;
    
    // Start scanning
    t.scanNextTile();
  },
  
  scanNextTile: function() {
    var t = Tabs.Defend;
    
    if (!t.mapScanInProgress || t.scanCoords.length === 0) {
      t.finishMapScan();
      return;
    }
    
    // Get next coordinate to scan
    var coord = t.scanCoords.shift();
    t.tilesScanned++;
    
    // Update progress
    var progress = Math.floor((t.tilesScanned / t.totalTiles) * 100);
    ById('btDefendProgressBar').style.width = progress + '%';
    ById('btDefendProgressText').innerHTML = 'Scanning: ' + t.tilesScanned + ' / ' + t.totalTiles + ' tiles';
    
    // Check map data for this tile
    uW.cm.MapController.fetchTileData(coord.x, coord.y, function(result) {
      if (result && result.tileInfo) {
        var tile = result.tileInfo;
        
        // Check if it's a city and if it's defending
        if (tile.tileType == 51 && tile.cityInfo) { // 51 is city tile type
          var cityInfo = tile.cityInfo;
          
          // Check if city is defending (look for defense status or defense boost)
          var isDefending = false;
          
          // Method 1: Check defense status directly if available
          if (cityInfo.defStatus && cityInfo.defStatus == 1) {
            isDefending = true;
          }
          
          // Method 2: Check for defense boost effects
          if (cityInfo.effects) {
            for (var i = 0; i < cityInfo.effects.length; i++) {
              var effect = cityInfo.effects[i];
              // Defense boost effects typically have IDs in certain ranges
              // This is an approximation - actual IDs may vary
              if (DefenceEffects.indexOf(effect.effectId) >= 0) {
                isDefending = true;
                break;
              }
            }
          }
          
          if (isDefending) {
            // Determine ownership type
            var ownerType = "enemy";
            if (cityInfo.playerId == uW.tvuid) {
              ownerType = "own";
            } else if (cityInfo.allianceId && cityInfo.allianceId == uW.seed.allianceInfo.allianceId) {
              ownerType = "alliance";
            }
            
            t.defendingCities.push({
              x: coord.x,
              y: coord.y,
              name: cityInfo.cityName || "Unknown City",
              ownerName: cityInfo.playerName || "Unknown Player",
              ownerType: ownerType,
              might: cityInfo.totalMight || 0
            });
          }
        }
      }
      
      // Schedule next tile scan with delay to prevent server overload
      setTimeout(t.scanNextTile, t.mapScanDelay);
    });
  },
  
  stopMapScan: function() {
    var t = Tabs.Defend;
    t.mapScanInProgress = false;
    ById('btDefendScanMap').value = "Scan Map";
    ById('btDefendStatus').innerHTML = 'Scan stopped. Found ' + t.defendingCities.length + ' defending cities.';
  },
  
  finishMapScan: function() {
    var t = Tabs.Defend;
    t.mapScanInProgress = false;
    ById('btDefendScanMap').value = "Scan Map";
    ById('btDefendStatus').innerHTML = 'Scan complete! Found ' + t.defendingCities.length + ' defending cities.';
    ById('btDefendProgress').style.display = 'none';
    
    // Display results
    t.displayResults();
  },
  
  filterResults: function() {
    var t = Tabs.Defend;
    t.displayResults();
  },
  
  displayResults: function() {
    var t = Tabs.Defend;
    
    // Get filter settings
    var showOwn = ById('btDefendShowOwn').checked;
    var showAlliance = ById('btDefendShowAlliance').checked;
    var showOthers = ById('btDefendShowOthers').checked;
    
    // Filter cities based on settings
    var filteredCities = t.defendingCities.filter(function(city) {
      if (city.ownerType === "own" && !showOwn) return false;
      if (city.ownerType === "alliance" && !showAlliance) return false;
      if (city.ownerType === "enemy" && !showOthers) return false;
      return true;
    });
    
    var m = '<TABLE width=100% class=xtab><TR class="xtabHD">' +
            '<TD width=15%>Coordinates</TD>' +
            '<TD width=25%>City Name</TD>' +
            '<TD width=25%>Owner</TD>' +
            '<TD width=15%>Might</TD>' +
            '<TD width=20%>Actions</TD></TR>';
    
    if (filteredCities.length === 0) {
      m += '<TR><TD colspan=5 align=center><BR><SPAN style="color:#800;">No defending cities found matching your filters.</SPAN></TD></TR>';
    } else {
      // Sort cities by distance from scan center
      filteredCities.sort(function(a, b) {
        var distA = Math.sqrt(Math.pow(a.x - t.mapScanX, 2) + Math.pow(a.y - t.mapScanY, 2));
        var distB = Math.sqrt(Math.pow(b.x - t.mapScanX, 2) + Math.pow(b.y - t.mapScanY, 2));
        return distA - distB;
      });
      
      for (var i = 0; i < filteredCities.length; i++) {
        var city = filteredCities[i];
        var rowClass = i % 2 ? 'evenRow' : 'oddRow';
        var ownerColor = '#000';
        
        // Color-code by owner type
        if (city.ownerType === "own") {
          ownerColor = '#080'; // Green for own cities
        } else if (city.ownerType === "alliance") {
          ownerColor = '#008'; // Blue for alliance cities
        } else {
          ownerColor = '#800'; // Red for enemy cities
        }
        
        m += '<TR class="' + rowClass + '">' +
             '<TD>(' + city.x + ',' + city.y + ')</TD>' +
             '<TD>' + city.name + '</TD>' +
             '<TD style="color:' + ownerColor + ';">' + city.ownerName + '</TD>' +
             '<TD>' + addCommas(city.might) + '</TD>' +
             '<TD>' +
             '<INPUT type=button value="View" class="btDefendViewMap" x="' + city.x + '" y="' + city.y + '" /> &nbsp;';
             
        // Add attack button for enemy cities
        if (city.ownerType === "enemy") {
          m += '<INPUT type=button value="Attack" class="btDefendAttack" x="' + city.x + '" y="' + city.y + '" />';
        }
        
        m += '</TD></TR>';
      }
    }
    
    m += '</TABLE>';
    ById('btDefendCityList').innerHTML = m;
    
    // Add event listeners to buttons
    var mapButtons = document.getElementsByClassName('btDefendViewMap');
    for (var i = 0; i < mapButtons.length; i++) {
      mapButtons[i].addEventListener('click', function() {
        var x = parseInt(this.getAttribute('x'));
        var y = parseInt(this.getAttribute('y'));
        uW.cm.MapController.centerMapOnCoord(x, y);
      }, false);
    }
    
    var attackButtons = document.getElementsByClassName('btDefendAttack');
    for (var i = 0; i < attackButtons.length; i++) {
      attackButtons[i].addEventListener('click', function() {
        var x = parseInt(this.getAttribute('x'));
        var y = parseInt(this.getAttribute('y'));
        t.prepareAttack(x, y);
      }, false);
    }
  },
  
  prepareAttack: function(x, y) {
    var t = Tabs.Defend;
    
    // Center map on target
    uW.cm.MapController.centerMapOnCoord(x, y);
    
    // Open attack dialog
    setTimeout(function() {
      // Find the city tile and click it
      var cityDiv = document.querySelector('div[data-tileclass="city"][data-x="' + x + '"][data-y="' + y + '"]');
      if (cityDiv) {
        nHtml.Click(cityDiv);
        
        // Wait for city info popup to appear
        setTimeout(function() {
          // Find and click the attack button
          var attackBtn = document.querySelector('.cityInfoAttackButton');
          if (attackBtn) {
            nHtml.Click(attackBtn);
          } else {
            actionLog('Could not find attack button for city at ' + x + ',' + y, 'DEFEND');
          }
        }, 1000);
      } else {
        actionLog('Could not find city at ' + x + ',' + y + ' on the map', 'DEFEND');
      }
    }, 1000);
  },
  
  // Helper function to detect if a city is defending
  isCityDefending: function(cityInfo) {
    // This is a more comprehensive check for defending status
    
    // Check direct defense status if available
    if (cityInfo.defStatus && cityInfo.defStatus == 1) {
      return true;
    }
    
    // Check for defense-related effects
    if (cityInfo.effects) {
      for (var i = 0; i < cityInfo.effects.length; i++) {
        var effectId = cityInfo.effects[i].effectId;
        
        // Check against known defense effect IDs
        if (DefenceEffects.indexOf(effectId) >= 0) {
          return true;
        }
        
        // Additional checks for specific defense effects
        // These IDs may need to be adjusted based on the game's current effect system
        if ([2, 18, 25, 30, 35, 40, 45, 51].indexOf(effectId) >= 0) {
          return true;
        }
      }
    }
    
    // Check for defense boost items
    if (cityInfo.activeItems) {
      for (var i = 0; i < cityInfo.activeItems.length; i++) {
        var item = cityInfo.activeItems[i];
        // Shield items typically have IDs like 362, 363, etc.
        if ([362, 363, 364, 365, 366].indexOf(item.itemId) >= 0) {
          return true;
        }
      }
    }
    
    return false;
  }
};