· 5 years ago · May 16, 2020, 03:14 AM
1//------------------------------
2//Tribal Wars script: Support Table Generator
3//Made by Erlend/Linoko
4//Last updated: 16. may 2020
5//------------------------------
6
7if(!premium){ //Ensure that premium account is activated
8 prompt("A premium account is required to run this script.");
9}
10else if(!document.URL.includes("mode=incomings") ){ //Ensure that the script is running on the right screen
11 var r = confirm("This script must be run from the incomings overview, where you check the attacks to be requested for support! Open this window?");
12 if (r === true) { //Open incoming overview if user clicks yes
13 window.open("/game.php?/&screen=overview_villages&mode=incomings","_self");
14 }
15}
16else{ //Define global variables
17 var allAttackers = [],
18 isArcherActive = checkCookie("isArcherActive");
19 main();
20}
21
22function main(){
23 var checkedAttacks = $(":checked","[class*='nowrap']").parent().parent(),
24 targetVillages = getTargetVillages(),
25 targetPlayer = game_data.player.name;
26 //Create output field:
27 if($("#outputField").length > 0) $("#outputField")[0].value="";
28 else setupOutput();
29 if(checkedAttacks.length===0)
30 $("#outputField")[0].value+="No checked attacks found! Mark the incomings you want to ask for support for, if you forgot to do this.\n\n";
31 $("#outputField")[0].value+="[b]Defender[/b]: [player]"+targetPlayer+"[/player]\n";
32 $("#outputField")[0].value+="[b]All-Attackers[/b]:\n";
33
34 for(var i=0;i<targetVillages.length;i++){ //Setup tables for each attacked village
35 if(i>=0) $("#outputField")[0].value+="\n[spoiler=separator][/spoiler]"; //Add separator between villages
36 var currentVillage = targetVillages[i],
37 currentAttacks = $("a:contains('"+currentVillage+"')",checkedAttacks).parent().parent();
38 formatHeader(checkedAttacks, currentVillage);
39 formatTable(currentAttacks);
40 formatAttackers();
41 }
42}
43
44function getTargetVillages(){ //Function to get attacked villages that are checked
45 var targets=[],
46 exists,
47 targetColumn = 1;
48 for(var i=0; i<checkedAttacks.length; i++){
49 exists=false;
50 var currentTarget = checkedAttacks[i].children[1].innerText.split(") K")[0].slice(-7); //Returns coords: "xxx|yyy"
51 for(var j=0; j<targets.length;j++){
52 if(currentTarget==targets[j]){
53 exists=true;
54 break;
55 }
56 }
57 if(exists===false) targets.push(currentTarget);
58 }
59 return targets;
60}
61
62//------------Table formatting-------------//
63function setupOutput(){
64 var outputField = document.createElement("TEXTAREA"),
65 outputId = document.createAttribute("id"),
66 outputStyle = document.createAttribute("style");
67 outputId.value = "outputField";
68 outputStyle.value = "width:90%;height:100px;margin:5px 5px 5px 5px";
69 outputField.setAttributeNode(outputId);
70 outputField.setAttributeNode(outputStyle);
71 $("#content_value")[0].appendChild(outputField);
72}
73function formatHeader(commandRows, attackedVillage){
74 var exists=false,
75 attackingPlayers=[];
76 for(var i=0;i<commandRows.length;i++){ //Get unique names of attacking players
77 exists=false;
78 var currentAttacker=commandRows[i].children[3].innerText;
79 for(var j=0;j<attackingPlayers.length;j++){
80 if(currentAttacker==attackingPlayers[j]){
81 exists=true;
82 break;
83 }
84 }
85 if(exists===false){
86 attackingPlayers[attackingPlayers.length]=currentAttacker;
87 }
88 }
89 $("#outputField")[0].value+="\n[b]Target village[/b]: [coord]"+attackedVillage+"[/coord]\n";
90 formatStationedTroops(attackedVillage);
91 $("#outputField")[0].value+= "\n[b]Attackers:[/b]\n";
92 for(var k=0;k<attackingPlayers.length;k++){
93 $("#outputField")[0].value+="[player]"+attackingPlayers[k]+"[/player] ("+attackingPlayers[k]+"-tribe)\n";
94 if(!allAttackers.includes(attackingPlayers[k])) allAttackers.push(attackingPlayers[k]);
95 }
96 getVillageData(attackedVillage);
97}
98
99function formatStationedTroops(attackedVillage){ //Creates troop table with placeholders for troop counts
100 var defUnits = (isArcherActive == "true") ? ['spear', 'sword', 'archer', 'spy', 'heavy'] : ['spear', 'sword', 'spy', 'heavy'],
101 unitHeader = "",
102 unitContent = "";
103
104 for(var i = 0; i < defUnits.length; i++){
105 unitHeader += "[unit]" + defUnits[i] + "[/unit][||]";
106 unitContent += attackedVillage+"-"+defUnits[i]+"[|]";
107 }
108 unitHeader += "[building]wall[/building][||][building]snob[/building]";
109 unitContent += attackedVillage+"-wall[|]"+attackedVillage+"-loyalty";
110
111 $("#outputField")[0].value+="\n[table]\n[**]"+ unitHeader +"[/**]\n";
112 $("#outputField")[0].value+="[*]"+ unitContent +"[/*]\n";
113 $("#outputField")[0].value+="[/table]";
114}
115
116function formatTable(commandRows){
117 var tableHeader = "\n[table]\n[**]Attacker[||]Origin[||]Unit[||]Arrival[||]Sent[||]Return[/**]\n";
118 $("#outputField")[0].value += tableHeader;
119
120 for(var i=0;i<commandRows.length;i++){
121 var tagImageLength = commandRows[i].getElementsByTagName("td")[0].getElementsByTagName("img").length,
122 sentTime = "",
123 returnTime = "",
124 duration;
125 if (tagImageLength == 2){ //Command row contains 2 images - meaning attack is tagged
126 var arrivalTime = commandRows[i].children[5].innerText.split(" ")[commandRows[i].children[5].innerText.split(" ").length-1].split(":"),
127 arrivalRawDate = commandRows[i].children[5].innerText.split(" "),
128 distance = getDistance(i,commandRows);
129 unitInfo = commandRows[i].getElementsByTagName("td")[0].getElementsByTagName("img")[1].src.split("/"),
130 date="",
131 unitType = unitInfo[unitInfo.length-1].split(".")[0];
132 arrivalRawDate.splice(arrivalRawDate.length-1);
133 arrivalDate = formatDate(arrivalRawDate);
134 duration = getTravelTime(unitType,distance);
135
136 var sentReturnTimes = getSentReturnTimes(arrivalTime,duration,arrivalDate);
137 sentTime = sentReturnTimes[0];
138 returnTime = sentReturnTimes[1];
139 }
140 else{
141 sentTime = "Not tagged";
142 returnTime = "Not tagged";
143
144 }
145 var currentAttacker = commandRows[i].children[3].innerText,
146 attackersVillage = commandRows[i].children[2].innerText.split(")")[commandRows[i].children[2].innerText.split(")").length-2].split("(")[commandRows[i].children[2].innerText.split(")")[commandRows[i].children[2].innerText.split(")").length-2].split("(").length-1],
147 unit,
148 rawDate = commandRows[i].children[5].innerText.split(" "),
149 date="",
150 arrival=rawDate[rawDate.length-1].split("\t")[0],
151 arrivalSplit=arrival.split(":"),
152 arrivalBig="",
153 arrivalMs=arrival.split(":")[arrival.split(":").length-1];
154
155
156 for(var k=0;k<arrivalSplit.length-1;k++){
157 arrivalBig+=arrivalSplit[k]+":";
158 }
159 try{
160 unit=$("[src*='.png']",commandRows[i])[1].src.split(".")[$("[src*='.png']",commandRows[i])[1].src.split(".").length-2].split("/")[$("[src*='.png']",commandRows[i])[1].src.split(".")[$("[src*='.png']",commandRows[i])[1].src.split(".").length-2].split("/").length-1];
161 }
162 catch(err) {
163 unit="not tagged"
164 }
165 rawDate[0] = rawDate[0].split("\t")[rawDate[0].split("\t").length-1];
166 for(var j=0;j<rawDate.length-1;j++){
167 date+=rawDate[j];
168 if(j<rawDate.length-2){
169 date+=" ";
170 }
171 }
172 $("#outputField")[0].value+=("[*][player]"+currentAttacker+"[/player]");
173 $("#outputField")[0].value+=("[|][coord]"+attackersVillage+"[/coord]");
174 $("#outputField")[0].value+=("[|][unit]"+unit+"[/unit]");
175 $("#outputField")[0].value+=("[|]"+arrivalDate+" at "+arrivalBig+"[color=#868686][size=7]"+arrivalMs+"[/size][/color]");
176 $("#outputField")[0].value+=("[|]"+sentTime);
177 $("#outputField")[0].value+=("[|]"+returnTime+"\n");
178 }
179 $("#outputField")[0].value+=("[/table]");
180}
181
182//-----------------------------------//
183//--------External data setup--------//
184
185function formatAttackers(){
186 attackerString = "[b]Attackers:[/b]\n";
187 for(var i = 0; i < allAttackers.length; i++){
188 attackerString += "[player]" + allAttackers[i] + "[/player] ("+allAttackers[i]+"-tribe)\n";
189 }
190 $("#outputField")[0].value = $("#outputField")[0].value.replace("[b]All-Attackers[/b]:\n", attackerString);
191
192 for(var i = 0; i < allAttackers.length; i++){
193 var attacker = allAttackers[i];
194 if($("#"+attacker+"_tribe_wrapper").length == 0){
195 var playerTribeDiv = document.createElement("div"),
196 playerTribeId = document.createAttribute("id"),
197 playerTribeStyle = document.createAttribute("style");
198 playerTribeId.value = attacker + "_tribe_wrapper";
199 playerTribeStyle.value = "display:none";
200 playerTribeDiv.setAttributeNode(playerTribeId);
201 playerTribeDiv.setAttributeNode(playerTribeStyle);
202 document.body.appendChild(playerTribeDiv);
203 }
204
205 $("#"+attacker+"_tribe_wrapper").bind('DOMSubtreeModified', function() {
206 var checkCount = 0; //Counting variable in case loop is stuck
207 while($("#outputField")[0].value.includes(attacker+"-tribe") && checkCount < 500){
208 var tribeTag = $("#"+attacker+"_tribe_wrapper")[0].innerText;
209 $("#outputField")[0].value = $("#outputField")[0].value.replace(attacker+"-tribe", "[ally]"+tribeTag+"[/ally]");
210 checkCount++;
211 }
212 $("#"+attacker+"_tribe_wrapper").unbind();
213 });
214 $.get("/game.php?screen=ranking&mode=player&name="+attacker.toLowerCase(), function(data){
215 var tribeColumn = $("th:contains(Tribe)", $("#player_ranking_table", data)[0])[0].cellIndex,
216 tribe = $("tr:contains(Linoko)", $("#player_ranking_table", data)[0])[0].children[tribeColumn].innerText.trim();
217 $("#"+attacker+"_tribe_wrapper")[0].innerText = tribe;
218 },'html');
219 }
220
221}
222
223function getVillageData(villageCoords){
224 //------General variables------//
225 var wallLevel = 0,
226 loyalty = 100,
227 villageUrl = $("a:contains("+villageCoords+")", $("#incomings_table"))[0].href,
228 villageCompactCoords = villageCoords.replace("|","");
229 villageUrl = villageUrl.split(".net")[1];
230 //----------------------------//
231 if($("#"+ villageCompactCoords + "_data_wrapper").length == 0){
232 var villageDiv = document.createElement("div"),
233 villageId = document.createAttribute("id"),
234 villageStyle = document.createAttribute("style");
235 villageId.value = villageCompactCoords + "_data_wrapper";
236 villageStyle.value = "display:none";
237 villageDiv.setAttributeNode(villageId);
238 villageDiv.setAttributeNode(villageStyle);
239 document.body.appendChild(villageDiv);
240 }
241 //------Troop variables------//
242 var defUnits = ['spear', 'sword', 'spy', 'heavy'],
243 unitColumn = [0, 0, 0, 0],
244 unitCount = [0, 0, 0, 0],
245 contentText = "";
246
247 if(isArcherActive == "true"){
248 defUnits = ['spear', 'sword', 'archer', 'spy', 'heavy'];
249 unitColumn.push(0);
250 unitCount.push(0);
251 }
252 //------------------------//
253
254 $("#"+villageCompactCoords+"_data_wrapper").bind('DOMSubtreeModified', function() {
255 //------Wall level------//
256 var wallCount = 0; //Counting variable in case loop is stuck
257 while($("#outputField")[0].value.includes(villageCoords+"-wall") && wallCount < 500){
258 var wallColour;
259 if(wallLevel == 20) wallColour = "[color=#000000]";
260 else if(wallLevel < 10) wallColour = "[color=#ff4800]";
261 else if(wallLevel < 15) wallColour = "[color=#ff6000]";
262 else if(wallLevel < 20) wallColour = "[color=#ff8a00]";
263 $("#outputField")[0].value = $("#outputField")[0].value.replace(villageCoords+"-wall", wallColour + wallLevel + "[/color]");
264 wallCount++;
265 }
266 //------------------------//
267 //------Loyalty------//
268 var loyaltyLoopCount = 0; //Counting variable in case loop is stuck
269 while($("#outputField")[0].value.includes(villageCoords+"-loyalty") && loyaltyLoopCount < 500){
270 var loyaltyColour;
271 if(loyalty == 100) loyaltyColour = "[color=#000000]";
272 else if(loyalty < 35) loyaltyColour = "[color=#ff4800]";
273 else if(loyalty < 75) loyaltyColour = "[color=#ff6000]";
274 else if(loyalty < 100) loyaltyColour = "[color=#ff8a00]";
275 $("#outputField")[0].value = $("#outputField")[0].value.replace(villageCoords+"-loyalty", loyaltyColour + loyalty + "[/color]");
276 loyaltyLoopCount++;
277 }
278 //------------------------//
279 //------Troop count------//
280 var troopLoopCount = 0; //Counting variable in case loop is stuck (if unable to change the forum post)
281 while($("#outputField")[0].value.includes(villageCoords+"-heavy") && troopLoopCount < 500){
282 for(var i = 0; i < defUnits.length; i++){
283 $("#outputField")[0].value = $("#outputField")[0].value.replace(villageCoords+"-"+defUnits[i], unitCount[i]);
284 }
285 troopLoopCount++;
286 }
287 //------------------------//
288
289 $("#"+villageCompactCoords+"_data_wrapper").unbind();
290 });
291 $.get(villageUrl, function(data){
292 if( $("a[href*=wall]", $("#overviewtable", data)[0]).length > 0) wallLevel = $("a[href*=wall]", $("#overviewtable", data))[0].innerText.match("\\d+")[0];
293 if($("b", $("#show_mood", data)[0]).length > 0) loyalty = $("b", $("#show_mood", data))[0].innerText;
294 for(var i = 0; i < defUnits.length; i++){
295 if($("img[src*=unit_"+defUnits[i]+"]", $(".all_unit", data)).length > 0) unitCount[i] = $("img[src*=unit_"+defUnits[i]+"]", $(".all_unit", data)).parent().parent()[0].innerText.match("\\d+")[0];
296 }
297 //Store the data in the villageCoord_data_wrapper:
298 var wrapperText = "[wall]"+wallLevel+"[/wall][loyalty]"+loyalty+"[/loyalty][troops]";
299 for(var i = 0; i < defUnits.length; i++) wrapperText += "[" + defUnits[i] + "]"+unitCount[i]+"[/"+defUnits[i]+"]";
300 wrapperText += "[/troops]";
301 $("#"+villageCompactCoords+"_data_wrapper")[0].innerText = wrapperText;
302 },'html');
303
304}
305//-----------------------------------//
306
307//------------Sent/Return Time Calculator-------------//
308function getDistance(i,commandRows){
309 var originCoords = commandRows[i].getElementsByTagName("td")[2].innerText.split(" "),
310 originLength = originCoords.length,
311 targetCoords = commandRows[i].getElementsByTagName("td")[1].innerText.split(" "),
312 targetLength = targetCoords.length,
313 x1,y1,x2,y2;
314 originCoords = originCoords[originLength-2].split("|");
315 targetCoords = targetCoords[targetLength-2].split("|");
316 x1 = Number(originCoords[0].split("(")[1]);
317 y1 = Number(originCoords[1].split(")")[0]);
318 x2 = Number(targetCoords[0].split("(")[1]);
319 y2 = Number(targetCoords[1].split(")")[0]);
320 return Math.abs(Math.sqrt(Math.pow((x2-x1),2)+Math.pow((y2-y1),2)));
321}
322function getTravelTime(unitType,distance){
323 var units = ["snob","ram","sword","axe","heavy","light","spy"],
324 speed,
325 unitSpeed = Number(checkCookie("unitSpeed")),
326 worldSpeed = Number(checkCookie("worldSpeed")),
327 speedConstant = worldSpeed*unitSpeed,
328 baseSpeed = [35,30,22,18,11,10,9];
329
330 var unitSpeedGroup = convertUnitSpeed(unitType); //returns one of the units in the list "units" above
331
332 switch (unitSpeedGroup) {
333 case units[0]:
334 speed = baseSpeed[0]/speedConstant;
335 break;
336 case units[1]:
337 speed = baseSpeed[1]/speedConstant;
338 break;
339 case units[2]:
340 speed = baseSpeed[2]/speedConstant;
341 break;
342 case units[3]:
343 speed = baseSpeed[3]/speedConstant;
344 break;
345 case units[4]:
346 speed = baseSpeed[4]/speedConstant;
347 break;
348 case units[5]:
349 speed = baseSpeed[5]/speedConstant;
350 break;
351 case units[6]:
352 speed = baseSpeed[6]/speedConstant;
353 break;
354 }
355 return Math.round((speed*distance)*60)*1000;
356
357}
358function getSentReturnTimes(arrival,duration,arrivalDate){ //Calculates sent and return times of command
359 var h = arrival[0],
360 m = arrival[1],
361 s = arrival[2],
362 ms = arrival[3],
363 arrivalSeconds = h*3600000+m*60000+s*1000,
364 sentTimeMs = arrivalSeconds - duration,
365 returnTimeMs = arrivalSeconds + duration,
366 sentDayDiff = Number(arrivalDate.substr(0,2))-new Date(getCurrentServerTime()).getDate(),
367 returnDayDiff = Number(arrivalDate.substr(0,2))-new Date(getCurrentServerTime()).getDate(),
368 sentTime,
369 returnTime;
370
371 while(sentTimeMs<0){
372 sentTimeMs = sentTimeMs + 3600000*24;
373 sentDayDiff-=1;
374 }
375 while(returnTimeMs>3600000*24){
376 returnTimeMs = returnTimeMs - 3600000*24;
377 returnDayDiff++;
378 }
379
380 var sentDate = new Date(getCurrentServerTime()+sentDayDiff*60*60*1000*24),
381 sentMonth = sentDate.getMonth()+1,
382 sentDay = sentDate.getDate(),
383 returnDate = new Date(getCurrentServerTime()+returnDayDiff*60*60*1000*24),
384 returnMonth = returnDate.getMonth()+1,
385 returnDay = returnDate.getDate();
386 sentTime = timeToString(sentTimeMs,Number(ms),sentDay,sentMonth);
387 returnTime = timeToString(returnTimeMs,0,returnDay,returnMonth);
388 return [sentTime, returnTime];
389}
390
391function convertUnitSpeed(unit){ //Converts manual tags to default tag for that unit speed
392 var ramSpeed = ["ram", "catapult"],
393 axeSpeed = ["axe", "spear", "archer"],
394 lightSpeed = ["light", "marcher", "knight"],
395 unitSpeed = unit;
396 if(ramSpeed.includes(unit)) unitSpeed = ramSpeed[0];
397 else if(axeSpeed.includes(unit)) unitSpeed = axeSpeed[0];
398 else if(lightSpeed.includes(unit)) unitSpeed = lightSpeed[0];
399 return unitSpeed;
400}
401//-----------------------------------------//
402
403//------------Time Utils-------------------//
404function getCurrentServerTime(){ //Reads server time from bottom of page
405 var dateArray = $("#serverDate")[0].innerHTML.split("/"),
406 timeArray = $("#serverTime")[0].innerHTML.split(":"),
407 serverFullDate = new Date(Number(dateArray[2]), Number(dateArray[1]-1), Number(dateArray[0]), Number(timeArray[0]), Number(timeArray[1]), Number(timeArray[2]), 0);
408 return serverFullDate.getTime();
409}
410
411function timeToString(time,ms,day,month){
412 var h = Math.floor(time / (3600000)),
413 m = Math.floor((time - h * 3600000) / (60000)),
414 s = Math.floor((time - h * 3600000 - m * 60000) / (1000));
415 h = formatTime(h);
416 m = formatTime(m);
417 s = formatTime(s);
418 if (ms < 100 && ms >= 10){ms = "0" + ms;}
419 else if (ms < 10) {ms = "00" + ms;}
420 return day+"."+month+" at "+h+":"+m+":"+s+":"+"[color=#868686][size=7]"+ms+"[/size][/color]";
421
422}
423function formatDate(arrivalRawDate){
424 date="";
425 for(var j=0;j<arrivalRawDate.length;j++){
426 date+=arrivalRawDate[j];
427 if(j<arrivalRawDate.length-1){
428 date+=" ";
429 }
430 }
431 var month=0,
432 day=0;
433 if(date=="tomorrow at"){
434 realDate = new Date(getCurrentServerTime()+60*60*1000*24);
435 month = realDate.getMonth()+1;
436 day = realDate.getDate();
437 }
438 else if(date=="today at"){
439 realDate = new Date(getCurrentServerTime());
440 month = realDate.getMonth()+1;
441 day = realDate.getDate();
442 }
443 else{
444 var arrivalMonth = date.substr(6,2),
445 arrivalDay = date.substr(3,2),
446 now = getCurrentServerTime(),
447 today = new Date(now);
448 realDate = new Date(today.getFullYear(),Number(arrivalMonth)-1,Number(arrivalDay),today.getHours(),today.getMinutes(),today.getSeconds(),today.getMilliseconds());
449 month = realDate.getMonth()+1;
450 day = realDate.getDate();
451 }
452 return day+"."+Number(month);
453}
454function formatTime(i){
455 if (i < 10) {
456 i = "0" + i;
457 }
458 return i;
459}
460//-----------------------------------------//
461//------------Data Utils-------------------//
462function checkCookie(cname) {
463 var value = getCookie(cname);
464 if (value !== "") {
465 return value;
466 }
467 else {
468 if (value === "" && value !== null){
469 var worldInfo = loadXMLDoc("/interface.php?func=get_config");
470 if (cname == "worldSpeed"){value=worldInfo.getElementsByTagName("speed")[0].innerHTML;}
471 else if (cname == "unitSpeed"){value=worldInfo.getElementsByTagName("unit_speed")[0].innerHTML;}
472 else if (cname == "isArcherActive"){
473 if(worldInfo.getElementsByTagName("archer")[0].innerHTML == "1"){value="true";}
474 else{value = "false";}
475 }
476 setCookie(cname, value);
477 return value;
478 }
479 }
480}
481
482function setCookie(cname,cvalue) {
483 document.cookie = cname+"="+cvalue+";";
484}
485
486function getCookie(cname) {
487 var name = cname + "=";
488 var ca = document.cookie.split(';');
489 for(var i=0; i<ca.length; i++) {
490 var c = ca[i];
491 while (c.charAt(0)==' ') c = c.substring(1);
492 if (c.indexOf(name) == 0) {
493 return c.substring(name.length, c.length);
494 }
495 }
496 return "";
497}
498
499function loadXMLDoc(dname){
500 if (window.XMLHttpRequest){
501 xhttp=new XMLHttpRequest();
502 }
503 else{
504 xhttp=new ActiveXObject("Microsoft.XMLDOM");
505 }
506 xhttp.open("GET",dname,false);
507 xhttp.send();
508 return xhttp.responseXML;
509}