C&C Tiberium Alliances PvP/PvE Ranking, POI Holding and split base kill score.

Shows PvP/PvE Ranking of the players alliance in the PlayerWindow, also adds POIs the Player holds and splits pve/pvp score.

// ==UserScript==
// @name           C&C Tiberium Alliances PvP/PvE Ranking, POI Holding and split base kill score.
// @author         ViolentVin, KRS_L, YiannisS
// @description    Shows PvP/PvE Ranking of the players alliance in the PlayerWindow, also adds POIs the Player holds and splits pve/pvp score. 
// @namespace      pvp_rank_mod
// @include        https://prodgame*.alliances.commandandconquer.com/*/index.aspx*
// @grant          none
// @version        1.7.3
// ==/UserScript==

(function () {
    var PvpRankMod_main = function () {
  		var allianceId = null;
   		var allianceName = null;
   		var button = null;
   		var general = null;
   		var memberCount = null;
   		var playerInfoWindow = null;
   		var playerName = null;
   		var pvpHighScoreLabel = null;
        var poiTableLabel = null;
   		var rowData = null;
   		var tabView = null;
        var pData = null;
  		var dataTable = null;
		var pvpScoreLabel = null;
		var pveScoreLabel = null;
        var Bname = null;
        var Olv = null;
        var Dlv = null;
        var Blv = null;
        var Slv = null;
        var Cylev = null;
        var Dflev = null;
		var tableModel = null;
		var atableModel = null;
        var levelData = null;
		var baseCoords = null;
		var rowData1 = null;
        var pois = null;
        var rowData2 = [];

          
        function CreateMod() {
            try {
                console.log('PvP/PvE Ranking Mod + POI + Base Levels Loaded.');
                var tr = qx.locale.Manager.tr;
                playerInfoWindow = webfrontend.gui.info.PlayerInfoWindow.getInstance();
                if (PerforceChangelist >= 436669) { // 15.3 patch
					var eventType = "cellTap";
					general = playerInfoWindow.getChildren()[0].getChildren()[0].getChildren()[0].getChildren()[0].getChildren()[0].getChildren()[0].getChildren()[1].getChildren()[0];
				} else { //old
					var eventType = "cellClick";
					general = playerInfoWindow.getChildren()[0].getChildren()[0].getChildren()[0].getChildren()[0].getChildren()[0].getChildren()[1].getChildren()[0];
				}
                tabView = playerInfoWindow.getChildren()[0];
                playerName = general.getChildren()[1];

                allianceName = ClientLib.Data.MainData.GetInstance().get_Alliance().get_Name();
                // New PvP Ranking Tab-page
                var pvpRankingTab = new qx.ui.tabview.Page("Ranking");
                pvpRankingTab.setLayout(new qx.ui.layout.Canvas());
                pvpRankingTab.setPaddingTop(6);
                pvpRankingTab.setPaddingLeft(8);
                pvpRankingTab.setPaddingRight(10);
                pvpRankingTab.setPaddingBottom(8);
                // Label PvP Ranking
                pvpHighScoreLabel = new qx.ui.basic.Label("PvP and PvE for Alliance: ").set({
                    textColor: "text-value",
                    font: "font_size_13_bold"
                });
                pvpRankingTab.add(pvpHighScoreLabel);
 
                // Table to show the PvP Scores of each player
                dataTable = new webfrontend.data.SimpleColFormattingDataModel().set({
                    caseSensitiveSorting: false
                });
                dataTable.setColumns(["Name", "PvP", "PvE"], ["name", "pve", "pvp"]);
                dataTable.setColFormat(0, "<div style=\"cursor:pointer;color:" + webfrontend.gui.util.BBCode.clrLink + "\">", "</div>");
                var pvpTable = new webfrontend.gui.widgets.CustomTable(dataTable);
                pvpTable.addListener("eventType", playerInfo, this);
                var columnModel = pvpTable.getTableColumnModel();
                columnModel.setColumnWidth(0, 200);
                columnModel.setColumnWidth(1, 80);
                columnModel.setColumnWidth(2, 80);
                columnModel.setDataCellRenderer(0, new qx.ui.table.cellrenderer.Html());
                pvpTable.setStatusBarVisible(false);
                pvpTable.setColumnVisibilityButtonVisible(false);
                pvpRankingTab.add(pvpTable, {
                    left: 0,
                    top: 25,
                    right: 0,
                    bottom: 0
                });
                // Add Tab page to the PlayerInfoWindow
                tabView.add(pvpRankingTab);
                
                // POI Tab
                var poiTab = new qx.ui.tabview.Page("POI");
				poiTab.setLayout(new qx.ui.layout.Canvas());
				poiTab.setPaddingTop(6);
				poiTab.setPaddingLeft(8);
				poiTab.setPaddingRight(10);
				poiTab.setPaddingBottom(8);
                poiTableLabel = new qx.ui.basic.Label("Player sits on these POIs").set({
                    textColor: "text-value",
                    font: "font_size_13_bold"
                });
                poiTab.add(poiTableLabel);
				tableModel = new webfrontend.data.SimpleColFormattingDataModel().set({
					caseSensitiveSorting: false
				});
				tableModel.setColumns([tr("POI Type"), tr("Level"), tr("Score"), tr("Coordinates"), tr("Base Name")], ["t", "l", "s", "c", "basen"]);
				tableModel.setColFormat(3, "<div style=\"cursor:pointer;color:" + webfrontend.gui.util.BBCode.clrLink + "\">", "</div>");
				var poiTable = new webfrontend.gui.widgets.CustomTable(tableModel);
				//poiTable.addListener("eventType", centerCoords, this);
				var columnModel = poiTable.getTableColumnModel();
				columnModel.setColumnWidth(0, 190);
				columnModel.setColumnWidth(1, 45);
				columnModel.setColumnWidth(2, 80);
				columnModel.setColumnWidth(3, 80);
				columnModel.setColumnWidth(4, 200);                
				columnModel.setDataCellRenderer(3, new qx.ui.table.cellrenderer.Html());
                //columnModel.getDataCellRenderer(1).setUseAutoAlign(true);
				columnModel.getDataCellRenderer(2).setUseAutoAlign(false);
				poiTable.setStatusBarVisible(false);
				poiTable.setColumnVisibilityButtonVisible(true);
				poiTab.add(poiTable, {
					left: 0,
					top: 25,
					right: 0,
					bottom: 0
				});
				tabView.add(poiTab);

                // Alliance POIs Tab
                var apoiTab = new qx.ui.tabview.Page("Alliance POIs");
				apoiTab.setLayout(new qx.ui.layout.Canvas());
				apoiTab.setPaddingTop(6);
				apoiTab.setPaddingLeft(8);
				apoiTab.setPaddingRight(10);
				apoiTab.setPaddingBottom(8);
                var apoiTableLabel = new qx.ui.basic.Label("Alliance members are holding the following POIs").set({
                    textColor: "text-value",
                    font: "font_size_13_bold"
                });
                apoiTab.add(apoiTableLabel);
				atableModel = new webfrontend.data.SimpleColFormattingDataModel().set({
					caseSensitiveSorting: false
				});
				atableModel.setColumns([tr("POI Type"), tr("Level"), tr("Score"), tr("Coordinates"), tr("Player Name"), tr("Base Name")], ["t", "l", "s", "c", "p", "basen"]);
				atableModel.setColFormat(3, "<div style=\"cursor:pointer;color:" + webfrontend.gui.util.BBCode.clrLink + "\">", "</div>");
				atableModel.setColFormat(4, "<div style=\"cursor:pointer;color:" + webfrontend.gui.util.BBCode.clrLink + "\">", "</div>");
                var apoiTable = new webfrontend.gui.widgets.CustomTable(atableModel);
				//apoiTable.addListener("eventType", centerCoords, this);
				var columnModel = apoiTable.getTableColumnModel();
				columnModel.setColumnWidth(0, 190);
				columnModel.setColumnWidth(1, 45);
				columnModel.setColumnWidth(2, 80);
				columnModel.setColumnWidth(3, 80);
                columnModel.setColumnWidth(4, 130);
				columnModel.setColumnWidth(5, 115);                
				columnModel.getDataCellRenderer(2).setUseAutoAlign(false);
                columnModel.setDataCellRenderer(3, new qx.ui.table.cellrenderer.Html());
				columnModel.setDataCellRenderer(4, new qx.ui.table.cellrenderer.Html());
				apoiTable.setStatusBarVisible(false);
				apoiTable.setColumnVisibilityButtonVisible(true);
				apoiTab.add(apoiTable, {
					left: 0,
					top: 25,
					right: 0,
					bottom: 5
				});
				tabView.add(apoiTab);
                
                // Levels Tab
                var levelTab = new qx.ui.tabview.Page("Base Levels");
				levelTab.setLayout(new qx.ui.layout.Canvas());
				levelTab.setPaddingTop(6);
				levelTab.setPaddingLeft(8);
				levelTab.setPaddingRight(10);
				levelTab.setPaddingBottom(8);

				levelData = new webfrontend.data.SimpleColFormattingDataModel().set({
					caseSensitiveSorting: false
				});
                levelData.setColumns(["Name", "Lvl", "DL", "OL", "SW", "CY", "DF"], ["Bname", "Blv", "Dlv", "Olv", "Slv", "Cylev", "Dflev"]);
                levelData.setColFormat(0, "<div style=\"cursor:pointer;color:" + webfrontend.gui.util.BBCode.clrLink + "\">", "</div>");
				var levelTable = new webfrontend.gui.widgets.CustomTable(levelData);
				levelTable.addListener("eventType", centerCoords, this);

				var columnlModel = levelTable.getTableColumnModel();
				columnlModel.setColumnWidth(0, 180);
				columnlModel.setColumnWidth(1, 70);
				columnlModel.setColumnWidth(2, 70);
				columnlModel.setColumnWidth(3, 70);
				columnlModel.setColumnWidth(4, 70);
				columnlModel.setColumnWidth(5, 70);
				columnlModel.setColumnWidth(6, 70);
				columnlModel.setDataCellRenderer(0, new qx.ui.table.cellrenderer.Html());
				columnlModel.getDataCellRenderer(2).setUseAutoAlign(false);
				levelTable.setStatusBarVisible(false);
				levelTable.setColumnVisibilityButtonVisible(false);
				levelTab.add(levelTable, {
					left: 0,
					top: 0,
					right: 0,
					bottom: 0
				});
				tabView.add(levelTab);
                
                
                var pvpLabel = new qx.ui.basic.Label("- PvP:");
				pvpScoreLabel = new qx.ui.basic.Label("").set({
					textColor: "text-value",
					font: "font_size_13_bold"
				});
				general.add(pvpLabel, {
					row: 3,
					column: 3
				});
				general.add(pvpScoreLabel, {
					row: 3,
					column: 4
				});

				var pveLabel = new qx.ui.basic.Label("- PvE:");
				pveScoreLabel = new qx.ui.basic.Label("").set({
					textColor: "text-value",
					font: "font_size_13_bold"
				});
				general.add(pveLabel, {
					row: 4,
					column: 3
				});
				general.add(pveScoreLabel, {
					row: 4,
					column: 4
				});

                
                // Hook up callback when another user has been selected
                playerInfoWindow.addListener("close", onPlayerInfoWindowClose, this);
                playerName.addListener("changeValue", onPlayerChanged, this);

            } catch (e) {
                console.log("CreateMod: ", e);
            }
        }

        function playerInfo(e) {
			try {
                var pname = dataTable.getRowData(e.getRow())[0];
                if (e.getColumn() == 0) {
                    webfrontend.gui.util.BBCode.openPlayerProfile(pname);
                }    
			} catch (e) {
				console.log("PlayerName: ", e);
			}
		}

        function centerCoords(e) {
			try {
				var poiCoord = tableModel.getRowData(e.getRow())[3].split(":");
				if (e.getColumn() == 3) webfrontend.gui.UtilView.centerCoordinatesOnRegionViewWindow(Number(poiCoord[0]), Number(poiCoord[1]));
			} catch (e) {
				console.log("centerCoords: ", e);
			}
		}
        
        function baseinfos(e){
            try {
                var Cylv = null;
                var Cylev = null;
                var Dflv = null;
                var Dflev = null;
                var Slev = null;
                var aC = ClientLib.Data.MainData.GetInstance().get_Cities().get_AllCities().d;
                //console.log("aC =", ClientLib.Data.Cities().get_Cities());
                var pData = [];
                for (var sBID in aC) {
                    if (!aC.hasOwnProperty(sBID)) {
                        continue;
                    }
                    var sBase = aC[sBID];
                    if (sBase === undefined) {
                        throw new Error('unable to find base: ' + sBID);
                    }
                    var unitlData = sBase.get_CityBuildingsData();
                    Cylv = unitlData.GetUniqueBuildingByTechName(ClientLib.Base.ETechName.Construction_Yard);
                    Dflv = unitlData.GetUniqueBuildingByTechName(ClientLib.Base.ETechName.Defense_Facility);
                    Slev = unitlData.GetUniqueBuildingByTechName(ClientLib.Base.ETechName.Support_Ion);
                    if (Slev === null)
                        Slev = unitlData.GetUniqueBuildingByTechName(ClientLib.Base.ETechName.Support_Art);
                    if (Slev === null)
                        Slev = unitlData.GetUniqueBuildingByTechName(ClientLib.Base.ETechName.Support_Air);
                    if ( Cylv !== null) {
                        Cylev = Cylv.get_CurrentLevel();
                    }
                    if (Dflv !== null) {
                        Dflev = Dflv.get_CurrentLevel();
                    }
                    if (Slev !== null) {
                        Slv = Slev.get_TechGameData_Obj().dn.slice(0, 3) + " : " + Slev.get_CurrentLevel();
                    }
                    Bname = sBase.get_Name();
                    if (typeof Bname === 'string') {
                        Bname.replace(/\./g, '');
                    }
                    Blv = sBase.get_LvlBase();
                    Dlv = ('0' + sBase.get_LvlDefense().toFixed(2)).slice(-5);
                    Olv = ('0' + sBase.get_LvlOffense().toFixed(2)).slice(-5);
                    pData.push([Bname, Blv, Dlv, Olv, Slv, Cylev, Dflev]);
                }
                levelData.setData(pData);
                levelData.sortByColumn(3, false);
            } catch (e) {
                console.log("baseinfos: ", e);
            }
        }
        // Callback GetPublicPlayerInfoByName
        // [bde] => Forgotten Bases Destroyed
        // [d] => Player Bases Destroyed
        // [n] => Player Name
        function onPlayerInfoReceived(context, data) {
            try {
                var memberName = data.n;
                var pvp = data.d;
                var pve = data.bde;
                
                // Add player Base Levels.
                var tt = baseinfos();
                var abases = data.c;
                var abaseCoords = new Object();
                for (var i in abases) {
                   var abase = abases[i];
                   abaseCoords[i] = new Object();
                   abaseCoords[i]["x"] = abase.x;
                   abaseCoords[i]["y"] = abase.y;
                   abaseCoords[i]["n"] = abase.n;
                }
                for (var k in pois) {
                    var apoi = pois[k];
                    for (var j in abaseCoords) {
                        var distanceX = Math.abs(abaseCoords[j].x - apoi.x);
                        var distanceY = Math.abs(abaseCoords[j].y - apoi.y);
                        if (distanceX > 2 || distanceY > 2) continue;
                        if (distanceX == 2 && distanceY == 2) continue;
                        var aname = phe.cnc.gui.util.Text.getPoiInfosByType(apoi.t).name;
                        var alevel = apoi.l;
                        var ascore = ClientLib.Base.PointOfInterestTypes.GetScoreByLevel(apoi.l);
                        var acoords = phe.cnc.gui.util.Numbers.formatCoordinates(apoi.x, apoi.y);
                        var abasen = abaseCoords[j].n;
                        rowData2.push([aname, alevel, ascore, acoords, memberName, abasen]);
                        break;
                    }
                }
             
                // Add player with its PvP/PvE score.
                rowData.push([memberName, pvp, pve]);

                if (rowData.length == memberCount) {
                    // Show Alliance name in label.
                    pvpHighScoreLabel.setValue("PvP and PvE for Alliance: " + data.an);

                    dataTable.setData(rowData);
                    dataTable.sortByColumn(1, false);
                }
            } catch (e) {
                console.log("onPlayerInfoReceived: ", e);
            }
        }
      
        // GetPublicAllianceInfo Callback
        // [m] => Member Array
        // (
        //    [0] => Array
        //            [n] => Name
        // )
        // [mc]  => Member Count
        function onAllianceInfoReceived(context, data) {
            try {
   				rowData1 = [];
				pois = data.opois;
                for (var k in pois) {
					var poi = pois[k];
					for (var j in baseCoords) {
                        var distanceX = Math.abs(baseCoords[j].x - poi.x);
						var distanceY = Math.abs(baseCoords[j].y - poi.y);
						if (distanceX > 2 || distanceY > 2) continue;
						if (distanceX == 2 && distanceY == 2) continue;
						var name = phe.cnc.gui.util.Text.getPoiInfosByType(poi.t).name;
						var level = poi.l;
						var score = ClientLib.Base.PointOfInterestTypes.GetScoreByLevel(poi.l);
						var coords = phe.cnc.gui.util.Numbers.formatCoordinates(poi.x, poi.y);
                        var basen = baseCoords[j].n; 
						rowData1.push([name, level, score, coords, basen]);
						break;
					}
				}
				tableModel.setData(rowData1);
				tableModel.sortByColumn(0, true);  
                // Clear
                rowData = [];
                dataTable.setData(rowData);

                var members = data.m;
                memberCount = data.mc;

                for (var i in members) {
                    var member = members[i];

                    // For Each member (player); Get the PvP/PvE Score
                    if (member.n.length > 0) {
                        ClientLib.Net.CommunicationManager.GetInstance().SendSimpleCommand("GetPublicPlayerInfoByName", {
                            name: member.n
                        }, phe.cnc.Util.createEventDelegate(ClientLib.Net.CommandResult, this, onPlayerInfoReceived), null);
                    }
                }
                atableModel.setData(rowData2);
                atableModel.sortByColumn(0, true);
            } catch (e) {
                console.log("onAllianceInfoReceived: ", e);
            }
        }

        function onPlayerAllianceIdReceived(context, data) {
            try {
                // No need to recreate the RankingPage when player is member of same alliance
                if (data.a != allianceId) {
                    allianceId = data.a;
                    // Show Alliance name in label.
                    pvpHighScoreLabel.setValue("PvP and PvE for alliance: " + data.an + "     (loading plz wait)");

                    // Get Alliance MembersList
                    ClientLib.Net.CommunicationManager.GetInstance().SendSimpleCommand("GetPublicAllianceInfo", {
                        id: allianceId
                    }, phe.cnc.Util.createEventDelegate(ClientLib.Net.CommandResult, this, onAllianceInfoReceived), null);
                    pvpScoreLabel.setValue((data.bd - data.bde).toString());
                    pveScoreLabel.setValue(data.bde.toString());
                    var bases = data.c;
                    baseCoords = new Object();
                    for (var i in bases) {
                        var base = bases[i];
                        baseCoords[i] = new Object();
                        baseCoords[i]["x"] = base.x;
                        baseCoords[i]["y"] = base.y;
                        baseCoords[i]["n"] = base.n;
                    }
                    
                    rowData1 = [];
                    var pois = data.opois;
                    for (var k in pois) {
                        var poi = pois[k];
                        for (var j in baseCoords) {
                            var distanceX = Math.abs(baseCoords[j].x - poi.x);
                            var distanceY = Math.abs(baseCoords[j].y - poi.y);
                            if (distanceX > 2 || distanceY > 2) continue;
                            if (distanceX == 2 && distanceY == 2) continue;
                            var name = phe.cnc.gui.util.Text.getPoiInfosByType(poi.t).name;
                            var level = poi.l;
                            var score = ClientLib.Base.PointOfInterestTypes.GetScoreByLevel(poi.l);
                            var coords = phe.cnc.gui.util.Numbers.formatCoordinates(poi.x, poi.y);
                            var basen = baseCoords[j].n; 
                            rowData1.push([name, level, score, coords, basen]);
                            break;
                        }
                    }
                    tableModel.setData(rowData1);
                    tableModel.sortByColumn(0, true);
                }
                else {
                    pvpScoreLabel.setValue((data.bd - data.bde).toString());
                    pveScoreLabel.setValue(data.bde.toString());
                    var bases = data.c;
                    baseCoords = new Object();
                    for (var i in bases) {
                        var base = bases[i];
                        baseCoords[i] = new Object();
                        baseCoords[i]["x"] = base.x;
                        baseCoords[i]["y"] = base.y;
                        baseCoords[i]["n"] = base.n;
                    }
                    ClientLib.Net.CommunicationManager.GetInstance().SendSimpleCommand("GetPublicAllianceInfo", {
                        id: data.a
                    }, phe.cnc.Util.createEventDelegate(ClientLib.Net.CommandResult, this, onAllianceInfoReceived), null);
                    rowData1 = [];
                    var pois = data.opois;
                    for (var k in pois) {
                        var poi = pois[k];
                        for (var j in baseCoords) {
                            var distanceX = Math.abs(baseCoords[j].x - poi.x);
                            var distanceY = Math.abs(baseCoords[j].y - poi.y);
                            if (distanceX > 2 || distanceY > 2) continue;
                            if (distanceX == 2 && distanceY == 2) continue;
                            var name = phe.cnc.gui.util.Text.getPoiInfosByType(poi.t).name;
                            var level = poi.l;
                            var score = ClientLib.Base.PointOfInterestTypes.GetScoreByLevel(poi.l);
                            var coords = phe.cnc.gui.util.Numbers.formatCoordinates(poi.x, poi.y);
                            var basen = baseCoords[j].n; 
                            rowData1.push([name, level, score, coords, basen]);
                            break;
                        }
                    }
                    tableModel.setData(rowData1);
                    tableModel.sortByColumn(0, true);
                }
            } catch (e) {
                console.log("onPlayerAllianceIdReceived: ", e);
            }
        }


        function onPlayerChanged() {
            try {
                // Get Players AllianceId 
                if (playerName.getValue().length > 0) {
                    ClientLib.Net.CommunicationManager.GetInstance().SendSimpleCommand("GetPublicPlayerInfoByName", {
                        name: playerName.getValue()
                    }, phe.cnc.Util.createEventDelegate(ClientLib.Net.CommandResult, this, onPlayerAllianceIdReceived), null);
                }
                rowData2 = [];
            } catch (e) {
                console.log("onPlayerChanged: ", e);
            }
        }



        function onPlayerInfoWindowClose() {
            try {
                console.log("onPlayerinfoWindowClose");
   				pvpScoreLabel.setValue("");
				pveScoreLabel.setValue("");
				tableModel.setData([]);
                //dataTable.setData([]);
            } catch (e) {
                console.log("onPlayerInfoWindowClose: ", e);
            }
        }

        function PvpRankMod_checkIfLoaded() {
            try {
                if (typeof qx !== 'undefined' && typeof qx.locale !== 'undefined' && typeof qx.locale.Manager !== 'undefined') {
                    if (ClientLib.Data.MainData.GetInstance().get_Alliance().get_FirstLeaders() !== null && ClientLib.Data.MainData.GetInstance().get_Alliance().get_FirstLeaders().l.length != 0) {
                        CreateMod();
                    } else {
                        window.setTimeout(PvpRankMod_checkIfLoaded, 1000);
                    }
                } else {
                    window.setTimeout(PvpRankMod_checkIfLoaded, 1000);
                }
            } catch (e) {
                console.log("PvpRankMod_checkIfLoaded: ", e);
            }
        }

        if (/commandandconquer\.com/i.test(document.domain)) {
            window.setTimeout(PvpRankMod_checkIfLoaded, 1000);
        }
    };

    try {
        var PvpRankMod = document.createElement("script");
        PvpRankMod.innerHTML = "(" + PvpRankMod_main.toString() + ")();";
        PvpRankMod.type = "text/javascript";
        if (/commandandconquer\.com/i.test(document.domain)) {
            document.getElementsByTagName("head")[0].appendChild(PvpRankMod);
        }
    } catch (e) {
        console.log("PvpRankMod: init error: ", e);
    }
})();